Toponaming: Fix transformed; abstract index element name generation

This commit is contained in:
bgbsww
2024-08-09 22:04:05 -04:00
parent 99b753b006
commit 25ba8ab223
7 changed files with 107 additions and 32 deletions

View File

@@ -91,4 +91,16 @@ bool Data::hasMissingElement(const char *subname) {
const char *Data::hasMappedElementName(const char *subname) {
return isMappedElement(findElementName(subname));
}
}
// Currently used by CrossSection.cpp and FeatureTransformed.cpp with different label types
// with a default of "I" and "_" used by CrossSection.
const std::string Data::indexSuffix(int index, const char *label)
{
if ( index < 2 ) { // Don't add a suffix for item #1, begin appending at 2
return {""};
}
std::string name(label);
name += std::to_string(index);
return name;
}

View File

@@ -69,6 +69,8 @@ constexpr const char* POSTFIX_GEN = ";:G";
constexpr const char* POSTFIX_MODGEN = ";:MG";
constexpr const char* POSTFIX_DUPLICATE = ";D";
constexpr const char* ELEMENT_MAP_INDEX = "I";
constexpr const char* ELEMENT_MAP_INDEX2 = "_";
/// Check if a subname contains missing element
AppExport bool hasMissingElement(const char *subname);
@@ -95,6 +97,7 @@ AppExport const char *findElementName(const char *subname);
AppExport const char *hasMappedElementName(const char *subname);
AppExport const std::string indexSuffix(int index, const char *label=ELEMENT_MAP_INDEX);
} // namespace Data
// clang-format on

View File

@@ -462,18 +462,7 @@ const std::string& StringHasher::getPersistenceFileName() const
void StringHasher::Save(Base::Writer& writer) const
{
size_t count = 0;
if (_hashes->SaveAll) {
count = _hashes->size();
}
else {
count = 0;
for (auto& hasher : _hashes->right) {
if (hasher.second->isMarked() || hasher.second->isPersistent()) {
++count;
}
}
}
std::size_t count = _hashes->SaveAll ? _hashes->size() : this->count();
writer.Stream() << writer.ind() << "<StringHasher saveall=\"" << _hashes->SaveAll
<< "\" threshold=\"" << _hashes->Threshold << "\"";

View File

@@ -265,10 +265,7 @@ void TopoCrossSection::sliceNonSolid(int idx,
BRepAlgoAPI_Section cs(shape.getShape(), gp_Pln(a, b, c, -d));
if (cs.IsDone()) {
std::string prefix(op);
if (idx > 1) {
prefix += '_';
prefix += std::to_string(idx);
}
prefix += Data::indexSuffix(idx,Data::ELEMENT_MAP_INDEX2);
auto res = TopoShape()
.makeElementShape(cs, shape, prefix.c_str())
.makeElementWires()
@@ -297,10 +294,7 @@ void TopoCrossSection::sliceSolid(int idx,
BRepPrimAPI_MakeHalfSpace mkSolid(TopoDS::Face(face.getShape()), refPoint);
TopoShape solid(idx);
std::string prefix(op);
if (idx > 1) {
prefix += '_';
prefix += std::to_string(idx);
}
prefix += Data::indexSuffix(idx,Data::ELEMENT_MAP_INDEX2);
solid.makeElementShape(mkSolid, face, prefix.c_str());
BRepAlgoAPI_Cut mkCut(shape.getShape(), solid.getShape());

View File

@@ -50,6 +50,7 @@
#include "FeatureLinearPattern.h"
#include "FeaturePolarPattern.h"
#include "FeatureSketchBased.h"
#include "Mod/Part/App/TopoShapeOpCode.h"
using namespace PartDesign;
@@ -285,10 +286,12 @@ App::DocumentObjectExecReturn* Transformed::execute()
auto getTransformedCompShape = [&](const auto& origShape) {
std::vector<TopoShape> shapes;
TopoShape shape = origShape;
auto transformIter = transformations.cbegin();
for (; transformIter != transformations.end(); ++transformIter) {
shapes.emplace_back(shape.makeElementTransform(*transformIter));
TopoShape shape (origShape);
int idx=1;
for ( const auto& transformIter : transformations ) {
auto opName = Data::indexSuffix(idx++);
auto transformed = shape.makeElementTransform(transformIter, opName.c_str());
shapes.emplace_back(transformed);
}
return shapes;
};
@@ -338,15 +341,15 @@ App::DocumentObjectExecReturn* Transformed::execute()
#endif
if (!fuseShape.isNull()) {
supportShape = supportShape.makeElementFuse(getTransformedCompShape(fuseShape.getShape()));
supportShape.makeElementFuse(getTransformedCompShape(fuseShape.getShape()));
}
if (!cutShape.isNull()) {
supportShape = supportShape.makeElementCut(getTransformedCompShape(cutShape.getShape()));
supportShape.makeElementFuse(getTransformedCompShape(cutShape.getShape()));
}
}
break;
case Mode::TransformBody: {
supportShape = supportShape.makeElementFuse(getTransformedCompShape(supportShape));
supportShape.makeElementFuse(getTransformedCompShape(supportShape));
break;
}
}

View File

@@ -65,6 +65,70 @@ class TestMultiTransform(unittest.TestCase):
self.Doc.recompute()
self.assertAlmostEqual(self.MultiTransform.Shape.Volume, 20000)
def testMultiTransformDressup(self):
# Arrange
Doc = self.Doc
Body = Doc.addObject('PartDesign::Body','Body')
# Make first offset cube Pad
PadSketch = Doc.addObject('Sketcher::SketchObject', 'SketchPad')
Body.addObject(PadSketch)
TestSketcherApp.CreateRectangleSketch(PadSketch, (0, 0), (10, 10))
Doc.recompute()
Pad = Doc.addObject("PartDesign::Pad", "Pad")
Body.addObject(Pad)
Pad.Profile = PadSketch
Pad.Length = 10
Doc.recompute()
PadSketch2 = Doc.addObject('Sketcher::SketchObject', 'SketchPad')
PadSketch2.AttachmentSupport = (Pad, ('Face6',))
Body.addObject(PadSketch2)
TestSketcherApp.CreateRectangleSketch(PadSketch, (9, 9), (1, 1))
Doc.recompute()
Pad2 = Doc.addObject("PartDesign::Pad", "Pad2")
Body.addObject(Pad2)
Pad2.Profile = PadSketch2
Pad2.Length = 10
Doc.recompute()
MultiTransform = Doc.addObject("PartDesign::MultiTransform","MultiTransform")
Doc.recompute()
MultiTransform.Originals = [Pad]
MultiTransform.Shape = Pad.Shape
Body.addObject(MultiTransform)
Doc.recompute()
Mirrored = Doc.addObject("PartDesign::Mirrored","Mirrored")
Mirrored.MirrorPlane = (Doc.getObject('XY_Plane'), [''])
Body.addObject(Mirrored)
Mirrored2 = Doc.addObject("PartDesign::Mirrored","Mirrored")
Mirrored2.MirrorPlane = (Doc.getObject('XZ_Plane'), [""])
Body.addObject(Mirrored2)
MultiTransform.Transformations = [Mirrored,Mirrored2]
Doc.recompute()
Fillet = Doc.addObject("PartDesign::Fillet","Fillet")
Fillet.Base = (MultiTransform, ['Face'+str(i+1) for i in range(2)])
Fillet.Radius = 3
Body.addObject(Fillet)
# Add a fillet here.
# Now do that copy thing...
Link = Doc.addObject('App::Link','Link001')
Link.setLink(Doc.Body)
Link.Label='Body001'
# Act
# There are properties on those objects with values
# Link.addProperty("App::PropertyInteger","test2","Table2")
# Assert
self.assertAlmostEqual(Body.Shape.Volume, 990)
self.assertAlmostEqual(Link.Shape.Volume, 990)
def testMultiTransformBody(self):
pass
# TODO: Someone who understands the second mode added to transform needs to
# write a test here. Maybe close to testMultiTransform but with
# self.Mirrored.TransformMode="Transform body" instead of
# self.Mirrored.TransformMode="Transform tools"
def tearDown(self):
#closing doc
FreeCAD.closeDocument("PartDesignTestMultiTransform")

View File

@@ -631,13 +631,14 @@ class TestTopologicalNamingProblem(unittest.TestCase):
# Arrange
body = self.Doc.addObject('PartDesign::Body', 'Body')
sketch = self.Doc.addObject('Sketcher::SketchObject', 'Sketch')
TestSketcherApp.CreateRectangleSketch(sketch, (0, 0), (1, 1))
TestSketcherApp.CreateRectangleSketch(sketch, (0,0), (1,1))
if body.Shape.ElementMapVersion == "": # Should be '4' as of Mar 2023.
return
# Act
helix = self.Doc.addObject('PartDesign::AdditiveHelix', 'Helix')
helix.Profile = sketch
helix.ReferenceAxis = (self.Doc.getObject('Sketch'), ['V_Axis'])
helix.ReferenceAxis = (self.Doc.getObject('Sketch'), ['N_Axis'])
# helix.Mode = 0
body.addObject(sketch)
body.addObject(helix)
self.Doc.recompute()
@@ -646,8 +647,17 @@ class TestTopologicalNamingProblem(unittest.TestCase):
self.assertGreaterEqual(body.Shape.childShapes()[0].ElementMapSize, 26)
revMap = body.Shape.childShapes()[0].ElementReverseMap
self.assertEqual(self.countFacesEdgesVertexes(revMap), (6, 12, 8))
volume = 9.424696540407776 # TODO: math formula to calc this.
self.assertAlmostEqual(helix.Shape.Volume, volume)
Radius = 0 # Rectangle is on the axis, but wouldn't matter regardless here
Area = Part.Face(sketch.Shape).Area
# General helix formula; not actually used here since devolves to just the
# height in this orientation.
helixLength = (helix.Height.Value / helix.Pitch.Value *
math.sqrt( (math.pi * Radius) ** 2 + helix.Pitch.Value ** 2))
Volume = Area * helixLength
self.assertAlmostEqual(Area, 1)
self.assertAlmostEqual(helixLength, helix.Height.Value)
self.assertAlmostEqual(helix.Shape.Volume, Volume, 2)
self.assertEqual(body.Shape.ElementMapSize,26)
def testPartDesignElementMapPocket(self):
# Arrange