From a600952665ce3fcd5709d363959b7fd60af98296 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Thu, 18 Jul 2024 17:16:04 -0400 Subject: [PATCH] Toponaming: Transfer in SketchObject::InternalShape --- src/Mod/Sketcher/App/SketchObject.cpp | 141 ++++++++++++++++++++++++-- src/Mod/Sketcher/App/SketchObject.h | 19 +++- 2 files changed, 146 insertions(+), 14 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index f63db00b59..5e8c45ed75 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -82,6 +82,7 @@ #include #include #include +#include #include "SketchObject.h" #include "SketchObjectPy.h" @@ -125,6 +126,14 @@ SketchObject::SketchObject() (App::PropertyType)(App::Prop_Output | App::Prop_ReadOnly | App::Prop_Hidden), "Sketch is fully constrained"); + ADD_PROPERTY(InternalShape, + (Part::TopoShape())); + ADD_PROPERTY_TYPE(MakeInternals, + (false), + "Internal Geometry", + App::Prop_None, + "Make internal geometry, e.g. split intersecting edges, face of closed wires."); + Geometry.setOrderRelevant(true); allowOtherBody = true; @@ -173,6 +182,8 @@ SketchObject::SketchObject() internaltransaction = false; managedoperation = false; + + registerElementCache(internalPrefix(), &InternalShape); } SketchObject::~SketchObject() @@ -186,6 +197,17 @@ SketchObject::~SketchObject() delete analyser; } +void SketchObject::setupObject() +{ + ParameterGrp::handle hGrpp = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Sketcher"); +// ArcFitTolerance.setValue(hGrpp->GetFloat("ArcFitTolerance", Precision::Confusion()*10.0)); +// ExternalBSplineMaxDegree.setValue(hGrpp->GetInt("ExternalBSplineMaxDegree", 5)); +// ExternalBSplineTolerance.setValue(hGrpp->GetFloat("ExternalBSplineTolerance", 1e-4)); + MakeInternals.setValue(hGrpp->GetBool("MakeInternals", false)); + inherited::setupObject(); +} + short SketchObject::mustExecute() const { if (Geometry.isTouched()) @@ -309,7 +331,11 @@ void SketchObject::buildShape() shapes.push_back(getEdge(geo, convertSubName( Data::IndexedName::fromConst("ExternalEdge", i-1), false).c_str())); } + + internalElementMap.clear(); + if(shapes.empty() && vertices.empty()) { + InternalShape.setValue(Part::TopoShape()); Shape.setValue(Part::TopoShape()); return; } @@ -337,9 +363,89 @@ void SketchObject::buildShape() result.makeElementCompound(results, Part::OpCodes::Sketch); } result.Tag = getID(); + InternalShape.setValue(buildInternals(result.located(TopLoc_Location()))); + // Must set Shape property after InternalShape so that + // GeoFeature::updateElementReference() can run properly on change of Shape + // property, because some reference may pointing to the InternalShape Shape.setValue(result); } +const std::map SketchObject::getInternalElementMap() const +{ + if (!internalElementMap.empty() || !MakeInternals.getValue()) + return internalElementMap; + + auto internalShape = InternalShape.getShape(); + auto shape = Shape.getShape().located(TopLoc_Location()); + if (!internalShape.isNull() && !shape.isNull()) { + std::vector names; + std::string prefix; + const std::array types = {TopAbs_VERTEX, TopAbs_EDGE}; + for (const auto &type : types) { + prefix = internalPrefix() + Part::TopoShape::shapeName(type); + std::size_t len = prefix.size(); + int i=0; + for (const auto &v : internalShape.getSubTopoShapes(type)) { + ++i; + shape.findSubShapesWithSharedVertex(v, &names, Data::SearchOption::CheckGeometry + |Data::SearchOption::SingleResult); + if (names.empty()) + continue; + prefix += std::to_string(i); + internalElementMap[prefix] = names.front(); + internalElementMap[names.front()] = prefix; + prefix.resize(len); + names.clear(); + } + } + } + return internalElementMap; +} + +Part::TopoShape SketchObject::buildInternals(const Part::TopoShape &edges) const +{ + if (!MakeInternals.getValue()) + return Part::TopoShape(); + + try { + Part::WireJoiner joiner; +// joiner.setTolerance(InternalTolerance.getValue()); + joiner.setTightBound(true); + joiner.setMergeEdges(true); + joiner.addShape(edges); + Part::TopoShape result(getID(), getDocument()->getStringHasher()); + if (!joiner.Shape().IsNull()) { + joiner.getResultWires(result, "SKF"); + + // NOTE: we set minElementNames to 2 (i.e to use at least two + // unused edge name to construct face name) in order to reduce the + // chance of face jumping. + result = result.makeElementFace(result.getSubTopoShapes(TopAbs_WIRE), + /*op*/"", + /*maker*/"Part::FaceMakerRing", + /*pln*/nullptr +#if 1 +// /*minElementNames (revert to 1 for now, see how it fares)*/1 +#else + /*minElementNames*/2 +#endif + ); + } + Part::TopoShape openWires(getID(), getDocument()->getStringHasher()); + joiner.getOpenWires(openWires, "SKF"); + if (openWires.isNull()) + return result; + if (result.isNull()) + return openWires; + return result.makeElementCompound({result, openWires}); + } catch (Base::Exception &e) { + FC_WARN("Failed to make face for sketch: " << e.what()); + } catch (Standard_Failure &e) { + FC_WARN("Failed to make face for sketch: " << e.GetMessageString()); + } + return Part::TopoShape(); +} + static const char *hasSketchMarker(const char *name) { static std::string marker(Part::TopoShape::elementMapPrefix()+Part::OpCodes::Sketch); if (!name) @@ -9514,11 +9620,11 @@ App::DocumentObject *SketchObject::getSubObject( if (auto realType = convertInternalName(indexedName.getType())) { if (realType[0] == '\0') - subshape = Shape.getShape(); + subshape = InternalShape.getShape(); else { auto shapeType = Part::TopoShape::shapeType(realType, true); if (shapeType != TopAbs_SHAPE) - subshape = Shape.getShape().getSubTopoShape(shapeType, indexedName.getIndex(), true); + subshape = InternalShape.getShape().getSubTopoShape(shapeType, indexedName.getIndex(), true); } if (subshape.isNull()) return nullptr; @@ -9662,13 +9768,12 @@ App::ElementNamePair SketchObject::getElementName( if (auto realName = convertInternalName(ret.oldName.c_str())) { Data::MappedElement mappedElement; (void)realName; -// Todo: Do we need to add the InternalShape? -// if (mapped) -// mappedElement = InternalShape.getShape().getElementName(name); -// else if (type == ElementNameType::Export) -// ret.newName = getExportElementName(InternalShape.getShape(), realName).first; -// else -// mappedElement = InternalShape.getShape().getElementName(realName); + if (mapped) + mappedElement = InternalShape.getShape().getElementName(name); + else if (type == ElementNameType::Export) + ret.first = getExportElementName(InternalShape.getShape(), realName).first; + else + mappedElement = InternalShape.getShape().getElementName(realName); if (mapped || type != ElementNameType::Export) { if (mappedElement.index) { @@ -9832,9 +9937,25 @@ bool SketchObject::geoIdFromShapeType(const Data::IndexedName & indexedName, return true; } -std::string SketchObject::convertSubName(const Data::IndexedName & indexedName, bool postfix) const +std::string SketchObject::convertSubName(const char *subname, bool postfix) const { + return convertSubName(checkSubName(subname), postfix); +} + +std::string SketchObject::convertSubName(const Data::IndexedName & indexedName, bool postfix) const{ std::ostringstream ss; + if (auto realType = convertInternalName(indexedName.getType())) { + auto mapped = InternalShape.getShape().getMappedName( + Data::IndexedName::fromConst(realType, indexedName.getIndex())); + if (!mapped) { + if (postfix) + ss << indexedName; + } else if (postfix) + ss << Data::ComplexGeoData::elementMapPrefix() << mapped << '.' << indexedName; + else + ss << mapped; + return ss.str(); + } int geoId; PointPos posId; if(!geoIdFromShapeType(indexedName,geoId,posId)) { diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h index aafbca8ca9..3279273e68 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -46,6 +46,7 @@ class SketchAnalysis; class SketcherExport SketchObject: public Part::Part2DObject { + typedef Part::Part2DObject inherited; PROPERTY_HEADER_WITH_OVERRIDE(Sketcher::SketchObject); public: @@ -66,6 +67,8 @@ public: Sketcher::PropertyConstraintList Constraints; App ::PropertyLinkSubList ExternalGeometry; App ::PropertyBool FullyConstrained; + Part ::PropertyPartShape InternalShape; + App ::PropertyBool MakeInternals; /** @name methods override Feature */ //@{ short mustExecute() const override; @@ -78,6 +81,7 @@ public: { return "SketcherGui::ViewProviderSketch"; } + void setupObject() override; //@} /** SketchObject can work in two modes: Recompute Mode and noRecomputes Mode @@ -695,10 +699,7 @@ public: return geoIdFromShapeType(shapetype, geoId, posId); } - std::string convertSubName(const char* subname, bool postfix = true) const - { - return convertSubName(checkSubName(subname), postfix); - } + std::string convertSubName(const char* subname, bool postfix = true) const; std::string convertSubName(const std::string& subname, bool postfix = true) const { @@ -769,6 +770,15 @@ public: // Validation routines std::vector getOpenVertices() const; + // Signaled when solver has done update + boost::signals2::signal signalSolverUpdate; + boost::signals2::signal signalElementsChanged; + + Part::TopoShape buildInternals(const Part::TopoShape& edges) const; + + /// Get a map from internal element to the same geometry in normal shape + const std::map getInternalElementMap() const; + public: // geometry extension functionalities for single element sketch object user convenience int setGeometryId(int GeoId, long id); int getGeometryId(int GeoId, long& id) const; @@ -920,6 +930,7 @@ private: // indicates whether changes to properties are the deed of SketchObject or not (for input // validation) bool managedoperation; + mutable std::map internalElementMap; }; inline int SketchObject::initTemporaryMove(int geoId, PointPos pos, bool fine /*=true*/)