mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-08-09 13:22:24 +03:00
0028426: Implementation of the EdgesToFaces function
1. The two new methods have been implemented: a. BOPAlgo_Tools::EdgesToWires - allows creating planar wires from edges. The input edges may be not shared, but the output wires will be sharing the coinciding vertices and edges. It is possible to skip the sharing if the input edges are already shared by passing the corresponding flag into the method. The input edges are expected to be planar, but the method does not check it. Thus, if the input edges are not planar, the output wires will also be not planar. In general, the output wires will be non-manifold and may contain free vertices. b. BOPAlgo_Tools::WiresToFaces - allows creating planar faces from the planar wires. In general, the input wires are non-manifold and may be not closed, but should share the coinciding parts. The wires located in the same plane and completely included into other wires will create holes in the faces built from bigger wires These two methods combined allow building faces from set of edges randomly located in 3D space. 2. The DRAW command *edgestofaces* has been implemented. 3. The documentation has been updated with the new section in Modeling Algorithms - Topological Tools. 4. Test cases for the issue.
This commit is contained in:
@@ -14,17 +14,85 @@
|
||||
|
||||
|
||||
#include <BOPAlgo_Tools.hxx>
|
||||
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Vec.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <gp_Circ.hxx>
|
||||
#include <gp_Elips.hxx>
|
||||
#include <gp_Hypr.hxx>
|
||||
#include <gp_Parab.hxx>
|
||||
|
||||
#include <Standard_ErrorHandler.hxx>
|
||||
#include <Standard_Failure.hxx>
|
||||
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
|
||||
#include <BOPCol_MapOfShape.hxx>
|
||||
#include <BOPCol_IndexedMapOfShape.hxx>
|
||||
#include <BOPCol_IndexedMapOfInteger.hxx>
|
||||
#include <BOPCol_IndexedDataMapOfShapeListOfShape.hxx>
|
||||
|
||||
#include <TopExp_Explorer.hxx>
|
||||
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
|
||||
#include <GeomAPI_ProjectPointOnCurve.hxx>
|
||||
#include <GeomAPI_ProjectPointOnSurf.hxx>
|
||||
|
||||
#include <BOPAlgo_Builder.hxx>
|
||||
#include <BOPAlgo_BuilderFace.hxx>
|
||||
|
||||
#include <BOPDS_CommonBlock.hxx>
|
||||
#include <BOPDS_DataMapOfPaveBlockListOfPaveBlock.hxx>
|
||||
#include <BOPDS_DS.hxx>
|
||||
#include <BOPDS_IndexedMapOfPaveBlock.hxx>
|
||||
#include <BOPDS_MapOfPaveBlock.hxx>
|
||||
#include <BOPDS_PaveBlock.hxx>
|
||||
|
||||
#include <BOPTools.hxx>
|
||||
#include <BOPTools_AlgoTools.hxx>
|
||||
#include <BOPTools_AlgoTools2D.hxx>
|
||||
|
||||
#include <IntTools_Context.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <GeomAPI_ProjectPointOnCurve.hxx>
|
||||
#include <GeomAPI_ProjectPointOnSurf.hxx>
|
||||
|
||||
typedef NCollection_IndexedDataMap
|
||||
<TopoDS_Shape, gp_Dir, TopTools_ShapeMapHasher> BOPAlgo_IndexedDataMapOfShapeDir;
|
||||
typedef NCollection_IndexedDataMap
|
||||
<TopoDS_Shape, gp_Pln, TopTools_ShapeMapHasher> BOPAlgo_IndexedDataMapOfShapePln;
|
||||
|
||||
static
|
||||
void MakeWires(const BOPCol_IndexedMapOfShape& theEdges,
|
||||
TopoDS_Compound& theWires,
|
||||
const Standard_Boolean theCheckUniquePlane,
|
||||
BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
|
||||
BOPCol_MapOfShape& theMEdgesNoUniquePlane);
|
||||
|
||||
static
|
||||
Standard_Boolean FindPlane(const BRepAdaptor_Curve& theCurve,
|
||||
gp_Pln& thePlane);
|
||||
|
||||
static
|
||||
Standard_Boolean FindPlane(const TopoDS_Shape& theWire,
|
||||
gp_Pln& thePlane,
|
||||
BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
|
||||
BOPCol_MapOfShape& theMEdgesNoUniquePlane);
|
||||
|
||||
static
|
||||
Standard_Boolean FindEdgeTangent(const TopoDS_Edge& theEdge,
|
||||
BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
|
||||
gp_Dir& theTgt);
|
||||
|
||||
static
|
||||
Standard_Boolean FindEdgeTangent(const BRepAdaptor_Curve& theCurve,
|
||||
gp_Vec& theTangent);
|
||||
|
||||
//=======================================================================
|
||||
//function : MakeBlocksCnx
|
||||
@@ -451,3 +519,624 @@ Standard_Real BOPAlgo_Tools::ComputeToleranceOfCB
|
||||
//
|
||||
return aTolMax;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : EdgesToWires
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
Standard_Integer BOPAlgo_Tools::EdgesToWires(const TopoDS_Shape& theEdges,
|
||||
TopoDS_Shape& theWires,
|
||||
const Standard_Boolean theShared,
|
||||
const Standard_Real theAngTol)
|
||||
{
|
||||
Standard_Integer iErr = 0;
|
||||
//
|
||||
// 1. Check the input edges
|
||||
//
|
||||
// List of edges to process
|
||||
BOPCol_ListOfShape aLE;
|
||||
//
|
||||
TopExp_Explorer aExp(theEdges, TopAbs_EDGE);
|
||||
for (; aExp.More(); aExp.Next()) {
|
||||
const TopoDS_Edge& aE = TopoDS::Edge(aExp.Current());
|
||||
if (!BRep_Tool::Degenerated(aE) && BRep_Tool::IsGeometric(aE)) {
|
||||
aLE.Append(aExp.Current());
|
||||
}
|
||||
}
|
||||
//
|
||||
if (aLE.IsEmpty()) {
|
||||
// no edges to process
|
||||
iErr = 1;
|
||||
return iErr;
|
||||
}
|
||||
//
|
||||
BRep_Builder aBB;
|
||||
TopoDS_Compound aRWires;
|
||||
aBB.MakeCompound(aRWires);
|
||||
//
|
||||
if (aLE.Extent() == 1) {
|
||||
TopoDS_Wire aWire;
|
||||
aBB.MakeWire(aWire);
|
||||
aBB.Add(aWire, aLE.First());
|
||||
aBB.Add(aRWires, aWire);
|
||||
theWires = aRWires;
|
||||
return iErr;
|
||||
}
|
||||
//
|
||||
// 2. Make compound of shared edges
|
||||
TopoDS_Shape aSEdges;
|
||||
//
|
||||
if (!theShared) {
|
||||
// intersect the edges if necessary
|
||||
BOPAlgo_Builder aGF;
|
||||
aGF.SetArguments(aLE);
|
||||
aGF.Perform();
|
||||
if (aGF.ErrorStatus()) {
|
||||
// unable to share the edges
|
||||
iErr = 2;
|
||||
return iErr;
|
||||
}
|
||||
//
|
||||
aSEdges = aGF.Shape();
|
||||
}
|
||||
else {
|
||||
aBB.MakeCompound(TopoDS::Compound(aSEdges));
|
||||
BOPCol_ListIteratorOfListOfShape aItLE(aLE);
|
||||
for (; aItLE.More(); aItLE.Next()) {
|
||||
aBB.Add(aSEdges, aItLE.Value());
|
||||
}
|
||||
}
|
||||
//
|
||||
// 3. Find edges located in the same planes and make wires from them.
|
||||
// If the plane cannot be found for a single edge, then it is necessary
|
||||
// to find all pairs of connected edges with the same cross product.
|
||||
|
||||
// Try to compute the plane in which the edge is located
|
||||
BOPAlgo_IndexedDataMapOfShapePln aDMEdgePln;
|
||||
// Compute the tangent direction for the edges for which the plane is not defined
|
||||
BOPAlgo_IndexedDataMapOfShapeDir aDMEdgeTgt;
|
||||
//
|
||||
// edges for which the plane is not found
|
||||
BOPCol_MapOfShape aMEdgesNoUniquePlane;
|
||||
//
|
||||
// edges for which the plane cannot be found on a single edge
|
||||
TopoDS_Compound aLEdges;
|
||||
aBB.MakeCompound(aLEdges);
|
||||
//
|
||||
aExp.Init(aSEdges, TopAbs_EDGE);
|
||||
for (; aExp.More(); aExp.Next()) {
|
||||
const TopoDS_Edge& aE = TopoDS::Edge(aExp.Current());
|
||||
BRepAdaptor_Curve aBAC(aE);
|
||||
//
|
||||
gp_Pln aPln;
|
||||
if (FindPlane(aBAC, aPln)) {
|
||||
aDMEdgePln.Add(aE, aPln);
|
||||
}
|
||||
else {
|
||||
gp_Vec aVT;
|
||||
if (FindEdgeTangent(aBAC, aVT)) {
|
||||
aDMEdgeTgt.Add(aE, gp_Dir(aVT));
|
||||
aBB.Add(aLEdges, aE);
|
||||
aMEdgesNoUniquePlane.Add(aE);
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
typedef NCollection_List<gp_Dir> BOPAlgo_ListOfDir;
|
||||
//
|
||||
// to avoid processing of the same edges in the same plane store
|
||||
// the processed planes into a list and use it as a fence map
|
||||
BOPAlgo_ListOfDir aLPFence;
|
||||
//
|
||||
// used edges
|
||||
BOPCol_MapOfShape aMEFence;
|
||||
//
|
||||
// look for a planes on the single edges
|
||||
Standard_Integer i, j, aNbPlanes = aDMEdgePln.Extent(), aNbEdges = aDMEdgeTgt.Extent();
|
||||
for (i = 1; i <= aNbPlanes; ++i) {
|
||||
const TopoDS_Shape& aEI = aDMEdgePln.FindKey(i);
|
||||
if (!aMEFence.Add(aEI)) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
const gp_Pln& aPlnI = aDMEdgePln(i);
|
||||
const gp_Dir& aDI = aPlnI.Position().Direction();
|
||||
//
|
||||
aLPFence.Append(aDI);
|
||||
//
|
||||
BOPCol_IndexedMapOfShape aMEPln;
|
||||
aMEPln.Add(aEI);
|
||||
//
|
||||
BOPCol_IndexedMapOfShape aMV;
|
||||
BOPTools::MapShapes(aEI, TopAbs_VERTEX, aMV);
|
||||
//
|
||||
// look for other edges with the plane parallel to current one
|
||||
for (j = i + 1; j <= aNbPlanes; ++j) {
|
||||
const gp_Dir& aDJ = aDMEdgePln(j).Position().Direction();
|
||||
if (aDI.IsParallel(aDJ, theAngTol)) {
|
||||
const TopoDS_Shape& aEJ = aDMEdgePln.FindKey(j);
|
||||
aMEPln.Add(aEJ);
|
||||
aMEFence.Add(aEJ);
|
||||
BOPTools::MapShapes(aEJ, TopAbs_VERTEX, aMV);
|
||||
}
|
||||
}
|
||||
//
|
||||
// look for all other edges located in the plane parallel to current one
|
||||
TopoDS_Compound aCEPln;
|
||||
aBB.MakeCompound(aCEPln);
|
||||
//
|
||||
for (j = 1; j <= aNbEdges; ++j) {
|
||||
const gp_Dir& aDJ = aDMEdgeTgt(j);
|
||||
if (aDI.IsNormal(aDJ, theAngTol)) {
|
||||
aBB.Add(aCEPln, aDMEdgeTgt.FindKey(j));
|
||||
}
|
||||
}
|
||||
//
|
||||
// make blocks of these edges and check blocks to be connected
|
||||
// to any of the already added edges or forming a wire themselves
|
||||
BOPCol_ListOfShape aLCBE;
|
||||
BOPTools_AlgoTools::MakeConnexityBlocks(aCEPln, TopAbs_VERTEX, TopAbs_EDGE, aLCBE);
|
||||
//
|
||||
// make wire from each block
|
||||
BOPCol_ListIteratorOfListOfShape aItLCB(aLCBE);
|
||||
for (; aItLCB.More(); aItLCB.Next()) {
|
||||
const TopoDS_Shape& aCBE = aItLCB.Value();
|
||||
//
|
||||
// check connectivity
|
||||
TopExp_Explorer aExpV(aCBE, TopAbs_VERTEX);
|
||||
for (; aExpV.More(); aExpV.Next()) {
|
||||
if (aMV.Contains(aExpV.Current())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
//
|
||||
Standard_Boolean bAddBlock = aExpV.More();
|
||||
if (!bAddBlock) {
|
||||
// check if the edges are forming a wire
|
||||
gp_Pln aPln;
|
||||
bAddBlock = FindPlane(aCBE, aPln, aDMEdgeTgt, aMEdgesNoUniquePlane);
|
||||
}
|
||||
//
|
||||
if (bAddBlock) {
|
||||
// add edges
|
||||
for (TopoDS_Iterator aItE(aCBE); aItE.More(); aItE.Next()) {
|
||||
aMEPln.Add(aItE.Value());
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
MakeWires(aMEPln, aRWires, Standard_False, aDMEdgeTgt, aMEdgesNoUniquePlane);
|
||||
}
|
||||
//
|
||||
// make connection map from vertices to edges to find the connected pairs
|
||||
BOPCol_IndexedDataMapOfShapeListOfShape aDMVE;
|
||||
BOPTools::MapShapesAndAncestors(aLEdges, TopAbs_VERTEX, TopAbs_EDGE, aDMVE);
|
||||
//
|
||||
// find planes for connected edges
|
||||
Standard_Integer aNbV = aDMVE.Extent();
|
||||
for (i = 1; i <= aNbV; ++i) {
|
||||
const BOPCol_ListOfShape& aLEI = aDMVE(i);
|
||||
if (aLEI.Extent() < 2) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
BOPCol_ListIteratorOfListOfShape aItLEI1(aLEI);
|
||||
for (; aItLEI1.More(); aItLEI1.Next()) {
|
||||
const TopoDS_Shape& aEI1 = aItLEI1.Value();
|
||||
const gp_Dir& aDI1 = aDMEdgeTgt.FindFromKey(aEI1);
|
||||
//
|
||||
BOPCol_ListIteratorOfListOfShape aItLEI2(aLEI);
|
||||
for (; aItLEI2.More(); aItLEI2.Next()) {
|
||||
const TopoDS_Shape& aEI2 = aItLEI2.Value();
|
||||
if (aEI2.IsSame(aEI1)) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
const gp_Dir& aDI2 = aDMEdgeTgt.FindFromKey(aEI2);
|
||||
//
|
||||
if (aDI1.IsParallel(aDI2, theAngTol)) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
gp_Dir aDNI = aDI1^aDI2;
|
||||
//
|
||||
// check if this normal direction has not been checked yet
|
||||
BOPAlgo_ListOfDir::Iterator aItLPln(aLPFence);
|
||||
for (; aItLPln.More(); aItLPln.Next()) {
|
||||
if (aDNI.IsParallel(aItLPln.Value(), theAngTol)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (aItLPln.More()) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
aLPFence.Append(aDNI);
|
||||
//
|
||||
// find all other edges in the plane parallel to current one
|
||||
BOPCol_IndexedMapOfShape aMEPln;
|
||||
aMEPln.Add(aEI1);
|
||||
aMEPln.Add(aEI2);
|
||||
//
|
||||
// iterate on all other edges to find all edges lying in the plane parallel to current one
|
||||
for (j = 1; j <= aNbEdges; ++j) {
|
||||
const gp_Dir& aDJ = aDMEdgeTgt(j);
|
||||
if (aDNI.IsNormal(aDJ, theAngTol)) {
|
||||
aMEPln.Add(aDMEdgeTgt.FindKey(j));
|
||||
}
|
||||
}
|
||||
//
|
||||
MakeWires(aMEPln, aRWires, Standard_True, aDMEdgeTgt, aMEdgesNoUniquePlane);
|
||||
} // for (; aItLEI2.More(); aItLEI2.Next()) {
|
||||
} // for (; aItLEI1.More(); aItLEI1.Next()) {
|
||||
} // for (i = 1; i < aNb; ++i) {
|
||||
//
|
||||
// 4. Find unused edges and make wires from them
|
||||
BOPCol_IndexedMapOfShape aMEAlone, aMEUsed;
|
||||
BOPTools::MapShapes(aRWires, TopAbs_EDGE, aMEUsed);
|
||||
//
|
||||
for (i = 1; i <= aNbEdges; ++i) {
|
||||
const TopoDS_Shape& aE = aDMEdgeTgt.FindKey(i);
|
||||
if (!aMEUsed.Contains(aE)) {
|
||||
aMEAlone.Add(aE);
|
||||
}
|
||||
}
|
||||
//
|
||||
MakeWires(aMEAlone, aRWires, Standard_False, aDMEdgeTgt, aMEdgesNoUniquePlane);
|
||||
//
|
||||
theWires = aRWires;
|
||||
//
|
||||
return iErr;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : WiresToFaces
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
Standard_Boolean BOPAlgo_Tools::WiresToFaces(const TopoDS_Shape& theWires,
|
||||
TopoDS_Shape& theFaces,
|
||||
const Standard_Real theAngTol)
|
||||
{
|
||||
BRep_Builder aBB;
|
||||
BOPCol_MapOfShape aMFence;
|
||||
TopoDS_Compound aRFaces;
|
||||
aBB.MakeCompound(aRFaces);
|
||||
//
|
||||
const Standard_Real aMax = 1.e+8;
|
||||
//
|
||||
// map to store the tangent vectors for the edges
|
||||
BOPAlgo_IndexedDataMapOfShapeDir aDMEdgeTgt;
|
||||
// maps to store the planes found for the wires
|
||||
BOPAlgo_IndexedDataMapOfShapePln aDMWirePln;
|
||||
// map to store the tolerance for the wire
|
||||
NCollection_DataMap<TopoDS_Shape, Standard_Real, TopTools_ShapeMapHasher> aDMWireTol;
|
||||
// edges for which the plane is not found
|
||||
BOPCol_MapOfShape aMEdgesNoUniquePlane;
|
||||
//
|
||||
// Find planes for the wires
|
||||
TopExp_Explorer aExpW(theWires, TopAbs_WIRE);
|
||||
for (; aExpW.More(); aExpW.Next()) {
|
||||
const TopoDS_Wire& aWire = TopoDS::Wire(aExpW.Current());
|
||||
gp_Pln aPlane;
|
||||
if (FindPlane(aWire, aPlane, aDMEdgeTgt, aMEdgesNoUniquePlane)) {
|
||||
aDMWirePln.Add(aWire, aPlane);
|
||||
// find tolerance for the wire - max tolerance of its edges
|
||||
aDMWireTol.Bind(aWire, BRep_Tool::MaxTolerance(aWire, TopAbs_EDGE));
|
||||
}
|
||||
}
|
||||
//
|
||||
Standard_Integer i, j, aNb = aDMWirePln.Extent();
|
||||
for (i = 1; i <= aNb; ++i) {
|
||||
const TopoDS_Shape& aWireI = aDMWirePln.FindKey(i);
|
||||
if (aMFence.Contains(aWireI)) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
const gp_Pln& aPlnI = aDMWirePln(i);
|
||||
//
|
||||
BOPCol_ListOfShape aLW;
|
||||
aLW.Append(aWireI);
|
||||
aMFence.Add(aWireI);
|
||||
//
|
||||
Standard_Real aTolI = aDMWireTol.Find(aWireI);
|
||||
//
|
||||
// Find other wires in the same plane
|
||||
for (j = i + 1; j <= aNb; ++j) {
|
||||
const TopoDS_Shape& aWireJ = aDMWirePln.FindKey(j);
|
||||
if (aMFence.Contains(aWireJ)) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
// check if the planes are the same
|
||||
const gp_Pln& aPlnJ = aDMWirePln(j);
|
||||
// check direction of the planes
|
||||
if (!aPlnI.Position().Direction().IsParallel(aPlnJ.Position().Direction(), theAngTol)) {
|
||||
continue;
|
||||
}
|
||||
// check distance between the planes
|
||||
Standard_Real aDist = aPlnI.Distance(aPlnJ.Location());
|
||||
Standard_Real aTolJ = aDMWireTol.Find(aWireJ);
|
||||
if (aDist > (aTolI + aTolJ)) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
aLW.Append(aWireJ);
|
||||
aMFence.Add(aWireJ);
|
||||
}
|
||||
//
|
||||
// Take the edges to build the face
|
||||
BOPCol_ListOfShape aLE;
|
||||
BOPCol_ListIteratorOfListOfShape aItLW(aLW);
|
||||
for (; aItLW.More(); aItLW.Next()) {
|
||||
TopoDS_Iterator aItE(aItLW.Value());
|
||||
for (; aItE.More(); aItE.Next()) {
|
||||
aLE.Append(aItE.Value().Oriented(TopAbs_FORWARD));
|
||||
aLE.Append(aItE.Value().Oriented(TopAbs_REVERSED));
|
||||
}
|
||||
}
|
||||
//
|
||||
// build planar face
|
||||
TopoDS_Face aFF = BRepBuilderAPI_MakeFace
|
||||
(aPlnI, -aMax, aMax, -aMax, aMax).Face();
|
||||
aFF.Orientation(TopAbs_FORWARD);
|
||||
//
|
||||
try {
|
||||
OCC_CATCH_SIGNALS
|
||||
//
|
||||
// build pcurves for edges on this face
|
||||
BOPTools_AlgoTools2D::BuildPCurveForEdgesOnPlane(aLE, aFF);
|
||||
//
|
||||
// split the face with the edges
|
||||
BOPAlgo_BuilderFace aBF;
|
||||
aBF.SetShapes(aLE);
|
||||
aBF.SetFace(aFF);
|
||||
aBF.Perform();
|
||||
if (aBF.ErrorStatus()) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
const BOPCol_ListOfShape& aLFSp = aBF.Areas();
|
||||
BOPCol_ListIteratorOfListOfShape aItLF(aLFSp);
|
||||
for (; aItLF.More(); aItLF.Next()) {
|
||||
const TopoDS_Shape& aFSp = aItLF.ChangeValue();
|
||||
aBB.Add(aRFaces, aFSp);
|
||||
}
|
||||
}
|
||||
catch (Standard_Failure) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
//
|
||||
// fix tolerances of the resulting faces
|
||||
BOPCol_IndexedMapOfShape aMEmpty;
|
||||
BOPTools_AlgoTools::CorrectTolerances(aRFaces, aMEmpty, 0.05, Standard_False);
|
||||
BOPTools_AlgoTools::CorrectShapeTolerances(aRFaces, aMEmpty, Standard_False);
|
||||
//
|
||||
theFaces = aRFaces;
|
||||
TopoDS_Iterator aItF(theFaces);
|
||||
return aItF.More();
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : MakeWires
|
||||
//purpose : Makes wires from the separate blocks of the given edges
|
||||
//=======================================================================
|
||||
void MakeWires(const BOPCol_IndexedMapOfShape& theEdges,
|
||||
TopoDS_Compound& theWires,
|
||||
const Standard_Boolean theCheckUniquePlane,
|
||||
BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
|
||||
BOPCol_MapOfShape& theMEdgesNoUniquePlane)
|
||||
{
|
||||
TopoDS_Compound aCE;
|
||||
BRep_Builder().MakeCompound(aCE);
|
||||
Standard_Integer i, aNbE = theEdges.Extent();
|
||||
for (i = 1; i <= aNbE; ++i) {
|
||||
BRep_Builder().Add(aCE, theEdges(i));
|
||||
}
|
||||
//
|
||||
BOPCol_ListOfShape aLCBE;
|
||||
BOPTools_AlgoTools::MakeConnexityBlocks(aCE, TopAbs_VERTEX, TopAbs_EDGE, aLCBE);
|
||||
//
|
||||
// make wire from each block
|
||||
BOPCol_ListIteratorOfListOfShape aItLCB(aLCBE);
|
||||
for (; aItLCB.More(); aItLCB.Next()) {
|
||||
const TopoDS_Shape& aCBE = aItLCB.Value();
|
||||
//
|
||||
if (theCheckUniquePlane) {
|
||||
gp_Pln aPln;
|
||||
if (!FindPlane(aCBE, aPln, theDMEdgeTgt, theMEdgesNoUniquePlane)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
//
|
||||
TopoDS_Wire aWire;
|
||||
BRep_Builder().MakeWire(aWire);
|
||||
for (TopoDS_Iterator aItE(aCBE); aItE.More(); aItE.Next()) {
|
||||
BRep_Builder().Add(aWire, aItE.Value());
|
||||
}
|
||||
//
|
||||
BRep_Builder().Add(theWires, aWire);
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : FindEdgeTangent
|
||||
//purpose : Finds the tangent for the edge using the map
|
||||
//=======================================================================
|
||||
Standard_Boolean FindEdgeTangent(const TopoDS_Edge& theEdge,
|
||||
BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
|
||||
gp_Dir& theTgt)
|
||||
{
|
||||
gp_Dir *pDTE = theDMEdgeTgt.ChangeSeek(theEdge);
|
||||
if (!pDTE) {
|
||||
gp_Vec aVTE;
|
||||
BRepAdaptor_Curve aBAC(theEdge);
|
||||
if (!FindEdgeTangent(aBAC, aVTE)) {
|
||||
return Standard_False;
|
||||
}
|
||||
pDTE = &theDMEdgeTgt(theDMEdgeTgt.Add(theEdge, gp_Dir(aVTE)));
|
||||
}
|
||||
theTgt = *pDTE;
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : FindEdgeTangent
|
||||
//purpose : Finds the tangent for the edge
|
||||
//=======================================================================
|
||||
Standard_Boolean FindEdgeTangent(const BRepAdaptor_Curve& theCurve,
|
||||
gp_Vec& theTangent)
|
||||
{
|
||||
if (!theCurve.Is3DCurve()) {
|
||||
return Standard_False;
|
||||
}
|
||||
// for the line the tangent is defined by the direction
|
||||
if (theCurve.GetType() == GeomAbs_Line) {
|
||||
theTangent = theCurve.Line().Position().Direction();
|
||||
return Standard_True;
|
||||
}
|
||||
//
|
||||
// for other curves take D1 and check for its length
|
||||
Standard_Real aT, aT1(theCurve.FirstParameter()), aT2(theCurve.LastParameter());
|
||||
const Standard_Integer aNbP = 11;
|
||||
const Standard_Real aDt = (aT2 - aT1) / aNbP;
|
||||
//
|
||||
for (aT = aT1 + aDt; aT <= aT2; aT += aDt) {
|
||||
gp_Pnt aP;
|
||||
theCurve.D1(aT, aP, theTangent);
|
||||
if (theTangent.Magnitude() > Precision::Confusion()) {
|
||||
return Standard_True;
|
||||
}
|
||||
}
|
||||
//
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : FindPlane
|
||||
//purpose : Finds the plane in which the edge is located
|
||||
//=======================================================================
|
||||
Standard_Boolean FindPlane(const BRepAdaptor_Curve& theCurve,
|
||||
gp_Pln& thePlane)
|
||||
{
|
||||
if (!theCurve.Is3DCurve()) {
|
||||
return Standard_False;
|
||||
}
|
||||
//
|
||||
Standard_Boolean bFound = Standard_True;
|
||||
gp_Vec aVN;
|
||||
switch (theCurve.GetType()) {
|
||||
case GeomAbs_Line:
|
||||
return Standard_False;
|
||||
case GeomAbs_Circle:
|
||||
aVN = theCurve.Circle().Position().Direction();
|
||||
break;
|
||||
case GeomAbs_Ellipse:
|
||||
aVN = theCurve.Ellipse().Position().Direction();
|
||||
break;
|
||||
case GeomAbs_Hyperbola:
|
||||
aVN = theCurve.Hyperbola().Position().Direction();
|
||||
break;
|
||||
case GeomAbs_Parabola:
|
||||
aVN = theCurve.Parabola().Position().Direction();
|
||||
break;
|
||||
default: {
|
||||
// for all other types of curve compute two tangent vectors
|
||||
// on the curve and cross them
|
||||
bFound = Standard_False;
|
||||
Standard_Real aT, aT1(theCurve.FirstParameter()), aT2(theCurve.LastParameter());
|
||||
const Standard_Integer aNbP = 11;
|
||||
const Standard_Real aDt = (aT2 - aT1) / aNbP;
|
||||
//
|
||||
aT = aT1;
|
||||
gp_Pnt aP1;
|
||||
gp_Vec aV1;
|
||||
theCurve.D1(aT, aP1, aV1);
|
||||
//
|
||||
for (aT = aT1 + aDt; aT <= aT2; aT += aDt) {
|
||||
gp_Pnt aP2;
|
||||
gp_Vec aV2;
|
||||
theCurve.D1(aT, aP2, aV2);
|
||||
//
|
||||
aVN = aV1^aV2;
|
||||
if (aVN.Magnitude() > Precision::Confusion()) {
|
||||
bFound = Standard_True;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
//
|
||||
if (bFound) {
|
||||
thePlane = gp_Pln(theCurve.Value(theCurve.FirstParameter()), gp_Dir(aVN));
|
||||
}
|
||||
return bFound;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : FindPlane
|
||||
//purpose : Finds the plane in which the wire is located
|
||||
//=======================================================================
|
||||
Standard_Boolean FindPlane(const TopoDS_Shape& theWire,
|
||||
gp_Pln& thePlane,
|
||||
BOPAlgo_IndexedDataMapOfShapeDir& theDMEdgeTgt,
|
||||
BOPCol_MapOfShape& theMEdgesNoUniquePlane)
|
||||
{
|
||||
TopExp_Explorer aExpE1(theWire, TopAbs_EDGE);
|
||||
if (!aExpE1.More()) {
|
||||
return Standard_False;
|
||||
}
|
||||
//
|
||||
// try to find two not parallel edges in wire to get normal of the plane
|
||||
for (; aExpE1.More(); aExpE1.Next()) {
|
||||
// get the first edge in the wire
|
||||
const TopoDS_Edge& aE1 = TopoDS::Edge(aExpE1.Current());
|
||||
//
|
||||
// find tangent for the first edge
|
||||
gp_Dir aDTE1;
|
||||
if (!FindEdgeTangent(aE1, theDMEdgeTgt, aDTE1)) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
// find the other edge not parallel to the first one
|
||||
TopExp_Explorer aExpE2(theWire, TopAbs_EDGE);
|
||||
for (; aExpE2.More(); aExpE2.Next()) {
|
||||
const TopoDS_Edge& aE2 = TopoDS::Edge(aExpE2.Current());
|
||||
if (aE1.IsSame(aE2)) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
// find tangent for the second edge
|
||||
gp_Dir aDTE2;
|
||||
if (!FindEdgeTangent(aE2, theDMEdgeTgt, aDTE2)) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
if (aDTE1.IsParallel(aDTE2, Precision::Angular())) {
|
||||
continue;
|
||||
}
|
||||
//
|
||||
gp_Dir aDN = aDTE1^aDTE2;
|
||||
//
|
||||
TopoDS_Iterator aItV(aE1);
|
||||
thePlane = gp_Pln(BRep_Tool::Pnt(TopoDS::Vertex(aItV.Value())), aDN);
|
||||
return Standard_True;
|
||||
}
|
||||
}
|
||||
//
|
||||
// try to compute normal on the single edge
|
||||
aExpE1.Init(theWire, TopAbs_EDGE);
|
||||
for (; aExpE1.More(); aExpE1.Next()) {
|
||||
const TopoDS_Edge& aE = TopoDS::Edge(aExpE1.Current());
|
||||
if (theMEdgesNoUniquePlane.Contains(aE)) {
|
||||
continue;
|
||||
}
|
||||
BRepAdaptor_Curve aBAC(aE);
|
||||
if (FindPlane(aBAC, thePlane)) {
|
||||
return Standard_True;
|
||||
}
|
||||
theMEdgesNoUniquePlane.Add(aE);
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
|
@@ -31,6 +31,7 @@
|
||||
class BOPDS_PaveBlock;
|
||||
class BOPDS_CommonBlock;
|
||||
class IntTools_Context;
|
||||
class TopoDS_Shape;
|
||||
|
||||
class BOPAlgo_Tools
|
||||
{
|
||||
@@ -58,6 +59,47 @@ public:
|
||||
const BOPDS_PDS theDS,
|
||||
const Handle(IntTools_Context)& theContext);
|
||||
|
||||
//! Creates planar wires from the given edges.<br>
|
||||
//! The input edges are expected to be planar. And for the performance
|
||||
//! sake the method does not check if the edges are really planar.<br>
|
||||
//! Thus, the result wires will also be not planar if the input edges are not planar.<br>
|
||||
//! The edges may be not shared, but the resulting wires will be sharing the
|
||||
//! coinciding parts and intersecting parts.<br>
|
||||
//! The output wires may be non-manifold and contain free and multi-connected vertices.<br>
|
||||
//! Parameters:
|
||||
//! <theEdges> - input edges;<br>
|
||||
//! <theWires> - output wires;<br>
|
||||
//! <theShared> - boolean flag which defines whether the input edges are already
|
||||
//! shared or have to be intersected;<br>
|
||||
//! <theAngTol> - the angular tolerance which will be used for distinguishing
|
||||
//! the planes in which the edges are located. Default value is
|
||||
//! 1.e-8 which is used for intersection of planes in IntTools_FaceFace.<br>
|
||||
//! Method returns the following error statuses:<br>
|
||||
//! 0 - in case of success (at least one wire has been built);<br>
|
||||
//! 1 - in case there are no edges in the given shape;<br>
|
||||
//! 2 - sharing of the edges has failed.<br>
|
||||
Standard_EXPORT static Standard_Integer EdgesToWires(const TopoDS_Shape& theEdges,
|
||||
TopoDS_Shape& theWires,
|
||||
const Standard_Boolean theShared = Standard_False,
|
||||
const Standard_Real theAngTol = 1.e-8);
|
||||
|
||||
//! Creates planar faces from given planar wires.<br>
|
||||
//! The method does not check if the wires are really planar.<br>
|
||||
//! The input wires may be non-manifold but should be shared.<br>
|
||||
//! The wires located in the same planes and included into other wires will create
|
||||
//! holes in the faces built from outer wires.<br>
|
||||
//! The tolerance values of the input shapes may be modified during the operation
|
||||
//! due to projection of the edges on the planes for creation of 2D curves.<br>
|
||||
//! Parameters:
|
||||
//! <theWires> - the given wires;<br>
|
||||
//! <theFaces> - the output faces;<br>
|
||||
//! <theAngTol> - the angular tolerance for distinguishing the planes in which
|
||||
//! the wires are located. Default value is 1.e-8 which is used
|
||||
//! for intersection of planes in IntTools_FaceFace.<br>
|
||||
//! Method returns TRUE in case of success, i.e. at least one face has been built.<br>
|
||||
Standard_EXPORT static Standard_Boolean WiresToFaces(const TopoDS_Shape& theWires,
|
||||
TopoDS_Shape& theFaces,
|
||||
const Standard_Real theAngTol = 1.e-8);
|
||||
};
|
||||
|
||||
#endif // _BOPAlgo_Tools_HeaderFile
|
||||
|
Reference in New Issue
Block a user