Non-linear mapping from uv to xy


I am working on a delaunay-based algorithim which I would like to apply on 3D geometry -> paramertic surface (nurbs surface in rhino). The surface has no “overlaps”, thus it can be projected to cplane without self intersection. I thought I could simply map the uv-coords to xy space in order to solve the entire thing in 2D. I don’t know how to do this best. The first approach I tested is based on this gh thread:

But this simple mapping does not do the job. The distances of the points on the surface do not correspond proportionally to the distances in 2d on the xy-plane. Rebuilding the surface seems to help a little but I still think I am not getting the right result. Is there another way to do this? Maybe with some sort of transformation matrix I could generate from the surface information.


A surface U,V parameter of a surface has nothing to do with the world X,Y. U,V is simply values within a surface’s domain, and this has no collation with with a surface’s real world size.

You might want to look at the Rhino help file for information on the CreateUVCrv and ApplyCrv commands. It sounds like this is what you are looking for. Correct me if I am mistaken.

Hi Dale,

thanks for the quick response. So the help under CreateUVCrv says: “command Projects a surface’s untrimmed boundary and trim curves onto the world x-y plane. Note: The control polygon determines the sizes of the uv curves.” Hmm…
But David’s example in the in the Grasshopper forum is exactly doing this: relating the UVs to XY, no? So, is his approach working? If not, is there a 2D approach for a delaunay triangulation on a nurbs-surface in rhino or do I need to check the circumcircle test based on a local best-fit-plane for the 3d points im checking on the surface? Similar to this example:

Any help on this is very much appreciated!

He is using U,V coordinates as you would X,Y coordinates. But he is not projecting or transforming them. Thus the Voronoi solver creates points that just happen to fall within this domain. The then evaluates these points with the surface to the the real deal 3-D points. Look like a good approach…

Thanks Dale,

Sorry, I might have used the wrong words. I understand what David did. Basically:

for pt in pts:
    uvs.append(rs.SurfaceClosestPoint(srf, pt))

#do fancy delaunay stuff in 2D

for i in range(len(uvs)):
    pts[i] = rs.EvaluateSurface (srf, uvs[i][0], uvs[i][1])

But I am not sure if this gives me the correct result. If I simply pull up a few control points of a surface with equally spaced points along the diagonal as illustrated here:

I get the following UVs as 2D point coords:

So, this looks more like a projection which will cause problems if this approach is used for a delaunay triangulation in which the spacing is relevant. If I rebuild the surface I am getting the following configuration:

Here, the spacing changes gradually, which makes sense. But how can I make sure that this works on all surfaces. How do I evaluate my results?

Thanks again

I’m not sure how to answer your question. But you are basically doing what the Grasshopper definition does…