Could there be a .ToDoubleArray methods in the Mesh.Vertices?

I’m doing a cpp + c# mixed programming to import some cpp code into Grasshopper plugins.
It is a bit painful that I always need to convert the list of vertices in Point3d first and then to a C array.

There’s a .ToFloatArray methods in Mesh.Vertices which convert the vertices into float array directly, is it possible to add a similar one for double?

I know that I can set mesh properties to store double for mesh vertices. What I want is a conversion methods.

You can interop the complete mesh to C++ side. If double precision vertices are used, you access these in C++ from the m_dV array.

In C# you can get the pointer of the mesh:

      Mesh m = null; // of course, your mesh is defined here.
      IntPtr p = Rhino.Runtime.Interop.NativeGeometryNonConstPointer(m);
      CallCFunction(p);

In C#, you can call this

    [DllImport("CPlusPlus.dll")]
    private static extern void CallCFunction(IntPtr pMesh);

If you have a C++ DLL called CPlusPlus.dll with the following code

extern "C" // use this to prevent C++ name mangling: C# needs to call the function by its unmangled name
{
  __declspec(dllexport) void CallCFunction(ON_Mesh* pMesh)
  {
    // do something in C++ with the mesh's double precision verts
    if (m->HasDoublePrecisionVertices()) 
    {
       ON_3dPointArray& doublePrecisionVerts = pMesh->m_dV;
    }
  }
}
1 Like

Do I need to Marshal.FreeHGlobal(p) after I finish?
(This IntPtr of the mesh is a managed one, correct?)

And may I ask what is this ON_Mesh type?
Does this mean I need to import the opennurbs lib on my cpp side?

OK, I installed the Rhino7 SDK, but I cannot find any tips on adding the SDK to my existing cpp project here: C/C++ Guides with C/C++

Could anyone point out how to do it?

Hi @xliotx,

Maybe this helps?

public static class MeshExtensions
{
  public static double[] ToDoubleArray(this Mesh mesh)
  {
    if (!mesh.Vertices.UseDoublePrecisionVertices)
      return new double[0];

    var rc = new double[mesh.Vertices.Count * 3];
    int index = 0;
    for (var i = 0; i < mesh.Vertices.Count; i++)
    {
      var pt = mesh.Vertices.Point3dAt(i);
      rc[index++] = pt.X;
      rc[index++] = pt.Y;
      rc[index++] = pt.Z;
    }
    return rc;
  }
}

You can use like this:

protected override Result RunCommand(RhinoDoc doc, RunMode mode)
{
  var filter = ObjectType.Mesh;
  var rc = RhinoGet.GetOneObject("Select mesh", false, filter, out var objref);
  if (rc != Rhino.Commands.Result.Success || null == objref)
    return rc;

  var mesh = objref.Mesh();
  if (null == mesh || !mesh.Vertices.UseDoublePrecisionVertices)
    return Result.Cancel;

  var doubles = mesh.ToDoubleArray();
  foreach (var d in doubles)
    RhinoApp.WriteLine(d.ToString());

  return Result.Success;
}

– Dale

@dale
Thanks.

Where should I put the MeshExtension class?

I tried to put it outside my namespace where the conversion of mesh vertices happens, but it doesn’t work.

BTW, I guess you’re the man who is in charge of the opennurbs?
I tried to build it and use it in my project somehow, but the compilation works in debug mode, not the release mode, saying

LNK1181 cannot open input file '<OPENNURBS_PUBLIC_LIBS_DIR>\bin\x64\Debug.obj'

Not sure why the release mode will try to find a Debug.obj file…

I’m writing a cpp+c# plugin for Grasshopper, so not sure how the example can be applied to a mesh loaded through Grasshopper…

I’d put the extension class inside your namespace.

More on extension methods:

If this is the case, then you must link with the version of openNURBS that comes with Rhino, not build and link some other version into your DLL. The easiest way to do this is to build a Rhino-dependent DLL.

– Dale

You could use the MeshUnsafeLock class if you want to directly stream the arrays to C++

Is there an example to use it?
Check the docs, but I’m a bit new to C#…
image

Mesh msh = .......; // Some mesh
using var meshRawData = msh.GetUnsafeLock();
var ptrToP3d = meshRawData.VertexPoint3dArray(out var verticeCnt);
...

But pay attention ptrToP3d is a Point3d* rather than Point3d[]. You probably want to memcpy later.

Pay attention on what you want to do here. Raw memory manipulation is quite dangerous in C# and may be slow than expected. I’d recommend C++/CLI if you are unfamliar with C#.

Thanks for the tips.
I’m using cpp, but need to bring the mesh I get from Grasshopper into the C++ world first.
And that’s what I’m actually doing…

OK, problem solved, thank you everyone!

Two approaches are working:

  1. Could there be a .ToDoubleArray methods in the Mesh.Vertices? - #6 by dale
    Build the first class method, and then do
double[] tar = MeshExtensions.ToDoubleArray(my mesh)
  1. Could there be a .ToDoubleArray methods in the Mesh.Vertices? - #12 by gankeyu
    And process on the point array.

I would use reflection to call Mesh's .(Non)ConstPointer() which can be converted to the C++ ON_Mesh object.

This will require to integrate opennurbs into my cpp project, which after trying yesterday, didn’t succeed…
The doc on the website is not very clearly written and if I follow the process, differen’t kinds of errors always occur. For instance, this:

@menno Is there a similar approach to get the pointer of C# containers, like List<Point3d>?

I assume the corresponding openNURBS class should be ON_3dPointArray, but cannot find the command to do the conversion.

To be honest, I don’t exactly know. Maybe you can get a pointer, but you need to make sure that the garbage collector doesn’t touch it, so you need to pin the pointer until you ar done in c++.
If you search for terms like marshalling and pointer pinning, maybe something useful turns up.

Another thing to look at is what rhino provides in the Rhino.Runtime.Interop class and the interop wrappers

1 Like

Ah, thanks for pointing out the InterpoWrappers. I didn’t know that.
Yes, that namespace contains all I need.

Problem solved.

1 Like

How come the Rhino.Runtime.InteropWrappers have SimpleArrayPoint3d, but not SimpleArrayVector3d ???