Salome HOME
1c6e61f18e1a517afb8ba73e21e3ddad482bfb6b
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintMirror.cpp
1 // Copyright (C) 2014-2024  CEA, EDF
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include <SketchSolver_ConstraintMirror.h>
21 #include <SketchSolver_Error.h>
22
23 #include <PlaneGCSSolver_Tools.h>
24 #include <PlaneGCSSolver_UpdateFeature.h>
25
26 #include <GeomAPI_Lin2d.h>
27 #include <GeomAPI_Pnt2d.h>
28 #include <GeomAPI_XY.h>
29 #include <GeomDataAPI_Point2D.h>
30 #include <ModelAPI_AttributeRefList.h>
31 #include <SketchPlugin_Arc.h>
32 #include <SketchPlugin_Circle.h>
33 #include <SketchPlugin_EllipticArc.h>
34
35
36 static void mirrorPoints(const std::shared_ptr<GeomAPI_Lin2d>& theMirrorLine,
37                          const AttributePoint2DPtr& theOriginal,
38                          const AttributePoint2DPtr& theMirrored);
39
40 static void mirrorEntities(const std::shared_ptr<GeomAPI_Lin2d>& theMirrorLine,
41                            const FeaturePtr& theOriginal,
42                            const FeaturePtr& theMirrored);
43
44
45
46 void SketchSolver_ConstraintMirror::getAttributes(
47     EntityWrapperPtr&,
48     std::vector<EntityWrapperPtr>&)
49 {
50   AttributeRefAttrPtr aMirLineRefAttr =
51       myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
52   if (!aMirLineRefAttr || !aMirLineRefAttr->isInitialized() || !aMirLineRefAttr->isObject()) {
53     myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
54     return;
55   }
56
57   FeaturePtr aMirrorLine = ModelAPI_Feature::feature(aMirLineRefAttr->object());
58   myFeatures.insert(aMirrorLine);
59
60   myType = TYPE(myBaseConstraint);
61   myStorage->update(aMirrorLine);
62
63
64   AttributeRefListPtr aBaseRefList =
65       myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_B());
66   AttributeRefListPtr aMirroredRefList =
67       myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_C());
68   myNumberOfObjects = aMirroredRefList->size();
69   if (!aBaseRefList || !aMirroredRefList) {
70     myErrorMsg = SketchSolver_Error::INCORRECT_MIRROR_ATTRIBUTE();
71     return;
72   }
73
74   // store only original entities because mirrored ones
75   // will be updated separately in adjustConstraint
76   std::list<ObjectPtr> aList = aBaseRefList->list();
77   std::list<ObjectPtr>::iterator anIt = aList.begin();
78   for (; anIt != aList.end(); ++anIt) {
79     FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
80     if (aFeature) {
81       myStorage->update(aFeature);
82       myFeatures.insert(aFeature);
83     }
84   }
85   // add mirrored features to the list
86   aList = aMirroredRefList->list();
87   for (anIt = aList.begin(); anIt != aList.end(); ++anIt) {
88     FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
89     if (aFeature)
90       myFeatures.insert(aFeature);
91   }
92 }
93
94 void SketchSolver_ConstraintMirror::process()
95 {
96   cleanErrorMsg();
97   if (!myBaseConstraint || !myStorage) {
98     // Not enough parameters are assigned
99     return;
100   }
101
102   EntityWrapperPtr aMirrorLine;
103   std::vector<EntityWrapperPtr> aBaseList;
104   getAttributes(aMirrorLine, aBaseList);
105   if (!myErrorMsg.empty())
106     return;
107
108   adjustConstraint();
109   myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateFeature::GROUP());
110 }
111
112
113 void SketchSolver_ConstraintMirror::update()
114 {
115   cleanErrorMsg();
116   remove();
117   process();
118 }
119
120 void SketchSolver_ConstraintMirror::adjustConstraint()
121 {
122   AttributeRefAttrPtr aMirrLineRefAttr =
123       myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
124   std::shared_ptr<GeomAPI_Lin2d> aMirrorLine =
125       PlaneGCSSolver_Tools::line(ModelAPI_Feature::feature(aMirrLineRefAttr->object()));
126
127   AttributeRefListPtr aBaseRefList =
128       myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_B());
129   AttributeRefListPtr aMirroredRefList =
130       myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_C());
131
132   std::list<ObjectPtr> aBaseList = aBaseRefList->list();
133   std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
134   std::list<ObjectPtr>::iterator aBIt, aMIt;
135   for (aBIt = aBaseList.begin(), aMIt = aMirroredList.begin();
136        aBIt != aBaseList.end() && aMIt != aMirroredList.end();
137        ++aBIt, ++aMIt) {
138     FeaturePtr aBase = ModelAPI_Feature::feature(*aBIt);
139     FeaturePtr aMirrored = ModelAPI_Feature::feature(*aMIt);
140     mirrorEntities(aMirrorLine, aBase, aMirrored);
141
142     // update mirrored entity if it exists in the storage
143     if (myStorage->entity(aMirrored))
144       myStorage->update(aMirrored);
145   }
146 }
147
148 void SketchSolver_ConstraintMirror::notify(const FeaturePtr& theFeature,
149                                            PlaneGCSSolver_Update*)
150 {
151   if (myFeatures.find(theFeature) == myFeatures.end())
152     return; // the feature is not used by constraint => nothing to update
153   adjustConstraint();
154 }
155
156 void SketchSolver_ConstraintMirror::blockEvents(bool isBlocked)
157 {
158   std::set<FeaturePtr>::iterator anIt = myFeatures.begin();
159   for (; anIt != myFeatures.end(); ++anIt)
160     (*anIt)->data()->blockSendAttributeUpdated(isBlocked);
161
162   SketchSolver_Constraint::blockEvents(isBlocked);
163 }
164
165
166
167
168 // =================   Auxiliary functions   ==================================
169 void mirrorPoints(const std::shared_ptr<GeomAPI_Lin2d>& theMirrorLine,
170                   const AttributePoint2DPtr& theOriginal,
171                   const AttributePoint2DPtr& theMirrored)
172 {
173   std::shared_ptr<GeomAPI_Pnt2d> anOriginal = theOriginal->pnt();
174   std::shared_ptr<GeomAPI_Pnt2d> aPtOnLine = theMirrorLine->project(anOriginal);
175   std::shared_ptr<GeomAPI_XY> aPerp = aPtOnLine->xy()->decreased(anOriginal->xy());
176   theMirrored->setValue(anOriginal->x() + aPerp->x() * 2.0, anOriginal->y() + aPerp->y() * 2.0);
177 }
178
179 void mirrorEntities(const std::shared_ptr<GeomAPI_Lin2d>& theMirrorLine,
180                     const FeaturePtr& theOriginal,
181                     const FeaturePtr& theMirrored)
182 {
183   std::list<AttributePtr> aPoints0 =
184       theOriginal->data()->attributes(GeomDataAPI_Point2D::typeId());
185   std::list<AttributePtr> aPoints1 =
186       theMirrored->data()->attributes(GeomDataAPI_Point2D::typeId());
187
188   // process specific features
189   if (theOriginal->getKind() == SketchPlugin_Arc::ID()) {
190     // orientation of arc
191     theMirrored->boolean(SketchPlugin_Arc::REVERSED_ID())->setValue(
192         !theOriginal->boolean(SketchPlugin_Arc::REVERSED_ID())->value());
193   } else if (theOriginal->getKind() == SketchPlugin_Circle::ID()) {
194     // radius of the circle
195     theMirrored->real(SketchPlugin_Circle::RADIUS_ID())->setValue(
196         theOriginal->real(SketchPlugin_Circle::RADIUS_ID())->value());
197   }
198   else if (theOriginal->getKind() == SketchPlugin_EllipticArc::ID()) {
199     // orientation of arc
200     theMirrored->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->setValue(
201         !theOriginal->boolean(SketchPlugin_EllipticArc::REVERSED_ID())->value());
202   }
203
204   // mirror all initialized points of features
205   std::list<AttributePtr>::iterator anIt0, anIt1;
206   for (anIt0 = aPoints0.begin(), anIt1 = aPoints1.begin();
207        anIt0 != aPoints0.end() && anIt1 != aPoints1.end(); ++anIt0, ++anIt1) {
208     AttributePoint2DPtr aPt0 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt0);
209     AttributePoint2DPtr aPt1 = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt1);
210     if (aPt0->isInitialized() && aPt1->isInitialized())
211       mirrorPoints(theMirrorLine, aPt0, aPt1);
212   }
213 }