# what to do when ProjectPointOnSurf fails?

i've been doing some tests on model Misc2.brep from the shape_gallery and i am sampling points along the boundary of a face and then projecting them onto the face using GeomAPI_ProjectPointOnSurf and it sometimes fails (Projection has no points).

The way I call GeomAPI_ProjectPointOnSurf is with a point and the associated surface. I've noticed that it fails a lot more when you provide parameter bounds (the ones coming from the face itself).

That's a bit of a problem because it really should not "fail" and I'd like to know if there is an alternate projection method.

Hi Ugo,

Yes, it's often caused by boundary restrction of the surface. In fact, you can manually extends the bounds by add/sub a du/dv to its raw bounds, and use surface boundary instead of face boundary.

Ding

thanks for the reply. i actually don't even input the bounds, i just let occ project on the underlying surface.

i don't quite understand why it fails to find the closest point.

Hello Ugo,

I hope the following meets your needs.

First, ensure your uv-bounds of the face, in the parametric space of the face's underlying Geom_Surface, is right.

Use BRepTools::UVBounds ( Face, UMin, UMax, VMin, VMax )

It will return the bounding values in the parametric space of. This is a generic method because it will handle both faces with natural (rectangular) bounds, e.g. cylindrical surface from U1, V1, U2, V2; as well as curve-bounded faces, e.g. a portion of a cylindrical surface bounded by a closed curve on the surface.

Second, you could add a check on the uv-bounds like this (will explain shortly)

Standard_Boolean is_umin_inf = Precision::IsInfinite ( UMin );

Standard_Boolean is_umax_inf = Precision::IsInfinite ( UMax );

Standard_Boolean is_vmin_inf = Precision::IsInfinite ( VMin );

Standard_Boolean is_vmax_inf = Precision::IsInfinite ( VMax );

Why this check? Normally, these bounds should be finite. However, if the definition is missing some boundary, some of the flags above will return infinite to Standard_True.

This check is necessary because the 'GeomAPI_ProjectPointOnSurf' could become unstable on non-finite bounds.

Finally, call 'GeomAPI_ProjectPointOnSurf'

FINAL NOTE:

I do not know whether you also would like to use other tools in OCCT to sample the points, e.g. by (i) number of points along an edge (ii) by abscissa along curve, or (iii) by chordal deviation; which you could use as input to GeomAPI_ProjectPointOnSurf?

If that's the case, use

- TopExp_Explorer Exp ( Face, TopAbs_EDGE ): to get all edges in face

- BRepTool::CurveOnSurface ( Edge, Face, Ufirst, Ulast ): to get curve_on_surface

- GPnts_XXX (see package GPnts, and several APIs there) to get point samples on curve

- use these points as input to your GeomAPI_ProjectPointOnSurf

Good luck!

IAT

Hello Ugo,

I hope the following meets your needs.

First, ensure the face's uv-bounds (i.e. in the parametric space of the face's underlying Geom_Surface) is right, preferably finite. Use

BRepTools::UVBounds ( Face, UMin, UMax, VMin, VMax )

Second, to be sure, you could add a check on the uv-bounds like this (explained shortly)

Standard_Boolean is_umin_inf = Precision::IsInfinite ( UMin );

Standard_Boolean is_umax_inf = Precision::IsInfinite ( UMax );

Standard_Boolean is_vmin_inf = Precision::IsInfinite ( VMin );

Standard_Boolean is_vmax_inf = Precision::IsInfinite ( VMax );

Why this check? Normally, face bounds should be finite for manifold topology. However, if any bound is infinite, the will miss loop edges in that direction. In that case, any of the above flags will return Standard_True.

This check is necessary because the 'GeomAPI_ProjectPointOnSurf' could become unstable on non-finite bounds, and at least gives you the chance to identify such cases and use other tools in OCCT.

Finally, call 'GeomAPI_ProjectPointOnSurf ( Point, Surf, UMin, UMax, VMin, VMax )'

FINAL NOTE: above? If that's an option (or could make life easier - bit of automation for you), you could use the package GCPnts.

I do not know whether you also would like to use other tools in OCCT to sample the points to use in

Here, you can sample curves on edges by, say,

(i) number of points along an edge

(ii) by abscissa along curve, or

(iii) by chordal deviation

If this would make life easier, then do the following for each you encounter during your sampling

a) TopExp_Explorer Exp ( Face, TopAbs_EDGE ): to get all edges in face as input to your GeomAPI_ProjectPointOnSurf

b) BRepTool::CurveOnSurface ( Edge, Face, Ufirst, Ulast ): to get 'curve on the surface'

c) GCPnts_XXX (see package GCPnts, and several APIs there) to get point samples on curve

d) use each

Good luck!

IAT

thanks. well, that's basically what i was doing (again, this is for testing purposes since it's better to use the curves along the face to get the u,v parameters) but i had to drop the u,v bounds since it works better if you don't give them, at least, in my limited experience. And, the faces i deal with, are pretty straight-forward (no infinite bounds), it's from that Misc2 model in the Shape_Gallery.

i am really wondering if this is actually a closest point computation because i am not sure why it would fail, i mean, closest point computation when you have a parameter space is, i believe, rather straightforward.

is there another method that computes the closest point on a face/surface especially when the point is potentially far away from any surface normals (in that case, i would expect the method to project on the face or surface's boundary in case it fails in the orthogonal projection)?

Hello Ugo,

First, it could be difficult to discuss without sample code. I assume you want to sample face boundaries? If so, the other method would be to call

1: TopExp_Explorer edge_exp ( Face, TopAbs_EDGE ): to access edges in face

2: for each edge, BRep_Tool::Curve ( Edge, .. ): to get face boundary

3: GeomAPI_ProjectPointOnCurve

This will bring your point onto the curve on the face boundary. Here, I am restricting suggestions to within OCCT tools that am aware of for such a problem.

However, if you want to sample points over the whole face (including the inside), then you could consider generating a grid of points within the boundng box (whether uv- or 3d bounding box).

Perhaps I do not understand your question.

Hope this helps?

Best regards,

IAT

well, what i end up doing is:

if ProjectPointOnSurf fails, I assume it's because the point is out of the surface normals space, so I project with ProjectPointOnCurve on the bounding edges/curves and keep track of the minimum distance (and parameter on edge/curve). i then get the (u,v) from the parameter on edge/curve. It works for my purposes but can't say it's ideal.

I had some problems in the past with GeomAPI_ProjectPointOnSurf (and other Extrema classes).

Mostly performance problems (when using a complex shape containing a lot of faces) and sometimes the call failed (like for you I guess).

so, what I did was to generate a very fine mesh of the shape (BRepMesh + refining by triangle splits), each triangle vertex containing the UV cordinates and the associated face. I projected on the mesh (using some raytracing algorithm and optimizations) to find the triangle intersecting my projection line, compute the intersection point on the triangle, interpolate the U and V coords from the triangle vertices to this point and from the UV on the mesh-projected create the 3d projected point from the face + UVs.

Once the mesh was generated, it was very very fast (but with a "close enough for my cases" approximates result) ....

yes, i see what you mean when speed is of the essence. thanks Stéphane.

Ugo,

Two extra ideas for you to consider, in addition to many other useful ones given above:

1. Consider BRepExtrema_DistShapeShape if you really need to take into account topological boundaries. You may experiment with 'distmini' commands in DRAWEXE.

2. ShapeAnalysis_Surface::ValueOfUV(). It tries harder applying different methods if one fails, and is especially useful if you have to calculate several projections on the same surface (as it caches the sample points on the surface).

Hope this helps.

Roman