Salome HOME
Issue #2024: Redesign of circle and arc of circle
[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 }
123
124 void SketchSolver_ConstraintMirror::notify(const FeaturePtr& theFeature,
125                                            PlaneGCSSolver_Update*)
126 {
127   if (myFeatures.find(theFeature) == myFeatures.end())
128     return; // the feature is not used by constraint => nothing to update
129   adjustConstraint();
130 }
131
132 void SketchSolver_ConstraintMirror::blockEvents(bool isBlocked)
133 {
134   std::set<FeaturePtr>::iterator anIt = myFeatures.begin();
135   for (; anIt != myFeatures.end(); ++anIt)
136     (*anIt)->data()->blockSendAttributeUpdated(isBlocked);
137
138   SketchSolver_Constraint::blockEvents(isBlocked);
139 }
140
141
142
143
144 // =================   Auxiliary functions   ==================================
145 void mirrorPoints(const std::shared_ptr<GeomAPI_Lin2d>& theMirrorLine,
146                   const AttributePoint2DPtr& theOriginal,
147                   const AttributePoint2DPtr& theMirrored)
148 {
149   std::shared_ptr<GeomAPI_Pnt2d> anOriginal = theOriginal->pnt();
150   std::shared_ptr<GeomAPI_Pnt2d> aPtOnLine = theMirrorLine->project(anOriginal);
151   std::shared_ptr<GeomAPI_XY> aPerp = aPtOnLine->xy()->decreased(anOriginal->xy());
152   theMirrored->setValue(anOriginal->x() + aPerp->x() * 2.0, anOriginal->y() + aPerp->y() * 2.0);
153 }
154
155 void mirrorEntities(const std::shared_ptr<GeomAPI_Lin2d>& theMirrorLine,
156                     const FeaturePtr& theOriginal,
157                     const FeaturePtr& theMirrored)
158 {
159   std::list<AttributePtr> aPoints0 =
160       theOriginal->data()->attributes(GeomDataAPI_Point2D::typeId());
161   std::list<AttributePtr> aPoints1 =
162       theMirrored->data()->attributes(GeomDataAPI_Point2D::typeId());
163
164   // process specific features
165   if (theOriginal->getKind() == SketchPlugin_Arc::ID()) {
166     // orientation of arc
167     theMirrored->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(
168         !theOriginal->boolean(SketchPlugin_Arc::REVERSED_ID())->value());
169   } else if (theOriginal->getKind() == SketchPlugin_Circle::ID()) {
170     // radius of the circle
171     theMirrored->real(SketchPlugin_Circle::RADIUS_ID())->setValue(
172         theOriginal->real(SketchPlugin_Circle::RADIUS_ID())->value());
173   }
174
175   // mirror all initialized points of features
176   std::list<AttributePtr>::iterator anIt0, anIt1;
177   for (anIt0 = aPoints0.begin(), anIt1 = aPoints1.begin();
178        anIt0 != aPoints0.end() && anIt1 != aPoints1.end(); ++anIt0, ++anIt1) {
179     AttributePoint2DPtr aPt0 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt0);
180     AttributePoint2DPtr aPt1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt1);
181     if (aPt0->isInitialized() && aPt1->isInitialized())
182       mirrorPoints(theMirrorLine, aPt0, aPt1);
183   }
184 }