From 29eb1a4299f07f04b574aa72fe677fc1ec72f190 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Sun, 14 Jul 2019 06:31:30 +0800 Subject: [PATCH] App: GeoFeature/ComplexGeoData API changes These are the bare minimum set of APIs for future new topogical naming feature (see [here](https://git.io/fj6hy) for a overview of the new APIs). These APIs are added early to avoid too much code change for the new features introduced in the current patch set. --- src/App/ComplexGeoData.cpp | 98 +++++++++++++++++++++++++++++++++ src/App/ComplexGeoData.h | 37 +++++++++++++ src/App/ComplexGeoDataPy.xml | 6 ++ src/App/ComplexGeoDataPyImp.cpp | 8 +++ src/App/GeoFeature.cpp | 59 ++++++++++++++++++++ src/App/GeoFeature.h | 43 ++++++++++++++- 6 files changed, 250 insertions(+), 1 deletion(-) diff --git a/src/App/ComplexGeoData.cpp b/src/App/ComplexGeoData.cpp index 7af8e84c24..477d3eb011 100644 --- a/src/App/ComplexGeoData.cpp +++ b/src/App/ComplexGeoData.cpp @@ -27,7 +27,10 @@ # include #endif +#include +#include +#include #include "ComplexGeoData.h" using namespace Data; @@ -39,6 +42,7 @@ TYPESYSTEM_SOURCE_ABSTRACT(Data::ComplexGeoData , Base::Persistence); ComplexGeoData::ComplexGeoData(void) + :Tag(0) { } @@ -153,3 +157,97 @@ bool ComplexGeoData::getCenterOfGravity(Base::Vector3d&) const { return false; } + +const std::string &ComplexGeoData::elementMapPrefix() { + static std::string prefix(";"); + return prefix; +} + +const char *ComplexGeoData::isMappedElement(const char *name) { + if(name && boost::starts_with(name,elementMapPrefix())) + return name+elementMapPrefix().size(); + return 0; +} + +std::string ComplexGeoData::newElementName(const char *name) { + if(!name) return std::string(); + const char *dot = strrchr(name,'.'); + if(!dot || dot==name) return name; + const char *c = dot-1; + for(;c!=name;--c) { + if(*c == '.') { + ++c; + break; + } + } + if(isMappedElement(c)) + return std::string(name,dot-name); + return name; +} + +std::string ComplexGeoData::oldElementName(const char *name) { + if(!name) return std::string(); + const char *dot = strrchr(name,'.'); + if(!dot || dot==name) return name; + const char *c = dot-1; + for(;c!=name;--c) { + if(*c == '.') { + ++c; + break; + } + } + if(isMappedElement(c)) + return std::string(name,c-name)+(dot+1); + return name; +} + +std::string ComplexGeoData::noElementName(const char *name) { + auto element = findElementName(name); + if(element) + return std::string(name,element-name); + return name; +} + +const char *ComplexGeoData::findElementName(const char *subname) { + if(!subname || !subname[0] || isMappedElement(subname)) + return subname; + const char *dot = strrchr(subname,'.'); + if(!dot) + return subname; + const char *element = dot+1; + if(dot==subname || isMappedElement(element)) + return element; + for(--dot;dot!=subname;--dot) { + if(*dot == '.') { + ++dot; + break; + } + } + if(isMappedElement(dot)) + return dot; + return element; +} + +const std::string &ComplexGeoData::tagPostfix() { + static std::string postfix(elementMapPrefix() + ":T"); + return postfix; +} + +const std::string &ComplexGeoData::indexPostfix() { + static std::string postfix(elementMapPrefix() + ":I"); + return postfix; +} + +const std::string &ComplexGeoData::missingPrefix() { + static std::string prefix("?"); + return prefix; +} + +bool ComplexGeoData::hasMissingElement(const char *subname) { + if(!subname) + return false; + auto dot = strrchr(subname,'.'); + if(dot) + subname = dot+1; + return boost::starts_with(subname,missingPrefix()); +} diff --git a/src/App/ComplexGeoData.h b/src/App/ComplexGeoData.h index 8133cb1bfb..f9f682be0b 100644 --- a/src/App/ComplexGeoData.h +++ b/src/App/ComplexGeoData.h @@ -156,6 +156,41 @@ public: virtual bool getCenterOfGravity(Base::Vector3d& center) const; //@} + /** @name Element name mapping */ + //@{ + /// Sepecial prefix to mark the begining of a mapped sub-element name + static const std::string &elementMapPrefix(); + /// Sepecial postfix to mark the following tag + static const std::string &tagPostfix(); + /// Speical postfix to mark the index of an array element + static const std::string &indexPostfix(); + /// Speical prefix to mark a missing element + static const std::string &missingPrefix(); + /// Check if a subname contains missing element + static bool hasMissingElement(const char *subname); + /** Check if the name starts with elementMapPrefix() + * + * @param name: input name + * @return Returns the name stripped with elementMapPrefix(), or 0 if not + * start with the prefix + */ + static const char *isMappedElement(const char *name); + + /// Strip out the trailing element name if there is mapped element name preceeds it. + static std::string newElementName(const char *name); + /// Strip out the mapped element name if there is one. + static std::string oldElementName(const char *name); + /// Strip out the old and new element name if there is one. + static std::string noElementName(const char *name); + + /// Find the start of an element name in a subname + static const char *findElementName(const char *subname); + + static inline const char *hasMappedElementName(const char *subname) { + return isMappedElement(findElementName(subname)); + } + //@} + protected: /// from local to outside @@ -171,6 +206,8 @@ protected: Base::Vector3d tmp = tmpM * vec; return Base::Vector3f((float)tmp.x,(float)tmp.y,(float)tmp.z); } +public: + mutable long Tag; }; } //namespace App diff --git a/src/App/ComplexGeoDataPy.xml b/src/App/ComplexGeoDataPy.xml index f65ca406a4..c341734a18 100644 --- a/src/App/ComplexGeoDataPy.xml +++ b/src/App/ComplexGeoDataPy.xml @@ -37,5 +37,11 @@ + + + Geometry Tag + + + diff --git a/src/App/ComplexGeoDataPyImp.cpp b/src/App/ComplexGeoDataPyImp.cpp index 0d74a2b3a8..cecffe3191 100644 --- a/src/App/ComplexGeoDataPyImp.cpp +++ b/src/App/ComplexGeoDataPyImp.cpp @@ -126,6 +126,14 @@ void ComplexGeoDataPy::setMatrix(Py::Object arg) } } +Py::Int ComplexGeoDataPy::getTag() const { + return Py::Int(getComplexGeoDataPtr()->Tag); +} + +void ComplexGeoDataPy::setTag(Py::Int tag) { + getComplexGeoDataPtr()->Tag = tag; +} + PyObject *ComplexGeoDataPy::getCustomAttributes(const char* /*attr*/) const { return 0; diff --git a/src/App/GeoFeature.cpp b/src/App/GeoFeature.cpp index 7f1b201a6e..379cf7cb8d 100644 --- a/src/App/GeoFeature.cpp +++ b/src/App/GeoFeature.cpp @@ -79,3 +79,62 @@ PyObject* GeoFeature::getPyObject(void) } return Py::new_reference_to(PythonObject); } + + +std::pair GeoFeature::getElementName( + const char *name, ElementNameType type) const +{ + (void)type; + + std::pair ret; + if(!name) return ret; + + ret.second = name; + return ret; +} + +DocumentObject *GeoFeature::resolveElement(DocumentObject *obj, const char *subname, + std::pair &elementName, bool append, + ElementNameType type, const DocumentObject *filter, + const char **_element, GeoFeature **geoFeature) +{ + if(!obj || !obj->getNameInDocument()) + return 0; + if(!subname) + subname = ""; + const char *element = Data::ComplexGeoData::findElementName(subname); + if(_element) *_element = element; + auto sobj = obj->getSubObject(subname); + if(!sobj) + return 0; + obj = sobj->getLinkedObject(true); + auto geo = dynamic_cast(obj); + if(geoFeature) + *geoFeature = geo; + if(!obj || (filter && obj!=filter)) + return 0; + if(!element || !element[0]) { + if(append) + elementName.second = Data::ComplexGeoData::oldElementName(subname); + return sobj; + } + + if(!geo || hasHiddenMarker(element)) { + if(!append) + elementName.second = element; + else + elementName.second = Data::ComplexGeoData::oldElementName(subname); + return sobj; + } + if(!append) + elementName = geo->getElementName(element,type); + else{ + const auto &names = geo->getElementName(element,type); + std::string prefix(subname,element-subname); + if(names.first.size()) + elementName.first = prefix + names.first; + elementName.second = prefix + names.second; + } + return sobj; +} + diff --git a/src/App/GeoFeature.h b/src/App/GeoFeature.h index 673b1516c3..bda64a21d3 100644 --- a/src/App/GeoFeature.h +++ b/src/App/GeoFeature.h @@ -66,7 +66,48 @@ public: * @return the Python binding object */ virtual PyObject* getPyObject(void); - + + /// Specify the type of element name to return when calling getElementName() + enum ElementNameType { + /// Normal usage + Normal=0, + /// For importing + Import=1, + /// For exporting + Export=2, + }; + /** Return the new and old style sub-element name + * + * @param name: input name + * @param type: desired element name type to return + * + * @return a pair(newName,oldName). New element name may be empty. + * + * This function currently is does nothing. The new style element name + * generation will be added in the next batch of patches. + */ + virtual std::pair getElementName( + const char *name, ElementNameType type=Normal) const; + + /** Resolve both the new and old style element name + * + * @param obj: top parent object + * @param subname: subname reference + * @param elementName: output of a pair(newElementName,oldElementName) + * @param append: Whether to include subname prefix into the returned + * element name + * @param type: the type of element name to request + * @param filter: If none zero, then only perform lookup when the element + * owner object is the same as this filter + * @param element: return the start of element name in subname + * + * @return Return the owner object of the element + */ + static DocumentObject *resolveElement(App::DocumentObject *obj, + const char *subname, std::pair &elementName, + bool append=false, ElementNameType type=Normal, + const DocumentObject *filter=0,const char **element=0, GeoFeature **geo=0); + /** * @brief Calculates the placement in the global reference coordinate system *