Fastest way to evaluate distance between 2 projected points?

Hello, I’m developing a tool for internal use to create a distance map between two meshes by Z axys. So I scripted it with python but the performance is very poor because there are a lot of pooints to evaluate. Here my script code:



import math
import rhinoscriptsyntax as rs

passo = 0.02 #map resolution

meshApp = rs.GetObject("Mesh iniziale", rs.filter.mesh) #import upper mesh
meshInc = rs.GetObject("Mesh incisa", rs.filter.mesh) #import lower mesh

startPoint = rs.GetPoint("Start point alto dx") #upper right corner
endPoint = rs.GetPoint("End point basso sx") #lower left corner
scanAreaX = abs(endPoint[0]-startPoint[0])
scanAreaY = abs(endPoint[1]-startPoint[1])

samplesX = int(math.ceil(scanAreaX/passo)) #sample points X
samplesY = int(math.ceil(scanAreaY/passo)) #sample points Y

file = open("c:\\test.txt", "w")
for i in range(0,samplesX):  #to iterate between 0 to samplesX
    for j in range(0,samplesY):
        file = open("c:\\test.txt", "a")
        basePoint = (endPoint[0]+i*passo,endPoint[1]+j*passo,0)
        # project down...
        point1 = rs.ProjectPointToMesh(basePoint, meshApp, (0,0,-1))[0]
        point2 = rs.ProjectPointToMesh(basePoint, meshInc, (0,0,-1))[0]
        distance = rs.Distance(point1, point2)
        file.write(str(distance))
        file.write('\n')
        file.close()


So the script get two meshes and, starting from lower left corner, begins to project a point on the two meshes and calculates the distance between the points. The result is outputted to a TXT file. Each line a distance.
Looks like the projectPointToMesh is very heavy. I’m thinking about building the same tool as a C# plugin but I’d like to know if this could lead to a good performance impovement. Also maybe there is a way to achieve the same result in a faster way.
Thank you very much!

If you’re going to open a file every time the inner loop runs then I’m not surprised it’s slow. You should collect your results in a list during the looping and only write it to a file afterwards.

1 Like

Yep you’re right! I used it for some kind of debug (watching hte file grow in size) because on first trial it seemed frozen… I changed it but the speed is still far from my dreams. Do you think making the same stuff with a c# plugin would be faster?

Doing this in a C# plug-in probably isn’t going to be too much faster.

Another thing you can to to improve performance is to rs.ProjectPointToMesh once (with all of your test points) instead of within every loop.

OK. If some points are not “over” the mesh I want to project on and the projection fails do I get an error for all the projections or I get a list with the projected points? The mesh could be not a complete square and I need to know wich points are off the mesh.

Newer version of Rhino (and RhinoCommon) have a new ProjectPointsToMeshesEx function that will not only project points to meshes, it will return he indices of the input points that actually hit something.

There is no Python support for this new function at this time. But, you can write your own easy-to-use wrapper (see below).

In this example, the main function adds the projected points and then draws a line between the projected point and the source point.

import Rhino
import rhinoscriptsyntax as rs
import scriptcontext

# Our new and improved ProjectPointToMeshEx function
def ProjectPointToMeshEx(points, mesh_ids, direction):
    pts = rs.coerce3dpointlist(points, False)
    if pts is None:
        pts = [rs.coerce3dpoint(points, True)]
    direction = rs.coerce3dvector(direction, True)
    id = rs.coerceguid(mesh_ids, False)
    if id: mesh_ids = [id]
    meshes = [rs.coercemesh(id, True) for id in mesh_ids]
    tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    rc = Rhino.Geometry.Intersect.Intersection.ProjectPointsToMeshesEx(meshes, pts, direction, tolerance)
    return rc

if __name__ == "__main__":
    points = rs.GetPointCoordinates("Select points to project")
    mesh = rs.GetObject("Select mesh to project onto", rs.filter.mesh)
    rc = ProjectPointToMeshEx(points, mesh, (0,0,-1))
    if rc:
        pts = rc[0]
        idx = rc[1]
        for i in range(len(pts)):
            rs.AddPoint(pts[i])
            rs.AddLine(pts[i], points[idx[i]])

Does this help?

I’m trying to move to C# to get everything on a plugin because actually the pythonscript write a txt that I process with a c# application for my needed final result. I’m having problems with

Point3d projectedPoint1 = new Point3d(Rhino.Geometry.Intersect.Intersection.ProjectPointsToMeshes(meshApp,pointToProject,projDir,0.0));

because “meshApp” is a Rhino.Geometry.mesh object while the method requires a Syste.Colletions.Generic.IEnumerable<Rhino.Geometry.mesh> and I don’t understand how to cast it.

About “ProjectPointsToMeshesEx” it could be useful if going this way speeds up everything a lot. Also I need to keep order because the txt will generate a bitmap… something like a displacement map.

Here is a C# equivalent.

https://github.com/dalefugier/SampleCsCommands/blob/master/SampleCsProjectPointToMesh.cs

Thank you Dale, actually ProjectPointsToMeshesEx() doesen’t exist on my SDK (RH5 SR9). Should I wait for next SR relase or can I pick the library somewhere?
Thak you!