Merge pull request #25199 from pieterhijma/doc-element-mapping
Doc: Improve the documentation of element mapping
This commit is contained in:
@@ -57,18 +57,21 @@ namespace Data
|
||||
{
|
||||
|
||||
// struct MappedChildElements;
|
||||
|
||||
/// Option for App::GeoFeature::searchElementCache()
|
||||
enum class SearchOption
|
||||
{
|
||||
/// Whether to compare shape geometry
|
||||
CheckGeometry = 1,
|
||||
SingleResult = 2,
|
||||
CheckGeometry = 1, ///< Whether to compare shape geometry
|
||||
SingleResult = 2, ///< Stop at first found result
|
||||
};
|
||||
|
||||
typedef Base::Flags<SearchOption> SearchOptions;
|
||||
|
||||
/** Segments
|
||||
* Sub-element type of the ComplexGeoData type
|
||||
* It is used to split an object in further sub-parts.
|
||||
/**
|
||||
* @brief A class for segments.
|
||||
*
|
||||
* A segment is a sub-element type of the ComplexGeoData type. It is used to
|
||||
* split an object in further sub-parts.
|
||||
*/
|
||||
class AppExport Segment: public Base::BaseClass
|
||||
{
|
||||
@@ -76,200 +79,356 @@ class AppExport Segment: public Base::BaseClass
|
||||
|
||||
public:
|
||||
~Segment() override = default;
|
||||
|
||||
/// Get the name of the segment.
|
||||
virtual std::string getName() const = 0;
|
||||
};
|
||||
|
||||
enum ElementMapResetPolicy
|
||||
{
|
||||
AllowNoMap,
|
||||
ForceEmptyMap
|
||||
};
|
||||
|
||||
/** ComplexGeoData Object
|
||||
/**
|
||||
* @brief A class for complex geometric data.
|
||||
* @ingroup ElementMapping
|
||||
*/
|
||||
class AppExport ComplexGeoData: public Base::Persistence, public Base::Handled
|
||||
{
|
||||
TYPESYSTEM_HEADER_WITH_OVERRIDE(); // NOLINT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief A line as a facet boundary in a 3D mesh.
|
||||
*
|
||||
* The line is represented by two point indices.
|
||||
*/
|
||||
struct Line
|
||||
{
|
||||
uint32_t I1;
|
||||
uint32_t I2;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A triangular facet in a 3D mesh.
|
||||
*
|
||||
* The facet is represented by three point indices.
|
||||
*/
|
||||
struct Facet
|
||||
{
|
||||
uint32_t I1;
|
||||
uint32_t I2;
|
||||
uint32_t I3;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A domain in a 3D mesh.
|
||||
*
|
||||
* A domain consists of a list of points and a list of facets where the
|
||||
* indices of a facet index into the points list.
|
||||
*/
|
||||
struct Domain
|
||||
{
|
||||
std::vector<Base::Vector3d> points;
|
||||
std::vector<Facet> facets;
|
||||
};
|
||||
|
||||
/// Constructor
|
||||
ComplexGeoData();
|
||||
/// Destructor
|
||||
~ComplexGeoData() override = default;
|
||||
|
||||
/** @name Sub-element management */
|
||||
//@{
|
||||
/** Sub type list
|
||||
* List of different sub-element types
|
||||
* its NOT a list of the sub-elements itself
|
||||
/**
|
||||
* @name Sub-element management
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Get a list of sub-element types.
|
||||
*
|
||||
* This list does not contain the sub-elements themselves.
|
||||
*/
|
||||
virtual std::vector<const char*> getElementTypes() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Get the number of sub-elements of a given type.
|
||||
*
|
||||
* @param[in] Type The type of sub-element.
|
||||
* @return The number of sub-elements of the given type.
|
||||
*/
|
||||
virtual unsigned long countSubElements(const char* Type) const = 0;
|
||||
/// Returns a generic element type and index. The determined element type isn't
|
||||
/// necessarily supported by this geometry.
|
||||
|
||||
/**
|
||||
* @brief Get the type and index from a combined name.
|
||||
*
|
||||
* An example is "Edge12", which would return the type "Edge" and the
|
||||
* index 12.
|
||||
*
|
||||
* @param[in] Name The combined name of the sub-element.
|
||||
* @returns A pair of a generic element type and index.
|
||||
*
|
||||
* @note The determined element type isn't necessarily supported by this
|
||||
* geometry.
|
||||
*/
|
||||
static std::pair<std::string, unsigned long> getTypeAndIndex(const char* Name);
|
||||
/// get the sub-element by type and number
|
||||
|
||||
/// Get the sub-element by type and number.
|
||||
virtual Segment* getSubElement(const char* Type, unsigned long) const = 0;
|
||||
/// get sub-element by combined name
|
||||
|
||||
/// Get sub-element by combined name
|
||||
virtual Segment* getSubElementByName(const char* Name) const;
|
||||
/** Get lines from segment */
|
||||
virtual void getLinesFromSubElement(const Segment*,
|
||||
|
||||
/**
|
||||
* @brief Get the lines from a segment.
|
||||
*
|
||||
* @param[in] segment The segment to get the lines from.
|
||||
*
|
||||
* @param[in,out] Points The list of points used by the lines.
|
||||
* @param[in,out] lines The list of lines retrieved from the segment.
|
||||
*/
|
||||
virtual void getLinesFromSubElement(const Segment* segment,
|
||||
std::vector<Base::Vector3d>& Points,
|
||||
std::vector<Line>& lines) const;
|
||||
/** Get faces from segment */
|
||||
virtual void getFacesFromSubElement(const Segment*,
|
||||
|
||||
/**
|
||||
* @brief Get the faces from a segment.
|
||||
*
|
||||
* @param[in] segment The segment to get the faces from.
|
||||
* @param[in,out] Points The list of points used by the faces.
|
||||
* @param[in,out] PointNormals The list of point normals used by the faces.
|
||||
* @param[in,out] faces The list of faces retrieved from the segment.
|
||||
*/
|
||||
virtual void getFacesFromSubElement(const Segment* segment,
|
||||
std::vector<Base::Vector3d>& Points,
|
||||
std::vector<Base::Vector3d>& PointNormals,
|
||||
std::vector<Facet>& faces) const;
|
||||
//@}
|
||||
/// @}
|
||||
|
||||
/** @name Placement control */
|
||||
//@{
|
||||
/** Applies an additional transformation to the current transformation. */
|
||||
/**
|
||||
* @name Placement control
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/// Apply an additional transformation to the current transformation.
|
||||
void applyTransform(const Base::Matrix4D& rclTrf);
|
||||
/** Applies an additional translation to the current transformation. */
|
||||
|
||||
/// Apply an additional translation to the current transformation.
|
||||
void applyTranslation(const Base::Vector3d&);
|
||||
/** Applies an additional rotation to the current transformation. */
|
||||
|
||||
/// Applies an additional rotation to the current transformation.
|
||||
void applyRotation(const Base::Rotation&);
|
||||
/** Override the current transformation with a placement
|
||||
* using the setTransform() method.
|
||||
|
||||
/**
|
||||
* @brief Override the current transformation with a placement.
|
||||
*
|
||||
* Override the current transformation with a placement using the
|
||||
* setTransform() method.
|
||||
*
|
||||
* @param[in] rclPlacement The new placement to set.
|
||||
*/
|
||||
void setPlacement(const Base::Placement& rclPlacement);
|
||||
/** Return the current transformation as placement using
|
||||
* getTransform().
|
||||
|
||||
/**
|
||||
* @brief Get the current transformation as placement.
|
||||
*
|
||||
* @return The current transformation as placement using getTransform().
|
||||
*/
|
||||
Base::Placement getPlacement() const;
|
||||
/** Override the current transformation with the new one.
|
||||
* This method has to be handled by the child classes.
|
||||
* the actual placement and matrix is not part of this class.
|
||||
|
||||
/**
|
||||
* @brief Override the current transformation.
|
||||
*
|
||||
* Override the current transformation with the new one. This method has
|
||||
* to be handled by the child classes. the actual placement and matrix is
|
||||
* not part of this class.
|
||||
*
|
||||
* @param[in] rclTrf The new transformation matrix to set.
|
||||
*/
|
||||
|
||||
virtual void setTransform(const Base::Matrix4D& rclTrf) = 0;
|
||||
/** Return the current matrix
|
||||
* This method has to be handled by the child classes.
|
||||
* the actual placement and matrix is not part of this class.
|
||||
|
||||
/**
|
||||
* @brief Get the current transformation matrix.
|
||||
*
|
||||
* This method has to be handled by the child classes. The actual
|
||||
* placement and matrix is not part of this class.
|
||||
*/
|
||||
virtual Base::Matrix4D getTransform() const = 0;
|
||||
//@}
|
||||
/// @}
|
||||
|
||||
/** @name Modification */
|
||||
//@{
|
||||
/// Applies a transformation on the real geometric data type
|
||||
/**
|
||||
*@name Modification
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Applies a transformation on the real geometric data type.
|
||||
*
|
||||
* @param[in] rclMat The transformation matrix to apply.
|
||||
*/
|
||||
virtual void transformGeometry(const Base::Matrix4D& rclMat) = 0;
|
||||
//@}
|
||||
/// @}
|
||||
|
||||
/** @name Getting basic geometric entities */
|
||||
//@{
|
||||
/// Get the standard accuracy to be used with getPoints, getLines or getFaces
|
||||
/**
|
||||
* @name Getting basic geometric entities
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Get the standard accuracy for meshing.
|
||||
*
|
||||
* Get the standard accuracy to be used with getPoints(), getLines() or
|
||||
* getFaces().
|
||||
*
|
||||
* @return The standard accuracy.
|
||||
*/
|
||||
virtual double getAccuracy() const;
|
||||
|
||||
/// Get the bound box
|
||||
virtual Base::BoundBox3d getBoundBox() const = 0;
|
||||
/** Get point from line object intersection */
|
||||
|
||||
/**
|
||||
* @brief Get point from line object intersection.
|
||||
*
|
||||
* @param[in] base The base point of the line.
|
||||
* @param[in] dir The direction of the line.
|
||||
*
|
||||
* @return The intersection point.
|
||||
*/
|
||||
virtual Base::Vector3d getPointFromLineIntersection(const Base::Vector3f& base,
|
||||
const Base::Vector3f& dir) const;
|
||||
/** Get points from object with given accuracy */
|
||||
|
||||
/**
|
||||
* @brief Get points from object with given accuracy.
|
||||
*
|
||||
* @param[in,out] Points The list of points retrieved from the object.
|
||||
* @param[in,out] Normals The list of normals associated with faces
|
||||
* retrieved from the object. If there are no faces, then this list will
|
||||
* be empty.
|
||||
* @param[in] Accuracy The accuracy to use when retrieving the points.
|
||||
* @param[in] flags Additional flags for point retrieval.
|
||||
*/
|
||||
virtual void getPoints(std::vector<Base::Vector3d>& Points,
|
||||
std::vector<Base::Vector3d>& Normals,
|
||||
double Accuracy,
|
||||
uint16_t flags = 0) const;
|
||||
/** Get lines from object with given accuracy */
|
||||
|
||||
/**
|
||||
* @brief Get lines from object with given accuracy
|
||||
*
|
||||
* @param[in,out] Points The list of points retrieved from the object.
|
||||
* @param[in,out] lines The list of lines retrieved from the object.
|
||||
* @param[in] Accuracy The accuracy to use when retrieving the lines.
|
||||
* @param[in] flags Additional flags for line retrieval.
|
||||
*/
|
||||
virtual void getLines(std::vector<Base::Vector3d>& Points,
|
||||
std::vector<Line>& lines,
|
||||
double Accuracy,
|
||||
uint16_t flags = 0) const;
|
||||
/** Get faces from object with given accuracy */
|
||||
|
||||
/**
|
||||
* @brief Get faces from object with given accuracy.
|
||||
*
|
||||
* @param[in,out] Points The list of points retrieved from the object.
|
||||
* @param[in,out] faces The list of faces retrieved from the object.
|
||||
* @param[in] Accuracy The accuracy to use when retrieving the faces.
|
||||
* @param[in] flags Additional flags for face retrieval.
|
||||
*/
|
||||
virtual void getFaces(std::vector<Base::Vector3d>& Points,
|
||||
std::vector<Facet>& faces,
|
||||
double Accuracy,
|
||||
uint16_t flags = 0) const;
|
||||
/** Get the center of gravity
|
||||
* If this method is implemented then true is returned and the center of gravity.
|
||||
* The default implementation only returns false.
|
||||
|
||||
/**
|
||||
* @brief Get the center of gravity.
|
||||
*
|
||||
* @param[out] center The center of gravity.
|
||||
*
|
||||
* @return True if this method is implemented. The default implementation returns false.
|
||||
*/
|
||||
virtual bool getCenterOfGravity(Base::Vector3d& center) const;
|
||||
virtual std::optional<Base::Vector3d> centerOfGravity() const;
|
||||
//@}
|
||||
|
||||
/**
|
||||
* @brief Get the center of gravity.
|
||||
*
|
||||
* @return The center of gravity if available.
|
||||
*/
|
||||
virtual std::optional<Base::Vector3d> centerOfGravity() const;
|
||||
/// @}
|
||||
|
||||
/// Get the element map prefix.
|
||||
static const std::string& elementMapPrefix();
|
||||
|
||||
/** @name Element name mapping */
|
||||
//@{
|
||||
|
||||
/** Get element indexed name
|
||||
/**
|
||||
* @name Element name mapping
|
||||
*
|
||||
* @param name: the input name
|
||||
* @param sid: optional output of and App::StringID involved forming this mapped name
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Get the element's indexed name.
|
||||
*
|
||||
* @param[in] name The mapped name.
|
||||
*
|
||||
* @param[out] sid Optional output of and App::StringID involved forming
|
||||
* this mapped name.
|
||||
*
|
||||
* @return Returns an indexed name.
|
||||
*/
|
||||
IndexedName getIndexedName(const MappedName& name, ElementIDRefs* sid = nullptr) const;
|
||||
|
||||
/** Get element mapped name
|
||||
/**
|
||||
* @brief Get the element's mapped name.
|
||||
*
|
||||
* @param name: the input name
|
||||
* @param allowUnmapped: If the queried element is not mapped, then return
|
||||
* an empty name if \c allowUnmapped is false, or
|
||||
* else, return the indexed name.
|
||||
* @param sid: optional output of and App::StringID involved forming this mapped name
|
||||
* @return Returns the mapped name.
|
||||
* @param[in] element The indexed name name of the element.
|
||||
* @param[in] allowUnmapped If the queried element is not mapped, then
|
||||
* return an empty name if @p allowUnmapped is false, or else, return the
|
||||
* indexed name.
|
||||
* @param sid Optional output of and App::StringID involved forming this
|
||||
* mapped name.
|
||||
*
|
||||
* @return The mapped name.
|
||||
*/
|
||||
MappedName getMappedName(const IndexedName& element,
|
||||
bool allowUnmapped = false,
|
||||
ElementIDRefs* sid = nullptr) const;
|
||||
|
||||
/** Return a pair of indexed name and mapped name
|
||||
*
|
||||
* @param name: the input name.
|
||||
* @param sid: optional output of any App::StringID involved in forming
|
||||
* this mapped name
|
||||
* @param copy: if true, copy the name string, or else use it as constant
|
||||
* string, and caller must make sure the memory is not freed.
|
||||
*
|
||||
* @return Returns the MappedElement which contains both the indexed and
|
||||
* mapped name.
|
||||
/**
|
||||
* @brief Get a pair of an indexed and mapped name.
|
||||
*
|
||||
* This function guesses whether the input name is an indexed name or
|
||||
* mapped, and perform a lookup and return the names found. If the input
|
||||
* mapped one, performs a lookup, and returns the names found. If the input
|
||||
* name contains only alphabets and underscore followed by optional digits,
|
||||
* it will be treated as indexed name. Or else, it will be treated as
|
||||
* it will be treated as indexed name. Otherwise, it will be treated as a
|
||||
* mapped name.
|
||||
*
|
||||
* @param[in] name The input name.
|
||||
* @param[out] sid Optional output of any App::StringID involved in forming
|
||||
* this mapped name.
|
||||
* @param[in] copy If true, copy the name string, or else use it as
|
||||
* constant string, and caller must make sure the memory is not freed.
|
||||
*
|
||||
* @return The MappedElement that contains both the indexed and mapped
|
||||
* name.
|
||||
*/
|
||||
MappedElement
|
||||
getElementName(const char* name, ElementIDRefs* sid = nullptr, bool copy = false) const;
|
||||
|
||||
/** Add a sub-element name mapping.
|
||||
*
|
||||
* @param element: the original \c Type + \c Index element name
|
||||
* @param name: the mapped sub-element name. May or may not start with
|
||||
* elementMapPrefix().
|
||||
* @param sid: in case you use a hasher to hash the element name, pass in
|
||||
* the string id reference using this parameter. You can have more than one
|
||||
* string id associated with the same name.
|
||||
* @param overwrite: if true, it will overwrite existing names
|
||||
*
|
||||
* @return Returns the stored mapped element name.
|
||||
/**
|
||||
* @brief Add a sub-element name mapping.
|
||||
*
|
||||
* An element can have multiple mapped names. However, a name can only be
|
||||
* mapped to one element
|
||||
*
|
||||
* Note: the original proc was in the context of ComplexGeoData, which provided `Tag` access,
|
||||
* now you must pass in `long masterTag` explicitly.
|
||||
* @param[in] element The original @c Type + @c Index element name.
|
||||
* @param[in] name The mapped sub-element name. It may or may not start
|
||||
* with elementMapPrefix().
|
||||
* @param[in] masterTag The master tag of the element.
|
||||
* @param[in] sid In case you use a hasher to hash the element name, pass
|
||||
* in the string id reference using this parameter. You can have more than
|
||||
* one string id associated with the same name.
|
||||
* @param[in] overwrite If true, it will overwrite existing names.
|
||||
*
|
||||
* @return The stored mapped element name.
|
||||
*
|
||||
* @note The original function was in the context of ComplexGeoData, which
|
||||
* provided `Tag` access, now you must pass in `long masterTag` explicitly.
|
||||
*/
|
||||
MappedName setElementName(const IndexedName& element,
|
||||
const MappedName& name,
|
||||
@@ -280,30 +439,42 @@ public:
|
||||
return _elementMap->setElementName(element, name, masterTag, sid, overwrite);
|
||||
}
|
||||
|
||||
/// Check if there is an element map.
|
||||
bool hasElementMap() const
|
||||
{
|
||||
return _elementMap != nullptr;
|
||||
}
|
||||
|
||||
/** Get mapped element names
|
||||
/**
|
||||
* @brief Get mapped element names.
|
||||
*
|
||||
* @param element: original element name with \c Type + \c Index
|
||||
* @param needUnmapped: if true, return the original element name if no
|
||||
* mapping is found
|
||||
* @param[in] element The original element name with @c Type + @c Index.
|
||||
* @param[in] needUnmapped If true, return the original element name if no
|
||||
* mapping is found.
|
||||
*
|
||||
* @return a list of mapped names of the give element along with their
|
||||
* associated string ID references
|
||||
* @return A list of mapped names of the give element along with their
|
||||
* associated string ID references.
|
||||
*/
|
||||
std::vector<std::pair<MappedName, ElementIDRefs>>
|
||||
getElementMappedNames(const IndexedName& element, bool needUnmapped = false) const;
|
||||
|
||||
/// Hash the child element map postfixes to shorten element name from hierarchical maps
|
||||
/**
|
||||
* @brief Hash the child element map postfixes.
|
||||
*
|
||||
* The hashing is done to shorten element names from hierarchical maps.
|
||||
*/
|
||||
void hashChildMaps();
|
||||
|
||||
/// Check if there is child element map
|
||||
/// Check if there is child element map.
|
||||
bool hasChildElementMap() const;
|
||||
|
||||
/// Append the Tag (if and only if it is non zero) into the element map
|
||||
/**
|
||||
* @brief Append the Tag (if and only if it is non zero) into the element map.
|
||||
*
|
||||
* @param[in] tag The master tag to append.
|
||||
* @param[in] hasher The string hasher to use.
|
||||
* @param[in] postfix An optional postfix to append after the tag.
|
||||
*/
|
||||
virtual void
|
||||
reTagElementMap(long tag, App::StringHasherRef hasher, const char* postfix = nullptr)
|
||||
{
|
||||
@@ -312,7 +483,17 @@ public:
|
||||
(void)postfix;
|
||||
}
|
||||
|
||||
// NOTE: getElementHistory is now in ElementMap
|
||||
/**
|
||||
* @brief Get the history of an element name.
|
||||
*
|
||||
* @param[in] name The mapped element name to query.
|
||||
* @param[out] original Optional output parameter to store the original
|
||||
* element name.
|
||||
* @param[out] history Optional output parameter to store the history of
|
||||
* element names.
|
||||
*
|
||||
* @note This function is now in ElementMap.
|
||||
*/
|
||||
long getElementHistory(const MappedName& name,
|
||||
MappedName* original = nullptr,
|
||||
std::vector<MappedName>* history = nullptr) const
|
||||
@@ -323,49 +504,68 @@ public:
|
||||
return 0;
|
||||
};
|
||||
|
||||
/// Set the mapped child elements.
|
||||
void setMappedChildElements(const std::vector<Data::ElementMap::MappedChildElements>& children);
|
||||
|
||||
/// Get the mapped child elements.
|
||||
std::vector<Data::ElementMap::MappedChildElements> getMappedChildElements() const;
|
||||
|
||||
/// Get the element type from a mapped name.
|
||||
char elementType(const Data::MappedName&) const;
|
||||
|
||||
/// Get the element type from an indexed name.
|
||||
char elementType(const Data::IndexedName&) const;
|
||||
|
||||
/// Get the element type from a raw name.
|
||||
char elementType(const char* name) const;
|
||||
|
||||
/** Reset/swap the element map
|
||||
/**
|
||||
* @brief Reset/swap the element map.
|
||||
*
|
||||
* @param elementMap: optional new element map
|
||||
* @param[in] elementMap: optional new element map.
|
||||
*
|
||||
* @return Returns the existing element map.
|
||||
* @return The existing element map.
|
||||
*/
|
||||
virtual ElementMapPtr resetElementMap(ElementMapPtr elementMap = ElementMapPtr());
|
||||
|
||||
/// Get the entire element map
|
||||
/// Get the entire element map.
|
||||
std::vector<MappedElement> getElementMap() const;
|
||||
|
||||
/// Set the entire element map
|
||||
/// Set the entire element map.
|
||||
void setElementMap(const std::vector<MappedElement>& elements);
|
||||
|
||||
/// Get the current element map size
|
||||
/// Get the current element map size.
|
||||
size_t getElementMapSize(bool flush = true) const;
|
||||
|
||||
/// Return the higher level element names of the given element
|
||||
/**
|
||||
* @brief Get the higher level element names of the given element.
|
||||
*
|
||||
* @param name: the input element name.
|
||||
* @param silent: if true, suppress throwing exceptions.
|
||||
*/
|
||||
virtual std::vector<IndexedName> getHigherElements(const char* name, bool silent = false) const;
|
||||
|
||||
/// Return the current element map version
|
||||
/// Get the current element map version.
|
||||
virtual std::string getElementMapVersion() const;
|
||||
|
||||
/// Return true to signal element map version change
|
||||
/// Check the element map version.
|
||||
virtual bool checkElementMapVersion(const char* ver) const;
|
||||
|
||||
/// Check if the given sub-name only contains an element name
|
||||
/// Check if the given sub-name only contains an element name.
|
||||
static bool isElementName(const char* subName)
|
||||
{
|
||||
return (subName != nullptr) && (*subName != 0) && findElementName(subName) == subName;
|
||||
}
|
||||
|
||||
/** Iterate through the history of the give element name with a given callback
|
||||
/**
|
||||
* @brief Iterate through the history given an element name.
|
||||
*
|
||||
* Iterate through the history of the given element name with a given
|
||||
* callback.
|
||||
*
|
||||
* @param[in] name: the input element name
|
||||
* @param[in] cb: trace callback function.
|
||||
*
|
||||
* @param name: the input element name
|
||||
* @param cb: trace callback with call signature.
|
||||
* @sa TraceCallback
|
||||
*/
|
||||
void traceElement(const MappedName& name, TraceCallback cb) const
|
||||
@@ -373,42 +573,62 @@ public:
|
||||
_elementMap->traceElement(name, Tag, std::move(cb));
|
||||
}
|
||||
|
||||
/** Flush an internal buffering for element mapping */
|
||||
/// Flush internal buffers for element mapping.
|
||||
virtual void flushElementMap() const;
|
||||
//@}
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* @name Save/restore
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @name Save/restore */
|
||||
//@{
|
||||
void Save(Base::Writer& writer) const override;
|
||||
void Restore(Base::XMLReader& reader) override;
|
||||
void SaveDocFile(Base::Writer& writer) const override;
|
||||
void RestoreDocFile(Base::Reader& reader) override;
|
||||
unsigned int getMemSize() const override;
|
||||
|
||||
/// Set the filename for persistence.
|
||||
void setPersistenceFileName(const char* name) const;
|
||||
|
||||
/// Called before saving.
|
||||
virtual void beforeSave() const;
|
||||
|
||||
/// Check if restore has failed.
|
||||
bool isRestoreFailed() const
|
||||
{
|
||||
return _restoreFailed;
|
||||
}
|
||||
|
||||
/// Reset the restore failure flag.
|
||||
void resetRestoreFailure() const
|
||||
{
|
||||
_restoreFailed = true;
|
||||
}
|
||||
//@}
|
||||
/// @}
|
||||
|
||||
/**
|
||||
* Debugging method to dump an entire element map in human readable form to a stream
|
||||
* @param stream
|
||||
* @brief Dump the entire element map.
|
||||
*
|
||||
* Debugging method to dump an entire element map in human readable form to a stream.
|
||||
*
|
||||
* @param[in,out] stream The output stream.
|
||||
*/
|
||||
void dumpElementMap(std::ostream& stream) const;
|
||||
|
||||
/**
|
||||
* Debugging method to dump an entire element map in human readable form into a string
|
||||
* @return The string
|
||||
* @brief Dump the entire element map to a string.
|
||||
*
|
||||
* Debugging method to dump an entire element map in human readable form
|
||||
* into a string.
|
||||
*
|
||||
* @return The string with the element map.
|
||||
*/
|
||||
const std::string dumpElementMap() const;
|
||||
|
||||
protected:
|
||||
/// from local to outside
|
||||
/// Transform the point from local to outside.
|
||||
inline Base::Vector3d transformPointToOutside(const Base::Vector3f& vec) const
|
||||
{
|
||||
// clang-format off
|
||||
@@ -417,7 +637,8 @@ protected:
|
||||
static_cast<double>(vec.z));
|
||||
// clang-format on
|
||||
}
|
||||
/// from local to outside
|
||||
|
||||
/// Transform the points from local to outside.
|
||||
template<typename Vec>
|
||||
inline std::vector<Base::Vector3d> transformPointsToOutside(const std::vector<Vec>& input) const
|
||||
{
|
||||
@@ -435,6 +656,8 @@ protected:
|
||||
return output;
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
/// Transform the vector from local to outside.
|
||||
inline Base::Vector3d transformVectorToOutside(const Base::Vector3f& vec) const
|
||||
{
|
||||
// clang-format off
|
||||
@@ -445,6 +668,8 @@ protected:
|
||||
static_cast<double>(vec.z));
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
/// Transform the vectors from local to outside.
|
||||
template<typename Vec>
|
||||
std::vector<Base::Vector3d> transformVectorsToOutside(const std::vector<Vec>& input) const
|
||||
{
|
||||
@@ -463,7 +688,8 @@ protected:
|
||||
return output;
|
||||
// clang-format on
|
||||
}
|
||||
/// from local to inside
|
||||
|
||||
/// Transform the point from local to inside.
|
||||
inline Base::Vector3f transformPointToInside(const Base::Vector3d& vec) const
|
||||
{
|
||||
Base::Matrix4D tmpM(getTransform());
|
||||
@@ -475,44 +701,48 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief The master tag.
|
||||
*
|
||||
* The master tag is used to identify the shape to its owner document
|
||||
* object. It should be unique within the document. A tag of zero meanss
|
||||
* that automatic element mapping is disabled.
|
||||
*/
|
||||
mutable long Tag {0};
|
||||
|
||||
/// String hasher for element name shortening
|
||||
mutable App::StringHasherRef Hasher;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Restore the element map from a stream.
|
||||
*
|
||||
* @param[in,out] stream The input stream.
|
||||
* @param[in] count The number of items to restore.
|
||||
*/
|
||||
void restoreStream(std::istream& stream, std::size_t count);
|
||||
|
||||
/**
|
||||
* @brief Read the elements from an XML reader.
|
||||
*
|
||||
* @param[in,out] reader The XML reader.
|
||||
* @param[in] count The number of elements to read.
|
||||
*/
|
||||
void readElements(Base::XMLReader& reader, size_t count);
|
||||
|
||||
/// from local to outside
|
||||
inline Base::Vector3d transformToOutside(const Base::Vector3f& vec) const
|
||||
{
|
||||
// clang-format off
|
||||
return getTransform() * Base::Vector3d(static_cast<double>(vec.x),
|
||||
static_cast<double>(vec.y),
|
||||
static_cast<double>(vec.z));
|
||||
// clang-format on
|
||||
}
|
||||
/// from local to inside
|
||||
inline Base::Vector3f transformToInside(const Base::Vector3d& vec) const
|
||||
{
|
||||
Base::Matrix4D tmpM(getTransform());
|
||||
tmpM.inverse();
|
||||
Base::Vector3d tmp = tmpM * vec;
|
||||
return Base::Vector3f(static_cast<float>(tmp.x),
|
||||
static_cast<float>(tmp.y),
|
||||
static_cast<float>(tmp.z));
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Get the element map.
|
||||
ElementMapPtr elementMap(bool flush = true) const;
|
||||
/// Ensure there is an element map.
|
||||
ElementMapPtr ensureElementMap(bool flush = true);
|
||||
|
||||
private:
|
||||
ElementMapPtr _elementMap;
|
||||
|
||||
protected:
|
||||
/// The persistence file name.
|
||||
mutable std::string _persistenceName;
|
||||
/// Flag to indicate restore failure.
|
||||
mutable bool _restoreFailed = false;
|
||||
};
|
||||
|
||||
|
||||
@@ -465,14 +465,14 @@ public:
|
||||
/**
|
||||
* @brief Add an object of a given type to the document.
|
||||
*
|
||||
* Add an object of of a given type with @p pObjectName that should be
|
||||
* ASCII to this document and set it active. Unicode names are set through
|
||||
* the Label property.
|
||||
* Add an object of a given type with @p pObjectName that should be ASCII
|
||||
* to this document and set it active. Unicode names are set through the
|
||||
* Label property.
|
||||
*
|
||||
* @tparam T The type of created object.
|
||||
* @param[in] pObjectName if `nullptr` generate a new unique name based on @p
|
||||
* T, otherwise use this name.
|
||||
* @param[in] isNew if `false don't call the DocumentObject::setupObject()
|
||||
* @param[in] pObjectName if `nullptr` generate a new unique name based on
|
||||
* @p T, otherwise use this name.
|
||||
* @param[in] isNew if `false` don't call the DocumentObject::setupObject()
|
||||
* callback (default * is true)
|
||||
* @param[in] viewType override object's view provider name
|
||||
* @param[in] isPartial indicate if this object is meant to be partially loaded
|
||||
|
||||
@@ -45,80 +45,108 @@ namespace Data
|
||||
class ElementMap;
|
||||
using ElementMapPtr = std::shared_ptr<ElementMap>;
|
||||
|
||||
/** Element trace callback
|
||||
/**
|
||||
* @brief The element trace callback.
|
||||
*
|
||||
* The callback has the following call signature
|
||||
* (const std::string &name, size_t offset, long encodedTag, long tag) -> bool
|
||||
*
|
||||
* @param name: the current element name.
|
||||
* @param offset: the offset skipping the encoded element name for the next iteration.
|
||||
* @param encodedTag: the tag encoded inside the current element, which is usually the tag
|
||||
* of the previous step in the shape history.
|
||||
* @param tag: the tag of the current shape element.
|
||||
* @param[in] name The current element name.
|
||||
*
|
||||
* @param[in] offset The offset skipping the encoded element name for the next
|
||||
* iteration.
|
||||
*
|
||||
* @param[in] encodedTag The tag encoded inside the current element, which is
|
||||
* usually the tag of the previous step in the shape history.
|
||||
*
|
||||
* @param[in] tag The tag of the current shape element.
|
||||
*
|
||||
* @sa traceElement()
|
||||
*/
|
||||
typedef std::function<bool(const MappedName&, int, long, long)> TraceCallback;
|
||||
|
||||
/* This class provides for ComplexGeoData's ability to provide proper naming.
|
||||
/**
|
||||
* @brief A class to manage element name mapping.
|
||||
* @ingroup ElementMapping
|
||||
*
|
||||
* This class provides for ComplexGeoData's ability to provide proper naming.
|
||||
* Specifically, ComplexGeoData uses this class for it's `_id` property.
|
||||
* Most of the operations work with the `indexedNames` and `mappedNames` maps.
|
||||
* `indexedNames` maps a string to both a name queue and children.
|
||||
* each of those children store an IndexedName, offset details, postfix, ids, and
|
||||
* possibly a recursive elementmap
|
||||
* `mappedNames` maps a MappedName to a specific IndexedName.
|
||||
*
|
||||
* - `indexedNames` maps a string to both a name queue and children. Each of
|
||||
* those children store an IndexedName, offset details, postfix, ids, and
|
||||
* possibly a recursive elementmap.
|
||||
* - `mappedNames` maps a MappedName to a specific IndexedName.
|
||||
*/
|
||||
class AppExport ElementMap
|
||||
: public std::enable_shared_from_this<ElementMap> // TODO can remove shared_from_this?
|
||||
{
|
||||
public:
|
||||
/** Default constructor: hooks internal functions to \c signalSaveDocument and
|
||||
* \c signalStartRestoreDocument. This is related to the save and restore process
|
||||
* of the map.
|
||||
/**
|
||||
* @brief Construct an element map.
|
||||
*
|
||||
* Default constructor: hooks internal functions to \c signalSaveDocument
|
||||
* and \c signalStartRestoreDocument. This is related to the save and
|
||||
* restore process of the map.
|
||||
*/
|
||||
ElementMap();
|
||||
|
||||
/** Ensures that naming is properly assigned. It then marks as "used" all the StringID
|
||||
* that are used to make up this particular map and are stored in the hasherRef passed
|
||||
* as a parameter. Finally do this recursively for all childEelementMaps as well.
|
||||
/**
|
||||
* @brief Prepare this map for saving.
|
||||
*
|
||||
* @param hasherRef where all the StringID needed to build the map are stored.
|
||||
* Ensures that naming is properly assigned. It then marks as "used" all
|
||||
* the @ref App::StringID "StringIDs" that are used to make up this
|
||||
* particular map and are stored in the hasherRef passed as a
|
||||
* parameter. Finally do this recursively for all childEelementMaps as
|
||||
* well.
|
||||
*
|
||||
* @param hasherRef Where all the @ref App::StringID "StringIDs" that are
|
||||
* needed to build the map are stored.
|
||||
*/
|
||||
// FIXME this should be made part of \c save, to achieve symmetry with the restore method
|
||||
void beforeSave(const ::App::StringHasherRef& hasherRef) const;
|
||||
|
||||
/** Serialize this map. Calls \c collectChildMaps to get \c childMapSet and
|
||||
* \c postfixMap, then calls the other (private) save function with those parameters.
|
||||
* @param stream: serialized stream
|
||||
/**
|
||||
* @brief Serialize this map.
|
||||
*
|
||||
* Serialize this map. Calls @c collectChildMaps to get @c childMapSet and
|
||||
* @c postfixMap, then calls the other (private) save function with those
|
||||
* parameters.
|
||||
*
|
||||
* @param[in,out] stream The stream to serialize to.
|
||||
*/
|
||||
void save(std::ostream& stream) const;
|
||||
|
||||
/** Deserialize and restore this map. This function restores \c childMaps and
|
||||
* \c postfixes from the stream, then calls the other (private) restore function with those
|
||||
* parameters.
|
||||
* @param hasherRef: where all the StringIDs are stored
|
||||
* @param stream: stream to deserialize
|
||||
/**
|
||||
* @brief Deserialize and restore this map.
|
||||
*
|
||||
* This function restores @c childMaps and @c postfixes from the stream,
|
||||
* then calls the other (private) restore function with those parameters.
|
||||
*
|
||||
* @param[in] hasherRef Where all the StringIDs are stored.
|
||||
* @param[in,out] stream The stream to deserialize from.
|
||||
*/
|
||||
ElementMapPtr restore(::App::StringHasherRef hasherRef, std::istream& stream);
|
||||
|
||||
|
||||
/** Add a sub-element name mapping.
|
||||
*
|
||||
* @param element: the original \c Type + \c Index element name
|
||||
* @param name: the mapped sub-element name. May or may not start with
|
||||
* elementMapPrefix().
|
||||
* @param sid: in case you use a hasher to hash the element name, pass in
|
||||
* the string id reference using this parameter. You can have more than one
|
||||
* string id associated with the same name.
|
||||
* @param overwrite: if true, it will overwrite existing names
|
||||
*
|
||||
* @return Returns the stored mapped element name.
|
||||
/**
|
||||
* @brief Add a sub-element name mapping.
|
||||
*
|
||||
* An element can have multiple mapped names. However, a name can only be
|
||||
* mapped to one element
|
||||
*
|
||||
* Note: the original proc was in the context of ComplexGeoData, which provided `Tag` access,
|
||||
* now you must pass in `long masterTag` explicitly.
|
||||
* @param[in] element The original @c Type + @c Index element name.
|
||||
* @param[in] name The mapped sub-element name. May or may not start with
|
||||
* elementMapPrefix().
|
||||
* @param[in] masterTag The master tag of the element.
|
||||
* @param[in] sid In case you use a hasher to hash the element name, pass
|
||||
* in the string id reference using this parameter. You can have more than
|
||||
* one string id associated with the same name.
|
||||
* @param[in] overwrite If true, it will overwrite existing names.
|
||||
*
|
||||
* @return The stored mapped element name.
|
||||
*
|
||||
* @note The original function was in the context of ComplexGeoData, which
|
||||
* provided `Tag` access, now you must pass in `long masterTag` explicitly.
|
||||
*/
|
||||
MappedName setElementName(const IndexedName& element,
|
||||
const MappedName& name,
|
||||
@@ -126,12 +154,22 @@ public:
|
||||
const ElementIDRefs* sid = nullptr,
|
||||
bool overwrite = false);
|
||||
|
||||
/* Generates a new MappedName from the current details.
|
||||
/**
|
||||
* @brief Generates a new MappedName from the current details.
|
||||
*
|
||||
* The result is streamed to `ss` and stored in `name`.
|
||||
*
|
||||
* Note: the original proc was in the context of ComplexGeoData, which provided `Tag` access,
|
||||
* now you must pass in `long masterTag` explicitly.
|
||||
* @param[in] element_type The element type character.
|
||||
* @param[in,out] name The mapped name to encode.
|
||||
* @param[in,out] ss The output stream to write the encoded name to.
|
||||
* @param[in,out] sids The string id references that make up the name.
|
||||
* @param[in] masterTag The master tag of the element.
|
||||
* @param[in] postfix Optional postfix to append to the name.
|
||||
* @param[in] tag Optional tag to encode in the name.
|
||||
* @param[in] forceTag If true, encode the tag.
|
||||
*
|
||||
* @note The original function was in the context of ComplexGeoData, which
|
||||
* provided `Tag` access, now you must pass in `long masterTag` explicitly.
|
||||
*/
|
||||
void encodeElementName(char element_type,
|
||||
MappedName& name,
|
||||
@@ -142,20 +180,47 @@ public:
|
||||
long tag = 0,
|
||||
bool forceTag = false) const;
|
||||
|
||||
/// Remove \c name from the map
|
||||
/// Remove @p name from the map.
|
||||
void erase(const MappedName& name);
|
||||
|
||||
/// Remove \c idx and all the MappedNames associated with it
|
||||
/// Remove @p idx and all the MappedNames associated with it.
|
||||
void erase(const IndexedName& idx);
|
||||
|
||||
/// Get the size of the map.
|
||||
unsigned long size() const;
|
||||
|
||||
/// Check if the map is empty.
|
||||
bool empty() const;
|
||||
|
||||
/**
|
||||
* @brief Find the IndexedName associated with the given MappedName.
|
||||
*
|
||||
* @param[in] name The mapped name to search for.
|
||||
* @param[in,out] sids Optional pointer to store the StringID references that
|
||||
* make up the name.
|
||||
*
|
||||
* @return The IndexedName associated with the given MappedName, or an
|
||||
* empty IndexedName if not found.
|
||||
*/
|
||||
IndexedName find(const MappedName& name, ElementIDRefs* sids = nullptr) const;
|
||||
|
||||
/**
|
||||
* @brief Find the MappedName associated with the given IndexedName.
|
||||
*
|
||||
* @param[in] idx The indexed name to search for.
|
||||
* @param[in,out] sids Optional pointer to store the StringID references that
|
||||
* make up the name.
|
||||
*/
|
||||
MappedName find(const IndexedName& idx, ElementIDRefs* sids = nullptr) const;
|
||||
|
||||
/**
|
||||
* @brief Find all MappedNames associated with the given IndexedName.
|
||||
*
|
||||
* @param[in] idx The indexed name to search for.
|
||||
*
|
||||
* @return A vector of pairs of MappedName and their corresponding
|
||||
* ElementIDRefs associated with the given IndexedName.
|
||||
*/
|
||||
std::vector<std::pair<MappedName, ElementIDRefs>> findAll(const IndexedName& idx) const;
|
||||
|
||||
// prefix searching is disabled, as TopoShape::getRelatedElement() is
|
||||
@@ -166,16 +231,23 @@ public:
|
||||
std::vector<MappedElement> findAllStartsWith(const char *prefix) const;
|
||||
#endif
|
||||
|
||||
/// Check if there are any child element maps.
|
||||
bool hasChildElementMap() const;
|
||||
|
||||
/* Ensures that for each IndexedName mapped to IndexedElements, that
|
||||
* each child is properly hashed (cached).
|
||||
/**
|
||||
* @brief Hash the child maps.
|
||||
*
|
||||
* Note: the original proc was in the context of ComplexGeoData, which provided `Tag` access,
|
||||
* now you must pass in `long masterTag` explicitly.
|
||||
* Ensures that for each IndexedName mapped to IndexedElements, that each
|
||||
* child is properly hashed (cached).
|
||||
*
|
||||
* @param[in] masterTag The master tag of the element.
|
||||
*
|
||||
* @note The original function was in the context of ComplexGeoData, which
|
||||
* provided `Tag` access, now you must pass in `long masterTag` explicitly.
|
||||
*/
|
||||
void hashChildMaps(long masterTag);
|
||||
|
||||
/// A struct to represent mapped child elements.
|
||||
struct AppExport MappedChildElements
|
||||
{
|
||||
IndexedName indexedName;
|
||||
@@ -189,23 +261,48 @@ public:
|
||||
// prefix() has been moved to ElementNamingUtils.h
|
||||
};
|
||||
|
||||
/* Note: the original addChildElements passed `ComplexGeoData& master` for getting the `Tag`,
|
||||
* now it just passes `long masterTag`.*/
|
||||
/**
|
||||
* @brief Add child elements to the map.
|
||||
*
|
||||
* @param[in] masterTag The master tag of the element.
|
||||
* @param[in] children The vector of child elements to add.
|
||||
*
|
||||
* @note The original addChildElements passed `ComplexGeoData& master` for
|
||||
* getting the `Tag`, now it just passes `long masterTag`.
|
||||
*/
|
||||
void addChildElements(long masterTag, const std::vector<MappedChildElements>& children);
|
||||
|
||||
/// Get the child elements.
|
||||
std::vector<MappedChildElements> getChildElements() const;
|
||||
|
||||
/// Get all mapped elements.
|
||||
std::vector<MappedElement> getAll() const;
|
||||
|
||||
/**
|
||||
* @brief Get the history of the given element name.
|
||||
*
|
||||
* @param[in] name The input element name.
|
||||
* @param[in] masterTag The master tag of the element.
|
||||
* @param[out] original Optional output parameter to store the original element name.
|
||||
* @param[out] history Optional output parameter to store the history of element names.
|
||||
*
|
||||
* @return The tag associated with the original element name.
|
||||
*/
|
||||
long getElementHistory(const MappedName& name,
|
||||
long masterTag,
|
||||
MappedName* original = nullptr,
|
||||
std::vector<MappedName>* history = nullptr) const;
|
||||
|
||||
/** Iterate through the history of the give element name with a given callback
|
||||
/**
|
||||
* @brief Iterate through the history of the given element name.
|
||||
*
|
||||
* Iterate through the history of the give element name with a given
|
||||
* callback
|
||||
*
|
||||
* @param[in] name The input element name.
|
||||
* @param[in] masterTag The master tag of the element.
|
||||
* @param[in] cb The trace callback.
|
||||
*
|
||||
* @param name: the input element name
|
||||
* @param cb: trace callback with call signature.
|
||||
* @sa TraceCallback
|
||||
*/
|
||||
void traceElement(const MappedName& name, long masterTag, TraceCallback cb) const;
|
||||
|
||||
@@ -10,9 +10,7 @@
|
||||
namespace App
|
||||
{
|
||||
|
||||
/** Return type for lookups of new and old style sub-element names
|
||||
*
|
||||
*/
|
||||
/// Return type for lookups of new and old style sub-element names
|
||||
struct ElementNamePair
|
||||
{
|
||||
std::string newName;
|
||||
@@ -42,8 +40,17 @@ struct ElementNamePair
|
||||
namespace Data
|
||||
{
|
||||
|
||||
/**
|
||||
* @name Element name constants
|
||||
* @ingroup ElementMapping
|
||||
* @anchor ElementNameConstants
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/// Special prefix to mark the beginning of a mapped sub-element name
|
||||
constexpr const char* ELEMENT_MAP_PREFIX = ";";
|
||||
/// The size of the element map prefix
|
||||
constexpr size_t ELEMENT_MAP_PREFIX_SIZE = 1;
|
||||
|
||||
/// Special prefix to mark a missing element
|
||||
@@ -52,27 +59,40 @@ constexpr const char* MISSING_PREFIX = "?";
|
||||
// IMPORTANT: For all the constants below, the semicolon ";"
|
||||
// at the start is ELEMENT_MAP_PREFIX
|
||||
|
||||
/// Prefix to mark child elements.
|
||||
constexpr const char* MAPPED_CHILD_ELEMENTS_PREFIX = ";:R";
|
||||
|
||||
/// Special postfix to mark the following tag
|
||||
constexpr const char* POSTFIX_TAG = ";:H";
|
||||
/// The size of the postfix tag
|
||||
constexpr size_t POSTFIX_TAG_SIZE = 3;
|
||||
|
||||
/// Postfix to mark a decimal tag.
|
||||
constexpr const char* POSTFIX_DECIMAL_TAG = ";:T";
|
||||
/// Postfix to mark an external tag.
|
||||
constexpr const char* POSTFIX_EXTERNAL_TAG = ";:X";
|
||||
/// Postfix to mark a child element.
|
||||
constexpr const char* POSTFIX_CHILD = ";:C";
|
||||
|
||||
/// Special postfix to mark the index of an array element
|
||||
constexpr const char* POSTFIX_INDEX = ";:I";
|
||||
/// Postfix to mark an element higher in the hierarcy.
|
||||
constexpr const char* POSTFIX_UPPER = ";:U";
|
||||
/// Postfix to mark an element lower in the hierarcy.
|
||||
constexpr const char* POSTFIX_LOWER = ";:L";
|
||||
/// Postfix to mark an element as being modified.
|
||||
constexpr const char* POSTFIX_MOD = ";:M";
|
||||
/// Postfix to mark an element as being generated.
|
||||
constexpr const char* POSTFIX_GEN = ";:G";
|
||||
/// Postfix to mark an element as being modified and generated.
|
||||
constexpr const char* POSTFIX_MODGEN = ";:MG";
|
||||
/// Postfix to mark a duplicate element.
|
||||
constexpr const char* POSTFIX_DUPLICATE = ";D";
|
||||
|
||||
/// Label to use for element index in element mapping.
|
||||
constexpr const char* ELEMENT_MAP_INDEX = "_";
|
||||
|
||||
/// @}
|
||||
|
||||
/// Check if a subname contains missing element
|
||||
AppExport bool hasMissingElement(const char *subname);
|
||||
|
||||
|
||||
@@ -40,30 +40,44 @@
|
||||
namespace Data
|
||||
{
|
||||
|
||||
/// The IndexedName class provides a very memory-efficient data structure to hold a name and an
|
||||
/// index value, and to perform various comparisons and validations of those values. The name must
|
||||
/// only consist of upper- and lower-case ASCII characters and the underscore ('_') character. The
|
||||
/// index must be a positive integer. The string representation of this IndexedName is the name
|
||||
/// followed by the index, with no spaces between: an IndexedName may be constructed from this
|
||||
/// string. For example "EDGE1" or "FACE345" might be the names of elements that use an IndexedName.
|
||||
/// If there is then an "EDGE2", only a pointer to the original stored name "EDGE" is retained.
|
||||
///
|
||||
/// The memory efficiency of the class comes from reusing the same character storage for names that
|
||||
/// match, while retaining their differing indices. This is achieved by either using user-provided
|
||||
/// const char * names (provided as a list of typeNames and presumed to never be deallocated), or by
|
||||
/// maintaining an internal list of names that have been used before, and can be reused later.
|
||||
/**
|
||||
* @brief A data structure to hold a name and an index value.
|
||||
* @ingroup ElementMapping
|
||||
*
|
||||
* The IndexedName class provides a very memory-efficient data structure to hold a name and an
|
||||
* index value, and to perform various comparisons and validations of those values. The name must
|
||||
* only consist of upper- and lower-case ASCII characters and the underscore ('_') character. The
|
||||
* index must be a positive integer. The string representation of this IndexedName is the name
|
||||
* followed by the index, with no spaces between: an IndexedName may be constructed from this
|
||||
* string. For example "Edge1" or "Face345" might be the names of elements that use an IndexedName.
|
||||
* If there is then an "Edge2", only a pointer to the original stored name "Edge" is retained.
|
||||
*
|
||||
* The memory efficiency of the class comes from reusing the same character storage for names that
|
||||
* match, while retaining their differing indices. This is achieved by either using user-provided
|
||||
* const char * names (provided as a list of typeNames and presumed to never be deallocated), or by
|
||||
* maintaining an internal list of names that have been used before, and can be reused later.
|
||||
*/
|
||||
class AppExport IndexedName
|
||||
{
|
||||
public:
|
||||
/// Construct from a name and an optional index. If the name contains an index it is read, but
|
||||
/// is used as the index *only* if _index parameter is unset. If the _index parameter is given
|
||||
/// it overrides any trailing integer in the name. Index must be positive, and name must contain
|
||||
/// only ASCII letters and the underscore character. If these conditions are not met, name is
|
||||
/// set to the empty string, and isNull() will return true.
|
||||
///
|
||||
/// \param name The new name - ASCII letters and underscores only, with optional integer suffix.
|
||||
/// This memory will be copied into a new internal storage location and need not be persistent.
|
||||
/// \param _index The new index - if provided, it overrides any suffix provided by name
|
||||
/**
|
||||
* @brief Construct an indexed name from a name and optional index.
|
||||
*
|
||||
* Construct an indexed name from a name and an optional index. If the name
|
||||
* contains an index, it is read, but is used as the index *only* if @p
|
||||
* _index is unset. If the @p _index is given, it overrides any trailing
|
||||
* integer in the name. The index must be positive, and the name must
|
||||
* contain only ASCII letters and the underscore character. If these
|
||||
* conditions are not met, the name is set to the empty string, and
|
||||
* isNull() will return true.
|
||||
*
|
||||
* @param[in] name The new name - ASCII letters and underscores only, with
|
||||
* optional integer suffix. This memory will be copied into a new internal
|
||||
* storage location and need not be persistent.
|
||||
*
|
||||
* @param[in] _index The new index. If provided, it overrides any suffix
|
||||
* provided by name.
|
||||
*/
|
||||
explicit IndexedName(const char* name = nullptr, int _index = 0)
|
||||
: index(0)
|
||||
{
|
||||
@@ -79,20 +93,31 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an indexed name that is restricted to a list of preset type names. If it appears in
|
||||
/// that list, only a pointer to the character storage in the list is retained: the memory
|
||||
/// locations pointed at by the list must never be destroyed once they have been used to create
|
||||
/// names. If allowOthers is true (the default) then a requested name that is not in the list
|
||||
/// will be added to a static internal storage table, and its memory then reused for later
|
||||
/// objects with the same name. If allowOthers is false, then the name request is rejected, and
|
||||
/// the name is treated as null.
|
||||
///
|
||||
/// \param name The new name - ASCII letters and underscores only, with optional integer suffix
|
||||
/// \param allowedTypeNames A vector of allowed names. Storage locations must persist for the
|
||||
/// entire run of the program.
|
||||
/// \param allowOthers Whether a name not in allowedTypeNames is permitted. If true (the
|
||||
/// default) then a name not in allowedTypeNames is added to a static internal storage vector
|
||||
/// so that it can be reused later without additional memory allocation.
|
||||
/**
|
||||
* @brief Construct an indexed name from a name and a list of preset type
|
||||
* names.
|
||||
*
|
||||
* Create an indexed name that is restricted to a list of preset type
|
||||
* names. If it appears in that list, only a pointer to the character
|
||||
* storage in the list is retained: the memory locations pointed at by the
|
||||
* list must never be destroyed once they have been used to create
|
||||
* names. If @p allowOthers is true (the default) then a requested name
|
||||
* that is not in the list will be added to a static internal storage
|
||||
* table, and its memory then reused for later objects with the same
|
||||
* name. If @p allowOthers is false, then the name request is rejected, and
|
||||
* the name is treated as null.
|
||||
*
|
||||
* @param[in] name The new name - ASCII letters and underscores only, with
|
||||
* optional integer suffix.
|
||||
*
|
||||
* @param allowedTypeNames A vector of allowed names. Storage locations
|
||||
* must persist for the entire run of the program.
|
||||
*
|
||||
* @param allowOthers Whether a name not in allowedTypeNames is
|
||||
* permitted. If true (the default) then a name not in allowedTypeNames is
|
||||
* added to a static internal storage vector so that it can be reused later
|
||||
* without additional memory allocation.
|
||||
*/
|
||||
IndexedName(const char* name,
|
||||
const std::vector<const char*>& allowedTypeNames,
|
||||
bool allowOthers = true)
|
||||
@@ -102,11 +127,15 @@ public:
|
||||
set(name, -1, allowedTypeNames, allowOthers);
|
||||
}
|
||||
|
||||
/// Construct from a QByteArray, but explicitly making a copy of the name on its first
|
||||
/// occurrence. If this is a name that has already been stored internally, no additional copy
|
||||
/// is made.
|
||||
///
|
||||
/// \param data The QByteArray to copy the data from
|
||||
/**
|
||||
* @brief Construct a mapped name from a QByteArray.
|
||||
*
|
||||
* Construct from a QByteArray, but explicitly making a copy of the name on
|
||||
* its first occurrence. If this is a name that has already been stored
|
||||
* internally, no additional copy is made.
|
||||
*
|
||||
* @param[in] data The QByteArray to copy the data from.
|
||||
*/
|
||||
explicit IndexedName(const QByteArray& data)
|
||||
: type("")
|
||||
, index(0)
|
||||
@@ -114,13 +143,21 @@ public:
|
||||
set(data.constData(), data.size());
|
||||
}
|
||||
|
||||
/// Given constant name and an index, reuse the existing memory for the name, not making a copy
|
||||
/// of it, or scanning any existing storage for it. The name must never become invalid for the
|
||||
/// lifetime of the object it names. This memory will never be reused by another object.
|
||||
///
|
||||
/// \param name The name of the object. This memory is NOT copied and must be persistent.
|
||||
/// \param index A positive, non-zero integer
|
||||
/// \return An IndexedName with the given name and index, reusing the existing memory for name
|
||||
/**
|
||||
* @brief Create an indexed name from a string and index.
|
||||
*
|
||||
* Given constant name and an index, reuse the existing memory for the
|
||||
* name, not making a copy of it, or scanning any existing storage for
|
||||
* it. The name must never become invalid for the lifetime of the object it
|
||||
* names. This memory will never be reused by another object.
|
||||
*
|
||||
* @param[in] name The name of the object. This memory is NOT copied and must be persistent.
|
||||
*
|
||||
* @param[in] index A positive, non-zero integer.
|
||||
*
|
||||
* @return An IndexedName with the given name and index, reusing the
|
||||
* existing memory for name.
|
||||
*/
|
||||
static IndexedName fromConst(const char* name, int index)
|
||||
{
|
||||
assert(index >= 0);
|
||||
@@ -130,11 +167,17 @@ public:
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Given an existing std::string, *append* this name to it. If index is not zero, this will
|
||||
/// include the index.
|
||||
///
|
||||
/// \param buffer A (possibly non-empty) string buffer to append the name to.
|
||||
/// \return A const char pointer to the name we appended to the buffer.
|
||||
/**
|
||||
* @brief Append this index name to a buffer.
|
||||
*
|
||||
* Given an existing std::string, *append* this name to it. If the index is
|
||||
* not zero, this will include the index.
|
||||
*
|
||||
* @param[in,out] buffer A (possibly non-empty) string buffer to append the
|
||||
* name to.
|
||||
*
|
||||
* @return A const char pointer to the name we appended to the buffer.
|
||||
*/
|
||||
const char* appendToStringBuffer(std::string& buffer) const
|
||||
{
|
||||
// Note! buffer is not cleared on purpose.
|
||||
@@ -146,9 +189,11 @@ public:
|
||||
return buffer.c_str() + offset;
|
||||
}
|
||||
|
||||
/// Create and return a new std::string with this name in it.
|
||||
///
|
||||
/// \return A newly-created string with the IndexedName in it (e.g. "EDGE42")
|
||||
/**
|
||||
* @brief Create and return a new std::string with this name in it.
|
||||
*
|
||||
* @return A newly-created string with the IndexedName in it (e.g. "EDGE42")
|
||||
*/
|
||||
std::string toString() const
|
||||
{
|
||||
std::string result;
|
||||
@@ -156,8 +201,12 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
/// An indexedName is represented as the simple concatenation of the name and its index, e.g.
|
||||
/// "EDGE1" or "FACE42".
|
||||
/**
|
||||
* @brief Append this indexed name to an output stream.
|
||||
*
|
||||
* An indexedName is represented as the simple concatenation of the name and its index, e.g.
|
||||
* "EDGE1" or "FACE42".
|
||||
*/
|
||||
friend std::ostream& operator<<(std::ostream& stream, const IndexedName& indexedName)
|
||||
{
|
||||
stream << indexedName.type;
|
||||
@@ -167,14 +216,26 @@ public:
|
||||
return stream;
|
||||
}
|
||||
|
||||
/// True only if both the name and index compare exactly equal.
|
||||
/**
|
||||
* Check if two indexed names are equal.
|
||||
*
|
||||
* @param[in] other The other IndexedName to compare against.
|
||||
*
|
||||
* @return True only if both the name and index compare exactly equal.
|
||||
*/
|
||||
bool operator==(const IndexedName& other) const
|
||||
{
|
||||
return this->index == other.index
|
||||
&& (this->type == other.type || std::strcmp(this->type, other.type) == 0);
|
||||
}
|
||||
|
||||
/// Increments the index by the given offset. Does not affect the text part of the name.
|
||||
/**
|
||||
* @brief Increments the index by the given offset.
|
||||
*
|
||||
* Does not affect the text part of the name.
|
||||
*
|
||||
* @param[in] offset The amount to increase the index by.
|
||||
*/
|
||||
IndexedName& operator+=(int offset)
|
||||
{
|
||||
this->index += offset;
|
||||
@@ -189,8 +250,12 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Pre-decrement operator: decreases the index of this element by one. Must not make the index
|
||||
/// negative (only checked when compiled in debug mode).
|
||||
/**
|
||||
* @brief Pre-decrement operator: decreases the index of this element by one.
|
||||
*
|
||||
* Must not make the index negative (only checked when compiled in debug
|
||||
* mode).
|
||||
*/
|
||||
IndexedName& operator--()
|
||||
{
|
||||
--this->index;
|
||||
@@ -198,13 +263,28 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// True if either the name or the index compare not equal.
|
||||
/**
|
||||
* @brief Check if two indexed names are not equal.
|
||||
*
|
||||
* @param[in] other The other IndexedName to compare against.
|
||||
*
|
||||
* @return True if either the name or the index compare not equal.
|
||||
*/
|
||||
bool operator!=(const IndexedName& other) const
|
||||
{
|
||||
return !(this->operator==(other));
|
||||
}
|
||||
|
||||
/// Equivalent to C++20's operator <=>
|
||||
/**
|
||||
* @brief Compare two IndexedNames.
|
||||
*
|
||||
* Equivalent to C++20's operator <=>. The comparison is first
|
||||
* lexicographical for the text and then numerical for the index.
|
||||
*
|
||||
* @param[in] other The other IndexedName to compare against.
|
||||
*
|
||||
* @return Negative value if this < other, positive if this > other, zero if equal.
|
||||
*/
|
||||
int compare(const IndexedName& other) const
|
||||
{
|
||||
int res = std::strcmp(this->type, other.type);
|
||||
@@ -220,15 +300,19 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Provided to enable sorting operations: the comparison is first lexicographical for the text
|
||||
/// element of the names, then numerical for the indices.
|
||||
/// Check if this IndexedName is less than another.
|
||||
bool operator<(const IndexedName& other) const
|
||||
{
|
||||
return compare(other) < 0;
|
||||
}
|
||||
|
||||
/// Allow direct memory access to the individual characters of the text portion of the name.
|
||||
/// NOTE: input is not range-checked when compiled in release mode.
|
||||
/**
|
||||
* @brief index into the text part of the name.
|
||||
*
|
||||
* Allow direct memory access to the individual characters of the text portion of the name.
|
||||
*
|
||||
* @note The input is not range-checked when compiled in release mode.
|
||||
*/
|
||||
char operator[](int input) const
|
||||
{
|
||||
assert(input >= 0);
|
||||
@@ -238,7 +322,11 @@ public:
|
||||
return this->type[input];
|
||||
}
|
||||
|
||||
/// Get a pointer to text part of the name - does NOT make a copy, returns direct memory access
|
||||
/**
|
||||
* @brief Get a pointer to text part of the name.
|
||||
*
|
||||
* Does NOT make a copy, returns direct memory access.
|
||||
*/
|
||||
const char* getType() const
|
||||
{
|
||||
return this->type;
|
||||
@@ -250,17 +338,25 @@ public:
|
||||
return this->index;
|
||||
}
|
||||
|
||||
/// Set the numerical part of the name (note that there is no equivalent function to allow
|
||||
/// changing the text part of the name, which is immutable once created).
|
||||
///
|
||||
/// \param input The new index. Must be a positive non-zero integer
|
||||
/**
|
||||
* @brief Set the numerical part of the name
|
||||
*
|
||||
* @note There is no equivalent function to allow changing the text part of
|
||||
* the name, which is immutable once created).
|
||||
*
|
||||
* @param[in] input The new index. Must be a positive non-zero integer.
|
||||
*/
|
||||
void setIndex(int input)
|
||||
{
|
||||
assert(input >= 0);
|
||||
this->index = input;
|
||||
}
|
||||
|
||||
/// A name is considered "null" if its text component is an empty string.
|
||||
/**
|
||||
* @brief Check whether this index name is null.
|
||||
*
|
||||
* A name is considered "null" if its text component is an empty string.
|
||||
*/
|
||||
// When we support C++20 we can use std::span<> to eliminate the clang-tidy warning
|
||||
// NOLINTNEXTLINE cppcoreguidelines-pro-bounds-pointer-arithmetic
|
||||
bool isNull() const
|
||||
@@ -268,26 +364,37 @@ public:
|
||||
return this->type[0] == '\0';
|
||||
}
|
||||
|
||||
/// Boolean conversion provides the opposite of isNull(), yielding true when the text part of
|
||||
/// the name is NOT the empty string.
|
||||
/**
|
||||
* @brief Boolean conversion of the indexed name.
|
||||
*
|
||||
* Boolean conversion provides the opposite of isNull(), yielding true when
|
||||
* the text part of the name is NOT the empty string.
|
||||
*/
|
||||
explicit operator bool() const
|
||||
{
|
||||
return !isNull();
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Apply the IndexedName rules and either store the characters of a new type or a reference to
|
||||
/// the characters in a type named in types, or stored statically within this function. If len
|
||||
/// is not set, or set to -1 (the default), then the provided string in name is scanned for its
|
||||
/// length using strlen (e.g. it must be null-terminated).
|
||||
///
|
||||
/// \param name The new name. If necessary a copy is made, this char * need not be persistent
|
||||
/// \param length The length of name
|
||||
/// \param allowedNames A vector of storage locations of allowed names. These storage locations
|
||||
/// must be persistent for the duration of the program run.
|
||||
/// \param allowOthers If true (the default), then if name is not in allowedNames it is allowed,
|
||||
/// and it is added to internal storage (making a copy of the name if this is its first
|
||||
/// occurrence).
|
||||
/**
|
||||
* @brief Set the text part of the indexed name.
|
||||
*
|
||||
* Apply the IndexedName rules and either store the characters of a new
|
||||
* type or a reference to the characters in a type named in types, or
|
||||
* stored statically within this function. If len is not set, or set to -1
|
||||
* (the default), then the provided string in name is scanned for its
|
||||
* length using strlen (e.g. it must be null-terminated).
|
||||
*
|
||||
* @param[in] name The new name. If necessary, a copy is made. The
|
||||
* provided string need not be persistent.
|
||||
* @param[in] length The length of name.
|
||||
* @param allowedNames A vector of storage locations of allowed
|
||||
* names. These storage locations must be persistent for the duration of
|
||||
* the program run.
|
||||
* @param[in] allowOthers If true (the default), then if name is not in
|
||||
* allowedNames, it is allowed and it is added to internal storage (making
|
||||
* a copy of the name if this is its first occurrence).
|
||||
*/
|
||||
void set(const char* name,
|
||||
int length = -1,
|
||||
const std::vector<const char*>& allowedNames = {},
|
||||
|
||||
@@ -35,21 +35,36 @@ class DocumentObject;
|
||||
namespace Data
|
||||
{
|
||||
|
||||
/// A MappedElement combines a MappedName and and IndexedName into a single entity and provides
|
||||
/// simple comparison operators for the combination (including operator< so that the entity can
|
||||
/// be sorted, or used in sorted containers).
|
||||
/**
|
||||
* @brief A combination of a MappedName and an IndexedName.
|
||||
* @ingroup ElementMapping
|
||||
*
|
||||
* A mapped element combines a mapped name and an indexed name into a single
|
||||
* entity and provides simple comparison operators for the combination
|
||||
* (including operator< so that the entity can be sorted, or used in sorted
|
||||
* containers).
|
||||
*/
|
||||
struct AppExport MappedElement
|
||||
{
|
||||
/// The indexed name.
|
||||
IndexedName index;
|
||||
/// The mapped name.
|
||||
MappedName name;
|
||||
|
||||
MappedElement() = default;
|
||||
|
||||
/**
|
||||
* @brief Construct a mapped element from an indexed name and a mapped name.
|
||||
*
|
||||
* @param[in] idx The indexed name.
|
||||
* @param[in] n The mapped name.
|
||||
*/
|
||||
MappedElement(const IndexedName& idx, MappedName n)
|
||||
: index(idx)
|
||||
, name(std::move(n))
|
||||
{}
|
||||
|
||||
///@copydoc MappedElement(const IndexedName& idx, MappedName n)
|
||||
MappedElement(MappedName n, const IndexedName& idx)
|
||||
: index(idx)
|
||||
, name(std::move(n))
|
||||
@@ -83,9 +98,14 @@ struct AppExport MappedElement
|
||||
return this->index != other.index || this->name != other.name;
|
||||
}
|
||||
|
||||
/// For sorting purposes, one MappedElement is considered "less" than another if its index
|
||||
/// compares less (which is first alphabetical, and then by numeric index). If the index of this
|
||||
/// MappedElement is the same, then the names are compared lexicographically.
|
||||
/**
|
||||
* @brief Compare two mapped elements.
|
||||
*
|
||||
* For sorting purposes, one MappedElement is considered "less" than
|
||||
* another if its index compares less (which is first alphabetical, and
|
||||
* then by numeric index). If the index of this MappedElement is the same,
|
||||
* then the names are compared lexicographically.
|
||||
*/
|
||||
bool operator<(const MappedElement& other) const
|
||||
{
|
||||
int res = this->index.compare(other.index);
|
||||
@@ -99,6 +119,7 @@ struct AppExport MappedElement
|
||||
}
|
||||
};
|
||||
|
||||
/// Struct to represent an item in the history of an object.
|
||||
struct AppExport HistoryItem
|
||||
{
|
||||
App::DocumentObject* obj;
|
||||
@@ -109,19 +130,20 @@ struct AppExport HistoryItem
|
||||
HistoryItem(App::DocumentObject* obj, const Data::MappedName& name);
|
||||
};
|
||||
|
||||
///Comparator struct to make element name sorting more stable.
|
||||
struct AppExport ElementNameComparator
|
||||
{
|
||||
/** Comparison function to make topo name more stable
|
||||
/**
|
||||
* @brief Comparison function to make topo name more stable.
|
||||
*
|
||||
* The sorting decomposes the name into either of the following two forms
|
||||
* '#' + hex_digits + tail
|
||||
* non_digits + digits + tail
|
||||
* The sorting decomposes the name into either of the following two forms:
|
||||
* - '#' + hex_digits + tail
|
||||
* - non_digits + digits + tail
|
||||
*
|
||||
* The non-digits part is compared lexically, while the digits part is
|
||||
* compared by its integer value.
|
||||
*
|
||||
* The reason for this is to prevent names with bigger digits (which usually means
|
||||
* they come later in history) from coming earlier when sorting.
|
||||
* The non-digits part is compared lexicographically, while the digits part
|
||||
* is compared by its integer value. The reason for this is to prevent
|
||||
* names with bigger digits (which usually means they come later in
|
||||
* history) from coming earlier when sorting.
|
||||
*/
|
||||
bool operator()(const MappedName& leftName, const MappedName& rightName) const;
|
||||
};
|
||||
|
||||
@@ -45,20 +45,30 @@ namespace Data
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
|
||||
/// The MappedName class maintains a two-part name: the first part ("data") is considered immutable
|
||||
/// once created, while the second part ("postfix") can be modified/appended to by later operations.
|
||||
/// It uses shared data when possible (see the fromRawData() members). Despite storing data and
|
||||
/// postfix separately, they can be accessed via calls to size(), operator[], etc. as though they
|
||||
/// were a single array.
|
||||
/**
|
||||
* @brief A class for managing element map names.
|
||||
* @ingroup ElementMapping
|
||||
*
|
||||
* The MappedName class maintains a two-part name: the first part ("data") is
|
||||
* considered immutable once created, while the second part ("postfix") can be
|
||||
* modified/appended to by later operations. It uses shared data when possible
|
||||
* (see the fromRawData() members). Despite storing data and postfix
|
||||
* separately, they can be accessed via calls to size(), operator[], etc. as
|
||||
* though they were a single array.
|
||||
*/
|
||||
class AppExport MappedName
|
||||
{
|
||||
public:
|
||||
/// Create a MappedName from a C string, optionally prefixed by an element map prefix, which
|
||||
/// will be omitted from the stored MappedName.
|
||||
///
|
||||
/// \param name The new name. A deep copy is made.
|
||||
/// \param size Optional, the length of the name string. If not provided, the string must be
|
||||
/// null-terminated.
|
||||
/**
|
||||
* @brief Create a MappedName from a C string.
|
||||
*
|
||||
* Create a MappedName from a C string, optionally prefixed by an element
|
||||
* map prefix, which will be omitted from the stored MappedName.
|
||||
*
|
||||
* @param[in] name The new name. A deep copy is made.
|
||||
* @param[in] size Optional, the length of the name string. If not
|
||||
* provided, the string must be null-terminated.
|
||||
*/
|
||||
explicit MappedName(const char* name, int size = -1)
|
||||
: raw(false)
|
||||
{
|
||||
@@ -72,10 +82,14 @@ public:
|
||||
data = size < 0 ? QByteArray(name) : QByteArray(name, size);
|
||||
}
|
||||
|
||||
/// Create a MappedName from a C++ std::string, optionally prefixed by an element map prefix,
|
||||
/// which will be omitted from the stored MappedName.
|
||||
///
|
||||
/// \param name The new name. A deep copy is made.
|
||||
/**
|
||||
* @brief Create a MappedName from a C++ std::string.
|
||||
*
|
||||
* Create a MappedName from a C++ std::string, optionally prefixed by an
|
||||
* element map prefix, which will be omitted from the stored MappedName.
|
||||
*
|
||||
* @param nameString The new name. A deep copy is made.
|
||||
*/
|
||||
explicit MappedName(const std::string& nameString)
|
||||
: raw(false)
|
||||
{
|
||||
@@ -88,9 +102,14 @@ public:
|
||||
data = QByteArray(name, static_cast<int>(size));
|
||||
}
|
||||
|
||||
/// Create a MappedName from an IndexedName. If non-zero, the numerical part of the IndexedName
|
||||
/// is appended as text to the MappedName. In that case the memory is *not* shared between the
|
||||
/// original IndexedName and the MappedName.
|
||||
/**
|
||||
* @brief Create a MappedName from an IndexedName.
|
||||
*
|
||||
* Create a MappedName from an IndexedName. If non-zero, the numerical part
|
||||
* of the IndexedName is appended as text to the MappedName. In that case
|
||||
* the memory is *not* shared between the original IndexedName and the
|
||||
* MappedName.
|
||||
*/
|
||||
explicit MappedName(const IndexedName& element)
|
||||
: data(QByteArray::fromRawData(element.getType(),
|
||||
static_cast<int>(qstrlen(element.getType()))))
|
||||
@@ -102,6 +121,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Create a MappedName from a StringIdRef.
|
||||
explicit MappedName(const App::StringIDRef& sid)
|
||||
: raw(false)
|
||||
{
|
||||
@@ -114,29 +135,39 @@ public:
|
||||
|
||||
MappedName(const MappedName& other) = default;
|
||||
|
||||
/// Copy constructor with start position offset and optional size. The data is *not* reused.
|
||||
///
|
||||
/// \param other The MappedName to copy
|
||||
/// \param startPosition an integer offset to start the copy from
|
||||
/// \param size the number of bytes to copy.
|
||||
/// \see append() for details about how the copy behaves for various sizes and start positions
|
||||
/**
|
||||
* @brief Copy constructor with start position offset and size.
|
||||
*
|
||||
* Copy constructor with start position offset and optional size. The data
|
||||
* is *not* reused.
|
||||
*
|
||||
* @param[in] other The MappedName to copy.
|
||||
* @param[in] startPosition An integer offset to start the copy from.
|
||||
* @param[in] size The number of bytes to copy.
|
||||
*
|
||||
* @see append() for details about how the copy behaves for various sizes
|
||||
* and start positions
|
||||
*/
|
||||
MappedName(const MappedName& other, int startPosition, int size = -1)
|
||||
: raw(false)
|
||||
{
|
||||
append(other, startPosition, size);
|
||||
}
|
||||
|
||||
/// Copy constructor with additional postfix
|
||||
///
|
||||
/// \param other The mapped name to copy. Its data and postfix become the new MappedName's data
|
||||
/// \param postfix The postfix for the new MappedName
|
||||
/**
|
||||
* @brief Copy constructor with additional postfix
|
||||
*
|
||||
* @param[in] other The mapped name to copy. Its data and postfix become
|
||||
* the new MappedName's data.
|
||||
*
|
||||
* @param postfix The postfix for the new MappedName.
|
||||
*/
|
||||
MappedName(const MappedName& other, const char* postfix)
|
||||
: data(other.data + other.postfix)
|
||||
, postfix(postfix)
|
||||
, raw(false)
|
||||
{}
|
||||
|
||||
/// Move constructor
|
||||
MappedName(MappedName&& other) noexcept
|
||||
: data(std::move(other.data))
|
||||
, postfix(std::move(other.postfix))
|
||||
@@ -145,12 +176,17 @@ public:
|
||||
|
||||
~MappedName() = default;
|
||||
|
||||
/// Construct a MappedName from raw character data (including null characters, if size is
|
||||
/// provided). No copy is made: the data is used in place.
|
||||
///
|
||||
/// \param name The raw data to use.
|
||||
/// \param size The number of bytes to access. If omitted, name must be null-terminated.
|
||||
/// \return a new MappedName with name as its data.
|
||||
/**
|
||||
* @brief Construct a MappedName from raw character data.
|
||||
*
|
||||
* Construct a MappedName from raw character data (including null characters, if size is
|
||||
* provided). No copy is made: the data is used in place.
|
||||
*
|
||||
* @param name The raw data to use.
|
||||
* @param size The number of bytes to access. If omitted, name must be null-terminated.
|
||||
*
|
||||
* @return a new MappedName with name as its data.
|
||||
*/
|
||||
static MappedName fromRawData(const char* name, int size = -1)
|
||||
{
|
||||
MappedName res;
|
||||
@@ -162,25 +198,36 @@ public:
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Construct a MappedName from QByteArray data (including any embedded null characters).
|
||||
///
|
||||
/// \param data The original data. No copy is made, the data is shared with the other instance.
|
||||
/// \return a new MappedName with data as its data.
|
||||
/**
|
||||
* @brief Construct a MappedName from QByteArray data.
|
||||
*
|
||||
* Construct a MappedName from QByteArray data (including any embedded null characters).
|
||||
*
|
||||
* @param[in] data The original data. No copy is made, the data is shared
|
||||
* with the other instance.
|
||||
*
|
||||
* @return a new MappedName with data as its data.
|
||||
*/
|
||||
static MappedName fromRawData(const QByteArray& data)
|
||||
{
|
||||
return fromRawData(data.constData(), data.size());
|
||||
}
|
||||
|
||||
/// Construct a MappedName from another MappedName
|
||||
///
|
||||
/// \param other The MappedName to copy from. The data is usually not copied, but in some
|
||||
/// cases a partial copy may be made to support a slice that extends across other's data into
|
||||
/// its postfix.
|
||||
/// \param startPosition The position to start the reference at.
|
||||
/// \param size The number of bytes to access. If omitted, continues from startPosition
|
||||
/// to the end of available data (including postfix).
|
||||
/// \return a new MappedName sharing (possibly a subset of) data with other.
|
||||
/// \see append() for details about how the copy behaves for various sizes and start positions
|
||||
/**
|
||||
* @brief Construct a MappedName from another MappedName.
|
||||
*
|
||||
* @param[in] other The MappedName to copy from. The data is usually not
|
||||
* copied, but in some cases a partial copy may be made to support a slice
|
||||
* that extends across other's data into its postfix.
|
||||
* @param[in] startPosition The position to start the reference at.
|
||||
* @param[in] size The number of bytes to access. If omitted, continues
|
||||
* from startPosition to the end of available data (including postfix).
|
||||
*
|
||||
* @return a new MappedName sharing (possibly a subset of) data with other.
|
||||
*
|
||||
* @see append() For details about how the copy behaves for various sizes
|
||||
* and start positions.
|
||||
*/
|
||||
static MappedName fromRawData(const MappedName& other, int startPosition, int size = -1)
|
||||
{
|
||||
if (startPosition < 0) {
|
||||
@@ -218,7 +265,7 @@ public:
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Share data with another MappedName
|
||||
/// Share data with another MappedName.
|
||||
MappedName& operator=(const MappedName& other) = default;
|
||||
|
||||
/// Create a new MappedName from a std::string: the string's data is copied.
|
||||
@@ -235,8 +282,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
/// Move-construct a MappedName
|
||||
/// Move-construct a MappedName.
|
||||
MappedName& operator=(MappedName&& other) noexcept
|
||||
{
|
||||
this->data = std::move(other.data);
|
||||
@@ -245,8 +291,12 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Write to a stream as the name with postfix directly appended to it. Note that there is no
|
||||
/// special handling for null or non-ASCII characters, they are simply written to the stream.
|
||||
/**
|
||||
* @brief Write to a stream as the name with postfix directly appended to it.
|
||||
*
|
||||
* Note that there is no special handling for null or non-ASCII characters,
|
||||
* they are simply written to the stream.
|
||||
*/
|
||||
friend std::ostream& operator<<(std::ostream& stream, const MappedName& mappedName)
|
||||
{
|
||||
stream.write(mappedName.data.constData(), mappedName.data.size());
|
||||
@@ -254,8 +304,11 @@ public:
|
||||
return stream;
|
||||
}
|
||||
|
||||
/// Two MappedNames are equal if the concatenation of their data and postfix is equal. The
|
||||
/// individual data and postfix may NOT be equal in this case.
|
||||
/**
|
||||
* @brief Two MappedNames are equal if the concatenation of their data and postfix is equal.
|
||||
*
|
||||
* The individual data and postfix may NOT be equal in this case.
|
||||
*/
|
||||
bool operator==(const MappedName& other) const
|
||||
{
|
||||
if (this->size() != other.size()) {
|
||||
@@ -286,13 +339,21 @@ public:
|
||||
return tmp == larger.postfix;
|
||||
}
|
||||
|
||||
/// Check if two mapped names are inequal.
|
||||
bool operator!=(const MappedName& other) const
|
||||
{
|
||||
return !(this->operator==(other));
|
||||
}
|
||||
|
||||
/// Returns a new MappedName whose data is the LHS argument's data and whose postfix is the LHS
|
||||
/// argument's postfix with the RHS argument's data and postfix appended to it.
|
||||
/**
|
||||
* @brief Concatenate two mapped names.
|
||||
*
|
||||
* @param[in] other The mapped name to append.
|
||||
*
|
||||
* @return A new MappedName whose data is the LHS argument's data and whose
|
||||
* postfix is the LHS argument's postfix with the RHS argument's data and
|
||||
* postfix appended to it.
|
||||
*/
|
||||
MappedName operator+(const MappedName& other) const
|
||||
{
|
||||
MappedName res(*this);
|
||||
@@ -300,8 +361,15 @@ public:
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Returns a new MappedName whose data is the LHS argument's data and whose postfix is the LHS
|
||||
/// argument's postfix with the RHS argument appended to it. The character data is copied.
|
||||
/**
|
||||
* @brief Concatenate two mapped names.
|
||||
*
|
||||
* @param[in] other The mapped name as a string to append.
|
||||
*
|
||||
* @return A new MappedName whose data is the LHS argument's data and whose
|
||||
* postfix is the LHS argument's postfix with the RHS argument appended to
|
||||
* it. The character data is copied.
|
||||
*/
|
||||
MappedName operator+(const char* other) const
|
||||
{
|
||||
MappedName res(*this);
|
||||
@@ -309,8 +377,7 @@ public:
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Returns a new MappedName whose data is the LHS argument's data and whose postfix is the LHS
|
||||
/// argument's postfix with the RHS argument appended to it. The character data is copied.
|
||||
/// @copydoc operator+(const char*) const
|
||||
MappedName operator+(const std::string& other) const
|
||||
{
|
||||
MappedName res(*this);
|
||||
@@ -318,8 +385,15 @@ public:
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Returns a new MappedName whose data is the LHS argument's data and whose postfix is the LHS
|
||||
/// argument's postfix with the RHS argument appended to it.
|
||||
/**
|
||||
* @brief Concatenate two mapped names.
|
||||
*
|
||||
* @param[in] other The mapped name as a QByteArray.
|
||||
*
|
||||
* @return A new MappedName whose data is the LHS argument's data and whose
|
||||
* postfix is the LHS argument's postfix with the RHS argument appended to
|
||||
* it.
|
||||
*/
|
||||
MappedName operator+(const QByteArray& other) const
|
||||
{
|
||||
MappedName res(*this);
|
||||
@@ -327,8 +401,16 @@ public:
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Appends other to this instance's postfix. other must be a null-terminated C string. The
|
||||
/// character data from the string is copied.
|
||||
/**
|
||||
* @brief Appends other to this instance's postfix.
|
||||
*
|
||||
* @p other must be a null-terminated C string. The character data from the
|
||||
* string is copied.
|
||||
*
|
||||
* @param[in] other The mapped name as a string.
|
||||
*
|
||||
* @return This with the other's postfix appended.
|
||||
*/
|
||||
MappedName& operator+=(const char* other)
|
||||
{
|
||||
if (other && (other[0] != 0)) {
|
||||
@@ -337,7 +419,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Appends other to this instance's postfix. The character data from the string is copied.
|
||||
/// @copydoc operator+=(const char* other)
|
||||
MappedName& operator+=(const std::string& other)
|
||||
{
|
||||
if (!other.empty()) {
|
||||
@@ -347,29 +429,50 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Appends other to this instance's postfix. The data may be either copied or shared, depending
|
||||
/// on whether this->postfix is empty (in which case the data is shared) or non-empty (in which
|
||||
/// case it is copied).
|
||||
/**
|
||||
* @brief Appends other to this instance's postfix.
|
||||
*
|
||||
* The data may be either copied or shared, depending on whether
|
||||
* this->postfix is empty (in which case the data is shared) or non-empty
|
||||
* (in which case it is copied).
|
||||
*
|
||||
* @param[in] other The mapped name as a QByteArray.
|
||||
* @return This with the other's data appended.
|
||||
*/
|
||||
MappedName& operator+=(const QByteArray& other)
|
||||
{
|
||||
this->postfix += other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Appends other to this instance's postfix, unless this is empty, in which case this acts
|
||||
/// like operator=, and makes this instance's data equal to other's data, and this instance's
|
||||
/// postfix equal to the other instance's postfix.
|
||||
/**
|
||||
* @brief Appends other to this instance's postfix.
|
||||
*
|
||||
* Appends other to this instance's postfix, unless this is empty, in which
|
||||
* case this acts like operator=, and makes this instance's data equal to
|
||||
* other's data, and this instance's postfix equal to the other instance's
|
||||
* postfix.
|
||||
*
|
||||
* @param[in] other The mapped name to append.
|
||||
* @return This with the other's data appended.
|
||||
*/
|
||||
MappedName& operator+=(const MappedName& other)
|
||||
{
|
||||
append(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Add dataToAppend to this MappedName. If the current name is empty, this becomes the new
|
||||
/// data element. If this MappedName already has data, then the data is appended to the postfix.
|
||||
///
|
||||
/// \param dataToAppend The data to add. A deep copy is made.
|
||||
/// \param size The number of bytes to copy. If omitted, dataToAppend must be null-terminated.
|
||||
/**
|
||||
* @brief Append to this mapped name.
|
||||
*
|
||||
* Add @p dataToAppend to this mapped name. If the current name is empty,
|
||||
* this becomes the new data element. If this MappedName already has data,
|
||||
* then the data is appended to the postfix.
|
||||
*
|
||||
* @param[in] dataToAppend The data to add. A deep copy is made.
|
||||
* @param[in] size The number of bytes to copy. If omitted, @p dataToAppend
|
||||
* must be null-terminated.
|
||||
*/
|
||||
void append(const char* dataToAppend, int size = -1)
|
||||
{
|
||||
if (dataToAppend && (size != 0)) {
|
||||
@@ -385,20 +488,30 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// Treating both this and other as single continuous byte arrays, append other to this. If this
|
||||
/// is empty, then other's data is shared with this instance's data beginning at startPosition.
|
||||
/// If this is *not* empty, then all data is appended to the postfix. If the copy crosses the
|
||||
/// boundary between other's data and its postfix, then if this instance was empty, the new
|
||||
/// data stops where other's data stops, and the remainder of the copy is placed in the suffix.
|
||||
/// Otherwise the copy simply continues as though there was no distinction between other's
|
||||
/// data and suffix.
|
||||
///
|
||||
/// \param other The MappedName to obtain the data from. The data is shared when possible,
|
||||
/// depending on the details of startPosition, size, and this->empty().
|
||||
/// \param startPosition The byte to start the copy at. Must be a positive non-zero integer less
|
||||
/// than the length of other's combined data + postfix.
|
||||
/// \param size The number of bytes to copy. Must not overrun the end of other's combined data
|
||||
/// storage when taking startPosition into consideration.
|
||||
/**
|
||||
* @brief Append to this mapped name.
|
||||
*
|
||||
* Treating both this and other as single continuous byte arrays, append
|
||||
* other to this. If this is empty, then other's data is shared with this
|
||||
* instance's data beginning at @p startPosition. If this is *not* empty,
|
||||
* then all data is appended to the postfix. If the copy crosses the
|
||||
* boundary between other's data and its postfix, then if this instance was
|
||||
* empty, the new data stops where other's data stops, and the remainder of
|
||||
* the copy is placed in the suffix. Otherwise the copy simply continues
|
||||
* as though there was no distinction between other's data and suffix.
|
||||
*
|
||||
* @param[in] other The MappedName to obtain the data from. The data is
|
||||
* shared when possible, depending on the details of startPosition, size,
|
||||
* and this->empty().
|
||||
*
|
||||
* @param startPosition The byte to start the copy at. Must be a positive
|
||||
* non-zero integer less than the length of other's combined data +
|
||||
* postfix.
|
||||
*
|
||||
* @param size The number of bytes to copy. Must not overrun the end of
|
||||
* other's combined data storage when taking @p startPosition into
|
||||
* consideration.
|
||||
*/
|
||||
void append(const MappedName& other, int startPosition = 0, int size = -1)
|
||||
{
|
||||
// enforce 0 <= startPosition <= other.size
|
||||
@@ -460,31 +573,49 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a std::string from this instance, starting at startPosition, and extending len bytes.
|
||||
///
|
||||
/// \param startPosition The offset into the data
|
||||
/// \param len The number of bytes to output
|
||||
/// \return A new std::string containing the bytes copied from this instance's data and postfix
|
||||
/// (depending on startPosition and len).
|
||||
/// \note No effort is made to ensure that these are valid ASCII characters, and it is possible
|
||||
/// the data includes embedded null characters, non-ASCII data, etc.
|
||||
/**
|
||||
* @brief Create a string representation.
|
||||
*
|
||||
* Create a std::string from this instance, starting at startPosition, and
|
||||
* extending len bytes.
|
||||
*
|
||||
* @param[in] startPosition The offset into the data.
|
||||
* @param[in] len The number of bytes to output.
|
||||
*
|
||||
* @return A new std::string containing the bytes copied from this
|
||||
* instance's data and postfix (depending on startPosition and len).
|
||||
*
|
||||
* @note No effort is made to ensure that these are valid ASCII characters,
|
||||
* and it is possible the data includes embedded null characters, non-ASCII
|
||||
* data, etc.
|
||||
*/
|
||||
std::string toString(int startPosition = 0, int len = -1) const
|
||||
{
|
||||
std::string res;
|
||||
return appendToBuffer(res, startPosition, len);
|
||||
}
|
||||
|
||||
/// Given a (possibly non-empty) std::string buffer, append this instance to it, starting at a
|
||||
/// specified position, and continuing for a specified number of bytes.
|
||||
///
|
||||
/// \param buffer The string buffer to append to.
|
||||
/// \param startPosition The position in this instance's data/postfix to start at (defaults to
|
||||
/// zero). Must be less than the total length of the data plus the postfix.
|
||||
/// \param len The number of bytes to append. If omitted, defaults to appending all available
|
||||
/// data starting at startPosition.
|
||||
/// \return A pointer to the beginning of the appended data within buffer.
|
||||
/// \note No effort is made to ensure that these are valid ASCII characters, and it is possible
|
||||
/// the data includes embedded null characters, non-ASCII data, etc.
|
||||
/**
|
||||
* @brief Append this mapped name to a buffer.
|
||||
*
|
||||
* Given a (possibly non-empty) std::string buffer, append this instance to it, starting at a
|
||||
* specified position, and continuing for a specified number of bytes.
|
||||
*
|
||||
* @param[in,out] buffer The string buffer to append to.
|
||||
*
|
||||
* @param[in] startPosition The position in this instance's data/postfix to
|
||||
* start at (defaults to * zero). Must be less than the total length of the
|
||||
* data plus the postfix.
|
||||
*
|
||||
* @param[in] len The number of bytes to append. If omitted, defaults to
|
||||
* appending all available data starting at startPosition.
|
||||
*
|
||||
* @return A pointer to the beginning of the appended data within buffer.
|
||||
*
|
||||
* @note No effort is made to ensure that these are valid ASCII characters,
|
||||
* and it is possible the data includes embedded null characters, non-ASCII
|
||||
* data, etc.
|
||||
*/
|
||||
const char* appendToBuffer(std::string& buffer, int startPosition = 0, int len = -1) const
|
||||
{
|
||||
std::size_t offset = buffer.size();
|
||||
@@ -531,16 +662,24 @@ public:
|
||||
return this->data.constData() + offset;
|
||||
}
|
||||
|
||||
/// Get access to raw byte data. When possible, data is shared between this instance and the
|
||||
/// returned QByteArray. If the combination of offset and size results in data that crosses the
|
||||
/// boundary between this->data and this->postfix, the data must be copied in order to provide
|
||||
/// access as a continuous array of bytes.
|
||||
///
|
||||
/// \param offset The start position of the raw data access.
|
||||
/// \param size The number of bytes to access. If omitted, the resulting QByteArray includes
|
||||
/// everything starting from offset to the end, including any postfix data.
|
||||
/// \return A new QByteArray that shares data with this instance if possible, or is a new copy
|
||||
/// if required by offset and size.
|
||||
/**
|
||||
* @brief Convert this mapped name to raw bytes.
|
||||
*
|
||||
* Get access to raw byte data. When possible, data is shared between this
|
||||
* instance and the returned QByteArray. If the combination of offset and
|
||||
* size results in data that crosses the boundary between this->data and
|
||||
* this->postfix, the data must be copied in order to provide access as a
|
||||
* continuous array of bytes.
|
||||
*
|
||||
* @param[in] offset The start position of the raw data access.
|
||||
*
|
||||
* @param[in] size The number of bytes to access. If omitted, the resulting
|
||||
* QByteArray includes everything starting from offset to the end,
|
||||
* including any postfix data.
|
||||
*
|
||||
* @return A new QByteArray that shares data with this instance if
|
||||
* possible, or is a new copy if required by offset and size.
|
||||
*/
|
||||
QByteArray toRawBytes(int offset = 0, int size = -1) const
|
||||
{
|
||||
if (offset < 0) {
|
||||
@@ -585,10 +724,16 @@ public:
|
||||
|
||||
// No constData() because 'data' is allowed to contain raw data, which may not end with 0.
|
||||
|
||||
/// Provide access to the content of this instance. If either postfix or data is empty, no copy
|
||||
/// is made and the original QByteArray is returned, sharing data with this instance. If this
|
||||
/// instance contains both data and postfix, a new QByteArray is created and stores a copy of
|
||||
/// the data and postfix concatenated together.
|
||||
/**
|
||||
* @brief Provide access to the content of this instance.
|
||||
*
|
||||
* If either postfix or data is empty, no copy is made and the original
|
||||
* QByteArray is returned, sharing data with this instance. If this
|
||||
* instance contains both data and postfix, a new QByteArray is created and
|
||||
* stores a copy of the data and postfix concatenated together.
|
||||
*
|
||||
* @return Either a new or the current QByteArray.
|
||||
*/
|
||||
QByteArray toBytes() const
|
||||
{
|
||||
if (this->postfix.isEmpty()) {
|
||||
@@ -600,13 +745,19 @@ public:
|
||||
return this->data + this->postfix;
|
||||
}
|
||||
|
||||
/// Create an IndexedName from the data portion of this MappedName. If this data has a postfix,
|
||||
/// the function returns an empty IndexedName. The function will fail if this->data contains
|
||||
/// anything other than the ASCII letter a-z, A-Z, and the underscore, with an optional integer
|
||||
/// suffix, returning an empty IndexedName (e.g. an IndexedName that evaluates to boolean
|
||||
/// false and isNull() == true).
|
||||
///
|
||||
/// \return a new IndexedName that shares its data with this instance's data member.
|
||||
/**
|
||||
* @brief Create an IndexedName from the mapped name.
|
||||
*
|
||||
* Create an IndexedName from the data portion of this MappedName. If this
|
||||
* data has a postfix, the function returns an empty IndexedName. The
|
||||
* function will fail if this->data contains anything other than the ASCII
|
||||
* letter a-z, A-Z, and the underscore, with an optional integer suffix,
|
||||
* returning an empty IndexedName (e.g. an IndexedName that evaluates to
|
||||
* boolean false and isNull() == true).
|
||||
*
|
||||
* @return a new IndexedName that shares its data with this instance's data
|
||||
* member.
|
||||
*/
|
||||
IndexedName toIndexedName() const
|
||||
{
|
||||
if (this->postfix.isEmpty()) {
|
||||
@@ -615,8 +766,13 @@ public:
|
||||
return IndexedName();
|
||||
}
|
||||
|
||||
/// Create and return a string version of this MappedName prefixed by the ComplexGeoData element
|
||||
/// map prefix, if this MappedName cannot be converted to an indexed name.
|
||||
/**
|
||||
* @brief Create a prefixed string from the mapped name.
|
||||
*
|
||||
* Create and return a string version of this MappedName prefixed by the
|
||||
* ComplexGeoData element map prefix, if this MappedName cannot be
|
||||
* converted to an indexed name.
|
||||
*/
|
||||
std::string toPrefixedString() const
|
||||
{
|
||||
std::string res;
|
||||
@@ -624,11 +780,18 @@ public:
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Append this MappedName to a provided string buffer, including the ComplexGeoData element
|
||||
/// map prefix if the MappedName cannot be converted to an IndexedName.
|
||||
///
|
||||
/// \param buf A (possibly non-empty) string to append this MappedName to.
|
||||
/// \return A pointer to the beginning of the buffer.
|
||||
/**
|
||||
* @brief Append this mapped name to a string buffer.
|
||||
*
|
||||
* Append this MappedName to a provided string buffer, including the
|
||||
* ComplexGeoData element map prefix if the MappedName cannot be converted
|
||||
* to an IndexedName.
|
||||
*
|
||||
* @param[in,out] buf A (possibly non-empty) string to append this
|
||||
* MappedName to.
|
||||
*
|
||||
* @return A pointer to the beginning of the buffer.
|
||||
*/
|
||||
const char* appendToBufferWithPrefix(std::string& buf) const
|
||||
{
|
||||
if (!toIndexedName()) {
|
||||
@@ -638,10 +801,20 @@ public:
|
||||
return buf.c_str();
|
||||
}
|
||||
|
||||
/// Equivalent to C++20 operator<=>. Performs byte-by-byte comparison of this and other,
|
||||
/// starting at the first byte and continuing through both data and postfix, ignoring which is
|
||||
/// which. If the combined data and postfix members are of unequal size but start with the same
|
||||
/// data, the shorter array is considered "less than" the longer.
|
||||
/**
|
||||
* @brief Compare two mapped names.
|
||||
*
|
||||
* Equivalent to C++20 operator<=>. Performs byte-by-byte comparison of
|
||||
* this and other, starting at the first byte and continuing through both
|
||||
* data and postfix, ignoring which is which. If the combined data and
|
||||
* postfix members are of unequal size but start with the same data, the
|
||||
* shorter array is considered "less than" the longer.
|
||||
*
|
||||
* @param[in] other The mapped name to compare.
|
||||
*
|
||||
* @return < 0 if this is less than other, 0 if they are equal and > 0 if
|
||||
* this is greater than other.
|
||||
*/
|
||||
int compare(const MappedName& other) const
|
||||
{
|
||||
int thisSize = this->size();
|
||||
@@ -665,14 +838,23 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \see compare()
|
||||
/// Check if this mapped name is less than @p other.
|
||||
bool operator<(const MappedName& other) const
|
||||
{
|
||||
return compare(other) < 0;
|
||||
}
|
||||
|
||||
/// Treat this MappedName as a single continuous array of bytes, beginning with data and
|
||||
/// continuing through postfix. No bounds checking is performed when compiled in release mode.
|
||||
/**
|
||||
* @brief Index into the mapped name.
|
||||
*
|
||||
* Treat this MappedName as a single continuous array of bytes, beginning
|
||||
* with data and continuing through postfix.
|
||||
*
|
||||
* @param index The byte offset to access.
|
||||
*
|
||||
* @return The byte at the specified offset, or 0 if the offset is out of
|
||||
* range.
|
||||
*/
|
||||
char operator[](int index) const
|
||||
{
|
||||
if (index < 0) {
|
||||
@@ -687,31 +869,52 @@ public:
|
||||
return this->data[index];
|
||||
}
|
||||
|
||||
/// Treat this MappedName as a single continuous array of bytes, returning the combined size
|
||||
/// of the data and postfix.
|
||||
/**
|
||||
* @brief Get the combined size of data and postfix.
|
||||
*
|
||||
* Treat this MappedName as a single continuous array of bytes, returning the combined size
|
||||
* of the data and postfix.
|
||||
*
|
||||
* @return The total number of bytes in data + postfix.
|
||||
*/
|
||||
int size() const
|
||||
{
|
||||
return this->data.size() + this->postfix.size();
|
||||
}
|
||||
|
||||
/// Treat this MappedName as a single continuous array of bytes, returning true only if both
|
||||
/// data and prefix are empty.
|
||||
/**
|
||||
* @brief Check if the mapped name is empty.
|
||||
*
|
||||
* Treat this MappedName as a single continuous array of bytes, returning true only if both
|
||||
* data and prefix are empty.
|
||||
*
|
||||
* @return true if there are no bytes in data or postfix.
|
||||
*/
|
||||
bool empty() const
|
||||
{
|
||||
return this->data.isEmpty() && this->postfix.isEmpty();
|
||||
}
|
||||
|
||||
/// Returns true if this is shared data, or false if a unique copy has been made.
|
||||
/// It is safe to access data only if it has been copied prior. To force a copy
|
||||
/// please \see compact()
|
||||
/**
|
||||
* @brief Check whether this mapped name is shared data.
|
||||
*
|
||||
* It is safe to access data only if it has been copied prior. To force a copy
|
||||
* please \see compact().
|
||||
*
|
||||
* @return True if this is shared data, or false if a unique copy has been made.
|
||||
*/
|
||||
bool isRaw() const
|
||||
{
|
||||
return this->raw;
|
||||
}
|
||||
|
||||
/// If this is shared data, a new unshared copy is made and returned. If it is already unshared
|
||||
/// no new copy is made, a new instance is returned that shares is data with the current
|
||||
/// instance.
|
||||
/**
|
||||
* @brief Copy the mapped name.
|
||||
*
|
||||
* If this is shared data, a new unshared copy is made and returned. If it
|
||||
* is already unshared no new copy is made, a new instance is returned that
|
||||
* shares is data with the current instance.
|
||||
*/
|
||||
MappedName copy() const
|
||||
{
|
||||
if (!this->raw) {
|
||||
@@ -726,14 +929,22 @@ public:
|
||||
/// Ensure that this data is unshared, making a copy if necessary.
|
||||
void compact() const;
|
||||
|
||||
/// Boolean conversion is the inverse of empty(), returning true if there is data in either the
|
||||
/// data or postfix, and false if there is nothing in either.
|
||||
/**
|
||||
* @brief Boolean conversion is the inverse of empty().
|
||||
*
|
||||
* @return True if there is data in either the data or postfix, and false
|
||||
* if there is nothing in either.
|
||||
*/
|
||||
explicit operator bool() const
|
||||
{
|
||||
return !empty();
|
||||
}
|
||||
|
||||
/// Reset this instance, clearing anything in data and postfix.
|
||||
/**
|
||||
* @brief Reset this instance.
|
||||
*
|
||||
* Clear anything in data and postfix.
|
||||
*/
|
||||
void clear()
|
||||
{
|
||||
this->data.clear();
|
||||
@@ -741,12 +952,19 @@ public:
|
||||
this->raw = false;
|
||||
}
|
||||
|
||||
/// Find a string of characters in this MappedName. The bytes must occur either entirely in the
|
||||
/// data, or entirely in the postfix: a string that overlaps the two will not be found.
|
||||
///
|
||||
/// \param searchTarget A null-terminated C string to search for.
|
||||
/// \param startPosition A byte offset to start the search at.
|
||||
/// \return The position of the target in this instance, or -1 if the target is not found.
|
||||
/**
|
||||
* @brief Find a string of characters in this mapped name.
|
||||
*
|
||||
* Find a string of characters in this mapped name. The bytes must occur
|
||||
* either entirely in the data, or entirely in the postfix: a string that
|
||||
* overlaps the two will not be found.
|
||||
*
|
||||
* @param[in] searchTarget A null-terminated C string to search for.
|
||||
* @param[in] startPosition A byte offset to start the search at.
|
||||
*
|
||||
* @return The position of the target in this instance, or -1 if the target
|
||||
* is not found.
|
||||
*/
|
||||
int find(const char* searchTarget, int startPosition = 0) const
|
||||
{
|
||||
if (!searchTarget) {
|
||||
@@ -772,25 +990,29 @@ public:
|
||||
return res + this->data.size();
|
||||
}
|
||||
|
||||
/// Find a string of characters in this MappedName. The bytes must occur either entirely in the
|
||||
/// data, or entirely in the postfix: a string that overlaps the two will not be found.
|
||||
///
|
||||
/// \param searchTarget A string to search for.
|
||||
/// \param startPosition A byte offset to start the search at.
|
||||
/// \return The position of the target in this instance, or -1 if the target is not found.
|
||||
/// @copydoc find(const char*,int) const
|
||||
int find(const std::string& searchTarget, int startPosition = 0) const
|
||||
{
|
||||
return find(searchTarget.c_str(), startPosition);
|
||||
}
|
||||
|
||||
/// Find a string of characters in this MappedName, starting at the back of postfix and
|
||||
/// proceeding in reverse through the data. The bytes must occur either entirely in the
|
||||
/// data, or entirely in the postfix: a string that overlaps the two will not be found.
|
||||
///
|
||||
/// \param searchTarget A null-terminated C string to search for.
|
||||
/// \param startPosition A byte offset to start the search at. Negative numbers are supported
|
||||
/// and count back from the end of the concatenated data (as in QByteArray::lastIndexOf()).
|
||||
/// \return The position of the target in this instance, or -1 if the target is not found.
|
||||
/**
|
||||
* @brief Reverse find a string of characters in this mapped name.
|
||||
*
|
||||
* Find a string of characters in this mapped name, starting at the back of
|
||||
* postfix and proceeding in reverse through the data. The bytes must occur
|
||||
* either entirely in the data, or entirely in the postfix: a string that
|
||||
* overlaps the two will not be found.
|
||||
*
|
||||
* @param[in] searchTarget A null-terminated C string to search for.
|
||||
*
|
||||
* @param[in] startPosition A byte offset to start the search at. Negative
|
||||
* numbers are supported and count back from the end of the concatenated
|
||||
* data (as in QByteArray::lastIndexOf()).
|
||||
*
|
||||
* @return The position of the target in this instance, or -1 if the target
|
||||
* is not found.
|
||||
*/
|
||||
int rfind(const char* searchTarget, int startPosition = -1) const
|
||||
{
|
||||
if (!searchTarget) {
|
||||
@@ -809,22 +1031,23 @@ public:
|
||||
return this->data.lastIndexOf(searchTarget, startPosition);
|
||||
}
|
||||
|
||||
/// Find a string in this MappedName, starting at the back of postfix and proceeding in reverse
|
||||
/// through the data. The bytes must occur either entirely in the data, or entirely in the
|
||||
/// postfix: a string that overlaps the two will not be found.
|
||||
///
|
||||
/// \param searchTarget A null-terminated C string to search for.
|
||||
/// \param startPosition A byte offset to start the search at. Negative numbers are supported
|
||||
/// and count back from the end of the concatenated data (as in QByteArray::lastIndexOf()).
|
||||
/// \return The position of the target in this instance, or -1 if the target is not found.
|
||||
/// @copydoc rfind(const char*,int) const
|
||||
int rfind(const std::string& searchTarget, int startPosition = -1) const
|
||||
{
|
||||
return rfind(searchTarget.c_str(), startPosition);
|
||||
}
|
||||
|
||||
/// Returns true if this MappedName ends with the search target. If there is a postfix, only the
|
||||
/// postfix is considered. If not, then only the data is considered. A search string that
|
||||
/// overlaps the two will not be found.
|
||||
/**
|
||||
* @brief Check if this mapped name ends with the search target.
|
||||
*
|
||||
* If there is a postfix, only the postfix is considered. If not, then only
|
||||
* the data is considered. A search string that overlaps the two will not
|
||||
* be found.
|
||||
*
|
||||
* @param[in] searchTarget The string to search for at the end of this mapped name.
|
||||
*
|
||||
* @return true if this MappedName ends with the search target.
|
||||
*/
|
||||
bool endsWith(const char* searchTarget) const
|
||||
{
|
||||
if (!searchTarget) {
|
||||
@@ -836,21 +1059,24 @@ public:
|
||||
return this->data.endsWith(searchTarget);
|
||||
}
|
||||
|
||||
/// Returns true if this MappedName ends with the search target. If there is a postfix, only the
|
||||
/// postfix is considered. If not, then only the data is considered. A search string that
|
||||
/// overlaps the two will not be found.
|
||||
/// @copydoc endsWith(const char*) const
|
||||
bool endsWith(const std::string& searchTarget) const
|
||||
{
|
||||
return endsWith(searchTarget.c_str());
|
||||
}
|
||||
|
||||
/// Returns true if this MappedName starts with the search target. If there is a postfix, only
|
||||
/// the postfix is considered. If not, then only the data is considered. A search string that
|
||||
/// overlaps the two will not be found.
|
||||
///
|
||||
/// \param searchTarget An array of bytes to match
|
||||
/// \param offset An offset to perform the match at
|
||||
/// \return True if this MappedName begins with the target bytes
|
||||
/**
|
||||
* @brief Check if this mapped name starts with the search target.
|
||||
*
|
||||
* If there is a postfix, only the postfix is considered. If not, then only
|
||||
* the data is considered. A search string that overlaps the two will not
|
||||
* be found.
|
||||
*
|
||||
* @param[in] searchTarget The search target to match.
|
||||
* @param[in] offset An offset to perform the match at.
|
||||
*
|
||||
* @return True if this MappedName begins with the target bytes.
|
||||
*/
|
||||
bool startsWith(const QByteArray& searchTarget, int offset = 0) const
|
||||
{
|
||||
if (searchTarget.size() > size() - offset) {
|
||||
@@ -866,13 +1092,7 @@ public:
|
||||
return this->postfix.startsWith(searchTarget);
|
||||
}
|
||||
|
||||
/// Returns true if this MappedName starts with the search target. If there is a postfix, only
|
||||
/// the postfix is considered. If not, then only the data is considered. A search string that
|
||||
/// overlaps the two will not be found.
|
||||
///
|
||||
/// \param searchTarget An array of bytes to match
|
||||
/// \param offset An offset to perform the match at
|
||||
/// \return True if this MappedName begins with the target bytes
|
||||
/// @copydoc startsWith(const QByteArray&,int) const
|
||||
bool startsWith(const char* searchTarget, int offset = 0) const
|
||||
{
|
||||
if (!searchTarget) {
|
||||
@@ -883,13 +1103,7 @@ public:
|
||||
offset);
|
||||
}
|
||||
|
||||
/// Returns true if this MappedName starts with the search target. If there is a postfix, only
|
||||
/// the postfix is considered. If not, then only the data is considered. A search string that
|
||||
/// overlaps the two will not be found.
|
||||
///
|
||||
/// \param searchTarget A string to match
|
||||
/// \param offset An offset to perform the match at
|
||||
/// \return True if this MappedName begins with the target bytes
|
||||
/// @copydoc startsWith(const QByteArray&,int) const
|
||||
bool startsWith(const std::string& searchTarget, int offset = 0) const
|
||||
{
|
||||
return startsWith(
|
||||
@@ -897,19 +1111,26 @@ public:
|
||||
offset);
|
||||
}
|
||||
|
||||
/// Extract tagOut and other information from a encoded element name
|
||||
///
|
||||
/// \param tagOut: optional pointer to receive the extracted tagOut
|
||||
/// \param lenOut: optional pointer to receive the length field after the tagOut field.
|
||||
/// This gives the length of the previous hashed element name starting
|
||||
/// from the beginning of the give element name.
|
||||
/// \param postfixOut: optional pointer to receive the postfixOut starting at the found tagOut
|
||||
/// field. \param typeOut: optional pointer to receive the element typeOut character \param
|
||||
/// negative: return negative tagOut as it is. If disabled, then always return positive tagOut.
|
||||
/// Negative tagOut is sometimes used for element disambiguation.
|
||||
/// \param recursive: recursively find the last non-zero tagOut
|
||||
///
|
||||
/// \return Return the end position of the tagOut field, or return -1 if not found.
|
||||
/**
|
||||
* @brief Extract information from an encoded element name.
|
||||
*
|
||||
* Extract tagOut and other information from an encoded element name.
|
||||
*
|
||||
* @param[out] tagOut: optional pointer to receive the extracted tagOut
|
||||
* @param[out] lenOut: optional pointer to receive the length field after
|
||||
* the tagOut field. This gives the length of the previous hashed element
|
||||
* name starting from the beginning of the give element name.
|
||||
* @param[out] postfixOut: optional pointer to receive the postfixOut
|
||||
* starting at the found tagOut field.
|
||||
* @param[out] typeOut: optional pointer to receive the element typeOut character
|
||||
* @param[in] negative: return negative tagOut as it is. If disabled, then
|
||||
* always return positive tagOut. Negative tagOut is sometimes used for
|
||||
* element disambiguation.
|
||||
* @param[in] recursive: recursively find the last non-zero tagOut
|
||||
*
|
||||
* @return Return the end position of the tagOut field, or return -1 if not
|
||||
* found.
|
||||
*/
|
||||
int findTagInElementName(long* tagOut = nullptr,
|
||||
int* lenOut = nullptr,
|
||||
std::string* postfixOut = nullptr,
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
* @ingroup CORE
|
||||
* @brief The part of FreeCAD that works without GUI (console or server mode)
|
||||
*
|
||||
* @htmlonly
|
||||
* <div class="textblock">
|
||||
* @endhtmlonly
|
||||
*
|
||||
* @details It contains the App namespace and defines core concepts such as
|
||||
* @ref ApplicationGroup "Application", @ref DocumentGroup "Document", @ref
|
||||
* DocumentObjectGroup "DocumentObject", @ref PropertyFramework "Property
|
||||
@@ -14,6 +18,10 @@
|
||||
* in @ref App::Document "Document" and @ref App::DocumentObject
|
||||
* "DocumentObject". In addition, %App has a representation of the running
|
||||
* @ref App::Application "Application".
|
||||
*
|
||||
* @htmlonly
|
||||
* </div>
|
||||
* @endhtmlonly
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -827,6 +835,45 @@
|
||||
* object are tracked and applied on the copy.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup ElementMapping Element Mapping for Topological naming.
|
||||
* @ingroup APP
|
||||
* @brief Element mapping system for topological naming
|
||||
*
|
||||
* Since the names of vertices, edges, and faces that we obtain from
|
||||
* OpenCascade are not stable under modifications of the shape, FreeCAD
|
||||
* implements a system called "topological naming" to provide stable names for
|
||||
* these elements.
|
||||
*
|
||||
* A shape in FreeCAD is represented by Part::TopoShape, a subclass of
|
||||
* Data::ComplexGeoData that contains much of the logic for element mapping.
|
||||
* This logic mainly resides in package Data.
|
||||
*
|
||||
* A @ref Data::ComplexGeoData "ComplexGeoData" object contains a @ref
|
||||
* Data::ComplexGeoData::Tag "Tag" that uniquely identifies the shape in the
|
||||
* document. A @ref Data::ComplexGeoData "ComplexGeoData" object also contains
|
||||
* a @ref Data::ElementMap "ElementMap" that maintains a mapping from an @ref
|
||||
* Data::IndexedName "IndexedName" to a @ref Data::MappedName "MappedName".
|
||||
*
|
||||
* An indexed name, is a name that we obtain from the shapes from OpenCascade.
|
||||
* A mapped name is a name that is formed by means of topological relations. A
|
||||
* mapped name consists of an immutable base name (called the "data") while the
|
||||
* second part is appended on operations on the shape. This is called the
|
||||
* "postfix" of the mapped name. For a selection of used postfix tags, see
|
||||
* the @ref ElementNameConstants "Element name constants" section in Data.
|
||||
*
|
||||
* An example of a mapped name is
|
||||
* `Pocket.;g2;SKT;:H7cf,E;:G;XTR;:H7cf:7,F;:M;CUT;:H-7d0:7,F.Face8` which
|
||||
* roughly means that the selected face `Face8` was modified `M` with a `CUT`
|
||||
* operation. The `T` or `H` tags provide the tag of the shape in decimal and
|
||||
* hexadecimal respectively.
|
||||
*
|
||||
* Because multiple operations can result in long mapped names, FreeCAD makes
|
||||
* use of a string hasher that creates short hashes out of the long mapped
|
||||
* names. An example of the hashed name for the above mapped name is:
|
||||
* `Pocket.;#20:2;:M;CUT;:H-e61:7,F.Face8`.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @namespace App
|
||||
* @ingroup APP
|
||||
@@ -841,3 +888,10 @@
|
||||
* For a more high-level discussion see the topic @ref APP "App".
|
||||
*/
|
||||
|
||||
/**
|
||||
* @namespace Data
|
||||
* @ingroup ElementMapping
|
||||
* @brief The namespace for element names
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user