U/V directions transposed on revolve feature [Solved]

I’m trying to extract NURBS data from a Rhino file using openNURBS. My approach usually goes well, but I have run into a surface on which the trimming curves look slightly off. In fact, I have found that the problem seems to apply to all “revolved” surfaces. Investigating the data, I was surprised to find that the domain of the U and V seem to have been swapped!

To take a concrete example, let’s say I make a vertical line from (50,0,0) to (50,0,20). Using the Revolve command, I make a surface by setting the revolve axis to (0,0,0)-(0,0,20) with default angles. I now have a broad, uncapped cylinder.

When extracting NURBS data from this object, I would expect it to have a domain which is broad on one side, representing the 360 degree sweep of the revolve, and narrower on the other, presumably from 0 to 20, representing the height of the “cylinder”. Any trimming curves on the surface would therefore have their u,v coordinates in this domain.
When I extract the NURBS data from the surface in question, this is the domain I find:
u: 0.000000-20.000000, v: 0.000000-314.159265
So on the face of it this makes sense. 0-20 matches the height and 0-100pi the direction of revolution.

The problem becomes apparent when I trim the surface. Let’s say I make a closed polyline between these points:
(0,0,10), (0,0,15), (0,5,10)
This describes a triangle in the center of the cylinder. Then I use the Trim tool to cut the majority of the cylinder, leaving me with two curved triangles. For sake of simplicity, I’ll delete one of them. When I get the uv control points for the remaining surface, I get the following:
Trim 0:
Point 0: 0.000000, 235.619449, 0.000000
Point 1: 0.000000, 157.079633, 0.000000
Trim 1:
Point 0: 0.000000, 157.079633, 0.000000
Point 1: 0.106281, 157.079633, 0.000000
Point 2: 0.212562, 157.079633, 0.000000
Point 3: 0.318843, 157.079633, 0.000000
Trim 2:
Point 0: 0.318843, 157.079633, 0.000000
Point 1: 0.212205, 183.259570, 0.000000
Point 2: 0.106103, 209.439510, 0.000000
Point 3: 0.000000, 235.619449, 0.000000
Now, the triangle starts halfway up the surface and is a quarter of the height. If the U (0-20) domain is the vertical, we would expect the U-coordinates to range betwen 10 and 15. Similarly, if the V (0-314) domain is the revolved length, we would expect the V-coordinates to lie somewhere in the start of this interval, say 0-10.
These values do not. Instead it becomes apparent that 0-20 represents the width and 0-314.15926 the height!

For comparison, here’s an identical-looking surface made from an extruded circle, rather than a revolved line:
Object 0 (on Default):
BREP 0:
Domain: u: 0.000000-314.159265, v: 0.000000-20.000000
Loop 0:
Trim 0:
Point 0: 0.000000, 15.000000, 0.000000
Point 1: 0.000000, 10.000000, 0.000000
Trim 1:
Point 0: 0.000000, 10.000000, 0.000000
Point 1: 1.818104, 10.000000, 0.000000
Point 2: 3.636207, 10.000000, 0.000000
Point 3: 5.454311, 10.000000, 0.000000
Trim 2:
Point 0: 5.454311, 10.000000, 0.000000
Point 1: 3.656060, 11.674260, 0.000000
Point 2: 1.841413, 13.342146, 0.000000
Point 3: 0.000000, 15.000000, 0.000000
Much better!

Now, all of this is puzzling, but not necessarily wrong. These two representations could well be creating the same surface. The problem is that they don’t. Visualizing these NURBS in the our own program, I found that the odd revolve trims are ever so slightly off in relation to the triangle data (and the extruded version), which is the real problem.

It’s a little hard to describe and, of course, you’d be forgiven for thinking that we’re simply misinterpreting the data on our end. So I have made a Rhino file to illustrate the problem:
First I create a square from two corners: (0,0,0) - (20,314.15926)
Then I create a closed polyline from three points: (0.000000, 235.619449, 0.000000), (0.000000, 157.079633, 0.000000), (0.318843, 157.079633, 0.000000)
Then I create two cylindrical surfaces like in the previous example. One from a revolve and one from an extrude.
Finally, I apply the curves to the surfaces using _ApplyCrv.
The result shows the problem I’m talking about. The triangle is slightly narrower on the revolve feature:

(Screenshot from Rhino)
I would have expected these curves to give rise to the same shape on the surface when mapped onto it as UV-values. Bizarrely, they do not. This would seem to indicate that there is some special case with revolve features that our own program is not taking into account.

So in short, my questions are:
Why is the domain of a revolve feature shifted in this way?
Am I doing anything wrong in retrieving the trim data? Can the process be improved?
Could it instead be the way we display NURBS data in our program that is at fault? Are we falling into some common trap, perhaps?

Thanks in advance,

  • Sean

I have attached the following files:

“revolveTest.cc” - a very simple test file showing how I retrieve the above data with openNURBS.
“revolvesurf.3dm” - A file containing two triangles produced as above. Running the revolveTest program with this file as argument produces the data shown above.
revolveTrims.rar (15.4 KB)

I’m not really clear what you’re trying to do in the long run here, so this may or may not address what you need.

When you make a surface of revolution, the parameterization is as you said - u = axis length and v = 2 * pi * r of the circle.

When you make an extrusion by extruding a circle, the parameterization is u = the circle’s parameterization and v = the extrusion vector length. If you just drew a circle and didn’t mess with its parameterization, it will also be 0 - 314 around the u direction.

When you convert either of those to a nurbs surface, which is what the calll to NurbsSurface() does, the shape and u and v directions of the surface are the same as the starting revolved or extruded surfaces.
The one that came from a revolved surface will have v around the circumference and the one from an extrude will have u around the circumference,

When you make a cylinder and a 3d triangle, and use Trim to cut the cylinder away, the triangle is projected onto the cylinder, and the part of the cylinder that’s left is a little longer measured along the surface than the flat triangle was.
So you have mapped the 3d coordinates (0,0,10), (0,0,15), (0,5,10) onto a slightly bigger part of the cylinder surface than the triangle was to start with.

Thanks for the answer, lowell. I realize that I’m groping slightly blindly here and appreciate the feedback. :smile:
So, just to summarize, due to the way the surfaces are converted with NURBSurface(), the result shown in the following diagram is the expected result:

If so, then that’s fine. As I say, this isn’t a problem per se, but it was kind of unexpected and may have been obscuring the issue for me. I’m glad we can nail that one shut, but it does leave me with the problem of the trimming curves being slightly off.

Firstly, to motivate this a but more: I’m writing an importer for Rhino files which attempts to retrieve NURBS data and write it to our own NURBS format. The end goal is to display surfaces created in Rhino in our own program. Generally this goes well, but with revolve surfaces all trimming curves are slightly shifted on the surface. I’m trying to work out why our software isn’t displaying these cases like Rhino does. I’ll continue my example from before:

So I have the parametrization of the extruded and revolved surfaces from the previous example. Their trimming curves each describe a triangle in the UV space of the surface. Intuitively, the points should lie in the same places proportionally to their respective UV domains.

Let’s say (Ur,Vr) is the size of the domain of the revolve feature and (Ue,Ve) the domain of the extrude feature (given that both U and V intervals start at 0).
(Ar,Br) and (Ae,Be) are the “rightmost” points of their respective trimming triangles. I would expect Ar/Ur = Ae/Ue. This is not the case.

On the revolved surface, the rightmost point on the triangle lies at 0.318842804 / 20.0 = 0.0159421402.
On the extruded surface, the rightmost point on the triangle lies at 5.454311228 / 314.159265 = 0.017361611881.
To clarify:

Surely these proportions should match, given that the trimmed area looks identical on the surface? This discrepancy is what I’m seeing in our own NURBS visualizer. The rightmost point of the triangle is not as far to the right as it should be.

Incidentally, the control vertices of the surfaces are identical, and their knot vectors lie at the same proportions of the domain.

I hope this clarifies the problem. If I’m making any bone-headed assumptions here, do please feel free to let me know. :smile:

First off, I was mistaken about what I wrote yesterday. Sorry for the confusing info.

Whether you make a cylinder by revolving a line or by extruding a circle, the parameterization is the same:
From the What command run on a Revolved surface and an Extrusion:

Revolved Surface made by revolving a line
Geometry:
Valid surface.
Surface
Surface of Revolution
U = angular parameter, V = curve parameter
"U": Periodic (0.00 <= U <= 314.16)
“V”: (0.00 <= V <= 20.00)
Axis of revolution: (0.00,0.00,0.00) to (0.00,0.00,9.00)
Angles: from 0.00 radians (0.00 degrees) to 6.28 radians (360.00 degrees).
Revolute:
Line
start = (50.00,0.00,0.00)
end = (50.00,0.00,20.00)
domain = 0.00 to 20.00
line length = 20.00

Extrusion made by extruding a circle
Geometry:
Valid extrusion.
Extrusion Surface
"U": Periodic (0.00 <= U <= 314.16)
“V”: (0.00 <= V <= 20.00)
Path: (-0.00,-0.00,0.00) to (-0.00,-0.00,20.00)
End caps: none
End miters: square start and end
Profile curve:
Circle
start = (50.00,0.00,0.00)
center = (0.00,0.00,0.00)
radius = 50.00

Now I’ll try to understand the rest of what you’re asking about.

I guess what you’re asking about is that the parameterization of the revolved surface doesn’t match the parameterization of the extrusion. I’m not clear about the practical application yet.

In the attached file, there are two surfaces, a Revolved Surface and an Extrusion in the same location.
The lines on layer RevSrfLines were made by a polar array at equal angle differences (and distances around the circle)
The lines on layer 2dLines were made by CreateUVCrv, which makes 3d curves on the world xy plane at their 2d coordinates on a surface.
The lines on layer ExtrusionLines were made using the 2dLines by ApplyCrv, which maps 3d curves onto the parameter space of a surface.

The reason the RevSrf lines do not correspond to the Extrusion lines is that the parameterizations of the surfaces around the circle are different.
The RevSrf is parameterized by angle, and the extrusion is parameterized as a rational nurbs curve.

So maybe the gap is that when you go from 2d to 3d on a surface, you need to use ClosestPoint to map 3d to 2d and PointAt to map 2d to 3d. RevSrfExtrusionParam.3dm (78.0 KB)

Thanks again for taking the time to help!

Oddly enough, I’m getting different results from the “What” command on revolves that I make myself in Rhino. Running it on the revolve surface in the file you sent gives the properties you list, but if I make one myself, the output of the “What” command differs in the following aspects:

...
        U = angular parameter, V = curve parameter
        "U": Periodic  (0.00 <= U <= 20.00)
        "V":  (0.00 <= V <= 314.16)
...
            domain = 0.00 to 20.00

Everything else is identical. Again, this shouldn’t really make any difference in the end result, I’m just confused as to why we’re getting different domains. I have attached a file to show the difference in our revolves: RevSrfExtrusionParam2.3dm (34.2 KB)


Regardless of the above, since the file you sent contains a revolve surface with the same domain as the matching extrude surface, it helps clarify the problem I’m having.
As far as I can tell, there is no difference in the NURBS surfaces that NurbsSurface() returns for the extrude and the revolve surfaces in your file. However, their trimming curves have different control points (corresponding to the discrepancy I outlined in my previous post). Using “PointAt” I can verify that although the control points are different, they map to the same point in 3d.

So my question is: Why is it that trimming two identical NURBS surfaces with different trimming curves produces the same result? Conversely, why does trimming them with the same curve produce different results?

I guess the problem is that some information is lost in the conversion that happens in the NurbsSurface method. These two surfaces have some difference in parametrization which is not retained, which means that the trims don’t trim the NurbsSurface the same way they would the underlying brep. Is that a correct assessment, do you think?

Your suggestion of converting the control points to the “correct” U/V space via 3d might indeed be the only way to work around this. As I understand it, though, the standalone OpenNURBS toolkit doesn’t offer “closest point” functionality?

Right, got it. It was simply a case of using the GetNurbFormParameterFromSurfaceParameter method to get the correct control points for the curve.
As I suspected, the NURBS representation given by GetNurbsForm doesn’t exactly match the original parametrization. Your suggestion of using surface->PointAt and nurbsSufrace->GetClosestPoint would have worked perfectly as well (I tried it in a Rhino plugin), but it seems this functionality has been encapsulated rather more handily in the above method.

Thanks again for bearing with me through all the confusion! :smile:
I’m still kind of puzzled about the seemingly transposed domain of my revolves, but in the end it seems this was irrelevant.