DivideByLengthPoints script question

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)

        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]
    return Rhino.Commands.Result.Success

if __name__=="__main__":

objref is an object, an instance of the class ObjRef.

That class has constructors, properties and methods

One of those methods is Curve()

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];
        if (ccx_event.PointA.DistanceTo(ccx_event.PointB) > double.Epsilon)
          doc.Objects.AddLine(ccx_event.PointA, ccx_event.PointB);
    return Rhino.Commands.Result.Success;

Actually this is the result of the method Object() for the GetObject Class


That returns an array of ObjRefs in this case 2 as there is a limt of min-max selected objects of 2:

Does this make sense?

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

EDIT: I created a new topic: What is the relationship between Rhino.Geometry, Rhino.Input and ObjRef