Creating face on cylindrical surface

Hi, all. I am really stuck and cannot find the reason what I am doing wrong :( I am trying to create a face, which technically is half cylinder with 3 mm distance. The code below is what I am trying to use, but the face is wrong. I don't understand what I am missing. The last lines supposed not to ASSERT at all. Can you help me? I really will appreciate this.


		TopoDS_Face TheFace;
		gp_Pnt pt(0.0, 0.0, 0.0);
		gp_Dir dir(0.0, 0.0, 1.0);
		gp_Ax3 ax(pt, dir, gp_Dir(1.0, 0.0, 0.0));

		gp_Cylinder cyl(ax, 5.0);//radius

		TopoDS_Wire Outwire;
		BRepBuilderAPI_MakeWire mkWire;
		{
			TopoDS_Edge e1, e2, e3, e4;
			{
				gp_Pnt oP1(-5.0, 0.0, 0.0);
				gp_Pnt oP2(0.0, -5.0, 0.0);
				gp_Pnt oP3(5.0, 0.0, 0.0);
				GC_MakeArcOfCircle mac(oP1, oP2, oP3);
				e1 = BRepBuilderAPI_MakeEdge(mac.Value());
			}
			{
				cD3DPoint P1(5.0, 0.0, 0.0);
				cD3DPoint P2(5.0, 0.0, 3.0);
				gp_Dir V(P2.x - P1.x, P2.y - P1.y, P2.z - P1.z);
				Handle_Geom_Line theCurve = new Geom_Line(gp_Pnt(P1.x, P1.y, P1.z), V);
				Handle_Geom_TrimmedCurve  TrimCurve = new Geom_TrimmedCurve(theCurve, 0.0, (P2 - P1).GetLength());

				e2 = BRepBuilderAPI_MakeEdge(TrimCurve);
			}

			{
				gp_Pnt oP1(5.0, 0.0, 3.0);
				gp_Pnt oP2(0.0, -5.0, 3.0);
				gp_Pnt oP3(-5.0, 0.0, 3.0);
				GC_MakeArcOfCircle mac(oP1, oP2, oP3);
				e3 = BRepBuilderAPI_MakeEdge(mac.Value());

			}

			{
				cD3DPoint P1(-5.0, 0.0, 3.0);
				cD3DPoint P2(-5.0, 0.0, 0.0);
				gp_Dir V(P2.x - P1.x, P2.y - P1.y, P2.z - P1.z);
				Handle_Geom_Line theCurve = new Geom_Line(gp_Pnt(P1.x, P1.y, P1.z), V);
				Handle_Geom_TrimmedCurve  TrimCurve = new Geom_TrimmedCurve(theCurve, 0.0, (P2 - P1).GetLength());

				e4 = BRepBuilderAPI_MakeEdge(TrimCurve);
			}

			mkWire.Add(e1);
			mkWire.Add(e2);
			mkWire.Add(e3);
			mkWire.Add(e4);

			Outwire = mkWire.Wire();
		}
		BRepBuilderAPI_MakeFace makeface(cyl, Outwire);
		TheFace = makeface.Face();

		gp_Pnt2d 	np(FLT_MAX, FLT_MAX);
		BRepClass_FaceClassifier fc;
		fc.Perform(TheFace, np, FLT_EPSILON);
		if (fc.State() == TopAbs_IN)
		{
			ASSERT(FALSE);
		}

 

gkv311 n's picture

BRepBuilderAPI_MakeFace taking gp_Cylinder implicitly creates Geom_CylindricalSurface and behaves the same as method taking Geom_Surface on input. Please pay attention to it's description:

  //! Make a face from a Surface and a wire.
  //! If the surface S is not plane,
  //! it must contain pcurves for all edges in W,
  //! otherwise the wrong shape will be created.
  Standard_EXPORT BRepBuilderAPI_MakeFace(const Handle(Geom_Surface)& S, const TopoDS_Wire& W, const Standard_Boolean Inside = Standard_True);

The Edges in Wire should define P-Curves (2D curves on your Geom_CylindricalSurface) to form a valid Face. But your current logic creates only 3D curves for Edges, which is not enough.

If you will pass created Face through checkshape tool, it will report 'No Curve on Surface' issue.

Kostadin Vrantzaliev's picture

Thank you very much for the quick and clear answer. It all makes sense now. Do you have any suggestions - how can I resolve this issue? Do I need to project the 3d curves on the surface and then use Geom2d_Curve to create the edge? What is the best workflow for the example like this one. I really appreciate your help.

gkv311 n's picture

You may use 3 ways to generate a valid shape, which one to use depends on requirements of your application.

  • Define both 2d and 3d curves analytically. I guess this is the most robust way (considering that you make calculations correctly).
  • Define 2d curve and rely on automatic 3d curve generation algorithms like BRepLib::BuildCurve3d(). This might be more or less robust way.
  • Define 3d curve and compute automatic 2d curve projections using tools like Shape Healing. This approach will also work, but I guess it is less preferrable.
Kostadin Vrantzaliev's picture

I used your second proposal and it works. All that you say makes huge sense and I hope this article will help others too. Большое спасибо.

Kostadin Vrantzaliev's picture

Can you help me a bit more :( I am trying to create the cylinder, but want to make a trimmed cylinder - so I need to pass top circle and bottom circle (not arc shape). can you advice - how can I use Makeface in this case? It fails despite I project the circles on the cylinder.

gkv311 n's picture

Maybe you can share a new code snippet with the problem...

Kostadin Vrantzaliev's picture

This is the code I am trying to use:

gp_Pnt pt(0.0, 0.0, 0.0);
		gp_Dir dir(0.0, 0.0, 1.0);
		gp_Ax3 ax(pt, dir, gp_Dir(1.0, 0.0, 0.0));

		gp_Cylinder cyl(ax, 5.0);//radius
		BRepBuilderAPI_MakeFace makeface(cyl);

		{
			TopoDS_Edge e1, e2;
			{
				gp_Circ occCircle( gp_Ax2(gp_Pnt(0.0, 0.0, 0.0), dir, gp_Dir(1.0, 0.0, 0.0) ), 5.0);
				GC_MakeCircle op(occCircle);
				e1 = BRepBuilderAPI_MakeEdge(op.Value());
			}
			{
				gp_Circ occCircle(gp_Ax2(gp_Pnt(0.0, 0.0, 3.0), dir, gp_Dir(1.0, 0.0, 0.0)), 5.0);
				GC_MakeCircle op(occCircle);
				e2 = BRepBuilderAPI_MakeEdge(op.Value());
			}

			const TopoDS_Face& baseface = makeface.Face();
			TopoDS_Edge  n1 = ProjectEdgeOnFace(e1, baseface);
			TopoDS_Edge  n2 = ProjectEdgeOnFace(e2, baseface);
			
			TopoDS_Wire w1 = BRepBuilderAPI_MakeWire(n1);
			TopoDS_Wire w2 = BRepBuilderAPI_MakeWire(n2);

			Handle(Geom_Surface) theSurface = BRep_Tool::Surface(baseface);

			BRepBuilderAPI_MakeFace MF(baseface);
			MF.Add(w1);
			MF.Add(w2);
			MF.Build();

			if (MF.IsDone())
			{
				face = MF.Face();
			}

		}

 

Kostadin Vrantzaliev's picture

Also, the projection code I found on internet also:

TopoDS_Edge OCCTools::ProjectEdgeOnFace (const TopoDS_Edge& Edge, const TopoDS_Face& Fac)
{
  TopoDS_Edge edgeOnSurf;
  edgeOnSurf.Nullify();

  BRep_Builder    theBuilder;
  TopLoc_Location LocFac;

  Handle (Geom_Surface)  theSurface   = BRep_Tool::Surface (Fac, LocFac);
  Handle (Standard_Type) surface_type = theSurface->DynamicType();

  if (surface_type == STANDARD_TYPE (Geom_RectangularTrimmedSurface))
  {
    theSurface   = Handle (Geom_RectangularTrimmedSurface)::DownCast (theSurface)->BasisSurface();
    surface_type = theSurface->DynamicType();
  }

  if (surface_type == STANDARD_TYPE (Geom_Plane))
  {
    return Edge;
  }

  Standard_Real f, l;

  Standard_Real Umin, Umax, Vmin, Vmax;
  BRepTools::UVBounds (Fac, Umin, Umax, Vmin, Vmax);

  Handle (Geom2d_Curve) aC2d = BRep_Tool::CurveOnSurface (Edge, Fac, f, l);
  if (!aC2d.IsNull())
  {
    gp_Pnt2d p2d;
    aC2d->D0 ((f + l) * 0.5, p2d);
    Standard_Boolean IsIn = Standard_True;
    if ((p2d.X() < Umin - Precision::PConfusion()) || (p2d.X() > Umax + Precision::PConfusion()))
      IsIn = Standard_False;
    if ((p2d.Y() < Vmin - Precision::PConfusion()) || (p2d.Y() > Vmax + Precision::PConfusion()))
      IsIn = Standard_False;

    if (IsIn)
      return Edge;
  }

  TopLoc_Location     Loc;
  Handle (Geom_Curve) C = BRep_Tool::Curve (Edge, Loc, f, l);

  if (!Loc.IsIdentity())
  {
    Handle (Geom_Geometry) GG = C->Transformed (Loc.Transformation());
    C                         = Handle (Geom_Curve)::DownCast (GG);
  }

  if (C->DynamicType() != STANDARD_TYPE (Geom_TrimmedCurve))
  {
    C = new Geom_TrimmedCurve (C, f, l);
  }

  Standard_Real TolFirst = -1, TolLast = -1;
  TopoDS_Vertex V1, V2;
  TopExp::Vertices (Edge, V1, V2);
  if (!V1.IsNull())
    TolFirst = BRep_Tool::Tolerance (V1);
  if (!V2.IsNull())
    TolLast = BRep_Tool::Tolerance (V2);

  Standard_Real         tol2d = Precision::Confusion();
  Handle (Geom2d_Curve) C2d;

  ShapeConstruct_ProjectCurveOnSurface aToolProj;
  aToolProj.Init (theSurface, tol2d);
  aToolProj.Perform (C, f, l, C2d, TolFirst, TolLast);
  if (C2d.IsNull())
    return edgeOnSurf;

  gp_Pnt2d pf (C2d->Value (f));
  gp_Pnt2d pl (C2d->Value (l));

  gp_Pnt PF, PL;
  theSurface->D0 (pf.X(), pf.Y(), PF);
  theSurface->D0 (pl.X(), pl.Y(), PL);

  if (Edge.Orientation() == TopAbs_REVERSED)
  {
    V1 = TopExp::LastVertex (Edge);
    V1.Reverse();
  }
  else
  {
    V1 = TopExp::FirstVertex (Edge);
  }
  if (Edge.Orientation() == TopAbs_REVERSED)
  {
    V2 = TopExp::FirstVertex (Edge);
    V2.Reverse();
  }
  else
  {
    V2 = TopExp::LastVertex (Edge);
  }

  if (!V1.IsNull() && V2.IsNull())
  {
    // Handling of internal vertices
    Standard_Real old1 = BRep_Tool::Tolerance (V1);
    Standard_Real old2 = BRep_Tool::Tolerance (V2);
    gp_Pnt        pnt1 = BRep_Tool::Pnt (V1);
    gp_Pnt        pnt2 = BRep_Tool::Pnt (V2);
    Standard_Real tol1 = pnt1.Distance (PF);
    Standard_Real tol2 = pnt2.Distance (PL);
    theBuilder.UpdateVertex (V1, Max (old1, tol1));
    theBuilder.UpdateVertex (V2, Max (old2, tol2));
  }

  if (theSurface->IsUPeriodic())
  {
    Standard_Real    up      = theSurface->UPeriod();
    Standard_Real    tolu    = Precision::PConfusion(); // Epsilon(up);
    Standard_Integer nbtra   = 0;
    Standard_Real    theUmin = Min (pf.X(), pl.X());
    Standard_Real    theUmax = Max (pf.X(), pl.X());

    if (theUmin < Umin - tolu)
    {
      while (theUmin < Umin - tolu)
      {
        theUmin += up;
        nbtra++;
      }
    }
    else if (theUmax > Umax + tolu)
    {
      while (theUmax > Umax + tolu)
      {
        theUmax -= up;
        nbtra--;
      }
    }

    if (nbtra != 0)
    {
      C2d->Translate (gp_Vec2d (nbtra * up, 0.));
    }
  }

  if (theSurface->IsVPeriodic())
  {
    Standard_Real    vp      = theSurface->VPeriod();
    Standard_Real    tolv    = Precision::PConfusion();
    Standard_Integer nbtra   = 0;
    Standard_Real    theVmin = Min (pf.Y(), pl.Y());
    Standard_Real    theVmax = Max (pf.Y(), pl.Y());

    if (theVmin < Vmin - tolv)
    {
      while (theVmin < Vmin - tolv)
      {
        theVmin += vp;
        theVmax += vp;
        nbtra++;
      }
    }
    else if (theVmax > Vmax + tolv)
    {
      while (theVmax > Vmax + tolv)
      {
        theVmax -= vp;
        theVmin -= vp;
        nbtra--;
      }
    }

    if (nbtra != 0)
    {
      C2d->Translate (gp_Vec2d (0., nbtra * vp));
    }
  }
  edgeOnSurf = BRepBuilderAPI_MakeEdge (C2d, theSurface, f, l);
  BRepLib::BuildCurve3d (edgeOnSurf);

  return edgeOnSurf;
}

 

Dmitrii Pasukhin's picture

Please update your comments with HTML styling and inserting code snipped. It is difficult to analyze as a general text.

If you have no permission - i will update, but please next comments write with code snippeds.

Best regards, Dmitrii,

Kostadin Vrantzaliev's picture

I am sorry, I just pasted as normal text. I can try, but if you can do this would be easier. Thank you very much.

Dmitrii Pasukhin's picture

Updated.

gkv311 n's picture

I am confused - why you create two Wires from circles? One Wire in the Face is supposed to define outer boundaries and others - holes. But I don't think you want to define a hole here.

Note that for making closed cylindrical Face you'll need defining a seam Edge. It might be helpful learning how to build simple topology and geometry in DRAW harness and displaying it in axonometric view - could help to understand how valid geomtry normally looks alike in OCCT.

            const TopoDS_Face& baseface = makeface.Face();
            TopoDS_Edge  n1 = ProjectEdgeOnFace(e1, baseface);
            TopoDS_Edge  n2 = ProjectEdgeOnFace(e2, baseface);

            TopoDS_Wire w1 = BRepBuilderAPI_MakeWire(n1);
            TopoDS_Wire w2 = BRepBuilderAPI_MakeWire(n2);

            Handle(Geom_Surface) theSurface = BRep_Tool::Surface(baseface);

            BRepBuilderAPI_MakeFace MF(baseface);
            MF.Add(w1);
            MF.Add(w2);
            MF.Build();