diff --git a/src/Mod/TechDraw/App/AppTechDraw.cpp b/src/Mod/TechDraw/App/AppTechDraw.cpp index 30af66945..90512398d 100644 --- a/src/Mod/TechDraw/App/AppTechDraw.cpp +++ b/src/Mod/TechDraw/App/AppTechDraw.cpp @@ -34,15 +34,12 @@ #include "DrawViewDraft.h" #include "DrawViewSpreadsheet.h" -extern struct PyMethodDef TechDraw_methods[]; - -PyDoc_STRVAR(module_techdraw_doc, -"This module is the TechDraw module."); - +namespace TechDraw { +extern PyObject* initModule(); +} /* Python entry */ -extern "C" { -void TechDrawExport initTechDraw() +PyMODINIT_FUNC initTechDraw() { // load dependent module try { @@ -53,7 +50,7 @@ void TechDrawExport initTechDraw() PyErr_SetString(PyExc_ImportError, e.what()); return; } - Py_InitModule3("TechDraw", TechDraw_methods, module_techdraw_doc); /* mod name, table ptr */ + (void)TechDraw::initModule(); Base::Console().Log("Loading TechDraw module... done\n"); @@ -87,5 +84,3 @@ void TechDrawExport initTechDraw() TechDraw::DrawTemplatePython ::init(); TechDraw::DrawViewSymbolPython::init(); } - -} // extern "C" diff --git a/src/Mod/TechDraw/App/AppTechDrawPy.cpp b/src/Mod/TechDraw/App/AppTechDrawPy.cpp index 928310f1f..60339f63e 100644 --- a/src/Mod/TechDraw/App/AppTechDrawPy.cpp +++ b/src/Mod/TechDraw/App/AppTechDrawPy.cpp @@ -1,6 +1,7 @@ /*************************************************************************** * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2002 * - * * + * Copyright (c) WandererFan (wandererfan@gmail.com) 2016 * +* * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * @@ -24,41 +25,178 @@ #include "PreCompiled.h" #ifndef _PreComp_ # include +# include +# include +# include +# include #endif -#include +#include +#include + #include -#include -#include +#include +#include +#include + +#include +#include +#include +#include #include -//using namespace TechDraw; -using namespace Part; -using namespace std; - -static PyObject * -tdPlaceholder(PyObject *self, PyObject *args) -{ - PyObject *pcObjShape; - PyObject *pcObjDir=0; - - if (!PyArg_ParseTuple(args, "O!|O!", &(TopoShapePy::Type), &pcObjShape,&(Base::VectorPy::Type), &pcObjDir)) // convert args: Python->C - return NULL; // NULL triggers exception - - PY_TRY { - TopoShapePy* pShape = static_cast(pcObjShape); - Py::List list; - list.append(Py::Object(pShape , true)); - return Py::new_reference_to(list); - - } PY_CATCH_OCC; +#include "EdgeWalker.h" +namespace TechDraw { +//module level static C++ functions go here } -/* registration table */ -struct PyMethodDef TechDraw_methods[] = { - {"tdPlaceholder" ,tdPlaceholder ,METH_VARARGS, - "[n/a] = tdPlaceholder(n/a) -- Temporary hack."}, - {NULL, NULL} /* end of table marker */ -}; +using Part::TopoShape; +using Part::TopoShapePy; +using Part::TopoShapeEdgePy; +using Part::TopoShapeWirePy; + +namespace TechDraw { + +class Module : public Py::ExtensionModule +{ +public: + Module() : Py::ExtensionModule("TechDraw") + { + add_varargs_method("edgeWalker",&Module::edgeWalker, + "[wires] = edgeWalker(edgePile,inclBiggest) -- Planar graph traversal finds wires in edge pile." + ); + add_varargs_method("findOuterWire",&Module::findOuterWire, + "wire = findOuterWire(edgeList) -- Planar graph traversal finds OuterWire in edge pile." + ); + initialize("This is a module for making drawings"); // register with Python + } + virtual ~Module() {} + +private: + virtual Py::Object invoke_method_varargs(void *method_def, const Py::Tuple &args) + { + try { + return Py::ExtensionModule::invoke_method_varargs(method_def, args); + } + catch (const Standard_Failure &e) { + std::string str; + Standard_CString msg = e.GetMessageString(); + str += typeid(e).name(); + str += " "; + if (msg) {str += msg;} + else {str += "No OCCT Exception Message";} + Base::Console().Error("%s\n", str.c_str()); + throw Py::Exception(Part::PartExceptionOCCError, str); + } + catch (const Base::Exception &e) { + std::string str; + str += "FreeCAD exception thrown ("; + str += e.what(); + str += ")"; + e.ReportException(); + throw Py::RuntimeError(str); + } + catch (const std::exception &e) { + std::string str; + str += "C++ exception thrown ("; + str += e.what(); + str += ")"; + Base::Console().Error("%s\n", str.c_str()); + throw Py::RuntimeError(str); + } + } + + Py::Object edgeWalker(const Py::Tuple& args) + { + PyObject *pcObj; + PyObject *inclBig = Py_True; + if (!PyArg_ParseTuple(args.ptr(), "O|O", &pcObj,&inclBig)) { + throw Py::Exception(); + } + + std::vector edgeList; + + try { + Py::Sequence list(pcObj); + for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { + if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapeEdgePy::Type))) { + const TopoDS_Shape& sh = static_cast((*it).ptr())-> + getTopoShapePtr()->getShape(); + const TopoDS_Edge e = TopoDS::Edge(sh); + edgeList.push_back(e); + } + } + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + throw Py::Exception(Part::PartExceptionOCCError, e->GetMessageString()); + } + + bool biggie; + if (inclBig == Py_True) { + biggie = true; + } else { + biggie = false; + } + PyObject* result = PyList_New(0); + + EdgeWalker ew; + ew.loadEdges(edgeList); + ew.perform(); + std::vector rw = ew.getResultWires(); + std::vector sortedWires = ew.sortStrip(rw,biggie); //false==>do not include biggest wires + for (auto& w:sortedWires) { + PyList_Append(result,new TopoShapeWirePy(new TopoShape(w))); + } + + return Py::asObject(result); + } + + Py::Object findOuterWire(const Py::Tuple& args) + { + PyObject *pcObj; + if (!PyArg_ParseTuple(args.ptr(), "O", &pcObj)) { + throw Py::Exception(); + } + + std::vector edgeList; + + try { + Py::Sequence list(pcObj); + for (Py::Sequence::iterator it = list.begin(); it != list.end(); ++it) { + if (PyObject_TypeCheck((*it).ptr(), &(Part::TopoShapeEdgePy::Type))) { + const TopoDS_Shape& sh = static_cast((*it).ptr())-> + getTopoShapePtr()->getShape(); + const TopoDS_Edge e = TopoDS::Edge(sh); + edgeList.push_back(e); + } + } + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + throw Py::Exception(Part::PartExceptionOCCError, e->GetMessageString()); + } + + PyObject* result = PyList_New(0); + + EdgeWalker ew; + ew.loadEdges(edgeList); + ew.perform(); + std::vector rw = ew.getResultWires(); + std::vector sortedWires = ew.sortStrip(rw,true); + for (auto& w:sortedWires) { + PyList_Append(result,new TopoShapeWirePy(new TopoShape(w))); + } + PyObject* outerWire = PyList_GetItem(result, 0); + return Py::asObject(outerWire); + } + }; + +PyObject* initModule() +{ + return (new Module)->module().ptr(); +} + +} // namespace TechDraw diff --git a/src/Mod/TechDraw/App/DrawUtil.cpp b/src/Mod/TechDraw/App/DrawUtil.cpp index cd908852f..891840416 100644 --- a/src/Mod/TechDraw/App/DrawUtil.cpp +++ b/src/Mod/TechDraw/App/DrawUtil.cpp @@ -32,6 +32,11 @@ # include # include # include + +//#include +#include +#include +#include #endif #include @@ -93,3 +98,14 @@ std::string DrawUtil::makeGeomName(std::string geomType, int index) return newName.str(); } + +bool DrawUtil::isSamePoint(TopoDS_Vertex v1, TopoDS_Vertex v2) +{ + bool result = false; + gp_Pnt p1 = BRep_Tool::Pnt(v1); + gp_Pnt p2 = BRep_Tool::Pnt(v2); + if (p1.IsEqual(p2,Precision::Confusion())) { + result = true; + } + return result; +} diff --git a/src/Mod/TechDraw/App/DrawUtil.h b/src/Mod/TechDraw/App/DrawUtil.h index c2ef489ec..ad930d91b 100644 --- a/src/Mod/TechDraw/App/DrawUtil.h +++ b/src/Mod/TechDraw/App/DrawUtil.h @@ -24,6 +24,7 @@ #define _DrawUtil_h_ #include +#include namespace TechDraw { @@ -34,6 +35,7 @@ class TechDrawExport DrawUtil { static int getIndexFromName(std::string geomName); static std::string getGeomTypeFromName(std::string geomName); static std::string makeGeomName(std::string geomType, int index); + static bool isSamePoint(TopoDS_Vertex v1, TopoDS_Vertex v2); }; } //end namespace TechDraw diff --git a/src/Mod/TechDraw/App/DrawViewPart.cpp b/src/Mod/TechDraw/App/DrawViewPart.cpp index 1965dccd1..3e44c1d31 100644 --- a/src/Mod/TechDraw/App/DrawViewPart.cpp +++ b/src/Mod/TechDraw/App/DrawViewPart.cpp @@ -1,867 +1,677 @@ -/*************************************************************************** - * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2002 * - * Copyright (c) Luke Parry (l.parry@warwick.ac.uk) 2013 * - * * - * 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 * - * * - ***************************************************************************/ - - -#include "PreCompiled.h" - -#ifndef _PreComp_ -# include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif - -#include - -#include -#include -#include -#include -#include - -#include "DrawViewSection.h" -#include "Geometry.h" -#include "GeometryObject.h" -#include "DrawViewPart.h" -#include "DrawHatch.h" -#include "EdgeWalker.h" - - -#include // generated from DrawViewPartPy.xml - -using namespace TechDraw; -using namespace std; - - -//=========================================================================== -// DrawViewPart -//=========================================================================== - -App::PropertyFloatConstraint::Constraints DrawViewPart::floatRange = {0.01f,5.0f,0.05f}; - -PROPERTY_SOURCE(TechDraw::DrawViewPart, TechDraw::DrawView) - -DrawViewPart::DrawViewPart(void) : geometryObject(0) -{ - static const char *group = "Projection"; - static const char *fgroup = "Format"; - static const char *lgroup = "SectionLine"; - - ADD_PROPERTY_TYPE(Direction ,(0,0,1.0) ,group,App::Prop_None,"Projection normal direction"); - ADD_PROPERTY_TYPE(Source ,(0),group,App::Prop_None,"3D Shape to view"); - ADD_PROPERTY_TYPE(ShowHiddenLines ,(false),group,App::Prop_None,"Hidden lines on/off"); - ADD_PROPERTY_TYPE(ShowSmoothLines ,(false),group,App::Prop_None,"Smooth lines on/off"); - ADD_PROPERTY_TYPE(ShowSeamLines ,(false),group,App::Prop_None,"Seam lines on/off"); - //ADD_PROPERTY_TYPE(ShowIsoLines ,(false),group,App::Prop_None,"Iso u,v lines on/off"); - ADD_PROPERTY_TYPE(Tolerance,(0.05f),group,App::Prop_None,"Internal tolerance"); - Tolerance.setConstraints(&floatRange); - ADD_PROPERTY_TYPE(XAxisDirection ,(1,0,0) ,group,App::Prop_None,"Where to place projection XAxis in display"); - - ADD_PROPERTY_TYPE(LineWidth,(0.7f),fgroup,App::Prop_None,"The thickness of visible lines"); - ADD_PROPERTY_TYPE(HiddenWidth,(0.15),fgroup,App::Prop_None,"The thickness of hidden lines, if enabled"); - ADD_PROPERTY_TYPE(ShowCenters ,(true),fgroup,App::Prop_None,"Center marks on/off"); - ADD_PROPERTY_TYPE(CenterScale,(2.0),fgroup,App::Prop_None,"Center mark size adjustment, if enabled"); - ADD_PROPERTY_TYPE(HorizCenterLine ,(false),fgroup,App::Prop_None,"Show a horizontal centerline through view"); - ADD_PROPERTY_TYPE(VertCenterLine ,(false),fgroup,App::Prop_None,"Show a vertical centerline through view"); - - ADD_PROPERTY_TYPE(ShowSectionLine ,(true) ,lgroup,App::Prop_None,"Show/hide section line if applicable"); - ADD_PROPERTY_TYPE(HorizSectionLine ,(true) ,lgroup,App::Prop_None,"Section line is horizontal"); - ADD_PROPERTY_TYPE(ArrowUpSection ,(true) ,lgroup,App::Prop_None,"Section line arrows point up"); - ADD_PROPERTY_TYPE(SymbolSection,("A") ,lgroup,App::Prop_None,"Section identifier"); - - - geometryObject = new TechDrawGeometry::GeometryObject(); -} - -DrawViewPart::~DrawViewPart() -{ - delete geometryObject; -} - - -App::DocumentObjectExecReturn *DrawViewPart::execute(void) -{ - App::DocumentObject *link = Source.getValue(); - if (!link) { - return new App::DocumentObjectExecReturn("FVP - No Source object linked"); - } - - if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - return new App::DocumentObjectExecReturn("FVP - Linked object is not a Part object"); - } - - TopoDS_Shape shape = static_cast(link)->Shape.getShape().getShape(); - if (shape.IsNull()) { - return new App::DocumentObjectExecReturn("FVP - Linked shape object is empty"); - } - - geometryObject->setTolerance(Tolerance.getValue()); - double s = Scale.getValue(); - if (!s) { //might be problem, might be mid property change - Base::Console().Log("INFO - DVP::execute - Scale: %.3f\n",s); - return DrawView::execute(); - } - - geometryObject->setScale(Scale.getValue()); - try { - gp_Pnt inputCenter = TechDrawGeometry::findCentroid(shape, - Direction.getValue(), - getValidXDir()); - shapeCentroid = Base::Vector3d(inputCenter.X(),inputCenter.Y(),inputCenter.Z()); - TopoDS_Shape mirroredShape = TechDrawGeometry::mirrorShape(shape, - inputCenter, - Scale.getValue()); - buildGeometryObject(mirroredShape,inputCenter); -#if MOD_TECHDRAW_HANDLE_FACES - extractFaces(); -#endif //#if MOD_TECHDRAW_HANDLE_FACES - - } - catch (Standard_Failure) { - Handle_Standard_Failure e = Standard_Failure::Caught(); - return new App::DocumentObjectExecReturn(e->GetMessageString()); - } - - // There is a guaranteed change so check any references linked to this and touch - // We need to update all views pointing at this (ProjectionGroup, ClipGroup, etc) - std::vector parent = getInList(); - for (std::vector::iterator it = parent.begin(); it != parent.end(); ++it) { - if ((*it)->getTypeId().isDerivedFrom(DrawView::getClassTypeId())) { - TechDraw::DrawView *view = static_cast(*it); - view->touch(); - } - } - return DrawView::execute(); -} - -short DrawViewPart::mustExecute() const -{ - short result = (Direction.isTouched() || - XAxisDirection.isTouched() || - Source.isTouched() || - Scale.isTouched() || - ScaleType.isTouched() || - ShowHiddenLines.isTouched() || - ShowSmoothLines.isTouched() || - ShowSeamLines.isTouched() || - LineWidth.isTouched() || - Tolerance.isTouched() || - HiddenWidth.isTouched()); - return result; -} - -void DrawViewPart::onChanged(const App::Property* prop) -{ - if (!isRestoring()) { - if (prop == &SymbolSection && getSectionRef()) { - getSectionRef()->touch(); - } - if (prop == &Direction || - prop == &XAxisDirection || - prop == &Source || - prop == &Scale || - prop == &ScaleType || - prop == &ShowHiddenLines || - prop == &ShowSmoothLines || - prop == &ShowSeamLines || - prop == &LineWidth || - prop == &HiddenWidth || - prop == &ShowCenters || - prop == &CenterScale || - prop == &ShowSectionLine || - prop == &HorizSectionLine || - prop == &ArrowUpSection || - prop == &SymbolSection || - prop == &HorizCenterLine || - prop == &VertCenterLine) { - try { - App::DocumentObjectExecReturn *ret = recompute(); - delete ret; - } - catch (...) { - } - } - } - DrawView::onChanged(prop); - -//TODO: when scale changes, any Dimensions for this View sb recalculated. (might happen anyway if document is recomputed?) -} - -void DrawViewPart::buildGeometryObject(TopoDS_Shape shape, gp_Pnt& inputCenter) -{ - Base::Vector3d baseProjDir = Direction.getValue(); - - saveParamSpace(baseProjDir, - getValidXDir()); - - geometryObject->projectShape(shape, - inputCenter, - Direction.getValue(), - getValidXDir()); - geometryObject->extractGeometry(TechDrawGeometry::ecHARD, - true); - geometryObject->extractGeometry(TechDrawGeometry::ecOUTLINE, - true); - if (ShowSmoothLines.getValue()) { - geometryObject->extractGeometry(TechDrawGeometry::ecSMOOTH, - true); - } - if (ShowSeamLines.getValue()) { - geometryObject->extractGeometry(TechDrawGeometry::ecSEAM, - true); - } - //if (ShowIsoLines.getValue()) { - // geometryObject->extractGeometry(TechDrawGeometry::ecUVISO, - // true); - //} - if (ShowHiddenLines.getValue()) { - geometryObject->extractGeometry(TechDrawGeometry::ecHARD, - false); - //geometryObject->extractGeometry(TechDrawGeometry::ecOUTLINE, //hidden outline,smooth,seam?? - // true); - } - bbox = geometryObject->calcBoundingBox(); -} - -//! make faces from the existing edge geometry -void DrawViewPart::extractFaces() -{ - geometryObject->clearFaceGeom(); - const std::vector& goEdges = geometryObject->getEdgeGeometry(); - std::vector::const_iterator itEdge = goEdges.begin(); - std::vector origEdges; - for (;itEdge != goEdges.end(); itEdge++) { - if ((*itEdge)->visible) { //don't make invisible faces! - origEdges.push_back((*itEdge)->occEdge); - } - } - - std::vector faceEdges = origEdges; - std::vector::iterator itOrig = origEdges.begin(); - - //HLR algo does not provide all edge intersections for edge endpoints. - //need to split long edges touched by Vertex of another edge - int idb = 0; - for (; itOrig != origEdges.end(); itOrig++, idb++) { - TopoDS_Vertex v1 = TopExp::FirstVertex((*itOrig)); - TopoDS_Vertex v2 = TopExp::LastVertex((*itOrig)); - std::vector::iterator itNew = faceEdges.begin(); - std::vector deleteList; - std::vector edgesToAdd; - int idx = 0; - for (; itNew != faceEdges.end(); itNew++,idx++) { - if ( itOrig->IsSame(*itNew) ){ - continue; - } - bool removeThis = false; - std::vector splitPoints; - if (isOnEdge((*itNew),v1,false)) { - splitPoints.push_back(v1); - removeThis = true; - } - if (isOnEdge((*itNew),v2,false)) { - splitPoints.push_back(v2); - removeThis = true; - } - if (removeThis) { - deleteList.push_back(idx); - } - - if (!splitPoints.empty()) { - std::vector subEdges = splitEdge(splitPoints,(*itNew)); - edgesToAdd.insert(std::end(edgesToAdd), std::begin(subEdges), std::end(subEdges)); - } - } - //delete the split edge(s) and add the subedges - //TODO: look into sets or maps or???? for all this - std::sort(deleteList.begin(),deleteList.end()); //ascending - auto last = std::unique(deleteList.begin(), deleteList.end()); //duplicates at back - deleteList.erase(last, deleteList.end()); //remove dupls - std::vector::reverse_iterator ritDel = deleteList.rbegin(); - for ( ; ritDel != deleteList.rend(); ritDel++) { - faceEdges.erase(faceEdges.begin() + (*ritDel)); - } - faceEdges.insert(std::end(faceEdges), std::begin(edgesToAdd),std::end(edgesToAdd)); - } - - std::vector uniqueVert = makeUniqueVList(faceEdges); - std::vector walkerEdges = makeWalkerEdges(faceEdges,uniqueVert); - - EdgeWalker ew; - ew.setSize(uniqueVert.size()); - ew.loadEdges(walkerEdges); - ew.perform(); - facelist result = ew.getResult(); - - facelist::iterator iFace = result.begin(); - std::vector fw; - for (;iFace != result.end(); iFace++) { - edgelist::iterator iEdge = (*iFace).begin(); - std::vector fe; - for (;iEdge != (*iFace).end(); iEdge++) { - fe.push_back(faceEdges.at((*iEdge).idx)); - } - TopoDS_Wire w = makeCleanWire(fe); //make 1 clean wire from its edges - fw.push_back(w); - } - - std::vector sortedWires = sortWiresBySize(fw,false); - if (!sortedWires.size()) { - Base::Console().Log("INFO - DVP::extractFaces - no sorted Wires!\n"); - return; // might happen in the middle of changes? - } - - //remove the largest wire (OuterWire of graph) - Bnd_Box bigBox; - if (sortedWires.size() && !sortedWires.front().IsNull()) { - BRepBndLib::Add(sortedWires.front(), bigBox); - bigBox.SetGap(0.0); - } - std::vector toBeChecked; - std::vector::iterator it = sortedWires.begin() + 1; - for (; it != sortedWires.end(); it++) { - if (!(*it).IsNull()) { - Bnd_Box littleBox; - BRepBndLib::Add((*it), littleBox); - littleBox.SetGap(0.0); - if (bigBox.SquareExtent() > littleBox.SquareExtent()) { - break; - } else { - auto position = std::distance( sortedWires.begin(), it ); //get an index from iterator - toBeChecked.push_back(position); - } - } - } - //unfortuneately, faces can have same bbox, but not be same size. need to weed out biggest - if (toBeChecked.size() == 0) { - //nobody had as big a bbox as first element of sortedWires - sortedWires.erase(sortedWires.begin()); - } else if (toBeChecked.size() > 0) { - BRepBuilderAPI_MakeFace mkFace(sortedWires.front()); - const TopoDS_Face& face = mkFace.Face(); - GProp_GProps props; - BRepGProp::SurfaceProperties(face, props); - double bigArea = props.Mass(); - unsigned int bigIndex = 0; - for (unsigned int idx = 1; idx < toBeChecked.size(); idx++) { - BRepBuilderAPI_MakeFace mkFace2(sortedWires.at(idx)); - const TopoDS_Face& face2 = mkFace2.Face(); - BRepGProp::SurfaceProperties(face2, props); - double area = props.Mass(); - if (area > bigArea) { - bigArea = area; - bigIndex = idx; - } - } - sortedWires.erase(sortedWires.begin() + bigIndex); - } - - std::vector::iterator itWire = sortedWires.begin(); - for (; itWire != sortedWires.end(); itWire++) { - //version 1: 1 wire/face - no voids in face - TechDrawGeometry::Face* f = new TechDrawGeometry::Face(); - const TopoDS_Wire& wire = (*itWire); - TechDrawGeometry::Wire* w = new TechDrawGeometry::Wire(wire); - f->wires.push_back(w); - geometryObject->addFaceGeom(f); - } -} - -std::vector DrawViewPart:: makeUniqueVList(std::vector edges) -{ - std::vector uniqueVert; - for(auto& e:edges) { - TopoDS_Vertex v1 = TopExp::FirstVertex(e); - TopoDS_Vertex v2 = TopExp::LastVertex(e); - bool addv1 = true; - bool addv2 = true; - for (auto v:uniqueVert) { - if (isSamePoint(v,v1)) - addv1 = false; - if (isSamePoint(v,v2)) - addv2 = false; - } - if (addv1) - uniqueVert.push_back(v1); - if (addv2) - uniqueVert.push_back(v2); - } - return uniqueVert; -} - -//!make WalkerEdges (unique Vertex index pairs) from edge list -std::vector DrawViewPart::makeWalkerEdges(std::vector edges, - std::vector verts) -{ - std::vector walkerEdges; - for (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); - WalkerEdge we; - we.v1 = v1dx; - we.v2 = v2dx; - walkerEdges.push_back(we); - } - return walkerEdges; -} - -int DrawViewPart::findUniqueVert(TopoDS_Vertex vx, std::vector &uniqueVert) -{ - int idx = 0; - int result = 0; - for(auto& v:uniqueVert) { //we're always going to find vx, right? - if (isSamePoint(v,vx)) { - result = idx; - break; - } - idx++; - } //if idx >= uniqueVert.size() TARFU - return result; -} - -double DrawViewPart::simpleMinDist(TopoDS_Shape s1, TopoDS_Shape s2) -{ - Standard_Real minDist = -1; - - BRepExtrema_DistShapeShape extss(s1, s2); - if (!extss.IsDone()) { - Base::Console().Message("DVP - BRepExtrema_DistShapeShape failed"); - return -1; - } - int count = extss.NbSolution(); - if (count != 0) { - minDist = extss.Value(); - } else { - minDist = -1; - } - return minDist; -} - -bool DrawViewPart::isOnEdge(TopoDS_Edge e, TopoDS_Vertex v, bool allowEnds) -{ - bool result = false; - double dist = simpleMinDist(v,e); - if (dist < 0.0) { - Base::Console().Error("DVP::isOnEdge - simpleMinDist failed: %.3f\n",dist); - result = false; - } else if (dist < Precision::Confusion()) { - result = true; - } - if (result) { - TopoDS_Vertex v1 = TopExp::FirstVertex(e); - TopoDS_Vertex v2 = TopExp::LastVertex(e); - if (isSamePoint(v,v1) || isSamePoint(v,v2)) { - if (!allowEnds) { - result = false; - } - } - } - return result; -} - -bool DrawViewPart::isSamePoint(TopoDS_Vertex v1, TopoDS_Vertex v2) -{ - bool result = false; - gp_Pnt p1 = BRep_Tool::Pnt(v1); - gp_Pnt p2 = BRep_Tool::Pnt(v2); - if (p1.IsEqual(p2,Precision::Confusion())) { - result = true; - } - return result; -} - -std::vector DrawViewPart::splitEdge(std::vector splitPoints, TopoDS_Edge e) -{ - std::vector result; - if (splitPoints.empty()) { - return result; - } - TopoDS_Vertex vStart = TopExp::FirstVertex(e); - TopoDS_Vertex vEnd = TopExp::LastVertex(e); - - BRepAdaptor_Curve adapt(e); - Handle_Geom_Curve c = adapt.Curve().Curve(); - //simple version for 1 splitPoint - //TODO: handle case where e is split in multiple points (ie circular edge cuts line twice) - BRepBuilderAPI_MakeEdge mkBuilder1(c, vStart, splitPoints[0]); - TopoDS_Edge e1 = mkBuilder1.Edge(); - BRepBuilderAPI_MakeEdge mkBuilder2(c, splitPoints[0], vEnd); - TopoDS_Edge e2 = mkBuilder2.Edge(); - result.push_back(e1); - result.push_back(e2); - return result; -} - -std::vector DrawViewPart::getHatches() const -{ - std::vector result; - std::vector children = getInList(); - for (std::vector::iterator it = children.begin(); it != children.end(); ++it) { - if ((*it)->getTypeId().isDerivedFrom(DrawHatch::getClassTypeId())) { - TechDraw::DrawHatch* hatch = dynamic_cast(*it); - result.push_back(hatch); - } - } - return result; -} - -const std::vector & DrawViewPart::getVertexGeometry() const -{ - return geometryObject->getVertexGeometry(); -} - -const std::vector & DrawViewPart::getFaceGeometry() const -{ - return geometryObject->getFaceGeometry(); -} - -const std::vector & DrawViewPart::getEdgeGeometry() const -{ - return geometryObject->getEdgeGeometry(); -} - -//! returns existing BaseGeom of 2D Edge(idx) -TechDrawGeometry::BaseGeom* DrawViewPart::getProjEdgeByIndex(int idx) const -{ - const std::vector &geoms = getEdgeGeometry(); - if (geoms.empty()) { - Base::Console().Log("INFO - getProjEdgeByIndex(%d) - no Edge Geometry. Probably restoring?\n",idx); - return NULL; - } - return geoms[idx]; -} - -//! returns existing geometry of 2D Vertex(idx) -TechDrawGeometry::Vertex* DrawViewPart::getProjVertexByIndex(int idx) const -{ - const std::vector &geoms = getVertexGeometry(); - if (geoms.empty()) { - Base::Console().Log("INFO - getProjVertexByIndex(%d) - no Vertex Geometry. Probably restoring?\n",idx); - return NULL; - } - return geoms[idx]; -} - -//! returns existing geometry of 2D Face(idx) -//version 1 Face has 1 wire -std::vector DrawViewPart::getProjFaceByIndex(int idx) const -{ - std::vector result; - const std::vector& faces = getFaceGeometry(); - for (auto& f:faces) { - for (auto& w:f->wires) { - for (auto& g:w->geoms) { - result.push_back(g); - } - } - } - return result; -} - - -Base::BoundBox3d DrawViewPart::getBoundingBox() const -{ - return bbox; -} - -double DrawViewPart::getBoxX(void) const -{ - Base::BoundBox3d bbx = getBoundingBox(); //bbox is already scaled & centered! - return (bbx.MaxX - bbx.MinX); -} - -double DrawViewPart::getBoxY(void) const -{ - Base::BoundBox3d bbx = getBoundingBox(); - return (bbx.MaxY - bbx.MinY); -} - -QRectF DrawViewPart::getRect() const -{ - QRectF result(0.0,0.0,getBoxX(),getBoxY()); //this is from GO and is already scaled - return result; -} - -//used to project pt (ex SectionOrigin) onto paper plane -Base::Vector3d DrawViewPart::projectPoint(Base::Vector3d pt) const -{ - Base::Vector3d centeredPoint = pt - shapeCentroid; - Base::Vector3d direction = Direction.getValue(); - Base::Vector3d xAxis = getValidXDir(); - gp_Ax2 viewAxis; - viewAxis = gp_Ax2(gp_Pnt(0.0,0.0,0.0), - gp_Dir(direction.x, direction.y, direction.z), - gp_Dir(xAxis.x, xAxis.y, xAxis.z)); - HLRAlgo_Projector projector( viewAxis ); - gp_Pnt2d prjPnt; - projector.Project(gp_Pnt(centeredPoint.x,centeredPoint.y,centeredPoint.z), prjPnt); - return Base::Vector3d(prjPnt.X(),prjPnt.Y(), 0.0); -} - - - -//! make a clean wire with sorted, oriented, connected, etc edges -TopoDS_Wire DrawViewPart::makeCleanWire(std::vector edges, double tol) -{ - TopoDS_Wire result; - BRepBuilderAPI_MakeWire mkWire; - ShapeFix_ShapeTolerance sTol; - Handle(ShapeExtend_WireData) wireData = new ShapeExtend_WireData(); - - for (auto e:edges) { - wireData->Add(e); - } - - Handle(ShapeFix_Wire) fixer = new ShapeFix_Wire; - fixer->Load(wireData); - fixer->Perform(); - fixer->FixReorder(); - fixer->SetMaxTolerance(tol); - fixer->ClosedWireMode() = Standard_True; - fixer->FixConnected(Precision::Confusion()); - fixer->FixClosed(Precision::Confusion()); - - 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 = mkWire.Wire(); - return result; -} - -//! return true if w1 bbox is bigger than w2 bbox -//NOTE: this won't necessarily sort the OuterWire correctly (ex smaller wire, same bbox) -class DrawViewPart::wireCompare: public std::binary_function -{ -public: - bool operator() (const TopoDS_Wire& w1, const TopoDS_Wire& w2) - { - Bnd_Box box1, box2; - if (!w1.IsNull()) { - BRepBndLib::Add(w1, box1); - box1.SetGap(0.0); - } - - if (!w2.IsNull()) { - BRepBndLib::Add(w2, box2); - box2.SetGap(0.0); - } - - return box1.SquareExtent() > box2.SquareExtent(); - } -}; - -//sort wires in order of bbox diagonal. -std::vector DrawViewPart::sortWiresBySize(std::vector& w, bool ascend) -{ - std::vector wires = w; - std::sort(wires.begin(), wires.end(), wireCompare()); - if (ascend) { - std::reverse(wires.begin(),wires.end()); - } - return wires; -} - -bool DrawViewPart::hasGeometry(void) const -{ - bool result = false; - const std::vector &verts = getVertexGeometry(); - const std::vector &edges = getEdgeGeometry(); - if (verts.empty() && - edges.empty() ) { - result = false; - } else { - result = true; - } - return result; -} - -Base::Vector3d DrawViewPart::getValidXDir() const -{ - Base::Vector3d X(1.0,0.0,0.0); - Base::Vector3d Y(0.0,1.0,0.0); - Base::Vector3d xDir = XAxisDirection.getValue(); - if (xDir.Length() < Precision::Confusion()) { - Base::Console().Warning("XAxisDirection has zero length - using (1,0,0)\n"); - xDir = X; - } - Base::Vector3d viewDir = Direction.getValue(); - if ((xDir - viewDir).Length() < Precision::Confusion()) { - if (xDir == X) { - xDir = Y; - }else{ - xDir = X; - } - Base::Console().Warning("XAxisDirection cannot equal Direction - using (%.3f,%.3f%.3f)\n", - xDir.x,xDir.y,xDir.z); - } - return xDir; -} - -void DrawViewPart::saveParamSpace(Base::Vector3d direction, - Base::Vector3d xAxis) -{ - gp_Ax2 viewAxis; - viewAxis = gp_Ax2(gp_Pnt(0, 0, 0), - gp_Dir(direction.x, -direction.y, direction.z), - gp_Dir(xAxis.x, -xAxis.y, xAxis.z)); // Y invert warning! // - - uDir = Base::Vector3d(xAxis.x, -xAxis.y, xAxis.z); - gp_Dir ydir = viewAxis.YDirection(); - vDir = Base::Vector3d(ydir.X(),ydir.Y(),ydir.Z()); - wDir = Base::Vector3d(direction.x, -direction.y, direction.z); -} - - -DrawViewSection* DrawViewPart::getSectionRef(void) const -{ - DrawViewSection* result = nullptr; - std::vector inObjs = getInList(); - for (auto& o:inObjs) { - if (o->getTypeId().isDerivedFrom(DrawViewSection::getClassTypeId())) { - result = static_cast(o); - } - } - return result; -} - -void DrawViewPart::dumpVertexes(const char* text, const TopoDS_Shape& s) -{ - Base::Console().Message("DUMP - %s\n",text); - TopExp_Explorer expl(s, TopAbs_VERTEX); - int i; - for (i = 1 ; expl.More(); expl.Next(),i++) { - const TopoDS_Vertex& v = TopoDS::Vertex(expl.Current()); - gp_Pnt pnt = BRep_Tool::Pnt(v); - Base::Console().Message("v%d: (%.3f,%.3f,%.3f)\n",i,pnt.X(),pnt.Y(),pnt.Z()); - } -} - -void DrawViewPart::countFaces(const char* text, const TopoDS_Shape& s) -{ - TopExp_Explorer expl(s, TopAbs_FACE); - int i; - for (i = 0 ; expl.More(); expl.Next(),i++) { - } - Base::Console().Message("COUNT - %s has %d Faces\n",text,i); -} - -void DrawViewPart::countWires(const char* text, const TopoDS_Shape& s) -{ - TopExp_Explorer expl(s, TopAbs_WIRE); - int i = 0; - for (; expl.More(); expl.Next()) { - i++; - } - Base::Console().Message("COUNT - %s has %d wires\n",text,i); -} - -void DrawViewPart::countEdges(const char* text, const TopoDS_Shape& s) -{ - TopExp_Explorer expl(s, TopAbs_EDGE); - int i = 0; - for (; expl.More(); expl.Next()) { - i++; - } - Base::Console().Message("COUNT - %s has %d edges\n",text,i); -} - -void DrawViewPart::dump1Vertex(const char* text, const TopoDS_Vertex& v) -{ - Base::Console().Message("DUMP - DVP::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()); -} - -PyObject *DrawViewPart::getPyObject(void) -{ - if (PythonObject.is(Py::_None())) { - // ref counter is set to 1 - PythonObject = Py::Object(new DrawViewPartPy(this),true); - } - return Py::new_reference_to(PythonObject); -} - -void DrawViewPart::dumpEdge(char* label, int i, TopoDS_Edge e) -{ - BRepAdaptor_Curve adapt(e); - double start = BRepLProp_CurveTool::FirstParameter(adapt); - double end = BRepLProp_CurveTool::LastParameter(adapt); - BRepLProp_CLProps propStart(adapt,start,0,Precision::Confusion()); - const gp_Pnt& vStart = propStart.Value(); - BRepLProp_CLProps propEnd(adapt,end,0,Precision::Confusion()); - const gp_Pnt& vEnd = propEnd.Value(); - //Base::Console().Message("%s edge:%d start:(%.3f,%.3f,%.3f)/%0.3f end:(%.2f,%.3f,%.3f)/%.3f\n",label,i, - // vStart.X(),vStart.Y(),vStart.Z(),start,vEnd.X(),vEnd.Y(),vEnd.Z(),end); - Base::Console().Message("%s edge:%d start:(%.3f,%.3f,%.3f) end:(%.2f,%.3f,%.3f)\n",label,i, - vStart.X(),vStart.Y(),vStart.Z(),vEnd.X(),vEnd.Y(),vEnd.Z()); -} - - -// Python Drawing feature --------------------------------------------------------- - -namespace App { -/// @cond DOXERR -PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawViewPartPython, TechDraw::DrawViewPart) -template<> const char* TechDraw::DrawViewPartPython::getViewProviderName(void) const { - return "TechDrawGui::ViewProviderViewPart"; -} -/// @endcond - -// explicit template instantiation -template class TechDrawExport FeaturePythonT; -} +/*************************************************************************** + * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2002 * + * Copyright (c) Luke Parry (l.parry@warwick.ac.uk) 2013 * + * Copyright (c) WandererFan (wandererfan@gmail.com) 2016 * + * * + * 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 * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +# include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + +#include + +#include +#include +#include +#include +#include + +#include "DrawUtil.h" +#include "DrawViewSection.h" +#include "Geometry.h" +#include "GeometryObject.h" +#include "DrawViewPart.h" +#include "DrawHatch.h" +#include "EdgeWalker.h" + + +#include // generated from DrawViewPartPy.xml + +using namespace TechDraw; +using namespace std; + + +//=========================================================================== +// DrawViewPart +//=========================================================================== + +App::PropertyFloatConstraint::Constraints DrawViewPart::floatRange = {0.01f,5.0f,0.05f}; + +PROPERTY_SOURCE(TechDraw::DrawViewPart, TechDraw::DrawView) + +DrawViewPart::DrawViewPart(void) : geometryObject(0) +{ + static const char *group = "Projection"; + static const char *fgroup = "Format"; + static const char *lgroup = "SectionLine"; + + ADD_PROPERTY_TYPE(Direction ,(0,0,1.0) ,group,App::Prop_None,"Projection direction. The direction you are looking."); + ADD_PROPERTY_TYPE(Source ,(0),group,App::Prop_None,"3D Shape to view"); + ADD_PROPERTY_TYPE(ShowHiddenLines ,(false),group,App::Prop_None,"Hidden lines on/off"); + ADD_PROPERTY_TYPE(ShowSmoothLines ,(false),group,App::Prop_None,"Smooth lines on/off"); + ADD_PROPERTY_TYPE(ShowSeamLines ,(false),group,App::Prop_None,"Seam lines on/off"); + //ADD_PROPERTY_TYPE(ShowIsoLines ,(false),group,App::Prop_None,"Iso u,v lines on/off"); + ADD_PROPERTY_TYPE(Tolerance,(0.05f),group,App::Prop_None,"Internal tolerance"); + Tolerance.setConstraints(&floatRange); + ADD_PROPERTY_TYPE(XAxisDirection ,(1,0,0) ,group,App::Prop_None,"Where to place projection's XAxis (rotation)"); + + ADD_PROPERTY_TYPE(LineWidth,(0.7f),fgroup,App::Prop_None,"The thickness of visible lines"); + ADD_PROPERTY_TYPE(HiddenWidth,(0.15),fgroup,App::Prop_None,"The thickness of hidden lines, if enabled"); + ADD_PROPERTY_TYPE(ShowCenters ,(true),fgroup,App::Prop_None,"Center marks on/off"); + ADD_PROPERTY_TYPE(CenterScale,(2.0),fgroup,App::Prop_None,"Center mark size adjustment, if enabled"); + ADD_PROPERTY_TYPE(HorizCenterLine ,(false),fgroup,App::Prop_None,"Show a horizontal centerline through view"); + ADD_PROPERTY_TYPE(VertCenterLine ,(false),fgroup,App::Prop_None,"Show a vertical centerline through view"); + + ADD_PROPERTY_TYPE(ShowSectionLine ,(true) ,lgroup,App::Prop_None,"Show/hide section line if applicable"); + ADD_PROPERTY_TYPE(HorizSectionLine ,(true) ,lgroup,App::Prop_None,"Section line is horizontal"); + ADD_PROPERTY_TYPE(ArrowUpSection ,(true) ,lgroup,App::Prop_None,"Section line arrows point up"); + ADD_PROPERTY_TYPE(SymbolSection,("A") ,lgroup,App::Prop_None,"Section identifier"); + + + geometryObject = new TechDrawGeometry::GeometryObject(); +} + +DrawViewPart::~DrawViewPart() +{ + delete geometryObject; +} + + +App::DocumentObjectExecReturn *DrawViewPart::execute(void) +{ + App::DocumentObject *link = Source.getValue(); + if (!link) { + return new App::DocumentObjectExecReturn("FVP - No Source object linked"); + } + + if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + return new App::DocumentObjectExecReturn("FVP - Linked object is not a Part object"); + } + + TopoDS_Shape shape = static_cast(link)->Shape.getShape().getShape(); + if (shape.IsNull()) { + return new App::DocumentObjectExecReturn("FVP - Linked shape object is empty"); + } + + geometryObject->setTolerance(Tolerance.getValue()); + double s = Scale.getValue(); + if (!s) { //might be problem, might be mid property change + Base::Console().Log("INFO - DVP::execute - Scale: %.3f\n",s); + return DrawView::execute(); + } + + geometryObject->setScale(Scale.getValue()); + try { + gp_Pnt inputCenter = TechDrawGeometry::findCentroid(shape, + Direction.getValue(), + getValidXDir()); + shapeCentroid = Base::Vector3d(inputCenter.X(),inputCenter.Y(),inputCenter.Z()); + TopoDS_Shape mirroredShape = TechDrawGeometry::mirrorShape(shape, + inputCenter, + Scale.getValue()); + buildGeometryObject(mirroredShape,inputCenter); +#if MOD_TECHDRAW_HANDLE_FACES + extractFaces(); +#endif //#if MOD_TECHDRAW_HANDLE_FACES + + } + catch (Standard_Failure) { + Handle_Standard_Failure e = Standard_Failure::Caught(); + return new App::DocumentObjectExecReturn(e->GetMessageString()); + } + + // There is a guaranteed change so check any references linked to this and touch + // We need to update all views pointing at this (ProjectionGroup, ClipGroup, etc) + std::vector parent = getInList(); + for (std::vector::iterator it = parent.begin(); it != parent.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(DrawView::getClassTypeId())) { + TechDraw::DrawView *view = static_cast(*it); + view->touch(); + } + } + return DrawView::execute(); +} + +short DrawViewPart::mustExecute() const +{ + short result = (Direction.isTouched() || + XAxisDirection.isTouched() || + Source.isTouched() || + Scale.isTouched() || + ScaleType.isTouched() || + ShowHiddenLines.isTouched() || + ShowSmoothLines.isTouched() || + ShowSeamLines.isTouched() || + LineWidth.isTouched() || + Tolerance.isTouched() || + HiddenWidth.isTouched()); + return result; +} + +void DrawViewPart::onChanged(const App::Property* prop) +{ + if (!isRestoring()) { + if (prop == &SymbolSection && getSectionRef()) { + getSectionRef()->touch(); + } + if (prop == &Direction || + prop == &XAxisDirection || + prop == &Source || + prop == &Scale || + prop == &ScaleType || + prop == &ShowHiddenLines || + prop == &ShowSmoothLines || + prop == &ShowSeamLines || + prop == &LineWidth || + prop == &HiddenWidth || + prop == &ShowCenters || + prop == &CenterScale || + prop == &ShowSectionLine || + prop == &HorizSectionLine || + prop == &ArrowUpSection || + prop == &SymbolSection || + prop == &HorizCenterLine || + prop == &VertCenterLine) { + try { + App::DocumentObjectExecReturn *ret = recompute(); + delete ret; + } + catch (...) { + } + } + } + DrawView::onChanged(prop); + +//TODO: when scale changes, any Dimensions for this View sb recalculated. (might happen anyway if document is recomputed?) +} + +void DrawViewPart::buildGeometryObject(TopoDS_Shape shape, gp_Pnt& inputCenter) +{ + Base::Vector3d baseProjDir = Direction.getValue(); + + saveParamSpace(baseProjDir, + getValidXDir()); + + geometryObject->projectShape(shape, + inputCenter, + Direction.getValue(), + getValidXDir()); + geometryObject->extractGeometry(TechDrawGeometry::ecHARD, + true); + geometryObject->extractGeometry(TechDrawGeometry::ecOUTLINE, + true); + if (ShowSmoothLines.getValue()) { + geometryObject->extractGeometry(TechDrawGeometry::ecSMOOTH, + true); + } + if (ShowSeamLines.getValue()) { + geometryObject->extractGeometry(TechDrawGeometry::ecSEAM, + true); + } + //if (ShowIsoLines.getValue()) { + // geometryObject->extractGeometry(TechDrawGeometry::ecUVISO, + // true); + //} + if (ShowHiddenLines.getValue()) { + geometryObject->extractGeometry(TechDrawGeometry::ecHARD, + false); + //geometryObject->extractGeometry(TechDrawGeometry::ecOUTLINE, //hidden outline,smooth,seam?? + // true); + } + bbox = geometryObject->calcBoundingBox(); +} + +//! make faces from the existing edge geometry +void DrawViewPart::extractFaces() +{ + geometryObject->clearFaceGeom(); + const std::vector& goEdges = geometryObject->getEdgeGeometry(); + std::vector::const_iterator itEdge = goEdges.begin(); + std::vector origEdges; + for (;itEdge != goEdges.end(); itEdge++) { + if ((*itEdge)->visible) { //don't make invisible faces! + origEdges.push_back((*itEdge)->occEdge); + } + } + + std::vector faceEdges = origEdges; + std::vector::iterator itOrig = origEdges.begin(); + + //HLR algo does not provide all edge intersections for edge endpoints. + //need to split long edges touched by Vertex of another edge + int idb = 0; + for (; itOrig != origEdges.end(); itOrig++, idb++) { + TopoDS_Vertex v1 = TopExp::FirstVertex((*itOrig)); + TopoDS_Vertex v2 = TopExp::LastVertex((*itOrig)); + std::vector::iterator itNew = faceEdges.begin(); + std::vector deleteList; + std::vector edgesToAdd; + int idx = 0; + for (; itNew != faceEdges.end(); itNew++,idx++) { + if ( itOrig->IsSame(*itNew) ){ + continue; + } + bool removeThis = false; + std::vector splitPoints; + if (isOnEdge((*itNew),v1,false)) { + splitPoints.push_back(v1); + removeThis = true; + } + if (isOnEdge((*itNew),v2,false)) { + splitPoints.push_back(v2); + removeThis = true; + } + if (removeThis) { + deleteList.push_back(idx); + } + + if (!splitPoints.empty()) { + std::vector subEdges = splitEdge(splitPoints,(*itNew)); + edgesToAdd.insert(std::end(edgesToAdd), std::begin(subEdges), std::end(subEdges)); + } + } + //delete the split edge(s) and add the subedges + //TODO: look into sets or maps or???? for all this + std::sort(deleteList.begin(),deleteList.end()); //ascending + auto last = std::unique(deleteList.begin(), deleteList.end()); //duplicates at back + deleteList.erase(last, deleteList.end()); //remove dupls + std::vector::reverse_iterator ritDel = deleteList.rbegin(); + for ( ; ritDel != deleteList.rend(); ritDel++) { + faceEdges.erase(faceEdges.begin() + (*ritDel)); + } + faceEdges.insert(std::end(faceEdges), std::begin(edgesToAdd),std::end(edgesToAdd)); + } + +//find all the wires in the pile of faceEdges + EdgeWalker ew; + ew.loadEdges(faceEdges); + ew.perform(); + std::vector fw = ew.getResultWires(); + //TODO: we should remove duplicates here in case of islands? + // but for non-mosaic's we should keep 1 copy of the outerWire + // if we remove duplicates after sortstrip, then the outerWire won't be a duplicate + // still ok as long as we draw biggest first? + + std::vector sortedWires = ew.sortStrip(fw,false); //false==>do not include biggest wires + + std::vector::iterator itWire = sortedWires.begin(); + for (; itWire != sortedWires.end(); itWire++) { + //version 1: 1 wire/face - no voids in face + TechDrawGeometry::Face* f = new TechDrawGeometry::Face(); + const TopoDS_Wire& wire = (*itWire); + TechDrawGeometry::Wire* w = new TechDrawGeometry::Wire(wire); + f->wires.push_back(w); + geometryObject->addFaceGeom(f); + } +} + +double DrawViewPart::simpleMinDist(TopoDS_Shape s1, TopoDS_Shape s2) +{ + Standard_Real minDist = -1; + + BRepExtrema_DistShapeShape extss(s1, s2); + if (!extss.IsDone()) { + Base::Console().Message("DVP - BRepExtrema_DistShapeShape failed"); + return -1; + } + int count = extss.NbSolution(); + if (count != 0) { + minDist = extss.Value(); + } else { + minDist = -1; + } + return minDist; +} + +bool DrawViewPart::isOnEdge(TopoDS_Edge e, TopoDS_Vertex v, bool allowEnds) +{ + bool result = false; + double dist = simpleMinDist(v,e); + if (dist < 0.0) { + Base::Console().Error("DVP::isOnEdge - simpleMinDist failed: %.3f\n",dist); + result = false; + } else if (dist < Precision::Confusion()) { + result = true; + } + if (result) { + TopoDS_Vertex v1 = TopExp::FirstVertex(e); + TopoDS_Vertex v2 = TopExp::LastVertex(e); + if (DrawUtil::isSamePoint(v,v1) || DrawUtil::isSamePoint(v,v2)) { + if (!allowEnds) { + result = false; + } + } + } + return result; +} + +std::vector DrawViewPart::splitEdge(std::vector splitPoints, TopoDS_Edge e) +{ + std::vector result; + if (splitPoints.empty()) { + return result; + } + TopoDS_Vertex vStart = TopExp::FirstVertex(e); + TopoDS_Vertex vEnd = TopExp::LastVertex(e); + + BRepAdaptor_Curve adapt(e); + Handle_Geom_Curve c = adapt.Curve().Curve(); + //simple version for 1 splitPoint + //TODO: handle case where e is split in multiple points (ie circular edge cuts line twice) + BRepBuilderAPI_MakeEdge mkBuilder1(c, vStart, splitPoints[0]); + TopoDS_Edge e1 = mkBuilder1.Edge(); + BRepBuilderAPI_MakeEdge mkBuilder2(c, splitPoints[0], vEnd); + TopoDS_Edge e2 = mkBuilder2.Edge(); + result.push_back(e1); + result.push_back(e2); + return result; +} + +std::vector DrawViewPart::getHatches() const +{ + std::vector result; + std::vector children = getInList(); + for (std::vector::iterator it = children.begin(); it != children.end(); ++it) { + if ((*it)->getTypeId().isDerivedFrom(DrawHatch::getClassTypeId())) { + TechDraw::DrawHatch* hatch = dynamic_cast(*it); + result.push_back(hatch); + } + } + return result; +} + +const std::vector & DrawViewPart::getVertexGeometry() const +{ + return geometryObject->getVertexGeometry(); +} + +const std::vector & DrawViewPart::getFaceGeometry() const +{ + return geometryObject->getFaceGeometry(); +} + +const std::vector & DrawViewPart::getEdgeGeometry() const +{ + return geometryObject->getEdgeGeometry(); +} + +//! returns existing BaseGeom of 2D Edge(idx) +TechDrawGeometry::BaseGeom* DrawViewPart::getProjEdgeByIndex(int idx) const +{ + const std::vector &geoms = getEdgeGeometry(); + if (geoms.empty()) { + Base::Console().Log("INFO - getProjEdgeByIndex(%d) - no Edge Geometry. Probably restoring?\n",idx); + return NULL; + } + return geoms[idx]; +} + +//! returns existing geometry of 2D Vertex(idx) +TechDrawGeometry::Vertex* DrawViewPart::getProjVertexByIndex(int idx) const +{ + const std::vector &geoms = getVertexGeometry(); + if (geoms.empty()) { + Base::Console().Log("INFO - getProjVertexByIndex(%d) - no Vertex Geometry. Probably restoring?\n",idx); + return NULL; + } + return geoms[idx]; +} + +//! returns existing geometry of 2D Face(idx) +//version 1 Face has 1 wire +std::vector DrawViewPart::getProjFaceByIndex(int idx) const +{ + std::vector result; + const std::vector& faces = getFaceGeometry(); + for (auto& f:faces) { + for (auto& w:f->wires) { + for (auto& g:w->geoms) { + result.push_back(g); + } + } + } + return result; +} + + +Base::BoundBox3d DrawViewPart::getBoundingBox() const +{ + return bbox; +} + +double DrawViewPart::getBoxX(void) const +{ + Base::BoundBox3d bbx = getBoundingBox(); //bbox is already scaled & centered! + return (bbx.MaxX - bbx.MinX); +} + +double DrawViewPart::getBoxY(void) const +{ + Base::BoundBox3d bbx = getBoundingBox(); + return (bbx.MaxY - bbx.MinY); +} + +QRectF DrawViewPart::getRect() const +{ + QRectF result(0.0,0.0,getBoxX(),getBoxY()); //this is from GO and is already scaled + return result; +} + +//used to project pt (ex SectionOrigin) onto paper plane +Base::Vector3d DrawViewPart::projectPoint(Base::Vector3d pt) const +{ + Base::Vector3d centeredPoint = pt - shapeCentroid; + Base::Vector3d direction = Direction.getValue(); + Base::Vector3d xAxis = getValidXDir(); + gp_Ax2 viewAxis; + viewAxis = gp_Ax2(gp_Pnt(0.0,0.0,0.0), + gp_Dir(direction.x, direction.y, direction.z), + gp_Dir(xAxis.x, xAxis.y, xAxis.z)); + HLRAlgo_Projector projector( viewAxis ); + gp_Pnt2d prjPnt; + projector.Project(gp_Pnt(centeredPoint.x,centeredPoint.y,centeredPoint.z), prjPnt); + return Base::Vector3d(prjPnt.X(),prjPnt.Y(), 0.0); +} + +bool DrawViewPart::hasGeometry(void) const +{ + bool result = false; + const std::vector &verts = getVertexGeometry(); + const std::vector &edges = getEdgeGeometry(); + if (verts.empty() && + edges.empty() ) { + result = false; + } else { + result = true; + } + return result; +} + +Base::Vector3d DrawViewPart::getValidXDir() const +{ + Base::Vector3d X(1.0,0.0,0.0); + Base::Vector3d Y(0.0,1.0,0.0); + Base::Vector3d xDir = XAxisDirection.getValue(); + if (xDir.Length() < Precision::Confusion()) { + Base::Console().Warning("XAxisDirection has zero length - using (1,0,0)\n"); + xDir = X; + } + Base::Vector3d viewDir = Direction.getValue(); + if ((xDir - viewDir).Length() < Precision::Confusion()) { + if (xDir == X) { + xDir = Y; + }else{ + xDir = X; + } + Base::Console().Warning("XAxisDirection cannot equal Direction - using (%.3f,%.3f%.3f)\n", + xDir.x,xDir.y,xDir.z); + } + return xDir; +} + +void DrawViewPart::saveParamSpace(Base::Vector3d direction, + Base::Vector3d xAxis) +{ + gp_Ax2 viewAxis; + viewAxis = gp_Ax2(gp_Pnt(0, 0, 0), + gp_Dir(direction.x, -direction.y, direction.z), + gp_Dir(xAxis.x, -xAxis.y, xAxis.z)); // Y invert warning! // + + uDir = Base::Vector3d(xAxis.x, -xAxis.y, xAxis.z); + gp_Dir ydir = viewAxis.YDirection(); + vDir = Base::Vector3d(ydir.X(),ydir.Y(),ydir.Z()); + wDir = Base::Vector3d(direction.x, -direction.y, direction.z); +} + + +DrawViewSection* DrawViewPart::getSectionRef(void) const +{ + DrawViewSection* result = nullptr; + std::vector inObjs = getInList(); + for (auto& o:inObjs) { + if (o->getTypeId().isDerivedFrom(DrawViewSection::getClassTypeId())) { + result = static_cast(o); + } + } + return result; +} + +void DrawViewPart::dumpVertexes(const char* text, const TopoDS_Shape& s) +{ + Base::Console().Message("DUMP - %s\n",text); + TopExp_Explorer expl(s, TopAbs_VERTEX); + int i; + for (i = 1 ; expl.More(); expl.Next(),i++) { + const TopoDS_Vertex& v = TopoDS::Vertex(expl.Current()); + gp_Pnt pnt = BRep_Tool::Pnt(v); + Base::Console().Message("v%d: (%.3f,%.3f,%.3f)\n",i,pnt.X(),pnt.Y(),pnt.Z()); + } +} + +void DrawViewPart::countFaces(const char* text, const TopoDS_Shape& s) +{ + TopExp_Explorer expl(s, TopAbs_FACE); + int i; + for (i = 0 ; expl.More(); expl.Next(),i++) { + } + Base::Console().Message("COUNT - %s has %d Faces\n",text,i); +} + +void DrawViewPart::countWires(const char* text, const TopoDS_Shape& s) +{ + TopExp_Explorer expl(s, TopAbs_WIRE); + int i = 0; + for (; expl.More(); expl.Next()) { + i++; + } + Base::Console().Message("COUNT - %s has %d wires\n",text,i); +} + +void DrawViewPart::countEdges(const char* text, const TopoDS_Shape& s) +{ + TopExp_Explorer expl(s, TopAbs_EDGE); + int i = 0; + for (; expl.More(); expl.Next()) { + i++; + } + Base::Console().Message("COUNT - %s has %d edges\n",text,i); +} + +void DrawViewPart::dump1Vertex(const char* text, const TopoDS_Vertex& v) +{ + Base::Console().Message("DUMP - DVP::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()); +} + +PyObject *DrawViewPart::getPyObject(void) +{ + if (PythonObject.is(Py::_None())) { + // ref counter is set to 1 + PythonObject = Py::Object(new DrawViewPartPy(this),true); + } + return Py::new_reference_to(PythonObject); +} + +void DrawViewPart::dumpEdge(char* label, int i, TopoDS_Edge e) +{ + BRepAdaptor_Curve adapt(e); + double start = BRepLProp_CurveTool::FirstParameter(adapt); + double end = BRepLProp_CurveTool::LastParameter(adapt); + BRepLProp_CLProps propStart(adapt,start,0,Precision::Confusion()); + const gp_Pnt& vStart = propStart.Value(); + BRepLProp_CLProps propEnd(adapt,end,0,Precision::Confusion()); + const gp_Pnt& vEnd = propEnd.Value(); + //Base::Console().Message("%s edge:%d start:(%.3f,%.3f,%.3f)/%0.3f end:(%.2f,%.3f,%.3f)/%.3f\n",label,i, + // vStart.X(),vStart.Y(),vStart.Z(),start,vEnd.X(),vEnd.Y(),vEnd.Z(),end); + Base::Console().Message("%s edge:%d start:(%.3f,%.3f,%.3f) end:(%.2f,%.3f,%.3f)\n",label,i, + vStart.X(),vStart.Y(),vStart.Z(),vEnd.X(),vEnd.Y(),vEnd.Z()); +} + + +// Python Drawing feature --------------------------------------------------------- + +namespace App { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawViewPartPython, TechDraw::DrawViewPart) +template<> const char* TechDraw::DrawViewPartPython::getViewProviderName(void) const { + return "TechDrawGui::ViewProviderViewPart"; +} +/// @endcond + +// explicit template instantiation +template class TechDrawExport FeaturePythonT; +} diff --git a/src/Mod/TechDraw/App/DrawViewPart.h b/src/Mod/TechDraw/App/DrawViewPart.h index cc4584958..48b3e647e 100644 --- a/src/Mod/TechDraw/App/DrawViewPart.h +++ b/src/Mod/TechDraw/App/DrawViewPart.h @@ -1,168 +1,159 @@ -/*************************************************************************** - * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2007 * - * Copyright (c) Luke Parry (l.parry@warwick.ac.uk) 2013 * - * * - * 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 * - * * - ***************************************************************************/ - -#ifndef _DrawViewPart_h_ -#define _DrawViewPart_h_ - -#include -#include -#include - -#include -#include -#include "DrawView.h" -#include - -#include - -class gp_Pnt; - -namespace TechDrawGeometry -{ -class GeometryObject; -class Vertex; -class BaseGeom; -class Face; -} - -namespace TechDraw { -class DrawHatch; -struct WalkerEdge; -} - -namespace TechDraw -{ -class DrawViewSection; - -class TechDrawExport DrawViewPart : public DrawView -{ - PROPERTY_HEADER(TechDraw::DrawViewPart); - -public: - /// Constructor - DrawViewPart(void); - virtual ~DrawViewPart(); - - App::PropertyLink Source; //Part Feature - App::PropertyVector Direction; //TODO: Rename to YAxisDirection or whatever this actually is (ProjectionDirection) - App::PropertyVector XAxisDirection; - App::PropertyBool ShowHiddenLines; - App::PropertyBool ShowSmoothLines; - App::PropertyBool ShowSeamLines; - App::PropertyFloat LineWidth; - App::PropertyFloat HiddenWidth; - App::PropertyBool ShowCenters; - App::PropertyFloat CenterScale; - App::PropertyFloatConstraint Tolerance; - App::PropertyBool HorizCenterLine; - App::PropertyBool VertCenterLine; - - App::PropertyBool ShowSectionLine; - App::PropertyBool HorizSectionLine; //true(horiz)/false(vert) - App::PropertyBool ArrowUpSection; //true(up/right)/false(down/left) - App::PropertyString SymbolSection; - - - std::vector getHatches(void) const; - - //TODO: are there use-cases for Python access to TechDrawGeometry??? - - const std::vector & getVertexGeometry() const; - const std::vector & getEdgeGeometry() const; - const std::vector & getFaceGeometry() const; - bool hasGeometry(void) const; - - TechDrawGeometry::BaseGeom* getProjEdgeByIndex(int idx) const; //get existing geom for edge idx in projection - TechDrawGeometry::Vertex* getProjVertexByIndex(int idx) const; //get existing geom for vertex idx in projection - std::vector getProjFaceByIndex(int idx) const; //get edges for face idx in projection - virtual Base::BoundBox3d getBoundingBox() const; - double getBoxX(void) const; - double getBoxY(void) const; - virtual QRectF getRect() const; - virtual DrawViewSection* getSectionRef() const; //is there a ViewSection based on this ViewPart? - Base::Vector3d getUDir(void) {return uDir;} //paperspace X - Base::Vector3d getVDir(void) {return vDir;} //paperspace Y - Base::Vector3d getWDir(void) {return wDir;} //paperspace Z - - short mustExecute() const; - - /** @name methods overide Feature */ - //@{ - /// recalculate the Feature - virtual App::DocumentObjectExecReturn *execute(void); - //@} - - /// returns the type name of the ViewProvider - virtual const char* getViewProviderName(void) const { - return "TechDrawGui::ViewProviderViewPart"; - } - //return PyObject as DrawViewPartPy - virtual PyObject *getPyObject(void); - - void dumpVertexes(const char* text, const TopoDS_Shape& s); - void dumpEdge(char* label, int i, TopoDS_Edge e); - void dump1Vertex(const char* label, const TopoDS_Vertex& v); - void countFaces(const char* label, const TopoDS_Shape& s); - void countWires(const char* label, const TopoDS_Shape& s); - void countEdges(const char* label, const TopoDS_Shape& s); - Base::Vector3d getValidXDir() const; - Base::Vector3d projectPoint(Base::Vector3d pt) const; - -protected: - TechDrawGeometry::GeometryObject *geometryObject; - Base::BoundBox3d bbox; - - void onChanged(const App::Property* prop); - void buildGeometryObject(TopoDS_Shape shape, gp_Pnt& center); - void extractFaces(); - std::vector sortWiresBySize(std::vector& w, bool reverse = false); - class wireCompare; - - bool isOnEdge(TopoDS_Edge e, TopoDS_Vertex v, bool allowEnds = false); - std::vector splitEdge(std::vector splitPoints, TopoDS_Edge e); - double simpleMinDist(TopoDS_Shape s1, TopoDS_Shape s2); - bool isSamePoint(TopoDS_Vertex v1, TopoDS_Vertex v2); - int findUniqueVert(TopoDS_Vertex vx, std::vector &uniqueVert); - std::vector makeUniqueVList(std::vector edges); - std::vector makeWalkerEdges(std::vector edges, - std::vector verts); - TopoDS_Wire makeCleanWire(std::vector edges, double tol = 0.10); - - //Projection parameter space - void saveParamSpace(Base::Vector3d direction, - Base::Vector3d xAxis); - Base::Vector3d uDir; //paperspace X - Base::Vector3d vDir; //paperspace Y - Base::Vector3d wDir; //paperspace Z - Base::Vector3d shapeCentroid; - -private: - static App::PropertyFloatConstraint::Constraints floatRange; - -}; - -typedef App::FeaturePythonT DrawViewPartPython; - -} //namespace TechDraw - -#endif // #ifndef _DrawViewPart_h_ +/*************************************************************************** + * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2007 * + * Copyright (c) Luke Parry (l.parry@warwick.ac.uk) 2013 * + * Copyright (c) WandererFan (wandererfan@gmail.com) 2016 * + * * + * 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 * + * * + ***************************************************************************/ + +#ifndef _DrawViewPart_h_ +#define _DrawViewPart_h_ + +#include +#include +#include + +#include +#include +#include "DrawView.h" +#include + +#include + +class gp_Pnt; + +namespace TechDrawGeometry +{ +class GeometryObject; +class Vertex; +class BaseGeom; +class Face; +} + +namespace TechDraw { +class DrawHatch; +} + +namespace TechDraw +{ +class DrawViewSection; + +class TechDrawExport DrawViewPart : public DrawView +{ + PROPERTY_HEADER(TechDraw::DrawViewPart); + +public: + DrawViewPart(void); + virtual ~DrawViewPart(); + + App::PropertyLink Source; //Part Feature + App::PropertyVector Direction; //TODO: Rename to YAxisDirection or whatever this actually is (ProjectionDirection) + App::PropertyVector XAxisDirection; + App::PropertyBool ShowHiddenLines; + App::PropertyBool ShowSmoothLines; + App::PropertyBool ShowSeamLines; + App::PropertyFloat LineWidth; + App::PropertyFloat HiddenWidth; + App::PropertyBool ShowCenters; + App::PropertyFloat CenterScale; + App::PropertyFloatConstraint Tolerance; + App::PropertyBool HorizCenterLine; + App::PropertyBool VertCenterLine; + + App::PropertyBool ShowSectionLine; + App::PropertyBool HorizSectionLine; //true(horiz)/false(vert) + App::PropertyBool ArrowUpSection; //true(up/right)/false(down/left) + App::PropertyString SymbolSection; + + + std::vector getHatches(void) const; + + //TODO: are there use-cases for Python access to TechDrawGeometry??? + + const std::vector & getVertexGeometry() const; + const std::vector & getEdgeGeometry() const; + const std::vector & getFaceGeometry() const; + bool hasGeometry(void) const; + + TechDrawGeometry::BaseGeom* getProjEdgeByIndex(int idx) const; //get existing geom for edge idx in projection + TechDrawGeometry::Vertex* getProjVertexByIndex(int idx) const; //get existing geom for vertex idx in projection + std::vector getProjFaceByIndex(int idx) const; //get edges for face idx in projection + virtual Base::BoundBox3d getBoundingBox() const; + double getBoxX(void) const; + double getBoxY(void) const; + virtual QRectF getRect() const; + virtual DrawViewSection* getSectionRef() const; //is there a ViewSection based on this ViewPart? + Base::Vector3d getUDir(void) {return uDir;} //paperspace X + Base::Vector3d getVDir(void) {return vDir;} //paperspace Y + Base::Vector3d getWDir(void) {return wDir;} //paperspace Z + + short mustExecute() const; + + /** @name methods overide Feature */ + //@{ + /// recalculate the Feature + virtual App::DocumentObjectExecReturn *execute(void); + //@} + + /// returns the type name of the ViewProvider + virtual const char* getViewProviderName(void) const { + return "TechDrawGui::ViewProviderViewPart"; + } + //return PyObject as DrawViewPartPy + virtual PyObject *getPyObject(void); + + void dumpVertexes(const char* text, const TopoDS_Shape& s); + void dumpEdge(char* label, int i, TopoDS_Edge e); + void dump1Vertex(const char* label, const TopoDS_Vertex& v); + void countFaces(const char* label, const TopoDS_Shape& s); + void countWires(const char* label, const TopoDS_Shape& s); + void countEdges(const char* label, const TopoDS_Shape& s); + Base::Vector3d getValidXDir() const; + Base::Vector3d projectPoint(Base::Vector3d pt) const; + +protected: + TechDrawGeometry::GeometryObject *geometryObject; + Base::BoundBox3d bbox; + + void onChanged(const App::Property* prop); + void buildGeometryObject(TopoDS_Shape shape, gp_Pnt& center); + void extractFaces(); + + bool isOnEdge(TopoDS_Edge e, TopoDS_Vertex v, bool allowEnds = false); + std::vector splitEdge(std::vector splitPoints, TopoDS_Edge e); + double simpleMinDist(TopoDS_Shape s1, TopoDS_Shape s2); + + //Projection parameter space + void saveParamSpace(Base::Vector3d direction, + Base::Vector3d xAxis); + Base::Vector3d uDir; //paperspace X + Base::Vector3d vDir; //paperspace Y + Base::Vector3d wDir; //paperspace Z + Base::Vector3d shapeCentroid; + +private: + static App::PropertyFloatConstraint::Constraints floatRange; + +}; + +typedef App::FeaturePythonT DrawViewPartPython; + +} //namespace TechDraw + +#endif // #ifndef _DrawViewPart_h_ diff --git a/src/Mod/TechDraw/App/DrawViewSection.cpp b/src/Mod/TechDraw/App/DrawViewSection.cpp index 4562f0fcf..44737f416 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.cpp +++ b/src/Mod/TechDraw/App/DrawViewSection.cpp @@ -1,466 +1,476 @@ -/*************************************************************************** - * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2002 * - * Copyright (c) Luke Parry (l.parry@warwick.ac.uk) 2013 * - * Copyright (c) WandererFan (wandererfan@gmail.com) 2016 * - * * - * 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 * - * * - ***************************************************************************/ - - -#include "PreCompiled.h" - -#ifndef _PreComp_ -# include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif - - -#include -#include -#include -#include -#include -#include - -#include - -#include "Geometry.h" -#include "GeometryObject.h" -#include "EdgeWalker.h" -#include "DrawViewSection.h" - -using namespace TechDraw; -using namespace std; - -//=========================================================================== -// DrawViewSection -//=========================================================================== - -PROPERTY_SOURCE(TechDraw::DrawViewSection, TechDraw::DrawViewPart) - -DrawViewSection::DrawViewSection() -{ - static const char *sgroup = "Section"; - static const char *lgroup = "Line"; - - Base::Reference hGrp = App::GetApplication().GetUserParameter() - .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Colors"); - App::Color fcColor = App::Color((uint32_t) hGrp->GetUnsigned("CutSurfaceColor", 0xC8C8C800)); - - ADD_PROPERTY_TYPE(SectionNormal ,(0,0,1.0) ,sgroup,App::Prop_None,"Section Plane normal direction"); - ADD_PROPERTY_TYPE(SectionOrigin ,(0,0,0) ,sgroup,App::Prop_None,"Section Plane Origin"); - ADD_PROPERTY_TYPE(ShowCutSurface ,(true),sgroup,App::Prop_None,"Show the cut surface"); - ADD_PROPERTY_TYPE(CutSurfaceColor,(fcColor),sgroup,App::Prop_None,"The color to shade the cut surface"); - - ADD_PROPERTY_TYPE(BaseView ,(0),lgroup,App::Prop_None,"2D View with SectionLine"); - - geometryObject = new TechDrawGeometry::GeometryObject(); -} - -DrawViewSection::~DrawViewSection() -{ -} - -short DrawViewSection::mustExecute() const -{ - // If Tolerance Property is touched - if(SectionNormal.isTouched() || - SectionOrigin.isTouched() || - ShowCutSurface.isTouched() || - CutSurfaceColor.isTouched() ) - return 1; - - return TechDraw::DrawViewPart::mustExecute(); -} - -App::DocumentObjectExecReturn *DrawViewSection::execute(void) -{ - App::DocumentObject* link = Source.getValue(); - App::DocumentObject* base = BaseView.getValue(); - if (!link || !base) { - Base::Console().Log("INFO - DVS::execute - No Source or Link - creation?\n"); - return DrawView::execute(); - } - - if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) - return new App::DocumentObjectExecReturn("Source object is not a Part object"); - if (!base->getTypeId().isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId())) - return new App::DocumentObjectExecReturn("BaseView object is not a DrawViewPart object"); - - const Part::TopoShape &partTopo = static_cast(link)->Shape.getShape(); - const TechDraw::DrawViewPart* dvp = static_cast(base); - - if (partTopo.getShape().IsNull()) - return new App::DocumentObjectExecReturn("Linked shape object is empty"); - - gp_Pln pln = getSectionPlane(); - // Get the Axis Directions for the Plane to transform UV components again - gp_XYZ xAxis = pln.XAxis().Direction().XYZ(); - gp_XYZ yAxis = pln.YAxis().Direction().XYZ(); - gp_XYZ origin = pln.Location().XYZ(); - gp_Dir plnNormal = pln.Axis().Direction().XYZ(); - - Base::BoundBox3d bb = partTopo.getBoundBox(); - - Base::Vector3d tmp1 = SectionOrigin.getValue(); - Base::Vector3d plnPnt(tmp1.x, tmp1.y, tmp1.z); - //Base::Vector3d tmp2 = SectionNormal.getValue(); - Base::Vector3d plnNorm(plnNormal.X(), plnNormal.Y(), plnNormal.Z()); - -// if(!bb.IsCutPlane(plnPnt, plnNorm)) { //this test doesn't work if plane is coincident with bb! - if(!isReallyInBox(plnPnt, bb)) { - Base::Console().Warning("DVS: Section Plane doesn't intersect part in %s\n",getNameInDocument()); - Base::Console().Warning("DVS: Using center of bounding box.\n"); - plnPnt = bb.GetCenter(); - SectionOrigin.setValue(plnPnt); - } - - // Gather the corner points of bbox - std::vector pnts; - pnts.push_back(Base::Vector3d(bb.MinX,bb.MinY,bb.MinZ)); - pnts.push_back(Base::Vector3d(bb.MaxX,bb.MinY,bb.MinZ)); - pnts.push_back(Base::Vector3d(bb.MinX,bb.MaxY,bb.MinZ)); - pnts.push_back(Base::Vector3d(bb.MaxX,bb.MaxY,bb.MinZ)); - pnts.push_back(Base::Vector3d(bb.MinX,bb.MinY,bb.MaxZ)); - pnts.push_back(Base::Vector3d(bb.MaxX,bb.MinY,bb.MaxZ)); - pnts.push_back(Base::Vector3d(bb.MinX,bb.MaxY,bb.MaxZ)); - pnts.push_back(Base::Vector3d(bb.MaxX,bb.MaxY,bb.MaxZ)); - - double uMax = 0, vMax = 0, wMax = 0., dMax = 0; - for(std::vector::const_iterator it = pnts.begin(); it != pnts.end(); ++it) { - // Project each bounding box point onto projection plane and find largest u,v,w values - Base::Vector3d pnt = (*it); - pnt.ProjectToPlane(plnPnt, plnNorm); - uMax = std::max(uMax, std::abs(plnPnt.x - pnt.x)); //one will be zero - vMax = std::max(vMax, std::abs(plnPnt.y - pnt.y)); - wMax = std::max(wMax, std::abs(plnPnt.z - pnt.z)); - - //dMax is the bounding box point furthest away from plane. used for determining extrusion length - double dist = (*it).DistanceToPlane(plnPnt, plnNorm); - dMax = std::max(dMax, dist); - } - - //use largest of u,v,w to make cutting face that covers whole shape - double maxParm = std::max(uMax,vMax); - maxParm = std::max(maxParm,wMax); - BRepBuilderAPI_MakePolygon mkPoly; - gp_Pnt pn1(origin + xAxis * maxParm + yAxis * maxParm); - gp_Pnt pn2(origin + xAxis * maxParm + yAxis * -maxParm); - gp_Pnt pn3(origin + xAxis * -maxParm + yAxis * -maxParm); - gp_Pnt pn4(origin + xAxis * -maxParm + yAxis * +maxParm); - - mkPoly.Add(pn1); - mkPoly.Add(pn2); - mkPoly.Add(pn3); - mkPoly.Add(pn4); - mkPoly.Close(); - - // Make the extrusion face - BRepBuilderAPI_MakeFace mkFace(mkPoly.Wire()); - TopoDS_Face aProjFace = mkFace.Face(); - if(aProjFace.IsNull()) - return new App::DocumentObjectExecReturn("DrawViewSection - Projected face is NULL"); - TopoDS_Shape prism = BRepPrimAPI_MakePrism(aProjFace, dMax * gp_Vec(pln.Axis().Direction()), false, true).Shape(); - - // We need to copy the shape to not modify the BRepstructure - BRepBuilderAPI_Copy BuilderCopy(partTopo.getShape()); - TopoDS_Shape myShape = BuilderCopy.Shape(); - - BRepAlgoAPI_Cut mkCut(myShape, prism); - if (!mkCut.IsDone()) - return new App::DocumentObjectExecReturn("Section cut has failed"); - - TopoDS_Shape rawShape = mkCut.Shape(); - - geometryObject->setTolerance(Tolerance.getValue()); - geometryObject->setScale(Scale.getValue()); - try { - gp_Pnt inputCenter = TechDrawGeometry::findCentroid(rawShape, - Direction.getValue(), - getValidXDir()); - TopoDS_Shape mirroredShape = TechDrawGeometry::mirrorShape(rawShape, - inputCenter, - Scale.getValue()); - buildGeometryObject(mirroredShape,inputCenter); //this is original shape after cut by section prism - -#if MOD_TECHDRAW_HANDLE_FACES - extractFaces(); -#endif //#if MOD_TECHDRAW_HANDLE_FACES - - TopoDS_Compound sectionCompound = findSectionPlaneIntersections(rawShape); - TopoDS_Shape mirroredSection = TechDrawGeometry::mirrorShape(sectionCompound, - inputCenter, - Scale.getValue()); - - TopoDS_Compound newFaces; - BRep_Builder builder; - builder.MakeCompound(newFaces); - TopExp_Explorer expl(mirroredSection, TopAbs_FACE); - for (; expl.More(); expl.Next()) { - const TopoDS_Face& face = TopoDS::Face(expl.Current()); - TopoDS_Face pFace = projectFace(face, - inputCenter, - Direction.getValue(), - getValidXDir()); - builder.Add(newFaces,pFace); - - } - sectionFaces = newFaces; - } - catch (Standard_Failure) { - Handle_Standard_Failure e1 = Standard_Failure::Caught(); - return new App::DocumentObjectExecReturn(std::string("DVS building Section shape failed: ") + - std::string(e1->GetMessageString())); - } - - std::string symbol = dvp->SymbolSection.getValue(); - std::string symbolText = "Section " + symbol + "-" + symbol; - if (symbolText.compare(Label.getValue())) { - Label.setValue(symbolText.c_str()); - } - - - touch(); - return DrawView::execute(); -} - -gp_Pln DrawViewSection::getSectionPlane() const -{ - Base::Vector3d plnPnt = SectionOrigin.getValue(); - Base::Vector3d plnNorm = SectionNormal.getValue(); - - return gp_Pln(gp_Pnt(plnPnt.x, plnPnt.y, plnPnt.z), gp_Dir(plnNorm.x, plnNorm.y, plnNorm.z)); -} - -//! tries to find the intersection of the section plane with the shape giving a collection of planar faces -TopoDS_Compound DrawViewSection::findSectionPlaneIntersections(const TopoDS_Shape& shape) -{ - TopoDS_Compound result; - if(shape.IsNull()){ - Base::Console().Log("DrawViewSection::getSectionSurface - Sectional View shape is Empty\n"); - return result; - } - - gp_Pln plnSection = getSectionPlane(); - BRep_Builder builder; - builder.MakeCompound(result); - - TopExp_Explorer expFaces(shape, TopAbs_FACE); - int i; - int dbAdded = 0; - for (i = 1 ; expFaces.More(); expFaces.Next(), i++) { - const TopoDS_Face& face = TopoDS::Face(expFaces.Current()); - BRepAdaptor_Surface adapt(face); - if (adapt.GetType() == GeomAbs_Plane){ - gp_Pln plnFace = adapt.Plane(); - - if(plnSection.Contains(plnFace.Location(), Precision::Confusion()) && - plnFace.Axis().IsParallel(plnSection.Axis(), Precision::Angular())) { - dbAdded++; - builder.Add(result, face); - } - } - } - return result; -} - -//! get display geometry for Section faces -std::vector DrawViewSection::getFaceGeometry() -{ - std::vector result; - TopoDS_Compound c = sectionFaces; - TopExp_Explorer faces(c, TopAbs_FACE); - for (; faces.More(); faces.Next()) { - TechDrawGeometry::Face* f = new TechDrawGeometry::Face(); - const TopoDS_Face& face = TopoDS::Face(faces.Current()); - TopExp_Explorer wires(face, TopAbs_WIRE); - for (; wires.More(); wires.Next()) { - TechDrawGeometry::Wire* w = new TechDrawGeometry::Wire(); - const TopoDS_Wire& wire = TopoDS::Wire(wires.Current()); - TopExp_Explorer edges(wire, TopAbs_EDGE); - for (; edges.More(); edges.Next()) { - const TopoDS_Edge& edge = TopoDS::Edge(edges.Current()); - //dumpEdge("edge",edgeCount,edge); - TechDrawGeometry::BaseGeom* base = TechDrawGeometry::BaseGeom::baseFactory(edge); - w->geoms.push_back(base); - } - f->wires.push_back(w); - } - result.push_back(f); - } - return result; -} - -//! project a single face using HLR -TopoDS_Face DrawViewSection::projectFace(const TopoDS_Shape &face, - gp_Pnt faceCenter, - const Base::Vector3d &direction, - const Base::Vector3d &xaxis) -{ - if(face.IsNull()) { - throw Base::Exception("DrawViewSection::projectFace - input Face is NULL"); - } - - gp_Ax2 transform; - transform = gp_Ax2(faceCenter, - gp_Dir(direction.x, direction.y, direction.z), - gp_Dir(xaxis.x, xaxis.y, xaxis.z)); - - HLRBRep_Algo *brep_hlr = new HLRBRep_Algo(); - brep_hlr->Add(face); - - HLRAlgo_Projector projector( transform ); - brep_hlr->Projector(projector); - brep_hlr->Update(); - brep_hlr->Hide(); - - HLRBRep_HLRToShape hlrToShape(brep_hlr); - TopoDS_Shape hardEdges = hlrToShape.VCompound(); -// TopoDS_Shape outEdges = hlrToShape.OutLineVCompound(); - std::vector faceEdges; - TopExp_Explorer expl(hardEdges, TopAbs_EDGE); - int i; - for (i = 1 ; expl.More(); expl.Next(),i++) { - const TopoDS_Edge& edge = TopoDS::Edge(expl.Current()); - if (edge.IsNull()) { - Base::Console().Log("INFO - GO::projectFace - hard edge: %d is NULL\n",i); - continue; - } - faceEdges.push_back(edge); - } - //if edge is both hard & outline, it will be duplicated? are hard edges enough? -// TopExp_Explorer expl2(outEdges, TopAbs_EDGE); -// for (i = 1 ; expl2.More(); expl2.Next(),i++) { -// const TopoDS_Edge& edge = TopoDS::Edge(expl2.Current()); -// if (edge.IsNull()) { -// Base::Console().Log("INFO - GO::projectFace - outline edge: %d is NULL\n",i); -// continue; -// } -// bool addEdge = true; -// //is edge already in faceEdges? maybe need to use explorer for this for IsSame to work? -// for (auto& e:faceEdges) { -// if (e.IsPartner(edge)) { -// addEdge = false; -// Base::Console().Message("TRACE - DVS::projectFace - skipping an edge 1\n"); -// } -// } -// expl.ReInit(); -// for (; expl.More(); expl.Next()){ -// const TopoDS_Edge& eHard = TopoDS::Edge(expl.Current()); -// if (eHard.IsPartner(edge)) { -// addEdge = false; -// Base::Console().Message("TRACE - DVS::projectFace - skipping an edge 2\n"); -// } -// } -// if (addEdge) { -// faceEdges.push_back(edge); -// } -// } - - std::vector uniqueVert = makeUniqueVList(faceEdges); - std::vector walkerEdges = makeWalkerEdges(faceEdges,uniqueVert); - - EdgeWalker ew; - ew.setSize(uniqueVert.size()); - ew.loadEdges(walkerEdges); - ew.perform(); - facelist result = ew.getResult(); - result = TechDraw::EdgeWalker::removeDuplicateFaces(result); - - facelist::iterator iFace = result.begin(); - std::vector fw; - int dbi = 0; - for (;iFace != result.end(); iFace++,dbi++) { - edgelist::iterator iEdge = (*iFace).begin(); - std::vector fe; - for (;iEdge != (*iFace).end(); iEdge++) { - fe.push_back(faceEdges.at((*iEdge).idx)); - } - TopoDS_Wire w = makeCleanWire(fe); - fw.push_back(w); - } - - TopoDS_Face projectedFace; - if (!fw.empty()) { - std::vector sortedWires = sortWiresBySize(fw); - if (sortedWires.empty()) { - return projectedFace; - } - //TODO: should have the same size checking logic as DVP? - //remove the largest wire (OuterWire of graph) ??? but duplicates have been removed? only do this if a mosaic? - //sortedWires.erase(sortedWires.begin()); - - BRepBuilderAPI_MakeFace mkFace(sortedWires.front(),true); //true => only want planes? - std::vector::iterator itWire = ++sortedWires.begin(); //starting with second face - for (; itWire != sortedWires.end(); itWire++) { - mkFace.Add(*itWire); - } - projectedFace = mkFace.Face(); - } - return projectedFace; -} - -//this should really be in BoundBox.h -bool DrawViewSection::isReallyInBox (const Base::Vector3d v, const Base::BoundBox3d bb) const -{ - if (v.x <= bb.MinX || v.x >= bb.MaxX) - return false; - if (v.y <= bb.MinY || v.y >= bb.MaxY) - return false; - if (v.z <= bb.MinZ || v.z >= bb.MaxZ) - return false; - return true; -} - - -// Python Drawing feature --------------------------------------------------------- - -namespace App { -/// @cond DOXERR -PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawViewSectionPython, TechDraw::DrawViewSection) -template<> const char* TechDraw::DrawViewSectionPython::getViewProviderName(void) const { - return "TechDrawGui::ViewProviderDrawingView"; -} -/// @endcond - -// explicit template instantiation -template class TechDrawExport FeaturePythonT; -} +/*************************************************************************** + * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2002 * + * Copyright (c) Luke Parry (l.parry@warwick.ac.uk) 2013 * + * Copyright (c) WandererFan (wandererfan@gmail.com) 2016 * + * * + * 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 * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#ifndef _PreComp_ +# include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + + +#include +#include +#include +#include +#include +#include + +#include + +#include "Geometry.h" +#include "GeometryObject.h" +#include "EdgeWalker.h" +#include "DrawViewSection.h" + +using namespace TechDraw; +using namespace std; + +//=========================================================================== +// DrawViewSection +//=========================================================================== + +PROPERTY_SOURCE(TechDraw::DrawViewSection, TechDraw::DrawViewPart) + +DrawViewSection::DrawViewSection() +{ + static const char *sgroup = "Section"; + static const char *lgroup = "Line"; + + Base::Reference hGrp = App::GetApplication().GetUserParameter() + .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Colors"); + App::Color fcColor = App::Color((uint32_t) hGrp->GetUnsigned("CutSurfaceColor", 0xC8C8C800)); + + ADD_PROPERTY_TYPE(SectionNormal ,(0,0,1.0) ,sgroup,App::Prop_None,"Section Plane normal direction"); //direction of extrusion of cutting prism + ADD_PROPERTY_TYPE(SectionOrigin ,(0,0,0) ,sgroup,App::Prop_None,"Section Plane Origin"); + ADD_PROPERTY_TYPE(ShowCutSurface ,(true),sgroup,App::Prop_None,"Show the cut surface"); + ADD_PROPERTY_TYPE(CutSurfaceColor,(fcColor),sgroup,App::Prop_None,"The color to shade the cut surface"); + + ADD_PROPERTY_TYPE(BaseView ,(0),lgroup,App::Prop_None,"2D View with SectionLine"); + + geometryObject = new TechDrawGeometry::GeometryObject(); +} + +DrawViewSection::~DrawViewSection() +{ +} + +short DrawViewSection::mustExecute() const +{ + // If Tolerance Property is touched + if(SectionNormal.isTouched() || + SectionOrigin.isTouched() || + ShowCutSurface.isTouched() || + CutSurfaceColor.isTouched() ) + return 1; + + return TechDraw::DrawViewPart::mustExecute(); +} + +App::DocumentObjectExecReturn *DrawViewSection::execute(void) +{ + App::DocumentObject* link = Source.getValue(); + App::DocumentObject* base = BaseView.getValue(); + if (!link || !base) { + Base::Console().Log("INFO - DVS::execute - No Source or Link - creation?\n"); + return DrawView::execute(); + } + + if (!link->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + return new App::DocumentObjectExecReturn("Source object is not a Part object"); + if (!base->getTypeId().isDerivedFrom(TechDraw::DrawViewPart::getClassTypeId())) + return new App::DocumentObjectExecReturn("BaseView object is not a DrawViewPart object"); + + const Part::TopoShape &partTopo = static_cast(link)->Shape.getShape(); + const TechDraw::DrawViewPart* dvp = static_cast(base); + + if (partTopo.getShape().IsNull()) + return new App::DocumentObjectExecReturn("Linked shape object is empty"); + + gp_Pln pln = getSectionPlane(); + // Get the Axis Directions for the Plane to transform UV components again + gp_XYZ xAxis = pln.XAxis().Direction().XYZ(); + gp_XYZ yAxis = pln.YAxis().Direction().XYZ(); + gp_XYZ origin = pln.Location().XYZ(); + gp_Dir plnNormal = pln.Axis().Direction().XYZ(); + + Base::BoundBox3d bb = partTopo.getBoundBox(); + + Base::Vector3d tmp1 = SectionOrigin.getValue(); + Base::Vector3d plnPnt(tmp1.x, tmp1.y, tmp1.z); + //Base::Vector3d tmp2 = SectionNormal.getValue(); + Base::Vector3d plnNorm(plnNormal.X(), plnNormal.Y(), plnNormal.Z()); + +// if(!bb.IsCutPlane(plnPnt, plnNorm)) { //this test doesn't work if plane is coincident with bb! + if(!isReallyInBox(plnPnt, bb)) { + Base::Console().Warning("DVS: Section Plane doesn't intersect part in %s\n",getNameInDocument()); + Base::Console().Warning("DVS: Using center of bounding box.\n"); + plnPnt = bb.GetCenter(); + SectionOrigin.setValue(plnPnt); + } + + // Gather the corner points of bbox + std::vector pnts; + pnts.push_back(Base::Vector3d(bb.MinX,bb.MinY,bb.MinZ)); + pnts.push_back(Base::Vector3d(bb.MaxX,bb.MinY,bb.MinZ)); + pnts.push_back(Base::Vector3d(bb.MinX,bb.MaxY,bb.MinZ)); + pnts.push_back(Base::Vector3d(bb.MaxX,bb.MaxY,bb.MinZ)); + pnts.push_back(Base::Vector3d(bb.MinX,bb.MinY,bb.MaxZ)); + pnts.push_back(Base::Vector3d(bb.MaxX,bb.MinY,bb.MaxZ)); + pnts.push_back(Base::Vector3d(bb.MinX,bb.MaxY,bb.MaxZ)); + pnts.push_back(Base::Vector3d(bb.MaxX,bb.MaxY,bb.MaxZ)); + + double uMax = 0, vMax = 0, wMax = 0., dMax = 0; + for(std::vector::const_iterator it = pnts.begin(); it != pnts.end(); ++it) { + // Project each bounding box point onto projection plane and find largest u,v,w values + Base::Vector3d pnt = (*it); + pnt.ProjectToPlane(plnPnt, plnNorm); + uMax = std::max(uMax, std::abs(plnPnt.x - pnt.x)); //one will be zero + vMax = std::max(vMax, std::abs(plnPnt.y - pnt.y)); + wMax = std::max(wMax, std::abs(plnPnt.z - pnt.z)); + + //dMax is the bounding box point furthest away from plane. used for determining extrusion length + double dist = (*it).DistanceToPlane(plnPnt, plnNorm); + dMax = std::max(dMax, dist); + } + + //use largest of u,v,w to make cutting face that covers whole shape + double maxParm = std::max(uMax,vMax); + maxParm = std::max(maxParm,wMax); + BRepBuilderAPI_MakePolygon mkPoly; + gp_Pnt pn1(origin + xAxis * maxParm + yAxis * maxParm); + gp_Pnt pn2(origin + xAxis * maxParm + yAxis * -maxParm); + gp_Pnt pn3(origin + xAxis * -maxParm + yAxis * -maxParm); + gp_Pnt pn4(origin + xAxis * -maxParm + yAxis * +maxParm); + + mkPoly.Add(pn1); + mkPoly.Add(pn2); + mkPoly.Add(pn3); + mkPoly.Add(pn4); + mkPoly.Close(); + + // Make the extrusion face + BRepBuilderAPI_MakeFace mkFace(mkPoly.Wire()); + TopoDS_Face aProjFace = mkFace.Face(); + if(aProjFace.IsNull()) + return new App::DocumentObjectExecReturn("DrawViewSection - Projected face is NULL"); + TopoDS_Shape prism = BRepPrimAPI_MakePrism(aProjFace, dMax * gp_Vec(pln.Axis().Direction()), false, true).Shape(); + + // We need to copy the shape to not modify the BRepstructure + BRepBuilderAPI_Copy BuilderCopy(partTopo.getShape()); + TopoDS_Shape myShape = BuilderCopy.Shape(); + + BRepAlgoAPI_Cut mkCut(myShape, prism); + if (!mkCut.IsDone()) + return new App::DocumentObjectExecReturn("Section cut has failed"); + + TopoDS_Shape rawShape = mkCut.Shape(); + + geometryObject->setTolerance(Tolerance.getValue()); + geometryObject->setScale(Scale.getValue()); + try { + gp_Pnt inputCenter = TechDrawGeometry::findCentroid(rawShape, + Direction.getValue(), + getValidXDir()); + TopoDS_Shape mirroredShape = TechDrawGeometry::mirrorShape(rawShape, + inputCenter, + Scale.getValue()); + buildGeometryObject(mirroredShape,inputCenter); //this is original shape after cut by section prism + +#if MOD_TECHDRAW_HANDLE_FACES + extractFaces(); +#endif //#if MOD_TECHDRAW_HANDLE_FACES + + TopoDS_Compound sectionCompound = findSectionPlaneIntersections(rawShape); + TopoDS_Shape mirroredSection = TechDrawGeometry::mirrorShape(sectionCompound, + inputCenter, + Scale.getValue()); + + TopoDS_Compound newFaces; + BRep_Builder builder; + builder.MakeCompound(newFaces); + TopExp_Explorer expl(mirroredSection, TopAbs_FACE); + for (; expl.More(); expl.Next()) { + const TopoDS_Face& face = TopoDS::Face(expl.Current()); + TopoDS_Face pFace = projectFace(face, + inputCenter, + Direction.getValue(), + getValidXDir()); + builder.Add(newFaces,pFace); + + } + sectionFaces = newFaces; + } + catch (Standard_Failure) { + Handle_Standard_Failure e1 = Standard_Failure::Caught(); + return new App::DocumentObjectExecReturn(std::string("DVS building Section shape failed: ") + + std::string(e1->GetMessageString())); + } + + std::string symbol = dvp->SymbolSection.getValue(); + std::string symbolText = "Section " + symbol + "-" + symbol; + if (symbolText.compare(Label.getValue())) { + Label.setValue(symbolText.c_str()); + } + + + touch(); + return DrawView::execute(); +} + +gp_Pln DrawViewSection::getSectionPlane() const +{ + Base::Vector3d plnPnt = SectionOrigin.getValue(); + Base::Vector3d plnNorm = SectionNormal.getValue(); + + return gp_Pln(gp_Pnt(plnPnt.x, plnPnt.y, plnPnt.z), gp_Dir(plnNorm.x, plnNorm.y, plnNorm.z)); +} + +//! tries to find the intersection of the section plane with the shape giving a collection of planar faces +TopoDS_Compound DrawViewSection::findSectionPlaneIntersections(const TopoDS_Shape& shape) +{ + TopoDS_Compound result; + if(shape.IsNull()){ + Base::Console().Log("DrawViewSection::getSectionSurface - Sectional View shape is Empty\n"); + return result; + } + + gp_Pln plnSection = getSectionPlane(); + BRep_Builder builder; + builder.MakeCompound(result); + + TopExp_Explorer expFaces(shape, TopAbs_FACE); + int i; + int dbAdded = 0; + for (i = 1 ; expFaces.More(); expFaces.Next(), i++) { + const TopoDS_Face& face = TopoDS::Face(expFaces.Current()); + BRepAdaptor_Surface adapt(face); + if (adapt.GetType() == GeomAbs_Plane){ + gp_Pln plnFace = adapt.Plane(); + + if(plnSection.Contains(plnFace.Location(), Precision::Confusion()) && + plnFace.Axis().IsParallel(plnSection.Axis(), Precision::Angular())) { + dbAdded++; + builder.Add(result, face); + } + } + } + return result; +} + +//! get display geometry for Section faces +std::vector DrawViewSection::getFaceGeometry() +{ + std::vector result; + TopoDS_Compound c = sectionFaces; + TopExp_Explorer faces(c, TopAbs_FACE); + for (; faces.More(); faces.Next()) { + TechDrawGeometry::Face* f = new TechDrawGeometry::Face(); + const TopoDS_Face& face = TopoDS::Face(faces.Current()); + TopExp_Explorer wires(face, TopAbs_WIRE); + for (; wires.More(); wires.Next()) { + TechDrawGeometry::Wire* w = new TechDrawGeometry::Wire(); + const TopoDS_Wire& wire = TopoDS::Wire(wires.Current()); + TopExp_Explorer edges(wire, TopAbs_EDGE); + for (; edges.More(); edges.Next()) { + const TopoDS_Edge& edge = TopoDS::Edge(edges.Current()); + //dumpEdge("edge",edgeCount,edge); + TechDrawGeometry::BaseGeom* base = TechDrawGeometry::BaseGeom::baseFactory(edge); + w->geoms.push_back(base); + } + f->wires.push_back(w); + } + result.push_back(f); + } + return result; +} + +//! project a single face using HLR - used for section faces +TopoDS_Face DrawViewSection::projectFace(const TopoDS_Shape &face, + gp_Pnt faceCenter, + const Base::Vector3d &direction, + const Base::Vector3d &xaxis) +{ + if(face.IsNull()) { + throw Base::Exception("DrawViewSection::projectFace - input Face is NULL"); + } + + gp_Ax2 transform; + transform = gp_Ax2(faceCenter, + gp_Dir(direction.x, direction.y, direction.z), + gp_Dir(xaxis.x, xaxis.y, xaxis.z)); + + HLRBRep_Algo *brep_hlr = new HLRBRep_Algo(); + brep_hlr->Add(face); + + HLRAlgo_Projector projector( transform ); + brep_hlr->Projector(projector); + brep_hlr->Update(); + brep_hlr->Hide(); + + HLRBRep_HLRToShape hlrToShape(brep_hlr); + TopoDS_Shape hardEdges = hlrToShape.VCompound(); +// TopoDS_Shape outEdges = hlrToShape.OutLineVCompound(); + std::vector faceEdges; + TopExp_Explorer expl(hardEdges, TopAbs_EDGE); + int i; + for (i = 1 ; expl.More(); expl.Next(),i++) { + const TopoDS_Edge& edge = TopoDS::Edge(expl.Current()); + if (edge.IsNull()) { + Base::Console().Log("INFO - DVS::projectFace - hard edge: %d is NULL\n",i); + continue; + } + faceEdges.push_back(edge); + } + //if edge is both hard & outline, it will be duplicated? are hard edges enough? +// TopExp_Explorer expl2(outEdges, TopAbs_EDGE); +// for (i = 1 ; expl2.More(); expl2.Next(),i++) { +// const TopoDS_Edge& edge = TopoDS::Edge(expl2.Current()); +// if (edge.IsNull()) { +// Base::Console().Log("INFO - GO::projectFace - outline edge: %d is NULL\n",i); +// continue; +// } +// bool addEdge = true; +// //is edge already in faceEdges? maybe need to use explorer for this for IsSame to work? +// for (auto& e:faceEdges) { +// if (e.IsPartner(edge)) { +// addEdge = false; +// Base::Console().Message("TRACE - DVS::projectFace - skipping an edge 1\n"); +// } +// } +// expl.ReInit(); +// for (; expl.More(); expl.Next()){ +// const TopoDS_Edge& eHard = TopoDS::Edge(expl.Current()); +// if (eHard.IsPartner(edge)) { +// addEdge = false; +// Base::Console().Message("TRACE - DVS::projectFace - skipping an edge 2\n"); +// } +// } +// if (addEdge) { +// faceEdges.push_back(edge); +// } +// } + +// std::vector uniqueVert = makeUniqueVList(faceEdges); +// std::vector walkerEdges = makeWalkerEdges(faceEdges,uniqueVert); + +//recreate the wires for this single face + EdgeWalker ew; + ew.loadEdges(faceEdges); + ew.perform(); + std::vector fw = ew.getResultNoDups(); + +// EdgeWalker ew; +// ew.setSize(uniqueVert.size()); +// ew.loadEdges(walkerEdges); +// ew.perform(); +// facelist result = ew.getResult(); + +//>>>>>>>>. result = TechDraw::EdgeWalker::removeDuplicateFaces(result); + +// facelist::iterator iFace = result.begin(); + +// std::vector fw; +// int dbi = 0; +// for (;iFace != result.end(); iFace++,dbi++) { +// edgelist::iterator iEdge = (*iFace).begin(); +// std::vector fe; +// for (;iEdge != (*iFace).end(); iEdge++) { +// fe.push_back(faceEdges.at((*iEdge).idx)); +// } +// TopoDS_Wire w = makeCleanWire(fe); +// fw.push_back(w); +// } + + TopoDS_Face projectedFace; + + if (!fw.empty()) { + std::vector sortedWires = ew.sortStrip(fw, true); + if (sortedWires.empty()) { + return projectedFace; + } + //TODO: should have the same size checking logic as DVP? + //remove the largest wire (OuterWire of graph) ??? but duplicates have been removed? only do this if a mosaic? + //sortedWires.erase(sortedWires.begin()); + + BRepBuilderAPI_MakeFace mkFace(sortedWires.front(),true); //true => only want planes? + std::vector::iterator itWire = ++sortedWires.begin(); //starting with second face + for (; itWire != sortedWires.end(); itWire++) { + mkFace.Add(*itWire); + } + projectedFace = mkFace.Face(); + } + + return projectedFace; +} + +//this should really be in BoundBox.h +bool DrawViewSection::isReallyInBox (const Base::Vector3d v, const Base::BoundBox3d bb) const +{ + if (v.x <= bb.MinX || v.x >= bb.MaxX) + return false; + if (v.y <= bb.MinY || v.y >= bb.MaxY) + return false; + if (v.z <= bb.MinZ || v.z >= bb.MaxZ) + return false; + return true; +} + + +// Python Drawing feature --------------------------------------------------------- + +namespace App { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(TechDraw::DrawViewSectionPython, TechDraw::DrawViewSection) +template<> const char* TechDraw::DrawViewSectionPython::getViewProviderName(void) const { + return "TechDrawGui::ViewProviderDrawingView"; +} +/// @endcond + +// explicit template instantiation +template class TechDrawExport FeaturePythonT; +} diff --git a/src/Mod/TechDraw/App/EdgeWalker.cpp b/src/Mod/TechDraw/App/EdgeWalker.cpp index b717271a8..81f42a44b 100644 --- a/src/Mod/TechDraw/App/EdgeWalker.cpp +++ b/src/Mod/TechDraw/App/EdgeWalker.cpp @@ -27,9 +27,24 @@ #include "PreCompiled.h" +#ifndef _PreComp_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif #include +#include "DrawUtil.h" #include "EdgeWalker.h" using namespace TechDraw; @@ -47,22 +62,22 @@ void edgeVisitor::next_edge(Edge e) we.v1 = s; we.v2 = t; we.idx = get(edge_index,m_g,e); - faceEdges.push_back(we); + wireEdges.push_back(we); } void edgeVisitor::begin_face() { - faceEdges.clear(); + wireEdges.clear(); } void edgeVisitor::end_face() { - graphFaces.push_back(faceEdges); + graphWires.push_back(wireEdges); } -TechDraw::facelist edgeVisitor::getResult(void) +TechDraw::ewWireList edgeVisitor::getResult(void) { - return graphFaces; + return graphWires; } void edgeVisitor::setGraph(TechDraw::graph& g) @@ -90,6 +105,15 @@ bool EdgeWalker::loadEdges(std::vector edges) return true; } +bool EdgeWalker::loadEdges(std::vector edges) +{ + std::vector verts = makeUniqueVList(edges); + setSize(verts.size()); + std::vector we = makeWalkerEdges(edges, verts); + saveInEdges = edges; + + return loadEdges(we); +} bool EdgeWalker::setSize(int size) { m_g.clear(); @@ -122,28 +146,153 @@ bool EdgeWalker::perform() return true; } -facelist EdgeWalker::getResult() +ewWireList EdgeWalker::getResult() { - TechDraw::facelist result = m_eV.getResult(); - return result; + ewWireList result = m_eV.getResult(); + // result is a list of many wires each of which is a list of many WE + return result; } -//static methods -bool EdgeWalker::orderEdges(WalkerEdge i, WalkerEdge j) +std::vector EdgeWalker::getResultWires() +{ + ewWireList result = m_eV.getResult(); + + std::vector::iterator iWire = result.wires.begin(); // a WE within [WE] + std::vector fw; + for (;iWire != result.wires.end(); iWire++) { + std::vector::iterator iEdge = (*iWire).wedges.begin(); + std::vector topoEdges; + for (;iEdge != (*iWire).wedges.end(); iEdge++) { + TopoDS_Edge e = saveInEdges.at((*iEdge).idx); + topoEdges.push_back(e); + } + TopoDS_Wire w = makeCleanWire(topoEdges); //make 1 clean wire from its edges + fw.push_back(w); + } + return fw; +} + +std::vector EdgeWalker::getResultNoDups() +{ + ewWireList result = m_eV.getResult(); + result = result.removeDuplicates(); + + std::vector::iterator iWire = result.wires.begin(); + std::vector fw; + for (;iWire != result.wires.end(); iWire++) { + std::vector::iterator iEdge = (*iWire).wedges.begin(); + std::vector topoEdges; + for (;iEdge != (*iWire).wedges.end(); iEdge++) { + TopoDS_Edge e = saveInEdges.at((*iEdge).idx); + topoEdges.push_back(e); + } + TopoDS_Wire w = makeCleanWire(topoEdges); //make 1 clean wire from its edges + fw.push_back(w); + } + return fw; +} + + +//! make a clean wire with sorted, oriented, connected, etc edges +TopoDS_Wire EdgeWalker::makeCleanWire(std::vector edges, double tol) +{ + TopoDS_Wire result; + BRepBuilderAPI_MakeWire mkWire; + ShapeFix_ShapeTolerance sTol; + Handle(ShapeExtend_WireData) wireData = new ShapeExtend_WireData(); + + for (auto e:edges) { + wireData->Add(e); + } + + Handle(ShapeFix_Wire) fixer = new ShapeFix_Wire; + fixer->Load(wireData); + fixer->Perform(); + fixer->FixReorder(); + fixer->SetMaxTolerance(tol); + fixer->ClosedWireMode() = Standard_True; + fixer->FixConnected(Precision::Confusion()); + fixer->FixClosed(Precision::Confusion()); + + 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 = mkWire.Wire(); + return result; +} + +std::vector EdgeWalker:: makeUniqueVList(std::vector edges) +{ + std::vector uniqueVert; + for(auto& e:edges) { + TopoDS_Vertex v1 = TopExp::FirstVertex(e); + TopoDS_Vertex v2 = TopExp::LastVertex(e); + bool addv1 = true; + bool addv2 = true; + for (auto v:uniqueVert) { + if (DrawUtil::isSamePoint(v,v1)) + addv1 = false; + if (DrawUtil::isSamePoint(v,v2)) + addv2 = false; + } + if (addv1) + uniqueVert.push_back(v1); + if (addv2) + uniqueVert.push_back(v2); + } + return uniqueVert; +} + +//!make WalkerEdges (unique Vertex index pairs) from edge list +std::vector EdgeWalker::makeWalkerEdges(std::vector edges, + std::vector verts) +{ + std::vector walkerEdges; + for (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); + WalkerEdge we; + we.v1 = v1dx; + we.v2 = v2dx; + walkerEdges.push_back(we); + } + return walkerEdges; +} + +int EdgeWalker::findUniqueVert(TopoDS_Vertex vx, std::vector &uniqueVert) +{ + int idx = 0; + int result = 0; + for(auto& v:uniqueVert) { //we're always going to find vx, right? + if (DrawUtil::isSamePoint(v,vx)) { + result = idx; + break; + } + idx++; + } //if idx >= uniqueVert.size() TARFU + return result; +} + +/*static*/ bool WalkerEdge::weCompare(WalkerEdge i, WalkerEdge j) { return (i.idx < j.idx); } -bool EdgeWalker::isEqual(edgelist el1, edgelist el2) +bool ewWire::isEqual(ewWire w2) { bool result = true; - if (el1.size() != el2.size()) { + if (wedges.size() != w2.wedges.size()) { result = false; } else { - std::sort(el1.begin(),el1.end(),orderEdges); - std::sort(el2.begin(),el2.end(),orderEdges); - for (unsigned int i = 0; i < el1.size(); i ++) { - if (el1.at(i).idx != el2.at(i).idx) { + std::sort(wedges.begin(),wedges.end(),WalkerEdge::weCompare); + std::sort(w2.wedges.begin(),w2.wedges.end(),WalkerEdge::weCompare); + for (unsigned int i = 0; i < w2.wedges.size(); i ++) { + if (wedges.at(i).idx != w2.wedges.at(i).idx) { result = false; break; } @@ -152,23 +301,122 @@ bool EdgeWalker::isEqual(edgelist el1, edgelist el2) return result; } -//check faces that use the same set of edges, but maybe in a different order. -facelist EdgeWalker::removeDuplicateFaces(facelist in) +void ewWire::push_back(WalkerEdge w) { - facelist result; - result.push_back(*(in.begin())); //save the first edgelist - facelist::iterator iFace = (in.begin()) + 1; //starting with second - for (; iFace != in.end(); iFace++) { + wedges.push_back(w); +} + +//check wirelist for wires that use the same set of edges, but maybe in a different order. +ewWireList ewWireList::removeDuplicates() +{ + ewWireList result; + result.push_back(*(wires.begin())); //save the first ewWire + std::vector::iterator iWire = (wires.begin()) + 1; //starting with second + for (; iWire != wires.end(); iWire++) { bool addToResult = true; - for (auto& e:result) { - if (isEqual((*iFace),e)) { //already in result? + for (auto& w:result.wires) { + if ((*iWire).isEqual(w)) { //already in result? addToResult = false; break; } } if (addToResult) { - result.push_back((*iFace)); + result.push_back((*iWire)); } } return result; } + +void ewWireList::push_back(ewWire w) +{ + wires.push_back(w); +} + + +std::vector EdgeWalker::sortStrip(std::vector fw, bool includeBiggest) +{ + std::vector sortedWires = sortWiresBySize(fw,false); //biggest 1st + if (!sortedWires.size()) { + Base::Console().Log("INFO - DVP::extractFaces - no sorted Wires!\n"); + return sortedWires; // might happen in the middle of changes? + } + + if (includeBiggest) { + return sortedWires; // all the wires + } + + //remove the largest wire (OuterWire of graph) wf: still not convinced we should do this in all cases. + Bnd_Box bigBox; + if (sortedWires.size() && !sortedWires.front().IsNull()) { + BRepBndLib::Add(sortedWires.front(), bigBox); + bigBox.SetGap(0.0); + } + std::vector toBeChecked; + std::vector::iterator it = sortedWires.begin() + 1; + for (; it != sortedWires.end(); it++) { + if (!(*it).IsNull()) { + Bnd_Box littleBox; + BRepBndLib::Add((*it), littleBox); + littleBox.SetGap(0.0); + if (bigBox.SquareExtent() > littleBox.SquareExtent()) { + break; + } else { + auto position = std::distance( sortedWires.begin(), it ); //get an index from iterator + toBeChecked.push_back(position); + } + } + } + //unfortuneately, faces can have same bbox, but not be same size. need to weed out biggest + if (toBeChecked.size() == 0) { + //nobody had as big a bbox as first element of sortedWires + sortedWires.erase(sortedWires.begin()); + } else if (toBeChecked.size() > 0) { + BRepBuilderAPI_MakeFace mkFace(sortedWires.front()); + const TopoDS_Face& face = mkFace.Face(); + GProp_GProps props; + BRepGProp::SurfaceProperties(face, props); + double bigArea = props.Mass(); + unsigned int bigIndex = 0; + for (unsigned int idx = 1; idx < toBeChecked.size(); idx++) { + BRepBuilderAPI_MakeFace mkFace2(sortedWires.at(idx)); + const TopoDS_Face& face2 = mkFace2.Face(); + BRepGProp::SurfaceProperties(face2, props); + double area = props.Mass(); + if (area > bigArea) { + bigArea = area; + bigIndex = idx; + } + } + sortedWires.erase(sortedWires.begin() + bigIndex); + } + return sortedWires; +} + +//sort wires in order of bbox diagonal. +std::vector EdgeWalker::sortWiresBySize(std::vector& w, bool ascend) +{ + std::vector wires = w; + std::sort(wires.begin(), wires.end(), EdgeWalker::wireCompare); + if (ascend) { + std::reverse(wires.begin(),wires.end()); + } + return wires; +} + +//! return true if w1 bbox is bigger than w2 bbox +//NOTE: this won't necessarily sort the OuterWire correctly (ex smaller wire, same bbox) +/*static*/bool EdgeWalker::wireCompare(const TopoDS_Wire& w1, const TopoDS_Wire& w2) +{ + Bnd_Box box1, box2; + if (!w1.IsNull()) { + BRepBndLib::Add(w1, box1); + box1.SetGap(0.0); + } + + if (!w2.IsNull()) { + BRepBndLib::Add(w2, box2); + box2.SetGap(0.0); + } + + return box1.SquareExtent() > box2.SquareExtent(); +} diff --git a/src/Mod/TechDraw/App/EdgeWalker.h b/src/Mod/TechDraw/App/EdgeWalker.h index 718ae4914..cee5557c3 100644 --- a/src/Mod/TechDraw/App/EdgeWalker.h +++ b/src/Mod/TechDraw/App/EdgeWalker.h @@ -39,6 +39,10 @@ #include #include +#include +#include +#include + namespace TechDraw { using namespace boost; @@ -51,14 +55,35 @@ typedef adjacency_list > graph; -struct WalkerEdge { +class WalkerEdge +{ +public: + static bool weCompare(WalkerEdge i, WalkerEdge j); + std::size_t v1; std::size_t v2; int idx; }; -typedef std::vector edgelist; -typedef std::vector facelist ; +class ewWire +{ +public: + bool isEqual(ewWire w); + + std::vector wedges; //[WE] representing 1 wire + void push_back(WalkerEdge w); + void clear() {wedges.clear();}; +}; + +class ewWireList +{ +public: + ewWireList removeDuplicates(); + + std::vector wires; + void push_back(ewWire e); +}; + class edgeVisitor : public planar_face_traversal_visitor @@ -68,12 +93,12 @@ public: void next_edge(Edge e); void begin_face(); void end_face(); - facelist getResult(void); + ewWireList getResult(void); //a list of many wires void setGraph(graph& g); private: - TechDraw::edgelist faceEdges; - TechDraw::facelist graphFaces; + ewWire wireEdges; + ewWireList graphWires; TechDraw::graph m_g; }; @@ -84,18 +109,31 @@ public: virtual ~EdgeWalker(); bool loadEdges(std::vector edges); + bool loadEdges(std::vector edges); bool setSize(int size); bool perform(); - facelist getResult(); - static bool orderEdges(WalkerEdge i, WalkerEdge j); - static bool isEqual(edgelist el1, edgelist el2); - static facelist removeDuplicateFaces(facelist in); + ewWireList getResult(); + std::vector getResultWires(); + std::vector getResultNoDups(); + + std::vector makeUniqueVList(std::vector edges); + std::vector makeWalkerEdges(std::vector edges, + std::vector verts); + int findUniqueVert(TopoDS_Vertex vx, std::vector &uniqueVert); + std::vector sortStrip(std::vector fw, bool includeBiggest); + std::vector sortWiresBySize(std::vector& w, bool reverse = false); + TopoDS_Wire makeCleanWire(std::vector edges, double tol = 0.10); + + +protected: + static bool wireCompare(const TopoDS_Wire& w1, const TopoDS_Wire& w2); + std::vector saveInEdges; private: edgeVisitor m_eV; TechDraw::graph m_g; }; -} //end namespace +} //end namespace TechDraw #endif //TECHDRAW_EDGEWALKER_H