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.
This commit is contained in:
Zheng, Lei
2019-07-14 06:31:30 +08:00
committed by wmayer
parent c5112ecdc5
commit 29eb1a4299
6 changed files with 250 additions and 1 deletions

View File

@@ -27,7 +27,10 @@
# include <cstdlib>
#endif
#include <boost/algorithm/string/predicate.hpp>
#include <Base/Exception.h>
#include <Base/Console.h>
#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());
}

View File

@@ -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

View File

@@ -37,5 +37,11 @@
</Documentation>
<Parameter Name="Matrix" Type="Object" />
</Attribute>
<Attribute Name="Tag">
<Documentation>
<UserDocu>Geometry Tag</UserDocu>
</Documentation>
<Parameter Name="Tag" Type="Int"/>
</Attribute>
</PythonExport>
</GenerateModel>

View File

@@ -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;

View File

@@ -79,3 +79,62 @@ PyObject* GeoFeature::getPyObject(void)
}
return Py::new_reference_to(PythonObject);
}
std::pair<std::string,std::string> GeoFeature::getElementName(
const char *name, ElementNameType type) const
{
(void)type;
std::pair<std::string,std::string> ret;
if(!name) return ret;
ret.second = name;
return ret;
}
DocumentObject *GeoFeature::resolveElement(DocumentObject *obj, const char *subname,
std::pair<std::string,std::string> &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<GeoFeature*>(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;
}

View File

@@ -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<std::string,std::string> 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<std::string,std::string> &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
*