Is mapping from TopoDS_Face to space not bijective?


I am doing two-dimensional computations on a TopoDS_Face. When I want to have the three-dimensional representations of my two-dimensional data, I use:

gp_Pnt spacePoint;
BRep_Tool::Surface(face)->D0(position.X(), position.Y(), spacePoint);

Now I was really surprised to find two two-dimensional positions on my surface that differ a lot (more than 6.0 length units), but are identical in the space (distance less than 1.0e-8). I thought that there might be a numerical instability, but at least with a tolerance of 1.0e-2 my BRepTopAdaptor_FClass2d claims that they are both TopAbs_ON the face.

Isn't the mapping from a Geom_Surface made out of a TopoDS_Face to the three-dimensional space bijective (one-to-one)???

Any hint is greatly appreciated!


Benjamin Bihler's picture

I have found out more about this topic: no, in general the mapping from a Geom_Surface made out of a TopoDS_Face to the three-dimensional space is not bijective.

Please see the attached picture. You see a shell here (the yellow area) and a face (with green boundary edges) that is part of the shell. One edge of the face (visualized with red color shining through) is exciting. The edge and its p-curve are not closed. The first point of the edge (visualized with white color on the left) has the coordinates (0 / 1.5708), the last point (visualized with blue color and on the right) has the coordinates (1.5708 / 1.5708) with respect to the Geom_Surface made out of the face.

I have a position (6.28319 / 1.5708) on the surface now that was computed by some algorithm before. This position obviously has a great distance from the first point of the edge (exactly 6.28319 length units). But when I compute their three-dimensional equivalents, the distance is zero. Also both points, (0 / 1.5708) and (6.28319 / 1.5708), are TopAbs_ON with respect to the face.

It is striking, that the coordinates look like 2 * M_PI and M_PI / 2. Could it be that the p-curve of the edge is a segment of a circle and therefore is somehow periodic?

For checking now whether two two-dimensional points on the Geom_Surface are identical, it does not suffice to compute their distance, because the mapping to the space is not one-to-one. Instead I have to compute the three-dimensional representations with BRep_Tool::Surface(face)->D0(position.X(), position.Y(), spacePoint) and then compute the distance in the space. This works, but might be costly from a performance point of view.

Still I would like to ask you: is this an OCC bug? Or is this usual behaviour? Is there a cheaper way to find out whether two different two-dimensional coordinates represent the same space point than using D0 of the Geom_Surface?

Thank you.

Mauro Mariotti's picture


surfaces may be periodic (cylinders, surfaces of revolution, ...) or just closed (e.g. a NURBS surface with the last column of control points coincident with the first).

They also may have a degenerate side (e.g. a "triangular" surface of revolution built from a curve with an end on the rotation axis), where all the UV's on a side of the domain map on the same 3d point.

In all these cases the UV-3d mapping is not bijective.


Benjamin Bihler's picture

Thanks for the answer. Can I very easily and cheaply recognize those cases in my algorithms? Then my distance check in the 3d space was only necessary in such cases and I could use the cheap 2d distance measurement in the other cases. Or is it best to always measure distance in the 3d space?

Mauro Mariotti's picture

In Geom_Surface you have methods IsUPeriodic/IsVPeriodic and IsUClosed/IsVClosed.

For "triangular" surfaces I don't know; so, if you can encounter them in your application, I am afraid that you need either to write some code to recognize them or alwasy measure distances in 3d space.

Benjamin Bihler's picture

Great! Doing the computation in space only when either U or V are periodic really speeds up the check. I have added an assert to ensure that the results are the same. With this I am confident to find out situations where this check does not suffice, if such situations exist at all.

Thank you again.

Benjamin Bihler's picture


I still have problems with periodic surfaces. When I create a Geom2d_BSplineCurve interpolating two points on a surface that are taken from different periods and then create a 3d curve with Adaptor3d_CurveOnSurface, the curve leaves the face and forms something like a complementary circle to the actually expected curve. In the attached picture the green/red curve should stay on the surface. But because of the described problem it changes direction, leaves the surface and approaches the target point from the other side.

If I could force all 2d points onto the same period of the Geom_Surface, this should be solved. Is there a way to do that or at least recognize such a situation? To be clearer: in my example the point (6.28319, 134.072) and the point (0.0, 134.072) have the same 3d coordinates. I can create a curve from (0.0, 134.072) to (1.0, 134.072), but creating a curve from (6.28319, 134.072) to (1.0, 134.072) leads to the error you see in Curve.png.

Sometimes computing the 3d representation of a 2d point and projecting it onto the Geom_Surface again helps, but not always. :-(

Any help is greatly appreciated!


Benjamin Bihler's picture

I guess I have found a solution: ShapeAnalysis::AdjustByPeriod can be used to get rid of the period. I use it like this:

double newX =  point.X() + ShapeAnalysis::AdjustByPeriod(point.X(), 0.0, surface->UPeriod());

and the same for Y. This seems to move all points into the same period and then the curve interpolation works fine!

sam landier's picture

Dear Mauro,

I have a bijective similar issue related on this post :

In my case it is not a periodic surface or surface of revolution, it is a quarter of disk-like surface that gives the same parameter for 2 distincts points on the real space.

Any idea ?