Skip to content

Commit bcf54d3

Browse files
authored
Merge pull request FreeCAD#12885 from bgbsww/bgbsww-toponamingAttachment
Toponaming/Part: Bring over attacher differences
2 parents 0def330 + 9aadc25 commit bcf54d3

File tree

7 files changed

+1479
-918
lines changed

7 files changed

+1479
-918
lines changed

src/Mod/Part/App/Attacher.cpp

+1,303-871
Large diffs are not rendered by default.

src/Mod/Part/App/Attacher.h

+38-6
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@
3030

3131
#include <GProp_GProps.hxx>
3232

33+
#include <App/DocumentObserver.h>
3334
#include <App/GeoFeature.h>
3435
#include <App/PropertyLinks.h>
36+
#include <App/PropertyStandard.h>
3537
#include <Base/Exception.h>
3638
#include <Base/Placement.h>
3739

@@ -222,7 +224,17 @@ class PartExport AttachEngine : public Base::BaseClass
222224
const Base::Placement &attachmentOffset = Base::Placement());
223225
virtual void setUp(const AttachEngine &another);
224226
virtual AttachEngine* copy() const = 0;
225-
virtual Base::Placement calculateAttachedPlacement(const Base::Placement& origPlacement) const = 0;
227+
228+
Base::Placement calculateAttachedPlacement(
229+
const Base::Placement &origPlacement, bool *subChanged=0);
230+
231+
virtual Base::Placement _calculateAttachedPlacement(
232+
const std::vector<App::DocumentObject*> &objs,
233+
const std::vector<std::string> &subs,
234+
const Base::Placement &origPlacement) const = 0;
235+
236+
void setReferences(const App::PropertyLinkSubList &references);
237+
void setReferences(const std::vector<App::SubObjectT> &references);
226238

227239
/**
228240
* @brief placementFactory calculates placement from Z axis direction,
@@ -348,6 +360,9 @@ class PartExport AttachEngine : public Base::BaseClass
348360

349361
static GProp_GProps getInertialPropsOfShape(const std::vector<const TopoDS_Shape*> &shapes);
350362

363+
std::vector<App::DocumentObject*> getRefObjects() const;
364+
const std::vector<std::string> &getSubValues() const {return subnames;}
365+
351366
/**
352367
* @brief verifyReferencesAreSafe: checks if pointers in references still
353368
* point to objects contained in open documents. This guarantees the links
@@ -362,6 +377,10 @@ class PartExport AttachEngine : public Base::BaseClass
362377

363378
public: //members
364379
App::PropertyLinkSubList references;
380+
std::string docName;
381+
std::vector<std::string> objNames;
382+
std::vector<std::string> subnames;
383+
std::vector<std::string> shadowSubs;
365384

366385
eMapMode mapMode = mmDeactivated;
367386
bool mapReverse = false;
@@ -405,7 +424,8 @@ class PartExport AttachEngine : public Base::BaseClass
405424
ret.push_back(rt4);
406425
return ret;
407426
}
408-
static void readLinks(const App::PropertyLinkSubList &references, std::vector<App::GeoFeature *> &geofs,
427+
static void readLinks(const std::vector<App::DocumentObject*> &objs,
428+
const std::vector<std::string> &subs, std::vector<App::GeoFeature *> &geofs,
409429
std::vector<const TopoDS_Shape*>& shapes, std::vector<TopoDS_Shape> &storage,
410430
std::vector<eRefType> &types);
411431

@@ -420,7 +440,10 @@ class PartExport AttachEngine3D : public AttachEngine
420440
public:
421441
AttachEngine3D();
422442
AttachEngine3D* copy() const override;
423-
Base::Placement calculateAttachedPlacement(const Base::Placement& origPlacement) const override;
443+
Base::Placement _calculateAttachedPlacement(
444+
const std::vector<App::DocumentObject*> &objs,
445+
const std::vector<std::string> &subs,
446+
const Base::Placement &origPlacement) const override;
424447
private:
425448
double calculateFoldAngle(gp_Vec axA, gp_Vec axB, gp_Vec edA, gp_Vec edB) const;
426449
};
@@ -432,7 +455,10 @@ class PartExport AttachEnginePlane : public AttachEngine
432455
public:
433456
AttachEnginePlane();
434457
AttachEnginePlane* copy() const override;
435-
Base::Placement calculateAttachedPlacement(const Base::Placement& origPlacement) const override;
458+
Base::Placement _calculateAttachedPlacement(
459+
const std::vector<App::DocumentObject*> &objs,
460+
const std::vector<std::string> &subs,
461+
const Base::Placement &origPlacement) const override;
436462
};
437463

438464
//attacher specialized for datum lines
@@ -442,7 +468,10 @@ class PartExport AttachEngineLine : public AttachEngine
442468
public:
443469
AttachEngineLine();
444470
AttachEngineLine* copy() const override;
445-
Base::Placement calculateAttachedPlacement(const Base::Placement& origPlacement) const override;
471+
Base::Placement _calculateAttachedPlacement(
472+
const std::vector<App::DocumentObject*> &objs,
473+
const std::vector<std::string> &subs,
474+
const Base::Placement &origPlacement) const override;
446475
};
447476

448477
//attacher specialized for datum points
@@ -452,7 +481,10 @@ class PartExport AttachEnginePoint : public AttachEngine
452481
public:
453482
AttachEnginePoint();
454483
AttachEnginePoint* copy() const override;
455-
Base::Placement calculateAttachedPlacement(const Base::Placement& origPlacement) const override;
484+
Base::Placement _calculateAttachedPlacement(
485+
const std::vector<App::DocumentObject*> &objs,
486+
const std::vector<std::string> &subs,
487+
const Base::Placement &origPlacement) const override;
456488

457489
private:
458490
gp_Pnt getProximityPoint(eMapMode mode, const TopoDS_Shape& s1, const TopoDS_Shape& s2) const;

src/Mod/Part/App/TopoShape.cpp

+9-40
Original file line numberDiff line numberDiff line change
@@ -336,50 +336,19 @@ Data::Segment* TopoShape::getSubElement(const char* Type, unsigned long n) const
336336
return new ShapeSegment(getSubShape(temp.c_str()));
337337
}
338338

339-
TopoDS_Shape TopoShape::getSubShape(const char* Type, bool silent) const
340-
{
341-
auto res = shapeTypeAndIndex(Type);
342-
return getSubShape(res.first,res.second,silent);
339+
TopoDS_Shape TopoShape::getSubShape(const char* Type, bool silent) const {
340+
TopoShape s(*this);
341+
s.Tag = 0;
342+
return s.getSubTopoShape(Type,silent).getShape();
343343
}
344344

345-
TopoDS_Shape TopoShape::getSubShape(TopAbs_ShapeEnum type, int index, bool silent) const
346-
{
347-
if(index <= 0) {
348-
if(silent)
349-
return {};
350-
// TODO: Is this message clear? Should we complain about the negative index instead
351-
Standard_Failure::Raise("Unsupported sub-shape type");
352-
}
353-
354-
if (this->_Shape.IsNull()) {
355-
if(silent)
356-
return {};
357-
Standard_Failure::Raise("Cannot get sub-shape from empty shape");
358-
}
359-
360-
try {
361-
if(type == TopAbs_SHAPE) {
362-
int i=1;
363-
for(TopoDS_Iterator it(_Shape);it.More();it.Next(),++i) {
364-
if(i == index)
365-
return it.Value();
366-
}
367-
} else {
368-
TopTools_IndexedMapOfShape anIndices;
369-
TopExp::MapShapes(this->_Shape, type, anIndices);
370-
if(index <= anIndices.Extent())
371-
return anIndices.FindKey(index);
372-
}
373-
} catch(Standard_Failure &) {
374-
if(silent)
375-
return {};
376-
throw;
377-
}
378-
if(!silent)
379-
Standard_Failure::Raise("Index out of bound");
380-
return {};
345+
TopoDS_Shape TopoShape::getSubShape(TopAbs_ShapeEnum type, int idx, bool silent) const {
346+
TopoShape s(*this);
347+
s.Tag = 0;
348+
return s.getSubTopoShape(type,idx,silent).getShape();
381349
}
382350

351+
383352
unsigned long TopoShape::countSubShapes(const char* Type) const
384353
{
385354
if(!Type)

src/Mod/Part/TestPartApp.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,9 @@ def testSubElements(self):
170170
box.getElement("InvalidName")
171171
with self.assertRaises(ValueError):
172172
box.getElement("Face6_abc")
173-
with self.assertRaises(Part.OCCError):
173+
# getSubTopoShape now catches this before it gets to OCC, so the error changes:
174+
# with self.assertRaises(Part.OCCError):
175+
with self.assertRaises(IndexError):
174176
box.getElement("Face7")
175177

176178
def tearDown(self):

tests/src/Mod/Part/App/Attacher.cpp

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// SPDX-License-Identifier: LGPL-2.1-or-later
2+
3+
#include "gtest/gtest.h"
4+
#include "PartTestHelpers.h"
5+
6+
#include <src/App/InitApplication.h>
7+
#include <App/Document.h>
8+
#include <Mod/Part/App/Attacher.h>
9+
10+
using namespace Part;
11+
using namespace Attacher;
12+
using namespace PartTestHelpers;
13+
14+
/*
15+
* Testing note: It looks like there are about 45 different attachment modes, and these tests all
16+
* only look at one of them - to prove that adding elementMap code doesn't break anything. A
17+
* comprehensive test of the Attacher would definitely want to try many more code paths.
18+
*/
19+
20+
class AttacherTest: public ::testing::Test, public PartTestHelpers::PartTestHelperClass
21+
{
22+
protected:
23+
static void SetUpTestSuite()
24+
{
25+
tests::initApplication();
26+
}
27+
28+
void SetUp() override
29+
{
30+
createTestDoc();
31+
_boxes[1]->MapReversed.setValue(false);
32+
_boxes[1]->AttachmentSupport.setValue(_boxes[0]);
33+
_boxes[1]->MapPathParameter.setValue(0.0);
34+
_boxes[1]->MapMode.setValue("ObjectXY"); // There are lots of attachment modes!
35+
_boxes[1]->recomputeFeature();
36+
}
37+
38+
void TearDown() override
39+
{
40+
App::GetApplication().closeDocument(_docName.c_str());
41+
}
42+
43+
App::Document* getDocument() const
44+
{
45+
return _doc;
46+
}
47+
48+
protected:
49+
};
50+
51+
TEST_F(AttacherTest, TestSetReferences)
52+
{
53+
auto& attacher = _boxes[1]->attacher();
54+
EXPECT_EQ(attacher.getRefObjects().size(), 1);
55+
}
56+
57+
TEST_F(AttacherTest, TestSuggestMapModes)
58+
{
59+
auto& attacher = _boxes[1]->attacher();
60+
SuggestResult result;
61+
attacher.suggestMapModes(result);
62+
EXPECT_EQ(result.allApplicableModes.size(), 4);
63+
EXPECT_EQ(result.allApplicableModes[0], mmObjectXY);
64+
EXPECT_EQ(result.allApplicableModes[1], mmObjectXZ);
65+
EXPECT_EQ(result.allApplicableModes[2], mmObjectYZ);
66+
EXPECT_EQ(result.allApplicableModes[3], mmInertialCS);
67+
}
68+
69+
TEST_F(AttacherTest, TestGetShapeType)
70+
{
71+
auto& attacher = _boxes[1]->attacher();
72+
auto subObjects = _boxes[1]->getSubObjects();
73+
auto shapeType = attacher.getShapeType(_boxes[1], "Vertex2");
74+
EXPECT_EQ(shapeType, TopAbs_COMPSOLID);
75+
}
76+
77+
TEST_F(AttacherTest, TestGetInertialPropsOfShape)
78+
{
79+
auto& attacher = _boxes[1]->attacher();
80+
std::vector<const TopoDS_Shape*> result;
81+
auto faces = _boxes[1]->Shape.getShape().getSubShapes(TopAbs_FACE);
82+
result.emplace_back(&faces[0]);
83+
auto shapeType = attacher.getInertialPropsOfShape(result);
84+
EXPECT_EQ(result.size(), 1);
85+
EXPECT_EQ(shapeType.Mass(), 6.0);
86+
}
87+
88+
TEST_F(AttacherTest, TestGetRefObjects)
89+
{
90+
auto& attacher = _boxes[1]->attacher();
91+
auto docObjects = attacher.getRefObjects();
92+
EXPECT_EQ(docObjects.size(), 1);
93+
EXPECT_STREQ(docObjects.front()->getNameInDocument(), "Part__Box");
94+
}
95+
96+
TEST_F(AttacherTest, TestCalculateAttachedPlacement)
97+
{
98+
auto& attacher = _boxes[1]->attacher();
99+
const Base::Placement orig;
100+
auto placement = attacher.calculateAttachedPlacement(orig);
101+
EXPECT_EQ(orig.getPosition().x, 0);
102+
EXPECT_EQ(orig.getPosition().y, 0);
103+
EXPECT_EQ(orig.getPosition().z, 0);
104+
EXPECT_EQ(placement.getPosition().x, 0);
105+
EXPECT_EQ(placement.getPosition().y, 0);
106+
EXPECT_EQ(placement.getPosition().z, 0);
107+
}

tests/src/Mod/Part/App/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
target_sources(
33
Part_tests_run
44
PRIVATE
5+
${CMAKE_CURRENT_SOURCE_DIR}/Attacher.cpp
56
${CMAKE_CURRENT_SOURCE_DIR}/BRepMesh.cpp
67
${CMAKE_CURRENT_SOURCE_DIR}/FeatureChamfer.cpp
78
${CMAKE_CURRENT_SOURCE_DIR}/FeatureCompound.cpp

tests/src/Mod/Part/App/TopoShape.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: LGPL-2.1-or-later
22

33
#include "gtest/gtest.h"
4+
#include "PartTestHelpers.h"
45
#include <Mod/Part/App/TopoShape.h>
56

67
// clang-format off
@@ -87,4 +88,21 @@ TEST(TopoShape, TestTypeNull)
8788
EXPECT_EQ(Part::TopoShape::getTypeAndIndex(nullptr),
8889
std::make_pair(std::string(), 0UL));
8990
}
91+
92+
TEST(TopoShape, TestGetSubshape)
93+
{
94+
// Arrange
95+
auto [cube1, cube2] = PartTestHelpers::CreateTwoTopoShapeCubes();
96+
// Act
97+
auto face = cube1.getSubShape("Face2");
98+
auto vertex = cube2.getSubShape(TopAbs_VERTEX,2);
99+
auto silentFail = cube1.getSubShape("NotThere", true);
100+
// Assert
101+
EXPECT_EQ(face.ShapeType(), TopAbs_FACE);
102+
EXPECT_EQ(vertex.ShapeType(), TopAbs_VERTEX);
103+
EXPECT_TRUE(silentFail.IsNull());
104+
EXPECT_THROW(cube1.getSubShape("Face7"), Base::IndexError); // Out of range
105+
EXPECT_THROW(cube1.getSubShape("WOOHOO", false), Base::ValueError); // Invalid
106+
}
107+
90108
// clang-format on

0 commit comments

Comments
 (0)