Salome HOME
ff1c97321320d37b57f3afb311d3ce6c7249f30c
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_MacroRectangle.cpp
1 // Copyright (C) 2014-2020  CEA/DEN, EDF R&D
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 "SketchPlugin_MacroRectangle.h"
21 #include "SketchPlugin_Rectangle.h"
22 #include "SketchPlugin_Sketch.h"
23 #include "SketchPlugin_Tools.h"
24 #include "SketchPlugin_Line.h"
25
26 #include <ModelAPI_Data.h>
27 #include <ModelAPI_ResultConstruction.h>
28 #include <ModelAPI_AttributeSelection.h>
29 #include <ModelAPI_Validator.h>
30 #include <ModelAPI_AttributeString.h>
31 #include <ModelAPI_Session.h>
32 #include <ModelAPI_AttributeRefList.h>
33 #include <ModelAPI_AttributeRefAttr.h>
34 #include <ModelAPI_AttributeReference.h>
35 #include <ModelAPI_Events.h>
36
37 #include <GeomAlgoAPI_CompoundBuilder.h>
38 #include <GeomAlgoAPI_EdgeBuilder.h>
39 #include <GeomAlgoAPI_PointBuilder.h>
40
41 #include <GeomAPI_Pnt2d.h>
42
43 #include <cmath>
44
45 const double tolerance = 1e-7;
46
47
48 SketchPlugin_MacroRectangle::SketchPlugin_MacroRectangle()
49   : SketchPlugin_SketchEntity(), myHasCenterPoint(false)
50 {  
51 }
52
53 void SketchPlugin_MacroRectangle::initAttributes()
54 {
55   data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
56   data()->addAttribute(START1_ID(), GeomDataAPI_Point2D::typeId());
57   data()->addAttribute(START1_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
58   data()->addAttribute(END1_ID(), GeomDataAPI_Point2D::typeId());
59   data()->addAttribute(END1_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
60   data()->addAttribute(END2_ID(), GeomDataAPI_Point2D::typeId());
61   data()->addAttribute(END2_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
62   data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId());
63   data()->addAttribute(CENTER_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
64   data()->addAttribute(RECTANGLE_TYPE_ID(), ModelAPI_AttributeString::typeId());
65   data()->addAttribute(EDIT_RECTANGLE_TYPE_ID(), ModelAPI_AttributeString::typeId());
66   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EDIT_RECTANGLE_TYPE_ID());
67   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_REF_ID());
68   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), END2_REF_ID());
69   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), END1_REF_ID());
70   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), START1_REF_ID());
71
72   string(EDIT_RECTANGLE_TYPE_ID())->setValue("");
73 }
74
75 void SketchPlugin_MacroRectangle::endPoint()
76 {
77   std::shared_ptr<GeomDataAPI_Point2D> aEndPoint;
78   if(string(RECTANGLE_TYPE_ID())->value() == START_END_POINT_TYPE_ID())
79     aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(END1_ID()));
80   else
81     aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(END2_ID()));
82   if(aEndPoint->isInitialized())
83     myEndPoint = std::make_shared<GeomAPI_Pnt2d>(aEndPoint->x(), aEndPoint->y());
84   else
85     myEndPoint.reset();
86 }
87
88 void SketchPlugin_MacroRectangle::startPoint()
89 {
90   if(string(RECTANGLE_TYPE_ID())->value() == START_END_POINT_TYPE_ID())
91   {
92     std::shared_ptr<GeomDataAPI_Point2D> aStartPoint =
93         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(START1_ID()));
94     if(aStartPoint->isInitialized())
95       myStartPoint = std::make_shared<GeomAPI_Pnt2d>(aStartPoint->x(), aStartPoint->y());
96     else
97       myStartPoint.reset();
98   }
99   else
100   {
101     /// Compute end point as the symmetric of start point w.r.t. center
102     std::shared_ptr<GeomDataAPI_Point2D> aEndPoint =
103         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(END2_ID()));
104     std::shared_ptr<GeomDataAPI_Point2D> aCenterPoint =
105         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
106
107     if(aCenterPoint->isInitialized())
108     {
109       myCenterPoint = std::make_shared<GeomAPI_Pnt2d>(aCenterPoint->x(), aCenterPoint->y());
110       myHasCenterPoint = true;
111     }
112     double xStart = 2.0*aCenterPoint->x() - aEndPoint->x();
113     double yStart = 2.0*aCenterPoint->y() - aEndPoint->y();
114
115     if(aEndPoint->isInitialized() && aCenterPoint->isInitialized())
116       myStartPoint =  std::make_shared<GeomAPI_Pnt2d>(xStart, yStart);
117     else
118       myStartPoint.reset();
119   }
120 }
121
122
123 void SketchPlugin_MacroRectangle::execute()
124 {
125   SketchPlugin_Sketch* aSketch = sketch();
126   if(!myStartPoint || !myEndPoint || !aSketch) {
127     return ;
128   }
129   // Wait all constraints being created, then send update events
130   static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
131   bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
132   if (isUpdateFlushed)
133     Events_Loop::loop()->setFlushed(anUpdateEvent, false);
134
135   /// create a rectangle sketch
136   FeaturePtr myRectangleFeature = aSketch->addFeature(SketchPlugin_Rectangle::ID());
137   if(!myRectangleFeature)
138     return;
139
140   if(myHasCenterPoint){
141     std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
142           myRectangleFeature->attribute(SketchPlugin_Rectangle::CENTER_ID()))->setValue(myCenterPoint->x(),
143                                                                                         myCenterPoint->y());
144   }
145
146   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
147         myRectangleFeature->attribute(SketchPlugin_Rectangle::START_ID()))->setValue(myStartPoint->x(),
148                                                                                      myStartPoint->y());
149   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
150         myRectangleFeature->attribute(SketchPlugin_Rectangle::END_ID()))->setValue(myEndPoint->x(),
151                                                                                    myEndPoint->y());
152
153   myRectangleFeature->boolean(SketchPlugin_Rectangle::AUXILIARY_ID())
154       ->setValue(boolean(AUXILIARY_ID())->value());
155   myRectangleFeature->execute();
156
157   /// create coincidences with rectangle start/center and  end points
158   AttributeRefListPtr aLinesList = myRectangleFeature->reflist(SketchPlugin_Rectangle::LINES_LIST_ID());
159   FeaturePtr aRectangleStartLineFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aLinesList->object(0));
160   FeaturePtr aRectangleEndLineFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aLinesList->object(2));
161   std::shared_ptr<GeomDataAPI_Point2D> aRectanglePointEndAttr =
162       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRectangleEndLineFeature->attribute(SketchPlugin_Line::END_ID()));
163   std::shared_ptr<GeomDataAPI_Point2D> aRectanglePointStartAttr =
164       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRectangleStartLineFeature->attribute(SketchPlugin_Line::END_ID()));
165
166   if(myHasCenterPoint){
167     FeaturePtr aCenterPointFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(myRectangleFeature->refattr(CENTER_REF_ID())->object());
168     SketchPlugin_Tools::createCoincidenceOrTangency(
169           this, CENTER_REF_ID(), AttributePtr(), aCenterPointFeature, false);
170     SketchPlugin_Tools::createCoincidenceOrTangency(
171           this, END2_REF_ID(), aRectanglePointEndAttr, ObjectPtr(), false);
172   }
173   else{
174     SketchPlugin_Tools::createCoincidenceOrTangency(
175           this, START1_REF_ID(), aRectanglePointStartAttr, ObjectPtr(), false);
176     SketchPlugin_Tools::createCoincidenceOrTangency(
177           this, END1_REF_ID(), aRectanglePointEndAttr, ObjectPtr(), false);
178   }
179
180   /// Send events to update the sub-features by the solver.
181   if (isUpdateFlushed)
182     Events_Loop::loop()->setFlushed(anUpdateEvent, true);
183 }
184
185 void SketchPlugin_MacroRectangle::attributeChanged(const std::string& theID)
186 {
187   if(theID == RECTANGLE_TYPE_ID()) {
188     SketchPlugin_Tools::resetAttribute(this, START1_ID());
189     SketchPlugin_Tools::resetAttribute(this, END1_ID());
190     SketchPlugin_Tools::resetAttribute(this, CENTER_ID());
191     SketchPlugin_Tools::resetAttribute(this, END2_ID());
192     SketchPlugin_Tools::resetAttribute(this, START1_REF_ID());
193     SketchPlugin_Tools::resetAttribute(this, END1_REF_ID());
194     SketchPlugin_Tools::resetAttribute(this, CENTER_REF_ID());
195     SketchPlugin_Tools::resetAttribute(this, END2_REF_ID());
196     myStartPoint.reset();
197     myEndPoint.reset();
198     myCenterPoint.reset();
199     myHasCenterPoint = false;
200   }
201   else if (theID == START1_ID() || theID == END1_ID() ||
202            theID == START1_REF_ID() || theID == END1_REF_ID() ||
203            theID == END2_ID() || theID == CENTER_ID() ||
204            theID == END2_REF_ID() || theID == CENTER_REF_ID())
205   {
206     // update points
207     startPoint();
208     endPoint();
209   }
210   bool aWasBlocked = data()->blockSendAttributeUpdated(true);
211   data()->blockSendAttributeUpdated(aWasBlocked, false);
212 }
213
214 AISObjectPtr SketchPlugin_MacroRectangle::getAISObject(AISObjectPtr thePrevious)
215 {
216   SketchPlugin_Sketch* aSketch = sketch();
217
218   if(!aSketch || !myEndPoint || ! myStartPoint)
219     return AISObjectPtr();
220
221   std::vector<double> aX = {myStartPoint->x(), myStartPoint->x(), myEndPoint->x(), myEndPoint->x()};
222   std::vector<double> aY = {myStartPoint->y(), myEndPoint->y(), myEndPoint->y(), myStartPoint->y()};
223
224   std::list<std::shared_ptr<GeomAPI_Shape> > aShapes;
225   /// Update coordinates of rectangle lines
226
227   std::set<int> createdPointIndex;
228   for(unsigned  i = 0; i < 4; i++)
229   {
230     std::shared_ptr<GeomAPI_Pnt> theStart(aSketch->to3D(aX[(i+3)%4], aY[(i+3)%4]));
231     std::shared_ptr<GeomAPI_Pnt> theEnd(aSketch->to3D(aX[i], aY[i]));
232     GeomShapePtr aLine = GeomAlgoAPI_EdgeBuilder::line(theStart, theEnd);
233
234     if(aLine)
235     {
236       aShapes.push_back(aLine);
237       if(createdPointIndex.insert(i).second){
238         GeomShapePtr aPointShape = GeomAlgoAPI_PointBuilder::vertex(theStart);
239         aShapes.push_back(aPointShape);
240       }
241       if(createdPointIndex.insert((i+1)%4).second){
242         GeomShapePtr aPointShape = GeomAlgoAPI_PointBuilder::vertex(theEnd);
243         aShapes.push_back(aPointShape);
244       }
245     }
246   }
247
248   if(string(RECTANGLE_TYPE_ID())->value() == CENTER_END_POINT_TYPE_ID()){
249     /// draw  a line center->end
250     std::shared_ptr<GeomDataAPI_Point2D> aCenterPoint =
251         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
252
253     std::shared_ptr<GeomAPI_Pnt> theEnd(aSketch->to3D(myEndPoint->x(), myEndPoint->y()));
254     std::shared_ptr<GeomAPI_Pnt> theStart(aSketch->to3D(aCenterPoint->x(), aCenterPoint->y()));
255     GeomShapePtr aLine = GeomAlgoAPI_EdgeBuilder::line(theStart, theEnd);
256     if(aLine)
257       aShapes.push_back(aLine);
258   }
259
260   // Compute a rectangle in 3D view.
261
262   std::shared_ptr<GeomAPI_Shape> aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
263   AISObjectPtr anAIS = thePrevious;
264   if(!anAIS.get()) {
265     anAIS.reset(new GeomAPI_AISObject());
266   }
267   anAIS->createShape(aCompound);
268
269   // Modify attributes
270   SketchPlugin_Tools::customizeFeaturePrs(anAIS, boolean(AUXILIARY_ID())->value());
271
272   return anAIS;
273 }