[TD]New face finder algo
This commit is contained in:
@@ -33,6 +33,7 @@
|
||||
#include <gp_Vec.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <BRepBuilderAPI_Transform.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#endif
|
||||
|
||||
#include <Mod/TechDraw/TechDrawGlobal.h>
|
||||
@@ -264,26 +265,28 @@ private:
|
||||
|
||||
Py::List result;
|
||||
|
||||
std::vector<TopoDS_Edge> closedEdges;
|
||||
edgeList = DrawProjectSplit::scrubEdges(edgeList, closedEdges);
|
||||
|
||||
std::vector<TopoDS_Wire> sortedWires;
|
||||
try {
|
||||
EdgeWalker eWalker;
|
||||
eWalker.loadEdges(edgeList);
|
||||
bool success = eWalker.perform();
|
||||
if (success) {
|
||||
std::vector<TopoDS_Wire> rWires = eWalker.getResultNoDups();
|
||||
std::vector<TopoDS_Wire> sortedWires = eWalker.sortStrip(rWires, biggie); //false==>do not include biggest wires
|
||||
for (auto& w:sortedWires) {
|
||||
PyObject* wire = new TopoShapeWirePy(new TopoShape(w));
|
||||
result.append(Py::asObject(wire));
|
||||
}
|
||||
}
|
||||
else {
|
||||
Base::Console().Warning("edgeWalker: input is not planar graph. Wire detection not done\n");
|
||||
}
|
||||
sortedWires = eWalker.execute(edgeList, biggie);
|
||||
}
|
||||
catch (Base::Exception &e) {
|
||||
e.setPyException();
|
||||
throw Py::Exception();
|
||||
}
|
||||
|
||||
if(sortedWires.empty()) {
|
||||
Base::Console().Warning("ATDP::edgeWalker: Wire detection failed\n");
|
||||
return Py::None();
|
||||
} else {
|
||||
for (auto& w:sortedWires) {
|
||||
PyObject* wire = new TopoShapeWirePy(new TopoShape(w));
|
||||
result.append(Py::asObject(wire));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -313,30 +316,29 @@ private:
|
||||
}
|
||||
|
||||
if (edgeList.empty()) {
|
||||
Base::Console().Log("LOG - findOuterWire: input is empty\n");
|
||||
Base::Console().Message("ATDP::findOuterWire: input is empty\n");
|
||||
return Py::None();
|
||||
}
|
||||
|
||||
std::vector<TopoDS_Edge> closedEdges;
|
||||
edgeList = DrawProjectSplit::scrubEdges(edgeList, closedEdges);
|
||||
|
||||
PyObject* outerWire = nullptr;
|
||||
bool success = false;
|
||||
std::vector<TopoDS_Wire> sortedWires;
|
||||
try {
|
||||
EdgeWalker eWalker;
|
||||
eWalker.loadEdges(edgeList);
|
||||
success = eWalker.perform();
|
||||
if (success) {
|
||||
std::vector<TopoDS_Wire> rWires = eWalker.getResultNoDups();
|
||||
std::vector<TopoDS_Wire> sortedWires = eWalker.sortStrip(rWires, true);
|
||||
outerWire = new TopoShapeWirePy(new TopoShape(*sortedWires.begin()));
|
||||
} else {
|
||||
Base::Console().Warning("findOuterWire: input is not planar graph. Wire detection not done\n");
|
||||
}
|
||||
sortedWires = eWalker.execute(edgeList);
|
||||
}
|
||||
catch (Base::Exception &e) {
|
||||
e.setPyException();
|
||||
throw Py::Exception();
|
||||
}
|
||||
if (!success) {
|
||||
|
||||
if(sortedWires.empty()) {
|
||||
Base::Console().Warning("ATDP::findOuterWire: Outline wire detection failed\n");
|
||||
return Py::None();
|
||||
} else {
|
||||
outerWire = new TopoShapeWirePy(new TopoShape(*sortedWires.begin()));
|
||||
}
|
||||
return Py::asObject(outerWire);
|
||||
}
|
||||
@@ -382,28 +384,25 @@ private:
|
||||
return Py::None();
|
||||
}
|
||||
|
||||
std::vector<TopoDS_Edge> closedEdges;
|
||||
edgeList = DrawProjectSplit::scrubEdges(edgeList, closedEdges);
|
||||
|
||||
PyObject* outerWire = nullptr;
|
||||
bool success = false;
|
||||
std::vector<TopoDS_Wire> sortedWires;
|
||||
try {
|
||||
EdgeWalker eWalker;
|
||||
eWalker.loadEdges(edgeList);
|
||||
if(eWalker.perform()) {
|
||||
std::vector<TopoDS_Wire> rWires = eWalker.getResultNoDups();
|
||||
std::vector<TopoDS_Wire> sortedWires = eWalker.sortStrip(rWires, true);
|
||||
if(!sortedWires.empty()) {
|
||||
outerWire = new TopoShapeWirePy(new TopoShape(*sortedWires.begin()));
|
||||
success = true;
|
||||
}
|
||||
} else {
|
||||
Base::Console().Warning("ATDP::findShapeOutline: input is not planar graph. Wire detection not done\n");
|
||||
}
|
||||
sortedWires = eWalker.execute(edgeList);
|
||||
}
|
||||
catch (Base::Exception &e) {
|
||||
e.setPyException();
|
||||
throw Py::Exception();
|
||||
}
|
||||
if (!success) {
|
||||
|
||||
if(sortedWires.empty()) {
|
||||
Base::Console().Warning("ATDP::findShapeOutline: Outline wire detection failed\n");
|
||||
return Py::None();
|
||||
} else {
|
||||
outerWire = new TopoShapeWirePy(new TopoShape(*sortedWires.begin()));
|
||||
}
|
||||
return Py::asObject(outerWire);
|
||||
}
|
||||
|
||||
@@ -166,6 +166,7 @@ SET(TechDraw_SRCS
|
||||
TechDrawExport.h
|
||||
ProjectionAlgos.cpp
|
||||
ProjectionAlgos.h
|
||||
EWTOLERANCE.h
|
||||
)
|
||||
|
||||
SET(Geometry_SRCS
|
||||
|
||||
@@ -29,18 +29,24 @@
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepGProp.hxx>
|
||||
#include <BRepAdaptor_Curve.hxx>
|
||||
#include <BRepAlgoAPI_Common.hxx>
|
||||
#include <BRepAlgoAPI_Fuse.hxx>
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeVertex.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <BRepBuilderAPI_Copy.hxx>
|
||||
#include <BRepLProp_CurveTool.hxx>
|
||||
#include <BRepLProp_CLProps.hxx>
|
||||
#include <BRepExtrema_DistShapeShape.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <BRepBndLib.hxx>
|
||||
#include <Bnd_Box.hxx>
|
||||
#include <Geom_Curve.hxx>
|
||||
#include <GeomAPI_ProjectPointOnCurve.hxx>
|
||||
#include <GProp_GProps.hxx>
|
||||
#include <GCPnts_AbscissaPoint.hxx>
|
||||
#include <gp_Ax2.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <gp_Dir.hxx>
|
||||
@@ -50,6 +56,7 @@
|
||||
#include <HLRAlgo_Projector.hxx>
|
||||
#include <HLRBRep_ShapeBounds.hxx>
|
||||
#include <HLRBRep_HLRToShape.hxx>
|
||||
#include <ShapeAnalysis.hxx>
|
||||
#include <ShapeFix_ShapeTolerance.hxx>
|
||||
#include <ShapeExtend_WireData.hxx>
|
||||
#include <ShapeFix_Wire.hxx>
|
||||
@@ -78,12 +85,8 @@
|
||||
#include "DrawUtil.h"
|
||||
#include "Geometry.h"
|
||||
#include "GeometryObject.h"
|
||||
#include "EWTOLERANCE.h"
|
||||
#include "DrawProjectSplit.h"
|
||||
#include "DrawHatch.h"
|
||||
#include "EdgeWalker.h"
|
||||
|
||||
|
||||
//#include <Mod/TechDraw/App/DrawProjectSplitPy.h> // generated from DrawProjectSplitPy.xml
|
||||
|
||||
using namespace TechDraw;
|
||||
using namespace std;
|
||||
@@ -101,48 +104,55 @@ DrawProjectSplit::~DrawProjectSplit()
|
||||
{
|
||||
}
|
||||
|
||||
//make a projection of shape and return the edges
|
||||
//used by python outline routines
|
||||
std::vector<TopoDS_Edge> DrawProjectSplit::getEdgesForWalker(TopoDS_Shape shape, double scale, Base::Vector3d direction)
|
||||
{
|
||||
std::vector<TopoDS_Edge> result;
|
||||
std::vector<TopoDS_Edge> edgesIn;
|
||||
if (shape.IsNull()) {
|
||||
return result;
|
||||
return edgesIn;
|
||||
}
|
||||
|
||||
BRepBuilderAPI_Copy BuilderCopy(shape);
|
||||
TopoDS_Shape copyShape = BuilderCopy.Shape();
|
||||
|
||||
gp_Pnt inputCenter(0, 0,0);
|
||||
gp_Pnt inputCenter(0, 0, 0);
|
||||
TopoDS_Shape scaledShape;
|
||||
scaledShape = TechDraw::scaleShape(copyShape,
|
||||
scale);
|
||||
// gp_Ax2 viewAxis = TechDraw::getViewAxis(Base::Vector3d(0.0, 0.0, 0.0), direction);
|
||||
gp_Ax2 viewAxis = TechDraw::legacyViewAxis1(Base::Vector3d(0.0, 0.0, 0.0), direction);
|
||||
scale);
|
||||
gp_Ax2 viewAxis = TechDraw::legacyViewAxis1(Base::Vector3d(0.0, 0.0, 0.0), direction, false);
|
||||
TechDraw::GeometryObject* go = buildGeometryObject(scaledShape, viewAxis);
|
||||
result = getEdges(go);
|
||||
const std::vector<TechDraw::BaseGeomPtr>& goEdges = go->getVisibleFaceEdges(false, false);
|
||||
for (auto& e: goEdges){
|
||||
edgesIn.push_back(e->occEdge);
|
||||
}
|
||||
|
||||
std::vector<TopoDS_Edge> nonZero;
|
||||
for (auto& e: edgesIn) { //drop any zero edges (shouldn't be any by now!!!)
|
||||
if (!DrawUtil::isZeroEdge(e, 2.0 * EWTOLERANCE)) {
|
||||
nonZero.push_back(e);
|
||||
} else {
|
||||
Base::Console().Message("DPS::getEdgesForWalker found ZeroEdge!\n");
|
||||
}
|
||||
}
|
||||
|
||||
delete go;
|
||||
return result;
|
||||
return nonZero;
|
||||
}
|
||||
|
||||
|
||||
//project the shape using viewAxis (coordinate system) and return a geometry object
|
||||
TechDraw::GeometryObject* DrawProjectSplit::buildGeometryObject(TopoDS_Shape shape,
|
||||
const gp_Ax2& viewAxis)
|
||||
{
|
||||
TechDraw::GeometryObject* geometryObject = new TechDraw::GeometryObject("DrawProjectSplit", nullptr);
|
||||
|
||||
if (geometryObject->usePolygonHLR()){
|
||||
geometryObject->projectShapeWithPolygonAlgo(shape,
|
||||
viewAxis);
|
||||
geometryObject->projectShapeWithPolygonAlgo(shape, viewAxis);
|
||||
}
|
||||
else{
|
||||
geometryObject->projectShape(shape,
|
||||
viewAxis);
|
||||
//note that this runs in the main thread, unlike DrawViewPart
|
||||
geometryObject->projectShape(shape, viewAxis);
|
||||
}
|
||||
|
||||
geometryObject->extractGeometry(TechDraw::ecHARD, //always show the hard&outline visible lines
|
||||
true);
|
||||
geometryObject->extractGeometry(TechDraw::ecOUTLINE,
|
||||
true);
|
||||
return geometryObject;
|
||||
}
|
||||
|
||||
@@ -159,10 +169,8 @@ std::vector<TopoDS_Edge> DrawProjectSplit::getEdges(TechDraw::GeometryObject* ge
|
||||
std::vector<TopoDS_Edge> faceEdges;
|
||||
std::vector<TopoDS_Edge> nonZero;
|
||||
for (auto& e:origEdges) { //drop any zero edges (shouldn't be any by now!!!)
|
||||
if (!DrawUtil::isZeroEdge(e)) {
|
||||
if (!DrawUtil::isZeroEdge(e, 2.0 * EWTOLERANCE)) {
|
||||
nonZero.push_back(e);
|
||||
} else {
|
||||
Base::Console().Message("INFO - DPS::getEdges found ZeroEdge!\n");
|
||||
}
|
||||
}
|
||||
faceEdges = nonZero;
|
||||
@@ -180,11 +188,9 @@ std::vector<TopoDS_Edge> DrawProjectSplit::getEdges(TechDraw::GeometryObject* ge
|
||||
BRepBndLib::AddOptimal(*itOuter, sOuter);
|
||||
sOuter.SetGap(0.1);
|
||||
if (sOuter.IsVoid()) {
|
||||
Base::Console().Message("DPS::Extract Faces - outer Bnd_Box is void\n");
|
||||
continue;
|
||||
}
|
||||
if (DrawUtil::isZeroEdge(*itOuter)) {
|
||||
Base::Console().Message("DPS::extractFaces - outerEdge: %d is ZeroEdge\n", iOuter); //this is not finding ZeroEdges
|
||||
continue; //skip zero length edges. shouldn't happen ;)
|
||||
}
|
||||
int iInner = 0;
|
||||
@@ -201,7 +207,6 @@ std::vector<TopoDS_Edge> DrawProjectSplit::getEdges(TechDraw::GeometryObject* ge
|
||||
BRepBndLib::AddOptimal(*itInner, sInner);
|
||||
sInner.SetGap(0.1);
|
||||
if (sInner.IsVoid()) {
|
||||
Base::Console().Log("INFO - DPS::Extract Faces - inner Bnd_Box is void\n");
|
||||
continue;
|
||||
}
|
||||
if (sOuter.IsOut(sInner)) { //bboxes of edges don't intersect, don't bother
|
||||
@@ -233,10 +238,9 @@ std::vector<TopoDS_Edge> DrawProjectSplit::getEdges(TechDraw::GeometryObject* ge
|
||||
sorted.erase(last, sorted.end()); //remove dupls
|
||||
std::vector<TopoDS_Edge> newEdges = splitEdges(faceEdges, sorted);
|
||||
|
||||
if (newEdges.empty()) {
|
||||
Base::Console().Log("LOG - DPS::extractFaces - no newEdges\n");
|
||||
if (!newEdges.empty()) {
|
||||
newEdges = removeDuplicateEdges(newEdges);
|
||||
}
|
||||
newEdges = removeDuplicateEdges(newEdges);
|
||||
return newEdges;
|
||||
}
|
||||
|
||||
@@ -253,9 +257,7 @@ bool DrawProjectSplit::isOnEdge(TopoDS_Edge e, TopoDS_Vertex v, double& param, b
|
||||
Bnd_Box sBox;
|
||||
BRepBndLib::AddOptimal(e, sBox);
|
||||
sBox.SetGap(0.1);
|
||||
if (sBox.IsVoid()) {
|
||||
Base::Console().Message("DPS::isOnEdge - Bnd_Box is void\n");
|
||||
} else {
|
||||
if (!sBox.IsVoid()) {
|
||||
gp_Pnt pt = BRep_Tool::Pnt(v);
|
||||
if (sBox.IsOut(pt)) {
|
||||
outOfBox = true;
|
||||
@@ -370,7 +372,7 @@ std::vector<TopoDS_Edge> DrawProjectSplit::split1Edge(TopoDS_Edge e, std::vector
|
||||
}
|
||||
}
|
||||
catch (Standard_Failure&) {
|
||||
Base::Console().Message("LOG - DPS::split1Edge failed building edge segment\n");
|
||||
Base::Console().Message("DPS::split1Edge failed building edge segment\n");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -445,12 +447,12 @@ std::vector<TopoDS_Edge> DrawProjectSplit::removeDuplicateEdges(std::vector<Topo
|
||||
auto last = std::unique(sorted.begin(), sorted.end(), edgeSortItem::edgeEqual); //duplicates to back
|
||||
sorted.erase(last, sorted.end()); //remove dupls
|
||||
|
||||
//TODO: "sorted" turns to garbage if pagescale set to "0.1"!!!!???? ***
|
||||
for (const auto& e: sorted) {
|
||||
if (e.idx < inEdges.size()) {
|
||||
result.push_back(inEdges.at(e.idx)); //<<< ***here
|
||||
result.push_back(inEdges.at(e.idx));
|
||||
} else {
|
||||
Base::Console().Message("ERROR - DPS::removeDuplicateEdges - access: %d inEdges: %d\n", e.idx, inEdges.size());
|
||||
//TODO: throw index error
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -517,4 +519,412 @@ std::string edgeSortItem::dump()
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//
|
||||
|
||||
//*****************************************
|
||||
// routines for revised face finding approach
|
||||
//*****************************************
|
||||
|
||||
//clean an unstructured group of edges so they can be connected into sensible closed faces.
|
||||
// Warning: uses loose tolerances to create connections between edges
|
||||
std::vector<TopoDS_Edge> DrawProjectSplit::scrubEdges(const std::vector<TechDraw::BaseGeomPtr>& origEdges,
|
||||
std::vector<TopoDS_Edge> &closedEdges)
|
||||
{
|
||||
// Base::Console().Message("DPS::scrubEdges() - edges in: %d\n", origEdges.size());
|
||||
//make a copy of the input edges so the loose tolerances of face finding are
|
||||
//not applied to the real edge geometry. See TopoDS_Shape::TShape().
|
||||
std::vector<TopoDS_Edge> copyEdges;
|
||||
bool copyGeometry = true;
|
||||
bool copyMesh = false;
|
||||
for (const auto& tdEdge: origEdges) {
|
||||
if (!DrawUtil::isZeroEdge(tdEdge->occEdge, 2.0 * EWTOLERANCE)) {
|
||||
BRepBuilderAPI_Copy copier(tdEdge->occEdge, copyGeometry, copyMesh);
|
||||
copyEdges.push_back(TopoDS::Edge(copier.Shape()));
|
||||
}
|
||||
}
|
||||
return scrubEdges(copyEdges, closedEdges);
|
||||
}
|
||||
|
||||
//origEdges should be a copy of the original edges since the underlying TShape will be modified.
|
||||
std::vector<TopoDS_Edge> DrawProjectSplit::scrubEdges(std::vector<TopoDS_Edge>& origEdges,
|
||||
std::vector<TopoDS_Edge> &closedEdges)
|
||||
{
|
||||
//HLR usually delivers overlapping edges. We need to refine edge overlaps
|
||||
//into non-overlapping pieces
|
||||
std::vector<TopoDS_Edge> noOverlaps;
|
||||
noOverlaps = DrawProjectSplit::removeOverlapEdges(origEdges);
|
||||
|
||||
//HLR algo does not provide all edge intersections.
|
||||
//need to split edges at intersection points.
|
||||
std::vector<TopoDS_Edge> splitEdges;
|
||||
splitEdges = DrawProjectSplit::splitIntersectingEdges(noOverlaps);
|
||||
|
||||
//separate any closed edges (ex circle) from the edge pile so as not to confuse
|
||||
//the edge walker later. Closed edges are added back in the caller after
|
||||
//EdgeWalker finds the faces using the open edges
|
||||
std::vector<TopoDS_Edge> openEdges;
|
||||
for (auto& edge : splitEdges) {
|
||||
if (BRep_Tool::IsClosed(edge)) {
|
||||
closedEdges.push_back(edge);
|
||||
} else {
|
||||
openEdges.push_back(edge);
|
||||
}
|
||||
}
|
||||
|
||||
//find all the unique vertices and count how many edges terminate at each, then
|
||||
//remove edges that can't be part of a closed region since they are not connected at both ends
|
||||
vertexMap verts = DrawProjectSplit::getUniqueVertexes(openEdges);
|
||||
std::vector<TopoDS_Edge> cleanEdges;
|
||||
cleanEdges = DrawProjectSplit::pruneUnconnected(verts, openEdges);
|
||||
|
||||
return cleanEdges;
|
||||
}
|
||||
|
||||
//extract a map of unique vertexes based on start and end point of each edge in
|
||||
//the input vector and count the usage of each unique vertex
|
||||
vertexMap DrawProjectSplit::getUniqueVertexes(std::vector<TopoDS_Edge> inEdges)
|
||||
{
|
||||
vertexMap verts;
|
||||
//count the occurrences of each vertex in the pile
|
||||
for (auto& edge: inEdges) {
|
||||
gp_Pnt p = BRep_Tool::Pnt(TopExp::FirstVertex(edge));
|
||||
Base::Vector3d v0(p.X(), p.Y(), p.Z());
|
||||
vertexMap::iterator it0(verts.find(v0));
|
||||
if (it0 != verts.end()) {
|
||||
it0->second++;
|
||||
} else {
|
||||
verts[v0] = 1;
|
||||
}
|
||||
p = BRep_Tool::Pnt(TopExp::LastVertex(edge));
|
||||
Base::Vector3d v1(p.X(), p.Y(), p.Z());
|
||||
vertexMap::iterator it1(verts.find(v1));
|
||||
if (it1 != verts.end()) {
|
||||
it1->second++;
|
||||
} else {
|
||||
verts[v1] = 1;
|
||||
}
|
||||
}
|
||||
return verts;
|
||||
}
|
||||
|
||||
//if an edge is not connected at both ends, then it can't be part of a face boundary
|
||||
//and unconnected edges may confuse up the edge walker.
|
||||
//note: closed edges have been removed by this point for later handling
|
||||
std::vector<TopoDS_Edge> DrawProjectSplit::pruneUnconnected(vertexMap verts,
|
||||
std::vector<TopoDS_Edge> edges)
|
||||
{
|
||||
// Base::Console().Message("DPS::pruneUnconnected() - edges in: %d\n", edges.size());
|
||||
//check if edge ends are used at least twice => edge is joined to another edge
|
||||
std::vector<TopoDS_Edge> newPile;
|
||||
std::vector<TopoDS_Edge> deadEnds;
|
||||
for (auto& edge: edges) {
|
||||
gp_Pnt p = BRep_Tool::Pnt(TopExp::FirstVertex(edge));
|
||||
Base::Vector3d v0(p.X(), p.Y(), p.Z());
|
||||
int count0 = 0;
|
||||
vertexMap::iterator it0(verts.find(v0));
|
||||
if (it0 != verts.end()) {
|
||||
count0 = it0->second;
|
||||
}
|
||||
p = BRep_Tool::Pnt(TopExp::LastVertex(edge));
|
||||
Base::Vector3d v1(p.X(), p.Y(), p.Z());
|
||||
int count1 = 0;
|
||||
vertexMap::iterator it1(verts.find(v1));
|
||||
if (it1 != verts.end()) {
|
||||
count1 = it1->second;
|
||||
}
|
||||
if ((count0 > 1) && (count1 > 1)) { //connected at both ends
|
||||
newPile.push_back(edge);
|
||||
} else if ((count0 == 1) && (count1 == 1)) {
|
||||
//completely disconnected edge. just drop it.
|
||||
continue;
|
||||
} else {
|
||||
//only connected at 1 end
|
||||
deadEnds.push_back(edge); //could separate dead ends here
|
||||
}
|
||||
}
|
||||
|
||||
return newPile;
|
||||
}
|
||||
|
||||
bool DrawProjectSplit::sameEndPoints(TopoDS_Edge& e1, TopoDS_Edge& e2)
|
||||
{
|
||||
bool result = false;
|
||||
TopoDS_Vertex first1 = TopExp::FirstVertex(e1);
|
||||
TopoDS_Vertex last1 = TopExp::LastVertex(e1);
|
||||
TopoDS_Vertex first2 = TopExp::FirstVertex(e2);
|
||||
TopoDS_Vertex last2 = TopExp::LastVertex(e2);
|
||||
|
||||
if (DrawUtil::vertexEqual(first1, first2) &&
|
||||
DrawUtil::vertexEqual(last1, last2) ) {
|
||||
result = true;
|
||||
} else if (DrawUtil::vertexEqual(first1, last2) &&
|
||||
DrawUtil::vertexEqual(last1, first2) ) {
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define e0ISSUBSET 0
|
||||
#define e1ISSUBSET 1
|
||||
#define EDGEOVERLAP 2
|
||||
#define NOTASUBSET 3
|
||||
|
||||
//eliminate edges that overlap another edge
|
||||
std::vector<TopoDS_Edge> DrawProjectSplit::removeOverlapEdges(std::vector<TopoDS_Edge> inEdges)
|
||||
{
|
||||
// Base::Console().Message("DPS::removeOverlapEdges() - %d edges in\n", inEdges.size());
|
||||
std::vector<TopoDS_Edge> outEdges;
|
||||
std::vector<TopoDS_Edge> overlapEdges;
|
||||
std::vector<bool> skipThisEdge(inEdges.size(), false);
|
||||
int edgeCount = inEdges.size();
|
||||
int ie0 = 0;
|
||||
for (; ie0 < edgeCount; ie0++) {
|
||||
if (skipThisEdge.at(ie0)) {
|
||||
continue;
|
||||
}
|
||||
int ie1 = ie0 + 1;
|
||||
for (; ie1 < edgeCount; ie1++) {
|
||||
if (skipThisEdge.at(ie1)) {
|
||||
continue;
|
||||
}
|
||||
int rc = isSubset(inEdges.at(ie0), inEdges.at(ie1));
|
||||
if (rc == e0ISSUBSET) {
|
||||
skipThisEdge.at(ie0) = true;
|
||||
break; //stop checking ie0
|
||||
} else if (rc == e1ISSUBSET) {
|
||||
skipThisEdge.at(ie1) = true;
|
||||
} else if (rc == EDGEOVERLAP) {
|
||||
skipThisEdge.at(ie0) = true;
|
||||
skipThisEdge.at(ie1) = true;
|
||||
std::vector<TopoDS_Edge> olap = fuseEdges(inEdges.at(ie0), inEdges.at(ie1));
|
||||
if (!olap.empty()) {
|
||||
overlapEdges.insert(overlapEdges.end(), olap.begin(), olap.end());
|
||||
}
|
||||
break; //stop checking ie0
|
||||
}
|
||||
} //inner loop
|
||||
} //outer loop
|
||||
|
||||
int iOut = 0;
|
||||
for (auto& e: inEdges) {
|
||||
if (!skipThisEdge.at(iOut)) {
|
||||
outEdges.push_back(e);
|
||||
}
|
||||
iOut++;
|
||||
}
|
||||
|
||||
if (!overlapEdges.empty()) {
|
||||
outEdges.insert(outEdges.end(), overlapEdges.begin(), overlapEdges.end());
|
||||
}
|
||||
return outEdges;
|
||||
}
|
||||
|
||||
//determine if edge0 & edge1 are superimposed, and classify the type of overlap
|
||||
int DrawProjectSplit::isSubset(TopoDS_Edge& edge0, TopoDS_Edge& edge1)
|
||||
{
|
||||
if (!boxesIntersect(edge0, edge1)) {
|
||||
return NOTASUBSET; //boxes don't intersect, so edges do not overlap
|
||||
}
|
||||
|
||||
//bboxes of edges intersect
|
||||
BRepAlgoAPI_Common anOp;
|
||||
anOp.SetFuzzyValue (FUZZYADJUST * EWTOLERANCE);
|
||||
TopTools_ListOfShape anArg1, anArg2;
|
||||
anArg1.Append (edge0);
|
||||
anArg2.Append (edge1);
|
||||
anOp.SetArguments (anArg1);
|
||||
anOp.SetTools (anArg2);
|
||||
anOp.Build();
|
||||
TopoDS_Shape aRes = anOp.Shape(); //always a compound
|
||||
if (aRes.IsNull()) {
|
||||
return NOTASUBSET; //no common segment
|
||||
}
|
||||
std::vector<TopoDS_Edge> commonEdgeList;
|
||||
TopExp_Explorer edges(aRes, TopAbs_EDGE);
|
||||
for (int i = 1; edges.More(); edges.Next(), i++) {
|
||||
commonEdgeList.push_back(TopoDS::Edge(edges.Current()));
|
||||
}
|
||||
if (commonEdgeList.empty()) {
|
||||
return NOTASUBSET;
|
||||
}
|
||||
//we're only going to deal with the situation where the common of the edges
|
||||
//is a single edge. A really odd pair of edges could have >1 edge in their
|
||||
//common.
|
||||
TopoDS_Edge commonEdge = commonEdgeList.at(0);
|
||||
if (sameEndPoints(edge1, commonEdge)) {
|
||||
return e1ISSUBSET; //e1 is a subset of e0
|
||||
}
|
||||
if (sameEndPoints(edge0, commonEdge)) {
|
||||
return e0ISSUBSET; //e0 is a subset of e1
|
||||
}
|
||||
// edge0 is not a subset of edge1, nor is edge1 a subset of edge0, but they have a common segment
|
||||
return EDGEOVERLAP;
|
||||
}
|
||||
|
||||
//edge0 and edge1 overlap, so we need to make 3 edges - part of edge0, common segment, part of edge1
|
||||
std::vector<TopoDS_Edge> DrawProjectSplit::fuseEdges(TopoDS_Edge &edge0, TopoDS_Edge &edge1)
|
||||
{
|
||||
std::vector<TopoDS_Edge> edgeList;
|
||||
BRepAlgoAPI_Fuse anOp;
|
||||
anOp.SetFuzzyValue (FUZZYADJUST * EWTOLERANCE);
|
||||
TopTools_ListOfShape anArg1, anArg2;
|
||||
anArg1.Append (edge0);
|
||||
anArg2.Append (edge1);
|
||||
anOp.SetArguments (anArg1);
|
||||
anOp.SetTools (anArg2);
|
||||
anOp.Build();
|
||||
TopoDS_Shape aRes = anOp.Shape(); //always a compound
|
||||
if (aRes.IsNull()) {
|
||||
return edgeList; //empty result
|
||||
}
|
||||
TopExp_Explorer edges(aRes, TopAbs_EDGE);
|
||||
for (int i = 1; edges.More(); edges.Next(), i++) {
|
||||
edgeList.push_back(TopoDS::Edge(edges.Current()));
|
||||
}
|
||||
return edgeList;
|
||||
}
|
||||
|
||||
//split edges that intersect into pieces.
|
||||
std::vector<TopoDS_Edge> DrawProjectSplit::splitIntersectingEdges(std::vector<TopoDS_Edge>& inEdges)
|
||||
{
|
||||
// Base::Console().Message("DPS::splitIntersectingEdges() - edges in: %d\n", inEdges.size());
|
||||
std::vector<TopoDS_Edge> outEdges;
|
||||
std::vector<bool> skipThisEdge(inEdges.size(), false);
|
||||
int edgeCount = inEdges.size();
|
||||
int iEdge0 = 0;
|
||||
for (; iEdge0 < edgeCount; iEdge0++) { //all but last one
|
||||
if (skipThisEdge.at(iEdge0)) {
|
||||
continue;
|
||||
}
|
||||
int iEdge1 = iEdge0 + 1;
|
||||
bool outerEdgeSplit = false;
|
||||
for (; iEdge1 < edgeCount; iEdge1++) {
|
||||
if (skipThisEdge.at(iEdge1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (boxesIntersect(inEdges.at(iEdge0), inEdges.at(iEdge1))) {
|
||||
std::vector<TopoDS_Edge> intersectEdges = fuseEdges(inEdges.at(iEdge0), inEdges.at(iEdge1));
|
||||
if (intersectEdges.empty()) {
|
||||
//don't think this can happen. fusion of disjoint edges is 2 edges.
|
||||
//maybe an error?
|
||||
continue; //next inner edge
|
||||
}
|
||||
|
||||
if (intersectEdges.size() == 1) {
|
||||
//one edge is a subset of the other.
|
||||
if (sameEndPoints(inEdges.at(iEdge0), intersectEdges.front())) {
|
||||
//we got the outer edge back so mark the inner edge
|
||||
skipThisEdge.at(iEdge1);
|
||||
} else if (sameEndPoints(inEdges.at(iEdge1), intersectEdges.front())) {
|
||||
//we got the inner edge back so mark the outer edge and go to the next outer edge
|
||||
skipThisEdge.at(iEdge0);
|
||||
break; //next outer edge
|
||||
} else {
|
||||
//not sure what this means? bad geometry?
|
||||
}
|
||||
|
||||
} else if (intersectEdges.size() == 2) {
|
||||
//got the input edges back, so no intersection. carry on with next inner edge
|
||||
continue; //next inner edge
|
||||
|
||||
} else if (intersectEdges.size() == 3) {
|
||||
//we have split 1 edge at a vertex of the other edge
|
||||
//check if outer edge is the one split
|
||||
bool innerEdgeSplit = false;
|
||||
for (auto& interEdge : intersectEdges) {
|
||||
if (!sameEndPoints(inEdges.at(iEdge0), interEdge) &&
|
||||
!sameEndPoints(inEdges.at(iEdge1), interEdge)) {
|
||||
//interEdge does not match either outer or inner edge,
|
||||
//so this is a piece of the split edge and we need to add it
|
||||
//to end of list
|
||||
inEdges.push_back(interEdge);
|
||||
skipThisEdge.push_back(false);
|
||||
edgeCount++;
|
||||
}
|
||||
if (sameEndPoints(inEdges.at(iEdge0), interEdge)) {
|
||||
//outer edge is in output, so it was not split.
|
||||
//therefore the inner edge was split and we should skip it in the future
|
||||
//the two pieces of the split edge will have been added to edgesToKeep
|
||||
//in the previous if
|
||||
innerEdgeSplit = true;
|
||||
skipThisEdge.at(iEdge1) = true;
|
||||
} else if (sameEndPoints(inEdges.at(iEdge1), interEdge)) {
|
||||
//inner edge is in output, so it was not split.
|
||||
//therefore the outer edge was split and we should skip it in the future.
|
||||
outerEdgeSplit = true;
|
||||
skipThisEdge.at(iEdge0) = true;
|
||||
}
|
||||
}
|
||||
if (!innerEdgeSplit && !outerEdgeSplit) {
|
||||
//neither edge found in output, so this was a partial overlap, so
|
||||
//both edges are replaced by the 3 split pieces
|
||||
//Q: why does this happen if we have run pruneOverlaps before this???
|
||||
skipThisEdge.at(iEdge0) = true;
|
||||
skipThisEdge.at(iEdge1) = true;
|
||||
outerEdgeSplit = true;
|
||||
}
|
||||
if (outerEdgeSplit) {
|
||||
//we can't use the outer edge any more, so we should exit the inner loop
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (intersectEdges.size() == 4) {
|
||||
//we have split both edges at a single intersection
|
||||
skipThisEdge.at(iEdge0) = true;
|
||||
skipThisEdge.at(iEdge1) = true;
|
||||
inEdges.insert(inEdges.end(), intersectEdges.begin(), intersectEdges.end());
|
||||
skipThisEdge.insert(skipThisEdge.end(), { false, false, false, false});
|
||||
edgeCount += 4;
|
||||
outerEdgeSplit = true;
|
||||
break;
|
||||
|
||||
} else {
|
||||
//this means multiple intersections of the 2 edges. we don't handle that yet.
|
||||
continue; //next inner edge?
|
||||
}
|
||||
|
||||
} else {
|
||||
//bboxes of edges do not intersect, so edges do not intersect
|
||||
}
|
||||
} //inner loop boundary
|
||||
|
||||
if (!outerEdgeSplit) {
|
||||
//outer edge[iEdge0] was not split, so add it to the output and mark it as used
|
||||
outEdges.push_back(inEdges.at(iEdge0));
|
||||
skipThisEdge.at(iEdge0) = true; //superfluous?
|
||||
}
|
||||
} //outer loop boundary
|
||||
|
||||
if (!skipThisEdge.back()) {
|
||||
//last entry has not been split, so add it to output
|
||||
outEdges.push_back(inEdges.back());
|
||||
}
|
||||
|
||||
return outEdges;
|
||||
}
|
||||
|
||||
bool DrawProjectSplit::boxesIntersect(TopoDS_Edge& edge0, TopoDS_Edge& edge1)
|
||||
{
|
||||
Bnd_Box box0, box1;
|
||||
BRepBndLib::Add(edge0, box0);
|
||||
box0.SetGap(0.1); //generous
|
||||
BRepBndLib::Add(edge1, box1);
|
||||
box1.SetGap(0.1);
|
||||
if (box0.IsOut(box1)) {
|
||||
return false; //boxes don't intersect
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//this is an aid to debugging and isn't used in normal processing.
|
||||
void DrawProjectSplit::dumpVertexMap(vertexMap verts)
|
||||
{
|
||||
Base::Console().Message("DPS::dumpVertexMap - %d verts\n", verts.size());
|
||||
int iVert = 0;
|
||||
for (auto& item : verts) {
|
||||
Base::Console().Message("%d: %s - %d\n",iVert,
|
||||
DrawUtil::formatVector(item.first).c_str(), item.second);
|
||||
iVert++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
#include <Base/Vector3D.h>
|
||||
|
||||
|
||||
#include "DrawUtil.h"
|
||||
#include "Geometry.h"
|
||||
|
||||
class gp_Pnt;
|
||||
class gp_Ax2;
|
||||
|
||||
@@ -44,6 +47,10 @@ class BaseGeom;
|
||||
|
||||
namespace TechDraw
|
||||
{
|
||||
|
||||
//magic number for finding parameter of point on curve
|
||||
#define PARAM_MAX_DIST 0.000001
|
||||
|
||||
struct splitPoint {
|
||||
int i;
|
||||
Base::Vector3d v;
|
||||
@@ -69,6 +76,21 @@ public:
|
||||
static bool edgeEqual(const edgeSortItem& e1, const edgeSortItem& e2);
|
||||
std::string dump();
|
||||
};
|
||||
|
||||
using vertexMap = std::map<Base::Vector3d, int, DrawUtil::vectorLessType>;
|
||||
|
||||
class edgeVectorEntry {
|
||||
public:
|
||||
edgeVectorEntry(TopoDS_Edge e, bool flag) {
|
||||
edge = e;
|
||||
validFlag = flag;
|
||||
}
|
||||
~edgeVectorEntry() = default;
|
||||
|
||||
TopoDS_Edge edge;
|
||||
bool validFlag;
|
||||
};
|
||||
|
||||
class TechDrawExport DrawProjectSplit
|
||||
{
|
||||
public:
|
||||
@@ -89,6 +111,28 @@ public:
|
||||
static std::vector<TopoDS_Edge> removeDuplicateEdges(std::vector<TopoDS_Edge>& inEdges);
|
||||
static std::vector<edgeSortItem> sortEdges(std::vector<edgeSortItem>& e, bool ascend);
|
||||
|
||||
|
||||
//routines for revised face finding approach
|
||||
static std::vector<TopoDS_Edge> scrubEdges(const std::vector<BaseGeomPtr> &origEdges,
|
||||
std::vector<TopoDS_Edge>& closedEdges);
|
||||
static std::vector<TopoDS_Edge> scrubEdges(std::vector<TopoDS_Edge>& origEdges,
|
||||
std::vector<TopoDS_Edge>& closedEdges);
|
||||
static vertexMap getUniqueVertexes(std::vector<TopoDS_Edge> inEdges);
|
||||
static std::vector<TopoDS_Edge> pruneUnconnected(vertexMap verts,
|
||||
std::vector<TopoDS_Edge> edges);
|
||||
static std::vector<TopoDS_Edge> removeOverlapEdges(std::vector<TopoDS_Edge> inEdges);
|
||||
static std::vector<TopoDS_Edge> splitIntersectingEdges(std::vector<TopoDS_Edge>& inEdges);
|
||||
|
||||
static bool sameEndPoints(TopoDS_Edge& e1,
|
||||
TopoDS_Edge& e2);
|
||||
static int isSubset(TopoDS_Edge &e0,
|
||||
TopoDS_Edge &e1);
|
||||
static std::vector<TopoDS_Edge> fuseEdges(TopoDS_Edge& e0,
|
||||
TopoDS_Edge& e1);
|
||||
static bool boxesIntersect(TopoDS_Edge& e0,
|
||||
TopoDS_Edge& e1);
|
||||
static void dumpVertexMap(vertexMap verts);
|
||||
|
||||
protected:
|
||||
static std::vector<TopoDS_Edge> getEdges(TechDraw::GeometryObject* geometryObject);
|
||||
|
||||
|
||||
@@ -75,6 +75,9 @@
|
||||
#include <Mod/Part/App/PartFeature.h>
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
|
||||
|
||||
#include "EWTOLERANCE.h"
|
||||
#include "GeometryObject.h"
|
||||
#include "DrawUtil.h"
|
||||
|
||||
using namespace TechDraw;
|
||||
@@ -155,9 +158,8 @@ bool DrawUtil::isZeroEdge(TopoDS_Edge e, double tolerance)
|
||||
TopoDS_Vertex vEnd = TopExp::LastVertex(e);
|
||||
if (isSamePoint(vStart, vEnd, tolerance)) {
|
||||
//closed edge will have same V's but non-zero length
|
||||
GProp_GProps props;
|
||||
BRepGProp::LinearProperties(e, props);
|
||||
double len = props.Mass();
|
||||
BRepAdaptor_Curve adapt(e);
|
||||
double len = GCPnts_AbscissaPoint::Length(adapt, Precision::Confusion());
|
||||
if (len > tolerance) {
|
||||
return false;
|
||||
}
|
||||
@@ -206,47 +208,61 @@ double DrawUtil::angleWithX(TopoDS_Edge e, TopoDS_Vertex v, double tolerance)
|
||||
{
|
||||
double param = 0;
|
||||
|
||||
//find tangent @ v
|
||||
double adjust = 1.0; //occ tangent points in direction of curve. at lastVert we need to reverse it.
|
||||
BRepAdaptor_Curve adapt(e);
|
||||
if (isFirstVert(e, v,tolerance)) {
|
||||
param = adapt.FirstParameter();
|
||||
} else if (isLastVert(e, v,tolerance)) {
|
||||
param = adapt.LastParameter();
|
||||
adjust = -1;
|
||||
} else {
|
||||
//TARFU
|
||||
Base::Console().Message("Error: DU::angleWithX - v is neither first nor last \n");
|
||||
//must be able to get non-terminal point parm from curve/
|
||||
}
|
||||
gp_Pnt paramPoint;
|
||||
gp_Vec derivative;
|
||||
const Handle(Geom_Curve) c = adapt.Curve().Curve();
|
||||
c->D1(param, paramPoint, derivative);
|
||||
double angle = atan2(derivative.Y(), derivative.X());
|
||||
if (angle < 0) { //map from [-PI:PI] to [0:2PI]
|
||||
angle += 2.0 * M_PI;
|
||||
}
|
||||
return angle;
|
||||
}
|
||||
|
||||
//! find angle of incidence at First/LastVertex
|
||||
double DrawUtil::incidenceAngleAtVertex(TopoDS_Edge e, TopoDS_Vertex v, double tolerance)
|
||||
{
|
||||
double incidenceAngle = 0;
|
||||
|
||||
BRepAdaptor_Curve adapt(e);
|
||||
double paramRange = adapt.LastParameter() - adapt.FirstParameter();
|
||||
double paramOffset = paramRange / 100.0;
|
||||
double vertexParam;
|
||||
Base::Vector3d anglePoint = DrawUtil::vertex2Vector(v);
|
||||
Base::Vector3d offsetPoint, incidenceVec;
|
||||
int noTangents = 0;
|
||||
if (isFirstVert(e,v,tolerance)) {
|
||||
vertexParam = adapt.FirstParameter();
|
||||
BRepLProp_CLProps prop(adapt, vertexParam + paramOffset, noTangents, Precision::Confusion());
|
||||
const gp_Pnt& gOffsetPoint = prop.Value();
|
||||
offsetPoint = Base::Vector3d(gOffsetPoint.X(), gOffsetPoint.Y(), gOffsetPoint.Z());
|
||||
} else if (isLastVert(e,v,tolerance)) {
|
||||
vertexParam = adapt.LastParameter();
|
||||
BRepLProp_CLProps prop(adapt, vertexParam - paramOffset, noTangents, Precision::Confusion());
|
||||
const gp_Pnt& gOffsetPoint = prop.Value();
|
||||
offsetPoint = Base::Vector3d(gOffsetPoint.X(), gOffsetPoint.Y(), gOffsetPoint.Z());
|
||||
} else {
|
||||
//TARFU
|
||||
// Base::Console().Message("DU::incidenceAngle - v is neither first nor last \n");
|
||||
}
|
||||
incidenceVec = anglePoint - offsetPoint;
|
||||
incidenceAngle = atan2(incidenceVec.y, incidenceVec.x);
|
||||
|
||||
//map to [0:2PI]
|
||||
if (incidenceAngle < 0.0) {
|
||||
incidenceAngle = M_2PI + incidenceAngle;
|
||||
}
|
||||
|
||||
Base::Vector3d uVec(0.0, 0.0, 0.0);
|
||||
gp_Dir uDir;
|
||||
BRepLProp_CLProps prop(adapt, param, 2,tolerance);
|
||||
if (prop.IsTangentDefined()) {
|
||||
prop.Tangent(uDir);
|
||||
uVec = Base::Vector3d(uDir.X(), uDir.Y(), uDir.Z()) * adjust;
|
||||
} else {
|
||||
//this bit is a little sketchy
|
||||
gp_Pnt gstart = BRep_Tool::Pnt(TopExp::FirstVertex(e));
|
||||
Base::Vector3d start(gstart.X(), gstart.Y(), gstart.Z());
|
||||
gp_Pnt gend = BRep_Tool::Pnt(TopExp::LastVertex(e));
|
||||
Base::Vector3d end(gend.X(), gend.Y(), gend.Z());
|
||||
if (isFirstVert(e, v,tolerance)) {
|
||||
uVec = end - start;
|
||||
} else if (isLastVert(e, v,tolerance)) {
|
||||
uVec = end - start;
|
||||
} else {
|
||||
gp_Pnt errPnt = BRep_Tool::Pnt(v);
|
||||
Base::Console().Warning("angleWithX: Tangent not defined at (%.3f, %.3f, %.3f)\n", errPnt.X(), errPnt.Y(), errPnt.Z());
|
||||
//throw ??????
|
||||
}
|
||||
}
|
||||
double result = atan2(uVec.y, uVec.x);
|
||||
if (result < 0) { //map from [-PI:PI] to [0:2PI]
|
||||
result += 2.0 * M_PI;
|
||||
}
|
||||
return result;
|
||||
return incidenceAngle;
|
||||
}
|
||||
|
||||
bool DrawUtil::isFirstVert(TopoDS_Edge e, TopoDS_Vertex v, double tolerance)
|
||||
@@ -399,20 +415,77 @@ std::string DrawUtil::formatVector(const QPointF& v)
|
||||
}
|
||||
|
||||
//! compare 2 vectors for sorting - true if v1 < v2
|
||||
//! precision::Confusion() is too strict for vertex - vertex comparisons
|
||||
bool DrawUtil::vectorLess(const Base::Vector3d& v1, const Base::Vector3d& v2)
|
||||
{
|
||||
if ((v1 - v2).Length() > Precision::Confusion()) { //ie v1 != v2
|
||||
if (!DrawUtil::fpCompare(v1.x, v2.x)) {
|
||||
return v1.x < v2.x;
|
||||
} else if (!DrawUtil::fpCompare(v1.y, v2.y)) {
|
||||
return v1.y < v2.y;
|
||||
if ((v1 - v2).Length() > EWTOLERANCE) { //ie v1 != v2
|
||||
if (!DrawUtil::fpCompare(v1.x, v2.x, 2.0 * EWTOLERANCE)) {
|
||||
return (v1.x < v2.x);
|
||||
} else if (!DrawUtil::fpCompare(v1.y, v2.y, 2.0 * EWTOLERANCE)) {
|
||||
return (v1.y < v2.y);
|
||||
} else {
|
||||
return v1.z < v2.z;
|
||||
return (v1.z < v2.z);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//! test for equality of two vertexes using the vectorLess comparator as used
|
||||
//! in sorts and containers
|
||||
bool DrawUtil::vertexEqual(TopoDS_Vertex& v1, TopoDS_Vertex& v2)
|
||||
{
|
||||
gp_Pnt gv1 = BRep_Tool::Pnt(v1);
|
||||
gp_Pnt gv2 = BRep_Tool::Pnt(v2);
|
||||
Base::Vector3d vv1(gv1.X(), gv1.Y(), gv1.Z());
|
||||
Base::Vector3d vv2(gv2.X(), gv2.Y(), gv2.Z());
|
||||
return vectorEqual(vv1, vv2);
|
||||
}
|
||||
|
||||
//! test for equality of two vectors using the vectorLess comparator as used
|
||||
//! in sorts and containers
|
||||
bool DrawUtil::vectorEqual(Base::Vector3d& v1, Base::Vector3d& v2)
|
||||
{
|
||||
bool less1 = vectorLess(v1, v2);
|
||||
bool less2 = vectorLess(v2, v1);
|
||||
return !less1 && !less2;
|
||||
}
|
||||
|
||||
//TODO: the next 2 could be templated
|
||||
//construct a compound shape from a list of edges
|
||||
TopoDS_Shape DrawUtil::vectorToCompound(std::vector<TopoDS_Edge> vecIn)
|
||||
{
|
||||
BRep_Builder builder;
|
||||
TopoDS_Compound compOut;
|
||||
builder.MakeCompound(compOut);
|
||||
for (auto& v : vecIn) {
|
||||
builder.Add(compOut, v);
|
||||
}
|
||||
return TechDraw::mirrorShape(compOut);
|
||||
}
|
||||
|
||||
//construct a compound shape from a list of wires
|
||||
TopoDS_Shape DrawUtil::vectorToCompound(std::vector<TopoDS_Wire> vecIn)
|
||||
{
|
||||
BRep_Builder builder;
|
||||
TopoDS_Compound compOut;
|
||||
builder.MakeCompound(compOut);
|
||||
for (auto& v : vecIn) {
|
||||
builder.Add(compOut, v);
|
||||
}
|
||||
return TechDraw::mirrorShape(compOut);
|
||||
}
|
||||
|
||||
//constructs a list of edges from a shape
|
||||
std::vector<TopoDS_Edge> DrawUtil::shapeToVector(TopoDS_Shape shapeIn)
|
||||
{
|
||||
std::vector<TopoDS_Edge> vectorOut;
|
||||
TopExp_Explorer expl(shapeIn, TopAbs_EDGE);
|
||||
for ( ; expl.More(); expl.Next()) {
|
||||
vectorOut.push_back(TopoDS::Edge(expl.Current()));
|
||||
}
|
||||
return vectorOut;
|
||||
}
|
||||
|
||||
//!convert fromPoint in coordinate system fromSystem to reference coordinate system
|
||||
Base::Vector3d DrawUtil::toR3(const gp_Ax2& fromSystem, const Base::Vector3d& fromPoint)
|
||||
{
|
||||
@@ -742,17 +815,6 @@ bool DrawUtil::isCrazy(TopoDS_Edge e)
|
||||
return false;
|
||||
}
|
||||
|
||||
//construct a compound shape from a list of edges
|
||||
TopoDS_Shape DrawUtil::vectorToCompound(std::vector<TopoDS_Edge> vecIn)
|
||||
{
|
||||
BRep_Builder builder;
|
||||
TopoDS_Compound compOut;
|
||||
builder.MakeCompound(compOut);
|
||||
for (auto& v : vecIn) {
|
||||
builder.Add(compOut, v);
|
||||
}
|
||||
return TopoDS_Compound(std::move(compOut));
|
||||
}
|
||||
//get 3d position of a face's center
|
||||
Base::Vector3d DrawUtil::getFaceCenter(TopoDS_Face f)
|
||||
{
|
||||
@@ -1220,7 +1282,7 @@ void DrawUtil::dumpEdges(const char* text, const TopoDS_Shape& s)
|
||||
|
||||
void DrawUtil::dump1Vertex(const char* text, const TopoDS_Vertex& v)
|
||||
{
|
||||
Base::Console().Message("DUMP - dump1Vertex - %s\n", text);
|
||||
// Base::Console().Message("DUMP - dump1Vertex - %s\n",text);
|
||||
gp_Pnt pnt = BRep_Tool::Pnt(v);
|
||||
Base::Console().Message("%s: (%.3f, %.3f, %.3f)\n", text, pnt.X(), pnt.Y(), pnt.Z());
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopoDS_Shape.hxx>
|
||||
#include <TopoDS_Vertex.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
|
||||
#include <Base/Vector3D.h>
|
||||
#include <Mod/Part/App/PartFeature.h>
|
||||
@@ -54,6 +55,7 @@
|
||||
#endif
|
||||
|
||||
#define VERTEXTOLERANCE (2.0 * Precision::Confusion())
|
||||
#define VECTORTOLERANCE (Precision::Confusion())
|
||||
|
||||
#define SVG_NS_URI "http://www.w3.org/2000/svg"
|
||||
#define FREECAD_SVG_NS_URI "http://www.freecadweb.org/wiki/index.php?title=Svg_Namespace"
|
||||
@@ -73,6 +75,8 @@ class TechDrawExport DrawUtil {
|
||||
static double sensibleScale(double working_scale);
|
||||
static double angleWithX(TopoDS_Edge e, bool reverse);
|
||||
static double angleWithX(TopoDS_Edge e, TopoDS_Vertex v, double tolerance = VERTEXTOLERANCE);
|
||||
static double incidenceAngleAtVertex(TopoDS_Edge e, TopoDS_Vertex v, double tolerance);
|
||||
|
||||
static bool isFirstVert(TopoDS_Edge e, TopoDS_Vertex v, double tolerance = VERTEXTOLERANCE);
|
||||
static bool isLastVert(TopoDS_Edge e, TopoDS_Vertex v, double tolerance = VERTEXTOLERANCE);
|
||||
static bool fpCompare(const double& d1, const double& d2, double tolerance = FLT_EPSILON);
|
||||
@@ -82,8 +86,6 @@ class TechDrawExport DrawUtil {
|
||||
double yRange) ;
|
||||
static Base::Vector3d vertex2Vector(const TopoDS_Vertex& v);
|
||||
|
||||
static TopoDS_Shape vectorToCompound(std::vector<TopoDS_Edge> vecIn);
|
||||
|
||||
static std::string formatVector(const Base::Vector3d& v);
|
||||
static std::string formatVector(const gp_Dir& v);
|
||||
static std::string formatVector(const gp_Dir2d& v);
|
||||
@@ -93,6 +95,19 @@ class TechDrawExport DrawUtil {
|
||||
static std::string formatVector(const QPointF& v);
|
||||
|
||||
static bool vectorLess(const Base::Vector3d& v1, const Base::Vector3d& v2);
|
||||
//!std::map require comparator to be a type not a function
|
||||
struct vectorLessType {
|
||||
bool operator()(const Base::Vector3d& a, const Base::Vector3d& b) const {
|
||||
return DrawUtil::vectorLess(a, b);
|
||||
}
|
||||
};
|
||||
static bool vertexEqual(TopoDS_Vertex& v1, TopoDS_Vertex& v2);
|
||||
static bool vectorEqual(Base::Vector3d& v1, Base::Vector3d& v2);
|
||||
|
||||
static TopoDS_Shape vectorToCompound(std::vector<TopoDS_Edge> vecIn);
|
||||
static TopoDS_Shape vectorToCompound(std::vector<TopoDS_Wire> vecIn);
|
||||
static std::vector<TopoDS_Edge> shapeToVector(TopoDS_Shape shapeIn);
|
||||
|
||||
static Base::Vector3d toR3(const gp_Ax2& fromSystem, const Base::Vector3d& fromPoint);
|
||||
static bool checkParallel(const Base::Vector3d v1, const Base::Vector3d v2, double tolerance = FLT_EPSILON);
|
||||
//! rotate vector by angle radians around axis through org
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <gp_Pln.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
#include <HLRAlgo_Projector.hxx>
|
||||
#include <ShapeAnalysis.hxx>
|
||||
#include <TopExp.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
@@ -414,8 +415,7 @@ void DrawViewPart::onHlrFinished(void)
|
||||
|
||||
//start face finding in a separate thread. We don't find faces when using the polygon
|
||||
//HLR method.
|
||||
if (handleFaces() && !CoarseView.getValue() &&
|
||||
!waitingForFaces() && !waitingForHlr()) {
|
||||
if (handleFaces() && !CoarseView.getValue() ) {
|
||||
try {
|
||||
//note that &m_faceWatcher in the third parameter is not strictly required, but using the
|
||||
//4 parameter signature instead of the 3 parameter signature prevents clazy warning:
|
||||
@@ -481,127 +481,180 @@ void DrawViewPart::extractFaces()
|
||||
|
||||
showProgressMessage(getNameInDocument(), "is extracting faces");
|
||||
|
||||
//make a copy of the input edges so the loose tolerances of face finding are
|
||||
//not applied to the real edge geometry. See TopoDS_Shape::TShape().
|
||||
const std::vector<TechDraw::BaseGeomPtr>& goEdges =
|
||||
geometryObject->getVisibleFaceEdges(SmoothVisible.getValue(), SeamVisible.getValue());
|
||||
geometryObject->getVisibleFaceEdges(SmoothVisible.getValue(),SeamVisible.getValue());
|
||||
|
||||
if (goEdges.empty()) {
|
||||
Base::Console().Message("DVP::extractFaces - %s - no face edges available!\n", getNameInDocument());
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<TopoDS_Edge> copyEdges;
|
||||
for (auto& tdEdge: goEdges) {
|
||||
BRepBuilderAPI_Copy copier(tdEdge->occEdge, true, true); //copy occEdge with its geometry (TShape) and mesh info
|
||||
copyEdges.push_back(TopoDS::Edge(copier.Shape()));
|
||||
}
|
||||
if (newFaceFinder()) {
|
||||
std::vector<TopoDS_Edge> closedEdges;
|
||||
std::vector<TopoDS_Edge> cleanEdges = DrawProjectSplit::scrubEdges(goEdges, closedEdges);
|
||||
|
||||
std::vector<TopoDS_Edge> nonZero;
|
||||
for (auto& e:copyEdges) { //drop any zero edges (shouldn't be any by now!!!)
|
||||
if (!DrawUtil::isZeroEdge(e)) {
|
||||
nonZero.push_back(e);
|
||||
//use EdgeWalker to make wires from edges
|
||||
EdgeWalker eWalker;
|
||||
std::vector<TopoDS_Wire> sortedWires;
|
||||
try {
|
||||
if (!cleanEdges.empty()) {
|
||||
sortedWires = eWalker.execute(cleanEdges, true); //include outer wire
|
||||
}
|
||||
}
|
||||
}
|
||||
geometryObject->clearFaceGeom();
|
||||
catch (Base::Exception &e) {
|
||||
throw Base::RuntimeError(e.what());
|
||||
}
|
||||
geometryObject->clearFaceGeom();
|
||||
|
||||
//HLR algo does not provide all edge intersections for edge endpoints.
|
||||
//need to split long edges touched by Vertex of another edge
|
||||
std::vector<splitPoint> splits;
|
||||
std::vector<TopoDS_Edge>::iterator itOuter = nonZero.begin();
|
||||
int iOuter = 0;
|
||||
for (; itOuter != nonZero.end(); ++itOuter, iOuter++) {
|
||||
TopoDS_Vertex v1 = TopExp::FirstVertex((*itOuter));
|
||||
TopoDS_Vertex v2 = TopExp::LastVertex((*itOuter));
|
||||
Bnd_Box sOuter;
|
||||
BRepBndLib::AddOptimal(*itOuter, sOuter);
|
||||
sOuter.SetGap(0.1);
|
||||
if (sOuter.IsVoid()) {
|
||||
continue;
|
||||
std::vector<TopoDS_Wire> closedWires;
|
||||
for (auto& e: closedEdges) {
|
||||
BRepBuilderAPI_MakeWire mkWire(e);
|
||||
TopoDS_Wire w = mkWire.Wire();
|
||||
closedWires.push_back(w);
|
||||
}
|
||||
if (DrawUtil::isZeroEdge(*itOuter)) {
|
||||
continue; //skip zero length edges. shouldn't happen ;)
|
||||
if (!closedWires.empty()) {
|
||||
sortedWires.insert(sortedWires.end(), closedWires.begin(), closedWires.end());
|
||||
//inserting the closedWires that did not go through EdgeWalker into
|
||||
//sortedWires ruins EdgeWalker's sort by size, so we have to do it again.
|
||||
sortedWires = eWalker.sortWiresBySize(sortedWires);
|
||||
}
|
||||
int iInner = 0;
|
||||
std::vector<TopoDS_Edge>::iterator itInner = nonZero.begin(); //***sb itOuter + 1;
|
||||
for (; itInner != nonZero.end(); ++itInner, iInner++) {
|
||||
if (iInner == iOuter) {
|
||||
|
||||
if (sortedWires.empty()) {
|
||||
Base::Console().Warning("DVP::extractFaces - %s - Can't make faces from projected edges\n", getNameInDocument());
|
||||
} else {
|
||||
BRepTools::Write(DrawUtil::vectorToCompound(sortedWires), "DVPSortedWires.brep"); //debug
|
||||
double minWireArea = 0.000001; //arbitrary very small face size
|
||||
std::vector<TopoDS_Wire>::iterator itWire = sortedWires.begin();
|
||||
for (; itWire != sortedWires.end(); itWire++) {
|
||||
if (!BRep_Tool::IsClosed(*itWire)) {
|
||||
continue; //can not make a face from open wire
|
||||
} else {
|
||||
double area = ShapeAnalysis::ContourArea(*itWire);
|
||||
if (area <= minWireArea) {
|
||||
continue; //can not make a face from wire with no area
|
||||
}
|
||||
}
|
||||
TechDraw::FacePtr f(std::make_shared<TechDraw::Face>());
|
||||
const TopoDS_Wire& wire = (*itWire);
|
||||
TechDraw::Wire* w = new TechDraw::Wire(wire);
|
||||
f->wires.push_back(w);
|
||||
if (geometryObject) {
|
||||
geometryObject->addFaceGeom(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { //use original method
|
||||
//make a copy of the input edges so the loose tolerances of face finding are
|
||||
//not applied to the real edge geometry. See TopoDS_Shape::TShape().
|
||||
std::vector<TopoDS_Edge> copyEdges;
|
||||
bool copyGeometry = true;
|
||||
bool copyMesh = false;
|
||||
for (const auto& e: goEdges) {
|
||||
BRepBuilderAPI_Copy copier(e->occEdge, copyGeometry, copyMesh);
|
||||
copyEdges.push_back(TopoDS::Edge(copier.Shape()));
|
||||
}
|
||||
std::vector<TopoDS_Edge> nonZero;
|
||||
for (auto& e: copyEdges) { //drop any zero edges (shouldn't be any by now!!!)
|
||||
if (!DrawUtil::isZeroEdge(e)) {
|
||||
nonZero.push_back(e);
|
||||
} else {
|
||||
Base::Console().Log("INFO - DVP::extractFaces for %s found ZeroEdge!\n",getNameInDocument());
|
||||
}
|
||||
}
|
||||
|
||||
//HLR algo does not provide all edge intersections for edge endpoints.
|
||||
//need to split long edges touched by Vertex of another edge
|
||||
std::vector<splitPoint> splits;
|
||||
std::vector<TopoDS_Edge>::iterator itOuter = nonZero.begin();
|
||||
int iOuter = 0;
|
||||
for (; itOuter != nonZero.end(); ++itOuter, iOuter++) { //*** itOuter != nonZero.end() - 1
|
||||
TopoDS_Vertex v1 = TopExp::FirstVertex((*itOuter));
|
||||
TopoDS_Vertex v2 = TopExp::LastVertex((*itOuter));
|
||||
Bnd_Box sOuter;
|
||||
BRepBndLib::AddOptimal(*itOuter, sOuter);
|
||||
sOuter.SetGap(0.1);
|
||||
if (sOuter.IsVoid()) {
|
||||
Base::Console().Log("DVP::Extract Faces - outer Bnd_Box is void for %s\n",getNameInDocument());
|
||||
continue;
|
||||
}
|
||||
if (DrawUtil::isZeroEdge((*itInner))) {
|
||||
if (DrawUtil::isZeroEdge(*itOuter)) {
|
||||
Base::Console().Log("DVP::extractFaces - outerEdge: %d is ZeroEdge\n",iOuter); //this is not finding ZeroEdges
|
||||
continue; //skip zero length edges. shouldn't happen ;)
|
||||
}
|
||||
int iInner = 0;
|
||||
std::vector<TopoDS_Edge>::iterator itInner = nonZero.begin(); //***sb itOuter + 1;
|
||||
for (; itInner != nonZero.end(); ++itInner,iInner++) {
|
||||
if (iInner == iOuter) {
|
||||
continue;
|
||||
}
|
||||
if (DrawUtil::isZeroEdge((*itInner))) {
|
||||
continue; //skip zero length edges. shouldn't happen ;)
|
||||
}
|
||||
|
||||
Bnd_Box sInner;
|
||||
BRepBndLib::AddOptimal(*itInner, sInner);
|
||||
sInner.SetGap(0.1);
|
||||
if (sInner.IsVoid()) {
|
||||
continue;
|
||||
Bnd_Box sInner;
|
||||
BRepBndLib::AddOptimal(*itInner, sInner);
|
||||
sInner.SetGap(0.1);
|
||||
if (sInner.IsVoid()) {
|
||||
Base::Console().Log("INFO - DVP::Extract Faces - inner Bnd_Box is void for %s\n",getNameInDocument());
|
||||
continue;
|
||||
}
|
||||
if (sOuter.IsOut(sInner)) { //bboxes of edges don't intersect, don't bother
|
||||
continue;
|
||||
}
|
||||
|
||||
double param = -1;
|
||||
if (DrawProjectSplit::isOnEdge((*itInner),v1,param,false)) {
|
||||
gp_Pnt pnt1 = BRep_Tool::Pnt(v1);
|
||||
splitPoint s1;
|
||||
s1.i = iInner;
|
||||
s1.v = Base::Vector3d(pnt1.X(),pnt1.Y(),pnt1.Z());
|
||||
s1.param = param;
|
||||
splits.push_back(s1);
|
||||
}
|
||||
if (DrawProjectSplit::isOnEdge((*itInner),v2,param,false)) {
|
||||
gp_Pnt pnt2 = BRep_Tool::Pnt(v2);
|
||||
splitPoint s2;
|
||||
s2.i = iInner;
|
||||
s2.v = Base::Vector3d(pnt2.X(),pnt2.Y(),pnt2.Z());
|
||||
s2.param = param;
|
||||
splits.push_back(s2);
|
||||
}
|
||||
} //inner loop
|
||||
} //outer loop
|
||||
|
||||
std::vector<splitPoint> sorted = DrawProjectSplit::sortSplits(splits,true);
|
||||
auto last = std::unique(sorted.begin(), sorted.end(), DrawProjectSplit::splitEqual); //duplicates to back
|
||||
sorted.erase(last, sorted.end()); //remove dupl splits
|
||||
std::vector<TopoDS_Edge> newEdges = DrawProjectSplit::splitEdges(nonZero,sorted);
|
||||
|
||||
if (newEdges.empty()) {
|
||||
Base::Console().Log("DVP::extractFaces - no newEdges\n");
|
||||
return;
|
||||
}
|
||||
|
||||
newEdges = DrawProjectSplit::removeDuplicateEdges(newEdges);
|
||||
|
||||
geometryObject->clearFaceGeom();
|
||||
|
||||
//find all the wires in the pile of faceEdges
|
||||
std::vector<TopoDS_Wire> sortedWires;
|
||||
EdgeWalker eWalker;
|
||||
sortedWires = eWalker.execute(newEdges);
|
||||
if (sortedWires.empty()) {
|
||||
Base::Console().Warning("DVP::extractFaces - %s -Can't make faces from projected edges\n", getNameInDocument());
|
||||
return;
|
||||
} else {
|
||||
std::vector<TopoDS_Wire>::iterator itWire = sortedWires.begin();
|
||||
for (; itWire != sortedWires.end(); itWire++) {
|
||||
//version 1: 1 wire/face - no voids in face
|
||||
TechDraw::FacePtr f(std::make_shared<TechDraw::Face>());
|
||||
const TopoDS_Wire& wire = (*itWire);
|
||||
TechDraw::Wire* w = new TechDraw::Wire(wire);
|
||||
f->wires.push_back(w);
|
||||
if (geometryObject) {
|
||||
geometryObject->addFaceGeom(f);
|
||||
}
|
||||
}
|
||||
if (sOuter.IsOut(sInner)) { //bboxes of edges don't intersect, don't bother
|
||||
continue;
|
||||
}
|
||||
|
||||
double param = -1; //parametric point on edge where the vertex touches
|
||||
if (DrawProjectSplit::isOnEdge((*itInner), v1, param, false)) {
|
||||
gp_Pnt pnt1 = BRep_Tool::Pnt(v1);
|
||||
splitPoint s1;
|
||||
s1.i = iInner;
|
||||
s1.v = Base::Vector3d(pnt1.X(), pnt1.Y(), pnt1.Z());
|
||||
s1.param = param;
|
||||
splits.push_back(s1);
|
||||
}
|
||||
if (DrawProjectSplit::isOnEdge((*itInner), v2, param, false)) {
|
||||
gp_Pnt pnt2 = BRep_Tool::Pnt(v2);
|
||||
splitPoint s2;
|
||||
s2.i = iInner;
|
||||
s2.v = Base::Vector3d(pnt2.X(), pnt2.Y(), pnt2.Z());
|
||||
s2.param = param;
|
||||
splits.push_back(s2);
|
||||
}
|
||||
} //inner loop
|
||||
} //outer loop
|
||||
|
||||
//if edge A was touched at the same point by multiple edges B, we only want to split A once
|
||||
std::vector<splitPoint> sorted = DrawProjectSplit::sortSplits(splits, true);
|
||||
auto last = std::unique(sorted.begin(), sorted.end(), DrawProjectSplit::splitEqual); //duplicates to back
|
||||
sorted.erase(last, sorted.end()); //remove duplicate splits
|
||||
|
||||
std::vector<TopoDS_Edge> newEdges = DrawProjectSplit::splitEdges(nonZero, sorted);
|
||||
|
||||
if (newEdges.empty()) {
|
||||
Base::Console().Log("DVP::extractFaces - no edges return by splitting process\n");
|
||||
waitingForFaces(false);
|
||||
return;
|
||||
}
|
||||
|
||||
//try to remove any duplicated edges since they will confuse the edgeWalker
|
||||
newEdges = DrawProjectSplit::removeDuplicateEdges(newEdges);
|
||||
|
||||
//find all the wires in the pile of faceEdges
|
||||
EdgeWalker ew;
|
||||
ew.loadEdges(newEdges);
|
||||
bool success = ew.perform();
|
||||
if (!success) {
|
||||
Base::Console().Warning("DVP::extractFaces - %s - Can't make faces from projected edges\n", getNameInDocument());
|
||||
waitingForFaces(false);
|
||||
return;
|
||||
}
|
||||
std::vector<TopoDS_Wire> fw = ew.getResultNoDups();
|
||||
|
||||
std::vector<TopoDS_Wire> sortedWires = ew.sortStrip(fw, true);
|
||||
|
||||
std::vector<TopoDS_Wire>::iterator itWire = sortedWires.begin();
|
||||
for (; itWire != sortedWires.end(); itWire++) {
|
||||
//version 1: 1 wire/face - no voids in face
|
||||
TechDraw::FacePtr f(std::make_shared<TechDraw::Face>());
|
||||
const TopoDS_Wire& wire = (*itWire);
|
||||
TechDraw::Wire* w = new TechDraw::Wire(wire);
|
||||
f->wires.push_back(w);
|
||||
if (geometryObject) {
|
||||
//it can happen that a new hlr cycle deletes geometryObject while we are
|
||||
//extracting faces. if it does happen, a new cycle should fix it.
|
||||
geometryObject->addFaceGeom(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -609,7 +662,7 @@ void DrawViewPart::extractFaces()
|
||||
//continue processing after extractFaces thread completes
|
||||
void DrawViewPart::onFacesFinished(void)
|
||||
{
|
||||
// Base::Console().Message("DVP::onFacesFinished()\n");
|
||||
// Base::Console().Message("DVP::onFacesFinished() - %s\n", getNameInDocument());
|
||||
waitingForFaces(false);
|
||||
QObject::disconnect(connectFaceWatcher);
|
||||
showProgressMessage(getNameInDocument(), "has finished extracting faces");
|
||||
@@ -980,6 +1033,14 @@ bool DrawViewPart::handleFaces()
|
||||
return hGrp->GetBool("HandleFaces", 1l);
|
||||
}
|
||||
|
||||
bool DrawViewPart::newFaceFinder(void)
|
||||
{
|
||||
Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
|
||||
.GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/General");
|
||||
bool result = hGrp->GetBool("NewFaceFinder", 0l);
|
||||
return result;
|
||||
}
|
||||
|
||||
//! remove features that are useless without this DVP
|
||||
//! hatches, geomhatches, dimensions, ...
|
||||
void DrawViewPart::unsetupObject()
|
||||
|
||||
@@ -159,6 +159,7 @@ public:
|
||||
|
||||
|
||||
bool handleFaces();
|
||||
bool newFaceFinder();
|
||||
|
||||
bool isUnsetting() { return nowUnsetting; }
|
||||
|
||||
|
||||
30
src/Mod/TechDraw/App/EWTOLERANCE.h
Normal file
30
src/Mod/TechDraw/App/EWTOLERANCE.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2022 Wanderer Fan <wandererfan@gmail.com> *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
//some shapes are being passed in where edges that should be connected are in fact
|
||||
//separated by more than 2*Precision::Confusion (expected tolerance for 2 TopoDS_Vertex)
|
||||
//this value is used in EdgeWalker, DrawProjectSplit and DrawUtil and needs to be in sync in
|
||||
//all 3 files.
|
||||
#define EWTOLERANCE 0.0001 //arbitrary number that seems to give good results for drawing
|
||||
|
||||
//a multiplier for EWTOLERANCE used in fuzzy fuse and common operations.
|
||||
#define FUZZYADJUST 4.0
|
||||
@@ -27,8 +27,6 @@
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <boost/graph/boyer_myrvold_planar_test.hpp>
|
||||
#include <boost/graph/is_kuratowski_subgraph.hpp>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <BRepBndLib.hxx>
|
||||
#include <Bnd_Box.hxx>
|
||||
@@ -38,19 +36,19 @@
|
||||
#include <ShapeExtend_WireData.hxx>
|
||||
#include <ShapeFix_Wire.hxx>
|
||||
#include <TopExp.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <GProp_GProps.hxx>
|
||||
#include <BRepGProp.hxx>
|
||||
|
||||
#endif
|
||||
|
||||
#include <sstream>
|
||||
#include <cmath>
|
||||
|
||||
#include <boost/graph/boyer_myrvold_planar_test.hpp>
|
||||
#include <boost/graph/is_kuratowski_subgraph.hpp>
|
||||
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Exception.h>
|
||||
|
||||
#include "DrawUtil.h"
|
||||
#include "EWTOLERANCE.h"
|
||||
#include "EdgeWalker.h"
|
||||
|
||||
using namespace TechDraw;
|
||||
@@ -69,19 +67,18 @@ void edgeVisitor::next_edge(Edge e)
|
||||
we.v2 = t;
|
||||
we.ed = e;
|
||||
we.idx = get(edge_index, m_g, e);
|
||||
//Base::Console().Message("TRACE - EV::next_Edge - visiting (%d, %d) idx: %d\n", s,t, we.idx);
|
||||
wireEdges.push_back(we);
|
||||
}
|
||||
|
||||
void edgeVisitor::begin_face()
|
||||
{
|
||||
//Base::Console().Message("TRACE - EV::begin_face()\n");
|
||||
// Base::Console().Message("EV::begin_face()\n");
|
||||
wireEdges.clear();
|
||||
}
|
||||
|
||||
void edgeVisitor::end_face()
|
||||
{
|
||||
//Base::Console().Message("TRACE - EV::end_face()\n");
|
||||
// Base::Console().Message("EV::end_face()\n");
|
||||
graphWires.push_back(wireEdges);
|
||||
}
|
||||
|
||||
@@ -99,11 +96,6 @@ void edgeVisitor::setGraph(TechDraw::graph& g)
|
||||
//* EdgeWalker methods
|
||||
//*******************************************************
|
||||
|
||||
//some shapes are being passed in where edges that should be connected are in fact
|
||||
//separated by more than 2*Precision::Confusion (expected tolerance for 2 TopoDS_Vertex)
|
||||
#define EWTOLERANCE 0.00001 //arbitrary number that seems to give good results for drawing
|
||||
|
||||
|
||||
EdgeWalker::EdgeWalker()
|
||||
{
|
||||
}
|
||||
@@ -115,7 +107,7 @@ EdgeWalker::~EdgeWalker()
|
||||
//loads a list of unique edges into the traversal mechanism
|
||||
bool EdgeWalker::loadEdges(std::vector<TechDraw::WalkerEdge>& edges)
|
||||
{
|
||||
//Base::Console().Message("TRACE -EW::loadEdges(we)\n");
|
||||
// Base::Console().Message("EW::loadEdges(we) - WEdgesIn: %d\n", edges.size());
|
||||
int idx = 0;
|
||||
for (auto& e: edges) {
|
||||
std::pair<edge_t, bool> p;
|
||||
@@ -131,7 +123,7 @@ bool EdgeWalker::loadEdges(std::vector<TechDraw::WalkerEdge>& edges)
|
||||
|
||||
bool EdgeWalker::loadEdges(std::vector<TopoDS_Edge> edges)
|
||||
{
|
||||
//Base::Console().Message("TRACE -EW::loadEdges(TopoDS)\n");
|
||||
// Base::Console().Message("EW::loadEdges(TopoDS) - edges: %d\n", edges.size());
|
||||
if (edges.empty()) {
|
||||
throw Base::ValueError("EdgeWalker has no edges to load\n");
|
||||
}
|
||||
@@ -146,19 +138,19 @@ bool EdgeWalker::loadEdges(std::vector<TopoDS_Edge> edges)
|
||||
|
||||
return true;
|
||||
}
|
||||
bool EdgeWalker::setSize(int size)
|
||||
bool EdgeWalker::setSize(std::size_t size)
|
||||
{
|
||||
m_g.clear();
|
||||
for (int i = 0; i < size; i++) {
|
||||
for (std::size_t i = 0; i < size; i++) {
|
||||
boost::adjacency_list<>::vertex_descriptor vd = boost::add_vertex(m_g);
|
||||
(void)vd;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EdgeWalker::perform()
|
||||
bool EdgeWalker::prepare()
|
||||
{
|
||||
//Base::Console().Message("TRACE - EW::perform()\n");
|
||||
//Base::Console().Message("TRACE - EW::prepare()\n");
|
||||
// Initialize the interior edge index
|
||||
property_map<TechDraw::graph, edge_index_t>::type e_index = get(edge_index, m_g);
|
||||
graph_traits<TechDraw::graph>::edges_size_type edge_count = 0;
|
||||
@@ -198,16 +190,16 @@ bool EdgeWalker::perform()
|
||||
std::back_inserter(kEdges));
|
||||
if (!isPlanar) {
|
||||
//TODO: remove kura subgraph to make planar??
|
||||
Base::Console().Log("LOG - EW::perform - input is NOT planar\n");
|
||||
Base::Console().Message("EW::prepare - input is NOT planar\n");
|
||||
ki_end = kEdges.end();
|
||||
std::stringstream ss;
|
||||
ss << "EW::perform - obstructing edges: ";
|
||||
ss << "EW::prepare - obstructing edges: ";
|
||||
for(ki = kEdges.begin(); ki != ki_end; ++ki) {
|
||||
e1 = *ki;
|
||||
ss << boost::get(edge_index, m_g, e1) << ", ";
|
||||
}
|
||||
ss << std::endl;
|
||||
Base::Console().Log("LOG - %s\n", ss.str().c_str());
|
||||
Base::Console().Message("%s\n", ss.str().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -217,6 +209,18 @@ bool EdgeWalker::perform()
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<TopoDS_Wire> EdgeWalker::execute(std::vector<TopoDS_Edge> edgeList, bool biggie)
|
||||
{
|
||||
std::vector<TopoDS_Wire> sortedWires;
|
||||
loadEdges(edgeList);
|
||||
bool success = prepare();
|
||||
if (success) {
|
||||
std::vector<TopoDS_Wire> rw = getResultNoDups();
|
||||
sortedWires = sortStrip(rw, biggie);
|
||||
}
|
||||
return sortedWires;
|
||||
}
|
||||
|
||||
ewWireList EdgeWalker::getResult()
|
||||
{
|
||||
//Base::Console().Message("TRACE - EW::getResult()\n");
|
||||
@@ -242,7 +246,7 @@ std::vector<TopoDS_Wire> EdgeWalker::getResultWires()
|
||||
TopoDS_Edge e = m_saveInEdges.at((*iEdge).idx);
|
||||
topoEdges.push_back(e);
|
||||
}
|
||||
TopoDS_Wire w = makeCleanWire(topoEdges); //make 1 clean wire from its edges
|
||||
TopoDS_Wire w = makeCleanWire(topoEdges, EWTOLERANCE); //make 1 clean wire from its edges
|
||||
fw.push_back(w);
|
||||
}
|
||||
return fw;
|
||||
@@ -267,8 +271,8 @@ std::vector<TopoDS_Wire> EdgeWalker::getResultNoDups()
|
||||
TopoDS_Edge e = m_saveInEdges.at((*iEdge).idx);
|
||||
topoEdges.push_back(e);
|
||||
}
|
||||
TopoDS_Wire w = makeCleanWire(topoEdges); //make 1 clean wire from its edges
|
||||
fw.push_back(w);
|
||||
TopoDS_Wire w = makeCleanWire(topoEdges, EWTOLERANCE); //make 1 clean wire from its edges
|
||||
fw.push_back(w);
|
||||
}
|
||||
return fw;
|
||||
}
|
||||
@@ -289,43 +293,50 @@ TopoDS_Wire EdgeWalker::makeCleanWire(std::vector<TopoDS_Edge> edges, double tol
|
||||
|
||||
Handle(ShapeFix_Wire) fixer = new ShapeFix_Wire;
|
||||
fixer->Load(wireData);
|
||||
fixer->Perform();
|
||||
fixer->FixReorder();
|
||||
fixer->SetPrecision(2.0 * EWTOLERANCE);
|
||||
fixer->SetMaxTolerance(tol);
|
||||
fixer->ClosedWireMode() = Standard_True;
|
||||
fixer->FixConnected(Precision::Confusion());
|
||||
fixer->FixClosed(Precision::Confusion());
|
||||
fixer->ModifyGeometryMode() = Standard_True;
|
||||
fixer->ModifyTopologyMode() = Standard_False;
|
||||
fixer->FixSelfIntersectingEdgeMode() = Standard_True;
|
||||
fixer->FixIntersectingEdgesMode() = Standard_True;
|
||||
fixer->FixIntersectingEdgesMode() = Standard_True;
|
||||
fixer->FixConnectedMode() = Standard_True;
|
||||
fixer->FixReorderMode() = Standard_True;
|
||||
fixer->Perform();
|
||||
|
||||
for (int i = 1; i <= wireData->NbEdges(); i ++) {
|
||||
TopoDS_Edge edge = fixer->WireData()->Edge(i);
|
||||
sTol.SetTolerance(edge, tol, TopAbs_VERTEX);
|
||||
mkWire.Add(edge);
|
||||
}
|
||||
result = fixer->WireAPIMake();
|
||||
|
||||
result = mkWire.Wire();
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<TopoDS_Vertex> EdgeWalker:: makeUniqueVList(std::vector<TopoDS_Edge> edges)
|
||||
{
|
||||
//Base::Console().Message("TRACE - EW::makeUniqueVList()\n");
|
||||
// Base::Console().Message("TRACE - EW::makeUniqueVList() - edgesIn: %d\n", edges.size());
|
||||
std::vector<TopoDS_Vertex> uniqueVert;
|
||||
for(auto& e:edges) {
|
||||
TopoDS_Vertex v1 = TopExp::FirstVertex(e);
|
||||
TopoDS_Vertex v2 = TopExp::LastVertex(e);
|
||||
Base::Vector3d v1 = DrawUtil::vertex2Vector(TopExp::FirstVertex(e));
|
||||
Base::Vector3d v2 = DrawUtil::vertex2Vector(TopExp::LastVertex(e));
|
||||
bool addv1 = true;
|
||||
bool addv2 = true;
|
||||
for (const auto& v:uniqueVert) {
|
||||
if (DrawUtil::isSamePoint(v, v1, EWTOLERANCE))
|
||||
//check if we've already added this vertex
|
||||
for (const auto& v: uniqueVert) {
|
||||
Base::Vector3d v3d = DrawUtil::vertex2Vector(v);
|
||||
if (v3d.IsEqual(v1, EWTOLERANCE)) {
|
||||
addv1 = false;
|
||||
if (DrawUtil::isSamePoint(v, v2, EWTOLERANCE))
|
||||
}
|
||||
if (v3d.IsEqual(v2, EWTOLERANCE)) {
|
||||
addv2 = false;
|
||||
}
|
||||
}
|
||||
if (addv1) {
|
||||
uniqueVert.push_back(TopExp::FirstVertex(e));
|
||||
}
|
||||
if (addv2) {
|
||||
uniqueVert.push_back(TopExp::LastVertex(e));
|
||||
}
|
||||
if (addv1)
|
||||
uniqueVert.push_back(v1);
|
||||
if (addv2)
|
||||
uniqueVert.push_back(v2);
|
||||
}
|
||||
// Base::Console().Message("EW::makeUniqueVList - verts out: %d\n", uniqueVert.size());
|
||||
return uniqueVert;
|
||||
}
|
||||
|
||||
@@ -333,17 +344,24 @@ std::vector<TopoDS_Vertex> EdgeWalker:: makeUniqueVList(std::vector<TopoDS_Edge>
|
||||
std::vector<WalkerEdge> EdgeWalker::makeWalkerEdges(std::vector<TopoDS_Edge> edges,
|
||||
std::vector<TopoDS_Vertex> verts)
|
||||
{
|
||||
// Base::Console().Message("TRACE - EW::makeWalkerEdges()\n");
|
||||
// Base::Console().Message("TRACE - EW::makeWalkerEdges() - edges: %d verts: %d\n", edges.size(), verts.size());
|
||||
m_saveInEdges = edges;
|
||||
std::vector<WalkerEdge> walkerEdges;
|
||||
for (const auto& e:edges) {
|
||||
TopoDS_Vertex ev1 = TopExp::FirstVertex(e);
|
||||
TopoDS_Vertex ev2 = TopExp::LastVertex(e);
|
||||
int v1dx = findUniqueVert(ev1, verts);
|
||||
int v2dx = findUniqueVert(ev2, verts);
|
||||
TopoDS_Vertex edgeVertex1 = TopExp::FirstVertex(e);
|
||||
TopoDS_Vertex edgeVertex2 = TopExp::LastVertex(e);
|
||||
std::size_t vertex1Index = findUniqueVert(edgeVertex1, verts);
|
||||
if (vertex1Index == SIZE_MAX) {
|
||||
continue;
|
||||
}
|
||||
std::size_t vertex2Index = findUniqueVert(edgeVertex2, verts);
|
||||
if (vertex2Index == SIZE_MAX) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WalkerEdge we;
|
||||
we.v1 = v1dx;
|
||||
we.v2 = v2dx;
|
||||
we.v1 = vertex1Index;
|
||||
we.v2 = vertex2Index;
|
||||
we.idx = 0;
|
||||
walkerEdges.push_back(we);
|
||||
}
|
||||
@@ -352,18 +370,20 @@ std::vector<WalkerEdge> EdgeWalker::makeWalkerEdges(std::vector<TopoDS_Edge> edg
|
||||
return walkerEdges;
|
||||
}
|
||||
|
||||
int EdgeWalker::findUniqueVert(TopoDS_Vertex vx, std::vector<TopoDS_Vertex> &uniqueVert)
|
||||
size_t EdgeWalker::findUniqueVert(TopoDS_Vertex vx, std::vector<TopoDS_Vertex> &uniqueVert)
|
||||
{
|
||||
// Base::Console().Message("TRACE - EW::findUniqueVert()\n");
|
||||
int idx = 0;
|
||||
int result = 0;
|
||||
for(auto& v:uniqueVert) { //we're always going to find vx, right?
|
||||
if (DrawUtil::isSamePoint(v, vx, EWTOLERANCE)) {
|
||||
std::size_t idx = 0;
|
||||
std::size_t result = SIZE_MAX;
|
||||
Base::Vector3d vx3d = DrawUtil::vertex2Vector(vx);
|
||||
for(auto& v : uniqueVert) {
|
||||
Base::Vector3d v3d = DrawUtil::vertex2Vector(v);
|
||||
if (vx3d.IsEqual(v3d, EWTOLERANCE)) {
|
||||
result = idx;
|
||||
break;
|
||||
}
|
||||
idx++;
|
||||
} //if idx >= uniqueVert.size() TARFU
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -377,8 +397,8 @@ std::vector<TopoDS_Wire> EdgeWalker::sortStrip(std::vector<TopoDS_Wire> fw, bool
|
||||
}
|
||||
std::vector<TopoDS_Wire> sortedWires = sortWiresBySize(closedWires, false); //biggest 1st
|
||||
if (sortedWires.empty()) {
|
||||
Base::Console().Log("INFO - EW::sortStrip - no sorted Wires!\n");
|
||||
return sortedWires; // might happen in the middle of changes?
|
||||
Base::Console().Message("EW::sortStrip - no sorted Wires!\n");
|
||||
return sortedWires;
|
||||
}
|
||||
|
||||
if (!includeBiggest) {
|
||||
@@ -415,30 +435,34 @@ std::vector<embedItem> EdgeWalker::makeEmbedding(const std::vector<TopoDS_Edge>
|
||||
// edges.size(), uniqueVList.size());
|
||||
std::vector<embedItem> result;
|
||||
|
||||
int iv = 0;
|
||||
std::size_t iVert = 0;
|
||||
//make an embedItem for each vertex in uniqueVList
|
||||
//for each vertex v
|
||||
// find all the edges that have v as first or last vertex
|
||||
for (auto& v: uniqueVList) {
|
||||
int ie = 0;
|
||||
TopoDS_Vertex cv = v; //v is const but we need non-const for vertexEqual
|
||||
std::size_t iEdge = 0;
|
||||
std::vector<incidenceItem> iiList;
|
||||
for (auto& e: edges) {
|
||||
double angle = 0;
|
||||
if (DrawUtil::isFirstVert(e, v,EWTOLERANCE)) {
|
||||
angle = DrawUtil::angleWithX(e, v,EWTOLERANCE);
|
||||
incidenceItem ii(ie, angle, m_saveWalkerEdges[ie].ed);
|
||||
TopoDS_Vertex edgeVertex1 = TopExp::FirstVertex(e);
|
||||
TopoDS_Vertex edgeVertex2 = TopExp::LastVertex(e);
|
||||
if (DrawUtil::vertexEqual(cv, edgeVertex1)) {
|
||||
angle = DrawUtil::incidenceAngleAtVertex(e,v,EWTOLERANCE);
|
||||
incidenceItem ii(iEdge, angle, m_saveWalkerEdges[iEdge].ed);
|
||||
iiList.push_back(ii);
|
||||
} else if (DrawUtil::isLastVert(e, v,EWTOLERANCE)) {
|
||||
angle = DrawUtil::angleWithX(e, v,EWTOLERANCE);
|
||||
incidenceItem ii(ie, angle, m_saveWalkerEdges[ie].ed);
|
||||
} else if (DrawUtil::vertexEqual(cv, edgeVertex2)) {
|
||||
angle = DrawUtil::incidenceAngleAtVertex(e,v,EWTOLERANCE);
|
||||
incidenceItem ii(iEdge, angle, m_saveWalkerEdges[iEdge].ed);
|
||||
iiList.push_back(ii);
|
||||
} else {
|
||||
//Base::Console().Message("TRACE - EW::makeEmbedding - neither first nor last\n");
|
||||
}
|
||||
ie++;
|
||||
iEdge++;
|
||||
}
|
||||
//sort incidenceList by angle
|
||||
iiList = embedItem::sortIncidenceList(iiList, false);
|
||||
embedItem embed(iv, iiList);
|
||||
embedItem embed(iVert, iiList);
|
||||
result.push_back(embed);
|
||||
iv++;
|
||||
iVert++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -523,7 +547,7 @@ void ewWire::push_back(WalkerEdge w)
|
||||
wedges.push_back(w);
|
||||
}
|
||||
|
||||
int ewWire::size()
|
||||
std::size_t ewWire::size(void)
|
||||
{
|
||||
return wedges.size();
|
||||
}
|
||||
@@ -560,7 +584,7 @@ void ewWireList::push_back(ewWire w)
|
||||
wires.push_back(w);
|
||||
}
|
||||
|
||||
int ewWireList::size()
|
||||
std::size_t ewWireList::size(void)
|
||||
{
|
||||
return wires.size();
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include <Mod/TechDraw/TechDrawGlobal.h>
|
||||
|
||||
#include <vector>
|
||||
#include <boost_graph_adjacency_list.hpp>
|
||||
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
#include <boost/graph/planar_face_traversal.hpp>
|
||||
#include <boost/property_map/property_map.hpp>
|
||||
@@ -49,7 +51,7 @@ using graph =
|
||||
boost::adjacency_list
|
||||
< boost::vecS,
|
||||
boost::vecS,
|
||||
boost::undirectedS,
|
||||
boost::bidirectionalS,
|
||||
boost::property<boost::vertex_index_t, int>,
|
||||
boost::property<boost::edge_index_t, int>
|
||||
>;
|
||||
@@ -78,7 +80,7 @@ public:
|
||||
std::size_t v1;
|
||||
std::size_t v2;
|
||||
edge_t ed;
|
||||
int idx;
|
||||
std::size_t idx;
|
||||
};
|
||||
|
||||
class TechDrawExport ewWire
|
||||
@@ -89,7 +91,7 @@ public:
|
||||
std::vector<WalkerEdge> wedges; //[WE] representing 1 wire
|
||||
void push_back(WalkerEdge w);
|
||||
void clear() {wedges.clear();}
|
||||
int size();
|
||||
std::size_t size(void);
|
||||
};
|
||||
|
||||
class TechDrawExport ewWireList
|
||||
@@ -99,7 +101,7 @@ public:
|
||||
|
||||
std::vector<ewWire> wires;
|
||||
void push_back(ewWire e);
|
||||
int size();
|
||||
std::size_t size(void);
|
||||
};
|
||||
|
||||
|
||||
@@ -124,11 +126,11 @@ class TechDrawExport incidenceItem
|
||||
{
|
||||
public:
|
||||
incidenceItem() {iEdge = 0; angle = 0.0;}
|
||||
incidenceItem(int idx, double a, edge_t ed) {iEdge = idx; angle = a; eDesc = ed;}
|
||||
incidenceItem(std::size_t idx, double a, edge_t ed) {iEdge = idx; angle = a; eDesc = ed;}
|
||||
~incidenceItem() = default;
|
||||
static bool iiCompare(const incidenceItem& i1, const incidenceItem& i2);
|
||||
static bool iiEqual(const incidenceItem& i1, const incidenceItem& i2);
|
||||
int iEdge;
|
||||
std::size_t iEdge;
|
||||
double angle;
|
||||
edge_t eDesc;
|
||||
};
|
||||
@@ -137,11 +139,11 @@ class TechDrawExport embedItem
|
||||
{
|
||||
public:
|
||||
embedItem();
|
||||
embedItem(int i,
|
||||
embedItem(std::size_t i,
|
||||
std::vector<incidenceItem> list) { iVertex = i; incidenceList = list;}
|
||||
~embedItem() = default;
|
||||
|
||||
int iVertex;
|
||||
std::size_t iVertex;
|
||||
std::vector<incidenceItem> incidenceList;
|
||||
std::string dump();
|
||||
static std::vector<incidenceItem> sortIncidenceList (std::vector<incidenceItem> &list, bool ascend);
|
||||
@@ -156,8 +158,9 @@ public:
|
||||
|
||||
bool loadEdges(std::vector<TechDraw::WalkerEdge>& edges);
|
||||
bool loadEdges(std::vector<TopoDS_Edge> edges);
|
||||
bool setSize(int size);
|
||||
bool perform();
|
||||
bool setSize(std::size_t size);
|
||||
std::vector<TopoDS_Wire> execute(std::vector<TopoDS_Edge> edgeList, bool biggie = true);
|
||||
|
||||
ewWireList getResult();
|
||||
std::vector<TopoDS_Wire> getResultWires();
|
||||
std::vector<TopoDS_Wire> getResultNoDups();
|
||||
@@ -166,7 +169,7 @@ public:
|
||||
std::vector<WalkerEdge> makeWalkerEdges(std::vector<TopoDS_Edge> edges,
|
||||
std::vector<TopoDS_Vertex> verts);
|
||||
|
||||
int findUniqueVert(TopoDS_Vertex vx, std::vector<TopoDS_Vertex> &uniqueVert);
|
||||
size_t findUniqueVert(TopoDS_Vertex vx, std::vector<TopoDS_Vertex> &uniqueVert);
|
||||
std::vector<TopoDS_Wire> sortStrip(std::vector<TopoDS_Wire> fw, bool includeBiggest);
|
||||
std::vector<TopoDS_Wire> sortWiresBySize(std::vector<TopoDS_Wire>& w, bool reverse = false);
|
||||
static TopoDS_Wire makeCleanWire(std::vector<TopoDS_Edge> edges, double tol = 0.10);
|
||||
@@ -177,6 +180,7 @@ public:
|
||||
const std::vector<TopoDS_Vertex> uniqueVList);
|
||||
|
||||
protected:
|
||||
bool prepare();
|
||||
static bool wireCompare(const TopoDS_Wire& w1, const TopoDS_Wire& w2);
|
||||
std::vector<TechDraw::WalkerEdge> m_saveWalkerEdges;
|
||||
std::vector<TopoDS_Edge> m_saveInEdges;
|
||||
|
||||
Reference in New Issue
Block a user