Yet Another Dotted Image Technique : Tangent On Curve Dotted Image

Here a script to make dotted image with tangent circles following a curve. (28.9 KB)


Joconde from Leonard da Vinci

With Hilbert Curve

Andy Warhol’s Marilyn Monroe

AUBRY GASPARD Mappemonde en métal laqué

The idea uses the script from this disucssion

The idea there is not to provide the radius for each dot but to provide the minimum and maximum radius for dots. The radius depends on the brightness with the following formula. Power is use to change the contrast.
Radius = (radius2 - radius1)*Math.Pow(brightness, power)+ radius1

For script you have to choose

  • The type of curve (spiral on center off the image, spiral on the side, Hilbert curve)
  • The coefficient between maximum radius and minimum radius (here 4)
  • The contrast (between 0.5 and 3 here)
  • The parameters for your curve
  • The path of your image

I choose to use a colored sphere instead of dots because I had many problems with dots. I don’t know if it is better now but I stay with that.
I use one of my spiral plugin

Some others discussions on dotted images or thickened curves images

And for the C# guys

  private void RunScript(Curve curve, Mesh mesh, double radius1, double radius2, double power, ref object points, ref object radiuses, ref object colors)

    //Calculate the center of circles with specified radius on a curve
    // Radiuses are calculated depending on the brightness of the image
    // 14/12/2021
    // Laurent Delrieu
    List<Point3d> lst_points = new List<Point3d>();
    List<double> lst_radiuses = new List<double>();
    List<Color> lst_colors = new List<Color>();

    Point3d pointOnCurve = curve.PointAtStart;
    System.Drawing.Color color = System.Drawing.Color.White;
    double radiusPrec = GetRadius(mesh, pointOnCurve, radius1, radius2, power, out color);
    double radius = radiusPrec;


    int count = 2000000;
    for (int i = 1; i < count; i++)

      Point3d pointOnCurveNew = CurveCircleIntersection(curve, pointOnCurve, radiusPrec + radius);
      if (pointOnCurveNew != Point3d.Unset)
        pointOnCurve = pointOnCurveNew;

        double radiusNew = GetRadius(mesh, pointOnCurve, radius1, radius2, power, out color);
        radiusPrec = radius;
        radius = radiusNew;


    points = lst_points;
    radiuses = lst_radiuses;
    colors = lst_colors;

  // <Custom additional code> 

  /// <summary>
  /// Return a radius depending on the brighness
  /// </summary>
  /// <param name="mesh">Colored mesh</param>
  /// <param name="point">Point near the mesh</param>
  /// <param name="radius1">First radius</param>
  /// <param name="radius2">Second radius</param>
  /// <param name="power">Power used for contrast, 1 if you don't know what to use, test with 0.5 or 1.5 to see the effect</param>
  /// <param name="color">Color near the point</param>
  /// <returns></returns>
  double GetRadius(Mesh mesh, Point3d point, double radius1, double radius2, double power, out System.Drawing.Color color)
    double radius = Math.Max(radius1, radius2);
    MeshPoint mp = mesh.ClosestMeshPoint(point, radius * 500);

    color = Color.White;
    if (mp != null)
      //System.Drawing.Color color = mesh.ColorAt(mp);
      color = mesh.ColorAt(mp);
      double brightness = (double) color.GetBrightness();
      radius = (radius2 - radius1) * Math.Pow(brightness, power) + radius1;
    return radius;


  /// <summary>
  /// Calculate the point on a curve that is at a certain radius from a point
  /// this point must be after the previous point
  /// </summary>
  /// <param name="curve">The curve</param>
  /// <param name="point">The point on the curve</param>
  /// <param name="radius">The radius at which the new pointt must be from previous point</param>
  /// <returns>Next point, Point3d.Unset if no point found</returns>
  Point3d CurveCircleIntersection(Curve curve, Point3d point, double radius)
    double tolerance = 0.0001;
    double overlapTolerance = 0.0001;

    Point3d output = Point3d.Unset;
    double t = double.NaN;
    curve.ClosestPoint(point, out t);

    if (t != double.NaN)
      Circle circle = new Circle(Plane.WorldXY, point, radius);
      CurveIntersections ci = Rhino.Geometry.Intersect.Intersection.CurveCurve(curve, new ArcCurve(circle), tolerance, overlapTolerance);

      double tMinOK = double.NaN;

      foreach (IntersectionEvent ie in ci)
        if (ie.ParameterA > t)
          //First parameter that is OK
          if (Double.IsNaN(tMinOK))
            tMinOK = ie.ParameterA;
            output = ie.PointA;
            //If a parameter is nearer
            if (ie.ParameterA < tMinOK)
              tMinOK = ie.ParameterA;
              output = ie.PointA;
    return output;

Another great effect! I wonder how these could be produced? A laser that dwells longer on each dot to represent radius perhaps?

I have tried making these images by creating a vertical line on each dot to control the depth of a V-Cutter on a CNC but its so hard to find a nice sheet material that has a light surface and a dark core. (or vice versa… dark surface and light core)

My best results were using MDF and applying a dark stain to the surface with a roller after drilling.

Have you tried making any?

1 Like

There’s some cool aluminum clad plastic sheet that signmakers use. It’s very thin aluminum on both sides of a plastic core. The aluminum paints well and the core comes in several colors. Here’s one example: Aluminum Display Graphic Substrates Aluminum Clad Panels from Regal Plastic sheets - Regal Plastic

I think this project was done with some version of it, but I might be wrong:


The only use I have in mind is to use this technique with classical print. I hope one of this image will be used in a book. Finger crossed.

If you want to use that for a drill the only problem is continuity. You will have a long strip of material.

1 Like

Thanks, that looks promising!
It looks like the controversial material used for exterior cladding on buildings here in the UK. I will try and find a UK supplier.

the hilbert curve works fine but when turning on spiral I get an error in C# script and not sure how to get it to work.

A screen copy with the error could help!

sorry! here’s a screenshot:

You must upload the spiral component. If you have no component you have no data (curve here), with no curve the C# doesn’t work
It s there

thanks! yeah I was missing that component. works now!

I’m curious is there a way to change the pattern instead of a spiral, make the circles run in lines horizontally?

A post was split to a new topic: Quick feedback