App/Toponaming: ComplexGeoData realthunder original

Minor modifications to make it compile with previous refactorings.
The only substantial change to the original is moving the
getElementHistory function from ComplexGeoData to MappedName so
that the dehash function can remain private.
This commit is contained in:
Chris Hennes
2023-06-15 10:55:38 -05:00
committed by Chris Hennes
parent e9b87b54fc
commit 9ea7b6424b
6 changed files with 491 additions and 43 deletions

View File

@@ -1,23 +1,26 @@
/***************************************************************************
* Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* *
* Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
* Copyright (c) 2022 Zheng, Lei <realthunder.dev@gmail.com> *
* Copyright (c) 2023 FreeCAD Project Association *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
@@ -30,11 +33,16 @@
#include <boost/regex.hpp>
#include "ComplexGeoData.h"
#include "ElementMap.h"
#include "ElementNamingUtils.h"
#include <Base/BoundBox.h>
#include <Base/Placement.h>
#include <Base/Rotation.h>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>
using namespace Data;
@@ -43,6 +51,11 @@ TYPESYSTEM_SOURCE_ABSTRACT(Data::Segment , Base::BaseClass)
TYPESYSTEM_SOURCE_ABSTRACT(Data::ComplexGeoData , Base::Persistence)
FC_LOG_LEVEL_INIT("ComplexGeoData", true,true)
namespace bio = boost::iostreams;
using namespace Data;
ComplexGeoData::ComplexGeoData()
:Tag(0)
@@ -166,3 +179,203 @@ bool ComplexGeoData::getCenterOfGravity(Base::Vector3d&) const
return false;
}
size_t ComplexGeoData::getElementMapSize(bool flush) const {
if (flush) {
flushElementMap();
#ifdef _FC_MEM_TRACE
FC_MSG("memory size " << (_MemSize/1024/1024) << "MB, " << (_MemMaxSize/1024/1024));
for (auto &unit : _MemUnits)
FC_MSG("unit " << unit.first << ": " << unit.second.count << ", " << unit.second.maxcount);
#endif
}
return _elementMap ? _elementMap->size():0;
}
MappedName ComplexGeoData::getMappedName(const IndexedName & element,
bool allowUnmapped,
ElementIDRefs *sid) const
{
if (!element)
return MappedName();
flushElementMap();
if(!_elementMap) {
if (allowUnmapped)
return MappedName(element);
return MappedName();
}
MappedName name = _elementMap->find(element, sid);
if (allowUnmapped && !name)
return MappedName(element);
return name;
}
IndexedName ComplexGeoData::getIndexedName(const MappedName & name,
ElementIDRefs *sid) const
{
flushElementMap();
if (!name)
return IndexedName();
if (!_elementMap) {
std::string s;
return IndexedName(name.appendToBuffer(s), getElementTypes());
}
return _elementMap->find(name, sid);
}
Data::MappedElement
ComplexGeoData::getElementName(const char *name,
ElementIDRefs *sid,
bool copy) const
{
IndexedName element(name, getElementTypes());
if (element)
return MappedElement(getMappedName(element, false, sid), element);
const char * mapped = isMappedElement(name);
if (mapped)
name = mapped;
MappedElement res;
// Strip out the trailing '.XXXX' if any
const char *dot = strchr(name,'.');
if(dot)
res.name = MappedName(name, dot-name);
else if (copy)
res.name = name;
else
res.name = MappedName(name);
res.index = getIndexedName(res.name, sid);
return res;
}
std::vector<std::pair<MappedName, ElementIDRefs> >
ComplexGeoData::getElementMappedNames(const IndexedName & element, bool needUnmapped) const {
flushElementMap();
if(_elementMap) {
auto res = _elementMap->findAll(element);
if (!res.empty())
return res;
}
if (!needUnmapped)
return {};
return {std::make_pair(MappedName(element), ElementIDRefs())};
}
std::vector<Data::MappedElement>
ComplexGeoData::getElementNamesWithPrefix(const char *prefix) const {
#if 0
std::vector<Data::MappedElement> names;
flushElementMap();
if(!prefix || !prefix[0] || !_elementMap)
return names;
const auto &p = elementMapPrefix();
if(boost::starts_with(prefix,p))
prefix += p.size();
names = _elementMap->findAllStartsWith(prefix);
return names;
#else
(void)prefix;
return {};
#endif
}
std::vector<MappedElement> ComplexGeoData::getElementMap() const {
flushElementMap();
if(!_elementMap)
return {};
return _elementMap->getAll();
}
ElementMapPtr ComplexGeoData::elementMap(bool flush) const
{
if (flush)
flushElementMap();
return _elementMap;
}
void ComplexGeoData::flushElementMap() const
{
}
void ComplexGeoData::setElementMap(const std::vector<MappedElement> &map) {
resetElementMap();
for(auto &v : map)
_elementMap->setElementName(v.index, v.name, Tag);
}
char ComplexGeoData::elementType(const Data::MappedName &name) const
{
if(!name)
return 0;
auto indexedName = getIndexedName(name);
if (indexedName)
return elementType(indexedName);
char element_type=0;
if (name.findTagInElementName(0,0,0,&element_type) < 0)
return elementType(name.toIndexedName());
return element_type;
}
char ComplexGeoData::elementType(const Data::IndexedName &element) const
{
if(!element)
return 0;
for(auto &type : getElementTypes()) {
if(boost::equals(element.getType(), type))
return type[0];
}
return 0;
}
char ComplexGeoData::elementType(const char *name) const {
if(!name)
return 0;
const char *type = nullptr;
IndexedName element(name, getElementTypes());
if (element)
type = element.getType();
else {
const char * mapped = isMappedElement(name);
if (mapped)
name = mapped;
MappedName n;
const char *dot = strchr(name,'.');
if(dot) {
n = MappedName(name, dot-name);
type = dot+1;
}
else
n = MappedName::fromRawData(name);
char res = elementType(n);
if (res)
return res;
}
if(type && type[0]) {
for(auto &t : getElementTypes()) {
if(boost::starts_with(type, t))
return type[0];
}
}
return 0;
}
MappedName ComplexGeoData::renameDuplicateElement(int index,
const IndexedName & element,
const IndexedName & element2,
const MappedName & name,
ElementIDRefs &sids)
{
std::ostringstream ss;
ss << ELEMENT_MAP_PREFIX << 'D' << std::hex << index;
MappedName renamed(name);
this->elementMap()->encodeElementName(element.getType()[0],renamed,ss,&sids,Tag);
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG))
FC_WARN("duplicate element mapping '" << name << " -> " << renamed << ' '
<< element << '/' << element2);
return renamed;
}

View File

@@ -1,23 +1,26 @@
/***************************************************************************
* Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
// SPDX-License-Identifier: LGPL-2.1-or-later
/****************************************************************************
* *
* Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
* Copyright (c) 2022 Zheng, Lei <realthunder.dev@gmail.com> *
* Copyright (c) 2023 FreeCAD Project Association *
* *
* This file is part of FreeCAD. *
* *
* FreeCAD is free software: you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 2.1 of the *
* License, or (at your option) any later version. *
* *
* FreeCAD is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with FreeCAD. If not, see *
* <https://www.gnu.org/licenses/>. *
* *
***************************************************************************/
@@ -28,6 +31,10 @@
#include <Base/Handle.h>
#include <Base/Matrix.h>
#include <Base/Persistence.h>
#include "MappedName.h"
#include "MappedElement.h"
#include "ElementMap.h"
#include "StringHasher.h"
#ifdef __GNUC__
# include <cstdint>
@@ -45,6 +52,8 @@ using BoundBox3d = BoundBox3<double>;
namespace Data
{
struct MappedChildElements;
/** Segments
* Subelement type of the ComplexGeoData type
* It is used to split an object in further sub-parts.
@@ -164,6 +173,135 @@ public:
virtual bool getCenterOfGravity(Base::Vector3d& center) const;
//@}
/** @name Element name mapping */
//@{
/** Get element indexed name
*
* @param name: the input name
* @param 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
*
* @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.
*/
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 and App::StringID involved 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.
*
* 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
* name contains only alphabets and underscore followed by optional digits,
* it will be treated as indexed name. Or else, it will be treated as
* mapped name.
*/
MappedElement getElementName(const char * name,
ElementIDRefs *sid = nullptr,
bool copy = false) const;
/** Get mapped element with a given prefix */
std::vector<MappedElement> getElementNamesWithPrefix(const char *prefix) const;
/** 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
*
* @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;
/// Append the Tag (if and only if it is non zero) into the element map
virtual void reTagElementMap(long tag, App::StringHasherRef hasher, const char *postfix=0) {
(void)tag;
(void)hasher;
(void)postfix;
}
// NOTE: getElementHistory is now in ElementMap
char elementType(const Data::MappedName &) const;
char elementType(const Data::IndexedName &) const;
char elementType(const char *name) const;
/** Reset/swap the element map
*
* @param elementMap: optional new element map
*
* @return Returns the existing element map.
*/
virtual ElementMapPtr resetElementMap(ElementMapPtr elementMap=ElementMapPtr()) {
_elementMap.swap(elementMap);
return elementMap;
}
/// Get the entire element map
std::vector<MappedElement> getElementMap() const;
/// Set the entire element map
void setElementMap(const std::vector<MappedElement> &elements);
/// Get the current element map size
size_t getElementMapSize(bool flush=true) const;
/// Check if the given subname only contains an element name
static bool isElementName(const char *subname) {
return subname && *subname && findElementName(subname)==subname;
}
/** 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.
*
* @sa traceElement()
*/
using TraceCallback = std::function<bool(const MappedName &, int, long, long)>;
/** Iterate through the history of the give element name with a given callback
*
* @param name: the input element name
* @param cb: trace callback with call signature.
* @sa TraceCallback
*/
void traceElement(const MappedName &name, TraceCallback cb) const;
/** Flush an internal buffering for element mapping */
virtual void flushElementMap() const;
virtual unsigned long getElementMapReserve() const { return 0; }
//@}
protected:
/// from local to outside
@@ -223,6 +361,42 @@ protected:
}
public:
mutable long Tag;
public:
/// String hasher for element name shortening
mutable App::StringHasherRef Hasher;
protected:
virtual MappedName renameDuplicateElement(int index,
const IndexedName & element,
const IndexedName & element2,
const MappedName & name,
ElementIDRefs &sids);
/// from local to outside
inline Base::Vector3d transformToOutside(const Base::Vector3f& vec) const
{
return getTransform() * Base::Vector3d(static_cast<double>(vec.x),
static_cast<double>(vec.y),
static_cast<double>(vec.z));
}
/// 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:
ElementMapPtr elementMap(bool flush=true) const;
private:
ElementMapPtr _elementMap;
};
} //namespace App

View File

@@ -1155,5 +1155,58 @@ std::vector<MappedElement> ElementMap::getAll() const
return ret;
}
long ElementMap::getElementHistory(const MappedName & name,
long masterTag,
MappedName *original,
std::vector<MappedName> *history) const
{
long tag = 0;
int len = 0;
int pos = name.findTagInElementName(&tag,&len,nullptr,nullptr,true);
if(pos < 0) {
if(original)
*original = name;
return tag;
}
if(!original && !history)
return tag;
MappedName tmp;
MappedName &ret = original?*original:tmp;
if(name.startsWith(ELEMENT_MAP_PREFIX)) {
unsigned offset = ELEMENT_MAP_PREFIX_SIZE;
ret = MappedName::fromRawData(name, offset);
} else
ret = name;
while(1) {
if(!len || len>pos) {
FC_WARN("invalid name length " << name);
return 0;
}
bool dehashed = false;
if (ret.startsWith(MAPPED_CHILD_ELEMENTS_PREFIX, len)) {
int offset = (int)POSTFIX_TAG_SIZE;
MappedName tmp = MappedName::fromRawData(ret, len+offset, pos-len-offset);
MappedName postfix = dehashElementName(tmp);
if (postfix != tmp) {
dehashed = true;
ret = MappedName::fromRawData(ret, 0, len) + postfix;
}
}
if (!dehashed)
ret = dehashElementName(MappedName::fromRawData(ret, 0, len));
long tag2 = 0;
pos = ret.findTagInElementName(&tag2,&len,nullptr,nullptr,true);
if(pos < 0 || (tag2!=tag && tag2!=-tag && tag!=masterTag && -tag!=masterTag))
return tag;
tag = tag2;
if(history)
history->push_back(ret.copy());
}
}
}// Namespace Data

View File

@@ -170,7 +170,7 @@ public:
QByteArray postfix;
ElementIDRefs sids;
// prefix() has been moved to PostfixStringReferences.h
// prefix() has been moved to ElementNamingUtils.h
};
/* Note: the original addChildElements passed `ComplexGeoData& master` for getting the `Tag`,
@@ -181,6 +181,10 @@ public:
std::vector<MappedElement> getAll() const;
long getElementHistory(const MappedName & name,
long masterTag,
MappedName *original=0, std::vector<MappedName> *history=0) const;
private:
/** Serialize this map
* @param s: serialized stream

View File

@@ -23,7 +23,6 @@
#ifndef APP_MAPPED_ELEMENT_H
#define APP_MAPPED_ELEMENT_H
#include "ComplexGeoData.h"
#include "IndexedName.h"
#include "MappedName.h"

View File

@@ -35,7 +35,6 @@
#include <QHash>
#include <QVector>
#include "ComplexGeoData.h"
#include "IndexedName.h"
#include "StringHasher.h"
#include "ElementNamingUtils.h"
@@ -102,6 +101,12 @@ public:
}
}
explicit MappedName(const App::StringIDRef & sid)
:raw(false)
{
sid.toBytes(this->data);
}
MappedName()
: raw(false)
{}