I have the attached curve: badCurve.3dm (45.1 KB)
and the following plugin command code:
public class MyTryGetPlane : Command
{
public MyTryGetPlane()
{
Instance = this;
}
public static MyTryGetPlane Instance { get; private set; }
public override string EnglishName => "MyTryGetPlane";
protected override Result RunCommand(RhinoDoc doc, RunMode mode)
{
using GetObject go = new();
go.SetCommandPrompt("Select Curve");
go.GeometryFilter = Rhino.DocObjects.ObjectType.Curve;
if (go.Get() == Rhino.Input.GetResult.Cancel)
{
return Result.Cancel;
}
Curve curve = go.Object(0).Curve();
if (curve == null)
{
return Result.Failure;
}
if (curve.TryGetPlane(out Plane plane))
{
doc.Objects.Add(NurbsSurface.CreateFromCorners(plane.PointAt(-1000, -1000), plane.PointAt(-1000, 1000), plane.PointAt(1000, 1000), plane.PointAt(1000, -1000)));
return Result.Success;
}
else
{
RhinoApp.WriteLine("failed to find plane");
return Result.Failure;
}
}
}
The command is not finding a plane for the curve, despite the curve originally being an intersection of a Brep with a plane.
I saw another post that said that this is probably due to tolerances. However, I can only get this command to work with tolerances as loose as 10, and I’m not convinced that the curve really needs that much tolerance.
Any ideas what’s going on? Thanks,
- Russell Emerine
Thanks for your response. While I was waiting for someone to see the post I ran another test as follows:
Use the start, end, and midpoint of the curve to create a plane
Use Curve.ExtremeParameters with the plane normal to find points on the curve
Find the distance between the plane and those points
I found with this test that all points found by Curve.ExtremeParameters were within 0.0005 of the plane. Is this an indication of problems with TryGetPlane, ExtremeParameters, or something else?
The documentation says that the Euclidean location of a control point is (x/w, y/w, z/w). I believe the TryGetPlane logic probably, and the control point test you suggested definitely, should use the Euclidean values cv.Location.X, cv.Location.Y, and cv.Location.Z instead of the control point cv.X, cv.Y, and cv.Z values. Can you check to see if there needs to be a change in TryGetPlane (and IsInPlane)?
Your curve is a PolyCurve, make up of 27 line, arc, and NURBS curve segments.
The underlying code behind PolyCurve.TryGetPlane method computes the first derivative at the start of the curve. It then tests every segment in the polycurve to see if it lies on this plane. In yoru case, the curve-in-plane test fails on the segment[5].
It looks like converting the polycurve to NURBS provides better results.
This is the segment from the previous file that fails. I’ve written a command with the following code:
...Command boilerplate...
using GetObject go = new();
go.GeometryFilter = ObjectType.Curve;
if (go.Get() == GetResult.Cancel)
{
return;
}
Curve curve = go.Object(0).Curve();
Plane p = new(curve.PointAtStart, Vector3d.YAxis);
if (curve is ArcCurve ac)
{
RhinoApp.WriteLine("found ArcCurve");
if (!ac.IsInPlane(p, 0.01))
{
RhinoApp.WriteLine("ArcCurve not in plane");
}
foreach (int i in Enumerable.Range(0, 11))
{
Point3d x = ac.PointAtNormalizedLength(((double)i) / 10);
double dist = p.ClosestPoint(x).DistanceTo(x);
RhinoApp.WriteLine("found point at dist " + dist);
if (dist > 0.01)
{
Utils.Add(m_Doc, x, System.Drawing.Color.Beige);
RhinoApp.WriteLine("dist was far from plane");
}
}
}
...Command boilerplate...
ac.IsInPlane is returning false, but each of the sampled points is within 0.0002 of the plane. Is this a problem with ArcCurve.IsInPlane?
I only care about the visible portion in my use case. When I ask RhinoCommon if a plane contains a curve, I don’t expect points that aren’t in the curve’s domain to matter in any way. Shouldn’t ArcCurve.IsInPlane only consider the arc itself and not the entire circle?
That does solve my problem. I’m just complaining now that the behavior of IsInPlane is not what I’d expect it to be, i.e. I don’t see any reason for it to be different between an ArcCurve and its corresponding NurbsCurve.
I want to make sure you understand that the result of ArcCurve.IsInPlane are correct. The question you asking was if an arc curve lies on a arbitrary plane. And in your case, the answer is no as I have demonstrated.
The test you wrote, sampling points on the arc curve and then computing closest points to the arbitrary plane and the distances between, is not an equivalent test to ArcCurve.IsInPlane. Your test does show, however, that the computed points are close to where the arc curve’s plane and the arbitrary planes intersect.
If you move the origin of the arbitrary plane to somewhere on the arc but away from the start point, the origin of the curve’s plane for example, you will see your results degrade.
I was trying to find if an arc, considered as a locus of points, lies on an arbitrary plane within some tolerance. Equivalently, I’m interested if all the points in the arc have distance less than the tolerance from the plane. The test with sampled points was meant to be an approximation of this (with some small room for error), simply by testing “some” point of the points in the arc instead of “all”.
I’m only testing points on the arc instead of around the whole circle since I only care about the arc and not the whole circle. Since your test considers points on the circle that aren’t on the arc, I don’t believe you’ve demonstrated in any way that the arc curve does not lie on the plane in the sense that I’m interested in.
(Side note: I should use Plane.DistanceTo instead of finding the closest point and getting the distance to that point.)