From e898789cba6f0c2a967d46d8bac6eb4bc532f0f1 Mon Sep 17 00:00:00 2001 From: DeepSOIC Date: Sun, 25 Sep 2016 18:26:47 +0300 Subject: [PATCH] Part: Face: use facemakers For old documents, default to FaceMakerCheese. For newly created objects, use FaceMakerBullseye --- src/Mod/Part/App/FeatureFace.cpp | 149 +++++-------------------------- src/Mod/Part/App/FeatureFace.h | 9 +- 2 files changed, 26 insertions(+), 132 deletions(-) diff --git a/src/Mod/Part/App/FeatureFace.cpp b/src/Mod/Part/App/FeatureFace.cpp index 916fa0dc1..0a95d08c2 100644 --- a/src/Mod/Part/App/FeatureFace.cpp +++ b/src/Mod/Part/App/FeatureFace.cpp @@ -44,6 +44,7 @@ #include #include "FeatureFace.h" +#include "FaceMaker.h" #include @@ -55,26 +56,37 @@ PROPERTY_SOURCE(Part::Face, Part::Feature) Face::Face() { ADD_PROPERTY(Sources,(0)); + ADD_PROPERTY(FaceMakerClass,("Part::FaceMakerCheese"));//default value here is for legacy documents. Default for new objects is set in setupObject. Sources.setSize(0); } short Face::mustExecute() const { + if (FaceMakerClass.isTouched()) + return 1; if (Sources.isTouched()) return 1; return Part::Feature::mustExecute(); } +void Face::setupObject() +{ + this->FaceMakerClass.setValue("Part::FaceMakerBullseye"); + Feature::setupObject(); +} + App::DocumentObjectExecReturn *Face::execute(void) { std::vector links = Sources.getValues(); if (links.empty()) return new App::DocumentObjectExecReturn("No shapes linked"); - std::vector wires; + std::unique_ptr fm_instance = FaceMaker::ConstructFromType(this->FaceMakerClass.getValue()); + FaceMaker* facemaker = &(*(fm_instance)); + for (std::vector::iterator it = links.begin(); it != links.end(); ++it) { - if (!(*it && (*it)->isDerivedFrom(Part::Part2DObject::getClassTypeId()))) - return new App::DocumentObjectExecReturn("Linked object is not a Sketch or Part2DObject"); + if (!(*it && (*it)->isDerivedFrom(Part::Feature::getClassTypeId()))) + return new App::DocumentObjectExecReturn("Linked object is not a Part object (has no Shape)."); TopoDS_Shape shape = static_cast(*it)->Shape.getShape().getShape(); if (shape.IsNull()) return new App::DocumentObjectExecReturn("Linked shape object is empty"); @@ -82,139 +94,26 @@ App::DocumentObjectExecReturn *Face::execute(void) // this is a workaround for an obscure OCC bug which leads to empty tessellations // for some faces. Making an explicit copy of the linked shape seems to fix it. // The error only happens when re-computing the shape. - if (!this->Shape.getValue().IsNull()) { + /*if (!this->Shape.getValue().IsNull()) { BRepBuilderAPI_Copy copy(shape); shape = copy.Shape(); if (shape.IsNull()) return new App::DocumentObjectExecReturn("Linked shape object is empty"); - } + }*/ - TopExp_Explorer ex; - for (ex.Init(shape, TopAbs_WIRE); ex.More(); ex.Next()) { - wires.push_back(TopoDS::Wire(ex.Current())); - } + if(links.size() == 1 && shape.ShapeType() == TopAbs_COMPOUND) + facemaker->useCompound(TopoDS::Compound(shape)); + else + facemaker->addShape(shape); } - if (wires.empty()) // there can be several wires - return new App::DocumentObjectExecReturn("Linked shape object is not a wire"); + facemaker->Build(); - TopoDS_Shape aFace = makeFace(wires); + TopoDS_Shape aFace = facemaker->Shape(); if (aFace.IsNull()) - return new App::DocumentObjectExecReturn("Creating a face from sketch failed"); + return new App::DocumentObjectExecReturn("Creating face failed (null shape result)"); this->Shape.setValue(aFace); return App::DocumentObject::StdReturn; } -// sort bounding boxes according to diagonal length -class Face::Wire_Compare { -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(); - } -}; - -TopoDS_Shape Face::makeFace(std::list& wires) const -{ - BRepBuilderAPI_MakeFace mkFace(wires.front()); - const TopoDS_Face& face = mkFace.Face(); - if (face.IsNull()) - return face; - gp_Dir axis(0,0,1); - BRepAdaptor_Surface adapt(face); - if (adapt.GetType() == GeomAbs_Plane) { - axis = adapt.Plane().Axis().Direction(); - } - - wires.pop_front(); - for (std::list::iterator it = wires.begin(); it != wires.end(); ++it) { - BRepBuilderAPI_MakeFace mkInnerFace(*it); - const TopoDS_Face& inner_face = mkInnerFace.Face(); - gp_Dir inner_axis(0,0,1); - BRepAdaptor_Surface adapt(inner_face); - if (adapt.GetType() == GeomAbs_Plane) { - inner_axis = adapt.Plane().Axis().Direction(); - } - // It seems that orientation is always 'Forward' and we only have to reverse - // if the underlying plane have opposite normals. - if (axis.Dot(inner_axis) < 0) - it->Reverse(); - mkFace.Add(*it); - } - return mkFace.Face(); -} - -TopoDS_Shape Face::makeFace(const std::vector& w) const -{ - if (w.empty()) - return TopoDS_Shape(); - - //FIXME: Need a safe method to sort wire that the outermost one comes last - // Currently it's done with the diagonal lengths of the bounding boxes - std::vector wires = w; - std::sort(wires.begin(), wires.end(), Wire_Compare()); - std::list wire_list; - wire_list.insert(wire_list.begin(), wires.rbegin(), wires.rend()); - - // separate the wires into several independent faces - std::list< std::list > sep_wire_list; - while (!wire_list.empty()) { - std::list sep_list; - TopoDS_Wire wire = wire_list.front(); - wire_list.pop_front(); - sep_list.push_back(wire); - - Bnd_Box box; - BRepBndLib::Add(wire, box); - box.SetGap(0.0); - - std::list::iterator it = wire_list.begin(); - while (it != wire_list.end()) { - Bnd_Box box2; - BRepBndLib::Add(*it, box2); - box2.SetGap(0.0); - if (!box.IsOut(box2)) { - sep_list.push_back(*it); - it = wire_list.erase(it); - } - else { - ++it; - } - } - - sep_wire_list.push_back(sep_list); - } - - if (sep_wire_list.size() == 1) { - std::list& wires = sep_wire_list.front(); - return makeFace(wires); - } - else if (sep_wire_list.size() > 1) { - TopoDS_Compound comp; - BRep_Builder builder; - builder.MakeCompound(comp); - for (std::list< std::list >::iterator it = sep_wire_list.begin(); it != sep_wire_list.end(); ++it) { - TopoDS_Shape aFace = makeFace(*it); - if (!aFace.IsNull()) - builder.Add(comp, aFace); - } - - return comp; - } - else { - return TopoDS_Shape(); // error - } -} - diff --git a/src/Mod/Part/App/FeatureFace.h b/src/Mod/Part/App/FeatureFace.h index 29e96c1fa..c2c1bdac2 100644 --- a/src/Mod/Part/App/FeatureFace.h +++ b/src/Mod/Part/App/FeatureFace.h @@ -37,6 +37,7 @@ public: Face(); App::PropertyLinkList Sources; + App::PropertyString FaceMakerClass; /** @name methods override feature */ //@{ @@ -47,14 +48,8 @@ public: const char* getViewProviderName(void) const { return "PartGui::ViewProviderFace"; } + void setupObject() override; //@} - -protected: - TopoDS_Shape makeFace(const std::vector&) const; - TopoDS_Shape makeFace(std::list&) const; // for internal use only - -private: - class Wire_Compare; }; } //namespace Part