Custom Vector class. Display in Rhino view port

Hi guys,

I have a custom Vector class I have written in VS and I want to know how can I display it to the Rhino view port. What I am looking for is identical to how a Point3d would be “automatically” displayed. Please give me any pointers on which classes from the GH API I need to derive from.

Thanks!

Say that the class is named CV, has a CV.Vector as Vector3d and there’s a List of type CV named cvList.

Then:

Then add the vectors to your points or do whatever else

@PeterFotiadis
thanks for your reply but that’s not what I am after. Perhaps I wasn’t very clear. I have a totally different Vector class than RhinoCommon’s Vector3d. So what I want to do is to be able to display a vector with a “point flavor” to the Rhino view port. So I guess I have to inherit from IGH_Goo so it can be displayed as such. But it would be nice to not have to make it in to a parameter that implements the Goo type

Well … still I can’t get it since in order to display something in R you need to use something that R understands … but … anyway can you provide a snapshot of the class definition?

Exactly! that’s precisely what I want to know. How can my class be understood by Rhino. Attached is the class

Vec3.cs (24.6 KB)

Er … like this?

Or

Obviously making the v3List is just a naive demo (make it with any way you want)

But the 1M Q is : IF the whole thing/task/goal/whatever is relatively simple … why using VS? (You reinvent the wheel in several places in that Vec3 thingy).

Actually this Vec3 class is part of a larger library I am developing, I am also in the process of adding more methods then the Vector3d class of RhinoCommon. That is the reason why I wrote my own Vector class.

Actually what I want to avoid is precisely what you did, at the moment that is my work around, I just would not like to deal with actually having to access each property (X,Y,Z) to then create a Vector3d, and a Vector3d list to contain them. I think this could be quite expensive when dealing with many instances. That’s why I would like to know how can I display a Vec3 and completely ignore Vector3d . Perhaps a better question would be: How does a Vector3d/ Point3d get displayed to the Rhino view port? My guess is that somewhere IGH_Goo is used but I don’t know exactly in which part of the code I should implement it

Well … for “similar” cases (collections with 1-10+ M items - or way more: FEA and the likes) and using custom “similar” classes it’s a matter of few milliseconds for doing some List by accessing some class properties. If you use an I9 or a Ryzen the Elapsed time is almost not measurable - more or less. On the other hand if you do something without a good // processing approach … all King’s horses and all King’s men etc etc.

Other than that … what R has to do with IGH_Goo is a big question (Rhino does what Rhino knows so you are attempting to avoid shooting your left foot only to discover that you’ve done it to the right one [time for boxing/unboxing]).

Here’s a small demo on the cost of accessing properties using an old i5 (I always use the slowest stuff available to test things).

Class_FromHereToThere_V1.gh (5.5 KB)

And here’s the V1A that allows you to fly from DC to NY via LA (or not). For 200K items the cost is about 3 milliseconds (i9) or 10 (that crap old i5). On the other hand displaying 200K items via a crap GPU …

Class_FromHereToThere_V1A.gh (116.1 KB)

Well… funny enough displaying 1,000,000 Vector3d’s is always quicker even though I create each instance accessing the properties of my Vec3 class… I wonder why

But It still does not make sense to create 2 lists just to output some vectors… why occupy more memory then needed. So I am still curious about displaying Vec3 by IGH_GOO and thus not create a Vector3d class.

    Random ran = new Random();


    System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    sw.Start();
    List<Vec3> myVec = new List<Vec3>();
    for (int i = 0; i < N; i++)
    {
      myVec.Add(new Vec3(ran.NextDouble(), ran.NextDouble(), ran.NextDouble()));
    }

   
    sw.Stop();
    Print("Total milliseconds to create Vec3 List: {0}", sw.ElapsedMilliseconds);

    if(run)
    {
      sw.Reset();

      sw.Start();
      List<Vector3d> rhinoVec = new List<Vector3d>();
      foreach (var item in myVec)
      {
        rhinoVec.Add(new Vector3d(item.X, item.Y, item.Z));

      }


    
      sw.Stop();
      Print("Total milliseconds to create Vector3d List: {0}", sw.ElapsedMilliseconds);


    }

On the contrary > you should use ALWAYS more resources than needed > in order to buy more stuff than you need, more cores, more this + more that == progress from what I’m told ( I consume , therefore I am).

Moral: more.

F[quote=“rawitscher-torres, post:7, topic:82255”]
I am also in the process of adding more methods then the Vector3d class of RhinoCommon. That is the reason why I wrote my own Vector class.
[/quote]

Have you considered extension methods?

There’s two apis you’re dealing with here. First there’s the Grasshopper part which will handle preview and baking for data types which provide the necessary interface implementations. Basically, implement the right methods and all that stuff comes free of charge, albeit at a performance cost.

Then you’re dealing with the Rhino display SDK, which knows nothing about Grasshopper. It does however only accept RhinoCommon types when it comes to drawing lines, arrowheads etc.

You can get rid of the performance overhead caused by the individual IGH_Goo access by caching data which displays as quickly as possible in the Rhino viewport. This data will necessarily have to be cached in a custom parameter which understands your data and which can store large amounts of it in arrays. Pumping arrays with coordinates to the display will always be much quicker than iterating over them and drawing lines one by one.

Performance. Either you bite the bullet and iterate over your data to invoke draw calls per vector, or you cache your millions of vectors in a memory format which is understood by the Rhino display.

General question; your vector class only has three double fields as far as I can work out, do you just want to draw all your vectors anchored to the origin?

Final observation; since you’re so concerned with performance, I think you should keep in mind that in the future you will want to use this vector type within multi-threaded algorithms. That will become a lot easier if you design your types to be immutable. The RhinoCommon Vector3d struct is not immutable, so creating a new vector type makes a lot more sense if it is different in this way. Additional benefits of immutable vectors are that you can cache values like the hash code or the length, in case you need to access those properties a lot.

Doing a quick pass through your code and making it immutable. Have a look, maybe you like this approach… Vec3.cs (5.3 KB)

edit: ugh, 51 is not prime…

Hi David,
thanks for jumping in and for taking the time to modify my Vector class in an impressive time!.

Concerning your first point about the Grasshopper and Rhino display part, I already have a GH parameter for my Vec3 type, but the Vector/s are still not displayed in the view port. I also noticed that in the IGH_PreviewData, for example in the DrawViewportWires() , DrawPoint() only accepts RhinoCommon types as you clarified, so I guess this is the reason why my Vec3 type is not being displayed? Obviously I haven’t been able to implement DrawPoint() yet.

  public void DrawViewportWires(GH_PreviewWireArgs args)
        {

            args.Pipeline.DrawPoint(…..);
        }

I would like to display a Vec3 at its corresponding origin in Cartesian space. As a “pertinent” note, what I would like to achieve, if possible, is to be able to display Vec3 at its corresponding origin in cartesian space with a point flavour and its magnitude/direction with an arrow head with the lowest performance cost as possible.

Which performance cost would this be?

On another hand, I am rather puzzled and probably I did not get your point accurately when you suggested to make my Vec3 immutable. I don’t understand why you are suggesting that because this class is used to store positions of physics objects that are going to change positions all of the time. So in my understanding, this would be computationally expensive because a immutable type cant be altered. When a mutable type is changed it will actually create a new instance beforehand. I actually also did a quick experiment on the classical mutable and immutable types in .NET String and StringBuilder. The difference is abruptly different

  Stopwatch sw = new Stopwatch();
    if(immutable)
    {


      sw.Start();
      string t = "";


      for (int i = 0; i < iterations; i++)
      {
        t += "d"; // operation will create a new instance, initial object t cant be altered. ie slower perfomance


      }


      I = t;

      sw.Stop();
      Print("Total milliseconds immutable: {0}", sw.ElapsedMilliseconds);

    }


    sw.Reset();
    if(mutable)
    {
      sw.Start();
      StringBuilder s = new StringBuilder("a", iterations);

      for (int i = 0; i < iterations; i++)
      {
        s.Append("g");// will modify the same object s. ie faster performance
      }

      M = s;
      sw.Stop();
      Print("Total milliseconds mutable: {0}", sw.ElapsedMilliseconds);

Anyways… I am sure I did not get your point correctly.

The cost of looping through all data on every redraw and drawing each one individually. You can speed this up significantly by building (and caching) your own lists of points to draw.

Yes, that is the point of immutable types. You get a lot of safety from the fact that once it exists, it cannot be altered. Imagine two threads operating on the same data, one is moving a point (or Vec3) to different x and y coordinates, while the other is calculating the distance from that vector to some other coordinate. Since this code runs in different threads, and since assigning two separate properties is not an atomic operation, the distance measuring code may use the old x and the new y in its own calculations, yielding a distance which is incorrect for both the old and the new state. Good luck trying to debug that…

The creation of new objects (especially structs) is not that expensive, whereas having mutable types may result in all manner of unpredictable and unrepeatable threading bugs.

Switching to immutable types does often requires a different coding approach, which is why Microsoft added a StringBuilder class to speed up the piece wise composing of longer strings. But there’s performance benefits associated with immutability as well. For example it becomes much easier for many objects to share the same data. If Rhino meshes were immutable, a transformed mesh would not have to duplicate its face and vertex-colour arrays, as those properties are not affected by transformations. Less memory = good, and less memory to copy around = faster.