C# : Why is Line.TryCreateBetweenCurves(...) failing?

OK, so I’ve tried with different settings, but my attempt to make a Tangent-Tangent line between two arcs keeps failing.

The two arcs I have are defined as follows, and when “debug-previewing” the input arcs and t-para,eters, the indata looks like this, and still the resulting Line (line.IsValid == true) cannot be converted to a ToNurbsCurve() which returns null:

The code (which also outputs the “debug curves” and parameter points in the picture above):

What am I doing wrong? The Line seems to be valid, the parametric values lands on the arc curves, … I’m lost on this one.

// Rolf

The code:
´´´
Curve connect_crv_a = null;

        corner_arc_a.Domain = new Interval(0, 1);
        top_arc_a.Domain = new Interval(0, 1);
        var t0 = 0.75;
        var t1 = 0.5;
        var line = Line.Unset;
        if (Line.TryCreateBetweenCurves(corner_arc_a, top_arc_a, ref t0, ref t1, false, false, out line))
        {
            connect_crv_a = line.ToNurbsCurve();
        }
        else if (line == null || !line.IsValid || line.ToNurbsCurve() == null)
        {
            HelperCurves.Add(corner_arc_a);
            HelperCurves.Add(top_arc_a);

            var pt = corner_arc_a.PointAt(t0);
            HelperPoints.Add(pt);

            pt = top_arc_a.PointAt(t1);
            HelperPoints.Add(pt);

            HelperGeo.Add(line);
            return false;
        }

´´´

Hello
I tried your code on R7 and it works. Or I didn’t understood your problem . Are your arc on the same plane ?
arc arc line.gh (2.9 KB)

For one of my tool for rubber band I used that

And I use 4 methods in order to have the 4 possible solutions if they exist
image

1 Like

Yes, they are on the same plane.

However, I just tried switching the values of the parameters t0, t1, then it started to work (also) for me:

        var t0 = 0.75;
        var t1 = 0.5;
-->
        var t0 = 0.5;
        var t1 = 0.75;

Subtle, but it had a drastic effect…

//Rolf

The documentation says it is seed value, but doesn’t say if there are some limitations. it could be good you post the curves and parameters that don’t work as it seems likely it is a bug.

Yes, it really puzzled me. I’ll try to make a small reproducible case and post it.

//Rolf

I have this one
t ~0.46 no line, if less a line, if more a line … => A BUG



arc arc line.gh (6.7 KB)

OK, here I have the exact same code and the exact same curves which failed in the VS-code, but here it seems it doesn’t really matter what values I set for the t0, t1 parameters. < scratching head >

Debug Line_TryBetweenCurves.ghx (40.8 KB)

//Rolf

Almost correctly state above.

If I set t0 == 0, then there’s an interval on t1 (the upper arc) between 0.58 … 0.88 where the Line.TryBetweenCurves fails.

I don’t know how relevant that is, but a test-case using permutations for both sliders should be performed to spot the value intervals where the algorithm goes bananas.


The problem I have with this function is that I run a series of these curves with arcs, but with different values, and if I can’t predict at which value intervals the parameters fail, my algorithm becomes very shaky.

// Rolf

1 Like

My solution to arbitrary located arcs with arbitrary radii:

In order to make the t0 & t1 (6.1 & 6.2) seed parameters closer to the final curve-curve tangent points (avoiding invalid result from the Line.TryCreateBetweenCurves()function), I made a helper function which approximates the t-parameters by performing ClosestPoint (6) from a rotated center-line (4) which is then moved away from perpendicularly the arcs (5).

See code far below.

The resulting t0 and t1 parameters can then safely be used in the Line.TryCreateBetweenCurves()function to get the tangent-tangent line between the arcs (7) :

This is a bit involved, yes, but the Line.TryCreateBetweenCurves()function really should be more robust regarding the values of the seed parameters.

// Rolf

Line.TryCreateBetweenCurves.ghx (145.4 KB)
Line.TryCreateBetweenCurves.3dm (176.0 KB)

The code for the helper function:

// Remove these for production code:
private List<Curve> M_DebugCurves;
private List<Point3d> M_DebugPoints;
private List<Object> M_DebugGeo;

public bool GetApproximateCurveCurveParameters(Plane pln, Curve arc_a, Curve arc_b, out double t0, out double t1)
{
  // -----------------------------------------------------
  // 1. Line from arc-center to arc-center
  //
  // 2. Rotate this "center line" into parallel with the
  //    arcs circumference.
  //
  // 3. Move perpendiculary with distance = largest radius
  //
  // 4. ClosestPoint to Both Curves producing t0 & t2
  // -----------------------------------------------------

  // In order to get the center point of each Arc the
  // (possibly) imperfect arc-curves are recreated as
  // truly perfect Arcs :

  var perfect_arc_a = new Arc(arc_a.PointAtStart, arc_a.TangentAtStart, arc_a.PointAtEnd);
  var arc_a_center = perfect_arc_a.Center;

  var perfect_arc_b = new Arc(arc_b.PointAtStart, arc_b.TangentAtStart, arc_b.PointAtEnd);
  var arc_b_center = perfect_arc_b.Center;

  var center_line = new Line(arc_a_center, arc_b_center).ToNurbsCurve();

  M_DebugCurves.Add(center_line.DuplicateCurve());

  // -------------------------------------------------
  // Tilt the line to align with the arc's difference
  // in radius
  // -------------------------------------------------

  // The rotation center should be from the smallest arc:
  var rotation_center = perfect_arc_a.Radius < perfect_arc_b.Radius ? perfect_arc_a.Center : perfect_arc_b.Center;

  var diff_radius = Math.Abs(perfect_arc_a.Radius - perfect_arc_b.Radius);
  var center_distance = (arc_a.PointAtStart - arc_b.PointAtEnd).Length;
  var arc_sin = Math.Asin(diff_radius / center_distance);
  var trx = Transform.Rotation(arc_sin, pln.ZAxis, rotation_center);

  var end_pt = center_line.PointAtEnd;
  end_pt.Transform(trx);
  center_line.SetEndPoint(end_pt);

  M_DebugCurves.Add(center_line.DuplicateCurve());

  // -------------------------------------------------
  // Move the rotated center_line away perpendiculary from the
  // arcs before performing ClosestPoint on them
  // -------------------------------------------------

  var center_line_direction = center_line.TangentAtEnd;
  var rotated_plane = new Plane(rotation_center, center_line_direction, Vector3d.CrossProduct(pln.ZAxis, center_line_direction));
  var max_radius = Math.Max(perfect_arc_a.Radius, perfect_arc_b.Radius) * 2;
  center_line.Translate(rotated_plane.YAxis * max_radius);

  M_DebugCurves.Add(center_line.DuplicateCurve());

  // -------------------------------------------------
  // get ClosestPoint parameter from each end of the
  // distant line back to each each arc :
  // -------------------------------------------------

  arc_a.ClosestPoint(center_line.PointAtStart, out t0);
  arc_b.ClosestPoint(center_line.PointAtEnd, out t1);

  return true;
}
1 Like