Salome HOME
Issue #2077: mirror constraint is destroyed
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintMirror.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 #include <SketchSolver_ConstraintMirror.h>
4 #include <SketchSolver_Error.h>
5
6 #include <PlaneGCSSolver_Tools.h>
7 #include <PlaneGCSSolver_UpdateFeature.h>
8
9 #include <GeomAPI_XY.h>
10 #include <GeomDataAPI_Point2D.h>
11 #include <ModelAPI_AttributeRefList.h>
12 #include <SketchPlugin_Arc.h>
13 #include <SketchPlugin_Circle.h>
14
15
16 static void mirrorPoints(const std::shared_ptr<GeomAPI_Lin2d>& theMirrorLine,
17                          const AttributePoint2DPtr& theOriginal,
18                          const AttributePoint2DPtr& theMirrored);
19
20 static void mirrorEntities(const std::shared_ptr<GeomAPI_Lin2d>& theMirrorLine,
21                            const FeaturePtr& theOriginal,
22                            const FeaturePtr& theMirrored);
23
24
25
26 void SketchSolver_ConstraintMirror::getAttributes(
27     EntityWrapperPtr&,
28     std::vector<EntityWrapperPtr>&)
29 {
30   AttributeRefAttrPtr aMirLineRefAttr =
31       myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
32   if (!aMirLineRefAttr || !aMirLineRefAttr->isInitialized() || !aMirLineRefAttr->isObject()) {
33     myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
34     return;
35   }
36
37   FeaturePtr aMirrorLine = ModelAPI_Feature::feature(aMirLineRefAttr->object());
38   myFeatures.insert(aMirrorLine);
39
40   myType = TYPE(myBaseConstraint);
41   myStorage->update(aMirrorLine);
42
43
44   AttributeRefListPtr aBaseRefList =
45       myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_B());
46   AttributeRefListPtr aMirroredRefList =
47       myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_C());
48   myNumberOfObjects = aMirroredRefList->size();
49   if (!aBaseRefList || !aMirroredRefList) {
50     myErrorMsg = SketchSolver_Error::INCORRECT_MIRROR_ATTRIBUTE();
51     return;
52   }
53
54   // store only original entities because mirrored ones
55   // will be updated separately in adjustConstraint
56   std::list<ObjectPtr> aList = aBaseRefList->list();
57   std::list<ObjectPtr>::iterator anIt = aList.begin();
58   for (; anIt != aList.end(); ++anIt) {
59     FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
60     if (aFeature) {
61       myStorage->update(aFeature);
62       myFeatures.insert(aFeature);
63     }
64   }
65 }
66
67 void SketchSolver_ConstraintMirror::process()
68 {
69   cleanErrorMsg();
70   if (!myBaseConstraint || !myStorage) {
71     // Not enough parameters are assigned
72     return;
73   }
74
75   EntityWrapperPtr aMirrorLine;
76   std::vector<EntityWrapperPtr> aBaseList;
77   getAttributes(aMirrorLine, aBaseList);
78   if (!myErrorMsg.empty())
79     return;
80
81   adjustConstraint();
82   myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateFeature::GROUP());
83 }
84
85
86 void SketchSolver_ConstraintMirror::update()
87 {
88   cleanErrorMsg();
89   adjustConstraint();
90 }
91
92 void SketchSolver_ConstraintMirror::adjustConstraint()
93 {
94   AttributeRefAttrPtr aMirrLineRefAttr =
95       myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
96   std::shared_ptr<GeomAPI_Lin2d> aMirrorLine =
97       PlaneGCSSolver_Tools::line(ModelAPI_Feature::feature(aMirrLineRefAttr->object()));
98
99   AttributeRefListPtr aBaseRefList =
100       myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_B());
101   AttributeRefListPtr aMirroredRefList =
102       myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_C());
103
104   std::list<ObjectPtr> aBaseList = aBaseRefList->list();
105   std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
106   std::list<ObjectPtr>::iterator aBIt, aMIt;
107   for (aBIt = aBaseList.begin(), aMIt = aMirroredList.begin();
108        aBIt != aBaseList.end() && aMIt != aMirroredList.end();
109        ++aBIt, ++aMIt) {
110     FeaturePtr aBase = ModelAPI_Feature::feature(*aBIt);
111     FeaturePtr aMirrored = ModelAPI_Feature::feature(*aMIt);
112     mirrorEntities(aMirrorLine, aBase, aMirrored);
113
114     // update mirrored entity if it exists in the storage
115     if (myStorage->entity(aMirrored))
116       myStorage->update(aMirrored);
117   }
118 }
119
120 void SketchSolver_ConstraintMirror::notify(const FeaturePtr& theFeature,
121                                            PlaneGCSSolver_Update*)
122 {
123   if (myFeatures.find(theFeature) == myFeatures.end())
124     return; // the feature is not used by constraint => nothing to update
125   adjustConstraint();
126 }
127
128 void SketchSolver_ConstraintMirror::blockEvents(bool isBlocked)
129 {
130   std::set<FeaturePtr>::iterator anIt = myFeatures.begin();
131   for (; anIt != myFeatures.end(); ++anIt)
132     (*anIt)->data()->blockSendAttributeUpdated(isBlocked);
133
134   AttributeRefListPtr aMirroredRefList =
135       myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_C());
136   std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
137   std::list<ObjectPtr>::iterator aMIt = aMirroredList.begin();
138   for (; aMIt != aMirroredList.end(); ++aMIt) {
139     FeaturePtr aMirrored = ModelAPI_Feature::feature(*aMIt);
140     aMirrored->data()->blockSendAttributeUpdated(isBlocked);
141   }
142
143
144   SketchSolver_Constraint::blockEvents(isBlocked);
145 }
146
147
148
149
150 // =================   Auxiliary functions   ==================================
151 void mirrorPoints(const std::shared_ptr<GeomAPI_Lin2d>& theMirrorLine,
152                   const AttributePoint2DPtr& theOriginal,
153                   const AttributePoint2DPtr& theMirrored)
154 {
155   std::shared_ptr<GeomAPI_Pnt2d> anOriginal = theOriginal->pnt();
156   std::shared_ptr<GeomAPI_Pnt2d> aPtOnLine = theMirrorLine->project(anOriginal);
157   std::shared_ptr<GeomAPI_XY> aPerp = aPtOnLine->xy()->decreased(anOriginal->xy());
158   theMirrored->setValue(anOriginal->x() + aPerp->x() * 2.0, anOriginal->y() + aPerp->y() * 2.0);
159 }
160
161 void mirrorEntities(const std::shared_ptr<GeomAPI_Lin2d>& theMirrorLine,
162                     const FeaturePtr& theOriginal,
163                     const FeaturePtr& theMirrored)
164 {
165   std::list<AttributePtr> aPoints0 =
166       theOriginal->data()->attributes(GeomDataAPI_Point2D::typeId());
167   std::list<AttributePtr> aPoints1 =
168       theMirrored->data()->attributes(GeomDataAPI_Point2D::typeId());
169
170   // process specific features
171   if (theOriginal->getKind() == SketchPlugin_Arc::ID()) {
172     // orientation of arc
173     theMirrored->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(
174         !theOriginal->boolean(SketchPlugin_Arc::REVERSED_ID())->value());
175   } else if (theOriginal->getKind() == SketchPlugin_Circle::ID()) {
176     // radius of the circle
177     theMirrored->real(SketchPlugin_Circle::RADIUS_ID())->setValue(
178         theOriginal->real(SketchPlugin_Circle::RADIUS_ID())->value());
179   }
180
181   // mirror all initialized points of features
182   std::list<AttributePtr>::iterator anIt0, anIt1;
183   for (anIt0 = aPoints0.begin(), anIt1 = aPoints1.begin();
184        anIt0 != aPoints0.end() && anIt1 != aPoints1.end(); ++anIt0, ++anIt1) {
185     AttributePoint2DPtr aPt0 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt0);
186     AttributePoint2DPtr aPt1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt1);
187     if (aPt0->isInitialized() && aPt1->isInitialized())
188       mirrorPoints(theMirrorLine, aPt0, aPt1);
189   }
190 }