Salome HOME
Merge branch 'master' into cgt/devCEA
[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   // add mirrored features to the list
66   aList = aMirroredRefList->list();
67   for (anIt = aList.begin(); anIt != aList.end(); ++anIt) {
68     FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
69     if (aFeature)
70       myFeatures.insert(aFeature);
71   }
72 }
73
74 void SketchSolver_ConstraintMirror::process()
75 {
76   cleanErrorMsg();
77   if (!myBaseConstraint || !myStorage) {
78     // Not enough parameters are assigned
79     return;
80   }
81
82   EntityWrapperPtr aMirrorLine;
83   std::vector<EntityWrapperPtr> aBaseList;
84   getAttributes(aMirrorLine, aBaseList);
85   if (!myErrorMsg.empty())
86     return;
87
88   adjustConstraint();
89   myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateFeature::GROUP());
90 }
91
92
93 void SketchSolver_ConstraintMirror::update()
94 {
95   cleanErrorMsg();
96   remove();
97   process();
98 }
99
100 void SketchSolver_ConstraintMirror::adjustConstraint()
101 {
102   AttributeRefAttrPtr aMirrLineRefAttr =
103       myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
104   std::shared_ptr<GeomAPI_Lin2d> aMirrorLine =
105       PlaneGCSSolver_Tools::line(ModelAPI_Feature::feature(aMirrLineRefAttr->object()));
106
107   AttributeRefListPtr aBaseRefList =
108       myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_B());
109   AttributeRefListPtr aMirroredRefList =
110       myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_C());
111
112   std::list<ObjectPtr> aBaseList = aBaseRefList->list();
113   std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
114   std::list<ObjectPtr>::iterator aBIt, aMIt;
115   for (aBIt = aBaseList.begin(), aMIt = aMirroredList.begin();
116        aBIt != aBaseList.end() && aMIt != aMirroredList.end();
117        ++aBIt, ++aMIt) {
118     FeaturePtr aBase = ModelAPI_Feature::feature(*aBIt);
119     FeaturePtr aMirrored = ModelAPI_Feature::feature(*aMIt);
120     mirrorEntities(aMirrorLine, aBase, aMirrored);
121
122     // update mirrored entity if it exists in the storage
123     if (myStorage->entity(aMirrored))
124       myStorage->update(aMirrored);
125   }
126 }
127
128 void SketchSolver_ConstraintMirror::notify(const FeaturePtr& theFeature,
129                                            PlaneGCSSolver_Update*)
130 {
131   if (myFeatures.find(theFeature) == myFeatures.end())
132     return; // the feature is not used by constraint => nothing to update
133   adjustConstraint();
134 }
135
136 void SketchSolver_ConstraintMirror::blockEvents(bool isBlocked)
137 {
138   std::set<FeaturePtr>::iterator anIt = myFeatures.begin();
139   for (; anIt != myFeatures.end(); ++anIt)
140     (*anIt)->data()->blockSendAttributeUpdated(isBlocked);
141
142   SketchSolver_Constraint::blockEvents(isBlocked);
143 }
144
145
146
147
148 // =================   Auxiliary functions   ==================================
149 void mirrorPoints(const std::shared_ptr<GeomAPI_Lin2d>& theMirrorLine,
150                   const AttributePoint2DPtr& theOriginal,
151                   const AttributePoint2DPtr& theMirrored)
152 {
153   std::shared_ptr<GeomAPI_Pnt2d> anOriginal = theOriginal->pnt();
154   std::shared_ptr<GeomAPI_Pnt2d> aPtOnLine = theMirrorLine->project(anOriginal);
155   std::shared_ptr<GeomAPI_XY> aPerp = aPtOnLine->xy()->decreased(anOriginal->xy());
156   theMirrored->setValue(anOriginal->x() + aPerp->x() * 2.0, anOriginal->y() + aPerp->y() * 2.0);
157 }
158
159 void mirrorEntities(const std::shared_ptr<GeomAPI_Lin2d>& theMirrorLine,
160                     const FeaturePtr& theOriginal,
161                     const FeaturePtr& theMirrored)
162 {
163   std::list<AttributePtr> aPoints0 =
164       theOriginal->data()->attributes(GeomDataAPI_Point2D::typeId());
165   std::list<AttributePtr> aPoints1 =
166       theMirrored->data()->attributes(GeomDataAPI_Point2D::typeId());
167
168   // process specific features
169   if (theOriginal->getKind() == SketchPlugin_Arc::ID()) {
170     // orientation of arc
171     theMirrored->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(
172         !theOriginal->boolean(SketchPlugin_Arc::REVERSED_ID())->value());
173   } else if (theOriginal->getKind() == SketchPlugin_Circle::ID()) {
174     // radius of the circle
175     theMirrored->real(SketchPlugin_Circle::RADIUS_ID())->setValue(
176         theOriginal->real(SketchPlugin_Circle::RADIUS_ID())->value());
177   }
178
179   // mirror all initialized points of features
180   std::list<AttributePtr>::iterator anIt0, anIt1;
181   for (anIt0 = aPoints0.begin(), anIt1 = aPoints1.begin();
182        anIt0 != aPoints0.end() && anIt1 != aPoints1.end(); ++anIt0, ++anIt1) {
183     AttributePoint2DPtr aPt0 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt0);
184     AttributePoint2DPtr aPt1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt1);
185     if (aPt0->isInitialized() && aPt1->isInitialized())
186       mirrorPoints(theMirrorLine, aPt0, aPt1);
187   }
188 }