Trimmed NURBS Surface Creation


Here is my problem.

I need to trim a nurbs surface (of type Geom_BSplineSurface) with a set of trimming nurbs curve (of type Geom2d_BSplineCurve).

I have obtained the values for the surface and the trim curves directly from an open cascade shape, I have start with a rectangular surface with a circular hole in the center.

I have searched this forums and internet in general for a simple and complete explanation of the procedure to obtain the trimmed surface without success, someone

suggest the use of BRepBuilderAPI_MakeFace class, others suggest the use of BRepFeat_SplitShape or LocOpe_SplitShape classes, but I can't find a complete explanation of how to apply

this methods/classes.

Can anyone help me ?

Thank You


Claudio Cordara

Qr Qr's picture

Hi Claudio,

Are these Geom2d_BSplineCurve geometries defined in the parametric space of your Geom_BSplineSurface? If so, you already have p-curves to build your edges. The edges should be put in a wire which can be added then to the face using BRepBuilderAPI_MakeFace API. If you could share your geometries in BREP format (*.brep), we can check together how to prepare a relevant code for this stuff.

Kind regards.

Claudio Cordara's picture

Hello, tank you for your reply

Yes, I think my Geom2d_BSplineCurve geometries are defined in the parametric space of my Geom_BSplineSurface because I have obtained the surface and the curves dumping the TopoDS_Shape.

I have to specify that the two trim curves are both circles, so the final shape is a circular surface with a hole in the center.

In attachment there is the brep format of the geometry

Thank You for any help, and let me know for any question


Claudio Cordara

Qr Qr's picture

Hello Claudio,

In the attached file I can see a planar face with two circular wires. It is a completely valid face already. So what actually your problem is? I thought your were speaking about B-spline surface which is not there... Anyway, if you want to recover 3D curves from p-curves, you may simply call:


where E is your edge. As you probably know, a p-curve is a two-dimensional curve lying on a surface, so this information is enough to rebuilt its 3D representation.

Claudio Cordara's picture


Thank You again for your reply. The dump I have sent you is the shape I'm trying to obtain using nurbs surfaces and curves and it is correct.

I had dumped this shape and I had write the code for surface and curves generation.

I have attached the code I have used in trimNurbsSurface.cpp

I have attached the dump of the shape (bad) obtained with my code in brep format in trimmedNurbsShape.brep

My problem is to generate correctly the AIS_Shape to visualize starting from Geom_BSplineSurface and Geom2d_BSplineCurve objects.

Thank You again for your kindness


Claudio Cordara

Qr Qr's picture

Hello Claudio,

Here is the simple patch how to bring your face to life:

// Create face and add wires
BRepBuilderAPI_MakeFace faceMaker(nurbsSurf, TopoDS::Wire( wire1.Reversed() ), false);

// Fix to recover 3D curves
ShapeFix_Face fix( faceMaker.Face() );
// Get the generated face
TopoDS_Face Nurbsface = fix.Face();

There are few points which are not quite correct in your code:

  • When you build a face with BRepBuilderAPI_MakeFace, you do not pass a wire. This forces the builder to construct the so called "natural" boundaries which are min/max u/v of your spline surface. At the end, this leads to invalid imbrication of wires (see the p01.png attached). To fix it, you have to pass the wire together with the surface (not forgetting to orient your wire correctly!).
  • Notice ShapeFix_Face invocation. This is the one (well, the easiest) way to construct 3D curves out of your p-curves. Without this fix, the face you obtain will not be valid wrt validity rules of OpenCascade.

The last screenshot (p02.png) illustrates the final face.

Your difficulties are quite natural since the learning curve in OpenCascade is about vertical. To build algorithms with OpenCascade you may want to check some specialized tools. There are several options. For me, the tool by Guido van Hilst ( looks very promising. I take advantage of this post to refer to this remarkable project.

Claudio Cordara's picture


I have applied you patch and now the surface is correctly visualized, moreover I think I have understand how to correctly create trimmed nurbs surfaces.

Thanks for your support, I do not think I could understand without your help, I will check out the tool suggested.


Claudio Cordara

Qr Qr's picture

Just keep asking questions. It is a job of community to expand on shadow topics ;)

Andrew Cunningham's picture

Hi, I have been reading this discussion as it is very similar to what I want to do - but currently my efforts have resulted in abject failure :)

  • I have a Geom_BSplineSurface that is a fit of a simple polygonal surface
  • I have the boundary of that original polygonal surface
  • I use ShapeAnalysis_Surface::ValueOfUV to find the UV values of the boundary "projected" onto the Geom_BSplineSurface
  • I create a 2D TopoDS_Wire from the points along the boundary using BRepBuilderAPI_MakeWire and BRepBuilderAPI_MakeEdge2d
    • This is just a series of edges
  • I am trying to create a "trimmed" surface using that 2D UV wire as the trimming 'curve' using BRepBuilderAPI_MakeFace faceMaker(aBSplineSurface, TopoDS::Wire(trimmingWire.Reversed()), false);
  • This fails to create a valid trimmed surface as BRepCheck_Analyzer returns false ( I also get an exception inside the visualization code)

I must be missing something obvious here.

The files attached are

trimmingwire.brep = UV space trimming curve

trimmingwire3d.brep = 3D version of trimming curve

untrimmed.brep = valid BREP of 'untrimmed' surface

trimmed_bad.brep = result of my attempt to create a trimmed version using trimmingwire.brep

Guido van Hilst not specified's picture

Hello Andrew,

I have took a look at this problem.

The problem lies in the fact that the bounded 3D wire is at some corners just outside the natural bounds of the surface (Geom_BSplineSurface) 

I tried several ways to project the 3D wire on the surface, but they all fail at the corners, causing edges missing, and no closed wire. (see image pic2.png)

(I tried making the UV bunds larger, but that also fails)

The only way I succeeded it to make an equivalent planer surface of the given Geom_BSplineSurface (it seems the BSplineSurface is planer?) (see pic1.png)

You can see my attempt here: FaceFromSurfaceAndWires

If you can provide more details on the generic algorithm you need (always planer surfaces?)  I can maybe find a general solution.

Best regards, Guido

Andrew Cunningham's picture

Hi Guido,

Thanks so much for your help.

I agree that using the original 3D  boundary of the polygonal shape to trim the surface won't work as some points will be just outside the surface.

However, I just need the find the "closest" point on the surface that corresponds to a boundary point and use that as a trimming curve.

What I don't understand is how the nearest point "trimming curve" could end up outside the boundary of the surface when I am calling the function below to find the UV values of the trimming curve.

			ShapeAnalysis_Surface sas(aBSplineSurface);
			for (int i = 0; i < nBoundaryPoints; i++) {
				// get UV of point on surface
				gp_Pnt2d uv = sas.ValueOfUV(boundary_points[i], 0.001);

Andrew Cunningham's picture

I have attached my "new" 3D trimming wire that is generated by

  • using ShapeAnalysis_Surface.ValueOfUV(polygon_boundary_point) and clamping UV to 0.0,1.0 to get closest point on surface.
  • back into 3D using aBSplineSurface->Value()

These points MUST be on the surface....

Sadly, when I pass this new trimming curve, I still don't get a valid surface.

Andrew Cunningham's picture

OK, I have made a lot of progress in understanding how to do this

  • The trimming curve needs to be constructed from a Geom2d_BSplineCurve of the points in UV space
  • BRepBuilderAPI_MakeEdge needs to include the Geom_BSplineSurface in it's constructor along with the Geom2d_BSplineCurve
  • The result is a "valid" surface. But the trimming is quite odd. The curve I passed (trimmingUVWireFromBSpline.brep) is of degree 1 in UV space but when evaluated on the surface causes an unexpected result and does not follow my expected trimming curve (trimmingWire3DOnSurface.brep)
    // construct 1-Degree 2D spline through the UV points of the "boundary"
    Geom2dAPI_PointsToBSpline splineBuilder2D(pts2DArray, 1, 1, GeomAbs_C0, 1.0e-3);
    opencascade::handle<Geom2d_BSplineCurve> trimmingUVCurve = splineBuilder2D.Curve();
    BRepBuilderAPI_MakeEdge ME2d(trimmingUVCurve, aBSplineSurface);
    const TopoDS_Edge &uvedge = ME2d.Edge();
    BRepBuilderAPI_MakeWire wireMakerUVTrim;
    assert(wireMakerUVTrim.Error() == BRepBuilderAPI_WireDone);
    trimmingUVWireFromBSpline = wireMakerUVTrim.Wire();
    BRepBuilderAPI_MakeFace faceMaker(aBSplineSurface, trimmingUVWireFromBSpline, true);
    auto error = faceMaker.Error();
    aFace = faceMaker.Face();
    // Fix to recover 3D curves
    ShapeFix_Face fix(faceMaker.Face());
Guido van Hilst not specified's picture

This is exactly the same odd shape I get: FaceFromWires

​I think theoretically we do it good!!

Andrew Cunningham's picture

Hi Guido,

Yes, we seem to have converged on the same 'solution'.

So the file trimmingUVCurve2d.brep is the  C0 trimming curve in UV space. I assume that the poor result is due to the stretching in 'real' space for this long, narrow geometry so that straight lines in UV space become curved lines in real space that are outside the geometry. Certainly some food for thought here on how to come up with a better approach.

Thanks for all your help ( and sorry to the OP for hijacking the original thread!)

Heike Broichhausen's picture


I am guessing my question is rather simple, but i don't understand why my 2D curves from mt BSplineSurface shape are all straight lines? I don't want to "create" a surface, I just want to get the "curved" boundary shapes in 2D.

I am using 

Handle(Geom2d_Curve) c2d = BRep_Tool::CurveOnSurface(edge, face, t0, t1);

double dStep = (t1 - t0) / 20;

for (double t = t0; t <= t1; t += dStep)


gp_Pnt2d pnt1 = c2d->Value(t);


and all pnt1 are lying on a straight line, but my 3D shape has curved boundaries.

Actually, they aren't straight. Just very stretched so they look straight.