diff --git a/src/Mod/Surface/App/FeatureFilling.cpp b/src/Mod/Surface/App/FeatureFilling.cpp index 172e01f6f9..b7a7abd1ca 100644 --- a/src/Mod/Surface/App/FeatureFilling.cpp +++ b/src/Mod/Surface/App/FeatureFilling.cpp @@ -46,42 +46,52 @@ PROPERTY_SOURCE(Surface::Filling, Part::Spline) Filling::Filling() { - ADD_PROPERTY_TYPE(Border,(0,""), "Filling", App::Prop_None, "Border Edges (C0 is required for edges without a corresponding face)"); - ADD_PROPERTY_TYPE(BorderFaces,(0,""), "Filling", App::Prop_None, "Border Faces"); - ADD_PROPERTY_TYPE(OrderBorderFaces,(-1), "Filling", App::Prop_None, "Order of constraint on border faces (C0, G1 and G2 are possible)"); + ADD_PROPERTY_TYPE(BoundaryEdges,(0,""), "Filling", App::Prop_None, "Boundary Edges (C0 is required for edges without a corresponding face)"); + ADD_PROPERTY_TYPE(BoundaryFaces,(""), "Filling", App::Prop_None, "Boundary Faces"); + ADD_PROPERTY_TYPE(BoundaryOrder,(-1), "Filling", App::Prop_None, "Order of constraint on boundary faces (C0, G1 and G2 are possible)"); - ADD_PROPERTY_TYPE(Curves,(0,""), "Filling", App::Prop_None, "Other Constraint Curves (C0 is required for edges without a corresponding face)"); - ADD_PROPERTY_TYPE(CurveFaces,(0,""), "Filling", App::Prop_None, "Curve Faces"); - ADD_PROPERTY_TYPE(OrderCurveFaces,(-1), "Filling", App::Prop_None, "Order of constraint on curve faces (C0, G1 and G2 are possible)"); + ADD_PROPERTY_TYPE(UnboundEdges,(0,""), "Filling", App::Prop_None, "Unbound constraint edges (C0 is required for edges without a corresponding face)"); + ADD_PROPERTY_TYPE(UnboundFaces,(""), "Filling", App::Prop_None, "Unbound constraint faces"); + ADD_PROPERTY_TYPE(UnboundOrder,(-1), "Filling", App::Prop_None, "Order of constraint on curve faces (C0, G1 and G2 are possible)"); ADD_PROPERTY_TYPE(FreeFaces,(0,""), "Filling", App::Prop_None, "Free constraint on a face"); - ADD_PROPERTY_TYPE(OrderFreeFaces,(0), "Filling", App::Prop_None, "Order of constraint on free faces"); + ADD_PROPERTY_TYPE(FreeOrder,(0), "Filling", App::Prop_None, "Order of constraint on free faces"); ADD_PROPERTY_TYPE(Points,(0,""), "Filling", App::Prop_None, "Constraint Points (on Surface)"); ADD_PROPERTY_TYPE(InitialFace,(0), "Filling", App::Prop_None, "Initial surface to use"); ADD_PROPERTY_TYPE(Degree,(3), "Filling", App::Prop_None, "Starting degree"); - ADD_PROPERTY_TYPE(PointsOnCurve,(3), "Filling", App::Prop_None, "Number of points on an edge for constraint"); + ADD_PROPERTY_TYPE(PointsOnCurve,(15), "Filling", App::Prop_None, "Number of points on an edge for constraint"); ADD_PROPERTY_TYPE(Iterations,(2), "Filling", App::Prop_None, "Number of iterations"); ADD_PROPERTY_TYPE(Anisotropy,(false), "Filling", App::Prop_None, "Anisotropy"); ADD_PROPERTY_TYPE(Tolerance2d,(0.00001), "Filling", App::Prop_None, "2D Tolerance"); ADD_PROPERTY_TYPE(Tolerance3d,(0.0001), "Filling", App::Prop_None, "3D Tolerance"); - ADD_PROPERTY_TYPE(TolAngular,(0.001), "Filling", App::Prop_None, "G1 tolerance"); - ADD_PROPERTY_TYPE(TolCurvature,(0.01), "Filling", App::Prop_None, "G2 tolerance"); + ADD_PROPERTY_TYPE(TolAngular,(0.01), "Filling", App::Prop_None, "G1 tolerance"); + ADD_PROPERTY_TYPE(TolCurvature,(0.1), "Filling", App::Prop_None, "G2 tolerance"); ADD_PROPERTY_TYPE(MaximumDegree,(8), "Filling", App::Prop_None, "Maximum curve degree"); - ADD_PROPERTY_TYPE(MaximumSegments,(10000), "Filling", App::Prop_None, "Maximum number of segments"); + ADD_PROPERTY_TYPE(MaximumSegments,(9), "Filling", App::Prop_None, "Maximum number of segments"); + + BoundaryEdges.setSize(0); + BoundaryFaces.setSize(0); + BoundaryOrder.setSize(0); + UnboundEdges.setSize(0); + UnboundFaces.setSize(0); + UnboundOrder.setSize(0); + FreeFaces.setSize(0); + FreeOrder.setSize(0); + Points.setSize(0); } short Filling::mustExecute() const { - if (Border.isTouched() || - BorderFaces.isTouched() || - OrderBorderFaces.isTouched() || - Curves.isTouched() || - CurveFaces.isTouched() || - OrderCurveFaces.isTouched() || + if (BoundaryEdges.isTouched() || + BoundaryFaces.isTouched() || + BoundaryOrder.isTouched() || + UnboundEdges.isTouched() || + UnboundFaces.isTouched() || + UnboundOrder.isTouched() || FreeFaces.isTouched() || - OrderFreeFaces.isTouched() || + FreeOrder.isTouched() || Points.isTouched() || InitialFace.isTouched() || Degree.isTouched() || @@ -100,39 +110,61 @@ short Filling::mustExecute() const void Filling::addConstraints(BRepFill_Filling& builder, const App::PropertyLinkSubList& edges, - const App::PropertyLinkSubList& faces, + const App::PropertyStringList& faces, const App::PropertyIntegerList& orders, Standard_Boolean bnd) { auto edge_obj = edges.getValues(); auto edge_sub = edges.getSubValues(); - auto face_obj = faces.getValues(); - auto face_sub = faces.getSubValues(); + auto face_sub = faces.getValues(); auto contvals = orders.getValues(); - // tmp. workaround - if (edge_obj.size() != contvals.size()) { - contvals.resize(edge_obj.size()); + // if the number of continuities doesn't match then fall back to C0 + if (edge_sub.size() != contvals.size()) { + contvals.resize(edge_sub.size()); std::fill(contvals.begin(), contvals.end(), static_cast(GeomAbs_C0)); } - if (edge_obj.size() == edge_sub.size() && - edge_obj.size() == contvals.size()) { + // if the number of faces doesn't match then fall back to empty strings + // an empty face string indicates that there is no face associated to an edge + if (face_sub.size() != edge_sub.size()) { + face_sub.resize(edge_obj.size()); + std::fill(face_sub.begin(), face_sub.end(), std::string()); + } + + if (edge_obj.size() == edge_sub.size()) { for (std::size_t index = 0; index < edge_obj.size(); index++) { + // get the part object App::DocumentObject* obj = edge_obj[index]; const std::string& sub = edge_sub[index]; + if (obj && obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { + // get the sub-edge of the part's shape const Part::TopoShape& shape = static_cast(obj)->Shape.getShape(); TopoDS_Shape edge = shape.getSubShape(sub.c_str()); if (!edge.IsNull() && edge.ShapeType() == TopAbs_EDGE) { GeomAbs_Shape cont = static_cast(contvals[index]); - if (cont == GeomAbs_C0) { + + // check for an adjacent face of the edge + std::string subFace = face_sub[index]; + + // edge doesn't have set an adjacent face + if (subFace.empty()) { builder.Add(TopoDS::Edge(edge), cont, bnd); } else { - builder.Add(TopoDS::Edge(edge), cont, bnd); + TopoDS_Shape face = shape.getSubShape(subFace.c_str()); + if (!face.IsNull() && face.ShapeType() == TopAbs_FACE) { + builder.Add(TopoDS::Edge(edge), TopoDS::Face(face), cont, bnd); + } + else { + Standard_Failure::Raise("Sub-shape is not a face"); + } } } + else { + Standard_Failure::Raise("Sub-shape is not an edge"); + } } } } @@ -141,6 +173,7 @@ void Filling::addConstraints(BRepFill_Filling& builder, } } +// Add free support faces with their continuities void Filling::addConstraints(BRepFill_Filling& builder, const App::PropertyLinkSubList& faces, const App::PropertyIntegerList& orders) @@ -161,6 +194,9 @@ void Filling::addConstraints(BRepFill_Filling& builder, GeomAbs_Shape cont = static_cast(contvals[index]); builder.Add(TopoDS::Face(face), cont); } + else { + Standard_Failure::Raise("Sub-shape is not a face"); + } } } } @@ -207,7 +243,7 @@ App::DocumentObjectExecReturn *Filling::execute(void) BRepFill_Filling builder(degree, ptsoncurve, numIter, anisotropy, tol2d, tol3d, tolG1, tolG2, maxdeg, maxseg); - if ((Border.getSize()) < 1) { + if ((BoundaryEdges.getSize()) < 1) { return new App::DocumentObjectExecReturn("Border must have at least one curve defined."); } @@ -226,16 +262,16 @@ App::DocumentObjectExecReturn *Filling::execute(void) } // Add the constraints of border curves/faces (bound) - addConstraints(builder, Border, BorderFaces, OrderBorderFaces, Standard_True); + addConstraints(builder, BoundaryEdges, BoundaryFaces, BoundaryOrder, Standard_True); - // Add additional curves constraints if available (unbound) - if (Curves.getSize() > 0) { - addConstraints(builder, Curves, CurveFaces, OrderCurveFaces, Standard_False); + // Add additional edge constraints if available (unbound) + if (UnboundEdges.getSize() > 0) { + addConstraints(builder, UnboundEdges, UnboundFaces, UnboundOrder, Standard_False); } // Add additional constraint on free faces if (FreeFaces.getSize() > 0) { - addConstraints(builder, FreeFaces, OrderFreeFaces); + addConstraints(builder, FreeFaces, FreeOrder); } // App point constraints diff --git a/src/Mod/Surface/App/FeatureFilling.h b/src/Mod/Surface/App/FeatureFilling.h index bdc1ba535d..9e1f1f6b8c 100644 --- a/src/Mod/Surface/App/FeatureFilling.h +++ b/src/Mod/Surface/App/FeatureFilling.h @@ -41,14 +41,14 @@ public: Filling(); //Properties of Curves - App::PropertyLinkSubList Border; // Border Edges (C0 is required for edges without a corresponding face) - App::PropertyLinkSubList BorderFaces; // Border Faces (C0, G1 and G2 are possible) - App::PropertyIntegerList OrderBorderFaces; // Order of constraint on border faces - App::PropertyLinkSubList Curves; // Other Constraint Curves (C0 is required for edges without a corresponding face) - App::PropertyLinkSubList CurveFaces; // Curve Faces (C0, G1 and G2 are possible) - App::PropertyIntegerList OrderCurveFaces; // Order of constraint on curve faces - App::PropertyLinkSubList FreeFaces; // Free constraint on a face - App::PropertyIntegerList OrderFreeFaces; // Order of constraint on free faces + App::PropertyLinkSubList BoundaryEdges; // Boundary Edges (C0 is required for edges without a corresponding face) + App::PropertyStringList BoundaryFaces; // Boundary Faces (C0, G1 and G2 are possible) + App::PropertyIntegerList BoundaryOrder; // Order of constraint on border faces + App::PropertyLinkSubList UnboundEdges; // Unbound constraint edges (C0 is required for edges without a corresponding face) + App::PropertyStringList UnboundFaces; // Unbound constraint faces (C0, G1 and G2 are possible) + App::PropertyIntegerList UnboundOrder; // Order of constraint on curve faces + App::PropertyLinkSubList FreeFaces; // Free constraint faces + App::PropertyIntegerList FreeOrder; // Order of constraint on free faces App::PropertyLinkSubList Points; // Constraint Points (on Surface) App::PropertyLinkSub InitialFace; // Initial Face to use @@ -75,7 +75,7 @@ public: private: void addConstraints(BRepFill_Filling& builder, const App::PropertyLinkSubList& edges, - const App::PropertyLinkSubList& faces, + const App::PropertyStringList& faces, const App::PropertyIntegerList& orders, Standard_Boolean bnd); void addConstraints(BRepFill_Filling& builder, diff --git a/src/Mod/Surface/Gui/TaskFilling.cpp b/src/Mod/Surface/Gui/TaskFilling.cpp index 4dfc123362..bd4c10b0af 100644 --- a/src/Mod/Surface/Gui/TaskFilling.cpp +++ b/src/Mod/Surface/Gui/TaskFilling.cpp @@ -107,7 +107,7 @@ QIcon ViewProviderFilling::getIcon(void) const void ViewProviderFilling::highlightReferences(bool on) { Surface::Filling* surface = static_cast(getObject()); - auto bounds = surface->Border.getSubListValues(); + auto bounds = surface->BoundaryEdges.getSubListValues(); for (auto it : bounds) { Part::Feature* base = dynamic_cast(it.first); if (base) { @@ -187,7 +187,7 @@ private: if (element.substr(0,4) != "Edge") return false; - auto links = editedObject->Border.getSubListValues(); + auto links = editedObject->BoundaryEdges.getSubListValues(); for (auto it : links) { if (it.first == pObj) { for (auto jt : it.second) { @@ -249,8 +249,8 @@ void FillingPanel::setEditedObject(Surface::Filling* obj) ui->lineInitFaceName->setText(text); } - auto objects = editedObject->Border.getValues(); - auto element = editedObject->Border.getSubValues(); + auto objects = editedObject->BoundaryEdges.getValues(); + auto element = editedObject->BoundaryEdges.getSubValues(); auto it = objects.begin(); auto jt = element.begin(); @@ -405,7 +405,7 @@ void FillingPanel::on_listBoundary_itemDoubleClicked(QListWidgetItem* item) ui->statusLabel->setText(tr("Edge has %n adjacent face(s)", 0, n)); // fill up the combo boxes - modifyBorder(true); + modifyBoundary(true); ui->comboBoxFaces->addItem(tr("None"), QByteArray("None")); ui->comboBoxCont->addItem(QString::fromLatin1("C0"), static_cast(GeomAbs_C0)); ui->comboBoxCont->addItem(QString::fromLatin1("G1"), static_cast(GeomAbs_G1)); @@ -478,11 +478,11 @@ void FillingPanel::onSelectionChanged(const Gui::SelectionChanges& msg) data << QByteArray(msg.pSubName); item->setData(Qt::UserRole, data); - auto objects = editedObject->Border.getValues(); + auto objects = editedObject->BoundaryEdges.getValues(); objects.push_back(sel.getObject()); - auto element = editedObject->Border.getSubValues(); + auto element = editedObject->BoundaryEdges.getSubValues(); element.push_back(msg.pSubName); - editedObject->Border.setValues(objects, element); + editedObject->BoundaryEdges.setValues(objects, element); this->vp->highlightReferences(true); } else if (selectionMode == RemoveEdge) { @@ -502,15 +502,15 @@ void FillingPanel::onSelectionChanged(const Gui::SelectionChanges& msg) this->vp->highlightReferences(false); App::DocumentObject* obj = sel.getObject(); std::string sub = msg.pSubName; - auto objects = editedObject->Border.getValues(); - auto element = editedObject->Border.getSubValues(); + auto objects = editedObject->BoundaryEdges.getValues(); + auto element = editedObject->BoundaryEdges.getSubValues(); auto it = objects.begin(); auto jt = element.begin(); for (; it != objects.end() && jt != element.end(); ++it, ++jt) { if (*it == obj && *jt == sub) { objects.erase(it); element.erase(jt); - editedObject->Border.setValues(objects, element); + editedObject->BoundaryEdges.setValues(objects, element); break; } } @@ -536,8 +536,8 @@ void FillingPanel::onDeleteEdge() App::Document* doc = App::GetApplication().getDocument(data[0].toByteArray()); App::DocumentObject* obj = doc ? doc->getObject(data[1].toByteArray()) : nullptr; std::string sub = data[2].toByteArray().constData(); - auto objects = editedObject->Border.getValues(); - auto element = editedObject->Border.getSubValues(); + auto objects = editedObject->BoundaryEdges.getValues(); + auto element = editedObject->BoundaryEdges.getSubValues(); auto it = objects.begin(); auto jt = element.begin(); this->vp->highlightReferences(false); @@ -545,7 +545,7 @@ void FillingPanel::onDeleteEdge() if (*it == obj && *jt == sub) { objects.erase(it); element.erase(jt); - editedObject->Border.setValues(objects, element); + editedObject->BoundaryEdges.setValues(objects, element); break; } } @@ -559,19 +559,22 @@ void FillingPanel::on_buttonAccept_clicked() if (item) { QList data; data = item->data(Qt::UserRole).toList(); + + QVariant face = ui->comboBoxFaces->itemData(ui->comboBoxFaces->currentIndex()); + QVariant cont = ui->comboBoxCont->itemData(ui->comboBoxCont->currentIndex()); if (data.size() == 5) { - data[3] = ui->comboBoxFaces->itemData(ui->comboBoxFaces->currentIndex()); - data[4] = ui->comboBoxCont->itemData(ui->comboBoxCont->currentIndex()); + data[3] = face; + data[4] = cont; } else { - data << ui->comboBoxFaces->itemData(ui->comboBoxFaces->currentIndex()); - data << ui->comboBoxCont->itemData(ui->comboBoxCont->currentIndex()); + data << face; + data << cont; } item->setData(Qt::UserRole, data); } - modifyBorder(false); + modifyBoundary(false); ui->comboBoxFaces->clear(); ui->comboBoxCont->clear(); ui->statusLabel->clear(); @@ -579,13 +582,13 @@ void FillingPanel::on_buttonAccept_clicked() void FillingPanel::on_buttonIgnore_clicked() { - modifyBorder(false); + modifyBoundary(false); ui->comboBoxFaces->clear(); ui->comboBoxCont->clear(); ui->statusLabel->clear(); } -void FillingPanel::modifyBorder(bool on) +void FillingPanel::modifyBoundary(bool on) { ui->buttonInitFace->setDisabled(on); ui->lineInitFaceName->setDisabled(on); diff --git a/src/Mod/Surface/Gui/TaskFilling.h b/src/Mod/Surface/Gui/TaskFilling.h index 752904f60a..a19bc497b6 100644 --- a/src/Mod/Surface/Gui/TaskFilling.h +++ b/src/Mod/Surface/Gui/TaskFilling.h @@ -83,7 +83,7 @@ protected: virtual void slotUndoDocument(const Gui::Document& Doc); /** Notifies on redo */ virtual void slotRedoDocument(const Gui::Document& Doc); - void modifyBorder(bool); + void modifyBoundary(bool); private Q_SLOTS: void on_buttonInitFace_clicked();