Path mapping in c#

Hi,

Im trying to step up game and after producing some very basic scripts in python Im trying c#. Anyways, 2 questions:

Grid of points.gh (5.9 KB)

  • I would welcome any tips to simplify my messy c# script producing grid of points according to input lists of distances in X, Y coordinates.
// Create list for points
Rhino.Collections.Point3dList PtList = new Rhino.Collections.Point3dList();

// Variable for loops
double xx = 0;
double yy = 0;

// List for X and Y distance values
List<double> ListXX = new List<double>();
List<double> ListYY = new List<double>();

// Add 0 coordinates to lists X, Y
ListXX.Add(0);
ListYY.Add(0);


//Loop to create List of X coordinates
for (var i = 0; i < x.Count; i++)
{
  xx = xx + x[i];
  ListXX.Add(xx);
}

//Loop to create List of Y coordinates
for (var i = 0; i < y.Count; i++)
{
  yy = yy + y[i];
  ListYY.Add(yy);
}

// Loop to generate points
for (var i = 0; i < ListXX.Count; i++)
{
  for (var j = 0; j < ListYY.Count; j++)
  {
    PtList.Add(ListXX[i], ListYY[j], 0);
  }
}


// Outputs
A = ListXX;
B = ListYY;
C = PtList;

Regards,
Dan.

Hi Daniel,

You are creating way more data and making your hardware do many more computations than needed. You can do this within a nested forloop and produce the necessary transformations on each point

Point3d [,] arr = new Point3d [rows, columns];
    for (int i = 0; i < rows; i++)
    {
      for (int j = 0; j < columns; j++)
      {
        // Perform here any arithmetic operation
        // to transform coordintes of each point
        arr[i, j] = new Point3d(i /* */, j /* */, 0 /* */);
      }
    }
A = arr;

Below the graph mapper thing

private void RunScript(List<double> x, int itemsPerBranch, ref object A)
  {
       
    A = Foo(x, itemsPerBranch);
  }

  // <Custom additional code> 
  public  DataTree<double> Foo(List<double> data, int itemsPerBranch)
  {
    if(data.Count == 0)throw new ArgumentException("data cant be null");
    DataTree<double> tree = new DataTree<double>();
    
    int c = -1;
    int pCount = 0;
    for (int i = 0; i < data.Count; i++)
    {
      c++;
      if (c == itemsPerBranch){c = 0; pCount++;}          
      tree.Add(data[i],new GH_Path(pCount));
    }
    
    return tree;
  }
  // </Custom additional code> 
}

1 Like

Hi Nicholas,

I feel like Im stuck. Ive been tinkering with the script for several hours but havent achieved the result in any way. Im not able to do the transformation for the points as I did before.

this part in particular

- loop through list x and sum the x[i] with previous values and create point with that coordinate

- same with Y list

If I try that with nested loops all I get is huge mess.

   x.Insert(0, 0);
    y.Insert(0, 0);

    int rows = x.Count;
    int columns = y.Count;
    
    double xx = 0;
    double yy = 0;     

    Point3d [,] arr = new Point3d [rows, columns];
    for (int i = 0; i < rows; i++)
    {
      for (int j = 0; j < columns; j++)
      {
        // Perform here any arithmetic operation
        // to transform coordintes of each point
        
        xx = xx + x[i];     
        yy = yy + y[j];
        
        arr[i, j] = new Point3d(i * xx, j * yy, 0);

      }
    }
    A = arr;

  Point3d [,] arr = new Point3d [rows, cols];

    double ss = 0;
    for (int i = 0; i < rows; i++)
    {
      for (int j = 0; j < cols; j++)
      {
        ss += 0.2;
        arr[i, j] = new Point3d(i, j/* */, Math.Sin(ss)/* */);
      }
    }
    A = arr;

Hi, thanks for the response, I took some time to elaborate on this.

So after more detailed research heres what I think:

  1. Your code does only the part. Your input is number of X,Y points whereas my input is DISTANCES (VARIABLE, so its not the same distance all over) of X,Y points. So to do that I need another loops to sum the distances to make coordinates. Basically it makes a good method to create grid from XY coordinates.

  2. Reviewing why you used arrays intstead of lists I thought about this: many articles refer to array to be faster than lists. I compared it and there was no significant difference (in magnitude of decimals of %). But in some other cases it may be waaay more, so in general its a right approach I think. So arrays seem to does not matter for speed in this. But I will use them anyway instead of lists. From what I understand array allocates chunk of memory whereas list stores values here and there (scattered arround) in memory.

  3. I need to generate about 100k + of points which takes long (order of seconds). Even just your script takes about 963ms to create 108000 points (given my machine performance). Script embedded in grasshopper to construct point takes 125ms to create 117000 points (same computer with same performance).

Question is, is there any other faster way to create points in c#? Seems like for loop is slow slow approach itself.

Dan.

Hi Daniel,

in response to your points.

  1. The example I sent, is just an example showing you how you can create a collection of points applying whatever transformation you provide. I attached another file for you to explore. The rest, you should modify to your needs and boos your learning process.

PtTrans_Forum.gh (8.7 KB)

  1. I used a multidimensional array, just because I wanted to. In general:

Arrays are good to use when you know the number of elements and know that the array is unlikely to change, or will never change.

Some properties:

  • Fixed Size
  • Fast Access O(1)
  • Slow Resizing O(N)
  • needs to copy every element to a new array
  • Continuous memory allocation
  • Occupies less memory

Lists are good when you collection will vary or are unsure if it will do during a program;

Some properties:

  • Dynamic Size
  • Fast Access O(1)
  • Fast Resizing O(Log N) this is the reason why its cheap to add or remove elements in a List
  • Non - continuous memory allocation
  • Occupies more memory
  1. There are several ways to boost performance on this issue, in the file I attached I I outputted GH_Point instead of Point3d. To display 1 million points it takes strictly 170 ms

You can further optimize this by not sending any data as an output and simply override :

 public override BoundingBox ClippingBox
  {
   
  }


  public override void DrawViewportWires(IGH_PreviewArgs args)
  {

  }

With this technique I have displayed 64 million points in just 2 seconds or 8 million points in 171 ms

Anyways, the rest is just history and there are endless discussions about micro optimizations out there. Do note, that the C# component compiles in debug mode, so to boost measurements and be more precise on this you will need to create a compiled component in Visual Studio. And If you are really interested of performance learn C++ and forget about Python

1 Like

Hi again,

Thank you for this thorough explanation, great source for improvement. GH_Point does the trick.

One thing that blow my mind is this:

ptArr[i, j] = new GH_Point(new Point3d(arrX[i], arrY[j], 0));

How come its faster if theres nested Point3d in GH_Point. Seems illogical to me. Maybe a short explanation on why GH_Point is faster than Point3d itself would help.

I’ve been playing around with Visual Studio and C#. I really like its intellisense and I must say I nearly hate basic C# script editor in GH :slightly_smiling_face: . It has near to none smart predictions. Is it possible to somehow use VS for C# scripts in GH interactively? I know I can create components for GH but its slow in reviewing. It takes to start rhino and GH every time I want to preview changes, which is very slow.

Thank you,
Dan.

Its a good question, because GH_Point is a class while Point3d is a struct which can trick in thinking it has better performance. Indeed Point3d rquires less resources because it will be allocated in the stack and not on the heap (loosely speaking) meaning it will not be GC’s business in the near future. But internally Grasshopper has to cast Point3d to GH_Point in order to display it. By being a good friend to Grasshopper you can provide it a GH_Point to save it some work .

I have seen some discussions about what you are asking check this one

But I am not sure if you can still use the debugger, so if you cant I think its not useful.