Part/Toponaming: Add TopoShapeCache base implementation
Copied from RealThunder's TopoNaming branch and modified only as much as required to enable compilation.
This commit is contained in:
committed by
Chris Hennes
parent
0c1f6138b4
commit
4077c55fae
@@ -530,6 +530,9 @@ SET(Part_SRCS
|
||||
ProgressIndicator.h
|
||||
TopoShape.cpp
|
||||
TopoShape.h
|
||||
TopoShapeCache.cpp
|
||||
TopoShapeCache.h
|
||||
TopoShapeExpansion.cpp
|
||||
TopoShapeOpCode.h
|
||||
edgecluster.cpp
|
||||
edgecluster.h
|
||||
|
||||
@@ -47,6 +47,8 @@ class Color;
|
||||
namespace Part
|
||||
{
|
||||
|
||||
class TopoShapeCache;
|
||||
|
||||
/* A special sub-class to indicate null shapes
|
||||
*/
|
||||
class PartExport NullShapeException : public Base::ValueError
|
||||
@@ -99,8 +101,10 @@ public:
|
||||
TopoShape(const TopoShape&);
|
||||
~TopoShape() override;
|
||||
|
||||
inline void setShape(const TopoDS_Shape& shape) {
|
||||
this->_Shape = shape;
|
||||
void setShape(const TopoDS_Shape& shape, bool resetElementMap=true);
|
||||
|
||||
inline void setShape(const TopoShape& shape) {
|
||||
*this = shape;
|
||||
}
|
||||
|
||||
inline const TopoDS_Shape& getShape() const {
|
||||
@@ -364,12 +368,29 @@ public:
|
||||
void move(const TopLoc_Location &loc) {
|
||||
_Shape.Move(loc);
|
||||
}
|
||||
/** Return a new shape that is moved to a new location
|
||||
*
|
||||
* @param loc: location
|
||||
*
|
||||
* @return Return a shallow copy of the shape moved to the new location
|
||||
* that is applied in addition to any current transformation of the
|
||||
* shape
|
||||
*/
|
||||
TopoShape moved(const TopLoc_Location &loc) const {
|
||||
TopoShape ret(*this);
|
||||
ret._Shape.Move(loc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static TopoDS_Shape &move(TopoDS_Shape &s, const TopLoc_Location &);
|
||||
static TopoDS_Shape moved(const TopoDS_Shape &s, const TopLoc_Location &);
|
||||
static TopoDS_Shape &move(TopoDS_Shape &s, const gp_Trsf &);
|
||||
static TopoDS_Shape moved(const TopoDS_Shape &s, const gp_Trsf &);
|
||||
static TopoDS_Shape &locate(TopoDS_Shape &s, const TopLoc_Location &loc);
|
||||
static TopoDS_Shape located(const TopoDS_Shape &s, const TopLoc_Location &);
|
||||
static TopoDS_Shape &locate(TopoDS_Shape &s, const gp_Trsf &);
|
||||
static TopoDS_Shape located(const TopoDS_Shape &s, const gp_Trsf &);
|
||||
|
||||
TopoShape &makeGTransform(const TopoShape &shape, const Base::Matrix4D &mat,
|
||||
const char *op=nullptr, bool copy=false);
|
||||
TopoShape makeGTransform(const Base::Matrix4D &mat, const char *op=nullptr, bool copy=false) const {
|
||||
@@ -388,6 +409,48 @@ public:
|
||||
static const std::string &shapeName(TopAbs_ShapeEnum type,bool silent=false);
|
||||
const std::string &shapeName(bool silent=false) const;
|
||||
static std::pair<TopAbs_ShapeEnum,int> shapeTypeAndIndex(const char *name);
|
||||
|
||||
|
||||
/** @name sub shape cached functions
|
||||
*
|
||||
* Mapped element names introduces some overhead when getting sub shapes
|
||||
* from a shape. These functions use internal caches for sub-shape maps to
|
||||
* improve performance.
|
||||
*/
|
||||
//@{
|
||||
void initCache(int reset=0, const char *file=nullptr, int line=0) const;
|
||||
int findShape(const TopoDS_Shape &subshape) const;
|
||||
TopoDS_Shape findShape(const char *name) const;
|
||||
TopoDS_Shape findShape(TopAbs_ShapeEnum type, int idx) const;
|
||||
int findAncestor(const TopoDS_Shape &subshape, TopAbs_ShapeEnum type) const;
|
||||
TopoDS_Shape findAncestorShape(const TopoDS_Shape &subshape, TopAbs_ShapeEnum type) const;
|
||||
std::vector<int> findAncestors(const TopoDS_Shape &subshape, TopAbs_ShapeEnum type) const;
|
||||
std::vector<TopoDS_Shape> findAncestorsShapes(const TopoDS_Shape &subshape, TopAbs_ShapeEnum type) const;
|
||||
/** Search sub shape
|
||||
*
|
||||
* unlike findShape(), the input shape does not have to be an actual
|
||||
* sub-shape of this shape. The sub-shape is searched by shape geometry
|
||||
*
|
||||
* @param subshape: a sub shape to search
|
||||
* @param names: optional output of found sub shape indexed based name
|
||||
* @param checkGeometry: whether to compare shape geometry
|
||||
* @param tol: tolerance to check coincident vertices
|
||||
* @param atol: tolerance to check for same angles
|
||||
*/
|
||||
std::vector<TopoShape> searchSubShape(const TopoShape &subshape,
|
||||
std::vector<std::string> *names=nullptr,
|
||||
bool checkGeometry=true,
|
||||
double tol=1e-7, double atol=1e-12) const;
|
||||
//@}
|
||||
|
||||
friend class TopoShapeCache;
|
||||
|
||||
private:
|
||||
// Cache storage
|
||||
mutable std::shared_ptr<TopoShapeCache> _parentCache;
|
||||
mutable std::shared_ptr<TopoShapeCache> _cache;
|
||||
mutable TopLoc_Location _subLocation;
|
||||
|
||||
private:
|
||||
TopoDS_Shape _Shape;
|
||||
};
|
||||
|
||||
25
src/Mod/Part/App/TopoShapeCache.cpp
Normal file
25
src/Mod/Part/App/TopoShapeCache.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "TopoShapeCache.h"
|
||||
292
src/Mod/Part/App/TopoShapeCache.h
Normal file
292
src/Mod/Part/App/TopoShapeCache.h
Normal file
@@ -0,0 +1,292 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef FREECAD_TOPOSHAPECACHE_H
|
||||
#define FREECAD_TOPOSHAPECACHE_H
|
||||
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
# include <TopoDS.hxx>
|
||||
# include <TopoDS_Compound.hxx>
|
||||
# include <TopoDS_Iterator.hxx>
|
||||
# include <TopoDS_Solid.hxx>
|
||||
# include <TopoDS_Vertex.hxx>
|
||||
# include <TopExp.hxx>
|
||||
# include <TopExp_Explorer.hxx>
|
||||
# include <TopTools_ListIteratorOfListOfShape.hxx>
|
||||
#endif
|
||||
|
||||
#include <App/ElementMap.h>
|
||||
|
||||
#include "TopoShape.h"
|
||||
|
||||
namespace Part
|
||||
{
|
||||
|
||||
struct ShapeRelationKey {
|
||||
Data::MappedName name;
|
||||
bool sameType;
|
||||
|
||||
ShapeRelationKey(const Data::MappedName & name, bool sameType)
|
||||
:name(name), sameType(sameType)
|
||||
{}
|
||||
|
||||
bool operator<(const ShapeRelationKey &other) const {
|
||||
if(sameType != other.sameType)
|
||||
return sameType;
|
||||
return name < other.name;
|
||||
}
|
||||
};
|
||||
|
||||
class TopoShapeCache: public std::enable_shared_from_this<TopoShapeCache>
|
||||
{
|
||||
public:
|
||||
Data::ElementMapPtr cachedElementMap;
|
||||
TopLoc_Location subLocation;
|
||||
TopoDS_Shape shape;
|
||||
TopLoc_Location loc;
|
||||
TopLoc_Location locInv;
|
||||
|
||||
std::size_t memsize = 0;
|
||||
|
||||
struct AncestorInfo
|
||||
{
|
||||
bool inited = false;
|
||||
TopTools_IndexedDataMapOfShapeListOfShape shapes;
|
||||
};
|
||||
class Info
|
||||
{
|
||||
private:
|
||||
TopoShapeCache* owner = 0;
|
||||
TopTools_IndexedMapOfShape shapes;
|
||||
std::vector<TopoShape> topoShapes;
|
||||
std::array<AncestorInfo, TopAbs_SHAPE + 1> ancestors;
|
||||
|
||||
TopoShape _getTopoShape(const TopoShape& parent, int index)
|
||||
{
|
||||
auto& s = topoShapes[index - 1];
|
||||
if (s.isNull()) {
|
||||
s.setShape(shapes.FindKey(index), true);
|
||||
s.initCache();
|
||||
s._cache->subLocation = s._Shape.Location();
|
||||
}
|
||||
|
||||
if (s._Shape.IsEqual(parent._cache->shape))
|
||||
return parent;
|
||||
|
||||
TopoShape res(s);
|
||||
res.Tag = parent.Tag;
|
||||
res.Hasher = parent.Hasher;
|
||||
|
||||
if (!parent.getShape().Location().IsIdentity())
|
||||
res.setShape(TopoShape::moved(res._Shape, parent.getShape().Location()), false);
|
||||
|
||||
if (s._cache->cachedElementMap)
|
||||
res.resetElementMap(s._cache->cachedElementMap);
|
||||
else if (parent._parentCache) {
|
||||
// If no cachedElementMap exists, we use _parentCache for
|
||||
// delayed generation of sub element map so that we don't need
|
||||
// to always generate a full map whenever we return a sub
|
||||
// shape. To simplify the mapping and avoid circular
|
||||
// dependency, we do not chain parent and grandparent.
|
||||
// Instead, we always use the cache from the top parent. And to
|
||||
// make it work, we must accumulate the TopLoc_Location along
|
||||
// the lineage, which is required for OCCT shape mapping to
|
||||
// work.
|
||||
//
|
||||
// Cache::subLocation is shared and only contains the location
|
||||
// in the direct parent shape, while TopoShape::_subLocation is
|
||||
// used to accumulate locations in higher ancestors. We
|
||||
// separate these two to avoid invalidating cache.
|
||||
|
||||
res._subLocation = parent._subLocation * parent._cache->subLocation;
|
||||
res._parentCache = parent._parentCache;
|
||||
}
|
||||
else
|
||||
res._parentCache = owner->shared_from_this();
|
||||
return res;
|
||||
}
|
||||
|
||||
public:
|
||||
void clear()
|
||||
{
|
||||
topoShapes.clear();
|
||||
}
|
||||
|
||||
TopoShape getTopoShape(const TopoShape& parent, int index)
|
||||
{
|
||||
TopoShape res;
|
||||
if (index <= 0 || index > shapes.Extent())
|
||||
return res;
|
||||
topoShapes.resize(shapes.Extent());
|
||||
return _getTopoShape(parent, index);
|
||||
}
|
||||
|
||||
std::vector<TopoShape> getTopoShapes(const TopoShape& parent)
|
||||
{
|
||||
int count = shapes.Extent();
|
||||
std::vector<TopoShape> res;
|
||||
res.reserve(count);
|
||||
topoShapes.resize(count);
|
||||
for (int i = 1; i <= count; ++i)
|
||||
res.push_back(_getTopoShape(parent, i));
|
||||
return res;
|
||||
}
|
||||
|
||||
TopoDS_Shape stripLocation(const TopoDS_Shape& parent, const TopoDS_Shape& child)
|
||||
{
|
||||
if (parent.Location() != owner->loc) {
|
||||
owner->loc = parent.Location();
|
||||
owner->locInv = parent.Location().Inverted();
|
||||
}
|
||||
return TopoShape::located(child, owner->locInv * child.Location());
|
||||
}
|
||||
|
||||
int find(const TopoDS_Shape& parent, const TopoDS_Shape& subshape)
|
||||
{
|
||||
if (parent.Location().IsIdentity())
|
||||
return shapes.FindIndex(subshape);
|
||||
return shapes.FindIndex(stripLocation(parent, subshape));
|
||||
}
|
||||
|
||||
TopoDS_Shape find(const TopoDS_Shape& parent, int index)
|
||||
{
|
||||
if (index <= 0 || index > shapes.Extent())
|
||||
return TopoDS_Shape();
|
||||
if (parent.Location().IsIdentity())
|
||||
return shapes.FindKey(index);
|
||||
else
|
||||
return TopoShape::moved(shapes.FindKey(index), parent.Location());
|
||||
}
|
||||
|
||||
int count() const
|
||||
{
|
||||
return shapes.Extent();
|
||||
}
|
||||
|
||||
friend TopoShapeCache;
|
||||
};
|
||||
|
||||
std::array<Info, TopAbs_SHAPE + 1> infos;
|
||||
std::map<ShapeRelationKey, QVector<Data::MappedElement>> relations;
|
||||
|
||||
TopoShapeCache(const TopoDS_Shape& s)
|
||||
: shape(s.Located(TopLoc_Location()))
|
||||
{}
|
||||
|
||||
void insertRelation(const ShapeRelationKey& key, const QVector<Data::MappedElement>& value)
|
||||
{
|
||||
auto res = relations.insert(std::make_pair(key, value));
|
||||
if (res.second)
|
||||
res.first->first.name.compact();
|
||||
else
|
||||
res.first->second = value;
|
||||
}
|
||||
|
||||
bool isTouched(const TopoDS_Shape& s)
|
||||
{
|
||||
return !this->shape.IsPartner(s) || this->shape.Orientation() != s.Orientation();
|
||||
}
|
||||
|
||||
Info& getInfo(TopAbs_ShapeEnum type)
|
||||
{
|
||||
auto& info = infos[type];
|
||||
if (!info.owner) {
|
||||
info.owner = this;
|
||||
if (!shape.IsNull()) {
|
||||
if (type == TopAbs_SHAPE) {
|
||||
for (TopoDS_Iterator it(shape); it.More(); it.Next())
|
||||
info.shapes.Add(it.Value());
|
||||
}
|
||||
else
|
||||
TopExp::MapShapes(shape, type, info.shapes);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
int countShape(TopAbs_ShapeEnum type)
|
||||
{
|
||||
if (shape.IsNull())
|
||||
return 0;
|
||||
return getInfo(type).count();
|
||||
}
|
||||
|
||||
int findShape(const TopoDS_Shape& parent, const TopoDS_Shape& subshape)
|
||||
{
|
||||
if (shape.IsNull() || subshape.IsNull())
|
||||
return 0;
|
||||
return getInfo(subshape.ShapeType()).find(parent, subshape);
|
||||
}
|
||||
|
||||
TopoDS_Shape findShape(const TopoDS_Shape& parent, TopAbs_ShapeEnum type, int index)
|
||||
{
|
||||
if (!shape.IsNull())
|
||||
return getInfo(type).find(parent, index);
|
||||
return TopoDS_Shape();
|
||||
}
|
||||
|
||||
TopoDS_Shape findAncestor(const TopoDS_Shape& parent,
|
||||
const TopoDS_Shape& subshape,
|
||||
TopAbs_ShapeEnum type,
|
||||
std::vector<TopoDS_Shape>* ancestors = 0)
|
||||
{
|
||||
TopoDS_Shape ret;
|
||||
if (shape.IsNull() || subshape.IsNull() || type == TopAbs_SHAPE)
|
||||
return ret;
|
||||
|
||||
auto& info = getInfo(type);
|
||||
|
||||
auto& ainfo = info.ancestors[subshape.ShapeType()];
|
||||
if (!ainfo.inited) {
|
||||
ainfo.inited = true;
|
||||
TopExp::MapShapesAndAncestors(shape, subshape.ShapeType(), type, ainfo.shapes);
|
||||
}
|
||||
int index;
|
||||
if (parent.Location().IsIdentity())
|
||||
index = ainfo.shapes.FindIndex(subshape);
|
||||
else
|
||||
index = ainfo.shapes.FindIndex(info.stripLocation(parent, subshape));
|
||||
if (!index)
|
||||
return ret;
|
||||
const auto& shapes = ainfo.shapes.FindFromIndex(index);
|
||||
if (!shapes.Extent())
|
||||
return ret;
|
||||
|
||||
if (ancestors) {
|
||||
ancestors->reserve(ancestors->size() + shapes.Extent());
|
||||
for (TopTools_ListIteratorOfListOfShape it(shapes); it.More(); it.Next())
|
||||
ancestors->push_back(TopoShape::moved(it.Value(), parent.Location()));
|
||||
}
|
||||
return TopoShape::moved(shapes.First(), parent.Location());
|
||||
}
|
||||
|
||||
std::size_t getMemSize();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FREECAD_TOPOSHAPECACHE_H
|
||||
43
src/Mod/Part/App/TopoShapeExpansion.cpp
Normal file
43
src/Mod/Part/App/TopoShapeExpansion.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
/****************************************************************************
|
||||
* *
|
||||
* 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/>. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "TopoShape.h"
|
||||
#include "TopoShapeCache.h"
|
||||
|
||||
namespace Part
|
||||
{
|
||||
|
||||
void TopoShape::setShape(const TopoDS_Shape& shape, bool resetElementMap)
|
||||
{
|
||||
if (resetElementMap)
|
||||
this->resetElementMap();
|
||||
else if (_cache && _cache->isTouched(shape))
|
||||
this->flushElementMap();
|
||||
//_Shape._Shape = shape; // TODO: Replace the next line with this once ShapeProtector is available.
|
||||
_Shape = shape;
|
||||
if (_cache)
|
||||
initCache();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user