Developing a C# Component for grasshopper, I am finding myself often in the situation where I need to extend or trim two curves such that their ends meet.
Both curves were segments of a closed curve. Each segment is offset on the XY plane by a different value. Whether the curved need to be extended or trimmed depends on curvature, angle, and offset distance.
My code currently checks for 4 possible conditions:
- curveA intersects curveB? trim both curves.
- curveA would intersect curveB if extended? extend curveA, trim curveB
- curveB would intersect curveA if extended? extend curveB, trim curveA
- otherwise: calculate the linear function of the tangent at the endpoint of both curves, find the point where both lines would intersect, calulated distance to that point, extend both curves.
It works but feels needlessly complex. Is there a simpler way?
My code:
(It is known that the curves both are in the same direction, so we want to trim or extend from the end of crvA and the start of crvB)
(It can also be take for granted that the curves are not parallel)
private static (Curve crvAn, Curve crvBn) ConnectCurves(Curve crvA, Curve crvB)
{
Vector3d tgtA = crvA.TangentAt(crvA.Domain.T1);
Vector3d tgtB = crvB.TangentAt(crvB.Domain.T0);
// curves intersect
CurveIntersections ccinter = Intersection.CurveCurve(crvA, crvB, DocumentTolerance(), DocumentTolerance());
if (ccinter.Count > 0)
{
IntersectionEvent inter = ccinter[0];
return (
crvA.Trim(crvA.Domain.T0, inter.ParameterA),
crvB.Trim(inter.ParameterB, crvB.Domain.T1)
);
}
// extending one curve will intersect another
Line lineA = new Line(crvA.PointAtEnd, tgtA);
CurveIntersections clinterA = Intersection.CurveLine(crvB, lineA, DocumentTolerance(), DocumentTolerance());
if (clinterA.Count > 0)
{
IntersectionEvent inter = clinterA[0];
var a = crvA.Extend(CurveEnd.End, new Line(crvA.PointAtEnd, inter.PointB).Length, CurveExtensionStyle.Line);
var b = crvB.Trim(inter.ParameterA, crvB.Domain.T1);
return (a, b);
}
Line lineB = new Line(crvB.PointAtStart, tgtB);
CurveIntersections clinterB = Intersection.CurveLine(crvA, lineB, DocumentTolerance(), DocumentTolerance());
if (clinterA.Count > 0)
{
IntersectionEvent inter = clinterB[0];
var a = crvA.Trim(crvA.Domain.T0, inter.ParameterA);
var b = crvB.Extend(CurveEnd.Start, new Line(crvB.PointAtStart, inter.PointB).Length, CurveExtensionStyle.Line);
return (a, b);
}
// basic math to find the intersection point
double slopeA = tgtA.Y / tgtA.X;
double slopeB = tgtB.Y / tgtB.X;
double offA = slopeA * crvA.PointAtEnd.X - crvA.PointAtEnd.Y;
double offB = slopeB * crvB.PointAtStart.X - crvB.PointAtStart.Y;
double ix = (offB - offA) / (slopeA - slopeB);
double iy = slopeA * ix + offA;
Point3d ipoint = new Point3d(ix, iy, crvA.PointAtEnd.Z);
// extend both lines until they intersect
return (
crvA.Extend(CurveEnd.End, new Line(crvA.PointAtEnd, ipoint).Length, CurveExtensionStyle.Line),
crvB.Extend(CurveEnd.Start, new Line(crvB.PointAtStart, ipoint).Length, CurveExtensionStyle.Line)
);
}