Merge pull request #15505 from bgbsww/bgbsww-toponamingSaveRestore6

Toponaming:  bring in SketchObject::InternalShape
This commit is contained in:
Chris Hennes
2024-07-24 18:52:12 -05:00
committed by GitHub
2 changed files with 146 additions and 29 deletions

View File

@@ -82,6 +82,7 @@
#include <Mod/Part/App/DatumFeature.h>
#include <Mod/Part/App/GeometryMigrationExtension.h>
#include <Mod/Part/App/TopoShapeOpCode.h>
#include <Mod/Part/App/WireJoiner.h>
#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,14 @@ SketchObject::~SketchObject()
delete analyser;
}
void SketchObject::setupObject()
{
ParameterGrp::handle hGrpp = App::GetApplication().GetParameterGroupByPath(
"User parameter:BaseApp/Preferences/Mod/Sketcher");
MakeInternals.setValue(hGrpp->GetBool("MakeInternals", false));
inherited::setupObject();
}
short SketchObject::mustExecute() const
{
if (Geometry.isTouched())
@@ -309,7 +328,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 +360,78 @@ 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<std::string,std::string> 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<std::string> names;
std::string prefix;
const std::array<TopAbs_ShapeEnum, 2> 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.setTightBound(true);
joiner.setMergeEdges(true);
joiner.addShape(edges);
Part::TopoShape result(getID(), getDocument()->getStringHasher());
if (!joiner.Shape().IsNull()) {
joiner.getResultWires(result, "SKF");
result = result.makeElementFace(result.getSubTopoShapes(TopAbs_WIRE),
/*op*/"",
/*maker*/"Part::FaceMakerRing",
/*pln*/nullptr
);
}
Part::TopoShape openWires(getID(), getDocument()->getStringHasher());
joiner.getOpenWires(openWires, "SKF");
if (openWires.isNull())
return result; // No open wires, return either face or empty toposhape
if (result.isNull())
return openWires; // No face, but we have open wires to return as a shape
return result.makeElementCompound({result, openWires}); // Compound and return both
} 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 +9606,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 +9754,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.newName = getExportElementName(InternalShape.getShape(), realName).newName;
else
mappedElement = InternalShape.getShape().getElementName(realName);
if (mapped || type != ElementNameType::Export) {
if (mappedElement.index) {
@@ -9832,45 +9923,60 @@ 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)) {
if (!geoIdFromShapeType(indexedName, geoId, posId)) {
ss << indexedName;
return ss.str();
}
if(geoId == Sketcher::GeoEnum::HAxis ||
geoId == Sketcher::GeoEnum::VAxis ||
geoId == Sketcher::GeoEnum::RtPnt) {
if (geoId == Sketcher::GeoEnum::HAxis ||
geoId == Sketcher::GeoEnum::VAxis ||
geoId == Sketcher::GeoEnum::RtPnt) {
if (postfix)
ss << Data::ELEMENT_MAP_PREFIX;
ss << indexedName;
if(postfix)
ss << '.' << indexedName;
if (postfix)
ss << '.' << indexedName;
return ss.str();
}
auto geo = getGeometry(geoId);
if(!geo) {
if (!geo) {
std::string res = indexedName.toString();
return res;
}
if (postfix)
ss << Data::ELEMENT_MAP_PREFIX;
ss << (geoId>=0?'g':'e') << GeometryFacade::getFacade(geo)->getId();
if(posId!=PointPos::none)
ss << (geoId >= 0 ? 'g' : 'e') << GeometryFacade::getFacade(geo)->getId();
if (posId != PointPos::none)
ss << 'v' << static_cast<int>(posId);
if(postfix) {
if (postfix) {
// rename Edge to edge, and Vertex to vertex to avoid ambiguous of
// element mapping of the public shape and internal geometry.
if (indexedName.getIndex() <= 0)
ss << '.' << indexedName;
else if(boost::starts_with(indexedName.getType(),"Edge"))
ss << ".e" << (indexedName.getType()+1) << indexedName.getIndex();
else if(boost::starts_with(indexedName.getType(),"Vertex"))
ss << ".v" << (indexedName.getType()+1) << indexedName.getIndex();
else if (boost::starts_with(indexedName.getType(), "Edge"))
ss << ".e" << (indexedName.getType() + 1) << indexedName.getIndex();
else if (boost::starts_with(indexedName.getType(), "Vertex"))
ss << ".v" << (indexedName.getType() + 1) << indexedName.getIndex();
else
ss << '.' << indexedName;
}

View File

@@ -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<Base::Vector3d> getOpenVertices() const;
// Signaled when solver has done update
boost::signals2::signal<void()> signalSolverUpdate;
boost::signals2::signal<void()> 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<std::string, std::string> 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<std::string, std::string> internalElementMap;
};
inline int SketchObject::initTemporaryMove(int geoId, PointPos pos, bool fine /*=true*/)