I started comparing the two languages C# and Python and there is something strange.
How does Python know the type of variable: crv = objref.Curve()
while in C# we properly specified it; Rhino.Geometry.Curve crv = objref.Curve();
Why do we need to use the (dot) .Curve as we already used the Curve filter before. C# - version
using Rhino.DocObjects;
partial class Examples
{
public static Rhino.Commands.Result DivideByLengthPoints(Rhino.RhinoDoc doc)
{
const ObjectType filter = Rhino.DocObjects.ObjectType.Curve;
Rhino.DocObjects.ObjRef objref;
Rhino.Commands.Result rc = Rhino.Input.RhinoGet.GetOneObject("Select curve to divide", false, filter, out objref);
if (rc != Rhino.Commands.Result.Success || objref == null)
return rc;
**Rhino.Geometry.Curve crv = objref.Curve();**
if (crv == null || crv.IsShort(Rhino.RhinoMath.ZeroTolerance))
return Rhino.Commands.Result.Failure;
double crv_length = crv.GetLength();
string s = string.Format("Curve length is {0:f3}. Segment length", crv_length);
double seg_length = crv_length / 2.0;
rc = Rhino.Input.RhinoGet.GetNumber(s, false, ref seg_length, 0, crv_length);
if (rc != Rhino.Commands.Result.Success)
return rc;
Rhino.Geometry.Point3d[] points;
crv.DivideByLength(seg_length, true, out points);
if (points == null)
return Rhino.Commands.Result.Failure;
foreach (Rhino.Geometry.Point3d point in points)
doc.Objects.AddPoint(point);
doc.Views.Redraw();
return Rhino.Commands.Result.Success;
}
}
Python - version
import Rhino
import scriptcontext
def DivideByLengthPoints():
filter = Rhino.DocObjects.ObjectType.Curve
rc, objref = Rhino.Input.RhinoGet.GetOneObject("Select curve to divide", False, filter)
if not objref or rc!=Rhino.Commands.Result.Success: return rc
**crv = objref.Curve()**
if not crv or crv.IsShort(Rhino.RhinoMath.ZeroTolerance):
return Rhino.Commands.Result.Failure
crv_length = crv.GetLength()
s = "Curve length is {0:.3f}. Segment length".format(crv_length)
seg_length = crv_length / 2.0
rc, length = Rhino.Input.RhinoGet.GetNumber(s, False, seg_length, 0, crv_length)
if rc!=Rhino.Commands.Result.Success: return rc
t_vals = crv.DivideByLength(length, True)
if not t_vals:
return Rhino.Commands.Result.Failure
[scriptcontext.doc.Objects.AddPoint(crv.PointAt(t)) for t in t_vals]
scriptcontext.doc.Views.Redraw()
return Rhino.Commands.Result.Success
if __name__=="__main__":
DivideByLengthPoints()
This method is called by the .Curve() syntax as a suffix after the instance. It will return a Rhino Curve object if the ObjRef references a Curve. If not it will return Null.
If I’m not mistaken, c# will throw an exception if there is no curve object returned because you have to define in advance what type of object your variable will be. Or at least it can only be the defined type or Null.
Hence the need to set the type before the variable declaration.
Contary to c# , Python does not know what crv is supposed to be and does not care.
If you want to be lazy in C# you can use var to have the compiler infer the type. The type will still be Curve in the case mentioned, and the variable is still statically typed - just less typing for you.
So, according to my understanding Python is looking up the Class that has the .Curve Method automatically.
I am just wondering if the ObjRef Class has the only named .Curve Method. I think, Yes.
I have found another script where the .Curve is typed as a method or Property of the Rhino.Input.Custom.GetObject() Method but it does not exist.
It is in the 14th and 15th row.
partial class Examples
{
public static Rhino.Commands.Result IntersectCurves(Rhino.RhinoDoc doc)
{
// Select two curves to intersect
var go = new Rhino.Input.Custom.GetObject();
go.SetCommandPrompt("Select two curves");
go.GeometryFilter = Rhino.DocObjects.ObjectType.Curve;
go.GetMultiple(2, 2);
if (go.CommandResult() != Rhino.Commands.Result.Success)
return go.CommandResult();
// Validate input
var curveA = go.Object(0).Curve();
var curveB = go.Object(1).Curve();
if (curveA == null || curveB == null)
return Rhino.Commands.Result.Failure;
// Calculate the intersection
const double intersection_tolerance = 0.001;
const double overlap_tolerance = 0.0;
var events = Rhino.Geometry.Intersect.Intersection.CurveCurve(curveA, curveB, intersection_tolerance, overlap_tolerance);
// Process the results
if (events != null)
{
for (int i = 0; i < events.Count; i++)
{
var ccx_event = events[i];
doc.Objects.AddPoint(ccx_event.PointA);
if (ccx_event.PointA.DistanceTo(ccx_event.PointB) > double.Epsilon)
{
doc.Objects.AddPoint(ccx_event.PointB);
doc.Objects.AddLine(ccx_event.PointA, ccx_event.PointB);
}
}
doc.Views.Redraw();
}
return Rhino.Commands.Result.Success;
}
}
The index numbers are make sense, however we also put the .Curve() after go.Object(0) that I do not understand
In this case the type of the curveA variable should be;
ObjRef curveA = go.Object(0).Curve(); because there is no “.Curve” Method for Rhino.Input.Custom.GetObject(); but for ObjRef .
I tried the plugin in Visual Studio and I have got an exciting result.
I left the 14th as it is and I removed .Curve from the 15th row.
When I moved the cursor onto the var on the 14th row it was Rhino.Geometry.Curve Type and in the 15th it was Rhino.DocObject.ObjRef. I think it converts Rhino.Input.Custom.GetObject to Rhino.Geometry.Curve when we put the.Curve() ObjRef Type.
...
var curveA = go.Object(0).Curve(); Type: Rhino.Geometry.Curve
var curveB = go.Object(1); Type: Rhino.DocObject.ObjRef