Boolean cut between cones and shape repairing (OCC 6.7.0)

Hello everyone,

I am investigating curious behaviors when performing boolean cuts on cones.
The software I am currently working on uses OCC 6.7.0
Not knowing where to begin, I tried to reproduce those behaviors in the mfc samples by modifying the OnCut() code in the ModelingDoc.cpp file in the Modeling project.

I was able to identify 2 problematic cases when :

1) Cutting two exact same cones with different orientations

2) Cutting a small cone with a larger one

In the first case, the resulting shape shows the 2 input cones, without a modification (Cones.png).
The second case shows some kind of distortion in the resulting shape (Strange_Cut.png).

Here is my OnCut() method for the first case :

void CModelingDoc::OnCut()
{
AIS_ListOfInteractive aList;
myAISContext->DisplayedObjects(aList);
AIS_ListIteratorOfListOfInteractive aListIterator;
for(aListIterator.Initialize(aList);aListIterator.More();aListIterator.Next())
{
myAISContext->Remove(aListIterator.Value());
}

// Cone1 Creation
TopoDS_Shape cone1 = BRepPrimAPI_MakeCone( 1,10, 200);
BRepCheck_Analyzer analyser1(cone1);
bool valid1 = analyser1.IsValid();
ASSERT(valid1);

// Cone1 Translation
const gp_Vec TranslationVec1(
Standard_Real(0.),
Standard_Real(0.),
Standard_Real(-100));
const gp_Trsf CylinderTrsf1 = gce_MakeTranslation(TranslationVec1);
cone1 = BRepBuilderAPI_Transform(cone1, CylinderTrsf1, Standard_False);

// Cone1 Rotation
const gp_Trsf RotYTrsf = gce_MakeRotation(gp::OY(), PI / 2.0);
cone1 = BRepBuilderAPI_Transform(cone1, RotYTrsf, Standard_True);

// 3D handling
Handle(AIS_Shape) ais1 = new AIS_Shape(cone1);
myAISContext->SetDisplayMode(ais1, 1, Standard_False);
myAISContext->SetColor(ais1, Quantity_NOC_YELLOW, Standard_False);
myAISContext->SetMaterial(ais1, Graphic3d_NOM_PLASTIC, Standard_False);
myAISContext->Display(ais1, Standard_False);
myAISContext->SetCurrentObject(ais1, Standard_False);
Fit();
Sleep(500);

// Cone2 creation
TopoDS_Shape cone2 = BRepPrimAPI_MakeCone(1, 10, 200);
BRepCheck_Analyzer analyser2(cone2);
bool valid2 = analyser2.IsValid();
ASSERT(valid2);

// Cone2 translation
const gp_Vec TranslationVec2(
Standard_Real(0.),
Standard_Real(0.),
Standard_Real(-100));
const gp_Trsf CylinderTrsf2 = gce_MakeTranslation(TranslationVec2);
cone2 = BRepBuilderAPI_Transform(cone2, CylinderTrsf2, Standard_False);

// Cone2 Rotation
const gp_Trsf RotXTrsf = gce_MakeRotation(gp::OX(), PI / 2.0);
cone2 = BRepBuilderAPI_Transform(cone2, RotXTrsf, Standard_True);

// Cone2 3D handling
Handle(AIS_Shape) ais2 = new AIS_Shape(cone2);
myAISContext->SetDisplayMode(ais2, 1, Standard_False);
myAISContext->SetColor(ais2, Quantity_NOC_YELLOW, Standard_False);
myAISContext->SetMaterial(ais2, Graphic3d_NOM_COPPER, Standard_False);
myAISContext->Display(ais2, Standard_False);
myAISContext->SetCurrentObject(ais2, Standard_False);
Fit();
Sleep(500);

// CUT
BRepAlgoAPI_Cut cutter(cone1, cone2);
cutter.Build();
TopoDS_Shape ShapeCut = cutter.Shape();

// CHECK CUT
BRepCheck_Analyzer CutAnalyser(ShapeCut);
CString sBool(std::to_string(CutAnalyser.IsValid()).c_str());
AfxMessageBox(sBool);

// Display Cut
myAISContext->Erase(ais1);
myAISContext->Erase(ais2);

Handle(AIS_Shape) aSection1 = new AIS_Shape(ShapeCut);
myAISContext->SetDisplayMode(aSection1, 1, Standard_False);
myAISContext->SetColor(aSection1, Quantity_NOC_RED, Standard_False);
myAISContext->SetMaterial(aSection1, Graphic3d_NOM_PLASTIC, Standard_False);
myAISContext->Display(aSection1, Standard_True);
myAISContext->SetCurrentObject(aSection1, Standard_False);
Fit();

Sleep(500);

}

For the second case, I just replaced
TopoDS_Shape cone1 = BRepPrimAPI_MakeCone( 1,10, 200);
by
TopoDS_Shape cone1 = BRepPrimAPI_MakeCone( 1,10, 500);

Am I missing something here ? For some reason, the hull in the second case seems to be correct.
I thought I had to repair the subshapes but my tries were not successful.

I used the BRepCheck_Analyzer all along but it didn't help in those cases.
Is there a way to recognize that something went wrong ?

If you have some idea on what is going on, please be as kind as to help me.
Have a nice day !

Attachments: 
Alexander Luger's picture

Hello!

My code works well with two cones, but my cutting is a little bit different to yours. I do not use the cones directly for cutting, I first of all create something like an infinite halfspace (aStamper in my code) from the cutting cone and use this one for the cutting-algorithm.

------------------------------------------------------
TopoDS_Shape aSplittingShape = ...; //Cone1
TopoDS_Shape aShapeToSplit = ...; //Cone2 .. or vice versa

BRep_Builder shellBB;
TopoDS_Shell aShell;
shellBB.MakeShell(aShell);
shellBB.Add(aShell,TopoDS::Face(aSplittingShape));

BRep_Builder solidBB;
TopoDS_Solid aStamper;
solidBB.MakeSolid(aStamper);
solidBB.Add(aStamper,aShell);

BRepAlgoAPI_Cut aCut(aShapeToSplit,aStamper);
...
TopoDS_Shape aRes = aCut.Shape();
------------------------------------------------------

Hope that helped!

Regards,
Alex

Rémi Loze's picture

Hello Alexander,

Thanks for your quick reply. I tried your method but without success.
Good news is, I finally understood some OCC mechanisms in the process (TopoDS_Shape, TopoDS_Face, TopoDS_Shape::Move...)

Actually I can cut cones together and it is not that big of an issue.
However, it seems that my first cone configuration does not work whatever the method.
Here is the code with Faces instead of Solids (and exceptions):

try
{

// Cone1 Creation
BRepPrimAPI_MakeCone coneMaker(1, 10, 200);
TopoDS_Face cone1 = coneMaker.Face();

// TopoDS_Shape cone1 = BRepPrimAPI_MakeCone( 1,10, 200);
BRepCheck_Analyzer analyser1(cone1);
bool valid1 = analyser1.IsValid();
ASSERT(valid1);

// Cone1 Translation
const gp_Vec TranslationVec1(
Standard_Real(0.),
Standard_Real(0.),
Standard_Real(-100));
const gp_Trsf CylinderTrsf1 = gce_MakeTranslation(TranslationVec1);
cone1.Move(CylinderTrsf1);

// Cone1 Rotation
const gp_Trsf RotYTrsf = gce_MakeRotation(gp::OY(), PI / 2.0);
cone1.Move(RotYTrsf);

// 3D handling
Handle(AIS_Shape) ais1 = new AIS_Shape(cone1);
myAISContext->SetDisplayMode(ais1, 1, Standard_False);
myAISContext->SetColor(ais1, Quantity_NOC_YELLOW, Standard_False);
myAISContext->SetMaterial(ais1, Graphic3d_NOM_PLASTIC, Standard_False);
myAISContext->Display(ais1, Standard_False);
myAISContext->SetCurrentObject(ais1, Standard_False);
Fit();
Sleep(500);

// Cone2 creation
BRepPrimAPI_MakeCone coneMaker2(1, 10, 200);
TopoDS_Face cone2 = coneMaker2.Face();

BRepCheck_Analyzer analyser2(cone2);
bool valid2 = analyser2.IsValid();
ASSERT(valid2);

// Cone2 translation
const gp_Vec TranslationVec2(
Standard_Real(0.),
Standard_Real(0.),
Standard_Real(-100));
const gp_Trsf CylinderTrsf2 = gce_MakeTranslation(TranslationVec2);
cone2.Move(CylinderTrsf2);

// Cone2 Rotation
const gp_Trsf RotXTrsf = gce_MakeRotation(gp::OX(), PI / 2.0);
cone2.Move(RotXTrsf);

// Cone2 3D handling
Handle(AIS_Shape) ais2 = new AIS_Shape(cone2);
myAISContext->SetDisplayMode(ais2, 1, Standard_False);
myAISContext->SetColor(ais2, Quantity_NOC_YELLOW, Standard_False);
myAISContext->SetMaterial(ais2, Graphic3d_NOM_COPPER, Standard_False);
myAISContext->Display(ais2, Standard_False);
myAISContext->SetCurrentObject(ais2, Standard_False);
Fit();
Sleep(500);

// Shell builder
BRep_Builder shellBB;
TopoDS_Shell aShell;

// Create empty shell
shellBB.MakeShell(aShell);

// Builder add shell to cone
shellBB.Add(aShell, cone2);

// Solid builder
BRep_Builder solidBB;
TopoDS_Solid aStamper;

// Create empty solid
solidBB.MakeSolid(aStamper);

// Solid builder adds cone shell
solidBB.Add(aStamper, aShell);

// CUT
BRepAlgoAPI_Cut cutter(cone1, aStamper);
cutter.Build();

TopoDS_Shape ShapeCut = cutter.Shape();

// CHECK CUT
BRepCheck_Analyzer CutAnalyser(ShapeCut);
CString sBool(std::to_string(CutAnalyser.IsValid()).c_str());
AfxMessageBox(sBool);

// Display Cut
myAISContext->Erase(ais1);
myAISContext->Erase(ais2);

Handle(AIS_Shape) aSection1 = new AIS_Shape(ShapeCut);
myAISContext->SetDisplayMode(aSection1, 1, Standard_False);
myAISContext->SetColor(aSection1, Quantity_NOC_RED, Standard_False);
myAISContext->SetMaterial(aSection1, Graphic3d_NOM_PLASTIC, Standard_False);
myAISContext->Display(aSection1, Standard_True);
myAISContext->SetCurrentObject(aSection1, Standard_False);
Fit();

}
catch (Standard_Failure& failure)
{
AfxMessageBox(failure.GetMessageString());
}

But if you cut cone2 with cone1, it works (See attached image).
This issue still seems kinda strange to me. Maybe a bug ?

As for my second problem, I do not have any clue (yet!).
Anyway, thanks for your reply, I'll continue to look for a solution.

Best regards !

Attachments: 
Alexander Luger's picture

Hello Rémi!

Your right, I have got the same result as you showed in the attached image. Unfortunately I did only try this and not to cut cone2 with cone1, which gives me bad results too. Did you search the Bugtracker if there is already an issue for this problem?

Regards,
Alex

Rémi Loze's picture

Hello Alexander,

I created an account to gain access to the bugtracker and I searched for a similar issue.
Sadly, I didn't find anything on this specific case, but since OCC is kinda new to me, I may have overlooked some topics.
Should I create an issue with DRAW commands to reproduce this bug (I believe it is one) ?
Anyway, thanks for taking time to try the code. It is always comforting to have someone obtain the same result :)

Best regards

Rémi Loze's picture

I tried to reproduce the problem with DRAW :

pcone p1 1 10 200
pcone p2 1 10 200
ttranslate p1 0 0 -100
ttranslate p2 0 0 -100
trotate p2 0 0 0 0 1 0 90
trotate p1 0 0 0 1 0 0 90
bop p2 p1
bopcut aCut
bopargcheck aCut

and there is indeed an exception raised somewhere :

An exception was caught 007AF028 : OSD_Exception_ACCESS_VIOLATION: ACCESS VIOLATION at address 0x00000000 during 'READ' operation

** Exception ** 007AF028 : OSD_Exception_ACCESS_VIOLATION: ACCESS VIOLATION at address 0x00000000 during 'READ' operation

And it works when switching p1 and p2.
I'll try the second problematic case in few moments.

Digging further,
best regards !

Forum supervisor's picture

Dear Rémi,
The case was checked on OCCT 6.7.1 beta and exception is not reproduced.
I can suggest you to try 6.7.1.
Best regards
FSR

Rémi Loze's picture

I am really amazed by the rapidity on this forum, many thanks for the reply:)
Is the second problematic case I mentionned fixed too in 6.7.1 ?

|
v

That is when cutting 2 cylinders with different sizes together :

vinit
vdisplaymode 1
pcone p1 1 10 2000
pcone p2 1 10 200
ttranslate p1 0 0 -100
ttranslate p2 0 0 -100
trotate p1 0 0 0 0 1 0 90
trotate p2 0 0 0 1 0 0 90
bop p1 p2
bopcut aCut
bopargcheck aCut
vdisplay aCut

In this case, some faces are missing in the cut cone.
Anyway, great community out there.

Best regards !

Forum supervisor's picture

Dear Rémi,
It seems that all faces (7) are presented in the result produced by 6.7.1:
Draw[]> explo aCut
aCut_1 aCut_2
Draw[]> checkshape aCut_1
This shape seems to be valid
Draw[]> checkshape aCut_2
This shape seems to be valid
Draw[]> nbshapes aCut_1
Number of shapes in aCut_1
VERTEX : 4
EDGE : 6
WIRE : 4
FACE : 4
SHELL : 1
SOLID : 1
COMPSOLID : 0
COMPOUND : 0
SHAPE : 20

Draw[]> nbshapes aCut_2
Number of shapes in aCut_2
VERTEX : 2
EDGE : 3
WIRE : 3
FACE : 3
SHELL : 1
SOLID : 1
COMPSOLID : 0
COMPOUND : 0
SHAPE : 13
Best regards
FSR

Forum supervisor's picture

Dear Rémi,
In addition you can try to make more precise mesh and do Z fit to see the shape in 3d view well:

> incmesh aCut 0.2
> vdisplay aCut
> vzfit

Besides, the result looks fine in 6.7.0 as well.
Best regards
FSR

Rémi Loze's picture

Hello,

Thanks for all your replies.
I tried the first case with 6.7.1 and I confirm, it is working really well, good job there.

As for my second problem, I recompiled 6.7.1 samples and inspected closely the second case.
Since I'm not that familiar with DRAW, I did it in the OnCut() method, in the mfc samples (modeling project).
I did 2 screenshots that show precisely the distortion I am referring to, you'll find them attached.
Here is my onCut() method :

void CModelingDoc::OnCut()
{
AIS_ListOfInteractive aList;
myAISContext->DisplayedObjects(aList);
AIS_ListIteratorOfListOfInteractive aListIterator;
for (aListIterator.Initialize(aList); aListIterator.More(); aListIterator.Next())
{
myAISContext->Remove(aListIterator.Value());
}

try
{

// Cone1 Creation
BRepPrimAPI_MakeCone coneMaker(1, 10, 500);
TopoDS_Shape cone1 = coneMaker.Shape();

// Cone2 creation
BRepPrimAPI_MakeCone coneMaker2(1, 10, 200);
TopoDS_Shape cone2 = coneMaker2.Shape();

// Center Cone
const gp_Vec TranslationVec(
Standard_Real(0.),
Standard_Real(0.),
Standard_Real(-100));
const gp_Trsf CylinderTrsf1 = gce_MakeTranslation(TranslationVec);

cone1.Move(CylinderTrsf1);
cone2.Move(CylinderTrsf1);

// Cone1 Rotation
const gp_Trsf RotYTrsf = gce_MakeRotation(gp::OY(), PI / 2.0);
cone1.Move(RotYTrsf);

// Cone2 Rotation
const gp_Trsf RotXTrsf = gce_MakeRotation(gp::OX(), PI / 2.0);
cone2.Move(RotXTrsf);

// CUT
BRepAlgoAPI_Cut cutter(cone1, cone2);

if (cutter.BuilderCanWork())
{
cutter.Build();

if (cutter.IsDone())
{

TopoDS_Shape ShapeCut = cutter.Shape();

// Check cut
BRepCheck_Analyzer CutAnalyser(ShapeCut);
CString sBool(std::to_string(CutAnalyser.IsValid()).c_str());
AfxMessageBox(sBool);

// 3D handle
Handle(AIS_Shape) aSection1 = new AIS_Shape(ShapeCut);
myAISContext->SetDisplayMode(aSection1, 1, Standard_False);
myAISContext->SetColor(aSection1, Quantity_NOC_RED, Standard_False);
myAISContext->SetMaterial(aSection1, Graphic3d_NOM_PLASTIC, Standard_False);
myAISContext->Display(aSection1, Standard_True);
myAISContext->SetCurrentObject(aSection1, Standard_False);
Fit();
}
}
else
{
std::cout << "Builder not done !" << endl;
}
}
catch (Standard_Failure& failure)
{
AfxMessageBox(failure.GetMessageString());
}
}

In DRAW, it should be equivalent to :

vinit
vsetdispmode 1

clear
vclear
pcone p1 1 10 500
pcone p2 1 10 200
ttranslate p1 0 0 -100
ttranslate p2 0 0 -100
trotate p1 0 0 0 0 1 0 90
trotate p2 0 0 0 1 0 0 90
bop p1 p2
bopcut aCut
bopargcheck aCut

incmesh aCut 0.2
vdisplay aCut
vzfit

But in my point of view, exploring the 3D space and turn around the shape with DRAW is still complicated.
What do you think of the distortion ?
Could it be a problem (or something I did wrong) in the 3D viewer ?

Many thanks for the time you're spending on this post.
Best Regards.

Attachments: 
Forum supervisor's picture

Dear Rémi,
It means that for this kind of shape a not optimal deflection is computed.
You can easy improve quality of the image using better deflection value, for example:
incmesh aCut 0.1
vdisplay aCut

See the result in the attached file.
Best regards
FSR

Attachments: 
Rémi Loze's picture

Well, I guess that's it :D .
Thanks to you, my two problems were solved in less than 3 days, I'm really impressed.
Moreover, I learned to use DRAW in the process and I understand now how some of the OCC mechanisms work.
OCC team and community, you have my gratitude !

I'm looking forward to use more and more OCC features in the near future.
I guess I'll be on this forum quite a lot from now on.
Again, my deepest thanks for the time you spent on the case.

Best Regards !