Fail to convert Geom_BSplineSurface to TopoDS_Face.

R G W

CAD community veteran
Hello, I'm RGW.
I read a step model, then converted one of the TopoDS_Face to Geom_BSplineSurface, and then reparametrized the Geom_BSplineSurface, now I want to re-convert the reparametrized Geom_BSplineSurface to TopoDS_Face, but I found that there is a problem with the result of my conversion: a circle surface becomes a square. How can I do it to get the result I want?

Below is my code and conversion result.

Code:
    //convert a face_shape to Geom_BSplineSurface
    TopoDS_Face faceo = TopoDS::Face(face_shape);
    BRepBuilderAPI_NurbsConvert nurbs_convert;
    nurbs_convert = BRepBuilderAPI_NurbsConvert(faceo);
    nurbs_convert.Perform(faceo);
    TopoDS_Shape face_shape = nurbs_convert.Shape();
    Handle(Geom_Surface) h_geomface = BRep_Tool::Surface(TopoDS::Face(face_shape));
    Handle(Geom_BSplineSurface)h_bsurface = GeomConvert::SurfaceToBSplineSurface(h_geomface);
    
    //Reparametrize u dir
    Standard_Integer nbuk = h_bsurface->NbUKnots();
    TColStd_Array1OfReal uk(1, nbuk);
    BSplCLib::Reparametrize(0, 1, uk);
    h_bsurface->SetUKnots(uk);
    
    //Reparametrize v dir
    Standard_Integer nbvk = h_bsurface->NbVKnots();
    TColStd_Array1OfReal vk(1, nbvk);
    BSplCLib::Reparametrize(0, 1, vk);
    h_bsurface->SetVKnots(vk);
    
    //convert Geom_BSplineSurface to TopoDS_Face
    TopoDS_Face res = BRepBuilderAPI_MakeFace(h_bsurface, Precision::Approximation());


The left image is the original graph, which is the result I want to get.

The right image is the wrong result of my code running.

1679750122708.png 1679750256414.png
 

Attachments

  • tutai.STEP
    11.7 KB · Views: 0

Quaoar

Administrator
Staff member
TopoDS_Face res = BRepBuilderAPI_MakeFace(h_bsurface, Precision::Approximation());
When you construct a face like this, it gets the "natural bounds" from the host surface. You would rather have to pass the original wire to retrim the converted surface. Have you already figured that out?
 

R G W

CAD community veteran
No, I haven't solved this problem yet, what you said makes sense, I will try it out, is there any function that will do the job?
When you construct a face like this, it gets the "natural bounds" from the host surface. You would rather have to pass the original wire to retrim the converted surface. Have you already figured that out?
 

R G W

CAD community veteran
When you construct a face like this, it gets the "natural bounds" from the host surface. You would rather have to pass the original wire to retrim the converted surface. Have you already figured that out?
Hi, I tried BRepBuilderAPI_MakeFace(const Handle<Geom_Surface> &S, const TopoDS_Wire &W) to construct a face, and I successfully constructed the plane I wanted.
Code:
TopoDS_Wire mywire = BRepTools::OuterWire(faceo);
...
TopoDS_Face res = BRepBuilderAPI_MakeFace(h_bsurface, mywire);
1680487722155.png

But now there is another problem, I use this surface to apply the algorithm of deintersection, but it does give a running error.
Code:
double uMin, uMax, vMin, vMax;
    BRepTools::UVBounds(res, uMin, uMax, vMin, vMax);

    const double uMid = (uMin + uMax)*0.5;
    const double vMid = (vMin + vMax)*0.5;

    Handle(Geom2d_Line) iso = new Geom2d_Line(gp_Pnt2d(uMin , 0), gp::DY2d());

    for (TopExp_Explorer eexp(res, TopAbs_EDGE); eexp.More(); eexp.Next())
    {
        const TopoDS_Edge& edge = TopoDS::Edge(eexp.Current());
        vout << edge;
        // Get pcurve of an edge.
        double f, l;
        Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface(edge, res, f, l);

        
            Geom2dAPI_InterCurveCurve intersector(iso, pcurve);

            if (intersector.NbPoints())
            {
                const int nsol = intersector.NbPoints();
                for (int isol = 1; isol <= nsol; ++isol)
                {
                    gp_Pnt2d pt2d = intersector.Point(isol);
                    gp_Pnt   pt = h_geomface->Value(pt2d.X(), pt2d.Y());

                    BRepBuilderAPI_MakeVertex mv(pt);
                    std::cout << pt.X() << std::endl;
                    std::cout << pt.Y() << std::endl;
                    std::cout << pt.Z() << std::endl;
                    vout << mv.Vertex();

                }
            }
        
    }
1680488537576.png

What I'm trying to do is:
1. Read a surface in the model and convert it to Geom_BSplineSurface
2. Reparameterize the uv vector of the surface to (0, 1)
3. Convert the reparameterized Geom_BSplineSurface to TopoDS_Face
4. Use the new TopoDS_Face to get the intersection point of the uv line and the model

Thank you very much!!
 

R G W

CAD community veteran
What's new, maybe I have solved the problem!


Code:
BRepBuilderAPI_MakeFace facemaker(shapesface, TopoDS::Wire(mywire), false);
    facemaker.Add(mywire);

    ShapeFix_Face fix(facemaker.Face());
    fix.Perform();
    TopoDS_Face res = fix.Face();


There are two points to note when creating a trimmed surface:
  • 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.

I'm missing the handling of ShapeFix_Face before.

1680514256892.png

Thank you very much!!
 
Top