From 5fc101b3290555faeec8adb5081e92e38cc9c387 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Sat, 17 Feb 2018 09:52:25 +0800 Subject: [PATCH] Sketcher: add support for sketch exports SketchObject now use the new TopoShape element name mapping to expose mapped geometry topological names during editing. SketchExport exports the editing geometry using those mapped names. The SketchExport acts just like SketchObject to the end-user, except that you can't directly edit its content. Instead, when you double click a SketchExport, it forwards the editing request to its parent SketchObject, and then pre-selects the exported geometries. You can then changed the export by selecting/removing geometries. The SketchExport is a Part2DObject, meaning that it can be mapped onto other faces, independent of its parent SketchObject. If no mapping, then it follows the parent SketchObject placement. If mapped, when you double click to edit the SketchExport, it will start editing the parent SketchObject in the placement of the SketchExport. --- src/Mod/Sketcher/App/AppSketcher.cpp | 1 + src/Mod/Sketcher/App/SketchObject.cpp | 448 ++++++++++++++++-- src/Mod/Sketcher/App/SketchObject.h | 46 +- src/Mod/Sketcher/Gui/AppSketcherGui.cpp | 1 + src/Mod/Sketcher/Gui/Command.cpp | 4 +- src/Mod/Sketcher/Gui/CommandAlterGeometry.cpp | 2 +- src/Mod/Sketcher/Gui/CommandConstraints.cpp | 50 +- src/Mod/Sketcher/Gui/CommandCreateGeo.cpp | 11 +- .../Sketcher/Gui/CommandSketcherBSpline.cpp | 8 +- src/Mod/Sketcher/Gui/CommandSketcherTools.cpp | 181 ++++++- .../Gui/CommandSketcherVirtualSpace.cpp | 4 +- src/Mod/Sketcher/Gui/Resources/Sketcher.qrc | 2 + .../Resources/icons/Sketcher_SketchExport.svg | 218 +++++++++ .../icons/Sketcher_SketchExportCompound.svg | 221 +++++++++ .../Sketcher/Gui/TaskSketcherConstrains.cpp | 4 +- src/Mod/Sketcher/Gui/TaskSketcherElements.cpp | 6 +- src/Mod/Sketcher/Gui/ViewProviderSketch.cpp | 212 +++++++-- src/Mod/Sketcher/Gui/ViewProviderSketch.h | 17 +- src/Mod/Sketcher/Gui/Workbench.cpp | 3 + 19 files changed, 1301 insertions(+), 138 deletions(-) create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/Sketcher_SketchExport.svg create mode 100644 src/Mod/Sketcher/Gui/Resources/icons/Sketcher_SketchExportCompound.svg diff --git a/src/Mod/Sketcher/App/AppSketcher.cpp b/src/Mod/Sketcher/App/AppSketcher.cpp index 9bfa4daaa107..5d997276e41b 100644 --- a/src/Mod/Sketcher/App/AppSketcher.cpp +++ b/src/Mod/Sketcher/App/AppSketcher.cpp @@ -67,6 +67,7 @@ PyMOD_INIT_FUNC(Sketcher) Sketcher::SketchObjectSF ::init(); Sketcher::SketchObject ::init(); + Sketcher::SketchExport ::init(); Sketcher::SketchObjectPython ::init(); Sketcher::Sketch ::init(); Sketcher::Constraint ::init(); diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index c2c215564f52..41c6d993da7f 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -58,11 +58,15 @@ # include # include # include +# include +# include +# include //# include #endif #include #include +#include #include #include @@ -78,9 +82,11 @@ #include #include #include +#include namespace Part { - PartExport Py::Object shape2pyshape(const TopoDS_Shape &shape); + PartExport std::list sort_Edges2(double tol3d, std::list& edges, + std::deque *hashes); } #include "SketchObject.h" @@ -90,39 +96,13 @@ namespace Part { using namespace Sketcher; using namespace Base; +FC_LOG_LEVEL_INIT("Sketcher",true,true); + const int GeoEnum::RtPnt = -1; const int GeoEnum::HAxis = -1; const int GeoEnum::VAxis = -2; const int GeoEnum::RefExt = -3; -namespace Sketcher { -const std::string &editPrefix() { - static std::string prefix("_"); - return prefix; -} - -std::vector checkSubNames(const std::vector &subnames) { - const auto &prefix = editPrefix(); - std::vector ret; - ret.reserve(subnames.size()); - for(const auto &subname : subnames) { - if(boost::starts_with(subname,prefix)) - ret.push_back(subname.substr(prefix.size())); - else - ret.push_back(subname); - } - return ret; -} - -const char *checkSubName(const char *subname) { - if(!subname) return 0; - const auto &prefix = editPrefix(); - if(boost::starts_with(subname,prefix)) - return subname + prefix.size(); - return subname; -} -} - PROPERTY_SOURCE(Sketcher::SketchObject, Part::Part2DObject) @@ -131,7 +111,10 @@ SketchObject::SketchObject() ADD_PROPERTY_TYPE(Geometry, (0) ,"Sketch",(App::PropertyType)(App::Prop_None),"Sketch geometry"); ADD_PROPERTY_TYPE(Constraints, (0) ,"Sketch",(App::PropertyType)(App::Prop_None),"Sketch constraints"); ADD_PROPERTY_TYPE(ExternalGeometry,(0,0),"Sketch",(App::PropertyType)(App::Prop_None),"Sketch external geometry"); + ADD_PROPERTY_TYPE(Exports, (0) ,"Sketch",(App::PropertyType)(App::Prop_Hidden),"Sketch export geometry"); + ADD_PROPERTY_TYPE(LastGeoID, (0) ,"Sketch",(App::PropertyType)(App::Prop_Output|App::Prop_Hidden|App::Prop_ReadOnly),"For generating geometry ID"); + geoCached = false; allowOtherBody = true; allowUnaligned = true; @@ -296,6 +279,14 @@ int SketchObject::solve(bool updateGeoAfterSolving/*=true*/) Geometry.setValues(geomlist); for (std::vector::iterator it = geomlist.begin(); it != geomlist.end(); ++it) if (*it) delete *it; + + for(auto obj : Exports.getValues()) { + auto exp = dynamic_cast(obj); + if(exp->testStatus(App::ObjectStatus::Recompute2)) + continue; + if(exp && exp->update() && !exp->positionBySupport()) + exp->Placement.setValue(Placement.getValue()); + } } else if(err <0) { // if solver failed, invalid constraints were likely added before solving @@ -344,6 +335,14 @@ int SketchObject::setDatum(int ConstrId, double Datum) return err; } +void SketchObject::generateExternalId(const char *key) { + auto extId = getDocument()->mapStringToID(key); + externalGeoMap.insert(std::make_pair(*extId, + std::make_pair((int)ExternalGeo.size(),ExternalGeo.back()->Id))); + externalGeoKeys.push_back(extId); + assert(externalGeoKeys.size()==ExternalGeo.size()); +} + int SketchObject::setDriving(int ConstrId, bool isdriving) { const std::vector &vals = this->Constraints.getValues(); @@ -708,12 +707,14 @@ std::vector SketchObject::supportedGeometry(const std::vector< int SketchObject::addGeometry(const std::vector &geoList, bool construction/*=false*/) { const std::vector< Part::Geometry * > &vals = getInternalGeometry(); + auto id = LastGeoID.getValue(); std::vector< Part::Geometry * > newVals(vals); std::vector< Part::Geometry * > copies; copies.reserve(geoList.size()); for (std::vector::const_iterator it = geoList.begin(); it != geoList.end(); ++it) { Part::Geometry* copy = (*it)->copy(); + copy->Id = ++id; if(construction && copy->getTypeId() != Part::GeomPoint::getClassTypeId()) { copy->Construction = construction; } @@ -723,6 +724,7 @@ int SketchObject::addGeometry(const std::vector &geoList, bool newVals.insert(newVals.end(), copies.begin(), copies.end()); Geometry.setValues(newVals); + LastGeoID.setValue(id); for (std::vector::iterator it = copies.begin(); it != copies.end(); ++it) delete *it; Constraints.acceptGeometry(getCompleteGeometry()); @@ -737,11 +739,13 @@ int SketchObject::addGeometry(const Part::Geometry *geo, bool construction/*=fal std::vector< Part::Geometry * > newVals(vals); Part::Geometry *geoNew = geo->copy(); + geoNew->Id = LastGeoID.getValue()+1; if(geoNew->getTypeId() != Part::GeomPoint::getClassTypeId()) geoNew->Construction = construction; newVals.push_back(geoNew); + LastGeoID.setValue(geoNew->Id); Geometry.setValues(newVals); Constraints.acceptGeometry(getCompleteGeometry()); delete geoNew; @@ -2323,6 +2327,7 @@ bool SketchObject::isCarbonCopyAllowed(App::Document *pDoc, App::DocumentObject int SketchObject::addSymmetric(const std::vector &geoIdList, int refGeoId, Sketcher::PointPos refPosId/*=Sketcher::none*/) { + auto id = LastGeoID.getValue(); const std::vector< Part::Geometry * > &geovals = getInternalGeometry(); std::vector< Part::Geometry * > newgeoVals(geovals); @@ -2350,6 +2355,7 @@ int SketchObject::addSymmetric(const std::vector &geoIdList, int refGeoId, for (std::vector::const_iterator it = geoIdList.begin(); it != geoIdList.end(); ++it) { const Part::Geometry *geo = getGeometry(*it); Part::Geometry *geosym = geo->copy(); + geosym->Id = ++id; // Handle Geometry if(geosym->getTypeId() == Part::GeomLineSegment::getClassTypeId()){ @@ -2610,6 +2616,7 @@ int SketchObject::addSymmetric(const std::vector &geoIdList, int refGeoId, for (std::vector::const_iterator it = geoIdList.begin(); it != geoIdList.end(); ++it) { const Part::Geometry *geo = getGeometry(*it); Part::Geometry *geosym = geo->copy(); + geosym->Id = ++id; // Handle Geometry if(geosym->getTypeId() == Part::GeomLineSegment::getClassTypeId()){ @@ -2748,6 +2755,7 @@ int SketchObject::addSymmetric(const std::vector &geoIdList, int refGeoId, // add the geometry Geometry.setValues(newgeoVals); + LastGeoID.setValue(id); Constraints.acceptGeometry(getCompleteGeometry()); rebuildVertexIndex(); @@ -2855,6 +2863,7 @@ int SketchObject::addCopy(const std::vector &geoIdList, const Base::Vector3 { const std::vector< Part::Geometry * > &geovals = getInternalGeometry(); std::vector< Part::Geometry * > newgeoVals(geovals); + auto id = LastGeoID.getValue(); const std::vector< Constraint * > &constrvals = this->Constraints.getValues(); std::vector< Constraint * > newconstrVals(constrvals); @@ -2910,6 +2919,7 @@ int SketchObject::addCopy(const std::vector &geoIdList, const Base::Vector3 for (std::vector::const_iterator it = geoIdList.begin(); it != geoIdList.end(); ++it) { const Part::Geometry *geo = getGeometry(*it); Part::Geometry *geocopy = geo->copy(); + geocopy->Id = ++id; // Handle Geometry if(geocopy->getTypeId() == Part::GeomLineSegment::getClassTypeId()){ @@ -3105,6 +3115,7 @@ int SketchObject::addCopy(const std::vector &geoIdList, const Base::Vector3 constrline->setPoints(sp,ep); constrline->Construction=true; + constrline->Id = ++id; newgeoVals.push_back(constrline); Constraint *constNew; @@ -3245,6 +3256,7 @@ int SketchObject::addCopy(const std::vector &geoIdList, const Base::Vector3 } Geometry.setValues(newgeoVals); + LastGeoID.setValue(id); Constraints.acceptGeometry(getCompleteGeometry()); rebuildVertexIndex(); @@ -4183,13 +4195,16 @@ bool SketchObject::convertToNURBS(int GeoId) const std::vector< Part::Geometry * > &vals = getInternalGeometry(); std::vector< Part::Geometry * > newVals(vals); + auto id = LastGeoID.getValue(); if (GeoId < 0) { // external geometry newVals.push_back(bspline); + bspline->Id = ++id; } else { // normal geometry newVals[GeoId] = bspline; + bspline->Id = geo->Id; const std::vector< Sketcher::Constraint * > &cvals = Constraints.getValues(); @@ -4208,6 +4223,7 @@ bool SketchObject::convertToNURBS(int GeoId) } Geometry.setValues(newVals); + LastGeoID.setValue(id); Constraints.acceptGeometry(getCompleteGeometry()); rebuildVertexIndex(); @@ -4249,6 +4265,7 @@ bool SketchObject::increaseBSplineDegree(int GeoId, int degreeincrement /*= 1*/) std::vector< Part::Geometry * > newVals(vals); newVals[GeoId] = bspline; + bspline->Id = geo->Id; Geometry.setValues(newVals); Constraints.acceptGeometry(getCompleteGeometry()); @@ -4395,6 +4412,7 @@ bool SketchObject::modifyBSplineKnotMultiplicity(int GeoId, int knotIndex, int m std::vector< Part::Geometry * > newVals(vals); newVals[GeoId] = bspline; + bspline->Id = geo->Id; Geometry.setValues(newVals); Constraints.acceptGeometry(getCompleteGeometry()); @@ -4438,6 +4456,8 @@ int SketchObject::carbonCopy(App::DocumentObject * pObj, bool construction) if (!isCarbonCopyAllowed(pObj->getDocument(), pObj, xinv, yinv)) return -1; + auto id = LastGeoID.getValue(); + SketchObject * psObj = static_cast(pObj); const std::vector< Part::Geometry * > &vals = getInternalGeometry(); @@ -4458,6 +4478,7 @@ int SketchObject::carbonCopy(App::DocumentObject * pObj, bool construction) for (std::vector::const_iterator it=svals.begin(); it != svals.end(); ++it){ Part::Geometry *geoNew = (*it)->copy(); + geoNew->Id = ++id; if(construction) { geoNew->Construction = true; } @@ -4476,6 +4497,7 @@ int SketchObject::carbonCopy(App::DocumentObject * pObj, bool construction) newcVals.push_back(newConstr); } + LastGeoID.setValue(id); Geometry.setValues(newVals); Constraints.acceptGeometry(getCompleteGeometry()); rebuildVertexIndex(); @@ -4907,12 +4929,26 @@ void SketchObject::rebuildExternalGeometry(void) VLine->Construction = true; ExternalGeo.push_back(HLine); ExternalGeo.push_back(VLine); + + externalGeoMap.clear(); + if(externalGeoKeys.size()<2) { + externalGeoKeys.clear(); + externalGeoKeys.push_back(App::Document::StringID()); + externalGeoKeys.push_back(App::Document::StringID()); + }else + externalGeoKeys.resize(2); + for (int i=0; i < int(Objects.size()); i++) { const App::DocumentObject *Obj=Objects[i]; const std::string SubElement=SubElements[i]; TopoDS_Shape refSubShape; + if(!Obj || !Obj->getNameInDocument()) + continue; + std::string key = Obj->getNameInDocument(); + key += '.'; + if (Obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId())) { const Part::Datum* datum = static_cast(Obj); refSubShape = datum->getShape(); @@ -4921,6 +4957,7 @@ void SketchObject::rebuildExternalGeometry(void) const Part::Feature *refObj=static_cast(Obj); const Part::TopoShape& refShape=refObj->Shape.getShape(); refSubShape = refShape.getSubShape(SubElement.c_str()); + key += Data::ComplexGeoData::newElementName(SubElement.c_str()); } catch (Standard_Failure& e) { @@ -4965,6 +5002,7 @@ void SketchObject::rebuildExternalGeometry(void) BRepAdaptor_Curve curve(edge); if (curve.GetType() == GeomAbs_Line) { ExternalGeo.push_back(projectLine(curve, gPlane, invPlm)); + generateExternalId(key.c_str()); } } @@ -4982,6 +5020,7 @@ void SketchObject::rebuildExternalGeometry(void) BRepAdaptor_Curve curve(edge); if (curve.GetType() == GeomAbs_Line) { ExternalGeo.push_back(projectLine(curve, gPlane, invPlm)); + generateExternalId(key.c_str()); } else if (curve.GetType() == GeomAbs_Circle) { gp_Dir vec1 = sketchPlane.Axis().Direction(); @@ -5005,6 +5044,7 @@ void SketchObject::rebuildExternalGeometry(void) gCircle->Construction = true; ExternalGeo.push_back(gCircle); + generateExternalId(key.c_str()); } else { Part::GeomArcOfCircle* gArc = new Part::GeomArcOfCircle(); @@ -5014,6 +5054,7 @@ void SketchObject::rebuildExternalGeometry(void) gArc->setHandle(tCurve); gArc->Construction = true; ExternalGeo.push_back(gArc); + generateExternalId(key.c_str()); } } else { @@ -5045,12 +5086,14 @@ void SketchObject::rebuildExternalGeometry(void) Part::GeomPoint* point = new Part::GeomPoint(p); point->Construction = true; ExternalGeo.push_back(point); + generateExternalId(key.c_str()); } else { Part::GeomLineSegment* line = new Part::GeomLineSegment(); line->setPoints(p1,p2); line->Construction = true; ExternalGeo.push_back(line); + generateExternalId(key.c_str()); } } else if (projCurve.GetType() == GeomAbs_Circle) { @@ -5066,6 +5109,7 @@ void SketchObject::rebuildExternalGeometry(void) circle->Construction = true; ExternalGeo.push_back(circle); + generateExternalId(key.c_str()); } else { Part::GeomArcOfCircle* arc = new Part::GeomArcOfCircle(); @@ -5075,6 +5119,7 @@ void SketchObject::rebuildExternalGeometry(void) arc->setHandle(tCurve); arc->Construction = true; ExternalGeo.push_back(arc); + generateExternalId(key.c_str()); } } else if (projCurve.GetType() == GeomAbs_BSplineCurve) { // Unfortunately, a normal projection of a circle can also give a Bspline @@ -5097,10 +5142,12 @@ void SketchObject::rebuildExternalGeometry(void) circle->Construction = true; ExternalGeo.push_back(circle); + generateExternalId(key.c_str()); } else { Part::GeomBSplineCurve* bspline = new Part::GeomBSplineCurve(projCurve.BSpline()); bspline->Construction = true; ExternalGeo.push_back(bspline); + generateExternalId(key.c_str()); } } else if (projCurve.GetType() == GeomAbs_Hyperbola) { gp_Hypr e = projCurve.Hyperbola(); @@ -5120,6 +5167,7 @@ void SketchObject::rebuildExternalGeometry(void) hyperbola->setAngleXU(-xdir.AngleWithRef(xdirref.XDirection(),normal)); hyperbola->Construction = true; ExternalGeo.push_back(hyperbola); + generateExternalId(key.c_str()); } else { Part::GeomArcOfHyperbola* aoh = new Part::GeomArcOfHyperbola(); @@ -5129,6 +5177,7 @@ void SketchObject::rebuildExternalGeometry(void) aoh->setHandle(tCurve); aoh->Construction = true; ExternalGeo.push_back(aoh); + generateExternalId(key.c_str()); } } else if (projCurve.GetType() == GeomAbs_Parabola) { gp_Parab e = projCurve.Parabola(); @@ -5147,6 +5196,7 @@ void SketchObject::rebuildExternalGeometry(void) parabola->setAngleXU(-xdir.AngleWithRef(xdirref.XDirection(),normal)); parabola->Construction = true; ExternalGeo.push_back(parabola); + generateExternalId(key.c_str()); } else { Part::GeomArcOfParabola* aop = new Part::GeomArcOfParabola(); @@ -5156,6 +5206,7 @@ void SketchObject::rebuildExternalGeometry(void) aop->setHandle(tCurve); aop->Construction = true; ExternalGeo.push_back(aop); + generateExternalId(key.c_str()); } } else if (projCurve.GetType() == GeomAbs_Ellipse) { @@ -5174,6 +5225,7 @@ void SketchObject::rebuildExternalGeometry(void) ellipse->setHandle(curve); ellipse->Construction = true; ExternalGeo.push_back(ellipse); + generateExternalId(key.c_str()); } else { Part::GeomArcOfEllipse* aoe = new Part::GeomArcOfEllipse(); @@ -5183,6 +5235,7 @@ void SketchObject::rebuildExternalGeometry(void) aoe->setHandle(tCurve); aoe->Construction = true; ExternalGeo.push_back(aoe); + generateExternalId(key.c_str()); } } else { @@ -5209,6 +5262,7 @@ void SketchObject::rebuildExternalGeometry(void) Part::GeomPoint* point = new Part::GeomPoint(p); point->Construction = true; ExternalGeo.push_back(point); + generateExternalId(key.c_str()); } break; default: @@ -5804,6 +5858,9 @@ void SketchObject::Restore(XMLReader &reader) void SketchObject::onChanged(const App::Property* prop) { + if (prop == &Geometry) + geoCached = false; + if (isRestoring() && prop == &Geometry) { std::vector geom = Geometry.getValues(); std::vector supportedGeom = supportedGeometry(geom); @@ -5845,6 +5902,13 @@ void SketchObject::onChanged(const App::Property* prop) void SketchObject::onDocumentRestored() { try { + if(!LastGeoID.getValue()) { + const auto &vals = getInternalGeometry(); + int i = 0; + for(;i<(int)vals.size();++i) + vals[i]->Id = i+1; + LastGeoID.setValue(i); + } validateExternalLinks(); rebuildExternalGeometry(); Constraints.acceptGeometry(getCompleteGeometry()); @@ -6098,15 +6162,35 @@ void SketchObject::setExpression(const App::ObjectIdentifier &path, boost::share solve(); } +std::vector > SketchObject::getPointRefs(const char *subname) { + std::vector > ret; + auto shapetype = checkSubName(subname); + int geoId; + PointPos posId; + if(!geoIdFromShapeType(shapetype.c_str(),geoId,posId) || posId!=none) + return ret; + auto geo = getGeometry(geoId); + if(geo) { + int pos[] = {start,mid,end}; + for(size_t i=0;i(pos[i])),ss.str())); + } + } + return ret; +} + App::DocumentObject *SketchObject::getSubObject( const char *subname, PyObject **pyObj, Base::Matrix4D *pmat, bool transform, int depth) const { - const auto &prefix = editPrefix(); - if(!subname || !boost::starts_with(subname,prefix)) + if(!subname || !Data::ComplexGeoData::isMappedElement(subname)) return Part2DObject::getSubObject(subname,pyObj,pmat,transform,depth); - const char *shapetype = subname+prefix.size(); + std::string sub = checkSubName(subname); + const char *shapetype = sub.c_str(); const Part::Geometry *geo = 0; Base::Vector3d point; if (boost::starts_with(shapetype,"Edge")) { @@ -6136,6 +6220,8 @@ App::DocumentObject *SketchObject::getSubObject( const std::vector< Constraint * > &vals = this->Constraints.getValues(); if (ConstrId < 0 || ConstrId >= int(vals.size())) return 0; + if(pyObj) + *pyObj = vals[ConstrId]->getPyObject(); return const_cast(this); }else if(*shapetype) return 0; @@ -6159,6 +6245,152 @@ App::DocumentObject *SketchObject::getSubObject( return const_cast(this); } +std::vector SketchObject::checkSubNames(const std::vector &subnames) const{ + std::vector ret; + ret.reserve(subnames.size()); + for(const auto &subname : subnames) + ret.push_back(checkSubName(subname.c_str())); + return ret; +} + +std::string SketchObject::checkSubName(const char *sub) const{ + if(!sub) return std::string(); + const char *subname = Data::ComplexGeoData::isMappedElement(sub); + if(!subname) + return sub; + if(!subname[0]) { + FC_ERR("invalid subname " << sub); + return sub; + } + std::istringstream iss(subname+1); + int id = -1; + bool valid = false; + switch(subname[0]) { + case 'g': + case 'e': + if(iss>>std::hex>>id) + valid = true; + break; + default: { + // for RootPoint,H_Axis,V_Axis + const char *dot = strchr(subname,'.'); + if(dot) + return dot+1; + return subname; + }} + if(!valid) { + FC_ERR("invalid subname " << sub); + return sub; + } + + int geoId; + const Part::Geometry *geo = 0; + + while(1) { + switch(subname[0]) { + case 'g': { + auto it = geoMap.find(id); + if(it!=geoMap.end()) { + std::ostringstream ss; + geoId = it->second; + geo = getGeometry(geoId); + } + break; + } case 'e': { + auto it = externalGeoMap.find(id); + if(it!=externalGeoMap.end()) { + geoId = -it->second.first; + id = it->second.second; + geo = getGeometry(geoId); + } + break; + }} + if(geo && geo->Id == id) { + char sep; + int posId = none; + std::ostringstream ss; + if((iss >> sep >> std::hex >> posId) && sep=='v') { + int idx = getVertexIndexGeoPos(geoId,static_cast(posId)); + if(idx < 0) { + FC_ERR("invalid subname " << sub); + return sub; + } + ss << "Vertex" << idx+1; + }else if(geoId>=0) + ss << "Edge" << geoId+1; + else + ss << "ExternalEdge" << (-geoId-3)+1; + return ss.str(); + } + switch(subname[0]) { + case 'g': { + if(geoCached) { + FC_ERR("cannot find subname " << sub); + return sub; + } + geoCached = true; + geoMap.clear(); + int i=0; + for(auto v : getInternalGeometry()) + geoMap[v->Id] = i++; + break; + } case 'e': + // external geo map is generated in rebuildExternalGeometry() + FC_ERR("cannot find subname " << sub); + return sub; + } + } +} + +bool SketchObject::geoIdFromShapeType(const char *shapetype, int &geoId, PointPos &posId) const { + posId = none; + if (boost::starts_with(shapetype,"Edge")) { + geoId = std::atoi(&shapetype[4]) - 1; + } else if (boost::starts_with(shapetype,"ExternalEdge")) { + geoId = std::atoi(&shapetype[12]) - 1; + geoId = -geoId - 3; + } else if (boost::starts_with(shapetype,"Vertex")) { + int VtId = std::atoi(&shapetype[6]) - 1; + getGeoVertexIndex(VtId,geoId,posId); + if (posId==none) return false; + } else if (strcmp(shapetype,"H_Axis")==0) { + geoId = Sketcher::GeoEnum::HAxis; + } else if (strcmp(shapetype,"V_Axis")==0) { + geoId = Sketcher::GeoEnum::VAxis; + } else if (strcmp(shapetype,"RootPoint")==0) { + geoId = Sketcher::GeoEnum::RtPnt; + posId = start; + } else + return false; + return true; +} + +std::string SketchObject::convertSubName(const char *shapetype) const{ + std::ostringstream ss; + int geoId; + PointPos posId; + if(!geoIdFromShapeType(shapetype,geoId,posId)) + return shapetype; + if(geoId == Sketcher::GeoEnum::HAxis || + geoId == Sketcher::GeoEnum::VAxis || + geoId == Sketcher::GeoEnum::RtPnt) { + ss << Data::ComplexGeoData::elementMapPrefix() << shapetype << '.' << shapetype; + return ss.str(); + } + + auto geo = getGeometry(geoId); + if(!geo) + return shapetype; + ss << Data::ComplexGeoData::elementMapPrefix(); + if(geoId>=0) + ss << 'g' << std::hex << geo->Id; + else + ss << 'e' << std::hex << App::Document::stringID(externalGeoKeys[-geoId-1]); + if(posId!=none) + ss << 'v' << std::hex << posId; + ss << '.' << shapetype; + return ss.str(); +} // Python Sketcher feature --------------------------------------------------------- @@ -6180,3 +6412,155 @@ template<> PyObject* Sketcher::SketchObjectPython::getPyObject(void) { // explicit template instantiation template class SketcherExport FeaturePythonT; } + +// --------------------------------------------------------- + +PROPERTY_SOURCE(Sketcher::SketchExport, Part::Part2DObject) + +SketchExport::SketchExport() { + ADD_PROPERTY_TYPE(Base,(""),"",App::Prop_Hidden,"Base sketch object name"); + ADD_PROPERTY_TYPE(Refs,(),"",App::Prop_None,"Sketch geometry references"); +} + +SketchExport::~SketchExport() +{} + +App::DocumentObject *SketchExport::getBase() const { + return getDocument()->getObject(Base.getValue()); +} + +App::DocumentObjectExecReturn *SketchExport::execute(void) { + try { + App::DocumentObjectExecReturn* rtn = Part2DObject::execute();//to positionBySupport + if(rtn!=App::DocumentObject::StdReturn) + //error + return rtn; + } + catch (const Base::Exception& e) { + return new App::DocumentObjectExecReturn(e.what()); + } + + auto base = getBase(); + if(!base) + return new App::DocumentObjectExecReturn("No sketch base"); + for(const auto &ref : Refs.getValues()) { + auto sobj = base->getSubObject(ref.c_str()); + if(!sobj) { + std::string ret("Invalid reference "); + return new App::DocumentObjectExecReturn(ret + ref); + } + } + return App::DocumentObject::StdReturn; +} + +void SketchExport::onChanged(const App::Property* prop) { + if(prop == &Shape) { + // bypass Part::Feature logic, 'cause we don't want to transform the + // shape and mess up the element map. + DocumentObject::onChanged(prop); + return; + } + Part2DObject::onChanged(prop); +} + +std::set SketchExport::getRefs() const { + std::set refSet; + const auto &refs = Refs.getValues(); + refSet.insert(refs.begin(),refs.end()); + if(refSet.size()>1) + refSet.erase(""); + return refSet; +} + +bool SketchExport::update() { + auto base = getBase(); + if(!base) return false; + auto sketch = dynamic_cast(base); + int count = 0; + BRep_Builder builder; + TopoDS_Compound comp; + builder.MakeCompound(comp); + std::list edgeList; + std::map refMap; + for(const auto &ref : getRefs()) { + // Obtain the shape without feature's placement transformation, because + // we may have our own support. + auto shape = Part::Feature::getShape(base,ref.c_str(),true,0,0,false,false); + if(shape.IsNull()) continue; + TopExp_Explorer exp(shape,TopAbs_EDGE); + if(exp.More()) { + refMap[exp.Current().HashCode(INT_MAX)] = ref; + edgeList.push_back(TopoDS::Edge(exp.Current())); + }else{ + ++count; + refMap[shape.HashCode(INT_MAX)] = ref; + builder.Add(comp,shape); + } + } + while(edgeList.size()) { + ++count; + BRepBuilderAPI_MakeWire mkWire; + std::deque hashes; + auto edges = Part::sort_Edges2(Precision::Confusion(),edgeList,&hashes); + auto hit = hashes.begin(); + for(auto &edge : edges){ + mkWire.Add(edge); + auto hash = *hit++; + auto ref = refMap[hash]; + assert(ref.size()); + auto e = mkWire.Edge(); + auto ehash = e.HashCode(INT_MAX); + if(ehash!=hash) + refMap[ehash] = ref; + if(sketch) { + auto names = sketch->getPointRefs(ref.c_str()); + if(names.size()) { + for(TopExp_Explorer it(e,TopAbs_VERTEX);it.More();it.Next()) { + auto pt = BRep_Tool::Pnt(TopoDS::Vertex(it.Current())); + Base::Vector3d point(pt.X(),pt.Y(),pt.Z()); + for(auto &name : names) { + if(point == name.first) { + refMap[it.Current().HashCode(INT_MAX)] = name.second; + break; + } + } + } + } + } + } + builder.Add(comp,mkWire.Wire()); + } + if(!count) return false; + + Part::TopoShape shape(comp); + TopTools_IndexedMapOfShape edgeMap; + TopExp::MapShapes(comp,TopAbs_EDGE,edgeMap); + for(int i=1;i<=edgeMap.Extent();i++) { + auto it = refMap.find(edgeMap(i).HashCode(INT_MAX)); + if(it!=refMap.end()) { + std::ostringstream str; + str << "Edge" << i; + shape.setElementName(str.str().c_str(),it->second.c_str()); + } + } + TopTools_IndexedMapOfShape vertexMap; + TopExp::MapShapes(comp,TopAbs_VERTEX,vertexMap); + for(int i=1;i<=vertexMap.Extent();i++) { + auto it = refMap.find(vertexMap(i).HashCode(INT_MAX)); + if(it!=refMap.end()) { + std::ostringstream str; + str << "Vertex" << i; + shape.setElementName(str.str().c_str(),it->second.c_str()); + } + } + Shape.setValue(shape); + return true; +} + +short SketchExport::mustExecute(void) const { + auto ret = Part2DObject::mustExecute(); + if(ret) return ret; + auto base = getBase(); + if(base) return base->mustExecute(); + return 0; +} diff --git a/src/Mod/Sketcher/App/SketchObject.h b/src/Mod/Sketcher/App/SketchObject.h index b2493e1d2c02..8aa607c26b8e 100644 --- a/src/Mod/Sketcher/App/SketchObject.h +++ b/src/Mod/Sketcher/App/SketchObject.h @@ -33,6 +33,7 @@ #include #include +#include #include "Sketch.h" namespace Sketcher @@ -58,6 +59,8 @@ class SketcherExport SketchObject : public Part::Part2DObject Part ::PropertyGeometryList Geometry; Sketcher::PropertyConstraintList Constraints; App ::PropertyLinkSubList ExternalGeometry; + App ::PropertyLinkList Exports; + App ::PropertyInteger LastGeoID; /** @name methods override Feature */ //@{ /// recalculate the Feature (if no recompute is needed see also solve() and solverNeedsUpdate boolean) @@ -353,7 +356,16 @@ class SketcherExport SketchObject : public Part::Part2DObject virtual DocumentObject *getSubObject(const char *subname, PyObject **pyObj=0, Base::Matrix4D *mat=0, bool transform=true, int depth=0) const override; + std::vector checkSubNames(const std::vector &) const; + std::string checkSubName(const char *) const; + bool geoIdFromShapeType(const char *shapetype, int &geoId, PointPos &posId) const; + std::string convertSubName(const char *) const; + std::string convertSubName(const std::string &subname) const + { return convertSubName(subname.c_str()); } + std::vector > getPointRefs(const char *subname); + protected: + /// get called by the container when a property has changed virtual void onChanged(const App::Property* /*prop*/); virtual void onDocumentRestored(); @@ -403,13 +415,41 @@ class SketcherExport SketchObject : public Part::Part2DObject boost::signals::scoped_connection constraintsRemovedConn; bool AutoLockTangencyAndPerpty(Constraint* cstr, bool bForce = false, bool bLock = true); + + mutable std::vector externalGeoKeys; + mutable std::map > externalGeoMap; + mutable std::map geoMap; + mutable bool geoCached; }; typedef App::FeaturePythonT SketchObjectPython; -const std::string &editPrefix(); -std::vector checkSubNames(const std::vector &); -const char *checkSubName(const char *); +// --------------------------------------------------------- + +class SketcherExport SketchExport: public Part::Part2DObject { + PROPERTY_HEADER(Sketcher::SketchObject); + +public: + SketchExport(); + ~SketchExport(); + + App::PropertyStringList Refs; + App::PropertyString Base; + + App::DocumentObjectExecReturn *execute(void); + virtual void onChanged(const App::Property* /*prop*/); + const char* getViewProviderName(void) const { + return "SketcherGui::ViewProviderSketchExport"; + } + + bool update(); + + App::DocumentObject *getBase() const; + std::set getRefs() const; + const char *getElementName(const char *element) const; + + virtual short mustExecute(void) const override; +}; } //namespace Sketcher diff --git a/src/Mod/Sketcher/Gui/AppSketcherGui.cpp b/src/Mod/Sketcher/Gui/AppSketcherGui.cpp index 46c0fea99a85..3f758864ffe9 100644 --- a/src/Mod/Sketcher/Gui/AppSketcherGui.cpp +++ b/src/Mod/Sketcher/Gui/AppSketcherGui.cpp @@ -113,6 +113,7 @@ PyMOD_INIT_FUNC(SketcherGui) // init objects SketcherGui::ViewProviderSketch ::init(); + SketcherGui::ViewProviderSketchExport ::init(); SketcherGui::ViewProviderPython ::init(); SketcherGui::ViewProviderCustom ::init(); SketcherGui::ViewProviderCustomPython ::init(); diff --git a/src/Mod/Sketcher/Gui/Command.cpp b/src/Mod/Sketcher/Gui/Command.cpp index 3d9927c480da..4d3f9fbcb7f2 100644 --- a/src/Mod/Sketcher/Gui/Command.cpp +++ b/src/Mod/Sketcher/Gui/Command.cpp @@ -613,8 +613,8 @@ void CmdSketcherViewSketch::activated(int iMsg) Gui::Document *doc = getActiveGuiDocument(); SketcherGui::ViewProviderSketch* vp = dynamic_cast(doc->getInEdit()); if (vp) { - doCommand(Gui,"Gui.ActiveDocument.ActiveView.setCameraOrientation(%s.Placement.Rotation.Q)" - ,getObjectCmd(vp->getObject()).c_str()); + runCommand(Gui,"Gui.ActiveDocument.ActiveView.setCameraOrientation(" + "App.Placement(Gui.editDocument().EditingTransform).Rotation.Q)"); } } diff --git a/src/Mod/Sketcher/Gui/CommandAlterGeometry.cpp b/src/Mod/Sketcher/Gui/CommandAlterGeometry.cpp index ede4fe2b545e..35e6bb82556a 100644 --- a/src/Mod/Sketcher/Gui/CommandAlterGeometry.cpp +++ b/src/Mod/Sketcher/Gui/CommandAlterGeometry.cpp @@ -123,7 +123,7 @@ void CmdSketcherToggleConstruction::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); if (SubNames.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select edge(s) from the sketch.")); diff --git a/src/Mod/Sketcher/Gui/CommandConstraints.cpp b/src/Mod/Sketcher/Gui/CommandConstraints.cpp index 4167cd647032..2b41d12a4f4a 100644 --- a/src/Mod/Sketcher/Gui/CommandConstraints.cpp +++ b/src/Mod/Sketcher/Gui/CommandConstraints.cpp @@ -751,7 +751,7 @@ int SketchSelection::setUp(void) } SketchObj = static_cast(selection[0].getObject()); - SketchSubNames = checkSubNames(selection[0].getSubNames()); + SketchSubNames = selection[0].getSubNames(); } else if(selection.size() == 2) { if(selection[0].getObject()->getTypeId().isDerivedFrom(Sketcher::SketchObject::getClassTypeId())){ SketchObj = static_cast(selection[0].getObject()); @@ -762,8 +762,8 @@ int SketchSelection::setUp(void) } // assume always a Part::Feature derived object as support assert(selection[1].getObject()->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())); - SketchSubNames = checkSubNames(selection[0].getSubNames()); - SupportSubNames = checkSubNames(selection[1].getSubNames()); + SketchSubNames = selection[0].getSubNames(); + SupportSubNames = selection[1].getSubNames(); } else if (selection[1].getObject()->getTypeId().isDerivedFrom(Sketcher::SketchObject::getClassTypeId())) { SketchObj = static_cast(selection[1].getObject()); @@ -774,8 +774,8 @@ int SketchSelection::setUp(void) } // assume always a Part::Feature derived object as support assert(selection[0].getObject()->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())); - SketchSubNames = checkSubNames(selection[1].getSubNames()); - SupportSubNames = checkSubNames(selection[0].getSubNames()); + SketchSubNames = selection[1].getSubNames(); + SupportSubNames = selection[0].getSubNames(); } else { ErrorMsg = QObject::tr("One of the selected has to be on the sketch"); @@ -1197,7 +1197,7 @@ void CmdSketcherConstrainHorizontal::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues(); @@ -1444,7 +1444,7 @@ void CmdSketcherConstrainVertical::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues(); @@ -1690,7 +1690,7 @@ void CmdSketcherConstrainLock::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); std::vector GeoId; @@ -1952,7 +1952,7 @@ void CmdSketcherConstrainBlock::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); // Check that the solver does not report redundant/conflicting constraints @@ -2262,7 +2262,7 @@ void CmdSketcherConstrainCoincident::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); if (SubNames.size() < 2) { @@ -2455,7 +2455,7 @@ void CmdSketcherConstrainDistance::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); if (SubNames.size() < 1 || SubNames.size() > 2) { @@ -2828,7 +2828,7 @@ void CmdSketcherConstrainPointOnObject::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); //count curves and points @@ -3011,7 +3011,7 @@ void CmdSketcherConstrainDistanceX::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); if (SubNames.size() < 1 || SubNames.size() > 2) { @@ -3257,7 +3257,7 @@ void CmdSketcherConstrainDistanceY::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); if (SubNames.size() < 1 || SubNames.size() > 2) { @@ -3539,7 +3539,7 @@ void CmdSketcherConstrainParallel::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); // go through the selected subelements @@ -3747,7 +3747,7 @@ void CmdSketcherConstrainPerpendicular::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = dynamic_cast(selection[0].getObject()); if (!Obj || (SubNames.size() != 2 && SubNames.size() != 3)) { @@ -4352,7 +4352,7 @@ void CmdSketcherConstrainTangent::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); if (SubNames.size() != 2 && SubNames.size() != 3){ @@ -4932,7 +4932,7 @@ void CmdSketcherConstrainRadius::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); if (SubNames.empty()) { @@ -5414,7 +5414,7 @@ void CmdSketcherConstrainAngle::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); if (SubNames.size() < 1 || SubNames.size() > 3) { @@ -5902,7 +5902,7 @@ void CmdSketcherConstrainEqual::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); // go through the selected subelements @@ -6089,7 +6089,7 @@ void CmdSketcherConstrainSymmetric::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); if (SubNames.size() != 3 && SubNames.size() != 2) { @@ -6345,7 +6345,7 @@ void CmdSketcherConstrainSnellsLaw::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); if (SubNames.size() != 3) { strError = QObject::tr("Number of selected objects is not 3 (is %1).", dmbg).arg(SubNames.size()); @@ -6485,7 +6485,7 @@ void CmdSketcherConstrainInternalAlignment::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); // go through the selected subelements @@ -6918,7 +6918,7 @@ void CmdSketcherToggleDrivingConstraint::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); if (SubNames.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select constraint(s) from the sketch.")); @@ -6948,7 +6948,7 @@ void CmdSketcherToggleDrivingConstraint::activated(int iMsg) else // toggle the selected constraint(s) { // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); if (SubNames.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select constraint(s) from the sketch.")); diff --git a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp index 13610f5ec132..4eaa3bd51b67 100644 --- a/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp +++ b/src/Mod/Sketcher/Gui/CommandCreateGeo.cpp @@ -6488,10 +6488,15 @@ class DrawSketchHandlerExternal: public DrawSketchHandler virtual bool onSelectionChanged(const Gui::SelectionChanges& msg) { if (msg.Type == Gui::SelectionChanges::AddSelection) { - App::DocumentObject* obj = sketchgui->getObject()->getDocument()->getObject(msg.pObjectName); + auto sels = Gui::Selection().getSelection(0,2,true); + if(sels.empty()) + return false; + auto &sel = sels[0]; + App::DocumentObject* obj = sel.pObject; if (obj == NULL) throw Base::Exception("Sketcher: External geometry: Invalid object in selection"); - std::string subName(msg.pSubName); + const char *dot = strrchr(sel.SubName,'.'); + std::string subName(dot?dot+1:sel.SubName); if (obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId()) || (subName.size() > 4 && subName.substr(0,4) == "Edge") || @@ -6501,7 +6506,7 @@ class DrawSketchHandlerExternal: public DrawSketchHandler Gui::Command::openCommand("Add external geometry"); FCMD_OBJ_CMD2("addExternal(\"%s\",\"%s\")", sketchgui->getObject(), - msg.pObjectName, msg.pSubName); + sel.FeatName, Data::ComplexGeoData::newElementName(sel.SubName).c_str()); Gui::Command::commitCommand(); // adding external geometry does not require a solve() per se (the DoF is the same), diff --git a/src/Mod/Sketcher/Gui/CommandSketcherBSpline.cpp b/src/Mod/Sketcher/Gui/CommandSketcherBSpline.cpp index 727173d27397..b25ef31109ea 100644 --- a/src/Mod/Sketcher/Gui/CommandSketcherBSpline.cpp +++ b/src/Mod/Sketcher/Gui/CommandSketcherBSpline.cpp @@ -368,7 +368,7 @@ void CmdSketcherConvertToNURB::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); bool nurbsized = false; @@ -446,7 +446,7 @@ void CmdSketcherIncreaseDegree::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); openCommand("Increase degree"); @@ -514,7 +514,7 @@ void CmdSketcherIncreaseKnotMultiplicity::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); if(SubNames.size()>1) { // Check that only one object is selected, as we need only one object to get the new GeoId after multiplicity change @@ -672,7 +672,7 @@ void CmdSketcherDecreaseKnotMultiplicity::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); if(SubNames.size()>1) { // Check that only one object is selected, as we need only one object to get the new GeoId after multiplicity change diff --git a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp index 7bed5213160a..537a3cce4077 100644 --- a/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp +++ b/src/Mod/Sketcher/Gui/CommandSketcherTools.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -119,14 +120,13 @@ void CmdSketcherCloseShape::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); + const std::vector &SubNames = Obj->checkSubNames(selection[0].getSubNames()); if (SubNames.size() < 2) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select at least two edges from the sketch.")); return; } - - Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); int GeoIdFirst=-1; int GeoIdLast=-1; @@ -224,13 +224,13 @@ void CmdSketcherConnect::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); + const std::vector &SubNames = Obj->checkSubNames(selection[0].getSubNames()); if (SubNames.size() < 2) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select at least two edges from the sketch.")); return; } - Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); // undo command open openCommand("add coincident constraint"); @@ -306,8 +306,8 @@ void CmdSketcherSelectConstraints::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); + const std::vector &SubNames = Obj->checkSubNames(selection[0].getSubNames()); const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues(); std::string doc_name = Obj->getDocument()->getName(); @@ -605,7 +605,7 @@ void CmdSketcherSelectElementsAssociatedWithConstraints::activated(int iMsg) Sketcher::SketchObject* Obj= vp->getSketchObject(); - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = Obj->checkSubNames(selection[0].getSubNames()); const std::vector< Sketcher::Constraint * > &vals = Obj->Constraints.getValues(); getSelection().clearSelection(); @@ -730,8 +730,8 @@ void CmdSketcherRestoreInternalAlignmentGeometry::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); + const std::vector &SubNames = Obj->checkSubNames(selection[0].getSubNames()); std::string doc_name = Obj->getDocument()->getName(); std::string obj_name = Obj->getNameInDocument(); @@ -822,15 +822,14 @@ void CmdSketcherSymmetry::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); + const std::vector &SubNames = Obj->checkSubNames(selection[0].getSubNames()); if (SubNames.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select elements from a single sketch.")); return; } - Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); - getSelection().clearSelection(); int LastGeoId = 0; @@ -1156,8 +1155,8 @@ void SketcherCopy::activate(bool clone) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); + const std::vector &SubNames = Obj->checkSubNames(selection[0].getSubNames()); getSelection().clearSelection(); @@ -1611,15 +1610,14 @@ void CmdSketcherRectangularArray::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); + const std::vector &SubNames = Obj->checkSubNames(selection[0].getSubNames()); if (SubNames.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select elements from a single sketch.")); return; } - Sketcher::SketchObject* Obj = static_cast(selection[0].getObject()); - getSelection().clearSelection(); int LastGeoId = 0; @@ -1773,7 +1771,6 @@ void CmdSketcherDeleteAllGeometry::activated(int iMsg) // do nothing return; } - } bool CmdSketcherDeleteAllGeometry::isActive(void) @@ -1781,6 +1778,156 @@ bool CmdSketcherDeleteAllGeometry::isActive(void) return isSketcherAcceleratorActive( getActiveGuiDocument(), false ); } +// Export geometry +DEF_STD_CMD_A(CmdSketcherExportGeometry); + +CmdSketcherExportGeometry::CmdSketcherExportGeometry() +:Command("Sketcher_ExportGeometry") +{ + sAppModule = "Sketcher"; + sGroup = QT_TR_NOOP("Sketcher"); + sMenuText = QT_TR_NOOP("Export Single Geometry"); + sToolTipText = QT_TR_NOOP("Export selected geometries as separate child objects"); + sWhatsThis = "Sketcher_ExportGeometry"; + sStatusTip = sToolTipText; + sPixmap = "Sketcher_SketchExport"; + sAccel = ""; + eType = ForEdit; +} + +static void exportSketch(Gui::Command &cmd, bool compound) +{ + std::vector selection = Gui::Selection().getSelectionEx( + 0, App::DocumentObject::getClassTypeId(), 2); + + auto title = QObject::tr("Wrong selection"); + auto msg = QObject::tr("Select any geometry element(s) from the sketch to export.\n" + "You can select an existing export to modify."); + + // only one sketch with its subelements are allowed to be selected + if (selection.empty() || selection.size() > 2) { + QMessageBox::warning(Gui::getMainWindow(), title,msg); + return; + } + + // get the needed lists and objects + int idx = 0; + Sketcher::SketchObject* Obj = dynamic_cast(selection[idx].getObject()); + Sketcher::SketchExport* Export = 0; + if(selection.size()>1) { + if(!Obj) { + idx = 1; + Obj = dynamic_cast(selection[idx].getObject()); + } + Export = dynamic_cast(selection[idx^1].getObject()); + if(!Export || Obj->Exports.find(Export->getNameInDocument())!=Export) { + QMessageBox::warning(Gui::getMainWindow(), title,msg); + return; + } + compound = true; + } + if(!Obj) { + QMessageBox::warning(Gui::getMainWindow(), title,msg); + return; + } + auto grp = App::GeoFeatureGroupExtension::getGroupOfObject(Obj); + + try { + cmd.openCommand("Sketch export"); + if(compound) { + if(!Export) { + std::string FeatName = cmd.getUniqueObjectName("Export",Obj); + FCMD_OBJ_DOC_CMD(Obj,"addObject('Sketcher::SketchExport','"<(Obj->getDocument()->getObject(FeatName.c_str())); + if(!Export) return; + FCMD_OBJ_CMD(Export,"Base = '"<getNameInDocument()<<"'"); + FCMD_OBJ_CMD(Obj,"Exports = {-1:"<(Obj->getDocument()->getObject(FeatName.c_str())); + if(!Export) continue; + FCMD_OBJ_CMD(Export,"Base = '"<getNameInDocument()<<"'"); + FCMD_OBJ_CMD(Obj,"Exports = {-1:"<commandManager(); @@ -1801,4 +1948,6 @@ void CreateSketcherCommandsConstraintAccel(void) rcCmdMgr.addCommand(new CmdSketcherCompCopy()); rcCmdMgr.addCommand(new CmdSketcherRectangularArray()); rcCmdMgr.addCommand(new CmdSketcherDeleteAllGeometry()); + rcCmdMgr.addCommand(new CmdSketcherExportGeometry()); + rcCmdMgr.addCommand(new CmdSketcherExportCompound()); } diff --git a/src/Mod/Sketcher/Gui/CommandSketcherVirtualSpace.cpp b/src/Mod/Sketcher/Gui/CommandSketcherVirtualSpace.cpp index e874f135b104..e06e9186174c 100644 --- a/src/Mod/Sketcher/Gui/CommandSketcherVirtualSpace.cpp +++ b/src/Mod/Sketcher/Gui/CommandSketcherVirtualSpace.cpp @@ -110,6 +110,7 @@ void CmdSketcherSwitchVirtualSpace::activated(int iMsg) bool modeChange=true; std::vector selection; + std::vector SubNames; if (Gui::Selection().countObjectsOfType(Sketcher::SketchObject::getClassTypeId()) > 0){ // Now we check whether we have a constraint selected or not. @@ -125,7 +126,7 @@ void CmdSketcherSwitchVirtualSpace::activated(int iMsg) } // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + SubNames = selection[0].getSubNames(); if (SubNames.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select constraint(s) from the sketch.")); @@ -149,7 +150,6 @@ void CmdSketcherSwitchVirtualSpace::activated(int iMsg) else // toggle the selected constraint(s) { // get the needed lists and objects - const std::vector &SubNames = Sketcher::checkSubNames(selection[0].getSubNames()); if (SubNames.empty()) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select constraint(s) from the sketch.")); diff --git a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc index 8f8daa0da4aa..00d77f8bc032 100644 --- a/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc +++ b/src/Mod/Sketcher/Gui/Resources/Sketcher.qrc @@ -169,6 +169,8 @@ icons/Sketcher_SelectRedundantConstraints.svg icons/Sketcher_SelectVerticalAxis.svg icons/Sketcher_Sketch.svg + icons/Sketcher_SketchExport.svg + icons/Sketcher_SketchExportCompound.svg icons/Sketcher_SwitchVirtualSpace.svg icons/Sketcher_Symmetry.svg icons/Sketcher_ToggleConstraint.svg diff --git a/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_SketchExport.svg b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_SketchExport.svg new file mode 100644 index 000000000000..a2b9c9d09119 --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_SketchExport.svg @@ -0,0 +1,218 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + [wmayer] + + + Sketcher_Sketch + 2011-10-10 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Sketch.svg + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_SketchExportCompound.svg b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_SketchExportCompound.svg new file mode 100644 index 000000000000..0f6f776767ce --- /dev/null +++ b/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_SketchExportCompound.svg @@ -0,0 +1,221 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + [wmayer] + + + Sketcher_Sketch + 2011-10-10 + http://www.freecadweb.org/wiki/index.php?title=Artwork + + + FreeCAD + + + FreeCAD/src/Mod/Sketcher/Gui/Resources/icons/Sketcher_Sketch.svg + + + FreeCAD LGPL2+ + + + https://www.gnu.org/copyleft/lesser.html + + + [agryson] Alexander Gryson + + + + + + + + + + + + + + + + + + diff --git a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp index 0f80c45d4e27..5cb4c6523a58 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherConstrains.cpp @@ -506,7 +506,7 @@ void ConstraintView::deleteSelectedItems() for (std::vector::iterator ft = sel.begin(); ft != sel.end(); ++ft) { Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(ft->getObject()); if (vp) { - vp->onDelete(Sketcher::checkSubNames(ft->getSubNames())); + vp->onDelete(ft->getSubNames()); } } doc->commitTransaction(); @@ -629,7 +629,7 @@ void TaskSketcherConstrains::onSelectionChanged(const Gui::SelectionChanges& msg strcmp(msg.pObjectName,sketchView->getSketchObject()->getNameInDocument())== 0) { if (msg.pSubName) { QRegExp rx(QString::fromLatin1("^Constraint(\\d+)$")); - QString expr = QString::fromLatin1(Sketcher::checkSubName(msg.pSubName)); + QString expr = QString::fromLatin1(msg.pSubName); int pos = expr.indexOf(rx); if (pos > -1) { bool ok; diff --git a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp index 76e6d88c2d87..3c0b6784457b 100644 --- a/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp +++ b/src/Mod/Sketcher/Gui/TaskSketcherElements.cpp @@ -209,7 +209,7 @@ void ElementView::deleteSelectedItems() for (std::vector::iterator ft = sel.begin(); ft != sel.end(); ++ft) { Gui::ViewProvider* vp = Gui::Application::Instance->getViewProvider(ft->getObject()); if (vp) { - vp->onDelete(Sketcher::checkSubNames(ft->getSubNames())); + vp->onDelete(ft->getSubNames()); } } doc->commitTransaction(); @@ -333,8 +333,8 @@ void TaskSketcherElements::onSelectionChanged(const Gui::SelectionChanges& msg) if (strcmp(msg.pDocName,sketchView->getSketchObject()->getDocument()->getName())==0 && strcmp(msg.pObjectName,sketchView->getSketchObject()->getNameInDocument())== 0) { if (msg.pSubName) { - QString expr = QString::fromLatin1(Sketcher::checkSubName(msg.pSubName)); - std::string shapetype(Sketcher::checkSubName(msg.pSubName)); + QString expr = QString::fromLatin1(msg.pSubName); + std::string shapetype(msg.pSubName); // if-else edge vertex if (shapetype.size() > 4 && shapetype.substr(0,4) == "Edge") { QRegExp rx(QString::fromLatin1("^Edge(\\d+)$")); diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 2de2c8793451..53d33fff0601 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -664,10 +664,11 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe if (pp) { //Base::Console().Log("Select Point:%d\n",this->DragPoint); // Do selection - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << edit->PreselectPoint + 1; -#define SEL_PARAMS editDocName.c_str(),editObjName.c_str(),ss.str().c_str() +#define SEL_PARAMS editDocName.c_str(),editObjName.c_str(),\ + (editSubName+getSketchObject()->convertSubName(ss.str())).c_str() if (Gui::Selection().isSelected(SEL_PARAMS) ) { Gui::Selection().rmvSelection(SEL_PARAMS); } else { @@ -685,7 +686,7 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe case STATUS_SELECT_Edge: if (pp) { //Base::Console().Log("Select Point:%d\n",this->DragPoint); - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; if (edit->PreselectCurve >= 0) ss << "Edge" << edit->PreselectCurve + 1; else // external geometry @@ -710,7 +711,7 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe case STATUS_SELECT_Cross: if (pp) { //Base::Console().Log("Select Point:%d\n",this->DragPoint); - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; switch(edit->PreselectCross){ case 0: ss << "RootPoint" ; break; case 1: ss << "H_Axis" ; break; @@ -736,7 +737,7 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe case STATUS_SELECT_Constraint: if (pp) { for(std::set::iterator it = edit->PreselectConstraintSet.begin(); it != edit->PreselectConstraintSet.end(); ++it) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << Sketcher::PropertyConstraintList::getConstraintName(*it); // If the constraint already selected remove @@ -918,7 +919,7 @@ bool ViewProviderSketch::mouseButtonPressed(int Button, bool pressed, const SbVe // only one sketch with its subelements are allowed to be selected if (selection.size() == 1) { // get the needed lists and objects - const std::vector &SubNames = checkSubNames(selection[0].getSubNames()); + const std::vector &SubNames = selection[0].getSubNames(); // Two Objects are selected if (SubNames.size() == 2) { @@ -1463,7 +1464,7 @@ void ViewProviderSketch::onSelectionChanged(const Gui::SelectionChanges& msg) if (strcmp(msg.pDocName,getSketchObject()->getDocument()->getName())==0 && strcmp(msg.pObjectName,getSketchObject()->getNameInDocument())== 0) { if (msg.pSubName) { - std::string shapetype(checkSubName(msg.pSubName)); + std::string shapetype(msg.pSubName); if (shapetype.size() > 4 && shapetype.substr(0,4) == "Edge") { int GeoId = std::atoi(&shapetype[4]) - 1; edit->SelCurvSet.insert(GeoId); @@ -1508,7 +1509,7 @@ void ViewProviderSketch::onSelectionChanged(const Gui::SelectionChanges& msg) if (strcmp(msg.pDocName,getSketchObject()->getDocument()->getName())==0 && strcmp(msg.pObjectName,getSketchObject()->getNameInDocument())== 0) { if (msg.pSubName) { - std::string shapetype(checkSubName(msg.pSubName)); + std::string shapetype(msg.pSubName); if (shapetype.size() > 4 && shapetype.substr(0,4) == "Edge") { int GeoId = std::atoi(&shapetype[4]) - 1; edit->SelCurvSet.erase(GeoId); @@ -1567,7 +1568,7 @@ void ViewProviderSketch::onSelectionChanged(const Gui::SelectionChanges& msg) if (strcmp(msg.pDocName,getSketchObject()->getDocument()->getName())==0 && strcmp(msg.pObjectName,getSketchObject()->getNameInDocument())== 0) { if (msg.pSubName) { - std::string shapetype(checkSubName(msg.pSubName)); + std::string shapetype(msg.pSubName); if (shapetype.size() > 4 && shapetype.substr(0,4) == "Edge") { int GeoId = std::atoi(&shapetype[4]) - 1; resetPreselectPoint(); @@ -1726,7 +1727,7 @@ bool ViewProviderSketch::detectPreselection(const SoPickedPoint *Point, } if (PtIndex != -1 && PtIndex != edit->PreselectPoint) { // if a new point is hit - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << PtIndex + 1; bool accepted = Gui::Selection().setPreselect(SEL_PARAMS @@ -1744,7 +1745,7 @@ bool ViewProviderSketch::detectPreselection(const SoPickedPoint *Point, return true; } } else if (GeoIndex != -1 && GeoIndex != edit->PreselectCurve) { // if a new curve is hit - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; if (GeoIndex >= 0) ss << "Edge" << GeoIndex + 1; else // external geometry @@ -1765,7 +1766,7 @@ bool ViewProviderSketch::detectPreselection(const SoPickedPoint *Point, return true; } } else if (CrossIndex != -1 && CrossIndex != edit->PreselectCross) { // if a cross line is hit - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; switch(CrossIndex){ case 0: ss << "RootPoint" ; break; case 1: ss << "H_Axis" ; break; @@ -1792,7 +1793,7 @@ bool ViewProviderSketch::detectPreselection(const SoPickedPoint *Point, } else if (constrIndices.empty() == false && constrIndices != edit->PreselectConstraintSet) { // if a constraint is hit bool accepted = true; for(std::set::iterator it = constrIndices.begin(); it != constrIndices.end(); ++it) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << Sketcher::PropertyConstraintList::getConstraintName(*it); accepted &= @@ -1948,7 +1949,7 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & VertexId += 1; if (polygon.Contains(Base::Vector2d(pnt0.x, pnt0.y))) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId + 1; Gui::Selection().addSelection(SEL_PARAMS); } @@ -1965,19 +1966,19 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & bool pnt1Inside = polygon.Contains(Base::Vector2d(pnt1.x, pnt1.y)); bool pnt2Inside = polygon.Contains(Base::Vector2d(pnt2.x, pnt2.y)); if (pnt1Inside) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId; Gui::Selection().addSelection(SEL_PARAMS); } if (pnt2Inside) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId + 1; Gui::Selection().addSelection(SEL_PARAMS); } if ((pnt1Inside && pnt2Inside) && !touchMode) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Edge" << GeoId + 1; Gui::Selection().addSelection(SEL_PARAMS); } @@ -1989,7 +1990,7 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & std::list resultList; polygon.Intersect(lineAsPolygon, resultList); if (!resultList.empty()) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Edge" << GeoId + 1; Gui::Selection().addSelection(SEL_PARAMS); } @@ -2007,7 +2008,7 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & if (polygon.Contains(Base::Vector2d(pnt0.x, pnt0.y)) || touchMode) { if (polygon.Contains(Base::Vector2d(pnt0.x, pnt0.y))) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId + 1; Gui::Selection().addSelection(SEL_PARAMS); } @@ -2041,7 +2042,7 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & } if (bpolyInside) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Edge" << GeoId + 1; Gui::Selection().addSelection(SEL_PARAMS); } @@ -2057,7 +2058,7 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & if (polygon.Contains(Base::Vector2d(pnt0.x, pnt0.y)) || touchMode) { if (polygon.Contains(Base::Vector2d(pnt0.x, pnt0.y))) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId + 1; Gui::Selection().addSelection(SEL_PARAMS); } @@ -2092,7 +2093,7 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & } if (bpolyInside) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Edge" << GeoId + 1; Gui::Selection().addSelection(SEL_PARAMS); } @@ -2154,26 +2155,26 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & } if (bpolyInside) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Edge" << GeoId + 1; Gui::Selection().addSelection(SEL_PARAMS); } } if (pnt0Inside) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId - 1; Gui::Selection().addSelection(SEL_PARAMS); } if (pnt1Inside) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId; Gui::Selection().addSelection(SEL_PARAMS); } if (polygon.Contains(Base::Vector2d(pnt2.x, pnt2.y))) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId + 1; Gui::Selection().addSelection(SEL_PARAMS); } @@ -2236,25 +2237,25 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & } if (bpolyInside) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Edge" << GeoId + 1; Gui::Selection().addSelection(SEL_PARAMS); } } if (pnt0Inside) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId - 1; Gui::Selection().addSelection(SEL_PARAMS); } if (pnt1Inside) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId; Gui::Selection().addSelection(SEL_PARAMS); } if (polygon.Contains(Base::Vector2d(pnt2.x, pnt2.y))) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId + 1; Gui::Selection().addSelection(SEL_PARAMS); } @@ -2320,24 +2321,24 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & } if (bpolyInside) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Edge" << GeoId + 1; Gui::Selection().addSelection(SEL_PARAMS); } if (pnt0Inside) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId - 1; Gui::Selection().addSelection(SEL_PARAMS); } if (pnt1Inside) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId; Gui::Selection().addSelection(SEL_PARAMS); } if (polygon.Contains(Base::Vector2d(pnt2.x, pnt2.y))) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId + 1; Gui::Selection().addSelection(SEL_PARAMS); } @@ -2406,24 +2407,24 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & } if (bpolyInside) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Edge" << GeoId + 1; Gui::Selection().addSelection(SEL_PARAMS); } if (pnt0Inside) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId - 1; Gui::Selection().addSelection(SEL_PARAMS); } if (pnt1Inside) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId; Gui::Selection().addSelection(SEL_PARAMS); } if (polygon.Contains(Base::Vector2d(pnt2.x, pnt2.y))) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId + 1; Gui::Selection().addSelection(SEL_PARAMS); } @@ -2442,13 +2443,13 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & bool pnt1Inside = polygon.Contains(Base::Vector2d(pnt1.x, pnt1.y)); bool pnt2Inside = polygon.Contains(Base::Vector2d(pnt2.x, pnt2.y)); if (pnt1Inside || (touchMode && pnt2Inside)) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId; Gui::Selection().addSelection(SEL_PARAMS); } if (pnt2Inside || (touchMode && pnt1Inside)) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Vertex" << VertexId + 1; Gui::Selection().addSelection(SEL_PARAMS); } @@ -2459,7 +2460,7 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & // where it is indeed comprised in the box. // The implementation of the touch mode is also far from a desirable "touch" as it only recognizes touched points not the curve itself if ((pnt1Inside && pnt2Inside) || (touchMode && (pnt1Inside || pnt2Inside))) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "Edge" << GeoId + 1; Gui::Selection().addSelection(SEL_PARAMS); } @@ -2468,7 +2469,7 @@ void ViewProviderSketch::doBoxSelection(const SbVec2s &startPos, const SbVec2s & pnt0 = proj(Plm.getPosition()); if (polygon.Contains(Base::Vector2d(pnt0.x, pnt0.y))) { - std::ostringstream ss(editPrefix,std::ios_base::ate); + std::stringstream ss; ss << "RootPoint"; Gui::Selection().addSelection(SEL_PARAMS); } @@ -5301,6 +5302,7 @@ bool ViewProviderSketch::setEdit(int ModNum) " tv.show([ref[0] for ref in ActiveSketch.Support if not ref[0].isDerivedFrom(\"PartDesign::Plane\")])\n" "if ActiveSketch.ViewObject.ShowLinks:\n" " tv.show([ref[0] for ref in ActiveSketch.ExternalGeometry])\n" + "tv.hide(ActiveSketch.Exports)\n" "tv.hide(ActiveSketch)\n" "ActiveSketch.ViewObject.TempoVis = tv\n" "del(tv)\n" @@ -5780,7 +5782,6 @@ void ViewProviderSketch::setEditViewer(Gui::View3DInventorViewer* viewer, int Mo editSubName.clear(); else editSubName.resize(dot-editSubName.c_str()+1); - editPrefix = editSubName + Sketcher::editPrefix(); Base::Placement plm = getEditingPlacement(); Base::Rotation tmp(plm.getRotation()); @@ -5965,7 +5966,7 @@ Sketcher::SketchObject *ViewProviderSketch::getSketchObject(void) const bool ViewProviderSketch::onDelete(const std::vector &subList) { if (edit) { - std::vector SubNames = subList; + std::vector SubNames = getSketchObject()->checkSubNames(subList); Gui::Selection().clearSelection(); resetPreselectPoint(); @@ -6098,3 +6099,126 @@ void ViewProviderSketch::showRestoreInformationLayer() { visibleInformationChanged = true ; draw(false,false); } + +std::vector ViewProviderSketch::claimChildren(void) const { + return getSketchObject()->Exports.getValues(); +} + +void ViewProviderSketch::selectElement(const char *element) const { + if(!edit || !element) return; + std::ostringstream ss; + ss << getSketchObject()->checkSubName(element); + Gui::Selection().addSelection(SEL_PARAMS); +} + +// --------------------------------------------------------- + +PROPERTY_SOURCE(SketcherGui::ViewProviderSketchExport, PartGui::ViewProvider2DObject) + +ViewProviderSketchExport::ViewProviderSketchExport() { + sPixmap = "Sketcher_SketchExport"; +} + +bool ViewProviderSketchExport::doubleClicked(void) { + auto obj = dynamic_cast(getObject()); + if(!obj) return false; + auto base = dynamic_cast(obj->getBase()); + if(!base) return false; + auto vp = dynamic_cast(Gui::Application::Instance->getViewProvider(base)); + if(!vp) return false; + + // Now comes the tricky part to detect where we are clicked, and activate + // edit-in-place in case we are being linked to some other place. In normal + // cases, Gui::Document can auto detect that, but here we need to forward + // the editing to parent sketch. Our goal is to select the base sketch in + // the correct position within the object hierarchy to help Gui::Document + // deduct the correct editing placement + // + // First, obtain the raw selection + auto sels = Gui::Selection().getSelection(0,0); + bool transform = false; + Base::Matrix4D mat; + if(sels.size()==1 && sels[0].pObject) { + // First, check if we are being selected. If so obtain the accumulated transformation + auto &sel = sels[0]; + auto sobj = sel.pObject->getSubObject(sel.SubName,0,&mat); + if(sobj && sobj->getLinkedObject(true)==obj) { + auto linked = sel.pObject->getLinkedObject(true); + if(linked == obj) + transform = true; + else if(linked == base) { + // if the top level object is the sketch or linked to the sketch, + // simply select it. + Gui::Selection().clearCompleteSelection(); + Gui::Selection().addSelection(sel.DocName,sel.FeatName,""); + transform = true; + } else { + std::string selSubname; + App::DocumentObject *group = 0; + App::DocumentObject *feat = sel.pObject; + if(feat->getLinkedObject(true)->hasExtension( + App::GeoFeatureGroupExtension::getExtensionClassTypeId())) + group = feat; + const char *subname = sel.SubName; + // Walk down the object hierachy in SubName to find the sketch + for(const char *dot=strchr(subname,'.');dot;subname=dot+1,dot=strchr(subname,'.')) { + std::string name(subname,dot-subname+1); + auto sobj = feat->getSubObject(name.c_str()); + if(!sobj) break; + auto linked = sobj->getLinkedObject(true); + if(linked == base) { + // found the base sketch, shorten the subname + selSubname = std::string(sel.SubName,subname); + transform = true; + break; + } + if(linked == obj) { + // found ourself, but no parent sketch in the path + if(group) { + // if we found a geo group in the path, try to see if + // the group contains the parent sketch + name = base->getNameInDocument(); + name += '.'; + transform = group->getSubObject(name.c_str()) == base; + } + break; + }else if(linked->hasExtension(App::GeoFeatureGroupExtension::getExtensionClassTypeId())) { + // remember last geo group in the path + group = sobj; + selSubname = std::string(sel.SubName,dot+1); + } + feat = sobj; + } + + if(transform) { + Gui::Selection().clearCompleteSelection(); + selSubname += base->getNameInDocument(); + selSubname += '.'; + Gui::Selection().addSelection(sel.DocName,sel.FeatName,selSubname.c_str()); + } + } + } + } + // Now forward the editing request + if(!vp->doubleClicked()) return false; + + if(transform) { + auto doc = Gui::Application::Instance->editDocument(); + if(doc) { + doc->setEditingTransform(mat); + auto cmd = Gui::Application::Instance->commandManager().getCommandByName("Sketcher_ViewSketch"); + if (cmd) cmd->invoke(0); + } + } + + // Select our references in the parent sketch + for(auto &ref : obj->getRefs()) + vp->selectElement(ref.c_str()); + + // Finally, select ourself + std::string name(obj->getNameInDocument()); + name += '.'; + vp->selectElement(name.c_str()); + return true; +} + diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.h b/src/Mod/Sketcher/Gui/ViewProviderSketch.h index e61059578d18..daf2888a637f 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.h +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.h @@ -242,6 +242,9 @@ class SketcherGuiExport ViewProviderSketch : public PartGui::ViewProvider2DObjec /// signals if the elements list has changed boost::signal signalElementsChanged; + virtual std::vector claimChildren(void) const override; + void selectElement(const char *element) const; + protected: Base::Placement getEditingPlacement() const; @@ -418,12 +421,24 @@ class SketcherGuiExport ViewProviderSketch : public PartGui::ViewProvider2DObjec std::string editDocName; std::string editObjName; std::string editSubName; - std::string editPrefix; // Virtual space variables bool isShownVirtualSpace; // indicates whether the present virtual space view is the Real Space or the Virtual Space (virtual space 1 or 2) }; +// --------------------------------------------------------- + +class SketcherGuiExport ViewProviderSketchExport: public PartGui::ViewProvider2DObject +{ + PROPERTY_HEADER(SketcherGui::ViewProviderSketchSketch); + +public: + typedef PartGui::ViewProvider2DObject inherited; + + ViewProviderSketchExport(); + virtual bool doubleClicked(void) override; +}; + } // namespace PartGui diff --git a/src/Mod/Sketcher/Gui/Workbench.cpp b/src/Mod/Sketcher/Gui/Workbench.cpp index 5b6830f273a5..e6c9eea6dcf2 100644 --- a/src/Mod/Sketcher/Gui/Workbench.cpp +++ b/src/Mod/Sketcher/Gui/Workbench.cpp @@ -203,6 +203,9 @@ inline void SketcherAddWorkbenchGeometries(T& geom){ << "Sketcher_External" << "Sketcher_CarbonCopy" << "Sketcher_ToggleConstruction" + << "Separator" + << "Sketcher_ExportGeometry" + << "Sketcher_ExportCompound" /*<< "Sketcher_CreateText"*/ /*<< "Sketcher_CreateDraftLine"*/; }