diff --git a/src/Mod/Part/App/FeatureFace.cpp b/src/Mod/Part/App/FeatureFace.cpp
index 916fa0dc17..0a95d08c2f 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 29e96c1fab..c2c1bdac2a 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