Problems with BrepOffsetAPI_ThruSections

Hello,
I face a problem when using BrepOffsetAPI_ThruSections.
I have two closed wires from which I want to create a solid by lofting, by applying BrepOffsetAPI_ThruSections(Standard_True). The first argument (isSolid) is set to true, forcing the algorithm to create a solid shape. However, the top and bottom surfaces are not generated and I get a shell.
Maybe the algorithm fails because in my case the two wires are 3D curves, not laying on primitive surfaces such as a plane or a Cylinder. ( on a cylinder it works, if you check the threading in the MakeBottle example)
A small test confirms this theory:

// test
TopoDS_Edge L1 = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0,0.0,0.0),gp_Pnt(1.0,0.0,0.5));
TopoDS_Edge L2 = BRepBuilderAPI_MakeEdge(gp_Pnt(1.0,0.0,0.5),gp_Pnt(1.0,1.0,0.0));
TopoDS_Edge L3 = BRepBuilderAPI_MakeEdge(gp_Pnt(1.0,1.0,0.0),gp_Pnt(0.0,1.0,0.5));
TopoDS_Edge L4 = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0,1.0,0.5),gp_Pnt(0.0,0.0,0.0));
BRepBuilderAPI_MakeWire mkWire_L;
mkWire_L.Add(L1);
mkWire_L.Add(L2);
mkWire_L.Add(L3);
mkWire_L.Add(L4);
TopoDS_Wire Wire_L = mkWire_L.Wire();

TopoDS_Edge L11 = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0,0.0,1.0),gp_Pnt(1.0,0.0,1.0));
TopoDS_Edge L12 = BRepBuilderAPI_MakeEdge(gp_Pnt(1.0,0.0,1.0),gp_Pnt(1.0,1.0,1.0));
TopoDS_Edge L13 = BRepBuilderAPI_MakeEdge(gp_Pnt(1.0,1.0,1.0),gp_Pnt(0.0,1.0,1.0));
TopoDS_Edge L14 = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0,1.0,1.0),gp_Pnt(0.0,0.0,1.0));
BRepBuilderAPI_MakeWire mkWire_U;
mkWire_U.Add(L11);
mkWire_U.Add(L12);
mkWire_U.Add(L13);
mkWire_U.Add(L14);
TopoDS_Wire Wire_U = mkWire_U.Wire();

BRepOffsetAPI_ThruSections mk_solid(Standard_True);
mk_solid.AddWire(Wire_L);
mk_solid.AddWire(Wire_U);
TopoDS_Shape Solid_Test = mk_solid.Shape();

in which 2 wires are created, Wire_L is not in a plane. The generated shape out of the two wires is a shell, without top and bottom surface... However, if you change all 0.5 to 0.0 (for the Z coordinates), a solid box is generated.

Why is this happening? And is there a way around? Could someone give me a hint or a general way to obtain a solid by lofting two (or more) closed wires, when only the wires are given?

Many thanks in advance

Pawel's picture

Hi Tom,

I'm not sure about the Z coordinates - 0.0, 0.5 and that stuff but to me it looks like you forget to call

mk_solid.Build();

before you access the object.
Try that.

Pawel

verstrae's picture

Hi Pawel,
Thank you for your quick reply. In my opinion, the call to mk_solid.Build(); is not necessary, I think mk_solid.Shape(); is calling it if no shape is yet build. Anyway, I added the command and the problem remains: a shell is created, even if you specify it should be a solid. There is no top or bottom surface created. However, if you call Solid_Test.ShapeType();, the return is 2, meaning it is a TopAbs_SOLID, although it is missing a top and bottom surface. The definition of a solid according to the reference manual is "A part of 3D space bounded by shells", which is not true in the above case. It is only the case if you put all 0.5 to 0.0, in that case a box is created.
I do understand that if the top and bottom wires are not on simple surfaces it is not obvious to create a Shell for those wires, and different shell's can match, so it leads to ambiguous situations. In my case however, the shape of the top and bottom shell does not matter. I only want to create a solid out of those wires, and only the loft surfaces are important to me.

I think one option would be to create myself the missing top and bottom surfaces and than add it to the already created faces and make from it a solid. In that case I would have to use a Sewing algorithm. Can anyone give me a hint on how to do that, for instance on the example of Solid_Test?

Many thanks in advance,

Tom

Pawel's picture

Hi Tom,

right doesn't work with mk_solid.Build() either. However, maybe you could try BRepOffsetAPI_MakePipeShell. Here's a sample:

TopoDS_Shape CHelixDoc::MyPipe( const TopoDS_Wire &wbase, const TopoDS_Wire &along,
double start, double pitch, double helixRadius)
{
ASSERT( ! along.IsNull() && ! wbase.IsNull() );

/// Calculate the length of the path
//----------------------------------
GProp_GProps lp;
BRepGProp::LinearProperties( along, lp );
double length1( lp.Mass() );

/// Prepare the shell
BRepOffsetAPI_MakePipeShell ps( along );

/// Create a linear law
//---------------------
//Handle( Law_Linear ) ll = new Law_Linear;
//ll->Set( 0.0, 1.0, length1, 1.0 );

/// Create a linear law
//---------------------
//Handle( Law_Constant) cc = new Law_Constant;
//cc->Set( 1.0, 0.0, 0.0);

/// Get the first and last point of the path
//------------------------------------------
TopoDS_Vertex pfirst, plast;

TopExp::Vertices( along, pfirst, plast );

/// Update the law parameters
//---------------------------
//ps.SetLaw( wbase, ll, pfirst, Standard_False, Standard_True );
//ps.SetLaw( wbase, cc, plast, Standard_False, Standard_False );

TopoDS_Wire wfirst = BRepBuilderAPI_MakeWire(wbase);
TopoDS_Wire wmiddle = BRepBuilderAPI_MakeWire(wbase);
TopoDS_Wire wlast = BRepBuilderAPI_MakeWire(wbase);

gp_Trsf trans0;
trans0.SetTranslation(gp_Vec(0,0,start));
wfirst.Move( TopLoc_Location( trans0 ) );

gp_Trsf trans1;
trans1.SetTranslation(gp_Vec(0,0, start + pitch));
wlast.Move( TopLoc_Location( trans1 ) );

gp_Trsf trans2;
trans2.SetTranslation(gp_Vec( -2 * helixRadius, 0, pitch/2 + start));
wmiddle.Move( TopLoc_Location( trans2 ) );

if(wbase.Closed() == Standard_False)
AfxMessageBox("Wire not closed.");
ps.Add(wfirst, pfirst);
ps.Add(wmiddle);
ps.Add(wlast, plast);

ps.Build();
ps.MakeSolid();

return( ps.Shape() );
};

Pawel

verstrae's picture

Thank you again Pawel!

If I added following lines to this small example, according to your reply:

TopoDS_Edge Edge_L1_L11 = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0,0.0,0.0),gp_Pnt(0.0,0.0,1.0));
TopoDS_Wire Wire_L1_L11= BRepBuilderAPI_MakeWire(Edge_L1_L11);

BRepOffsetAPI_MakePipeShell Ps(Wire_L1_L11);
Ps.Add(Wire_L_B);
Ps.Add(Wire_U_B);
Ps.Build();
Ps.MakeSolid();

TopoDS_Shape Solid_Test2 = Ps.Shape();

But the result remains the same... again only a shell is created without top and bottom faces... So it is a hard problem :-). I still think that it fails just because it is not possible for OCC to create a face for a wire laying in a non-planar or non-primitive surface. Both methods (BRepOffsetAPI_MakePipeShell and BRepOffsetAPI_ThruSections) can only make a solid if the wires are laying on "simple" surfaces according to my little experience with them. However, this is not written in the reference manual.

I think the option of making the solid myself is getting more and more the only way out... Can anyone give me a hint on that option, for the small example? I.e. how to build a top and bottom face, make from all the faces a shell and then transform it into a solid?

Thank you!

Rob Bachrach's picture

I looked at the source code for BRepOffsetAPI_ThruSections. When creating the end faces for the solid, it first looks to see if the wire is planar. Failing that, it calls BRepBuilderAPI_MakeFace with your wire. If BRepBuilderAPI_MakeFace fails to make a face from the wire, the face is not created. I am not sure, but it appears that BRepBuilderAPI_MakeFace goes through some simple attempts to create non-planar surfaces (like checking if a usable surface is attached to any of the edges already), but in the long run, attempts to create a plane.

So, in conclusion, I think you need to make the end surfaces yourself.

verstrae's picture

Thank you Rob,
that clarifies alot!

Mauro Mariotti's picture

To create two faces which fill the holes, I would try with BRepOffsetAPI_MakeFilling.

Ciao.
Mauro