Merge pull request #12157 from chennes/toponamingMakeShapeWithElementMap
Toponaming make shape with element map
This commit is contained in:
@@ -638,7 +638,6 @@ public:
|
||||
void mapSubElement(const std::vector<TopoShape> &shapes, const char *op=nullptr);
|
||||
bool hasPendingElementMap() const;
|
||||
|
||||
|
||||
/** Helper class to return the generated and modified shape given an input shape
|
||||
*
|
||||
* Shape history information is extracted using OCCT APIs
|
||||
@@ -660,6 +659,24 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/** Core function to generate mapped element names from shape history
|
||||
*
|
||||
* @param shape: the new shape
|
||||
* @param mapper: for mapping input shapes to generated/modified shapes
|
||||
* @param sources: list of source shapes.
|
||||
* @param op: optional string to be encoded into topo naming for indicating
|
||||
* the operation
|
||||
*
|
||||
* @return The original content of this TopoShape is discarded and replaced
|
||||
* with the given new shape. The function returns the TopoShape
|
||||
* itself as a self reference so that multiple operations can be
|
||||
* carried out for the same shape in the same line of code.
|
||||
*/
|
||||
TopoShape &makeShapeWithElementMap(const TopoDS_Shape &shape,
|
||||
const Mapper &mapper,
|
||||
const std::vector<TopoShape> &sources,
|
||||
const char *op=nullptr);
|
||||
|
||||
/** Make a compound shape
|
||||
*
|
||||
* @param shapes: input shapes
|
||||
|
||||
@@ -25,23 +25,28 @@
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <BRep_Builder.hxx>
|
||||
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <BRep_Tool.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
#include <ShapeFix_ShapeTolerance.hxx>
|
||||
|
||||
#endif
|
||||
|
||||
#include <BRepCheck_Analyzer.hxx>
|
||||
#include <BRepFill_Generator.hxx>
|
||||
#include <BRepTools.hxx>
|
||||
#include <BRep_Builder.hxx>
|
||||
#include <Precision.hxx>
|
||||
#include <ShapeFix_Shape.hxx>
|
||||
#include <ShapeFix_ShapeTolerance.hxx>
|
||||
#include <ShapeUpgrade_ShellSewing.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
|
||||
#include <utility>
|
||||
#endif
|
||||
|
||||
#include "TopoShape.h"
|
||||
#include "TopoShapeCache.h"
|
||||
#include "TopoShapeOpCode.h"
|
||||
#include "FaceMaker.h"
|
||||
|
||||
#include <App/ElementNamingUtils.h>
|
||||
|
||||
|
||||
FC_LOG_LEVEL_INIT("TopoShape", true, true) // NOLINT
|
||||
|
||||
@@ -338,6 +343,8 @@ void checkAndMatchHasher(TopoShape& topoShape1, const TopoShape& topoShape2)
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
// TODO: Refactor mapSubElementTypeForShape to reduce complexity
|
||||
void TopoShape::mapSubElementTypeForShape(const TopoShape& other,
|
||||
TopAbs_ShapeEnum type,
|
||||
const char* op,
|
||||
@@ -387,8 +394,8 @@ void TopoShape::mapSubElementTypeForShape(const TopoShape& other,
|
||||
}
|
||||
std::ostringstream ss;
|
||||
char elementType {shapeName(type)[0]};
|
||||
if ( ! elementMap() ) {
|
||||
FC_THROWM(NullShapeException, "No element map");
|
||||
if (!elementMap()) {
|
||||
FC_THROWM(NullShapeException, "No element map"); // NOLINT
|
||||
}
|
||||
elementMap()->encodeElementName(elementType, name, ss, &sids, Tag, op, other.Tag);
|
||||
elementMap()->setElementName(element, name, Tag, &sids);
|
||||
@@ -509,6 +516,743 @@ void TopoShape::mapSubElement(const std::vector<TopoShape>& shapes, const char*
|
||||
}
|
||||
}
|
||||
|
||||
struct ShapeInfo
|
||||
{
|
||||
const TopoDS_Shape& shape;
|
||||
TopoShapeCache::Ancestry& cache;
|
||||
TopAbs_ShapeEnum type;
|
||||
const char* shapetype;
|
||||
|
||||
ShapeInfo(const TopoDS_Shape& shape, TopAbs_ShapeEnum type, TopoShapeCache::Ancestry& cache)
|
||||
: shape(shape)
|
||||
, cache(cache)
|
||||
, type(type)
|
||||
, shapetype(TopoShape::shapeName(type).c_str())
|
||||
{}
|
||||
|
||||
int count() const
|
||||
{
|
||||
return cache.count();
|
||||
}
|
||||
|
||||
TopoDS_Shape find(int index)
|
||||
{
|
||||
return cache.find(shape, index);
|
||||
}
|
||||
|
||||
int find(const TopoDS_Shape& subshape)
|
||||
{
|
||||
return cache.find(shape, subshape);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
// makESHAPE -> makeShapeWithElementMap
|
||||
///////////////////////////////////////
|
||||
|
||||
struct NameKey
|
||||
{
|
||||
Data::MappedName name;
|
||||
long tag = 0;
|
||||
int shapetype = 0;
|
||||
|
||||
NameKey()
|
||||
= default;
|
||||
explicit NameKey(Data::MappedName n)
|
||||
: name(std::move(n))
|
||||
{}
|
||||
NameKey(int type, Data::MappedName n)
|
||||
: name(std::move(n))
|
||||
{
|
||||
// Order the shape type from vertex < edge < face < other. We'll rely
|
||||
// on this for sorting when we name the geometry element.
|
||||
switch (type) {
|
||||
case TopAbs_VERTEX:
|
||||
shapetype = 0;
|
||||
break;
|
||||
case TopAbs_EDGE:
|
||||
shapetype = 1;
|
||||
break;
|
||||
case TopAbs_FACE:
|
||||
shapetype = 2;
|
||||
break;
|
||||
default:
|
||||
shapetype = 3;
|
||||
}
|
||||
}
|
||||
bool operator<(const NameKey& other) const
|
||||
{
|
||||
if (shapetype < other.shapetype) {
|
||||
return true;
|
||||
}
|
||||
if (shapetype > other.shapetype) {
|
||||
return false;
|
||||
}
|
||||
if (tag < other.tag) {
|
||||
return true;
|
||||
}
|
||||
if (tag > other.tag) {
|
||||
return false;
|
||||
}
|
||||
return name < other.name;
|
||||
}
|
||||
};
|
||||
|
||||
struct NameInfo
|
||||
{
|
||||
int index {};
|
||||
Data::ElementIDRefs sids;
|
||||
const char* shapetype {};
|
||||
};
|
||||
|
||||
|
||||
const std::string& modPostfix()
|
||||
{
|
||||
static std::string postfix(Data::POSTFIX_MOD);
|
||||
return postfix;
|
||||
}
|
||||
|
||||
const std::string& modgenPostfix()
|
||||
{
|
||||
static std::string postfix(Data::POSTFIX_MODGEN);
|
||||
return postfix;
|
||||
}
|
||||
|
||||
const std::string& genPostfix()
|
||||
{
|
||||
static std::string postfix(Data::POSTFIX_GEN);
|
||||
return postfix;
|
||||
}
|
||||
|
||||
const std::string& upperPostfix()
|
||||
{
|
||||
static std::string postfix(Data::POSTFIX_UPPER);
|
||||
return postfix;
|
||||
}
|
||||
|
||||
const std::string& lowerPostfix()
|
||||
{
|
||||
static std::string postfix(Data::POSTFIX_LOWER);
|
||||
return postfix;
|
||||
}
|
||||
|
||||
// TODO: Refactor checkForParallelOrCoplanar to reduce complexity
|
||||
void checkForParallelOrCoplanar(const TopoDS_Shape& newShape,
|
||||
const ShapeInfo& newInfo,
|
||||
std::vector<TopoDS_Shape>& newShapes,
|
||||
const gp_Pln& pln,
|
||||
int parallelFace,
|
||||
int& coplanarFace,
|
||||
int& checkParallel)
|
||||
{
|
||||
for (TopExp_Explorer xp(newShape, newInfo.type); xp.More(); xp.Next()) {
|
||||
newShapes.push_back(xp.Current());
|
||||
|
||||
if ((parallelFace < 0 || coplanarFace < 0) && checkParallel > 0) {
|
||||
// Specialized checking for high level mapped
|
||||
// face that are either coplanar or parallel
|
||||
// with the source face, which are common in
|
||||
// operations like extrusion. Once found, the
|
||||
// first coplanar face will assign an index of
|
||||
// INT_MIN+1, and the first parallel face
|
||||
// INT_MIN. The purpose of these special
|
||||
// indexing is to make the name more stable for
|
||||
// those generated faces.
|
||||
//
|
||||
// For example, the top or bottom face of an
|
||||
// extrusion will be named using the extruding
|
||||
// face. With a fixed index, the name is no
|
||||
// longer affected by adding/removing of holes
|
||||
// inside the extruding face/sketch.
|
||||
gp_Pln plnOther;
|
||||
if (TopoShape(newShapes.back()).findPlane(plnOther)) {
|
||||
if (pln.Axis().IsParallel(plnOther.Axis(), Precision::Angular())) {
|
||||
if (coplanarFace < 0) {
|
||||
gp_Vec vec(pln.Axis().Location(), plnOther.Axis().Location());
|
||||
Standard_Real D1 = gp_Vec(pln.Axis().Direction()).Dot(vec);
|
||||
if (D1 < 0) {
|
||||
D1 = -D1;
|
||||
}
|
||||
Standard_Real D2 = gp_Vec(plnOther.Axis().Direction()).Dot(vec);
|
||||
if (D2 < 0) {
|
||||
D2 = -D2;
|
||||
}
|
||||
if (D1 <= Precision::Confusion() && D2 <= Precision::Confusion()) {
|
||||
coplanarFace = (int)newShapes.size();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (parallelFace < 0) {
|
||||
parallelFace = (int)newShapes.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Refactor makeShapeWithElementMap to reduce complexity
|
||||
TopoShape& TopoShape::makeShapeWithElementMap(const TopoDS_Shape& shape,
|
||||
const Mapper& mapper,
|
||||
const std::vector<TopoShape>& shapes,
|
||||
const char* op)
|
||||
{
|
||||
setShape(shape);
|
||||
if (shape.IsNull()) {
|
||||
FC_THROWM(NullShapeException, "Null shape");
|
||||
}
|
||||
|
||||
if (shapes.empty()) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
size_t canMap = 0;
|
||||
for (auto& incomingShape : shapes) {
|
||||
if (canMapElement(incomingShape)) {
|
||||
++canMap;
|
||||
}
|
||||
}
|
||||
if (canMap == 0U) {
|
||||
return *this;
|
||||
}
|
||||
if (canMap != shapes.size() && FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("Not all input shapes are mappable"); // NOLINT
|
||||
}
|
||||
|
||||
if (!op) {
|
||||
op = Part::OpCodes::Maker;
|
||||
}
|
||||
std::string _op = op;
|
||||
_op += '_';
|
||||
|
||||
initCache();
|
||||
ShapeInfo vertexInfo(_Shape, TopAbs_VERTEX, _cache->getAncestry(TopAbs_VERTEX));
|
||||
ShapeInfo edgeInfo(_Shape, TopAbs_EDGE, _cache->getAncestry(TopAbs_EDGE));
|
||||
ShapeInfo faceInfo(_Shape, TopAbs_FACE, _cache->getAncestry(TopAbs_FACE));
|
||||
mapSubElement(shapes, op);
|
||||
|
||||
std::array<ShapeInfo*, 3> infos = {&vertexInfo, &edgeInfo, &faceInfo};
|
||||
|
||||
std::array<ShapeInfo*, TopAbs_SHAPE> infoMap {};
|
||||
infoMap[TopAbs_VERTEX] = &vertexInfo;
|
||||
infoMap[TopAbs_EDGE] = &edgeInfo;
|
||||
infoMap[TopAbs_WIRE] = &edgeInfo;
|
||||
infoMap[TopAbs_FACE] = &faceInfo;
|
||||
infoMap[TopAbs_SHELL] = &faceInfo;
|
||||
infoMap[TopAbs_SOLID] = &faceInfo;
|
||||
infoMap[TopAbs_COMPOUND] = &faceInfo;
|
||||
infoMap[TopAbs_COMPSOLID] = &faceInfo;
|
||||
|
||||
std::ostringstream ss;
|
||||
std::string postfix;
|
||||
Data::MappedName newName;
|
||||
|
||||
std::map<Data::IndexedName, std::map<NameKey, NameInfo>> newNames;
|
||||
|
||||
// First, collect names from other shapes that generates or modifies the
|
||||
// new shape
|
||||
for (auto& pinfo : infos) {
|
||||
auto& info = *pinfo;
|
||||
for (const auto & incomingShape : shapes) {
|
||||
if (!canMapElement(incomingShape)) {
|
||||
continue;
|
||||
}
|
||||
auto& otherMap = incomingShape._cache->getAncestry(info.type);
|
||||
if (otherMap.count() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 1; i <= otherMap.count(); i++) {
|
||||
const auto& otherElement = otherMap.find(incomingShape._Shape, i);
|
||||
// Find all new objects that are a modification of the old object
|
||||
Data::ElementIDRefs sids;
|
||||
NameKey key(info.type,
|
||||
incomingShape.getMappedName(Data::IndexedName::fromConst(info.shapetype, i),
|
||||
true,
|
||||
&sids));
|
||||
|
||||
int newShapeCounter = 0;
|
||||
for (auto& newShape : mapper.modified(otherElement)) {
|
||||
++newShapeCounter;
|
||||
if (newShape.ShapeType() >= TopAbs_SHAPE) {
|
||||
// NOLINTNEXTLINE
|
||||
FC_ERR("unknown modified shape type " << newShape.ShapeType() << " from "
|
||||
<< info.shapetype << i);
|
||||
continue;
|
||||
}
|
||||
auto& newInfo = *infoMap.at(newShape.ShapeType());
|
||||
if (newInfo.type != newShape.ShapeType()) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
// TODO: it seems modified shape may report higher
|
||||
// level shape type just like generated shape below.
|
||||
// Maybe we shall do the same for name construction.
|
||||
// NOLINTNEXTLINE
|
||||
FC_WARN("modified shape type " << shapeName(newShape.ShapeType())
|
||||
<< " mismatch with " << info.shapetype
|
||||
<< i);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
int newShapeIndex = newInfo.find(newShape);
|
||||
if (newShapeIndex == 0) {
|
||||
// This warning occurs in makERevolve. It generates
|
||||
// some shape from a vertex that never made into the
|
||||
// final shape. There may be incomingShape cases there.
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
// NOLINTNEXTLINE
|
||||
FC_WARN("Cannot find " << op << " modified " << newInfo.shapetype
|
||||
<< " from " << info.shapetype << i);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Data::IndexedName element = Data::IndexedName::fromConst(newInfo.shapetype, newShapeIndex);
|
||||
if (getMappedName(element)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
key.tag = incomingShape.Tag;
|
||||
auto& name_info = newNames[element][key];
|
||||
name_info.sids = sids;
|
||||
name_info.index = newShapeCounter;
|
||||
name_info.shapetype = info.shapetype;
|
||||
}
|
||||
|
||||
int checkParallel = -1;
|
||||
gp_Pln pln;
|
||||
|
||||
// Find all new objects that were generated from an old object
|
||||
// (e.g. a face generated from an edge)
|
||||
newShapeCounter = 0;
|
||||
for (auto& newShape : mapper.generated(otherElement)) {
|
||||
if (newShape.ShapeType() >= TopAbs_SHAPE) {
|
||||
// NOLINTNEXTLINE
|
||||
FC_ERR("unknown generated shape type " << newShape.ShapeType() << " from "
|
||||
<< info.shapetype << i);
|
||||
continue;
|
||||
}
|
||||
|
||||
int parallelFace = -1;
|
||||
int coplanarFace = -1;
|
||||
auto& newInfo = *infoMap.at(newShape.ShapeType());
|
||||
std::vector<TopoDS_Shape> newShapes;
|
||||
int shapeOffset = 0;
|
||||
if (newInfo.type == newShape.ShapeType()) {
|
||||
newShapes.push_back(newShape);
|
||||
}
|
||||
else {
|
||||
// It is possible for the maker to report generating a
|
||||
// higher level shape, such as shell or solid. For
|
||||
// example, when extruding, OCC will report the
|
||||
// extruding face generating the entire solid. However,
|
||||
// it will also report the edges of the extruding face
|
||||
// generating the side faces. In this case, too much
|
||||
// information is bad for us. We don't want the name of
|
||||
// the side face (and its edges) to be coupled with
|
||||
// incomingShape (unrelated) edges in the extruding face.
|
||||
//
|
||||
// shapeOffset below is used to make sure the higher
|
||||
// level mapped names comes late after sorting. We'll
|
||||
// ignore those names if there are more precise mapping
|
||||
// available.
|
||||
shapeOffset = 3;
|
||||
|
||||
if (info.type == TopAbs_FACE && checkParallel < 0) {
|
||||
if (!TopoShape(otherElement).findPlane(pln)) {
|
||||
checkParallel = 0;
|
||||
}
|
||||
else {
|
||||
checkParallel = 1;
|
||||
}
|
||||
}
|
||||
checkForParallelOrCoplanar(newShape,
|
||||
newInfo,
|
||||
newShapes,
|
||||
pln,
|
||||
parallelFace,
|
||||
coplanarFace,
|
||||
checkParallel);
|
||||
}
|
||||
key.shapetype += shapeOffset;
|
||||
for (auto& workingShape : newShapes) {
|
||||
++newShapeCounter;
|
||||
int workingShapeIndex = newInfo.find(workingShape);
|
||||
if (workingShapeIndex == 0) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
// NOLINTNEXTLINE
|
||||
FC_WARN("Cannot find " << op << " generated " << newInfo.shapetype
|
||||
<< " from " << info.shapetype << i);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Data::IndexedName element =
|
||||
Data::IndexedName::fromConst(newInfo.shapetype, workingShapeIndex);
|
||||
auto mapped = getMappedName(element);
|
||||
if (mapped) {
|
||||
continue;
|
||||
}
|
||||
|
||||
key.tag = incomingShape.Tag;
|
||||
auto& name_info = newNames[element][key];
|
||||
name_info.sids = sids;
|
||||
if (newShapeCounter == parallelFace) {
|
||||
name_info.index = std::numeric_limits<int>::min();
|
||||
}
|
||||
else if (newShapeCounter == coplanarFace) {
|
||||
name_info.index = std::numeric_limits<int>::min() + 1;
|
||||
}
|
||||
else {
|
||||
name_info.index = -newShapeCounter;
|
||||
}
|
||||
name_info.shapetype = info.shapetype;
|
||||
}
|
||||
key.shapetype -= shapeOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We shall first exclude those names generated from high level mapping. If
|
||||
// there are still any unnamed elements left after we go through the process
|
||||
// below, we set delayed=true, and start using those excluded names.
|
||||
bool delayed = false;
|
||||
|
||||
while (true) {
|
||||
|
||||
// Construct the names for modification/generation info collected in
|
||||
// the previous step
|
||||
for (auto itName = newNames.begin(), itNext = itName; itNext != newNames.end();
|
||||
itName = itNext) {
|
||||
// We treat the first modified/generated source shape name specially.
|
||||
// If case there are more than one source shape. We hash the first
|
||||
// source name separately, and then obtain the second string id by
|
||||
// hashing all the source names together. We then use the second
|
||||
// string id as the postfix for our name.
|
||||
//
|
||||
// In this way, we can associate the same source that are modified by
|
||||
// multiple other shapes.
|
||||
|
||||
++itNext;
|
||||
|
||||
auto& element = itName->first;
|
||||
auto& names = itName->second;
|
||||
const auto& first_key = names.begin()->first;
|
||||
auto& first_info = names.begin()->second;
|
||||
|
||||
if (!delayed && first_key.shapetype >= 3 && first_info.index > INT_MIN + 1) {
|
||||
// This name is mapped from high level (shell, solid, etc.)
|
||||
// Delay till next round.
|
||||
//
|
||||
// index>INT_MAX+1 is for checking generated coplanar and
|
||||
// parallel face mapping, which has special fixed index to make
|
||||
// name stable. These names are not delayed.
|
||||
continue;
|
||||
}
|
||||
if (!delayed && getMappedName(element)) {
|
||||
newNames.erase(itName);
|
||||
continue;
|
||||
}
|
||||
|
||||
int name_type =
|
||||
first_info.index > 0 ? 1 : 2; // index>0 means modified, or else generated
|
||||
Data::MappedName first_name = first_key.name;
|
||||
|
||||
Data::ElementIDRefs sids(first_info.sids);
|
||||
|
||||
postfix.clear();
|
||||
if (names.size() > 1) {
|
||||
ss.str("");
|
||||
ss << '(';
|
||||
bool first = true;
|
||||
auto it = names.begin();
|
||||
int count = 0;
|
||||
for (++it; it != names.end(); ++it) {
|
||||
auto& other_key = it->first;
|
||||
if (other_key.shapetype >= 3 && first_key.shapetype < 3) {
|
||||
// shapetype>=3 means it's a high level mapping (e.g. a face
|
||||
// generates a solid). We don't want that if there are more
|
||||
// precise low level mapping available. See comments above
|
||||
// for more details.
|
||||
break;
|
||||
}
|
||||
if (first) {
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
ss << '|';
|
||||
}
|
||||
auto& other_info = it->second;
|
||||
std::ostringstream ss2;
|
||||
if (other_info.index != 1) {
|
||||
// 'K' marks the additional source shape of this
|
||||
// generate (or modified) shape.
|
||||
ss2 << elementMapPrefix() << 'K';
|
||||
if (other_info.index == INT_MIN) {
|
||||
ss2 << '0';
|
||||
}
|
||||
else if (other_info.index == INT_MIN + 1) {
|
||||
ss2 << "00";
|
||||
}
|
||||
else {
|
||||
// The same source shape may generate or modify
|
||||
// more than one shape. The index here marks the
|
||||
// position it is reported by OCC. Including the
|
||||
// index here is likely to degrade name stablilty,
|
||||
// but is unfortunately a necessity to avoid
|
||||
// duplicate names.
|
||||
ss2 << other_info.index;
|
||||
}
|
||||
}
|
||||
Data::MappedName other_name = other_key.name;
|
||||
elementMap()->encodeElementName(*other_info.shapetype,
|
||||
other_name,
|
||||
ss2,
|
||||
&sids,
|
||||
Tag,
|
||||
nullptr,
|
||||
other_key.tag);
|
||||
ss << other_name;
|
||||
if ((name_type == 1 && other_info.index < 0)
|
||||
|| (name_type == 2 && other_info.index > 0)) {
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("element is both generated and modified"); // NOLINT
|
||||
}
|
||||
name_type = 0;
|
||||
}
|
||||
sids += other_info.sids;
|
||||
// To avoid the name becoming to long, just put some limit here
|
||||
if (++count == 4) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!first) {
|
||||
ss << ')';
|
||||
if (Hasher) {
|
||||
sids.push_back(Hasher->getID(ss.str().c_str()));
|
||||
ss.str("");
|
||||
ss << sids.back().toString();
|
||||
}
|
||||
postfix = ss.str();
|
||||
}
|
||||
}
|
||||
|
||||
ss.str("");
|
||||
if (name_type == 2) {
|
||||
ss << genPostfix();
|
||||
}
|
||||
else if (name_type == 1) {
|
||||
ss << modPostfix();
|
||||
}
|
||||
else {
|
||||
ss << modgenPostfix();
|
||||
}
|
||||
if (first_info.index == INT_MIN) {
|
||||
ss << '0';
|
||||
}
|
||||
else if (first_info.index == INT_MIN + 1) {
|
||||
ss << "00";
|
||||
}
|
||||
else if (abs(first_info.index) > 1) {
|
||||
ss << abs(first_info.index);
|
||||
}
|
||||
ss << postfix;
|
||||
elementMap()
|
||||
->encodeElementName(element[0], first_name, ss, &sids, Tag, op, first_key.tag);
|
||||
elementMap()->setElementName(element, first_name, Tag, &sids);
|
||||
|
||||
if (!delayed && first_key.shapetype < 3) {
|
||||
newNames.erase(itName);
|
||||
}
|
||||
}
|
||||
|
||||
// The reverse pass. Starting from the highest level element, i.e.
|
||||
// Face, for any element that are named, assign names for its lower unnamed
|
||||
// elements. For example, if Edge1 is named E1, and its vertexes are not
|
||||
// named, then name them as E1;U1, E1;U2, etc.
|
||||
//
|
||||
// In order to make the name as stable as possible, we may assign multiple
|
||||
// names (which must be sorted, because we may use the first one to name
|
||||
// upper element in the final pass) to lower element if it appears in
|
||||
// multiple higher elements, e.g. same edge in multiple faces.
|
||||
|
||||
for (size_t infoIndex = infos.size() - 1; infoIndex != 0; --infoIndex) {
|
||||
std::map<Data::IndexedName,
|
||||
std::map<Data::MappedName, NameInfo, Data::ElementNameComparator>>
|
||||
names;
|
||||
auto& info = *infos.at(infoIndex);
|
||||
auto& next = *infos.at(infoIndex - 1);
|
||||
int elementCounter = 1;
|
||||
auto it = newNames.end();
|
||||
if (delayed) {
|
||||
it = newNames.upper_bound(Data::IndexedName::fromConst(info.shapetype, 0));
|
||||
}
|
||||
for (;; ++elementCounter) {
|
||||
Data::IndexedName element;
|
||||
if (!delayed) {
|
||||
if (elementCounter > info.count()) {
|
||||
break;
|
||||
}
|
||||
element = Data::IndexedName::fromConst(info.shapetype, elementCounter);
|
||||
if (newNames.count(element) != 0U) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (it == newNames.end()
|
||||
|| !boost::starts_with(it->first.getType(), info.shapetype)) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
element = it->first;
|
||||
++it;
|
||||
elementCounter = element.getIndex();
|
||||
if (elementCounter == 0 || elementCounter > info.count()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Data::ElementIDRefs sids;
|
||||
Data::MappedName mapped = getMappedName(element, false, &sids);
|
||||
if (!mapped) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TopTools_IndexedMapOfShape submap;
|
||||
TopExp::MapShapes(info.find(elementCounter), next.type, submap);
|
||||
for (int submapIndex = 1, infoCounter = 1; submapIndex <= submap.Extent(); ++submapIndex) {
|
||||
ss.str("");
|
||||
int elementIndex = next.find(submap(submapIndex));
|
||||
assert(elementIndex);
|
||||
Data::IndexedName indexedName = Data::IndexedName::fromConst(next.shapetype, elementIndex);
|
||||
if (getMappedName(indexedName)) {
|
||||
continue;
|
||||
}
|
||||
auto& infoRef = names[indexedName][mapped];
|
||||
infoRef.index = infoCounter++;
|
||||
infoRef.sids = sids;
|
||||
}
|
||||
}
|
||||
// Assign the actual names
|
||||
for (auto& [indexedName, nameInfoMap] : names) {
|
||||
// Do we really want multiple names for an element in this case?
|
||||
// If not, we just pick the name in the first sorting order here.
|
||||
auto& nameInfoMapEntry = *nameInfoMap.begin();
|
||||
{
|
||||
auto& nameInfo = nameInfoMapEntry.second;
|
||||
auto& sids = nameInfo.sids;
|
||||
newName = nameInfoMapEntry.first;
|
||||
ss.str("");
|
||||
ss << upperPostfix();
|
||||
if (nameInfo.index > 1) {
|
||||
ss << nameInfo.index;
|
||||
}
|
||||
elementMap()->encodeElementName(indexedName[0], newName, ss, &sids, Tag, op);
|
||||
elementMap()->setElementName(indexedName, newName, Tag, &sids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The forward pass. For any elements that are not named, try construct its
|
||||
// name from the lower elements
|
||||
bool hasUnnamed = false;
|
||||
for (size_t ifo = 1; ifo < infos.size(); ++ifo) {
|
||||
auto& info = *infos.at(ifo);
|
||||
auto& prev = *infos.at(ifo-1);
|
||||
for (int i = 1; i <= info.count(); ++i) {
|
||||
Data::IndexedName element = Data::IndexedName::fromConst(info.shapetype, i);
|
||||
if (getMappedName(element)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Data::ElementIDRefs sids;
|
||||
std::map<Data::MappedName, Data::IndexedName, Data::ElementNameComparator> names;
|
||||
TopExp_Explorer xp;
|
||||
if (info.type == TopAbs_FACE) {
|
||||
xp.Init(BRepTools::OuterWire(TopoDS::Face(info.find(i))), TopAbs_EDGE);
|
||||
}
|
||||
else {
|
||||
xp.Init(info.find(i), prev.type);
|
||||
}
|
||||
for (; xp.More(); xp.Next()) {
|
||||
int previousElementIndex = prev.find(xp.Current());
|
||||
assert(previousElementIndex);
|
||||
Data::IndexedName prevElement = Data::IndexedName::fromConst(prev.shapetype, previousElementIndex);
|
||||
if (!delayed && (newNames.count(prevElement) != 0U)) {
|
||||
names.clear();
|
||||
break;
|
||||
}
|
||||
Data::ElementIDRefs sid;
|
||||
Data::MappedName name = getMappedName(prevElement, false, &sid);
|
||||
if (!name) {
|
||||
// only assign name if all lower elements are named
|
||||
if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
|
||||
FC_WARN("unnamed lower element " << prevElement); // NOLINT
|
||||
}
|
||||
names.clear();
|
||||
break;
|
||||
}
|
||||
auto res = names.emplace(name, prevElement);
|
||||
if (res.second) {
|
||||
sids += sid;
|
||||
}
|
||||
else if (prevElement != res.first->second) {
|
||||
// The seam edge will appear twice, which is normal. We
|
||||
// only warn if the mapped element names are different.
|
||||
// NOLINTNEXTLINE
|
||||
FC_WARN("lower element " << prevElement << " and " << res.first->second
|
||||
<< " has duplicated name " << name << " for "
|
||||
<< info.shapetype << i);
|
||||
}
|
||||
}
|
||||
if (names.empty()) {
|
||||
hasUnnamed = true;
|
||||
continue;
|
||||
}
|
||||
auto it = names.begin();
|
||||
newName = it->first;
|
||||
if (names.size() == 1) {
|
||||
ss << lowerPostfix();
|
||||
}
|
||||
else {
|
||||
bool first = true;
|
||||
ss.str("");
|
||||
if (!Hasher) {
|
||||
ss << lowerPostfix();
|
||||
}
|
||||
ss << '(';
|
||||
int count = 0;
|
||||
for (++it; it != names.end(); ++it) {
|
||||
if (first) {
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
ss << '|';
|
||||
}
|
||||
ss << it->first;
|
||||
|
||||
// To avoid the name becoming to long, just put some limit here
|
||||
if (++count == 4) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ss << ')';
|
||||
if (Hasher) {
|
||||
sids.push_back(Hasher->getID(ss.str().c_str()));
|
||||
ss.str("");
|
||||
ss << lowerPostfix() << sids.back().toString();
|
||||
}
|
||||
}
|
||||
elementMap()->encodeElementName(element[0], newName, ss, &sids, Tag, op);
|
||||
elementMap()->setElementName(element, newName, Tag, &sids);
|
||||
}
|
||||
}
|
||||
if (!hasUnnamed || delayed || newNames.empty()) {
|
||||
break;
|
||||
}
|
||||
delayed = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void addShapesToBuilder(const std::vector<TopoShape>& shapes,
|
||||
@@ -634,7 +1378,8 @@ TopoShape& TopoShape::makeElementFace(const std::vector<TopoShape>& shapes,
|
||||
/**
|
||||
* Encode and set an element name in the elementMap. If a hasher is defined, apply it to the name.
|
||||
*
|
||||
* @param element The element name(type) that provides 1 one character suffix to the name IF <conditions>.
|
||||
* @param element The element name(type) that provides 1 one character suffix to the name IF
|
||||
* <conditions>.
|
||||
* @param names The subnames to build the name from. If empty, return the TopoShape MappedName.
|
||||
* @param marker The elementMap name or suffix to start the name with. If null, use the
|
||||
* elementMapPrefix.
|
||||
|
||||
@@ -15,5 +15,6 @@ target_sources(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TopoShape.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TopoShapeCache.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TopoShapeExpansion.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TopoShapeMakeShapeWithElementMap.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/TopoShapeMapper.cpp
|
||||
)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
#include <BRepPrimAPI_MakeBox.hxx>
|
||||
|
||||
#include "PartTestHelpers.h"
|
||||
|
||||
// NOLINTBEGIN(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers)
|
||||
@@ -137,6 +139,22 @@ std::map<IndexedName, MappedName> elementMap(const TopoShape& shape)
|
||||
return result;
|
||||
}
|
||||
|
||||
std::pair<TopoDS_Shape, TopoDS_Shape> CreateTwoCubes()
|
||||
{
|
||||
auto boxMaker1 = BRepPrimAPI_MakeBox(1.0, 1.0, 1.0);
|
||||
boxMaker1.Build();
|
||||
auto box1 = boxMaker1.Shape();
|
||||
|
||||
auto boxMaker2 = BRepPrimAPI_MakeBox(1.0, 1.0, 1.0);
|
||||
boxMaker2.Build();
|
||||
auto box2 = boxMaker2.Shape();
|
||||
auto transform = gp_Trsf();
|
||||
transform.SetTranslation(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0));
|
||||
box2.Location(TopLoc_Location(transform));
|
||||
|
||||
return {box1, box2};
|
||||
}
|
||||
|
||||
} // namespace PartTestHelpers
|
||||
|
||||
// NOLINTEND(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers)
|
||||
|
||||
@@ -57,4 +57,6 @@ boxesMatch(const Base::BoundBox3d& b1, const Base::BoundBox3d& b2, double prec =
|
||||
|
||||
std::map<IndexedName, MappedName> elementMap(const TopoShape& shape);
|
||||
|
||||
std::pair<TopoDS_Shape, TopoDS_Shape> CreateTwoCubes();
|
||||
|
||||
} // namespace PartTestHelpers
|
||||
|
||||
@@ -8,16 +8,15 @@
|
||||
#include "PartTestHelpers.h"
|
||||
|
||||
#include <BRepBuilderAPI_MakeEdge.hxx>
|
||||
#include <BRepBuilderAPI_MakeFace.hxx>
|
||||
#include <BRepBuilderAPI_MakeWire.hxx>
|
||||
#include <BRepPrimAPI_MakeBox.hxx>
|
||||
#include <GC_MakeCircle.hxx>
|
||||
#include <TopExp_Explorer.hxx>
|
||||
#include <TopoDS.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
|
||||
// NOLINTBEGIN(readability-magic-numbers,cppcoreguidelines-avoid-magic-numbers)
|
||||
|
||||
using namespace PartTestHelpers;
|
||||
|
||||
class TopoShapeExpansionTest: public ::testing::Test
|
||||
{
|
||||
@@ -31,7 +30,6 @@ protected:
|
||||
{
|
||||
_docName = App::GetApplication().getUniqueDocumentName("test");
|
||||
App::GetApplication().newDocument(_docName.c_str(), "testUser");
|
||||
_sids = &_sid;
|
||||
_hasher = Base::Reference<App::StringHasher>(new App::StringHasher);
|
||||
ASSERT_EQ(_hasher.getRefCount(), 1);
|
||||
}
|
||||
@@ -45,7 +43,6 @@ protected:
|
||||
private:
|
||||
std::string _docName;
|
||||
Data::ElementIDRefs _sid;
|
||||
QVector<App::StringIDRef>* _sids = nullptr;
|
||||
App::StringHasherRef _hasher;
|
||||
};
|
||||
|
||||
@@ -125,26 +122,6 @@ TEST_F(TopoShapeExpansionTest, makeElementCompoundTwoShapesGeneratesMap)
|
||||
EXPECT_EQ(4, topoShape.getMappedChildElements().size()); // two vertices and two edges
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::pair<TopoDS_Shape, TopoDS_Shape> CreateTwoCubes()
|
||||
{
|
||||
auto boxMaker1 = BRepPrimAPI_MakeBox(1.0, 1.0, 1.0);
|
||||
boxMaker1.Build();
|
||||
auto box1 = boxMaker1.Shape();
|
||||
|
||||
auto boxMaker2 = BRepPrimAPI_MakeBox(1.0, 1.0, 1.0);
|
||||
boxMaker2.Build();
|
||||
auto box2 = boxMaker2.Shape();
|
||||
auto transform = gp_Trsf();
|
||||
transform.SetTranslation(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(1.0, 0.0, 0.0));
|
||||
box2.Location(TopLoc_Location(transform));
|
||||
|
||||
return {box1, box2};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, makeElementCompoundTwoCubes)
|
||||
{
|
||||
// Arrange
|
||||
@@ -169,42 +146,20 @@ TEST_F(TopoShapeExpansionTest, makeElementCompoundTwoCubes)
|
||||
// 26 subshapes each
|
||||
}
|
||||
|
||||
std::tuple<TopoDS_Face, TopoDS_Wire, TopoDS_Edge, TopoDS_Edge, TopoDS_Edge, TopoDS_Edge>
|
||||
CreateRectFace(float len = 2.0, float wid = 3.0)
|
||||
{
|
||||
auto edge1 = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, 0.0, 0.0), gp_Pnt(len, 0.0, 0.0)).Edge();
|
||||
auto edge2 = BRepBuilderAPI_MakeEdge(gp_Pnt(len, 0.0, 0.0), gp_Pnt(len, wid, 0.0)).Edge();
|
||||
auto edge3 = BRepBuilderAPI_MakeEdge(gp_Pnt(len, wid, 0.0), gp_Pnt(0.0, wid, 0.0)).Edge();
|
||||
auto edge4 = BRepBuilderAPI_MakeEdge(gp_Pnt(0.0, wid, 0.0), gp_Pnt(0.0, 0.0, 0.0)).Edge();
|
||||
auto wire1 = BRepBuilderAPI_MakeWire({edge1, edge2, edge3, edge4}).Wire();
|
||||
auto face1 = BRepBuilderAPI_MakeFace(wire1).Face();
|
||||
return {face1, wire1, edge1, edge2, edge3, edge4};
|
||||
}
|
||||
|
||||
std::tuple<TopoDS_Face, TopoDS_Wire, TopoDS_Wire>
|
||||
CreateFaceWithRoundHole(float len = 2.0, float wid = 3.0, float radius = 1.0)
|
||||
{
|
||||
auto [face1, wire1, edge1, edge2, edge3, edge4] = CreateRectFace(len, wid);
|
||||
auto circ1 =
|
||||
GC_MakeCircle(gp_Pnt(len / 2.0, wid / 2.0, 0), gp_Dir(0.0, 0.0, 1.0), radius).Value();
|
||||
auto edge5 = BRepBuilderAPI_MakeEdge(circ1).Edge();
|
||||
auto wire2 = BRepBuilderAPI_MakeWire(edge5).Wire();
|
||||
auto face2 = BRepBuilderAPI_MakeFace(face1, wire2).Face();
|
||||
return {face2, wire1, wire2};
|
||||
}
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, makeElementFaceNull)
|
||||
{
|
||||
// Arrange
|
||||
const double Len = 3, Wid = 2, Rad = 1;
|
||||
const float Len = 3;
|
||||
const float Wid = 2;
|
||||
const float Rad = 1;
|
||||
auto [face1, wire1, wire2] = CreateFaceWithRoundHole(Len, Wid, Rad);
|
||||
Part::TopoShape topoShape {face1};
|
||||
double area = PartTestHelpers::getArea(face1);
|
||||
double area1 = PartTestHelpers::getArea(topoShape.getShape());
|
||||
double area = getArea(face1);
|
||||
double area1 = getArea(topoShape.getShape());
|
||||
// Act
|
||||
Part::TopoShape newFace = topoShape.makeElementFace(nullptr);
|
||||
double area2 = PartTestHelpers::getArea(newFace.getShape());
|
||||
double area3 = PartTestHelpers::getArea(topoShape.getShape());
|
||||
double area2 = getArea(newFace.getShape());
|
||||
double area3 = getArea(topoShape.getShape());
|
||||
// Assert
|
||||
EXPECT_FALSE(face1.IsEqual(newFace.getShape()));
|
||||
EXPECT_FLOAT_EQ(area, Len * Wid + M_PI * Rad * Rad);
|
||||
@@ -217,15 +172,17 @@ TEST_F(TopoShapeExpansionTest, makeElementFaceNull)
|
||||
TEST_F(TopoShapeExpansionTest, makeElementFaceSimple)
|
||||
{
|
||||
// Arrange
|
||||
const double Len = 3, Wid = 2, Rad = 1;
|
||||
const float Len = 3;
|
||||
const float Wid = 2;
|
||||
const float Rad = 1;
|
||||
auto [face1, wire1, wire2] = CreateFaceWithRoundHole(Len, Wid, Rad);
|
||||
Part::TopoShape topoShape {face1};
|
||||
double area = PartTestHelpers::getArea(face1);
|
||||
double area1 = PartTestHelpers::getArea(topoShape.getShape());
|
||||
double area = getArea(face1);
|
||||
double area1 = getArea(topoShape.getShape());
|
||||
// Act
|
||||
Part::TopoShape newFace = topoShape.makeElementFace(wire1);
|
||||
double area2 = PartTestHelpers::getArea(newFace.getShape());
|
||||
double area3 = PartTestHelpers::getArea(topoShape.getShape());
|
||||
double area2 = getArea(newFace.getShape());
|
||||
double area3 = getArea(topoShape.getShape());
|
||||
// Assert
|
||||
EXPECT_TRUE(newFace.getShape().IsEqual(topoShape.getShape())); // topoShape was altered
|
||||
EXPECT_FALSE(face1.IsEqual(newFace.getShape()));
|
||||
@@ -239,16 +196,18 @@ TEST_F(TopoShapeExpansionTest, makeElementFaceSimple)
|
||||
TEST_F(TopoShapeExpansionTest, makeElementFaceParams)
|
||||
{
|
||||
// Arrange
|
||||
const double Len = 3, Wid = 2, Rad = 1;
|
||||
const float Len = 3;
|
||||
const float Wid = 2;
|
||||
const float Rad = 1;
|
||||
auto [face1, wire1, wire2] = CreateFaceWithRoundHole(Len, Wid, Rad);
|
||||
Part::TopoShape topoShape {face1, 1L};
|
||||
double area = PartTestHelpers::getArea(face1);
|
||||
double area1 = PartTestHelpers::getArea(topoShape.getShape());
|
||||
double area = getArea(face1);
|
||||
double area1 = getArea(topoShape.getShape());
|
||||
// Act
|
||||
Part::TopoShape newFace =
|
||||
topoShape.makeElementFace(wire1, "Cut", "Part::FaceMakerBullseye", nullptr);
|
||||
double area2 = PartTestHelpers::getArea(newFace.getShape());
|
||||
double area3 = PartTestHelpers::getArea(topoShape.getShape());
|
||||
double area2 = getArea(newFace.getShape());
|
||||
double area3 = getArea(topoShape.getShape());
|
||||
// Assert
|
||||
EXPECT_TRUE(newFace.getShape().IsEqual(topoShape.getShape())); // topoShape was altered
|
||||
EXPECT_FALSE(face1.IsEqual(newFace.getShape()));
|
||||
@@ -262,16 +221,18 @@ TEST_F(TopoShapeExpansionTest, makeElementFaceParams)
|
||||
TEST_F(TopoShapeExpansionTest, makeElementFaceFromFace)
|
||||
{
|
||||
// Arrange
|
||||
const double Len = 3, Wid = 2, Rad = 1;
|
||||
const float Len = 3;
|
||||
const float Wid = 2;
|
||||
const float Rad = 1;
|
||||
auto [face1, wire1, wire2] = CreateFaceWithRoundHole(Len, Wid, Rad);
|
||||
Part::TopoShape topoShape {face1, 1L};
|
||||
double area = PartTestHelpers::getArea(face1);
|
||||
double area1 = PartTestHelpers::getArea(topoShape.getShape());
|
||||
double area = getArea(face1);
|
||||
double area1 = getArea(topoShape.getShape());
|
||||
// Act
|
||||
Part::TopoShape newFace =
|
||||
topoShape.makeElementFace(face1, "Cut", "Part::FaceMakerBullseye", nullptr);
|
||||
double area2 = PartTestHelpers::getArea(newFace.getShape());
|
||||
double area3 = PartTestHelpers::getArea(topoShape.getShape());
|
||||
double area2 = getArea(newFace.getShape());
|
||||
double area3 = getArea(topoShape.getShape());
|
||||
// Assert
|
||||
EXPECT_TRUE(newFace.getShape().IsEqual(topoShape.getShape())); // topoShape was altered
|
||||
EXPECT_FALSE(face1.IsEqual(newFace.getShape()));
|
||||
@@ -286,15 +247,17 @@ TEST_F(TopoShapeExpansionTest, makeElementFaceFromFace)
|
||||
TEST_F(TopoShapeExpansionTest, makeElementFaceOpenWire)
|
||||
{
|
||||
// Arrange
|
||||
const double Len = 3, Wid = 2, Rad = 1;
|
||||
const float Len = 3;
|
||||
const float Wid = 2;
|
||||
const float Rad = 1;
|
||||
auto [face1, wire1, wire2] = CreateFaceWithRoundHole(Len, Wid, Rad);
|
||||
Part::TopoShape topoShape {wire1, 1L};
|
||||
double area = PartTestHelpers::getArea(face1);
|
||||
double area1 = PartTestHelpers::getArea(topoShape.getShape());
|
||||
double area = getArea(face1);
|
||||
double area1 = getArea(topoShape.getShape());
|
||||
// Act
|
||||
Part::TopoShape newFace = topoShape.makeElementFace(wire1, "Cut", nullptr, nullptr);
|
||||
double area2 = PartTestHelpers::getArea(newFace.getShape());
|
||||
double area3 = PartTestHelpers::getArea(topoShape.getShape());
|
||||
double area2 = getArea(newFace.getShape());
|
||||
double area3 = getArea(topoShape.getShape());
|
||||
// Assert
|
||||
EXPECT_TRUE(newFace.getShape().IsEqual(topoShape.getShape())); // topoShape was altered
|
||||
EXPECT_FALSE(face1.IsEqual(newFace.getShape()));
|
||||
@@ -309,16 +272,18 @@ TEST_F(TopoShapeExpansionTest, makeElementFaceOpenWire)
|
||||
TEST_F(TopoShapeExpansionTest, makeElementFaceClosedWire)
|
||||
{
|
||||
// Arrange
|
||||
const double Len = 3, Wid = 2, Rad = 1;
|
||||
const float Len = 3;
|
||||
const float Wid = 2;
|
||||
const float Rad = 1;
|
||||
auto [face1, wire1, wire2] = CreateFaceWithRoundHole(Len, Wid, Rad);
|
||||
Part::TopoShape topoShape {wire2, 1L};
|
||||
double area = PartTestHelpers::getArea(face1);
|
||||
double area1 = PartTestHelpers::getArea(topoShape.getShape());
|
||||
double area = getArea(face1);
|
||||
double area1 = getArea(topoShape.getShape());
|
||||
// Act
|
||||
Part::TopoShape newFace =
|
||||
topoShape.makeElementFace(wire2, "Cut", "Part::FaceMakerBullseye", nullptr);
|
||||
double area2 = PartTestHelpers::getArea(newFace.getShape());
|
||||
double area3 = PartTestHelpers::getArea(topoShape.getShape());
|
||||
double area2 = getArea(newFace.getShape());
|
||||
double area3 = getArea(topoShape.getShape());
|
||||
// Assert
|
||||
EXPECT_TRUE(newFace.getShape().IsEqual(topoShape.getShape())); // topoShape was altered
|
||||
EXPECT_FALSE(face1.IsEqual(newFace.getShape()));
|
||||
@@ -414,7 +379,9 @@ TEST_F(TopoShapeExpansionTest, setElementComboNameCompound)
|
||||
TEST_F(TopoShapeExpansionTest, splitWires)
|
||||
{
|
||||
// Arrange
|
||||
const double Len = 3, Wid = 2, Rad = 1;
|
||||
const float Len = 3;
|
||||
const float Wid = 2;
|
||||
const float Rad = 1;
|
||||
auto [face1, wire1, wire2] = CreateFaceWithRoundHole(Len, Wid, Rad);
|
||||
Part::TopoShape topoShape {face1, 1L};
|
||||
std::vector<Part::TopoShape> inner;
|
||||
@@ -424,8 +391,8 @@ TEST_F(TopoShapeExpansionTest, splitWires)
|
||||
topoShape.splitWires(&inner, Part::TopoShape::SplitWireReorient::ReorientReversed);
|
||||
// Assert
|
||||
EXPECT_EQ(inner.size(), 1);
|
||||
EXPECT_FLOAT_EQ(PartTestHelpers::getLength(wire.getShape()), 2 + 2 + 3 + 3);
|
||||
EXPECT_FLOAT_EQ(PartTestHelpers::getLength(inner.front().getShape()), M_PI * Rad * 2);
|
||||
EXPECT_FLOAT_EQ(getLength(wire.getShape()), 2 + 2 + 3 + 3);
|
||||
EXPECT_FLOAT_EQ(getLength(inner.front().getShape()), M_PI * Rad * 2);
|
||||
EXPECT_EQ(wire.getShape().Orientation(), TopAbs_REVERSED);
|
||||
for (Part::TopoShape& shape : inner) {
|
||||
EXPECT_EQ(shape.getShape().Orientation(), TopAbs_FORWARD);
|
||||
@@ -434,8 +401,8 @@ TEST_F(TopoShapeExpansionTest, splitWires)
|
||||
|
||||
// Possible future tests:
|
||||
// splitWires without inner Wires
|
||||
// splitWires with allfour reorientation values NoReorient, ReOrient, ReorientForward,
|
||||
// ReorientRevesed
|
||||
// splitWires with all four reorientation values NoReorient, ReOrient, ReorientForward,
|
||||
// ReorientReversed
|
||||
|
||||
TEST_F(TopoShapeExpansionTest, mapSubElementInvalidParm)
|
||||
{
|
||||
@@ -461,7 +428,8 @@ TEST_F(TopoShapeExpansionTest, mapSubElementFindShapeByNames)
|
||||
Part::TopoShape cube2TS {cube2};
|
||||
cube1TS.Tag = 1;
|
||||
cube2TS.Tag = 2;
|
||||
Part::TopoShape topoShape, topoShape1;
|
||||
Part::TopoShape topoShape;
|
||||
Part::TopoShape topoShape1;
|
||||
|
||||
// Act
|
||||
int fs1 = topoShape1.findShape(cube1);
|
||||
@@ -546,8 +514,13 @@ TEST_F(TopoShapeExpansionTest, mapSubElementFindAncestors)
|
||||
cube2TS.Tag = 2;
|
||||
cube3TS.Tag = 3;
|
||||
cube4TS.Tag = 4;
|
||||
Part::TopoShape topoShape, topoShape1, topoShape2;
|
||||
Part::TopoShape topoShape3, topoShape4, topoShape5, topoShape6;
|
||||
Part::TopoShape topoShape;
|
||||
Part::TopoShape topoShape1;
|
||||
Part::TopoShape topoShape2;
|
||||
Part::TopoShape topoShape3;
|
||||
Part::TopoShape topoShape4;
|
||||
Part::TopoShape topoShape5;
|
||||
Part::TopoShape topoShape6;
|
||||
topoShape.makeElementCompound({cube1TS, cube2TS});
|
||||
topoShape1.makeElementCompound({cube3TS, cube4TS});
|
||||
topoShape2.makeElementCompound({cube1TS, cube3TS});
|
||||
@@ -595,7 +568,8 @@ TEST_F(TopoShapeExpansionTest, makeElementShellInvalid)
|
||||
TEST_F(TopoShapeExpansionTest, makeElementShellSingle)
|
||||
{
|
||||
// Arrange
|
||||
const double Len = 3, Wid = 2;
|
||||
const float Len = 3;
|
||||
const float Wid = 2;
|
||||
auto [face1, wire1, edge1, edge2, edge3, _] = CreateRectFace(Len, Wid);
|
||||
Part::TopoShape topoShape {face1, 1L};
|
||||
// Act
|
||||
@@ -613,7 +587,8 @@ TEST_F(TopoShapeExpansionTest, makeElementShellSingle)
|
||||
TEST_F(TopoShapeExpansionTest, makeElementShellOpen)
|
||||
{
|
||||
// Arrange
|
||||
const double Len = 3, Wid = 2;
|
||||
const float Len = 3;
|
||||
const float Wid = 2;
|
||||
auto [face1, wire1, edge1, edge2, edge3, edge4] = CreateRectFace(Len, Wid);
|
||||
auto transform {gp_Trsf()};
|
||||
transform.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(1, 0, 0)), M_PI / 2);
|
||||
@@ -644,7 +619,7 @@ TEST_F(TopoShapeExpansionTest, makeElementShellClosed)
|
||||
Part::TopoShape topoShape {cube1};
|
||||
std::vector<Part::TopoShape> shapes;
|
||||
for (const auto& face : topoShape.getSubShapes(TopAbs_FACE)) {
|
||||
shapes.push_back(Part::TopoShape {face});
|
||||
shapes.emplace_back(face);
|
||||
}
|
||||
// Act
|
||||
Part::TopoShape topoShape1 {1L};
|
||||
@@ -671,11 +646,11 @@ TEST_F(TopoShapeExpansionTest, makeElementShellIntersecting)
|
||||
Part::TopoShape topoShape {cube1};
|
||||
std::vector<Part::TopoShape> shapes;
|
||||
for (const auto& face : topoShape.getSubShapes(TopAbs_FACE)) {
|
||||
shapes.push_back(Part::TopoShape {face});
|
||||
shapes.emplace_back(face);
|
||||
}
|
||||
topoShape.setShape(cube2);
|
||||
for (const auto& face : topoShape.getSubShapes(TopAbs_FACE)) {
|
||||
shapes.push_back(Part::TopoShape {face});
|
||||
shapes.emplace_back(face);
|
||||
}
|
||||
// Act
|
||||
Part::TopoShape topoShape1 {1L};
|
||||
|
||||
342
tests/src/Mod/Part/App/TopoShapeMakeShapeWithElementMap.cpp
Normal file
342
tests/src/Mod/Part/App/TopoShapeMakeShapeWithElementMap.cpp
Normal file
@@ -0,0 +1,342 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
// Tests for the makeShapeWithElementMap method, extracted from the main set of tests for TopoShape
|
||||
// due to length and complexity.
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "src/App/InitApplication.h"
|
||||
#include "PartTestHelpers.h"
|
||||
#include <Mod/Part/App/TopoShape.h>
|
||||
#include <Mod/Part/App/TopoShapeOpCode.h>
|
||||
// #include <MappedName.h>
|
||||
|
||||
#include <TopoDS_Vertex.hxx>
|
||||
#include <TopoDS_Edge.hxx>
|
||||
#include <TopoDS_Wire.hxx>
|
||||
#include <TopoDS_Face.hxx>
|
||||
#include <TopoDS_Shell.hxx>
|
||||
#include <TopoDS_Solid.hxx>
|
||||
#include <TopoDS_CompSolid.hxx>
|
||||
#include <TopoDS_Compound.hxx>
|
||||
|
||||
using namespace Part;
|
||||
using namespace Data;
|
||||
|
||||
class TopoShapeMakeShapeWithElementMapTests: public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
static void SetUpTestSuite()
|
||||
{
|
||||
tests::initApplication();
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
_docName = App::GetApplication().getUniqueDocumentName("test");
|
||||
App::GetApplication().newDocument(_docName.c_str(), "testUser");
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
App::GetApplication().closeDocument(_docName.c_str());
|
||||
}
|
||||
|
||||
Part::TopoShape* Shape()
|
||||
{
|
||||
return &_shape;
|
||||
}
|
||||
|
||||
Part::TopoShape::Mapper* Mapper()
|
||||
{
|
||||
return &_mapper;
|
||||
}
|
||||
|
||||
void testFindSourceSubShapesInElementMapForSource(const std::vector<TopoShape>& sources,
|
||||
const TopoShape& source);
|
||||
|
||||
private:
|
||||
std::string _docName;
|
||||
Data::ElementIDRefs _sid;
|
||||
Part::TopoShape _shape;
|
||||
Part::TopoShape::Mapper _mapper;
|
||||
};
|
||||
|
||||
TEST_F(TopoShapeMakeShapeWithElementMapTests, nullShapeThrows)
|
||||
{
|
||||
// Arrange
|
||||
auto [cube1, cube2] = PartTestHelpers::CreateTwoCubes();
|
||||
std::vector<Part::TopoShape> sources {cube1, cube2};
|
||||
TopoDS_Vertex nullVertex;
|
||||
TopoDS_Edge nullEdge;
|
||||
TopoDS_Wire nullWire;
|
||||
TopoDS_Face nullFace;
|
||||
TopoDS_Shell nullShell;
|
||||
TopoDS_Solid nullSolid;
|
||||
TopoDS_CompSolid nullCompSolid;
|
||||
TopoDS_Compound nullCompound;
|
||||
|
||||
// Act and assert
|
||||
EXPECT_THROW(Shape()->makeShapeWithElementMap(nullVertex, *Mapper(), sources),
|
||||
Part::NullShapeException);
|
||||
EXPECT_THROW(Shape()->makeShapeWithElementMap(nullEdge, *Mapper(), sources),
|
||||
Part::NullShapeException);
|
||||
EXPECT_THROW(Shape()->makeShapeWithElementMap(nullWire, *Mapper(), sources),
|
||||
Part::NullShapeException);
|
||||
EXPECT_THROW(Shape()->makeShapeWithElementMap(nullFace, *Mapper(), sources),
|
||||
Part::NullShapeException);
|
||||
EXPECT_THROW(Shape()->makeShapeWithElementMap(nullShell, *Mapper(), sources),
|
||||
Part::NullShapeException);
|
||||
EXPECT_THROW(Shape()->makeShapeWithElementMap(nullSolid, *Mapper(), sources),
|
||||
Part::NullShapeException);
|
||||
EXPECT_THROW(Shape()->makeShapeWithElementMap(nullCompSolid, *Mapper(), sources),
|
||||
Part::NullShapeException);
|
||||
EXPECT_THROW(Shape()->makeShapeWithElementMap(nullCompound, *Mapper(), sources),
|
||||
Part::NullShapeException);
|
||||
}
|
||||
|
||||
using Data::IndexedName, Data::MappedName;
|
||||
using Part::TopoShape;
|
||||
|
||||
std::map<IndexedName, MappedName> elementMap(const TopoShape& shape)
|
||||
{
|
||||
std::map<IndexedName, MappedName> result {};
|
||||
auto elements = shape.getElementMap();
|
||||
for (auto const& entry : elements) {
|
||||
result[entry.index] = entry.name;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// TEST_F(TopoShapeMakeShapeWithElementMapTests, mapVertex)
|
||||
// TEST_F(TopoShapeMakeShapeWithElementMapTests, mapEdge)
|
||||
// TEST_F(TopoShapeMakeShapeWithElementMapTests, mapWire)
|
||||
// TEST_F(TopoShapeMakeShapeWithElementMapTests, mapFace)
|
||||
// TEST_F(TopoShapeMakeShapeWithElementMapTests, mapShell)
|
||||
// TEST_F(TopoShapeMakeShapeWithElementMapTests, mapSolid)
|
||||
|
||||
TEST_F(TopoShapeMakeShapeWithElementMapTests, mapCompoundCount)
|
||||
{
|
||||
// Arrange
|
||||
auto [cube1, cube2] = PartTestHelpers::CreateTwoCubes();
|
||||
std::vector<TopoShape> sources {cube1, cube2};
|
||||
sources[0].Tag = 1;
|
||||
sources[1].Tag = 2;
|
||||
TopoShape compound = TopoShape();
|
||||
compound.makeElementCompound(sources);
|
||||
auto preElements = elementMap(compound); // Map before mapping.
|
||||
// Act
|
||||
compound.makeShapeWithElementMap(compound.getShape(), *Mapper(), sources);
|
||||
auto postElements = elementMap(compound); // Map after mapping
|
||||
// Assert
|
||||
EXPECT_EQ(preElements.size(), 52); // Check the before map.
|
||||
EXPECT_EQ(postElements.size(), 52); // 12 Edges, 8 Vertexes, 6 Faces per each Cube
|
||||
EXPECT_EQ(postElements.count(IndexedName("Edge", 24)), 1);
|
||||
EXPECT_EQ(postElements.count(IndexedName("Edge", 25)), 0);
|
||||
EXPECT_EQ(postElements.count(IndexedName("Vertex", 16)), 1);
|
||||
EXPECT_EQ(postElements.count(IndexedName("Vertex", 17)), 0);
|
||||
EXPECT_EQ(postElements.count(IndexedName("Face", 12)), 1);
|
||||
EXPECT_EQ(postElements.count(IndexedName("Face", 13)), 0);
|
||||
EXPECT_STREQ(sources[0].shapeName().c_str(), "Solid");
|
||||
EXPECT_STREQ(sources[1].shapeName().c_str(), "Solid");
|
||||
EXPECT_STREQ(compound.shapeName().c_str(), "Compound");
|
||||
}
|
||||
|
||||
TEST_F(TopoShapeMakeShapeWithElementMapTests, mapCompoundMap)
|
||||
{
|
||||
// Arrange
|
||||
auto [cube1, cube2] = PartTestHelpers::CreateTwoCubes();
|
||||
std::vector<TopoShape> sources {cube1, cube2};
|
||||
sources[0].Tag = 1;
|
||||
sources[1].Tag = 2;
|
||||
// Map only one of the two sources to test different names.
|
||||
sources[0].makeShapeWithElementMap(sources[0].getShape(), *Mapper(), {sources[0]});
|
||||
TopoShape compound = TopoShape();
|
||||
compound.makeElementCompound(sources);
|
||||
auto preElements = elementMap(compound); // Map before mapping.
|
||||
// Act
|
||||
compound.makeShapeWithElementMap(compound.getShape(), *Mapper(), sources);
|
||||
auto postElements = elementMap(compound); // Map after mapping
|
||||
// Assert
|
||||
EXPECT_EQ(preElements[IndexedName("Edge", 1)], MappedName("Edge1;MAK;:H:4,E;:H1:b,E"));
|
||||
EXPECT_EQ(preElements[IndexedName("Edge", 13)], MappedName("Edge1;:H2,E"));
|
||||
EXPECT_EQ(postElements[IndexedName("Edge", 1)], MappedName("Edge1;MAK;:H:4,E;MAK;:H1:f,E"));
|
||||
EXPECT_EQ(postElements[IndexedName("Edge", 13)], MappedName("Edge1;MAK;:H2:4,E"));
|
||||
}
|
||||
|
||||
TEST_F(TopoShapeMakeShapeWithElementMapTests, emptySourceShapes)
|
||||
{
|
||||
// Arrange
|
||||
auto [cube1, cube2] = PartTestHelpers::CreateTwoCubes();
|
||||
std::vector<Part::TopoShape> emptySources;
|
||||
std::vector<Part::TopoShape> nonEmptySources {cube1, cube2};
|
||||
|
||||
// Act and assert
|
||||
for (auto& source : nonEmptySources) {
|
||||
Part::TopoShape& modifiedShape = source;
|
||||
Part::TopoShape& originalShape = source;
|
||||
|
||||
EXPECT_EQ(
|
||||
&originalShape,
|
||||
&modifiedShape.makeShapeWithElementMap(source.getShape(), *Mapper(), emptySources));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TopoShapeMakeShapeWithElementMapTests, nonMappableSources)
|
||||
{
|
||||
// Arrange
|
||||
auto [cube1, cube2] = PartTestHelpers::CreateTwoCubes();
|
||||
std::vector<Part::TopoShape> sources {cube1, cube2};
|
||||
|
||||
// Act and assert
|
||||
for (auto& source : sources) {
|
||||
size_t canMap = 0;
|
||||
for (const auto& mappableSource : sources) {
|
||||
if (source.canMapElement(mappableSource)) {
|
||||
++canMap;
|
||||
}
|
||||
}
|
||||
|
||||
if (canMap == 0U) {
|
||||
EXPECT_EQ(&source,
|
||||
&source.makeShapeWithElementMap(source.getShape(), *Mapper(), sources));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testFindSourceShapesInSingleShape(const Part::TopoShape& cmpdShape,
|
||||
const Part::TopoShape& source,
|
||||
const std::vector<Part::TopoShape>& sources,
|
||||
const TopoShape::Mapper& mapper)
|
||||
{
|
||||
std::vector<Part::TopoShape> tmpSources {source};
|
||||
for (const auto& subSource : sources) {
|
||||
Part::TopoShape tmpShape {source.getShape()};
|
||||
tmpShape.makeShapeWithElementMap(source.getShape(), mapper, tmpSources);
|
||||
if (&source == &subSource) {
|
||||
EXPECT_NE(tmpShape.findShape(subSource.getShape()),
|
||||
0); // if tmpShape uses, for example, cube1 and we search for cube1 than
|
||||
// we should find it
|
||||
}
|
||||
else {
|
||||
EXPECT_EQ(tmpShape.findShape(subSource.getShape()),
|
||||
0); // if tmpShape uses, for example, cube1 and we search for cube2 than
|
||||
// we shouldn't find it
|
||||
}
|
||||
}
|
||||
EXPECT_NE(cmpdShape.findShape(source.getShape()),
|
||||
0); // as cmpdShape is made with cube1 and cube2 we should find both of them
|
||||
}
|
||||
|
||||
TEST_F(TopoShapeMakeShapeWithElementMapTests, findSourceShapesInShape)
|
||||
{
|
||||
// Arrange
|
||||
auto [cube1, cube2] = PartTestHelpers::CreateTwoCubes();
|
||||
std::vector<Part::TopoShape> sources {cube1, cube2};
|
||||
sources[0].Tag = 1; // setting Tag explicitly otherwise it is likely that this test will be
|
||||
// more or less the same of nonMappableSources
|
||||
sources[1].Tag = 2; // setting Tag explicitly otherwise it is likely that this test will be
|
||||
// more or less the same of nonMappableSources
|
||||
Part::TopoShape cmpdShape;
|
||||
cmpdShape.makeElementCompound(sources);
|
||||
|
||||
// Act and assert
|
||||
for (const auto& source : sources) {
|
||||
testFindSourceShapesInSingleShape(cmpdShape, source, sources, *Mapper());
|
||||
}
|
||||
}
|
||||
|
||||
void testFindSubShapesForSourceWithTypeAndIndex(const std::string& shapeTypeStr,
|
||||
std::map<IndexedName, MappedName>& elementStdMap,
|
||||
unsigned long shapeIndex)
|
||||
{
|
||||
std::string shapeIndexStr = std::to_string(shapeIndex);
|
||||
std::string shapeName {shapeTypeStr + shapeIndexStr};
|
||||
|
||||
IndexedName indexedName {shapeTypeStr.c_str(), (int)shapeIndex};
|
||||
MappedName mappedName {elementStdMap[indexedName]};
|
||||
const char shapeTypePrefix {indexedName.toString()[0]};
|
||||
|
||||
EXPECT_NO_THROW(elementStdMap.at(indexedName)); // We check that the IndexedName
|
||||
// is one of the keys...
|
||||
EXPECT_NE(mappedName.find(shapeName.c_str()),
|
||||
-1); // ... that the element name is in the MappedName...
|
||||
EXPECT_EQ(mappedName.toString().back(), shapeTypePrefix);
|
||||
}
|
||||
|
||||
void testFindSubShapesForSourceWithType(const TopoShape& source,
|
||||
const char* shapeType,
|
||||
std::map<IndexedName, MappedName>& elementStdMap)
|
||||
{
|
||||
std::string shapeTypeStr {shapeType};
|
||||
|
||||
// ... and all the elements of the various types in the source TopoShape ...
|
||||
for (unsigned long shapeIndex = 1U; shapeIndex <= source.countSubElements(shapeType);
|
||||
shapeIndex++) {
|
||||
testFindSubShapesForSourceWithTypeAndIndex(shapeTypeStr, elementStdMap, shapeIndex);
|
||||
}
|
||||
|
||||
// ... we also check that we don't find shapes that don't exist and therefore don't
|
||||
// have either an IndexedName or a MappedName
|
||||
IndexedName fakeIndexedName {shapeTypeStr.c_str(), (int)source.countSubElements(shapeType) + 1};
|
||||
EXPECT_THROW(elementStdMap.at(fakeIndexedName), std::out_of_range);
|
||||
}
|
||||
|
||||
void TopoShapeMakeShapeWithElementMapTests::testFindSourceSubShapesInElementMapForSource(
|
||||
const std::vector<TopoShape>& sources,
|
||||
const TopoShape& source)
|
||||
{
|
||||
TopoShape tmpShape {source.getShape()};
|
||||
tmpShape.makeShapeWithElementMap(source.getShape(), *Mapper(), sources);
|
||||
|
||||
// First we create a map with the IndexedNames and MappedNames
|
||||
std::map<IndexedName, MappedName> elementStdMap;
|
||||
for (const auto& mappedElement : tmpShape.getElementMap()) {
|
||||
elementStdMap.emplace(mappedElement.index, mappedElement.name);
|
||||
}
|
||||
|
||||
// Then for all the elements types (Vertex, Edge, Face) ...
|
||||
for (const auto& shapeType : source.getElementTypes()) {
|
||||
testFindSubShapesForSourceWithType(source, shapeType, elementStdMap);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TopoShapeMakeShapeWithElementMapTests, findSourceSubShapesInElementMap)
|
||||
{
|
||||
// Arrange
|
||||
auto [cube1, cube2] = PartTestHelpers::CreateTwoCubes();
|
||||
std::vector<TopoShape> sources {cube1, cube2};
|
||||
sources[0].Tag = 1; // setting Tag explicitly otherwise it is likely that this test will be
|
||||
// more or less the same of nonMappableSources
|
||||
sources[1].Tag = 2; // setting Tag explicitly otherwise it is likely that this test will be
|
||||
// more or less the same of nonMappableSources
|
||||
|
||||
// Act and assert
|
||||
// Testing with all the source TopoShapes
|
||||
for (const auto& source : sources) {
|
||||
testFindSourceSubShapesInElementMapForSource(sources, source);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TopoShapeMakeShapeWithElementMapTests, findMakerOpInElementMap)
|
||||
{
|
||||
// Arrange
|
||||
auto [cube1, cube2] = PartTestHelpers::CreateTwoCubes();
|
||||
std::vector<TopoShape> sources {cube1, cube2};
|
||||
sources[0].Tag = 1; // setting Tag explicitly otherwise it is likely that this test will be
|
||||
// more or less the same of nonMappableSources
|
||||
sources[1].Tag = 2; // setting Tag explicitly otherwise it is likely that this test will be
|
||||
// more or less the same of nonMappableSources
|
||||
|
||||
// Act and assert
|
||||
// Testing with all the source TopoShapes
|
||||
for (const auto& source : sources) {
|
||||
TopoShape tmpShape {source.getShape()};
|
||||
tmpShape.makeShapeWithElementMap(source.getShape(), *Mapper(), sources);
|
||||
|
||||
// For all the mappedElements ...
|
||||
for (const auto& mappedElement : tmpShape.getElementMap()) {
|
||||
EXPECT_NE(mappedElement.name.find(OpCodes::Maker),
|
||||
-1); // ... we check that there's the "MAK" OpCode
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user