OBB is implemented in IntTools_OBB class, and is represented as center, axes and half-size dimensions.
The method IntTools_OBB::IsOut(theOther) is based on the Separated Axes theorem for Oriented Bounding Boxes.
According to this theorem it is necessary to consider 15 separating axes.
By default the OBB are not used. To enable the OBB usage in Boolean Operations it is necessary to call the method BOPAlgo_PaveFiller::SetUseOBB(const Standard_Boolean theFlag) with TRUE value.
To enable OBB usage in DRAW it is necessary to use the command:
buseobb 1
pPF->SetFuzzyValue(myFuzzyValue);
pPF->SetNonDestructive(myNonDestructive);
pPF->SetGlue(myGlue);
+ pPF->SetUseOBB(myUseOBB);
//
pPF->Perform();
//
pPF->SetFuzzyValue(myFuzzyValue);
pPF->SetNonDestructive(myNonDestructive);
pPF->SetGlue(myGlue);
+ pPF->SetUseOBB(myUseOBB);
//
pPF->Perform();
//
myNonDestructive = theFiller.NonDestructive();
myFuzzyValue = theFiller.FuzzyValue();
myGlue = theFiller.Glue();
+ myUseOBB = theFiller.UseOBB();
PerformInternal(theFiller);
}
//=======================================================================
myDS->SetArguments(myArguments);
myDS->Init(myFuzzyValue);
//
- // 2.myIterator
+ // 2 myContext
+ myContext=new IntTools_Context;
+ //
+ // 3.myIterator
BOPDS_PIteratorSI theIterSI=new BOPDS_IteratorSI(myAllocator);
theIterSI->SetDS(myDS);
- theIterSI->Prepare();
+ theIterSI->Prepare(myContext, myUseOBB);
theIterSI->UpdateByLevelOfCheck(myLevelOfCheck);
//
myIterator=theIterSI;
- //
- // 3 myContext
- myContext=new IntTools_Context;
}
//=======================================================================
//function : Perform
pPF->SetFuzzyValue(myFuzzyValue);
pPF->SetNonDestructive(myNonDestructive);
pPF->SetGlue(myGlue);
+ pPF->SetUseOBB(myUseOBB);
pPF->Perform();
//
myEntryPoint = 1;
myReport(new Message_Report),
myRunParallel(myGlobalRunParallel),
myFuzzyValue(Precision::Confusion()),
- myCheckInverted(Standard_True)
+ myCheckInverted(Standard_True),
+ myUseOBB(Standard_False)
{
BOPAlgo_LoadMessages();
}
myReport(new Message_Report),
myRunParallel(myGlobalRunParallel),
myFuzzyValue(Precision::Confusion()),
- myCheckInverted(Standard_True)
+ myCheckInverted(Standard_True),
+ myUseOBB(Standard_False)
{
BOPAlgo_LoadMessages();
}
//! for inverted status (holes in the space). The default value is TRUE,
//! i.e. the check is performed. Setting this flag to FALSE for inverted solids,
//! most likely will lead to incorrect results.
+//! - *Using the Oriented Bounding Boxes* - Allows using the Oriented Bounding Boxes of the shapes
+//! for filtering the intersections.
//!
class BOPAlgo_Options
{
return myCheckInverted;
}
+public:
+ //!@name Usage of Oriented Bounding boxes
+
+ //! Enables/Disables the usage of OBB
+ void SetUseOBB(const Standard_Boolean theUseOBB)
+ {
+ myUseOBB = theUseOBB;
+ }
+
+ //! Returns the flag defining usage of OBB
+ Standard_Boolean UseOBB() const
+ {
+ return myUseOBB;
+ }
+
protected:
//! Breaks the execution if the break signal
Standard_Real myFuzzyValue;
Handle(Message_ProgressIndicator) myProgressIndicator;
Standard_Boolean myCheckInverted;
+ Standard_Boolean myUseOBB;
};
myDS->SetArguments(myArguments);
myDS->Init(myFuzzyValue);
//
- // 2.myIterator
+ // 2 myContext
+ myContext=new IntTools_Context;
+ //
+ // 3.myIterator
myIterator=new BOPDS_Iterator(myAllocator);
myIterator->SetRunParallel(myRunParallel);
myIterator->SetDS(myDS);
- myIterator->Prepare();
- //
- // 3 myContext
- myContext=new IntTools_Context;
+ myIterator->Prepare(myContext, myUseOBB);
//
// 4 NonDestructive flag
SetNonDestructive();
pPF->SetFuzzyValue(myFuzzyValue);
pPF->SetNonDestructive(myNonDestructive);
pPF->SetGlue(myGlue);
+ pPF->SetUseOBB(myUseOBB);
//
pPF->Perform();
//
#include <NCollection_UBTreeFiller.hxx>
#include <TopoDS_Shape.hxx>
#include <algorithm>
+#include <IntTools_Context.hxx>
+#include <IntTools_OBB.hxx>
+
+#ifdef DEBUG_OBB
+#include <IntTools_Tools.hxx>
+#endif
/////////////////////////////////////////////////////////////////////////
//=======================================================================
// function: Prepare
// purpose:
//=======================================================================
-void BOPDS_Iterator::Prepare()
+void BOPDS_Iterator::Prepare(Handle(IntTools_Context)& theCtx,
+ const Standard_Boolean theCheckOBB)
{
Standard_Integer i, aNbInterfTypes;
//
if (myDS==NULL){
return;
}
- Intersect();
+ Intersect(theCtx, theCheckOBB);
}
//
//=======================================================================
// function: Intersect
// purpose:
//=======================================================================
-void BOPDS_Iterator::Intersect()
+void BOPDS_Iterator::Intersect(Handle(IntTools_Context)& theCtx,
+ const Standard_Boolean theCheckOBB)
{
Standard_Integer i, j, iX, i1, i2, iR, aNb, aNbR;
Standard_Integer iTi, iTj;
i1 = aR.First();
i2 = aR.Last();
for (i = i1; i <= i2; ++i) {
- const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
+ BOPDS_ShapeInfo& aSI = myDS->ChangeShapeInfo(i);
//
if (!aSI.IsInterfering() || (aSI.ShapeType() == TopAbs_SOLID)) {
continue;
continue;// same range
}
//
- const BOPDS_ShapeInfo& aSJ = myDS->ShapeInfo(j);
+ BOPDS_ShapeInfo& aSJ = myDS->ChangeShapeInfo(j);
aTj = aSJ.ShapeType();
iTj = BOPDS_Tools::TypeToInteger(aTj);
//
//
BOPDS_Pair aPair(i, j);
if (aMPFence.Add(aPair)) {
+ if (theCheckOBB)
+ {
+ IntTools_OBB& anOBBi = theCtx->OBB(aSI.Shape(), aSI.Box().GetGap());
+ IntTools_OBB& anOBBj = theCtx->OBB(aSJ.Shape(), aSJ.Box().GetGap());
+
+#ifdef DEBUG_OBB
+ TopoDS_Shape aBox1 = IntTools_Tools::GetOBBShapeBox(anOBBi);
+ TopoDS_Shape aBox2 = IntTools_Tools::GetOBBShapeBox(anOBBj);
+#endif
+ if (anOBBi.IsOut(anOBBj))
+ continue;
+ }
+
iX = BOPDS_Tools::TypeToInteger(aTi, aTj);
myLists(iX).Append(aPair);
}// if (aMPFence.Add(aPair)) {
#include <Standard_Boolean.hxx>
#include <TopAbs_ShapeEnum.hxx>
class BOPDS_DS;
-
+class IntTools_Context;
//! The class BOPDS_Iterator is
//! Perform the intersection algorithm and prepare
//! the results to be used
- Standard_EXPORT virtual void Prepare();
+ Standard_EXPORT virtual void Prepare(Handle(IntTools_Context)& theCtx,
+ const Standard_Boolean theCheckOBB = Standard_False);
//! Returns the number of intersections founded
Standard_EXPORT Standard_Integer ExpectedLength() const;
protected:
- Standard_EXPORT virtual void Intersect();
+ Standard_EXPORT virtual void Intersect(Handle(IntTools_Context)& theCtx,
+ const Standard_Boolean theCheckOBB = Standard_False);
BOPCol_BaseAllocator myAllocator;
Standard_Integer myLength;
#include <TopoDS.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Vertex.hxx>
+#include <IntTools_Context.hxx>
+#include <IntTools_OBB.hxx>
//
//=======================================================================
// function: Intersect
// purpose:
//=======================================================================
-void BOPDS_IteratorSI::Intersect()
+void BOPDS_IteratorSI::Intersect(Handle(IntTools_Context)& theCtx,
+ const Standard_Boolean theCheckOBB)
{
Standard_Integer i, j, iX, aNbS;
Standard_Integer iTi, iTj;
//
BOPDS_Pair aPair(i, j);
if (aMPFence.Add(aPair)) {
+ if (theCheckOBB)
+ {
+ IntTools_OBB& anOBBi = theCtx->OBB(aSI.Shape(), aSI.Box().GetGap());
+ IntTools_OBB& anOBBj = theCtx->OBB(aSJ.Shape(), aSJ.Box().GetGap());
+
+ if (anOBBi.IsOut(anOBBj))
+ continue;
+ }
+
iX = BOPDS_Tools::TypeToInteger(aTi, aTj);
myLists(iX).Append(aPair);
}// if (aMPKXB.Add(aPKXB)) {
protected:
- Standard_EXPORT virtual void Intersect() Standard_OVERRIDE;
+ Standard_EXPORT virtual void Intersect(Handle(IntTools_Context)& theCtx,
+ const Standard_Boolean theCheckOBB = Standard_False) Standard_OVERRIDE;
pBuilder->SetNonDestructive(bNonDestructive);
pBuilder->SetGlue(aGlue);
pBuilder->SetCheckInverted(BOPTest_Objects::CheckInverted());
+ pBuilder->SetUseOBB(BOPTest_Objects::UseOBB());
//
pBuilder->Build();
//
aBuilder.SetNonDestructive(bNonDestructive);
aBuilder.SetGlue(aGlue);
aBuilder.SetCheckInverted(BOPTest_Objects::CheckInverted());
+ aBuilder.SetUseOBB(BOPTest_Objects::UseOBB());
//
aBuilder.Build();
//
aSplitter.SetNonDestructive(BOPTest_Objects::NonDestructive());
aSplitter.SetGlue(BOPTest_Objects::Glue());
aSplitter.SetCheckInverted(BOPTest_Objects::CheckInverted());
+ aSplitter.SetUseOBB(BOPTest_Objects::UseOBB());
//
// performing operation
aSplitter.Build();
pPF->SetRunParallel(bRunParallel);
pPF->SetNonDestructive(bNonDestructive);
pPF->SetGlue(aGlue);
+ pPF->SetUseOBB(BOPTest_Objects::UseOBB());
//
pPF->Perform();
BOPTest::ReportAlerts(*pPF);
aSec.SetRunParallel(bRunParallel);
aSec.SetNonDestructive(bNonDestructive);
aSec.SetGlue(aGlue);
+ aSec.SetUseOBB(BOPTest_Objects::UseOBB());
//
aSec.Build();
//
aPF.SetRunParallel(bRunParallel);
aPF.SetNonDestructive(bNonDestructive);
aPF.SetGlue(aGlue);
+ aPF.SetUseOBB(BOPTest_Objects::UseOBB());
//
aPF.Perform();
BOPTest::ReportAlerts(aPF);
aMV.SetNonDestructive(bNonDestructive);
aMV.SetAvoidInternalShapes(bAvoidInternal);
aMV.SetGlue(aGlue);
+ aMV.SetUseOBB(BOPTest_Objects::UseOBB());
//
aMV.Perform();
BOPTest::ReportAlerts(aMV);
aCBuilder.SetNonDestructive(bNonDestructive);
aCBuilder.SetGlue(aGlue);
aCBuilder.SetCheckInverted(BOPTest_Objects::CheckInverted());
+ aCBuilder.SetUseOBB(BOPTest_Objects::UseOBB());
//
aCBuilder.PerformWithFiller(aPF);
BOPTest::ReportAlerts(aCBuilder);
#include <BOPCol_DataMapOfShapeShape.hxx>
#include <BOPCol_DataMapOfShapeListOfShape.hxx>
+#include <IntTools_Context.hxx>
static
void GetTypeByName(const char* theName,
char buf[64], aST1[10], aST2[10];
BOPDS_Iterator aIt;
//
+ Handle(IntTools_Context) aCtx = new IntTools_Context();
+
BOPDS_DS& aDS = *pDS;
aIt.SetDS(&aDS);
- aIt.Prepare();
+ aIt.Prepare(aCtx, BOPTest_Objects::UseOBB());
//
if (n == 1) {
// type has not been defined. show all pairs
myGlue = BOPAlgo_GlueOff;
myDrawWarnShapes = Standard_False;
myCheckInverted = Standard_True;
+ myUseOBB = Standard_False;
};
//
// Clear
return myCheckInverted;
};
//
+ void SetUseOBB(const Standard_Boolean bUse) {
+ myUseOBB = bUse;
+ };
+ //
+ Standard_Boolean UseOBB() const {
+ return myUseOBB;
+ };
protected:
//
BOPTest_Session(const BOPTest_Session&);
BOPAlgo_GlueEnum myGlue;
Standard_Boolean myDrawWarnShapes;
Standard_Boolean myCheckInverted;
+ Standard_Boolean myUseOBB;
};
//
//=======================================================================
return GetSession().CheckInverted();
}
//=======================================================================
+//function : SetUseOBB
+//purpose :
+//=======================================================================
+void BOPTest_Objects::SetUseOBB(const Standard_Boolean bUseOBB)
+{
+ GetSession().SetUseOBB(bUseOBB);
+}
+//=======================================================================
+//function : UseOBB
+//purpose :
+//=======================================================================
+Standard_Boolean BOPTest_Objects::UseOBB()
+{
+ return GetSession().UseOBB();
+}
+//=======================================================================
//function : Allocator1
//purpose :
//=======================================================================
Standard_EXPORT static Standard_Boolean CheckInverted();
+ Standard_EXPORT static void SetUseOBB(const Standard_Boolean bUseOBB);
+
+ Standard_EXPORT static Standard_Boolean UseOBB();
+
protected:
private:
static Standard_Integer bGlue(Draw_Interpretor&, Standard_Integer, const char**);
static Standard_Integer bdrawwarnshapes(Draw_Interpretor&, Standard_Integer, const char**);
static Standard_Integer bcheckinverted(Draw_Interpretor&, Standard_Integer, const char**);
+static Standard_Integer buseobb(Draw_Interpretor&, Standard_Integer, const char**);
//=======================================================================
//function : OptionCommands
__FILE__, bdrawwarnshapes, g);
theCommands.Add("bcheckinverted", "Defines whether to check the input solids on inverted status or not\n"
"Usage: bcheckinverted [0 (off) / 1 (on)]", __FILE__, bcheckinverted, g);
+ theCommands.Add("buseobb", "Enables/disables the usage of OBB\n"
+ "Usage: buseobb [0 (off) / 1 (on)]", __FILE__, buseobb, g);
}
//=======================================================================
//function : boptions
aGlue = BOPTest_Objects::Glue();
Standard_Boolean bDrawWarnShapes = BOPTest_Objects::DrawWarnShapes();
Standard_Boolean bCheckInverted = BOPTest_Objects::CheckInverted();
+ Standard_Boolean bUseOBB = BOPTest_Objects::UseOBB();
//
Sprintf(buf, " RunParallel: %d\n", bRunParallel);
di << buf;
di << buf;
Sprintf(buf, " Check for inverted solids: %s\n", bCheckInverted ? "Yes" : "No");
di << buf;
+ Sprintf(buf, " Use OBB:%s\n", bUseOBB ? "Yes" : "No");
+ di << buf;
//
return 0;
}
BOPTest_Objects::SetCheckInverted(iCheck != 0);
return 0;
}
+
+//=======================================================================
+//function : buseobb
+//purpose :
+//=======================================================================
+Standard_Integer buseobb(Draw_Interpretor& di,
+ Standard_Integer n,
+ const char** a)
+{
+ if (n != 2) {
+ di.PrintHelp(a[0]);
+ return 1;
+ }
+ //
+ Standard_Integer iUse = Draw::Atoi(a[1]);
+ BOPTest_Objects::SetUseOBB(iUse != 0);
+ return 0;
+}
aPF.SetNonDestructive(bNonDestructive);
aPF.SetFuzzyValue(aTol);
aPF.SetGlue(aGlue);
+ aPF.SetUseOBB(BOPTest_Objects::UseOBB());
//
OSD_Timer aTimer;
aTimer.Start();
using BOPAlgo_Options::GetReport;
using BOPAlgo_Options::SetProgressIndicator;
using BOPAlgo_Options::SetCheckInverted;
+ using BOPAlgo_Options::SetUseOBB;
protected:
myDSFiller->SetFuzzyValue(myFuzzyValue);
myDSFiller->SetNonDestructive(myNonDestructive);
myDSFiller->SetGlue(myGlue);
+ myDSFiller->SetUseOBB(myUseOBB);
//
SetAttributes();
//
myDSFiller->SetFuzzyValue(myFuzzyValue);
myDSFiller->SetNonDestructive(myNonDestructive);
myDSFiller->SetGlue(myGlue);
+ myDSFiller->SetUseOBB(myUseOBB);
//
myDSFiller->Perform();
//
myDSFiller->SetFuzzyValue(myFuzzyValue);
myDSFiller->SetNonDestructive(myNonDestructive);
myDSFiller->SetGlue(myGlue);
+ myDSFiller->SetUseOBB(myUseOBB);
//
myDSFiller->Perform();
//
IntTools_MarkedRangeSet.cxx
IntTools_MarkedRangeSet.hxx
IntTools_MarkedRangeSet.lxx
+IntTools_OBB.cxx
+IntTools_OBB.hxx
IntTools_PntOn2Faces.cxx
IntTools_PntOn2Faces.hxx
IntTools_PntOnFace.cxx
#include <IntTools_FClass2d.hxx>
#include <IntTools_SurfaceRangeLocalizeData.hxx>
#include <IntTools_Tools.hxx>
+#include <IntTools_OBB.hxx>
#include <Precision.hxx>
#include <Standard_Type.hxx>
#include <TopAbs_State.hxx>
myProjSDataMap(100, myAllocator),
myBndBoxDataMap(100, myAllocator),
mySurfAdaptorMap(100, myAllocator),
+ myOBBMap(100, myAllocator),
myCreateFlag(0),
myPOnSTolerance(1.e-12)
{
myProjSDataMap(100, myAllocator),
myBndBoxDataMap(100, myAllocator),
mySurfAdaptorMap(100, myAllocator),
+ myOBBMap(100, myAllocator),
myCreateFlag(1),
myPOnSTolerance(1.e-12)
{
myAllocator->Free(anAdr);
}
mySurfAdaptorMap.Clear();
+ //
+ IntTools_OBB* pOBB;
+ aIt.Initialize(myOBBMap);
+ for (; aIt.More(); aIt.Next()) {
+ anAdr=aIt.Value();
+ pOBB=(IntTools_OBB*)anAdr;
+ (*pOBB).~IntTools_OBB();
+ myAllocator->Free(anAdr);
+ }
+ myOBBMap.Clear();
}
//=======================================================================
//function : BndBox
return *pHatcher;
}
+//=======================================================================
+//function : OBB
+//purpose :
+//=======================================================================
+IntTools_OBB& IntTools_Context::OBB(const TopoDS_Shape& aS,
+ const Standard_Real theFuzzy)
+{
+ Standard_Address anAdr;
+ IntTools_OBB* pBox;
+ //
+ if (!myOBBMap.IsBound(aS))
+ {
+ pBox = (IntTools_OBB*)myAllocator->Allocate(sizeof(IntTools_OBB));
+ new (pBox) IntTools_OBB();
+ //
+ IntTools_OBB &aBox = *pBox;
+ IntTools_Tools::BuildOBB(aS, theFuzzy, aBox);
+ //
+ anAdr = (Standard_Address)pBox;
+ myOBBMap.Bind(aS, anAdr);
+ }
+ else
+ {
+ anAdr = myOBBMap.Find(aS);
+ pBox = (IntTools_OBB*)anAdr;
+ }
+ return *pBox;
+}
+
//=======================================================================
//function : SurfaceData
//purpose :
class IntTools_Curve;
class Bnd_Box;
class TopoDS_Shape;
-
+class IntTools_OBB;
//! The intersection Context contains geometrical
//! and topological toolkit (classifiers, projectors, etc).
//! Returns a reference to surface adaptor for given face
Standard_EXPORT BRepAdaptor_Surface& SurfaceAdaptor (const TopoDS_Face& theFace);
+ //! Returns a reference to surface adaptor for given face
+ Standard_EXPORT IntTools_OBB& OBB(const TopoDS_Shape& theShape,
+ const Standard_Real theFuzzy = Precision::Confusion());
+
//! Computes the boundaries of the face using surface adaptor
Standard_EXPORT void UVBounds (const TopoDS_Face& theFace,
Standard_Real& UMin,
BOPCol_DataMapOfShapeAddress myProjSDataMap;
BOPCol_DataMapOfShapeAddress myBndBoxDataMap;
BOPCol_DataMapOfShapeAddress mySurfAdaptorMap;
+ BOPCol_DataMapOfShapeAddress myOBBMap; //! Map of oriented bounding boxes
Standard_Integer myCreateFlag;
Standard_Real myPOnSTolerance;
--- /dev/null
+// Created by: Eugeny MALTCHIKOV
+// Copyright (c) 2017 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <IntTools_OBB.hxx>
+
+#include <Bnd_B3d.hxx>
+
+// =======================================================================
+// function : IsOut
+// purpose :
+// =======================================================================
+Standard_Boolean IntTools_OBB::IsOut(const IntTools_OBB& theOther) const
+{
+ if (IsVoid() || theOther.IsVoid())
+ return Standard_False;
+
+ if (myIsAABox && theOther.myIsAABox)
+ {
+ // Both boxes are axis aligned - PMax points should be defined in this case.
+ // Use Bnd_B3d::IsOut method to check if the boxes are interfering
+ Bnd_B3d myB3d(myCenter, gp_Vec(myPMin, myCenter).XYZ());
+ Bnd_B3d otherB3d(theOther.myCenter, gp_Vec(theOther.myPMin, theOther.myCenter).XYZ());
+ return myB3d.IsOut(otherB3d);
+ }
+
+ // According to the Separating Axis Theorem for Oriented Bounding Boxes
+ // it is necessary to check the 15 separating axes:
+ // - 6 axes of the boxes;
+ // - 9 cross products of the axes of the boxes.
+ // If any of these axes is valid, the boxes do not interfere.
+
+ // The algorithm is following:
+ // 1. For the analyzed axis L:
+ // 2. Half of boxes vertices are projected onto the axis.
+ // 3. The projection segments for each box are computed.
+ // The length of the segment will be:
+ // Abs((HDimX*DirX).Dot(L)) + Abs((HDimY*DirY).Dot(L)) + Abs((HDimZ*DirZ).Dot(L))
+ // 3. It is necessary to check if the distance between centers of the boxes
+ // projected onto the axis is more than the sum of the lengths
+ // of the projection segments:
+ // isOut = (theCenter2 - theCenter1).Dot(L) > (Length1 + Length2);
+
+
+ // Precomputed difference between centers
+ gp_XYZ D = theOther.myCenter - myCenter;
+
+ // Check the axes of the this box, i.e. L is one of myAxes
+ // Since the Dot product of two of these directions is null, it could be skipped:
+ // myXDirection.Dot(myYDirection) = 0
+
+ for (Standard_Integer i = 0; i < 3; ++i)
+ {
+ // Length of the first segment
+ Standard_Real aLSegm1 = myHDims[i];
+
+ // Length of the second segment
+ Standard_Real aLSegm2 = 0;
+ for (Standard_Integer j = 0; j < 3; ++j)
+ aLSegm2 += Abs(theOther.myAxesMultiplied[j].Dot(myAxes[i]));
+
+ // Distance between projected centers
+ Standard_Real aDistCC = Abs(D.Dot(myAxes[i]));
+
+ if (aDistCC > aLSegm1 + aLSegm2)
+ return Standard_True;
+ }
+
+ // Check the axes of the Other box, i.e. L is one of theOther.myAxes
+
+ for (Standard_Integer i = 0; i < 3; ++i)
+ {
+ // Length of the first segment
+ Standard_Real aLSegm1 = 0.;
+ for (Standard_Integer j = 0; j < 3; ++j)
+ aLSegm1 += Abs(myAxesMultiplied[j].Dot(theOther.myAxes[i]));
+
+ // Length of the second segment
+ Standard_Real aLSegm2 = theOther.myHDims[i];
+
+ // Distance between projected centers
+ Standard_Real aDistCC = Abs(D.Dot(theOther.myAxes[i]));
+
+ if (aDistCC > aLSegm1 + aLSegm2)
+ return Standard_True;
+ }
+
+ // Check the axes produced by the cross products
+ for (Standard_Integer i = 0; i < 3; ++i)
+ {
+ for (Standard_Integer j = 0; j < 3; ++j)
+ {
+ // Separating axis
+ gp_XYZ L = myAxes[i].Crossed(theOther.myAxes[j]);
+
+ // Length of the first segment
+ Standard_Real aLSegm1 = 0.;
+ for (Standard_Integer k = 0; k < 3; ++k)
+ aLSegm1 += Abs(myAxesMultiplied[k].Dot(L));
+
+ // Length of the second segment
+ Standard_Real aLSegm2 = 0.;
+ for (Standard_Integer k = 0; k < 3; ++k)
+ aLSegm2 += Abs(theOther.myAxesMultiplied[k].Dot(L));
+
+ // Distance between projected centers
+ Standard_Real aDistCC = Abs(D.Dot(L));
+
+ if (aDistCC > aLSegm1 + aLSegm2)
+ return Standard_True;
+ }
+ }
+
+ return Standard_False;
+}
--- /dev/null
+// Created by: Eugeny MALTCHIKOV
+// Copyright (c) 2017 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _IntTools_OBB_HeaderFile
+#define _IntTools_OBB_HeaderFile
+
+#include <Standard.hxx>
+#include <Standard_DefineAlloc.hxx>
+#include <Standard_Handle.hxx>
+#include <Standard_Real.hxx>
+#include <Standard_Boolean.hxx>
+
+#include <gp_Dir.hxx>
+#include <gp_Pnt.hxx>
+#include <gp_XYZ.hxx>
+
+//! The class describes the Oriented Bounding Box (OBB).
+//! It is defined by a center of the box, the axes and the halves
+//! of its three dimensions.
+//! The OBB are used as a second step, after intersection of the
+//! axes aligned boxes, for filtering the time-consuming interfering pairs
+//! in Boolean Operations.
+class IntTools_OBB
+{
+public:
+
+ DEFINE_STANDARD_ALLOC
+
+ //! Empty constructor
+ IntTools_OBB()
+ :
+ myIsAABox(Standard_False)
+ {
+ myHDims[0] = 0.;
+ myHDims[1] = 0.;
+ myHDims[2] = 0.;
+ }
+
+ //! Constructor taking all defining parameters
+ IntTools_OBB(const gp_Pnt& theCenter,
+ const gp_Dir& theXDirection,
+ const gp_Dir& theYDirection,
+ const gp_Dir& theZDirection,
+ const Standard_Real theHXSize,
+ const Standard_Real theHYSize,
+ const Standard_Real theHZSize)
+ :
+ myCenter (theCenter.XYZ()),
+ myIsAABox(Standard_False)
+ {
+ myAxes[0] = theXDirection.XYZ();
+ myAxes[1] = theYDirection.XYZ();
+ myAxes[2] = theZDirection.XYZ();
+
+ myHDims[0] = theHXSize;
+ myHDims[1] = theHYSize;
+ myHDims[2] = theHZSize;
+
+ myAxesMultiplied[0] = myAxes[0].Multiplied(myHDims[0]);
+ myAxesMultiplied[1] = myAxes[1].Multiplied(myHDims[1]);
+ myAxesMultiplied[2] = myAxes[2].Multiplied(myHDims[2]);
+ }
+
+ //! Sets the center of OBB
+ void SetCenter(const gp_Pnt& theCenter)
+ {
+ myCenter = theCenter.XYZ();
+ }
+
+ //! Returns the center of OBB
+ const gp_XYZ& Center() const
+ {
+ return myCenter;
+ }
+
+ //! Sets the X component of OBB - direction and size
+ void SetXComponent(const gp_Dir& theXDirection,
+ const Standard_Real theHXSize)
+ {
+ myAxes[0] = theXDirection.XYZ();
+ myHDims[0] = theHXSize;
+
+ myAxesMultiplied[0] = myAxes[0].Multiplied(myHDims[0]);
+ }
+
+ //! Returns the X Direction of OBB
+ const gp_XYZ& XDirection() const
+ {
+ return myAxes[0];
+ }
+
+ //! Returns the X Dimension of OBB
+ Standard_Real HXSize() const
+ {
+ return myHDims[0];
+ }
+
+ //! Sets the Y component of OBB - direction and size
+ void SetYComponent(const gp_Dir& theYDirection,
+ const Standard_Real theHYSize)
+ {
+ myAxes[1] = theYDirection.XYZ();
+ myHDims[1] = theHYSize;
+
+ myAxesMultiplied[1] = myAxes[1].Multiplied(myHDims[1]);
+ }
+
+ //! Returns the Y Direction of OBB
+ const gp_XYZ& YDirection() const
+ {
+ return myAxes[1];
+ }
+
+ //! Returns the Y Dimension of OBB
+ Standard_Real HYSize() const
+ {
+ return myHDims[1];
+ }
+
+ //! Sets the Z component of OBB - direction and size
+ void SetZComponent(const gp_Dir& theZDirection,
+ const Standard_Real theHZSize)
+ {
+ myAxes[2] = theZDirection.XYZ();
+ myHDims[2] = theHZSize;
+
+ myAxesMultiplied[2] = myAxes[2].Multiplied(myHDims[2]);
+ }
+
+ //! Returns the Z Direction of OBB
+ const gp_XYZ& ZDirection() const
+ {
+ return myAxes[2];
+ }
+
+ //! Returns the Z Dimension of OBB
+ Standard_Real HZSize() const
+ {
+ return myHDims[2];
+ }
+
+ //! Checks if the box is empty.
+ Standard_Boolean IsVoid() const
+ {
+ return (((myHDims[0] + myHDims[1] + myHDims[2]) < gp::Resolution()) && !myIsAABox);
+ }
+
+ //! Sets the flag for axes aligned box
+ void SetAABox(const Standard_Boolean& theFlag)
+ {
+ myIsAABox = theFlag;
+ }
+
+ //! Returns TRUE if the box is axes aligned
+ Standard_Boolean IsAABox() const
+ {
+ return myIsAABox;
+ }
+
+ //! Sets the min point
+ void SetMinPoint(const gp_Pnt& theMin)
+ {
+ myPMin = theMin.XYZ();
+ }
+
+ //! Returns the min point of the box
+ const gp_XYZ& MinPoint() const
+ {
+ return myPMin;
+ }
+
+ //! Check if the box do not interfere the other box.
+ Standard_EXPORT Standard_Boolean IsOut(const IntTools_OBB& theOther) const;
+
+private:
+
+ // OBB definition
+ gp_XYZ myCenter; //! Center of the OBB
+ gp_XYZ myAxes[3]; //! The axes of the box
+ Standard_Real myHDims[3]; //! Half-size dimensions of the OBB
+
+ gp_XYZ myAxesMultiplied[3]; //! Multiplied axes to avoid their recalculation in IsOut method
+
+ Standard_Boolean myIsAABox; //! To be set if the OBB is axis aligned box;
+ gp_XYZ myPMin; //! Min point of the box.
+};
+
+#endif
#include <TopoDS_Wire.hxx>
#include <TopTools_IndexedDataMapOfShapeShape.hxx>
+#include <gp_Ax3.hxx>
+#include <BRepGProp.hxx>
+#include <BRepBndLib.hxx>
+#include <GProp_GProps.hxx>
+#include <GProp_PrincipalProps.hxx>
+#include <BRepBuilderAPI_Transform.hxx>
+#include <IntTools_OBB.hxx>
+
+#ifdef DEBUG_OBB
+#include <BRepPrimAPI_MakeBox.hxx>
+#endif
+
static
void ParabolaTolerance(const Handle(Geom_Curve)& ,
const Standard_Real ,
//
return aDt;
}
+
+//=======================================================================
+// Function : BuildOBB
+// purpose :
+//=======================================================================
+void IntTools_Tools::BuildOBB(const TopoDS_Shape& theS,
+ const Standard_Real theFuzzy,
+ IntTools_OBB& theOBB)
+{
+ // Compute the transformation matrix to obtain more tight bounding box
+ GProp_GProps G;
+ switch (theS.ShapeType())
+ {
+ case TopAbs_VERTEX:
+ {
+ // Just make the AA box
+ const gp_Pnt& aP = BRep_Tool::Pnt(TopoDS::Vertex(theS));
+ Bnd_Box aBox;
+ aBox.Add(aP);
+ aBox.SetGap(BRep_Tool::Tolerance(TopoDS::Vertex(theS)) + theFuzzy);
+
+ theOBB.SetCenter(aP);
+ theOBB.SetXComponent(gp_Dir(1, 0, 0), aBox.GetGap());
+ theOBB.SetYComponent(gp_Dir(0, 1, 0), aBox.GetGap());
+ theOBB.SetZComponent(gp_Dir(0, 0, 1), aBox.GetGap());
+
+ theOBB.SetAABox(Standard_True);
+ theOBB.SetMinPoint(aBox.CornerMin());
+ return;
+ }
+ case TopAbs_EDGE:
+ BRepGProp::LinearProperties(theS, G, Standard_True);
+ break;
+ case TopAbs_FACE:
+ BRepGProp::SurfaceProperties(theS, G, Standard_True);
+ break;
+ case TopAbs_SOLID:
+ BRepGProp::VolumeProperties(theS, G, Standard_True);
+ break;
+ default:
+ break;
+ }
+
+ // Coordinate system in which the shape will have the optimal bounding box
+ gp_Ax3 aLocCoordSys(G.CentreOfMass(),
+ G.PrincipalProperties().ThirdAxisOfInertia(),
+ G.PrincipalProperties().FirstAxisOfInertia());
+
+ // Transform the shape to the local coordinate system
+ gp_Trsf aTrsf;
+ aTrsf.SetTransformation(aLocCoordSys);
+
+ BRepBuilderAPI_Transform aTransformer(theS, aTrsf);
+ if (aTransformer.IsDone())
+ {
+ const TopoDS_Shape& aST = aTransformer.Shape();
+
+ // Build the bounding box for oriented shape
+ Bnd_Box anOBB;
+ BRepBndLib::Add(aST, anOBB);
+ anOBB.SetGap(theFuzzy);
+
+ // Create the OBB box
+ gp_Pnt aPMin = anOBB.CornerMin();
+ gp_Pnt aPMax = anOBB.CornerMax();
+
+ // Compute the center of the box
+ gp_XYZ aCenter = (aPMin.XYZ() + aPMax.XYZ()) / 2.;
+ aTrsf.Inverted().Transforms(aCenter);
+
+ // Compute the half diagonal size of the box
+ gp_XYZ anOBBHSize = (aPMax.XYZ() - aPMin.XYZ()) / 2.;
+ // Make transformation
+ const Standard_Real * aMat = &aTrsf.Inverted().HVectorialPart().Value(1, 1);
+ // Compute axes directions of the box
+ gp_XYZ aXDir(aMat[0], aMat[3], aMat[6]);
+ gp_XYZ aYDir(aMat[1], aMat[4], aMat[7]);
+ gp_XYZ aZDir(aMat[2], aMat[5], aMat[8]);
+
+ theOBB.SetCenter(aCenter);
+ theOBB.SetXComponent(aXDir, anOBBHSize.X());
+ theOBB.SetYComponent(aYDir, anOBBHSize.Y());
+ theOBB.SetZComponent(aZDir, anOBBHSize.Z());
+
+ gp_XYZ aPMinXYZ = aPMin.XYZ();
+ aTrsf.Inverted().Transforms(aPMinXYZ);
+ theOBB.SetMinPoint(aPMinXYZ);
+#ifdef DEBUG_OBB
+ // Get the obtained box
+ GetOBBShapeBox(theOBB);
+#endif
+ }
+}
+
+
+#ifdef DEBUG_OBB
+//=======================================================================
+// Function : GetOBBShapeBox
+// purpose :
+//=======================================================================
+TopoDS_Shape IntTools_Tools::GetOBBShapeBox(const IntTools_OBB& theOBB)
+{
+ gp_Ax2 axis(theOBB.MinPoint(), theOBB.ZDirection());
+ axis.SetXDirection(theOBB.XDirection());
+ BRepPrimAPI_MakeBox aSMaker(axis, 2 * theOBB.HXSize(), 2 * theOBB.HYSize(), 2 * theOBB.HZSize());
+ const TopoDS_Shape& aSolid = aSMaker.Solid();
+
+ return aSolid;
+}
+#endif
class gp_Pln;
class Geom2d_Curve;
class Geom_Surface;
-
+class IntTools_OBB;
//! The class contains handy static functions
const Standard_Real theAngle);
+ //! Computes the Oriented Bounding box for the shape
+ Standard_EXPORT static void BuildOBB(const TopoDS_Shape& theS,
+ const Standard_Real theFuzzy,
+ IntTools_OBB& theOBB);
+
+#ifdef DEBUG_OBB
+ //! Get the solid built from the OBB box
+ Standard_EXPORT static TopoDS_Shape GetOBBShapeBox(const IntTools_OBB& theOBB);
+#endif
+
protected: