Here the script, I used surface because surface is used by shortestPath, but I am sure that ShortestPath is not the fastest way to do that. Using mesh approach then projecting curve on surface (or Brep) could be more effective and more general. But it works.

```
private void RunScript(Surface surface, List<Point3d> points, List<double> distances, double width, int seed, ref object A)
{
//Laurent Delrieu 11/5/2020
List<Curve> lst_curves = new List<Curve>();
//TODO test on list of distances that must have the same size as list of points ...
Random rnd = new Random(seed);
for (int i = 0; i < points.Count; i++)
{
//We seek the normal on the mesh, could be done on Brep
double u, v;
double distance = distances[i];
Point3d point = points[i];
surface.ClosestPoint(point, out u, out v);
Point3d closestPoint = surface.PointAt(u, v);
Vector3d normal = surface.NormalAt(u, v);
//We try with the cross product of normal and X
Vector3d direction = Vector3d.CrossProduct(normal, Vector3d.XAxis);
if (direction.Length < 1e-10) // If length to little (near 0 we choose another vector)
{
direction = Vector3d.CrossProduct(normal, Vector3d.YAxis);
}
//Random angle
double angle = rnd.NextDouble() * Math.PI * 2.0;
//random direction
direction.Rotate(angle, normal);
Curve firstCurve = CurveOnSurface(surface, point, direction, distance);
lst_curves.Add(firstCurve);//Add the first curve
//First lateral move
Point3d firstPoint = firstCurve.PointAtStart;
surface.ClosestPoint(firstPoint, out u, out v);
Vector3d normalFirstPoint = surface.NormalAt(u, v);
Vector3d directionFirstPoint = firstCurve.TangentAtStart;
directionFirstPoint.Rotate(Math.PI / 2, normalFirstPoint);//Rotate 90°
Curve lateral_0 = CurveOnSurface(surface, firstPoint, directionFirstPoint, width);
//Last lateral move
Point3d lastPoint = firstCurve.PointAtEnd;
surface.ClosestPoint(lastPoint, out u, out v);
Vector3d normalLastPoint = surface.NormalAt(u, v);
Vector3d directionLastPoint = firstCurve.TangentAtEnd;
directionLastPoint.Rotate(Math.PI / 2, normalLastPoint);//Rotate 90°
Curve lateral_1 = CurveOnSurface(surface, lastPoint, directionLastPoint, width);
lst_curves.Add(lateral_0);
lst_curves.Add(lateral_1);
//Closing the rectangle
double u0, v0;
surface.ClosestPoint(lateral_0.PointAtEnd, out u0, out v0);
double u1, v1;
surface.ClosestPoint(lateral_1.PointAtEnd, out u1, out v1);
lst_curves.Add(surface.ShortPath(new Point2d(u0, v0), new Point2d(u1, v1), RhinoDoc.ActiveDoc.ModelAbsoluteTolerance * 100));
}
A = lst_curves;
}
// <Custom additional code>
public Curve CurveOnSurface(Surface surface, Point3d departurePoint, Vector3d departureDirection, double distance)
{
List<Point3d> lst_points = WalkOnSurface(surface, departurePoint, departureDirection, distance);
double u0, v0;
surface.ClosestPoint(lst_points[0], out u0, out v0);
double u1, v1;
surface.ClosestPoint(lst_points[lst_points.Count - 1], out u1, out v1);
Curve curve = surface.ShortPath(new Point2d(u0, v0), new Point2d(u1, v1), RhinoDoc.ActiveDoc.ModelAbsoluteTolerance * 100);
double t;
//if OK we take the firts segement that must have the good length
if (curve.LengthParameter(distance, out t))
{
Curve[] curves_splitted = curve.Split(t);
curve = curves_splitted[0];
}
return curve;
}
public List<Point3d> WalkOnSurface(Surface surface, Point3d departurePoint, Vector3d departureDirection, double distance)
{
int n = 100;
double incrementOfDistance = distance / (double) n; //Increment of move abritrary set, could be changed
List<Point3d> lst_points = new List<Point3d>();//List to store the points
//Seeking the closest point, need some test if closest is OK
double u, v;
surface.ClosestPoint(departurePoint, out u, out v);
lst_points.Add(surface.PointAt(u, v));
Vector3d direction = departureDirection;
direction.Unitize();
for (int i = 0; i < (n + 4); i++)//I took some more points in order to have a projected curve of good length
{
Point3d nextPoint = lst_points[lst_points.Count - 1] + direction * incrementOfDistance;
double u1, v1;
surface.ClosestPoint(nextPoint, out u1, out v1);
lst_points.Add(surface.PointAt(u1, v1));
direction = lst_points[lst_points.Count - 1] - lst_points[lst_points.Count - 2];
if (!direction.Unitize()) //It means the 2 last points are the same
{
break;
}
}
return lst_points;
}
```

rectangle on mesh brep LEGACY.gh (13.3 KB)