Finding the average curve between two curves

Does dynamo have anything for the title? I ended up doing a right angle lines off the two curves. Clashing them with the surface between the two curves and getting the center points of the lines, organizing and running a nurbs curve through it (not sure how accurate it is). However my two lines were more consistent between each other. What if you had two crazy lines like in the post below? Do we have this circle fitting? distance field on a mesh?

Little left of the title. What I came up with to try use the average curve to get sawcut lines along a path. But curious if you have more inconsistent parallel lines.
Floors_Sawcut segments along path.dyn (228.4 KB)
R23
Test Paths.rvt (1.3 MB)

The stuff in the Rhino forum applies here too.

Lofting between the two curves and finding the isocurve is likely the ‘easy’ path, but that won’t work in all situations.

You could also try converting both to nurbs curves and building from the average weighting, but that may not work on all cases.

Sampling along curve A and getting the mid point to the closest point on curve B could also work.

Getting the medial axis and finding the shortest path works well, but could be inefficient.

One solution I didn’t see there is, getting a UV map of the distance from the curves within the same domain and finding the ‘common’ values within the surface… could be the most effective overall but the math on it might not be as straightforward as I would like.

2 Likes

Hi,
a trial by calculating an approximate curve (with scipy), then a search along the perpendiculars for points equidistant from the input curves.

import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import numpy as np
from scipy.interpolate import interp1d
from scipy.ndimage import uniform_filter1d

curveA, curveB = IN[0]
plane = Plane.ByOriginNormal(Point.ByCoordinates(0, 0 , 0), Vector.ByCoordinates(0,0,1))
# ensure curves are Z zero
curveA = curveA.PullOntoPlane(plane)
curveB = curveB.PullOntoPlane(plane)
ptCurveA = [curveA.PointAtParameter(n) for n in np.linspace(0, 1, num=500)]
ptCurveB = [curveB.PointAtParameter(n) for n in np.linspace(0, 1, num=500)]
# merge, flatten points and keeping order
pts  = [pt for pairPts in zip(ptCurveA,ptCurveB) for pt in pairPts]

data = [[int(p.X), int(p.Y)] for p in pts]
x, y = [i for i in zip(*data)]
# compute the arithmetic average with scipy.ndimage.uniform_filter1d
y_smooth = uniform_filter1d(y,size=5, mode='wrap')
x_smooth = uniform_filter1d(x,size=5, mode='wrap')

rays = []
mid_Pts = []
ray_length = 6000 # example in millimeter
# compute an approximative average curve 
pts_uniform = [Point.ByCoordinates(x, y , 0) for x, y in zip(x_smooth, y_smooth)]
pts_uniform_iter = iter(pts_uniform[:])
dsPoints = [Point.ByCoordinates((pta.X + ptb.X) / 2, (pta.Y + ptb.Y) / 2, 0) for pta, ptb in zip(pts_uniform_iter, pts_uniform_iter)]
# remove extra points
dsPoints = dsPoints[1:-1]
aprox_average_curve = PolyCurve.ByPoints(dsPoints, False)
# with this curve compute an new average curve by normal curve intersection (ray) and compute middle points 
for n in np.linspace(0, 1, num=100):
    normal = aprox_average_curve.NormalAtParameter(n)
    pt = aprox_average_curve.PointAtParameter(n)
    ray_line = Line.ByStartPointDirectionLength(pt, normal, ray_length) 
    ray_line = ray_line.Translate(normal.Reverse(), ray_length / 2)
    if ray_line.DoesIntersect(curveA) and ray_line.DoesIntersect(curveB):
        ptInterA = ray_line.Intersect(curveA)[0]
        ptInterB = ray_line.Intersect(curveB)[0]
        midpt = Point.ByCoordinates((ptInterA.X + ptInterB.X) / 2, (ptInterA.Y + ptInterB.Y) / 2, 0)
        rays.append(ray_line)
        mid_Pts.append(midpt)

OUT = rays, PolyCurve.ByPoints(mid_Pts, False)
5 Likes

This is so cool. This forum always blows me away how smart people are

1 Like