mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-08-14 13:30:48 +03:00
0029311: Implementation of the Oriented Bounding Boxes (OBB) functionality
1. The class Bnd_OBB has been created to describe the Oriented Bounding Box. 2. Several key methods have been implemented: Bnd_OBB::IsOut(...), Bnd_OBB::Add(...) and Bnd_OBB::Enlarge(...). 3. Interface of Bnd_Box class has changed. New methods have been created. See Bnd_Box.hxx for detailed information. 4. BRepBndLib and Draw_Box classes have been amended in order to provide correct work with Bnd_OBB class. 5. Interface of "bounding" DRAW-command has been changed. Please see help for detailed information. 6. New DRAW-command "isbbinterf" has been created. Please see help for detailed information. 7. "boundingstr" and "optbounding" DRAW-commands have been eliminated because their function can be made by "bounding" DRAW-command (e.g. see tests/bugs/vis/buc60857 or samples/tcl/snowflake.tcl test cases). 8. Documentation has been updated.
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
#include <Standard_Boolean.hxx>
|
||||
class TopoDS_Shape;
|
||||
class Bnd_Box;
|
||||
class Bnd_OBB;
|
||||
|
||||
|
||||
//! This package provides the bounding boxes for curves
|
||||
@@ -82,6 +83,25 @@ public:
|
||||
const Standard_Boolean useShapeTolerance = Standard_False);
|
||||
|
||||
|
||||
//! Computes the Oriented Bounding box for the shape <theS>.
|
||||
//! Two independent methods of computation are implemented:
|
||||
//! first method based on set of points (so, it demands the
|
||||
//! triangulated shape or shape with planar faces and linear edges).
|
||||
//! The second method is based on use of inertia axes and is called
|
||||
//! if use of the first method is impossible.
|
||||
//! If theIsTriangulationUsed == FALSE then the triangulation will
|
||||
//! be ignored at all.
|
||||
//! If theIsShapeToleranceUsed == TRUE then resulting box will be
|
||||
//! extended on the tolerance of the shape.
|
||||
//! theIsOptimal flag defines the algorithm for construction of initial
|
||||
//! Bnd_Box for the second method (if theIsOptimal == TRUE then
|
||||
//! this box will be created by AddOptimal(...) method).
|
||||
Standard_EXPORT static
|
||||
void AddOBB(const TopoDS_Shape& theS,
|
||||
Bnd_OBB& theOBB,
|
||||
const Standard_Boolean theIsTriangulationUsed = Standard_True,
|
||||
const Standard_Boolean theIsOptimal = Standard_False,
|
||||
const Standard_Boolean theIsShapeToleranceUsed = Standard_True);
|
||||
|
||||
protected:
|
||||
|
||||
|
494
src/BRepBndLib/BRepBndLib_1.cxx
Normal file
494
src/BRepBndLib/BRepBndLib_1.cxx
Normal file
@@ -0,0 +1,494 @@
|
||||
// Copyright (c) 1999-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 <Adaptor3d_HCurve.hxx>
|
||||
#include <Adaptor3d_HSurface.hxx>
|
||||
#include <GeomAdaptor_HCurve.hxx>
|
||||
#include <BRepBndLib.hxx>
|
||||
#include <GProp_GProps.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <Bnd_OBB.hxx>
|
||||
#include <BRepGProp.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <GProp_PrincipalProps.hxx>
|
||||
#include <gp_Ax3.hxx>
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
#include <Bnd_Box.hxx>
|
||||
#include <NCollection_List.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <Geom_Line.hxx>
|
||||
#include <TColStd_Array1OfInteger.hxx>
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <BRepAdaptor_HSurface.hxx>
|
||||
|
||||
#include <Geom_OffsetCurve.hxx>
|
||||
#include <Geom_BSplineCurve.hxx>
|
||||
#include <Geom_BezierCurve.hxx>
|
||||
#include <Geom_BSplineSurface.hxx>
|
||||
#include <Geom_BezierSurface.hxx>
|
||||
|
||||
//=======================================================================
|
||||
// Function : IsLinear
|
||||
// purpose : Returns TRUE if theC is line-like.
|
||||
//=======================================================================
|
||||
static Standard_Boolean IsLinear(const Adaptor3d_Curve& theC)
|
||||
{
|
||||
const GeomAbs_CurveType aCT = theC.GetType();
|
||||
if(aCT == GeomAbs_OffsetCurve)
|
||||
{
|
||||
return IsLinear(GeomAdaptor_Curve(theC.OffsetCurve()->BasisCurve()));
|
||||
}
|
||||
|
||||
if((aCT == GeomAbs_BSplineCurve) || (aCT == GeomAbs_BezierCurve))
|
||||
{
|
||||
// Indeed, curves with C0-continuity and degree==1, may be
|
||||
// represented with set of points. It will be possible made
|
||||
// in the future.
|
||||
|
||||
return ((theC.Degree() == 1) &&
|
||||
(theC.Continuity() != GeomAbs_C0));
|
||||
}
|
||||
|
||||
if(aCT == GeomAbs_Line)
|
||||
{
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Function : IsPlanar
|
||||
// purpose : Returns TRUE if theS is plane-like.
|
||||
//=======================================================================
|
||||
static Standard_Boolean IsPlanar(const Adaptor3d_Surface& theS)
|
||||
{
|
||||
const GeomAbs_SurfaceType aST = theS.GetType();
|
||||
if(aST == GeomAbs_OffsetSurface)
|
||||
{
|
||||
return IsPlanar(theS.BasisSurface()->Surface());
|
||||
}
|
||||
|
||||
if(aST == GeomAbs_SurfaceOfExtrusion)
|
||||
{
|
||||
return IsLinear(theS.BasisCurve()->Curve());
|
||||
}
|
||||
|
||||
if((aST == GeomAbs_BSplineSurface) || (aST == GeomAbs_BezierSurface))
|
||||
{
|
||||
if((theS.UDegree() != 1) || (theS.VDegree() != 1))
|
||||
return Standard_False;
|
||||
|
||||
// Indeed, surfaces with C0-continuity and degree==1, may be
|
||||
// represented with set of points. It will be possible made
|
||||
// in the future.
|
||||
|
||||
return ((theS.UContinuity() != GeomAbs_C0) && (theS.VContinuity() != GeomAbs_C0));
|
||||
}
|
||||
|
||||
if(aST == GeomAbs_Plane)
|
||||
{
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Function : PointsForOBB
|
||||
// purpose : Returns number of points for array.
|
||||
//
|
||||
// Attention!!!
|
||||
// 1. Start index for thePts must be 0 strictly.
|
||||
// 2. Currently, infinite edges/faces (e.g. half-space) are not
|
||||
// processed correctly because computation of UV-bounds is a costly operation.
|
||||
//=======================================================================
|
||||
static Standard_Integer PointsForOBB(const TopoDS_Shape& theS,
|
||||
const Standard_Boolean theIsTriangulationUsed,
|
||||
TColgp_Array1OfPnt* thePts = 0,
|
||||
TColStd_Array1OfReal* theArrOfToler = 0)
|
||||
{
|
||||
Standard_Integer aRetVal = 0;
|
||||
TopExp_Explorer anExpF, anExpE;
|
||||
|
||||
// get all vertices from the shape
|
||||
for(anExpF.Init(theS, TopAbs_VERTEX); anExpF.More(); anExpF.Next())
|
||||
{
|
||||
const TopoDS_Vertex &aVert = TopoDS::Vertex(anExpF.Current());
|
||||
if(thePts)
|
||||
{
|
||||
const gp_Pnt aP = BRep_Tool::Pnt(aVert);
|
||||
(*thePts)(aRetVal) = aP;
|
||||
}
|
||||
|
||||
if(theArrOfToler)
|
||||
{
|
||||
(*theArrOfToler) (aRetVal) = BRep_Tool::Tolerance(aVert);
|
||||
}
|
||||
|
||||
++aRetVal;
|
||||
}
|
||||
|
||||
if(aRetVal == 0)
|
||||
return 0;
|
||||
|
||||
// analyze the faces of the shape on planarity and existence of triangulation
|
||||
TopLoc_Location aLoc;
|
||||
for(anExpF.Init(theS, TopAbs_FACE); anExpF.More(); anExpF.Next())
|
||||
{
|
||||
const TopoDS_Face &aF = TopoDS::Face(anExpF.Current());
|
||||
const BRepAdaptor_Surface anAS(aF, Standard_False);
|
||||
|
||||
if (!IsPlanar(anAS.Surface()))
|
||||
{
|
||||
if (!theIsTriangulationUsed)
|
||||
// not planar and triangulation usage disabled
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// planar face
|
||||
for(anExpE.Init(aF, TopAbs_EDGE); anExpE.More(); anExpE.Next())
|
||||
{
|
||||
const TopoDS_Edge &anE = TopoDS::Edge(anExpE.Current());
|
||||
const BRepAdaptor_Curve anAC(anE);
|
||||
if (!IsLinear(anAC))
|
||||
{
|
||||
if (!theIsTriangulationUsed)
|
||||
// not linear and triangulation usage disabled
|
||||
return 0;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!anExpE.More())
|
||||
// skip planar face with linear edges as its vertices have already been added
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use triangulation of the face
|
||||
const Handle(Poly_Triangulation) &aTrng = BRep_Tool::Triangulation(aF, aLoc);
|
||||
if (aTrng.IsNull())
|
||||
// no triangulation on the face
|
||||
return 0;
|
||||
|
||||
const Standard_Integer aCNode = aTrng->NbNodes();
|
||||
const TColgp_Array1OfPnt& aNodesArr = aTrng->Nodes();
|
||||
for (Standard_Integer i = 1; i <= aCNode; i++)
|
||||
{
|
||||
if (thePts)
|
||||
{
|
||||
const gp_Pnt aP = aLoc.IsIdentity() ? aNodesArr(i) :
|
||||
aNodesArr(i).Transformed(aLoc);
|
||||
(*thePts)(aRetVal) = aP;
|
||||
}
|
||||
|
||||
if (theArrOfToler)
|
||||
{
|
||||
(*theArrOfToler) (aRetVal) = aTrng->Deflection();
|
||||
}
|
||||
|
||||
++aRetVal;
|
||||
}
|
||||
}
|
||||
|
||||
// Consider edges without faces
|
||||
|
||||
for(anExpE.Init(theS, TopAbs_EDGE, TopAbs_FACE); anExpE.More(); anExpE.Next())
|
||||
{
|
||||
const TopoDS_Edge &anE = TopoDS::Edge(anExpE.Current());
|
||||
const BRepAdaptor_Curve anAC(anE);
|
||||
|
||||
if (IsLinear(anAC))
|
||||
// skip linear edge as its vertices have already been added
|
||||
continue;
|
||||
|
||||
if (!theIsTriangulationUsed)
|
||||
// not linear and triangulation usage disabled
|
||||
return 0;
|
||||
|
||||
const Handle(Poly_Polygon3D) &aPolygon = BRep_Tool::Polygon3D(anE, aLoc);
|
||||
if (aPolygon.IsNull())
|
||||
return 0;
|
||||
|
||||
const Standard_Integer aCNode = aPolygon->NbNodes();
|
||||
const TColgp_Array1OfPnt& aNodesArr = aPolygon->Nodes();
|
||||
for (Standard_Integer i = 1; i <= aCNode; i++)
|
||||
{
|
||||
if (thePts)
|
||||
{
|
||||
const gp_Pnt aP = aLoc.IsIdentity() ? aNodesArr(i) :
|
||||
aNodesArr(i).Transformed(aLoc);
|
||||
(*thePts)(aRetVal) = aP;
|
||||
}
|
||||
|
||||
if (theArrOfToler)
|
||||
{
|
||||
(*theArrOfToler) (aRetVal) = aPolygon->Deflection();
|
||||
}
|
||||
|
||||
++aRetVal;
|
||||
}
|
||||
}
|
||||
|
||||
return aRetVal;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Function : IsWCS
|
||||
// purpose : Returns 0 if the theDir does not match any axis of WCS.
|
||||
// Otherwise, returns the index of correspond axis.
|
||||
//=======================================================================
|
||||
static Standard_Integer IsWCS(const gp_Dir& theDir)
|
||||
{
|
||||
const Standard_Real aToler = Precision::Angular()*Precision::Angular();
|
||||
|
||||
const Standard_Real aX = theDir.X(),
|
||||
aY = theDir.Y(),
|
||||
aZ = theDir.Z();
|
||||
|
||||
const Standard_Real aVx = aY*aY + aZ*aZ,
|
||||
aVy = aX*aX + aZ*aZ,
|
||||
aVz = aX*aX + aY*aY;
|
||||
|
||||
if(aVz < aToler)
|
||||
return 3; // Z-axis
|
||||
|
||||
if(aVy < aToler)
|
||||
return 2; // Y-axis
|
||||
|
||||
if(aVx < aToler)
|
||||
return 1; // X-axis
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Function : CheckPoints
|
||||
// purpose : Collects points for DiTO algorithm for OBB construction on
|
||||
// linear/planar shapes and shapes having triangulation
|
||||
// (http://www.idt.mdh.se/~tla/publ/FastOBBs.pdf).
|
||||
//=======================================================================
|
||||
static Standard_Boolean CheckPoints(const TopoDS_Shape& theS,
|
||||
const Standard_Boolean theIsTriangulationUsed,
|
||||
const Standard_Boolean theIsShapeToleranceUsed,
|
||||
Bnd_OBB& theOBB)
|
||||
{
|
||||
const Standard_Integer aNbPnts = PointsForOBB(theS, theIsTriangulationUsed);
|
||||
|
||||
if(aNbPnts < 1)
|
||||
return Standard_False;
|
||||
|
||||
TColgp_Array1OfPnt anArrPnts(0, theOBB.IsVoid() ? aNbPnts - 1 : aNbPnts + 7);
|
||||
TColStd_Array1OfReal anArrOfTolerances;
|
||||
if(theIsShapeToleranceUsed)
|
||||
{
|
||||
anArrOfTolerances.Resize(anArrPnts.Lower(), anArrPnts.Upper(), Standard_False);
|
||||
anArrOfTolerances.Init(0.0);
|
||||
}
|
||||
|
||||
TColStd_Array1OfReal *aPtrArrTol = theIsShapeToleranceUsed ? &anArrOfTolerances : 0;
|
||||
|
||||
PointsForOBB(theS, theIsTriangulationUsed, &anArrPnts, aPtrArrTol);
|
||||
|
||||
if(!theOBB.IsVoid())
|
||||
{
|
||||
// All points of old OBB have zero-tolerance
|
||||
theOBB.GetVertex(&anArrPnts(aNbPnts));
|
||||
}
|
||||
|
||||
#if 0
|
||||
for(Standard_Integer i = anArrPnts.Lower(); i <= anArrPnts.Upper(); i++)
|
||||
{
|
||||
const gp_Pnt &aP = anArrPnts(i);
|
||||
std::cout << "point p" << i << " " << aP.X() << ", " <<
|
||||
aP.Y() << ", " <<
|
||||
aP.Z() << ", "<< std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
theOBB.ReBuild(anArrPnts, aPtrArrTol);
|
||||
|
||||
return (!theOBB.IsVoid());
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Function : ComputeProperties
|
||||
// purpose : Computes properties of theS.
|
||||
//=======================================================================
|
||||
static void ComputeProperties(const TopoDS_Shape& theS,
|
||||
GProp_GProps& theGCommon)
|
||||
{
|
||||
TopExp_Explorer anExp;
|
||||
for(anExp.Init(theS, TopAbs_SOLID); anExp.More(); anExp.Next())
|
||||
{
|
||||
GProp_GProps aG;
|
||||
BRepGProp::VolumeProperties(anExp.Current(), aG, Standard_True);
|
||||
theGCommon.Add(aG);
|
||||
}
|
||||
|
||||
for(anExp.Init(theS, TopAbs_FACE, TopAbs_SOLID); anExp.More(); anExp.Next())
|
||||
{
|
||||
GProp_GProps aG;
|
||||
BRepGProp::SurfaceProperties(anExp.Current(), aG, Standard_True);
|
||||
theGCommon.Add(aG);
|
||||
}
|
||||
|
||||
for(anExp.Init(theS, TopAbs_EDGE, TopAbs_FACE); anExp.More(); anExp.Next())
|
||||
{
|
||||
GProp_GProps aG;
|
||||
BRepGProp::LinearProperties(anExp.Current(), aG, Standard_True);
|
||||
theGCommon.Add(aG);
|
||||
}
|
||||
|
||||
for(anExp.Init(theS, TopAbs_VERTEX, TopAbs_EDGE); anExp.More(); anExp.Next())
|
||||
{
|
||||
GProp_GProps aG(BRep_Tool::Pnt(TopoDS::Vertex(anExp.Current())));
|
||||
theGCommon.Add(aG);
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Function : ComputePCA
|
||||
// purpose : Creates OBB with axes of inertia.
|
||||
//=======================================================================
|
||||
static void ComputePCA(const TopoDS_Shape& theS,
|
||||
Bnd_OBB& theOBB,
|
||||
const Standard_Boolean theIsTriangulationUsed,
|
||||
const Standard_Boolean theIsOptimal,
|
||||
const Standard_Boolean theIsShapeToleranceUsed)
|
||||
{
|
||||
// Compute the transformation matrix to obtain more tight bounding box
|
||||
GProp_GProps aGCommon;
|
||||
ComputeProperties(theS, aGCommon);
|
||||
|
||||
// Transform the shape to the local coordinate system
|
||||
gp_Trsf aTrsf;
|
||||
|
||||
const Standard_Integer anIdx1 =
|
||||
IsWCS(aGCommon.PrincipalProperties().FirstAxisOfInertia());
|
||||
const Standard_Integer anIdx2 =
|
||||
IsWCS(aGCommon.PrincipalProperties().SecondAxisOfInertia());
|
||||
|
||||
if((anIdx1 == 0) || (anIdx2 == 0))
|
||||
{
|
||||
// Coordinate system in which the shape will have the optimal bounding box
|
||||
gp_Ax3 aLocCoordSys(aGCommon.CentreOfMass(),
|
||||
aGCommon.PrincipalProperties().ThirdAxisOfInertia(),
|
||||
aGCommon.PrincipalProperties().FirstAxisOfInertia());
|
||||
aTrsf.SetTransformation(aLocCoordSys);
|
||||
}
|
||||
|
||||
const TopoDS_Shape aST = (aTrsf.Form() == gp_Identity) ? theS :
|
||||
theS.Moved(TopLoc_Location(aTrsf));
|
||||
|
||||
// Initial axis-aligned BndBox
|
||||
Bnd_Box aShapeBox;
|
||||
if(theIsOptimal)
|
||||
{
|
||||
BRepBndLib::AddOptimal(aST, aShapeBox, theIsTriangulationUsed, theIsShapeToleranceUsed);
|
||||
}
|
||||
else
|
||||
{
|
||||
BRepBndLib::Add(aST, aShapeBox);
|
||||
}
|
||||
|
||||
gp_Pnt aPMin = aShapeBox.CornerMin();
|
||||
gp_Pnt aPMax = aShapeBox.CornerMax();
|
||||
|
||||
gp_XYZ aXDir(1, 0, 0);
|
||||
gp_XYZ aYDir(0, 1, 0);
|
||||
gp_XYZ aZDir(0, 0, 1);
|
||||
|
||||
// Compute the center of the box
|
||||
gp_XYZ aCenter = (aPMin.XYZ() + aPMax.XYZ()) / 2.;
|
||||
|
||||
// Compute the half diagonal size of the box.
|
||||
// It takes into account the gap.
|
||||
gp_XYZ anOBBHSize = (aPMax.XYZ() - aPMin.XYZ()) / 2.;
|
||||
|
||||
// Apply transformation if necessary
|
||||
if(aTrsf.Form() != gp_Identity)
|
||||
{
|
||||
aTrsf.Invert();
|
||||
aTrsf.Transforms(aCenter);
|
||||
|
||||
// Make transformation
|
||||
const Standard_Real * aMat = &aTrsf.HVectorialPart().Value(1, 1);
|
||||
// Compute axes directions of the box
|
||||
aXDir = gp_XYZ(aMat[0], aMat[3], aMat[6]);
|
||||
aYDir = gp_XYZ(aMat[1], aMat[4], aMat[7]);
|
||||
aZDir = gp_XYZ(aMat[2], aMat[5], aMat[8]);
|
||||
}
|
||||
|
||||
if(theOBB.IsVoid())
|
||||
{
|
||||
// Create the OBB box
|
||||
|
||||
// Set parameters to the OBB
|
||||
theOBB.SetCenter(aCenter);
|
||||
|
||||
theOBB.SetXComponent(aXDir, anOBBHSize.X());
|
||||
theOBB.SetYComponent(aYDir, anOBBHSize.Y());
|
||||
theOBB.SetZComponent(aZDir, anOBBHSize.Z());
|
||||
theOBB.SetAABox(aTrsf.Form() == gp_Identity);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Recreate the OBB box
|
||||
|
||||
TColgp_Array1OfPnt aListOfPnts(0, 15);
|
||||
theOBB.GetVertex(&aListOfPnts(0));
|
||||
|
||||
const Standard_Real aX = anOBBHSize.X();
|
||||
const Standard_Real aY = anOBBHSize.Y();
|
||||
const Standard_Real aZ = anOBBHSize.Z();
|
||||
|
||||
const gp_XYZ aXext = aX*aXDir,
|
||||
aYext = aY*aYDir,
|
||||
aZext = aZ*aZDir;
|
||||
|
||||
Standard_Integer aPntIdx = 8;
|
||||
aListOfPnts(aPntIdx++) = aCenter - aXext - aYext - aZext;
|
||||
aListOfPnts(aPntIdx++) = aCenter + aXext - aYext - aZext;
|
||||
aListOfPnts(aPntIdx++) = aCenter - aXext + aYext - aZext;
|
||||
aListOfPnts(aPntIdx++) = aCenter + aXext + aYext - aZext;
|
||||
aListOfPnts(aPntIdx++) = aCenter - aXext - aYext + aZext;
|
||||
aListOfPnts(aPntIdx++) = aCenter + aXext - aYext + aZext;
|
||||
aListOfPnts(aPntIdx++) = aCenter - aXext + aYext + aZext;
|
||||
aListOfPnts(aPntIdx++) = aCenter + aXext + aYext + aZext;
|
||||
|
||||
theOBB.ReBuild(aListOfPnts);
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Function : AddOBB
|
||||
// purpose :
|
||||
//=======================================================================
|
||||
void BRepBndLib::AddOBB(const TopoDS_Shape& theS,
|
||||
Bnd_OBB& theOBB,
|
||||
const Standard_Boolean theIsTriangulationUsed,
|
||||
const Standard_Boolean theIsOptimal,
|
||||
const Standard_Boolean theIsShapeToleranceUsed)
|
||||
{
|
||||
if(CheckPoints(theS, theIsTriangulationUsed, theIsShapeToleranceUsed, theOBB))
|
||||
return;
|
||||
|
||||
ComputePCA(theS, theOBB, theIsTriangulationUsed, theIsOptimal, theIsShapeToleranceUsed);
|
||||
}
|
@@ -1,2 +1,3 @@
|
||||
BRepBndLib.cxx
|
||||
BRepBndLib.hxx
|
||||
BRepBndLib_1.cxx
|
@@ -50,15 +50,35 @@
|
||||
#include <DrawTrSurf.hxx>
|
||||
#include <Geom_Plane.hxx>
|
||||
|
||||
#include <OSD_Timer.hxx>
|
||||
#include <Draw_Segment3D.hxx>
|
||||
#include <Draw_Marker3D.hxx>
|
||||
#include <Draw_MarkerShape.hxx>
|
||||
|
||||
#include <BRepPrimAPI_MakeBox.hxx>
|
||||
#include <stdio.h>
|
||||
|
||||
Standard_IMPORT Draw_Viewer dout;
|
||||
|
||||
//=======================================================================
|
||||
//function : ConvertBndToShape
|
||||
//purpose : Creates TopoDS_Solid from theBox
|
||||
//=======================================================================
|
||||
static void ConvertBndToShape(const Bnd_OBB& theBox,
|
||||
const char* const theName)
|
||||
{
|
||||
const gp_Pnt &aBaryCenter = theBox.Center();
|
||||
const gp_XYZ &aXDir = theBox.XDirection(),
|
||||
&aYDir = theBox.YDirection(),
|
||||
&aZDir = theBox.ZDirection();
|
||||
Standard_Real aHalfX = theBox.XHSize(),
|
||||
aHalfY = theBox.YHSize(),
|
||||
aHalfZ = theBox.ZHSize();
|
||||
|
||||
gp_Ax2 anAxes(aBaryCenter, aZDir, aXDir);
|
||||
anAxes.SetLocation(aBaryCenter.XYZ() - aHalfX*aXDir - aHalfY*aYDir - aHalfZ*aZDir);
|
||||
TopoDS_Solid aBox = BRepPrimAPI_MakeBox(anAxes, 2.0*aHalfX, 2.0*aHalfY, 2.0*aHalfZ);
|
||||
DBRep::Set(theName, aBox);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// addpcurve
|
||||
@@ -400,31 +420,6 @@ static Standard_Integer orientsolid(Draw_Interpretor& ,Standard_Integer n,const
|
||||
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : boundingstr
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
static Standard_Integer boundingstr(Draw_Interpretor& di,Standard_Integer n,const char** a)
|
||||
{
|
||||
if (n < 2) return 1;
|
||||
TopoDS_Shape S = DBRep::Get(a[1]);
|
||||
if (S.IsNull()) return 1;
|
||||
Bnd_Box B;
|
||||
BRepBndLib::Add(S,B);
|
||||
Standard_Real axmin,aymin,azmin,axmax,aymax,azmax;
|
||||
B.Get(axmin,aymin,azmin,axmax,aymax,azmax);
|
||||
di << axmin<<" "<< aymin<<" "<< azmin<<" "<< axmax<<" "<< aymax<<" "<< azmax;
|
||||
if (n >= 8) {
|
||||
Draw::Set(a[2],axmin) ;
|
||||
Draw::Set(a[3],aymin) ;
|
||||
Draw::Set(a[4],azmin) ;
|
||||
Draw::Set(a[5],axmax) ;
|
||||
Draw::Set(a[6],aymax) ;
|
||||
Draw::Set(a[7],azmax) ;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : getcoords
|
||||
//purpose :
|
||||
@@ -454,76 +449,380 @@ static Standard_Integer getcoords(Draw_Interpretor& di,Standard_Integer n,const
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : bounding
|
||||
//function : BoundBox
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
static Standard_Integer bounding(Draw_Interpretor& di,Standard_Integer n,const char** a)
|
||||
static Standard_Integer BoundBox(Draw_Interpretor& theDI,
|
||||
Standard_Integer theNArg,
|
||||
const char** theArgVal)
|
||||
{
|
||||
if (n < 2) return 1;
|
||||
Standard_Real axmin,aymin,azmin,axmax,aymax,azmax;
|
||||
Bnd_Box B; Handle(Draw_Box) DB;
|
||||
if(theNArg < 2)
|
||||
{
|
||||
theDI << "Use: " << theArgVal[0] << " {-s shape | -c xmin ymin zmin xmax ymax zmax} "
|
||||
"[-obb]\n\t\t[-shape name] [-dump] [-notriangulation]\n\t\t"
|
||||
"[-perfmeter name NbIters] [-nodraw] [-optimal] [-exttoler]\n\t\t"
|
||||
"[-save xmin ymin zmin xmax ymax zmax]\n\n\n";
|
||||
|
||||
theDI << "Computes a bounding box (BndBox). Two types of the source data are supported:\n";
|
||||
theDI << " * \"-s\"-option sets the shape, which will be circumscribed by the BndBox;\n";
|
||||
theDI << " * \"-c\"-option sets two opposite corners (having (xmin, ymin, zmin) and\n\t"
|
||||
"(xmax, ymax, zmax) coordinates) of the resulting\n\taxis-aligned BndBox (AABB).\n";
|
||||
theDI << "\nThe following options are supported:\n";
|
||||
theDI << " * \"-obb\". If it is switched on then the oriented BndBox (OBB) will "
|
||||
"be\n\tcreated. Otherwise, AABB will be created.\n";
|
||||
theDI << " * \"-shape\". If it is switched on then the resulting BndBox will be "
|
||||
"stored\n\tas a shape (solid) with specified name.\n";
|
||||
theDI << " * \"-nodraw\". If it is switched on then the resulting BndBox will not be\n\t"
|
||||
"drawn as DRAW-object.\n";
|
||||
theDI << " * \"-dump\". Prints the information about the created BndBox.\n";
|
||||
theDI << " * \"-notriangulation\". By default, AABB is built from existing mesh.\n\t"
|
||||
"This option allows ignoring triangulation.\n";
|
||||
theDI << " * \"-save\". Stores the information about created AABB in "
|
||||
"specified variables.\n";
|
||||
theDI << " * \"-optimal\". If it is switched on then the AABB will be optimal.\n\t"
|
||||
"This option is useful for OBB, too. It allows constructing\n\toptimal "
|
||||
"initial AABB.\n";
|
||||
theDI << " * \"-exttoler\". If it is switched on then the resulting box will be "
|
||||
"extended\n\ton the tolerance of the source shape.\n";
|
||||
theDI << " * \"-perfmeter\" - Auxiliary option. It provides compatibility "
|
||||
"with\n\tOCCT-test system. \"name\" is the counter name for "
|
||||
"\"chrono\"-TCL-command.\n\tNbIters is the number of iterations.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
TopoDS_Shape aShape;
|
||||
|
||||
if (n == 2) {
|
||||
TopoDS_Shape S = DBRep::Get(a[1]);
|
||||
if (S.IsNull()) return 1;
|
||||
BRepBndLib::Add(S,B);
|
||||
B.Get(axmin,aymin,azmin,axmax,aymax,azmax);
|
||||
DB = new Draw_Box(gp_Pnt(axmin,aymin,azmin),gp_Pnt(axmax,aymax,azmax),Draw_orange);
|
||||
dout<<DB;
|
||||
di << axmin<<" "<< aymin<<" "<< azmin<<" "<< axmax<<" "<< aymax<<" "<< azmax;
|
||||
Standard_Boolean isOBB = Standard_False;
|
||||
Standard_Boolean hasToPrint = Standard_False,
|
||||
isTriangulationReq = Standard_True,
|
||||
isOptimal = Standard_False,
|
||||
isTolerUsed = Standard_False,
|
||||
hasToDraw = Standard_True;
|
||||
Standard_Integer aNbIters = 1;
|
||||
Standard_Integer aStartIdxToSave = -1,
|
||||
aStartIdxToCreate = -1,
|
||||
aNameToShape = -1,
|
||||
anIdxCounterName = -1;
|
||||
|
||||
for(Standard_Integer anAIdx = 1; anAIdx < theNArg; anAIdx++)
|
||||
{
|
||||
if(theArgVal[anAIdx][0] != '-')
|
||||
{
|
||||
theDI << "Error: Wrong option \"" << theArgVal[anAIdx] <<
|
||||
"\". Please use \'-\' symbol\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!strcmp(theArgVal[anAIdx], "-s"))
|
||||
{
|
||||
aShape = DBRep::Get(theArgVal[++anAIdx]);
|
||||
if(aShape.IsNull())
|
||||
{
|
||||
theDI << "Error: Argument " << theArgVal[anAIdx] << " is not a shape.\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if(!strcmp(theArgVal[anAIdx], "-c"))
|
||||
{
|
||||
aStartIdxToCreate = anAIdx + 1;
|
||||
anAIdx += 6;
|
||||
}
|
||||
else if(!strncmp(theArgVal[anAIdx], "-obb", 4))
|
||||
{
|
||||
isOBB = Standard_True;
|
||||
}
|
||||
else if(!strncmp(theArgVal[anAIdx], "-shape", 4))
|
||||
{
|
||||
aNameToShape = ++anAIdx;
|
||||
}
|
||||
else if(!strncmp(theArgVal[anAIdx], "-dump", 4))
|
||||
{
|
||||
hasToPrint = Standard_True;
|
||||
}
|
||||
else if(!strncmp(theArgVal[anAIdx], "-save", 4))
|
||||
{
|
||||
aStartIdxToSave = anAIdx+1;
|
||||
anAIdx += 6;
|
||||
}
|
||||
else if(!strncmp(theArgVal[anAIdx], "-notriangulation", 9))
|
||||
{
|
||||
isTriangulationReq = Standard_False;
|
||||
}
|
||||
else if(!strncmp(theArgVal[anAIdx], "-perfmeter", 8))
|
||||
{
|
||||
anIdxCounterName = ++anAIdx;
|
||||
aNbIters = Draw::Atoi(theArgVal[++anAIdx]);
|
||||
}
|
||||
else if(!strncmp(theArgVal[anAIdx], "-optimal", 4))
|
||||
{
|
||||
isOptimal = Standard_True;
|
||||
}
|
||||
else if(!strcmp(theArgVal[anAIdx], "-exttoler"))
|
||||
{
|
||||
isTolerUsed = Standard_True;
|
||||
}
|
||||
else if(!strcmp(theArgVal[anAIdx], "-nodraw"))
|
||||
{
|
||||
hasToDraw = Standard_False;
|
||||
}
|
||||
else
|
||||
{
|
||||
theDI << "Error: Unknown option \"" << theArgVal[anAIdx] << "\".\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (n == 7) {
|
||||
axmin=Draw::Atof(a[1]);
|
||||
aymin=Draw::Atof(a[2]);
|
||||
azmin=Draw::Atof(a[3]);
|
||||
axmax=Draw::Atof(a[4]);
|
||||
aymax=Draw::Atof(a[5]);
|
||||
azmax=Draw::Atof(a[6]);
|
||||
DB = new Draw_Box(gp_Pnt(axmin,aymin,azmin),gp_Pnt(axmax,aymax,azmax),Draw_orange);
|
||||
dout<<DB;
|
||||
|
||||
if(aShape.IsNull() && (aStartIdxToCreate < 0))
|
||||
{
|
||||
theDI << "Error: One of the options \'-s\' or \'-c\' must be set necessarily.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(aStartIdxToCreate > 0)
|
||||
{
|
||||
if(!aShape.IsNull())
|
||||
{
|
||||
theDI << "Error: Options \'-s\' and \'-c\' are fail for using simultaneously.\n";
|
||||
return 1;
|
||||
}
|
||||
else if(isOBB)
|
||||
{
|
||||
theDI << "Error: Options \'-c\' and \"-obb\" are fail for using simultaneously.\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(isOptimal)
|
||||
{
|
||||
if(aShape.IsNull())
|
||||
{
|
||||
theDI << "Error: Options \"-optimal\" is used without any shape. "
|
||||
"Use \'-s\'-option.\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(isTolerUsed)
|
||||
{
|
||||
if(aShape.IsNull())
|
||||
{
|
||||
theDI << "Error: Option \"-exttoler\" is used without any shape. "
|
||||
"Use \'-s\'-option.\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
Handle(Draw_Box) aDB;
|
||||
OSD_Timer aTimer;
|
||||
|
||||
if(isOBB)
|
||||
{
|
||||
if(aStartIdxToSave > 0)
|
||||
{
|
||||
theDI << "Error: Option \"-save\" work only with axes-aligned boxes.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
Bnd_OBB anOBB;
|
||||
Standard_Integer aN = aNbIters;
|
||||
|
||||
aTimer.Start();
|
||||
while(aN-- > 0)
|
||||
{
|
||||
anOBB.SetVoid();
|
||||
BRepBndLib::AddOBB(aShape, anOBB, isTriangulationReq, isOptimal, isTolerUsed);
|
||||
}
|
||||
aTimer.Stop();
|
||||
|
||||
if(anOBB.IsVoid())
|
||||
{
|
||||
theDI << "Void box.\n";
|
||||
hasToPrint = Standard_False;
|
||||
}
|
||||
|
||||
const gp_Pnt &aBaryCenter= anOBB.Center();
|
||||
const gp_XYZ &aXDir = anOBB.XDirection(),
|
||||
&aYDir = anOBB.YDirection(),
|
||||
&aZDir = anOBB.ZDirection();
|
||||
Standard_Real aHalfX = anOBB.XHSize(),
|
||||
aHalfY = anOBB.YHSize(),
|
||||
aHalfZ = anOBB.ZHSize();
|
||||
|
||||
if(hasToPrint)
|
||||
{
|
||||
theDI << "Oriented bounding box\n";
|
||||
theDI << "Center: " << aBaryCenter.X() << " " <<
|
||||
aBaryCenter.Y() << " " <<
|
||||
aBaryCenter.Z() << "\n";
|
||||
theDI << "X-axis: " << aXDir.X() << " " << aXDir.Y() << " " << aXDir.Z() << "\n";
|
||||
theDI << "Y-axis: " << aYDir.X() << " " << aYDir.Y() << " " << aYDir.Z() << "\n";
|
||||
theDI << "Z-axis: " << aZDir.X() << " " << aZDir.Y() << " " << aZDir.Z() << "\n";
|
||||
theDI << "Half X: " << aHalfX << "\n" <<
|
||||
"Half Y: " << aHalfY << "\n" << "Half Z: " << aHalfZ << "\n";
|
||||
}
|
||||
|
||||
if(hasToDraw)
|
||||
aDB = new Draw_Box(anOBB, Draw_orange);
|
||||
|
||||
if(aNameToShape > 0)
|
||||
{
|
||||
ConvertBndToShape(anOBB, theArgVal[aNameToShape]);
|
||||
}
|
||||
}
|
||||
else // if(!isOBB)
|
||||
{
|
||||
Standard_Real aXmin = RealFirst(), aYmin = RealFirst(), aZmin = RealFirst(),
|
||||
aXMax = RealLast(), aYMax = RealLast(), aZMax = RealLast();
|
||||
|
||||
Bnd_Box anAABB;
|
||||
|
||||
if(aStartIdxToCreate < 0)
|
||||
{
|
||||
Standard_Integer aN = aNbIters;
|
||||
if(isOptimal)
|
||||
{
|
||||
aTimer.Start();
|
||||
while(aN-- > 0)
|
||||
{
|
||||
anAABB.SetVoid();
|
||||
BRepBndLib::AddOptimal(aShape, anAABB, isTriangulationReq, isTolerUsed);
|
||||
}
|
||||
aTimer.Stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
aTimer.Start();
|
||||
while(aN-- > 0)
|
||||
{
|
||||
anAABB.SetVoid();
|
||||
BRepBndLib::Add(aShape, anAABB, isTriangulationReq);
|
||||
}
|
||||
aTimer.Stop();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(anIdxCounterName > 0)
|
||||
{
|
||||
theDI << "Error: Option \"-perfmeter\"does not work if the option \'-c\' "
|
||||
"is switched on.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
Standard_Integer anIdx = aStartIdxToCreate;
|
||||
aXmin = Draw::Atof(theArgVal[anIdx++]);
|
||||
aYmin = Draw::Atof(theArgVal[anIdx++]);
|
||||
aZmin = Draw::Atof(theArgVal[anIdx++]);
|
||||
aXMax = Draw::Atof(theArgVal[anIdx++]);
|
||||
aYMax = Draw::Atof(theArgVal[anIdx++]);
|
||||
aZMax = Draw::Atof(theArgVal[anIdx++]);
|
||||
|
||||
anAABB.Add(gp_Pnt(aXmin, aYmin, aZmin));
|
||||
anAABB.Add(gp_Pnt(aXMax, aYMax, aZMax));
|
||||
}
|
||||
|
||||
if(anAABB.IsVoid())
|
||||
{
|
||||
theDI << "Void box.\n";
|
||||
hasToPrint = Standard_False;
|
||||
}
|
||||
|
||||
if(hasToPrint || (aStartIdxToSave>0))
|
||||
{
|
||||
anAABB.Get(aXmin, aYmin, aZmin, aXMax, aYMax, aZMax);
|
||||
|
||||
if(hasToPrint)
|
||||
{
|
||||
theDI << "Axes-aligned bounding box\n";
|
||||
theDI << "X-range: " << aXmin << " " << aXMax << "\n" <<
|
||||
"Y-range: " << aYmin << " " << aYMax << "\n" <<
|
||||
"Z-range: " << aZmin << " " << aZMax << "\n";
|
||||
}
|
||||
|
||||
if(aStartIdxToSave > 0)
|
||||
{
|
||||
Draw::Set(theArgVal[aStartIdxToSave++], aXmin);
|
||||
Draw::Set(theArgVal[aStartIdxToSave++], aYmin);
|
||||
Draw::Set(theArgVal[aStartIdxToSave++], aZmin);
|
||||
Draw::Set(theArgVal[aStartIdxToSave++], aXMax);
|
||||
Draw::Set(theArgVal[aStartIdxToSave++], aYMax);
|
||||
Draw::Set(theArgVal[aStartIdxToSave++], aZMax);
|
||||
}
|
||||
}
|
||||
|
||||
if(hasToDraw)
|
||||
aDB = new Draw_Box(anAABB, Draw_orange);
|
||||
|
||||
if(aNameToShape > 0)
|
||||
{
|
||||
ConvertBndToShape(anAABB, theArgVal[aNameToShape]);
|
||||
}
|
||||
}
|
||||
|
||||
if(hasToDraw)
|
||||
dout << aDB;
|
||||
|
||||
if(anIdxCounterName > 0)
|
||||
{
|
||||
theDI << "COUNTER " << theArgVal[anIdxCounterName] << ": " << aTimer.ElapsedTime() << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : optbounding
|
||||
//function : IsBoxesInterfered
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
static Standard_Integer optbounding(Draw_Interpretor& di,Standard_Integer n,const char** a)
|
||||
static Standard_Integer IsBoxesInterfered(Draw_Interpretor& theDI,
|
||||
Standard_Integer theNArg,
|
||||
const char** theArgVal)
|
||||
{
|
||||
if (n < 2)
|
||||
if(theNArg < 2)
|
||||
{
|
||||
di << "Usage: optbounding shape [usetri [usetol]]\n";
|
||||
di << "usetri and usetol can be 0 or 1, by default usetri = 1, usetol = 0\n";
|
||||
theDI << "Use: isbbinterf shape1 shape2 [-o].\n";
|
||||
return 1;
|
||||
}
|
||||
Standard_Real axmin,aymin,azmin,axmax,aymax,azmax;
|
||||
Bnd_Box B; Handle(Draw_Box) DB;
|
||||
|
||||
TopoDS_Shape S = DBRep::Get(a[1]);
|
||||
if (S.IsNull())
|
||||
|
||||
const TopoDS_Shape aShape1 = DBRep::Get(theArgVal[1]);
|
||||
const TopoDS_Shape aShape2 = DBRep::Get(theArgVal[2]);
|
||||
|
||||
Standard_Boolean isOBB = (theNArg > 3) && (!strcmp(theArgVal[3], "-o"));
|
||||
|
||||
if(isOBB)
|
||||
{
|
||||
di << "Null shape\n";
|
||||
return 1;
|
||||
Bnd_OBB anOBB1, anOBB2;
|
||||
BRepBndLib::AddOBB(aShape1, anOBB1);
|
||||
BRepBndLib::AddOBB(aShape2, anOBB2);
|
||||
|
||||
if(anOBB1.IsOut(anOBB2))
|
||||
{
|
||||
theDI << "The shapes are NOT interfered by OBB.\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
theDI << "The shapes are interfered by OBB.\n";
|
||||
}
|
||||
}
|
||||
Standard_Boolean useTri = Standard_True;
|
||||
Standard_Boolean useTol = Standard_False;
|
||||
if(n > 2 )
|
||||
else
|
||||
{
|
||||
Standard_Integer ii = atoi(a[2]);
|
||||
useTri = ii > 0;
|
||||
Bnd_Box anAABB1, anAABB2;
|
||||
BRepBndLib::Add(aShape1, anAABB1);
|
||||
BRepBndLib::Add(aShape2, anAABB2);
|
||||
|
||||
if(anAABB1.IsOut(anAABB2))
|
||||
{
|
||||
theDI << "The shapes are NOT interfered by AABB.\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
theDI << "The shapes are interfered by AABB.\n";
|
||||
}
|
||||
}
|
||||
if(n > 3 )
|
||||
{
|
||||
Standard_Integer ii = atoi(a[3]);
|
||||
useTol = ii > 0;
|
||||
}
|
||||
BRepBndLib::AddOptimal(S, B, useTri, useTol);
|
||||
B.Get(axmin, aymin, azmin, axmax, aymax, azmax);
|
||||
DB = new Draw_Box(gp_Pnt(axmin,aymin,azmin),gp_Pnt(axmax,aymax,azmax),Draw_vert);
|
||||
dout<<DB;
|
||||
di << axmin<<" "<< aymin<<" "<< azmin<<" "<< axmax<<" "<< aymax<<" "<< azmax;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : gbounding
|
||||
//purpose :
|
||||
@@ -600,7 +899,7 @@ static Standard_Integer gbounding(Draw_Interpretor& di,Standard_Integer n,const
|
||||
if (Is3d)
|
||||
{
|
||||
B.Get(axmin,aymin,azmin,axmax,aymax,azmax);
|
||||
DB = new Draw_Box(gp_Pnt(axmin,aymin,azmin),gp_Pnt(axmax,aymax,azmax),Draw_vert);
|
||||
DB = new Draw_Box(B, Draw_vert);
|
||||
dout<<DB;
|
||||
di << axmin<<" "<< aymin<<" "<< azmin<<" "<< axmax<<" "<< aymax<<" "<< azmax;
|
||||
}
|
||||
@@ -1208,25 +1507,21 @@ void BRepTest::BasicCommands(Draw_Interpretor& theCommands)
|
||||
__FILE__,
|
||||
getcoords,g);
|
||||
|
||||
theCommands.Add("bounding",
|
||||
"bounding shape [ xmin ymin zmin xmax ymax zmax] ; draw bounds",
|
||||
__FILE__,
|
||||
bounding,g);
|
||||
theCommands.Add("bounding", "enter the comand w/o any arguments to obtain the help.",
|
||||
__FILE__, BoundBox, g);
|
||||
|
||||
theCommands.Add("optbounding",
|
||||
"optbounding shape [usetri (0/1) [usetol (0/1)]] ; ",
|
||||
__FILE__,
|
||||
optbounding,g);
|
||||
//
|
||||
theCommands.Add("gbounding",
|
||||
"gbounding surf/curve/curve2d [-o] ",
|
||||
__FILE__,
|
||||
gbounding,g);
|
||||
|
||||
theCommands.Add("boundingstr",
|
||||
"boundingstr shape [ xmin ymin zmin xmax ymax zmax] ; print bounding box",
|
||||
__FILE__,
|
||||
boundingstr,g);
|
||||
theCommands.Add("isbbinterf", "isbbinterf shape1 shape2 [-o]\n"
|
||||
"Checks whether the bounding-boxes created from "
|
||||
"the given shapes are interfered. If \"-o\"-option "
|
||||
"is switched on then the oriented boxes will be checked. "
|
||||
"Otherwise, axes-aligned boxes will be checked.",
|
||||
__FILE__, IsBoxesInterfered, g);
|
||||
|
||||
theCommands.Add("nurbsconvert",
|
||||
"nurbsconvert result name [result name]",
|
||||
|
679
src/Bnd/Bnd_OBB.cxx
Normal file
679
src/Bnd/Bnd_OBB.cxx
Normal file
@@ -0,0 +1,679 @@
|
||||
// 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 <Bnd_OBB.hxx>
|
||||
|
||||
#include <Bnd_B3d.hxx>
|
||||
#include <NCollection_Array1.hxx>
|
||||
#include <Precision.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
|
||||
class OBBTool
|
||||
{
|
||||
public:
|
||||
//! Constructor. theL - list of points.
|
||||
//! theLT is a pointer to the list of tolerances
|
||||
//! (i-th element of this array is a tolerance
|
||||
//! of i-th point in theL). If theLT is empty
|
||||
//! then the tolerance of every point is equal to 0.
|
||||
//! Attention! The objects, which theL and theLT links on,
|
||||
//! must be available during all time of OBB creation
|
||||
//! (i.e. while the object of OBBTool exists).
|
||||
OBBTool(const TColgp_Array1OfPnt& theL,
|
||||
const TColStd_Array1OfReal *theLT = 0);
|
||||
|
||||
//! DiTO algorithm for OBB construction
|
||||
//! (http://www.idt.mdh.se/~tla/publ/FastOBBs.pdf)
|
||||
void ProcessDiTetrahedron();
|
||||
|
||||
//! Creates OBB with already computed parameters
|
||||
void BuildBox(Bnd_OBB& theBox);
|
||||
|
||||
protected:
|
||||
//! Works with the triangle set by the points in myTriIdx.
|
||||
//! If theIsBuiltTrg == TRUE, new set of triangles will be
|
||||
//! recomputed.
|
||||
void ProcessTriangle(const Standard_Integer theIdx1,
|
||||
const Standard_Integer theIdx2,
|
||||
const Standard_Integer theIdx3,
|
||||
const Standard_Boolean theIsBuiltTrg);
|
||||
|
||||
//! Computes myTriIdx[2]
|
||||
void FillToTriangle3();
|
||||
|
||||
//! Computes myTriIdx[3] and myTriIdx[4]
|
||||
void FillToTriangle5(const gp_XYZ& theNormal,
|
||||
const gp_XYZ& theBarryCenter);
|
||||
|
||||
//! Returns half of the Surface area of the box
|
||||
static Standard_Real ComputeQuality(const Standard_Real* const thePrmArr)
|
||||
{
|
||||
const Standard_Real aDX = thePrmArr[1] - thePrmArr[0],
|
||||
aDY = thePrmArr[3] - thePrmArr[2],
|
||||
aDZ = thePrmArr[5] - thePrmArr[4];
|
||||
|
||||
return (aDX*aDY + aDY*aDZ + aDX*aDZ);
|
||||
}
|
||||
|
||||
protected:
|
||||
//! Assignment operator is forbidden
|
||||
OBBTool& operator=(const OBBTool&);
|
||||
|
||||
private:
|
||||
//! Number of the initial axes.
|
||||
static const Standard_Integer myNbInitAxes = 7;
|
||||
|
||||
//! Number of extremal points
|
||||
static const Standard_Integer myNbExtremalPoints = 2 * myNbInitAxes;
|
||||
|
||||
//! The source list of points
|
||||
const TColgp_Array1OfPnt& myPntsList;
|
||||
|
||||
//! Pointer to the array of tolerances
|
||||
const TColStd_Array1OfReal *myListOfTolers;
|
||||
|
||||
//! Points of ditetrahedron
|
||||
//! given by their indices in myLExtremalPoints.
|
||||
Standard_Integer myTriIdx[5];
|
||||
|
||||
//! List of extremal points
|
||||
gp_XYZ myLExtremalPoints[myNbExtremalPoints];
|
||||
|
||||
//! The axes of the box (always normalized or
|
||||
//! can be null-vector)
|
||||
gp_XYZ myAxes[3];
|
||||
|
||||
//! The surface area of the OBB
|
||||
Standard_Real myQualityCriterion;
|
||||
};
|
||||
|
||||
//=======================================================================
|
||||
// Function : SetMinMax
|
||||
// purpose :
|
||||
// ATTENTION!!! thePrmArr must be initialized before this method calling.
|
||||
//=======================================================================
|
||||
static inline void SetMinMax(Standard_Real* const thePrmArr,
|
||||
const Standard_Real theNewParam)
|
||||
{
|
||||
if(theNewParam < thePrmArr[0])
|
||||
{
|
||||
thePrmArr[0] = theNewParam;
|
||||
}
|
||||
else if(theNewParam > thePrmArr[1])
|
||||
{
|
||||
thePrmArr[1] = theNewParam;
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Function : Constructor
|
||||
// purpose :
|
||||
//=======================================================================
|
||||
OBBTool::
|
||||
OBBTool(const TColgp_Array1OfPnt& theL,
|
||||
const TColStd_Array1OfReal *theLT) :myPntsList(theL),
|
||||
myListOfTolers(theLT),
|
||||
myQualityCriterion(RealLast())
|
||||
{
|
||||
const Standard_Real aSqrt3 = Sqrt(3);
|
||||
// Origin of all initial axis is (0,0,0).
|
||||
// All axes must be normalized.
|
||||
const gp_XYZ anInitialAxesArray[myNbInitAxes] = {gp_XYZ(1.0, 0.0, 0.0),
|
||||
gp_XYZ(0.0, 1.0, 0.0),
|
||||
gp_XYZ(0.0, 0.0, 1.0),
|
||||
gp_XYZ(1.0, 1.0, 1.0) / aSqrt3,
|
||||
gp_XYZ(1.0, 1.0, -1.0) / aSqrt3,
|
||||
gp_XYZ(1.0, -1.0, 1.0) / aSqrt3,
|
||||
gp_XYZ(1.0, -1.0, -1.0) / aSqrt3};
|
||||
|
||||
// Minimal and maximal point on every axis
|
||||
const Standard_Integer aNbPoints = 2 * myNbInitAxes;
|
||||
|
||||
for(Standard_Integer i = 0; i < 5; i++)
|
||||
{
|
||||
myTriIdx[i] = INT_MAX;
|
||||
}
|
||||
|
||||
// Min and Max parameter
|
||||
Standard_Real aParams[aNbPoints];
|
||||
for(Standard_Integer i = 0; i < aNbPoints; i += 2)
|
||||
{
|
||||
aParams[i] = RealLast();
|
||||
aParams[i + 1] = RealFirst();
|
||||
}
|
||||
|
||||
// Look for the extremal points (myLExtremalPoints)
|
||||
for(Standard_Integer i = myPntsList.Lower() ; i <= myPntsList.Upper(); i++)
|
||||
{
|
||||
const gp_XYZ &aCurrPoint = myPntsList(i).XYZ();
|
||||
for(Standard_Integer anAxeInd = 0, aPrmInd = 0; anAxeInd < myNbInitAxes; anAxeInd++, aPrmInd++)
|
||||
{
|
||||
const Standard_Real aParam = aCurrPoint.Dot(anInitialAxesArray[anAxeInd]);
|
||||
if(aParam < aParams[aPrmInd])
|
||||
{
|
||||
myLExtremalPoints[aPrmInd] = aCurrPoint;
|
||||
aParams[aPrmInd] = aParam;
|
||||
}
|
||||
aPrmInd++;
|
||||
|
||||
if(aParam > aParams[aPrmInd])
|
||||
{
|
||||
myLExtremalPoints[aPrmInd] = aCurrPoint;
|
||||
aParams[aPrmInd] = aParam;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compute myTriIdx[0] and myTriIdx[1].
|
||||
|
||||
Standard_Real aMaxSqDist = -1.0;
|
||||
for(Standard_Integer aPrmInd = 0; aPrmInd < aNbPoints; aPrmInd += 2)
|
||||
{
|
||||
const gp_Pnt &aP1 = myLExtremalPoints[aPrmInd],
|
||||
&aP2 = myLExtremalPoints[aPrmInd + 1];
|
||||
const Standard_Real aSqDist = aP1.SquareDistance(aP2);
|
||||
if(aSqDist > aMaxSqDist)
|
||||
{
|
||||
aMaxSqDist = aSqDist;
|
||||
myTriIdx[0] = aPrmInd;
|
||||
myTriIdx[1] = aPrmInd + 1;
|
||||
}
|
||||
}
|
||||
|
||||
FillToTriangle3();
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Function : FillToTriangle3
|
||||
// purpose : Two value of myTriIdx array is known. Let us find myTriIdx[2].
|
||||
// It must be in maximal distance from the infinite axis going
|
||||
// through the points with indexes myTriIdx[0] and myTriIdx[1].
|
||||
//=======================================================================
|
||||
void OBBTool::FillToTriangle3()
|
||||
{
|
||||
const gp_XYZ &aP0 = myLExtremalPoints[myTriIdx[0]];
|
||||
const gp_XYZ anAxis = myLExtremalPoints[myTriIdx[1]] - aP0;
|
||||
Standard_Real aMaxSqDist = -1.0;
|
||||
for(Standard_Integer i = 0; i < myNbExtremalPoints; i++)
|
||||
{
|
||||
if((i == myTriIdx[0]) || (i == myTriIdx[1]))
|
||||
continue;
|
||||
|
||||
const gp_XYZ &aP = myLExtremalPoints[i];
|
||||
const Standard_Real aDistToAxe = anAxis.CrossSquareMagnitude(aP - aP0);
|
||||
if(aDistToAxe > aMaxSqDist)
|
||||
{
|
||||
myTriIdx[2] = i;
|
||||
aMaxSqDist = aDistToAxe;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Function : FillToTriangle5
|
||||
// purpose : Three value of myTriIdx array is known.
|
||||
// Let us find myTriIdx[3] and myTriIdx[4].
|
||||
// They must be in the different sides of the plane of
|
||||
// triangle set by points myTriIdx[0], myTriIdx[1] and
|
||||
// myTriIdx[2]. Moreover, the distance from these points
|
||||
// to the triangle plane must be maximal.
|
||||
//=======================================================================
|
||||
void OBBTool::FillToTriangle5(const gp_XYZ& theNormal,
|
||||
const gp_XYZ& theBarryCenter)
|
||||
{
|
||||
Standard_Real aParams[2] = {0.0, 0.0};
|
||||
|
||||
for(Standard_Integer aPtIdx = 0; aPtIdx < myNbExtremalPoints; aPtIdx++)
|
||||
{
|
||||
if((aPtIdx == myTriIdx[0]) || (aPtIdx == myTriIdx[1]) || (aPtIdx == myTriIdx[2]))
|
||||
continue;
|
||||
|
||||
const gp_XYZ &aCurrPoint = myLExtremalPoints[aPtIdx];
|
||||
const Standard_Real aParam = theNormal.Dot(aCurrPoint - theBarryCenter);
|
||||
|
||||
if(aParam < aParams[0])
|
||||
{
|
||||
myTriIdx[3] = aPtIdx;
|
||||
aParams[0] = aParam;
|
||||
}
|
||||
else if(aParam > aParams[1])
|
||||
{
|
||||
myTriIdx[4] = aPtIdx;
|
||||
aParams[1] = aParam;
|
||||
}
|
||||
}
|
||||
|
||||
// The points must be in the different sides of the triangle plane.
|
||||
if(aParams[0] > -Precision::Confusion())
|
||||
{
|
||||
myTriIdx[3] = INT_MAX;
|
||||
}
|
||||
|
||||
if(aParams[1] < Precision::Confusion())
|
||||
{
|
||||
myTriIdx[4] = INT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Function : ProcessTriangle
|
||||
// purpose : Choose the optimal box with triple axes containing normal
|
||||
// to the triangle and some edge of the triangle (3rd axis is
|
||||
// computed from these two ones).
|
||||
//=======================================================================
|
||||
void OBBTool::ProcessTriangle(const Standard_Integer theIdx1,
|
||||
const Standard_Integer theIdx2,
|
||||
const Standard_Integer theIdx3,
|
||||
const Standard_Boolean theIsBuiltTrg)
|
||||
{
|
||||
const Standard_Integer aNbAxes = 3;
|
||||
|
||||
//Some vertex of the triangle
|
||||
const gp_XYZ aP0 = myLExtremalPoints[theIdx1];
|
||||
|
||||
// All axes must be normalized in order to provide correct area computation
|
||||
// (see ComputeQuality(...) method).
|
||||
gp_XYZ aYAxis[aNbAxes] = {(myLExtremalPoints[theIdx2] - myLExtremalPoints[theIdx1]),
|
||||
(myLExtremalPoints[theIdx3] - myLExtremalPoints[theIdx2]),
|
||||
(myLExtremalPoints[theIdx1] - myLExtremalPoints[theIdx3])};
|
||||
|
||||
// Normal to the triangle plane
|
||||
gp_XYZ aZAxis = aYAxis[0].Crossed(aYAxis[1]);
|
||||
|
||||
Standard_Real aSqMod = aZAxis.SquareModulus();
|
||||
|
||||
if(aSqMod < Precision::SquareConfusion())
|
||||
return;
|
||||
|
||||
aZAxis /= Sqrt(aSqMod);
|
||||
|
||||
gp_XYZ aXAxis[aNbAxes];
|
||||
for(Standard_Integer i = 0; i < aNbAxes; i++)
|
||||
{
|
||||
aXAxis[i] = aYAxis[i].Crossed(aZAxis).Normalized();
|
||||
aYAxis[i].Normalize();
|
||||
}
|
||||
|
||||
if(theIsBuiltTrg)
|
||||
FillToTriangle5(aZAxis, aP0);
|
||||
|
||||
// Min and Max parameter
|
||||
const Standard_Integer aNbPoints = 2 * aNbAxes;
|
||||
|
||||
Standard_Integer aMinIdx = -1;
|
||||
for(Standard_Integer anAxeInd = 0; anAxeInd < aNbAxes; anAxeInd++)
|
||||
{
|
||||
const gp_XYZ &aAX = aXAxis[anAxeInd],
|
||||
&aAY = aYAxis[anAxeInd];
|
||||
|
||||
Standard_Real aParams[aNbPoints] = {0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0};
|
||||
|
||||
for(Standard_Integer aPtIdx = 0; aPtIdx < myNbExtremalPoints; aPtIdx++)
|
||||
{
|
||||
if(aPtIdx == theIdx1)
|
||||
continue;
|
||||
|
||||
const gp_XYZ aCurrPoint = myLExtremalPoints[aPtIdx] - aP0;
|
||||
SetMinMax(&aParams[0], aAX.Dot(aCurrPoint));
|
||||
SetMinMax(&aParams[2], aAY.Dot(aCurrPoint));
|
||||
SetMinMax(&aParams[4], aZAxis.Dot(aCurrPoint));
|
||||
}
|
||||
|
||||
const Standard_Real anArea = ComputeQuality(aParams);
|
||||
if(anArea < myQualityCriterion)
|
||||
{
|
||||
myQualityCriterion = anArea;
|
||||
aMinIdx = anAxeInd;
|
||||
}
|
||||
}
|
||||
|
||||
if(aMinIdx < 0)
|
||||
return;
|
||||
|
||||
myAxes[0] = aXAxis[aMinIdx];
|
||||
myAxes[1] = aYAxis[aMinIdx];
|
||||
myAxes[2] = aZAxis;
|
||||
}
|
||||
//=======================================================================
|
||||
// Function : ProcessDiTetrahedron
|
||||
// purpose : DiTo-algorithm (http://www.idt.mdh.se/~tla/publ/FastOBBs.pdf)
|
||||
//=======================================================================
|
||||
void OBBTool::ProcessDiTetrahedron()
|
||||
{
|
||||
ProcessTriangle(myTriIdx[0], myTriIdx[1], myTriIdx[2], Standard_True);
|
||||
|
||||
if(myTriIdx[3] <= myNbExtremalPoints)
|
||||
{
|
||||
ProcessTriangle(myTriIdx[0], myTriIdx[1], myTriIdx[3], Standard_False);
|
||||
ProcessTriangle(myTriIdx[1], myTriIdx[2], myTriIdx[3], Standard_False);
|
||||
ProcessTriangle(myTriIdx[0], myTriIdx[2], myTriIdx[3], Standard_False);
|
||||
}
|
||||
|
||||
if(myTriIdx[4] <= myNbExtremalPoints)
|
||||
{
|
||||
ProcessTriangle(myTriIdx[0], myTriIdx[1], myTriIdx[4], Standard_False);
|
||||
ProcessTriangle(myTriIdx[1], myTriIdx[2], myTriIdx[4], Standard_False);
|
||||
ProcessTriangle(myTriIdx[0], myTriIdx[2], myTriIdx[4], Standard_False);
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Function : BuildBox
|
||||
// purpose :
|
||||
//=======================================================================
|
||||
void OBBTool::BuildBox(Bnd_OBB& theBox)
|
||||
{
|
||||
theBox.SetVoid();
|
||||
|
||||
// In fact, use Precision::SquareConfusion().
|
||||
const Standard_Boolean isOBB = myAxes[0].SquareModulus()*
|
||||
myAxes[1].SquareModulus()*
|
||||
myAxes[2].SquareModulus() > 1.0e-14;
|
||||
|
||||
const gp_Dir aXDir = isOBB ? myAxes[0] : gp_Dir(1, 0, 0);
|
||||
const gp_Dir aYDir = isOBB ? myAxes[1] : gp_Dir(0, 1, 0);
|
||||
const gp_Dir aZDir = isOBB ? myAxes[2] : gp_Dir(0, 0, 1);
|
||||
|
||||
const Standard_Integer aNbPoints = 6;
|
||||
Standard_Real aParams[aNbPoints];
|
||||
|
||||
gp_XYZ aFCurrPoint = myPntsList.First().XYZ();
|
||||
|
||||
aParams[0] = aParams[1] = aFCurrPoint.Dot(aXDir.XYZ());
|
||||
aParams[2] = aParams[3] = aFCurrPoint.Dot(aYDir.XYZ());
|
||||
aParams[4] = aParams[5] = aFCurrPoint.Dot(aZDir.XYZ());
|
||||
|
||||
if(myListOfTolers != 0)
|
||||
{
|
||||
const Standard_Real aTol = myListOfTolers->First();
|
||||
aParams[0] -= aTol;
|
||||
aParams[1] += aTol;
|
||||
aParams[2] -= aTol;
|
||||
aParams[3] += aTol;
|
||||
aParams[4] -= aTol;
|
||||
aParams[5] += aTol;
|
||||
}
|
||||
|
||||
for(Standard_Integer i = myPntsList.Lower() + 1; i <= myPntsList.Upper(); i++)
|
||||
{
|
||||
const gp_XYZ &aCurrPoint = myPntsList(i).XYZ();
|
||||
const Standard_Real aDx = aCurrPoint.Dot(aXDir.XYZ()),
|
||||
aDy = aCurrPoint.Dot(aYDir.XYZ()),
|
||||
aDz = aCurrPoint.Dot(aZDir.XYZ());
|
||||
|
||||
if(myListOfTolers == 0)
|
||||
{
|
||||
SetMinMax(&aParams[0], aDx);
|
||||
SetMinMax(&aParams[2], aDy);
|
||||
SetMinMax(&aParams[4], aDz);
|
||||
}
|
||||
else
|
||||
{
|
||||
const Standard_Real aTol = myListOfTolers->Value(i);
|
||||
aParams[0] = Min(aParams[0], aDx - aTol);
|
||||
aParams[1] = Max(aParams[1], aDx + aTol);
|
||||
aParams[2] = Min(aParams[2], aDy - aTol);
|
||||
aParams[3] = Max(aParams[3], aDy + aTol);
|
||||
aParams[4] = Min(aParams[4], aDz - aTol);
|
||||
aParams[5] = Max(aParams[5], aDz + aTol);
|
||||
}
|
||||
}
|
||||
|
||||
//Half-sizes
|
||||
const Standard_Real aHX = 0.5*(aParams[1] - aParams[0]);
|
||||
const Standard_Real aHY = 0.5*(aParams[3] - aParams[2]);
|
||||
const Standard_Real aHZ = 0.5*(aParams[5] - aParams[4]);
|
||||
|
||||
const gp_XYZ aCenter = 0.5*((aParams[1] + aParams[0])*aXDir.XYZ() +
|
||||
(aParams[3] + aParams[2])*aYDir.XYZ() +
|
||||
(aParams[5] + aParams[4])*aZDir.XYZ());
|
||||
|
||||
theBox.SetCenter(aCenter);
|
||||
theBox.SetXComponent(aXDir, aHX);
|
||||
theBox.SetYComponent(aYDir, aHY);
|
||||
theBox.SetZComponent(aZDir, aHZ);
|
||||
theBox.SetAABox(!isOBB);
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : ReBuild
|
||||
// purpose : http://www.idt.mdh.se/~tla/publ/
|
||||
// =======================================================================
|
||||
void Bnd_OBB::ReBuild(const TColgp_Array1OfPnt& theListOfPoints,
|
||||
const TColStd_Array1OfReal *theListOfTolerances)
|
||||
{
|
||||
switch(theListOfPoints.Length())
|
||||
{
|
||||
case 1:
|
||||
ProcessOnePoint(theListOfPoints.First());
|
||||
if(theListOfTolerances)
|
||||
Enlarge(theListOfTolerances->First());
|
||||
return;
|
||||
case 2:
|
||||
{
|
||||
const Standard_Real aTol1 = (theListOfTolerances == 0) ? 0.0 :
|
||||
theListOfTolerances->First();
|
||||
|
||||
const Standard_Real aTol2 = (theListOfTolerances == 0) ? 0.0 :
|
||||
theListOfTolerances->Last();
|
||||
|
||||
const gp_XYZ &aP1 = theListOfPoints.First().XYZ(),
|
||||
&aP2 = theListOfPoints.Last().XYZ();
|
||||
const gp_XYZ aDP = aP2 - aP1;
|
||||
const Standard_Real aDPm = aDP.Modulus();
|
||||
myIsAABox = Standard_False;
|
||||
myHDims[1] = myHDims[2] = Max(aTol1, aTol2);
|
||||
|
||||
if(aDPm < Precision::Confusion())
|
||||
{
|
||||
ProcessOnePoint(aP1);
|
||||
Enlarge(myHDims[1] + Precision::Confusion());
|
||||
return;
|
||||
}
|
||||
|
||||
myHDims[0] = 0.5*(aDPm+aTol1+aTol2);
|
||||
myAxes[0] = aDP/aDPm;
|
||||
if(Abs(myAxes[0].X()) > Abs(myAxes[0].Y()))
|
||||
{
|
||||
// Z-coord. is maximal or X-coord. is maximal
|
||||
myAxes[1].SetCoord(-myAxes[0].Z(), 0.0, myAxes[0].X());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Z-coord. is maximal or Y-coord. is maximal
|
||||
myAxes[1].SetCoord(0.0, -myAxes[0].Z(), myAxes[0].Y());
|
||||
}
|
||||
|
||||
myAxes[2] = myAxes[0].Crossed(myAxes[1]).Normalized();
|
||||
myCenter = aP1 + 0.5*(aDPm - aTol1 + aTol2)*myAxes[0];
|
||||
}
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
OBBTool aTool(theListOfPoints, theListOfTolerances);
|
||||
aTool.ProcessDiTetrahedron();
|
||||
aTool.BuildBox(*this);
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : IsOut
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Boolean Bnd_OBB::IsOut(const Bnd_OBB& theOther) const
|
||||
{
|
||||
if (IsVoid() || theOther.IsVoid())
|
||||
return Standard_True;
|
||||
|
||||
if (myIsAABox && theOther.myIsAABox)
|
||||
{
|
||||
return ((Abs(theOther.myCenter.X() - myCenter.X()) > theOther.myHDims[0] + myHDims[0]) ||
|
||||
(Abs(theOther.myCenter.Y() - myCenter.Y()) > theOther.myHDims[1] + myHDims[1]) ||
|
||||
(Abs(theOther.myCenter.Z() - myCenter.Z()) > theOther.myHDims[2] + myHDims[2]));
|
||||
}
|
||||
|
||||
// According to the Separating Axis Theorem for Oriented Bounding Boxes
|
||||
// it is necessary to check the 15 separating axes (Ls):
|
||||
// - 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. Compute the "length" for j-th BndBox (j=1...2) according to the formula:
|
||||
// L(j)=Sum(myHDims[i]*Abs(myAxes[i].Dot(Ls)))
|
||||
// 2. If (theCenter2 - theCenter1).Dot(Ls) > (L(1) + L(2))
|
||||
// then the considered OBBs are not interfered in terms of the axis Ls.
|
||||
//
|
||||
// If OBBs are not interfered in terms of at least one axis (of 15) then
|
||||
// they are not interfered at all.
|
||||
|
||||
// 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 second segment
|
||||
Standard_Real aLSegm2 = 0;
|
||||
for(Standard_Integer j = 0; j < 3; ++j)
|
||||
aLSegm2 += theOther.myHDims[j] * Abs(theOther.myAxes[j].Dot(myAxes[i]));
|
||||
|
||||
// Distance between projected centers
|
||||
Standard_Real aDistCC = Abs(D.Dot(myAxes[i]));
|
||||
|
||||
if(aDistCC > myHDims[i] + 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 += myHDims[j] * Abs(myAxes[j].Dot(theOther.myAxes[i]));
|
||||
|
||||
// Distance between projected centers
|
||||
Standard_Real aDistCC = Abs(D.Dot(theOther.myAxes[i]));
|
||||
|
||||
if(aDistCC > aLSegm1 + theOther.myHDims[i])
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
const Standard_Real aTolNull = Epsilon(1.0);
|
||||
|
||||
// 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 aLAxe = myAxes[i].Crossed(theOther.myAxes[j]);
|
||||
|
||||
const Standard_Real aNorm = aLAxe.Modulus();
|
||||
if(aNorm < aTolNull)
|
||||
continue;
|
||||
|
||||
aLAxe /= aNorm;
|
||||
|
||||
// Length of the first segment
|
||||
Standard_Real aLSegm1 = 0.;
|
||||
for(Standard_Integer k = 0; k < 3; ++k)
|
||||
aLSegm1 += myHDims[k] * Abs(myAxes[k].Dot(aLAxe));
|
||||
|
||||
// Length of the second segment
|
||||
Standard_Real aLSegm2 = 0.;
|
||||
for(Standard_Integer k = 0; k < 3; ++k)
|
||||
aLSegm2 += theOther.myHDims[k] * Abs(theOther.myAxes[k].Dot(aLAxe));
|
||||
|
||||
// Distance between projected centers
|
||||
Standard_Real aDistCC = Abs(D.Dot(aLAxe));
|
||||
|
||||
if(aDistCC > aLSegm1 + aLSegm2)
|
||||
return Standard_True;
|
||||
}
|
||||
}
|
||||
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : IsOut
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Boolean Bnd_OBB::IsOut(const gp_Pnt& theP) const
|
||||
{
|
||||
// 1. Project the point to myAxes[i] (i=0...2).
|
||||
// 2. Check, whether the absolute value of the correspond
|
||||
// projection parameter is greater than myHDims[i].
|
||||
// In this case, IsOut method will return TRUE.
|
||||
|
||||
const gp_XYZ aRV = theP.XYZ() - myCenter;
|
||||
|
||||
return ((Abs(myAxes[0].Dot(aRV)) > myHDims[0]) ||
|
||||
(Abs(myAxes[1].Dot(aRV)) > myHDims[1]) ||
|
||||
(Abs(myAxes[2].Dot(aRV)) > myHDims[2]));
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : IsCompletelyInside
|
||||
// purpose : Checks if every vertex of theOther is completely inside *this
|
||||
// =======================================================================
|
||||
Standard_Boolean Bnd_OBB::IsCompletelyInside(const Bnd_OBB& theOther) const
|
||||
{
|
||||
if(IsVoid() || theOther.IsVoid())
|
||||
return Standard_False;
|
||||
|
||||
gp_Pnt aVert[8];
|
||||
theOther.GetVertex(aVert);
|
||||
for(Standard_Integer i = 0; i < 8; i++)
|
||||
{
|
||||
if(IsOut(aVert[i]))
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Add
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void Bnd_OBB::Add(const gp_Pnt& theP)
|
||||
{
|
||||
gp_Pnt aList[9];
|
||||
GetVertex(aList);
|
||||
aList[8] = theP;
|
||||
|
||||
ReBuild(TColgp_Array1OfPnt(aList[0], 0, 8));
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Add
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void Bnd_OBB::Add(const Bnd_OBB& theOther)
|
||||
{
|
||||
gp_Pnt aList[16];
|
||||
GetVertex(&aList[0]);
|
||||
theOther.GetVertex(&aList[8]);
|
||||
ReBuild(TColgp_Array1OfPnt(aList[0], 0, 15));
|
||||
}
|
||||
|
290
src/Bnd/Bnd_OBB.hxx
Normal file
290
src/Bnd/Bnd_OBB.hxx
Normal file
@@ -0,0 +1,290 @@
|
||||
// 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 _Bnd_OBB_HeaderFile
|
||||
#define _Bnd_OBB_HeaderFile
|
||||
|
||||
#include <Standard.hxx>
|
||||
#include <Standard_DefineAlloc.hxx>
|
||||
#include <Standard_Handle.hxx>
|
||||
#include <Standard_Real.hxx>
|
||||
#include <Standard_Boolean.hxx>
|
||||
|
||||
#include <Bnd_Box.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_XYZ.hxx>
|
||||
#include <TColgp_Array1OfPnt.hxx>
|
||||
#include <TColStd_Array1OfReal.hxx>
|
||||
|
||||
//! The class describes the Oriented Bounding Box (OBB),
|
||||
//! much tighter enclosing volume for the shape than the
|
||||
//! Axis Aligned Bounding Box (AABB).
|
||||
//! The OBB is defined by a center of the box, the axes and the halves
|
||||
//! of its three dimensions.
|
||||
//! The OBB can be used more effectively than AABB as a rejection mechanism
|
||||
//! for non-interfering objects.
|
||||
class Bnd_OBB
|
||||
{
|
||||
public:
|
||||
|
||||
DEFINE_STANDARD_ALLOC
|
||||
|
||||
//! Empty constructor
|
||||
Bnd_OBB() :myIsAABox(Standard_False)
|
||||
{
|
||||
myHDims[0] = myHDims[1] = myHDims[2] = -1.0;
|
||||
}
|
||||
|
||||
//! Constructor taking all defining parameters
|
||||
Bnd_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();
|
||||
|
||||
Standard_ASSERT_VOID(theHXSize >= 0.0, "Negative value of X-size");
|
||||
Standard_ASSERT_VOID(theHYSize >= 0.0, "Negative value of Y-size");
|
||||
Standard_ASSERT_VOID(theHZSize >= 0.0, "Negative value of Z-size");
|
||||
|
||||
myHDims[0] = theHXSize;
|
||||
myHDims[1] = theHYSize;
|
||||
myHDims[2] = theHZSize;
|
||||
}
|
||||
|
||||
//! Constructor to create OBB from AABB.
|
||||
Bnd_OBB(const Bnd_Box& theBox) : myIsAABox(Standard_True)
|
||||
{
|
||||
Standard_Real aX1, aY1, aZ1, aX2, aY2, aZ2;
|
||||
theBox.Get(aX1, aY1, aZ1, aX2, aY2, aZ2);
|
||||
|
||||
myAxes[0].SetCoord(1.0, 0.0, 0.0);
|
||||
myAxes[1].SetCoord(0.0, 1.0, 0.0);
|
||||
myAxes[2].SetCoord(0.0, 0.0, 1.0);
|
||||
|
||||
myHDims[0] = 0.5*(aX2 - aX1);
|
||||
myHDims[1] = 0.5*(aY2 - aY1);
|
||||
myHDims[2] = 0.5*(aZ2 - aZ1);
|
||||
|
||||
myCenter.SetCoord(0.5*(aX2 + aX1), 0.5*(aY2 + aY1), 0.5*(aZ2 + aZ1));
|
||||
}
|
||||
|
||||
//! Created new OBB covering every point in theListOfPoints.
|
||||
//! Tolerance of every such point is set by *theListOfTolerances array.
|
||||
//! If this array is not void (not null-pointer) then the resulted Bnd_OBB
|
||||
//! will be enlarged using tolerances of points lying on the box surface.
|
||||
Standard_EXPORT void ReBuild(const TColgp_Array1OfPnt& theListOfPoints,
|
||||
const TColStd_Array1OfReal *theListOfTolerances = 0);
|
||||
|
||||
//! Sets the center of OBB
|
||||
void SetCenter(const gp_Pnt& theCenter)
|
||||
{
|
||||
myCenter = theCenter.XYZ();
|
||||
}
|
||||
|
||||
//! Sets the X component of OBB - direction and size
|
||||
void SetXComponent(const gp_Dir& theXDirection,
|
||||
const Standard_Real theHXSize)
|
||||
{
|
||||
Standard_ASSERT_VOID(theHXSize >= 0.0, "Negative value of X-size");
|
||||
|
||||
myAxes[0] = theXDirection.XYZ();
|
||||
myHDims[0] = theHXSize;
|
||||
}
|
||||
|
||||
//! Sets the Y component of OBB - direction and size
|
||||
void SetYComponent(const gp_Dir& theYDirection,
|
||||
const Standard_Real theHYSize)
|
||||
{
|
||||
Standard_ASSERT_VOID(theHYSize >= 0.0, "Negative value of Y-size");
|
||||
|
||||
myAxes[1] = theYDirection.XYZ();
|
||||
myHDims[1] = theHYSize;
|
||||
}
|
||||
|
||||
//! Sets the Z component of OBB - direction and size
|
||||
void SetZComponent(const gp_Dir& theZDirection,
|
||||
const Standard_Real theHZSize)
|
||||
{
|
||||
Standard_ASSERT_VOID(theHZSize >= 0.0, "Negative value of Z-size");
|
||||
|
||||
myAxes[2] = theZDirection.XYZ();
|
||||
myHDims[2] = theHZSize;
|
||||
}
|
||||
|
||||
//! Returns the center of OBB
|
||||
const gp_XYZ& Center() const
|
||||
{
|
||||
return myCenter;
|
||||
}
|
||||
|
||||
//! Returns the X Direction of OBB
|
||||
const gp_XYZ& XDirection() const
|
||||
{
|
||||
return myAxes[0];
|
||||
}
|
||||
|
||||
//! Returns the Y Direction of OBB
|
||||
const gp_XYZ& YDirection() const
|
||||
{
|
||||
return myAxes[1];
|
||||
}
|
||||
|
||||
//! Returns the Z Direction of OBB
|
||||
const gp_XYZ& ZDirection() const
|
||||
{
|
||||
return myAxes[2];
|
||||
}
|
||||
|
||||
//! Returns the X Dimension of OBB
|
||||
Standard_Real XHSize() const
|
||||
{
|
||||
return myHDims[0];
|
||||
}
|
||||
|
||||
//! Returns the Y Dimension of OBB
|
||||
Standard_Real YHSize() const
|
||||
{
|
||||
return myHDims[1];
|
||||
}
|
||||
|
||||
//! Returns the Z Dimension of OBB
|
||||
Standard_Real ZHSize() const
|
||||
{
|
||||
return myHDims[2];
|
||||
}
|
||||
|
||||
//! Checks if the box is empty.
|
||||
Standard_Boolean IsVoid() const
|
||||
{
|
||||
return ((myHDims[0] < 0.0) || (myHDims[1] < 0.0) || (myHDims[2] < 0.0));
|
||||
}
|
||||
|
||||
//! Clears this box
|
||||
void SetVoid()
|
||||
{
|
||||
myHDims[0] = myHDims[1] = myHDims[2] = -1.0;
|
||||
myCenter = myAxes[0] = myAxes[1] = myAxes[2] = gp_XYZ();
|
||||
myIsAABox = Standard_False;
|
||||
}
|
||||
|
||||
//! 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;
|
||||
}
|
||||
|
||||
//! Enlarges the box with the given value
|
||||
void Enlarge(const Standard_Real theGapAdd)
|
||||
{
|
||||
const Standard_Real aGap = Abs(theGapAdd);
|
||||
myHDims[0] += aGap;
|
||||
myHDims[1] += aGap;
|
||||
myHDims[2] += aGap;
|
||||
}
|
||||
|
||||
//! Returns the array of vertices in <this>.
|
||||
//! The local coordinate of the vertex depending on the
|
||||
//! index of the array are follow:
|
||||
//! Index == 0: (-XHSize(), -YHSize(), -ZHSize())
|
||||
//! Index == 1: ( XHSize(), -YHSize(), -ZHSize())
|
||||
//! Index == 2: (-XHSize(), YHSize(), -ZHSize())
|
||||
//! Index == 3: ( XHSize(), YHSize(), -ZHSize())
|
||||
//! Index == 4: (-XHSize(), -YHSize(), ZHSize())
|
||||
//! Index == 5: ( XHSize(), -YHSize(), ZHSize())
|
||||
//! Index == 6: (-XHSize(), YHSize(), ZHSize())
|
||||
//! Index == 7: ( XHSize(), YHSize(), ZHSize()).
|
||||
Standard_Boolean GetVertex(gp_Pnt theP[8]) const
|
||||
{
|
||||
if(IsVoid())
|
||||
return Standard_False;
|
||||
|
||||
theP[0].SetXYZ(myCenter - myHDims[0]*myAxes[0] - myHDims[1]*myAxes[1] - myHDims[2]*myAxes[2]);
|
||||
theP[1].SetXYZ(myCenter + myHDims[0]*myAxes[0] - myHDims[1]*myAxes[1] - myHDims[2]*myAxes[2]);
|
||||
theP[2].SetXYZ(myCenter - myHDims[0]*myAxes[0] + myHDims[1]*myAxes[1] - myHDims[2]*myAxes[2]);
|
||||
theP[3].SetXYZ(myCenter + myHDims[0]*myAxes[0] + myHDims[1]*myAxes[1] - myHDims[2]*myAxes[2]);
|
||||
theP[4].SetXYZ(myCenter - myHDims[0]*myAxes[0] - myHDims[1]*myAxes[1] + myHDims[2]*myAxes[2]);
|
||||
theP[5].SetXYZ(myCenter + myHDims[0]*myAxes[0] - myHDims[1]*myAxes[1] + myHDims[2]*myAxes[2]);
|
||||
theP[6].SetXYZ(myCenter - myHDims[0]*myAxes[0] + myHDims[1]*myAxes[1] + myHDims[2]*myAxes[2]);
|
||||
theP[7].SetXYZ(myCenter + myHDims[0]*myAxes[0] + myHDims[1]*myAxes[1] + myHDims[2]*myAxes[2]);
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//! Returns square diagonal of this box
|
||||
Standard_Real SquareExtent() const
|
||||
{
|
||||
return (4.0*myHDims[0] * myHDims[0] +
|
||||
myHDims[1] * myHDims[1] +
|
||||
myHDims[1] * myHDims[1]);
|
||||
}
|
||||
|
||||
//! Check if the box do not interfere the other box.
|
||||
Standard_EXPORT Standard_Boolean IsOut(const Bnd_OBB& theOther) const;
|
||||
|
||||
//! Check if the point is inside of <this>.
|
||||
Standard_EXPORT Standard_Boolean IsOut(const gp_Pnt& theP) const;
|
||||
|
||||
//! Check if the theOther is completely inside *this.
|
||||
Standard_EXPORT Standard_Boolean IsCompletelyInside(const Bnd_OBB& theOther) const;
|
||||
|
||||
//! Rebuilds this in order to include all previous objects
|
||||
//! (which it was created from) and theOther.
|
||||
Standard_EXPORT void Add(const Bnd_OBB& theOther);
|
||||
|
||||
//! Rebuilds this in order to include all previous objects
|
||||
//! (which it was created from) and theP.
|
||||
Standard_EXPORT void Add(const gp_Pnt& theP);
|
||||
|
||||
protected:
|
||||
void ProcessOnePoint(const gp_Pnt& theP)
|
||||
{
|
||||
myIsAABox = Standard_True;
|
||||
myHDims[0] = myHDims[1] = myHDims[2] = 0.0;
|
||||
myAxes[0].SetCoord(1.0, 0.0, 0.0);
|
||||
myAxes[1].SetCoord(0.0, 1.0, 0.0);
|
||||
myAxes[2].SetCoord(0.0, 0.0, 1.0);
|
||||
myCenter = theP.XYZ();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//! Center of the OBB
|
||||
gp_XYZ myCenter;
|
||||
|
||||
//! Directions of the box's axes
|
||||
//! (all vectors are already normalized)
|
||||
gp_XYZ myAxes[3];
|
||||
|
||||
//! Half-size dimensions of the OBB
|
||||
Standard_Real myHDims[3];
|
||||
|
||||
//! To be set if the OBB is axis aligned box;
|
||||
Standard_Boolean myIsAABox;
|
||||
};
|
||||
|
||||
#endif
|
@@ -24,6 +24,8 @@ Bnd_Box2d.hxx
|
||||
Bnd_HArray1OfBox.hxx
|
||||
Bnd_HArray1OfBox2d.hxx
|
||||
Bnd_HArray1OfSphere.hxx
|
||||
Bnd_OBB.cxx
|
||||
Bnd_OBB.hxx
|
||||
Bnd_Range.cxx
|
||||
Bnd_Range.hxx
|
||||
Bnd_SeqOfBox.hxx
|
||||
|
@@ -24,116 +24,111 @@
|
||||
IMPLEMENT_STANDARD_RTTIEXT(Draw_Box,Draw_Drawable3D)
|
||||
|
||||
//=======================================================================
|
||||
//function : Draw_Box
|
||||
//function : Constructor
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
Draw_Box::Draw_Box(const gp_Pnt& p1, const gp_Pnt& p2, const Draw_Color& col) :
|
||||
myFirst(p1), myLast(p2),myColor(col)
|
||||
Draw_Box::Draw_Box(const Bnd_OBB& theOBB,
|
||||
const Draw_Color& theColor) :myOBB(theOBB), myColor(theColor)
|
||||
{
|
||||
Standard_Real t;
|
||||
if (myLast.X() < myFirst.X()) {
|
||||
t = myFirst.X();
|
||||
myFirst.SetX(myLast.X());
|
||||
myLast.SetX(t);
|
||||
}
|
||||
if (myLast.Y() < myFirst.Y()) {
|
||||
t = myFirst.Y();
|
||||
myFirst.SetY(myLast.Y());
|
||||
myLast.SetY(t);
|
||||
}
|
||||
if (myLast.Z() < myFirst.Z()) {
|
||||
t = myFirst.Z();
|
||||
myFirst.SetZ(myLast.Z());
|
||||
myLast.SetZ(t);
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : ToWCS
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
void Draw_Box::ToWCS(const Standard_Real theX,
|
||||
const Standard_Real theY,
|
||||
const Standard_Real theZ,
|
||||
gp_Pnt& theP) const
|
||||
{
|
||||
const gp_XYZ & aC = myOBB.Center();
|
||||
const gp_XYZ aXDir = myOBB.XDirection(),
|
||||
aYDir = myOBB.YDirection(),
|
||||
aZDir = myOBB.ZDirection();
|
||||
|
||||
theP.SetXYZ(aC + theX*aXDir + theY*aYDir + theZ*aZDir);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : MoveX
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
void Draw_Box::MoveX(const Standard_Real theShift, gp_Pnt& thePt) const
|
||||
{
|
||||
const gp_XYZ aXDir = myOBB.XDirection();
|
||||
thePt.SetXYZ(thePt.XYZ() + theShift*aXDir);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : MoveY
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
void Draw_Box::MoveY(const Standard_Real theShift, gp_Pnt& thePt) const
|
||||
{
|
||||
const gp_XYZ aYDir = myOBB.YDirection();
|
||||
thePt.SetXYZ(thePt.XYZ() + theShift*aYDir);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : MoveZ
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
void Draw_Box::MoveZ(const Standard_Real theShift, gp_Pnt& thePt) const
|
||||
{
|
||||
const gp_XYZ aZDir = myOBB.ZDirection();
|
||||
thePt.SetXYZ(thePt.XYZ() + theShift*aZDir);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : DrawOn
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
|
||||
void Draw_Box::DrawOn(Draw_Display& dis) const
|
||||
void Draw_Box::DrawOn(Draw_Display& theDIS) const
|
||||
{
|
||||
dis.SetColor(myColor);
|
||||
gp_Pnt P = myFirst;
|
||||
if(myOBB.IsVoid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dis.MoveTo(P);
|
||||
P.SetX(myLast.X());
|
||||
dis.DrawTo(P);
|
||||
P.SetY(myLast.Y());
|
||||
dis.DrawTo(P);
|
||||
P.SetZ(myLast.Z());
|
||||
dis.DrawTo(P);
|
||||
P.SetX(myFirst.X());
|
||||
dis.DrawTo(P);
|
||||
P.SetY(myFirst.Y());
|
||||
dis.DrawTo(P);
|
||||
P.SetZ(myFirst.Z());
|
||||
dis.DrawTo(P);
|
||||
|
||||
P.SetX(myLast.X());
|
||||
dis.MoveTo(P);
|
||||
P.SetZ(myLast.Z());
|
||||
dis.DrawTo(P);
|
||||
P.SetX(myFirst.X());
|
||||
dis.DrawTo(P);
|
||||
theDIS.SetColor(myColor);
|
||||
|
||||
P.SetX(myLast.X());
|
||||
dis.MoveTo(P);
|
||||
P.SetY(myLast.Y());
|
||||
dis.DrawTo(P);
|
||||
const Standard_Real aHx = myOBB.XHSize(),
|
||||
aHy = myOBB.YHSize(),
|
||||
aHz = myOBB.ZHSize();
|
||||
|
||||
gp_Pnt aP;
|
||||
ToWCS(-aHx, -aHy, -aHz, aP);
|
||||
theDIS.MoveTo(aP);
|
||||
|
||||
for(Standard_Integer i = 0; i<2; i++)
|
||||
{
|
||||
MoveX(2.0*aHx, aP);
|
||||
theDIS.DrawTo(aP);
|
||||
MoveY(2.0*aHy, aP);
|
||||
theDIS.DrawTo(aP);
|
||||
MoveX(-2.0*aHx, aP);
|
||||
theDIS.DrawTo(aP);
|
||||
MoveY(-2.0*aHy, aP);
|
||||
theDIS.DrawTo(aP);
|
||||
|
||||
ToWCS(-aHx, -aHy, aHz, aP);
|
||||
theDIS.MoveTo(aP);
|
||||
}
|
||||
|
||||
P.SetX(myFirst.X());
|
||||
dis.MoveTo(P);
|
||||
P.SetZ(myFirst.Z());
|
||||
dis.DrawTo(P);
|
||||
P.SetY(myFirst.Y());
|
||||
dis.DrawTo(P);
|
||||
|
||||
P.SetY(myLast.Y());
|
||||
dis.MoveTo(P);
|
||||
P.SetX(myLast.X());
|
||||
dis.DrawTo(P);
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : First
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
|
||||
const gp_Pnt& Draw_Box::First() const
|
||||
{
|
||||
return myFirst;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : First
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
|
||||
void Draw_Box::First(const gp_Pnt& P)
|
||||
{
|
||||
myFirst = P;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : Last
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
|
||||
const gp_Pnt& Draw_Box::Last() const
|
||||
{
|
||||
return myLast;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : Last
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
|
||||
void Draw_Box::Last(const gp_Pnt& P)
|
||||
{
|
||||
myLast = P;
|
||||
for(Standard_Integer i = 0; i < 4; i++)
|
||||
{
|
||||
switch(i)
|
||||
{
|
||||
case 0: ToWCS(-aHx, -aHy, -aHz, aP); break;
|
||||
case 1: ToWCS(aHx, -aHy, -aHz, aP); break;
|
||||
case 2: ToWCS(aHx, aHy, -aHz, aP); break;
|
||||
case 3: ToWCS(-aHx, aHy, -aHz, aP); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
theDIS.MoveTo(aP);
|
||||
MoveZ(2.0*aHz, aP);
|
||||
theDIS.DrawTo(aP);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -20,10 +20,9 @@
|
||||
#include <Standard.hxx>
|
||||
#include <Standard_Type.hxx>
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <Bnd_OBB.hxx>
|
||||
#include <Draw_Color.hxx>
|
||||
#include <Draw_Drawable3D.hxx>
|
||||
class gp_Pnt;
|
||||
class Draw_Color;
|
||||
class Draw_Display;
|
||||
|
||||
@@ -34,46 +33,41 @@ DEFINE_STANDARD_HANDLE(Draw_Box, Draw_Drawable3D)
|
||||
//! a 3d box
|
||||
class Draw_Box : public Draw_Drawable3D
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
Standard_EXPORT Draw_Box(const Bnd_OBB& theOBB,
|
||||
const Draw_Color& theColor);
|
||||
|
||||
//! Draws myOBB
|
||||
Standard_EXPORT void DrawOn (Draw_Display& theDis) const Standard_OVERRIDE;
|
||||
|
||||
Standard_EXPORT Draw_Box(const gp_Pnt& p1, const gp_Pnt& p2, const Draw_Color& col);
|
||||
|
||||
Standard_EXPORT void DrawOn (Draw_Display& dis) const Standard_OVERRIDE;
|
||||
|
||||
Standard_EXPORT const gp_Pnt& First() const;
|
||||
|
||||
Standard_EXPORT void First (const gp_Pnt& P);
|
||||
|
||||
Standard_EXPORT const gp_Pnt& Last() const;
|
||||
|
||||
Standard_EXPORT void Last (const gp_Pnt& P);
|
||||
|
||||
|
||||
|
||||
|
||||
DEFINE_STANDARD_RTTIEXT(Draw_Box,Draw_Drawable3D)
|
||||
|
||||
protected:
|
||||
|
||||
//! Converts the point (theX, theY, theZ) in local coordinate system to WCS.
|
||||
void ToWCS(const Standard_Real theX,
|
||||
const Standard_Real theY,
|
||||
const Standard_Real theZ,
|
||||
gp_Pnt& theP) const;
|
||||
|
||||
//! Moves the point thePt along X-direction of myOBB on the distance theShift.
|
||||
void MoveX(const Standard_Real theShift, gp_Pnt& thePt) const;
|
||||
|
||||
//! Moves the point thePt along Y-direction of myOBB on the distance theShift.
|
||||
void MoveY(const Standard_Real theShift, gp_Pnt& thePt) const;
|
||||
|
||||
//! Moves the point thePt along Z-direction of myOBB on the distance theShift.
|
||||
void MoveZ(const Standard_Real theShift, gp_Pnt& thePt) const;
|
||||
|
||||
private:
|
||||
|
||||
//! Oriented bounding box
|
||||
Bnd_OBB myOBB;
|
||||
|
||||
gp_Pnt myFirst;
|
||||
gp_Pnt myLast;
|
||||
//! Color value
|
||||
Draw_Color myColor;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // _Draw_Box_HeaderFile
|
||||
|
Reference in New Issue
Block a user