| McNeel Wiki | |||||
| edit · print · help · all topics | |||||
Main Pages
Languages
| QuestionAs part of a plug-in that I'm writing, it would be fantastic if it were possible to identify shapes that planar curves might be identified as (within tolerance). I have not found anything like this in the libraries available for .NET. Any assistance that you could provide would be appreciated AnswerRhino support a number of basic curve types, including lines (OnLineCurve), polylines (OnPolylineCurve), arcs and circles (OnCrvCurve), NURBS curves (OnNurbsCurve), and more. You can verify if a geometric object is one of these curves types simply by trying to cast that geometry as one of these types. The problem gets a little more complicated because it is possible for NURBS curves to look like basic curve types. So, if you are trying to identify curve by their shape and not just their object type. But, the .NET SDK provides enough methods to even help with this task. The following example command demonstrates how to classify a selected curve. You can also download this sample here. C#
using System;
using RMA.Rhino;
using RMA.OpenNURBS;
namespace <put_your_plugin_namespace_here>
{
public class ClassifyCurveCommand : RMA.Rhino.MRhinoCommand
{
public override System.Guid CommandUUID()
{
return new System.Guid("{<put_unique_command_uuid_here>}");
}
public override string EnglishCommandName()
{
return "ClassifyCurve";
}
public override IRhinoCommand.result RunCommand(IRhinoCommandContext context)
{
// Select a curve to clasify
MRhinoGetObject go = new MRhinoGetObject();
go.SetCommandPrompt("Select curve to classify");
go.SetGeometryFilter(IRhinoGetObject.GEOMETRY_TYPE_FILTER.curve_object);
go.EnableSubObjectSelect(false);
go.GetObjects(1, 1);
if (go.CommandResult() != IRhinoCommand.result.success)
return go.CommandResult();
// Get the geometry
MRhinoObjRef objref = go.Object(0);
IOnCurve crv = objref.Curve();
if (crv == null)
return IRhinoCommand.result.failure;
// Obtain the document tolerances
double tol = context.m_doc.AbsoluteTolerance();
double angtol = context.m_doc.AngleToleranceRadians();
// Is the curve a line?
if (IsLine(crv))
{
RhUtil.RhinoApp().Print("Curve is a line.\n");
return IRhinoCommand.result.success;
}
// Is the curve an arc or circle?
bool bCircle = false;
if (IsArc(crv, tol, ref bCircle))
{
if (bCircle)
RhUtil.RhinoApp().Print("Curve is a circle.\n");
else
RhUtil.RhinoApp().Print("Curve is an arc.\n");
return IRhinoCommand.result.success;
}
// Is the curve an ellipse or an elliptical arc?
bool bEllipticalArc = false;
if (IsEllipse(crv, tol, ref bEllipticalArc))
{
if (bEllipticalArc)
RhUtil.RhinoApp().Print("Curve is an elliptical arc.\n");
else
RhUtil.RhinoApp().Print("Curve is an ellipse.\n");
return IRhinoCommand.result.success;
}
// Is the curve some kind of polyline?
int point_count = 0; // number of vertices
bool bClosed = false; // curve is closed
bool bDistance = false; // segments are identical
bool bAngle = false; // angles are identical
bool bIntersect = false; // curve self-intersects
if (IsPolyline(crv, tol, angtol, ref point_count,
ref bClosed, ref bDistance, ref bAngle, ref bIntersect))
{
// If the curve is closed and does not self-intersect,
// then it must be a polygon.
if (bClosed && !bIntersect)
{
// If segment distances and angles are identical,
// then it must be a regular polygon.
if (bDistance && bAngle && !bIntersect)
{
if (point_count == 3)
RhUtil.RhinoApp().Print("Curve is an equilateral triangle.\n");
else if (point_count == 4)
RhUtil.RhinoApp().Print("Curve is a square.\n");
else if (point_count == 5)
RhUtil.RhinoApp().Print("Curve is a regular pentagon.\n");
else if (point_count == 6)
RhUtil.RhinoApp().Print("Curve is a regular hexagon.\n");
else if (point_count == 7)
RhUtil.RhinoApp().Print("Curve is a regular heptagon.\n");
else if (point_count == 8)
RhUtil.RhinoApp().Print("Curve is a regular octagon.\n");
else if (point_count == 9)
RhUtil.RhinoApp().Print("Curve is a regular nonagon.\n");
else if (point_count == 10)
RhUtil.RhinoApp().Print("Curve is a regular decagon.\n");
else
RhUtil.RhinoApp().Print("Curve is a regular polygon.\n");
}
// If segment distances or angles are not identical,
// then it must be an irregular polygon.
else if (!bIntersect)
{
if (point_count == 3)
{
// I'll leave searching for isosceles, scalene, acute, obtuse
// and right triangles for somebody else...
RhUtil.RhinoApp().Print("Curve is a triangle.\n");
}
else if (point_count == 4)
{
// I'll leave searching for parallelogram and trapezoids
// for somebody else...
if (bAngle)
RhUtil.RhinoApp().Print("Curve is a rectangle.\n");
else if (bDistance)
RhUtil.RhinoApp().Print("Curve is a rhombus.\n");
else
RhUtil.RhinoApp().Print("Curve is a quadrilateral.\n");
}
else if (point_count == 5)
RhUtil.RhinoApp().Print("Curve is an irregular pentagon.\n");
else if (point_count == 6)
RhUtil.RhinoApp().Print("Curve is an irregular hexagon.\n");
else if (point_count == 7)
RhUtil.RhinoApp().Print("Curve is an irregular heptagon.\n");
else if (point_count == 8)
RhUtil.RhinoApp().Print("Curve is an irregular octagon.\n");
else if (point_count == 9)
RhUtil.RhinoApp().Print("Curve is an irregular nonagon.\n");
else if (point_count == 10)
RhUtil.RhinoApp().Print("Curve is an irregular decagon.\n");
else
RhUtil.RhinoApp().Print("Curve is an irregular polygon.\n");
}
}
else
RhUtil.RhinoApp().Print("Curve is a polyline.\n");
return IRhinoCommand.result.success;
}
// Is the curve a NURBS curve?
if (IsNurbsCurve(crv))
{
RhUtil.RhinoApp().Print("Curve is a NURBS curve.\n");
return IRhinoCommand.result.success;
}
// Give up...
RhUtil.RhinoApp().Print("Curve is unclassified.\n");
return IRhinoCommand.result.success;
}
/////////////////////////////////////////////////////////////////
// Test to see if a curve has the properties of a line
private bool IsLine(IOnCurve crv)
{
if (crv == null)
return false;
// Is the curve a line curve?
IOnLineCurve line_crv = OnLineCurve.ConstCast(crv);
if (line_crv != null)
return true;
// Is the curve a polyline that looks like a line?
IOnPolylineCurve pline_crv = OnPolylineCurve.ConstCast(crv);
if (pline_crv != null && pline_crv.m_pline.Count() == 2)
return true;
// Is the curve a polycurve that looks like a line?
IOnPolyCurve poly_crv = OnPolyCurve.ConstCast(crv);
if (poly_crv != null)
{
ArrayOn3dPoint pline_points = new ArrayOn3dPoint();
if (poly_crv.IsPolyline(pline_points) == 2)
return true;
}
// Is the curve a NURBS curve that looks like a line?
IOnNurbsCurve nurb_crv = OnNurbsCurve.ConstCast(crv);
if (nurb_crv != null && nurb_crv.IsPolyline() == 2)
return true;
return false;
}
/////////////////////////////////////////////////////////////////
// Test to see if a curve has the properties of an arc
private bool IsArc(IOnCurve crv, double tol, ref bool bCircle)
{
if (crv == null)
return false;
// Is the curve an arc curve?
IOnArcCurve arc_crv = OnArcCurve.ConstCast(crv);
if (arc_crv != null)
{
bCircle = arc_crv.IsCircle();
return true;
}
// Is the curve a polycurve that looks like an arc?
IOnPolyCurve poly_crv = OnPolyCurve.ConstCast(crv);
if (poly_crv != null)
{
OnPlane arc_plane = new OnPlane();
OnArc arc = new OnArc();
if (poly_crv.IsArc(arc_plane, arc, tol))
{
bCircle = arc.IsCircle();
return true;
}
}
// Is the curve an ellipse that looks like an arc?
OnPlane ellipse_plane = new OnPlane();
OnEllipse ellipse = new OnEllipse();
if (crv.IsEllipse(ellipse_plane, ellipse, tol))
{
if (ellipse.IsCircle())
{
bCircle = crv.IsClosed();
return true;
}
}
// Is the curve a NURBS curve that looks like an arc?
IOnNurbsCurve nurb_crv = OnNurbsCurve.ConstCast(crv);
if (nurb_crv != null)
{
OnPlane arc_plane = new OnPlane();
OnArc arc = new OnArc();
if (nurb_crv.IsArc(arc_plane, arc, tol))
{
bCircle = nurb_crv.IsClosed();
return true;
}
}
return false;
}
/////////////////////////////////////////////////////////////////
// Test to see if a curve has the properties of an ellipse
private bool IsEllipse(IOnCurve crv, double tol, ref bool bEllipticalArc)
{
if (crv == null)
return false;
// If curve is a polycure, get the first curve segment
IOnPolyCurve poly_crv = OnPolyCurve.ConstCast(crv);
if (poly_crv != null)
{
if (poly_crv.Count() == 1)
crv = poly_crv.SegmentCurve(0);
else
return false;
}
OnPlane ellipse_plane = new OnPlane();
OnEllipse ellipse = new OnEllipse();
if (crv.IsEllipse(ellipse_plane, ellipse, tol))
{
if (!ellipse.IsCircle())
{
bEllipticalArc = !crv.IsClosed();
return true;
}
}
return false;
}
/////////////////////////////////////////////////////////////////
// Test to see if a curve has the properties of a polyline
bool IsPolyline(IOnCurve crv, double tol, double angtol, ref int point_count,
ref bool bClosed, ref bool bDistance, ref bool bAngle, ref bool bIntersect)
{
if (crv == null)
return false;
ArrayOn3dPoint pline_points = new ArrayOn3dPoint();
IOnPolylineCurve pline_crv = OnPolylineCurve.ConstCast(crv);
IOnPolyCurve poly_crv = OnPolyCurve.ConstCast(crv);
IOnNurbsCurve nurb_crv = OnNurbsCurve.ConstCast(crv);
// Is the curve a polyline?
if (pline_crv != null)
{
if (pline_crv.m_pline.Count() <= 2)
return false;
for (int i = 0; i < pline_crv.m_pline.Count(); i++)
pline_points.Append(pline_crv.m_pline[i]);
}
// Is the curve a polycurve that looks like a polyline?
else if (poly_crv != null)
{
if (poly_crv.IsPolyline(pline_points) <= 2)
return true;
}
// Is the curve a NURBS curve that looks like a line?
else if (nurb_crv != null)
{
if (nurb_crv.IsPolyline(pline_points) <= 2)
return false;
}
else
{
return false;
}
// Is the curve closed?
bClosed = crv.IsClosed();
// Get the vertex count
point_count = (bClosed ? pline_points.Count() - 1 : pline_points.Count());
// Test for self-intersection
ArrayOnX_EVENT x = new ArrayOnX_EVENT();
bIntersect = (crv.IntersectSelf(ref x) > 0 ? true : false);
// If the curve is closed, no reason to continue...
if (!bClosed)
return true;
// Test if the distance between each point is identical
double distance = 0.0;
for (int i = 1; i < pline_points.Count(); i++)
{
On3dPoint p0 = new On3dPoint(pline_points[i - 1]);
On3dPoint p1 = new On3dPoint(pline_points[i]);
On3dVector v = new On3dVector();
v = p0 - p1;
double d = v.Length();
if (i == 1)
{
distance = d;
continue;
}
else if (Math.Abs(distance - d) < tol)
continue;
else
{
distance = OnUtil.On_UNSET_VALUE;
break;
}
}
// Set return value
bDistance = (distance == OnUtil.On_UNSET_VALUE) ? false : true;
// Test if the angle between each point is identical
double angle = 0.0;
for (int i = 1; i < pline_points.Count() - 1; i++)
{
On3dPoint p0 = new On3dPoint(pline_points[i - 1]);
On3dPoint p1 = new On3dPoint(pline_points[i]);
On3dPoint p2 = new On3dPoint(pline_points[i + 1]);
On3dVector v0 = new On3dVector();
On3dVector v1 = new On3dVector();
v0 = p1 - p0;
v0.Unitize();
v1 = p1 - p2;
v1.Unitize();
double a = AngleBetweenVectors(v0, v1);
if (i == 1)
{
angle = a;
continue;
}
else if (Math.Abs(angle - a) < angtol)
continue;
else
{
angle = OnUtil.On_UNSET_VALUE;
break;
}
}
// Set return value
bAngle = (angle == OnUtil.On_UNSET_VALUE) ? false : true;
return true;
}
/////////////////////////////////////////////////////////////////
// Test to see if a curve has the properties of a NURBS curve
private bool IsNurbsCurve(IOnCurve crv)
{
if (crv == null)
return false;
IOnNurbsCurve nurb_crv = OnNurbsCurve.ConstCast(crv);
if (nurb_crv != null)
return true;
return false;
}
/////////////////////////////////////////////////////////////////
// Calculates angle (in radians) between two 3-d vectors
private double AngleBetweenVectors(On3dVector v0, On3dVector v1)
{
v0.Unitize();
v1.Unitize();
double dot = OnUtil.ON_DotProduct(v0, v1);
// Force the dot product of the two input vectors to
// fall within the domain for inverse cosine, which
// is -1.0 <= x <= 1.0. This will prevent runtime
// "domain error" math exceptions.
dot = (dot < -1.0 ? -1.0 : (dot > 1.0 ? 1.0 : dot));
return Math.Acos(dot);
}
}
}
| ||||
| Last Modified [9/11/2008] rename · changes · history · subscriptions · references · file upload | |||||