Salome HOME
rectangle feature: complete rectangle type by center and end points
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_Rectangle.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_Rectangle.h"
21 #include "SketchPlugin_Sketch.h"
22 #include <ModelAPI_ResultConstruction.h>
23 #include <ModelAPI_AttributeSelection.h>
24 #include <ModelAPI_Validator.h>
25 #include <ModelAPI_AttributeRefList.h>
26 #include <ModelAPI_AttributeRefAttr.h>
27 #include <GeomDataAPI_Point2D.h>
28 #include <GeomAlgoAPI_CompoundBuilder.h>
29
30 #include <SketchPlugin_Line.h>
31 #include <SketchPlugin_Point.h>
32 #include <SketchPlugin_Tools.h>
33 #include <SketchPlugin_ConstraintCoincidence.h>
34 #include <SketchPlugin_ConstraintHorizontal.h>
35 #include <SketchPlugin_ConstraintVertical.h>
36 #include <SketchPlugin_ConstraintCoincidenceInternal.h>
37
38 #include <cmath>
39
40
41 const double tolerance = 1e-7;
42
43
44 SketchPlugin_Rectangle::SketchPlugin_Rectangle()
45   : SketchPlugin_SketchEntity()
46 {
47 }
48
49
50 void SketchPlugin_Rectangle::initDerivedClassAttributes()
51 {
52   data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
53   data()->addAttribute(START_ID(), GeomDataAPI_Point2D::typeId());
54   data()->addAttribute(END_ID(), GeomDataAPI_Point2D::typeId());
55   data()->addAttribute(CENTER_ID(), GeomDataAPI_Point2D::typeId());
56   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_ID());
57   data()->addAttribute(CENTER_REF_ID(), ModelAPI_AttributeRefAttr::typeId());
58   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), CENTER_REF_ID());
59   data()->addAttribute(LINES_LIST_ID(), ModelAPI_AttributeRefList::typeId());
60   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), LINES_LIST_ID());
61   data()->addAttribute(DIAGONAL_LIST_ID(), ModelAPI_AttributeRefList::typeId());
62   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), DIAGONAL_LIST_ID());
63   data()->addAttribute(ISHV_LIST_ID(), ModelAPI_AttributeIntArray::typeId());
64   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), ISHV_LIST_ID());
65   data()->addAttribute(NOT_TO_DUMP_LIST_ID(), ModelAPI_AttributeRefList::typeId());
66   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), NOT_TO_DUMP_LIST_ID());
67 }
68
69 namespace {
70   static const std::pair<unsigned, std::string> cornerToDiagonalLinePoints[4]
71   = {
72     {0, SketchPlugin_Line::START_ID()},
73     {1, SketchPlugin_Line::START_ID()},
74     {0, SketchPlugin_Line::END_ID()},
75     {1, SketchPlugin_Line::END_ID()}
76   };
77 }
78
79 void SketchPlugin_Rectangle::updateLines()
80 {
81   // Retrieving list of already created lines
82   AttributeRefListPtr aLinesList = reflist(LINES_LIST_ID());
83   unsigned  aNbLines = aLinesList->size();
84   std::shared_ptr<GeomDataAPI_Point2D> aStartPoint =
85       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(START_ID()));
86   std::shared_ptr<GeomDataAPI_Point2D> aEndPoint =
87       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(END_ID()));
88
89   double aXStart = aStartPoint->x();
90   double aYStart = aStartPoint->y();
91   double aXEnd = aEndPoint->x();
92   double aYEnd = aEndPoint->y();
93
94   std::vector<double> aX = {aXStart, aXStart, aXEnd, aXEnd};
95   std::vector<double> aY = {aYStart, aYEnd, aYEnd, aYStart};
96
97   bool anAuxiliary = data()->boolean(AUXILIARY_ID())->value();
98   AttributeRefListPtr aDiagonalList =  reflist(DIAGONAL_LIST_ID());
99
100
101   /// Update coordinates of rectangle lines
102   for(unsigned  i = 0; i < aNbLines; i++)
103   {
104     FeaturePtr aLine = std::dynamic_pointer_cast<ModelAPI_Feature>(aLinesList->object(i));
105     std::shared_ptr<GeomDataAPI_Point2D> aLineStart =
106         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aLine->attribute(SketchPlugin_Line::START_ID()));
107     std::shared_ptr<GeomDataAPI_Point2D> aLineEnd =
108         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aLine->attribute(SketchPlugin_Line::END_ID()));
109     aLineStart->setValue(aX[(i+3)%4], aY[(i+3)%4]);
110     aLineEnd->setValue(aX[i], aY[i]);
111     aLine->data()->boolean(AUXILIARY_ID())->setValue(anAuxiliary);
112     /// Cooordinates of diagonals
113     if(aDiagonalList->size())
114     {
115       auto aDiagonalPoint = cornerToDiagonalLinePoints[i];
116       FeaturePtr aDiagonal = std::dynamic_pointer_cast<ModelAPI_Feature>(aDiagonalList->object(aDiagonalPoint.first));
117       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aDiagonal->attribute(aDiagonalPoint.second))->setValue(aX[(i+3)%4], aY[(i+3)%4]);
118     }
119   }
120 }
121
122 void SketchPlugin_Rectangle::updateStartPoint()
123 {
124   /// Retrieving list of already created lines
125   AttributeRefListPtr aLinesList = reflist(LINES_LIST_ID());
126   unsigned  aNbLines = aLinesList->size();
127   std::shared_ptr<GeomDataAPI_Point2D> aStartPoint =
128       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(START_ID()));
129
130   double aXStart = aStartPoint->x();
131   double aYStart = aStartPoint->y();
132
133   /// Update coordinates of rectangle lines
134   for(unsigned  i = 0; i < aNbLines; i++)
135   {
136     FeaturePtr aLine = std::dynamic_pointer_cast<ModelAPI_Feature>(aLinesList->object(i));
137     std::shared_ptr<GeomDataAPI_Point2D> aLineStart =
138         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aLine->attribute(SketchPlugin_Line::END_ID()));
139     aLineStart->setValue(aXStart, aYStart);
140   }
141 }
142
143 void SketchPlugin_Rectangle::execute()
144 {
145   SketchPlugin_Sketch* aSketch = sketch();
146   if(!aSketch) {
147     return;
148   }
149
150   // Compute a Rectangle in 3D view.
151   std::shared_ptr<GeomDataAPI_Point2D> aStartAttr =
152       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(START_ID()));
153
154   std::shared_ptr<GeomDataAPI_Point2D> aEndAttr =
155       std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(END_ID()));
156
157   if(!aStartAttr->isInitialized() || !aEndAttr->isInitialized()) {
158     return;
159   }
160
161   AttributeRefListPtr aLinesList =  reflist(LINES_LIST_ID());
162   unsigned aNbLines = aLinesList->size();
163   AttributeIntArrayPtr isHVList = intArray(ISHV_LIST_ID());
164   AttributeRefListPtr aNotToDumpList = reflist(NOT_TO_DUMP_LIST_ID());
165   AttributeRefListPtr aDiagonalList =  reflist(DIAGONAL_LIST_ID());
166
167   if(aNbLines == 1)
168   {
169     /// Create 1-4 lines to compose the rectangle
170     for( unsigned i = 0; i < 3; i++)
171     {
172       FeaturePtr aLine = aSketch->addFeature(SketchPlugin_Line::ID());
173       aLinesList->append(aLine);
174       aNotToDumpList->append(aLine);
175     }
176
177     updateLines();
178
179     aNbLines = aLinesList->size();
180     FeaturePtr aCenterPointFeature;
181
182     if(aDiagonalList->size())
183     {
184       /// compute diagonals intersection point
185       std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
186           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
187
188       aCenterPointFeature = aSketch->addFeature(SketchPlugin_Point::ID());
189       aNotToDumpList->append(aCenterPointFeature);
190       AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
191             aCenterPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
192       aCoord->setValue(aCenterAttr->x(), aCenterAttr->y());
193       aCenterPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
194       refattr(CENTER_REF_ID())->setObject(aCenterPointFeature);
195
196       for(int i = 0; i < 2; i++)
197       {
198         FeaturePtr aDiagonal = std::dynamic_pointer_cast<ModelAPI_Feature>(aDiagonalList->object(i));
199         FeaturePtr aConstraint = SketchPlugin_Tools::createConstraintAttrObject(aSketch, SketchPlugin_ConstraintCoincidenceInternal::ID(),
200                                                                                 aCoord, aDiagonal);
201         aNotToDumpList->append(aConstraint);
202       }
203     }
204
205     /// Create constraints to keep the rectangle
206     for( unsigned i = 0; i < aNbLines; i++)
207     {
208       FeaturePtr  aLine = std::dynamic_pointer_cast<ModelAPI_Feature>(aLinesList->object(i));
209       /// connect neighbor lines by coincidence
210       unsigned iPrev = (i+3)%4;
211       FeaturePtr aPrevLine = std::dynamic_pointer_cast<ModelAPI_Feature>(aLinesList->object(iPrev));
212       FeaturePtr aConstraint = SketchPlugin_Tools::createConstraintAttrAttr(aSketch, SketchPlugin_ConstraintCoincidence::ID(),
213                                                                             aPrevLine->attribute(SketchPlugin_Line::END_ID()),
214                                                                             aLine->attribute(SketchPlugin_Line::START_ID()));
215       aNotToDumpList->append(aConstraint);
216
217       /// case of  rectangle created from its center
218       if(aDiagonalList->size())
219       {
220         auto aDiagonalPoint = cornerToDiagonalLinePoints[i];
221         FeaturePtr aDiagonal = std::dynamic_pointer_cast<ModelAPI_Feature>(aDiagonalList->object(aDiagonalPoint.first));
222         FeaturePtr aConstraint = SketchPlugin_Tools::createConstraintAttrAttr(aSketch, SketchPlugin_ConstraintCoincidenceInternal::ID(),
223                                                                               aDiagonal->attribute(aDiagonalPoint.second),
224                                                                               aLine->attribute(SketchPlugin_Line::START_ID()));
225         aNotToDumpList->append(aConstraint);
226       }
227     }
228     /// Update coordinates of created lines
229     updateLines();
230   }
231
232   /// Add horizontal and vertical constraint for the lines which already have result
233   if(isHVList->size() == 0)
234   {
235     isHVList->setSize(4, false);
236     for(int i = 0; i< 4;)
237       isHVList->setValue(i++, 0, false);
238   }
239
240   for(unsigned i = 0; i< aNbLines; i++)
241   {
242     if(isHVList->value(i))
243       continue;
244     FeaturePtr aLine = std::dynamic_pointer_cast<ModelAPI_Feature>(aLinesList->object(i));
245     ResultPtr aLineResult = aLine->lastResult();
246     if(!aLineResult.get())
247       continue;
248     std::string aHVName = SketchPlugin_ConstraintHorizontal::ID();
249     if(i%2)
250       aHVName = SketchPlugin_ConstraintVertical::ID();
251     FeaturePtr aHVConstraint = aSketch->addFeature(aHVName);
252     aNotToDumpList->append(aHVConstraint);
253     AttributeRefAttrPtr aRefAttrA = aHVConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
254     aRefAttrA->setObject(aLine->lastResult());
255     isHVList->setValue(i, 1, false);
256   }
257
258   double aDiag = std::pow(aStartAttr->x() - aEndAttr->x(), 2.0);
259   aDiag += std::pow(aStartAttr->y() - aEndAttr->y(), 2.0);
260   aDiag = std::sqrt(aDiag);
261   if(aDiag < tolerance) {
262     return;
263   }
264
265   /// store results.
266   GeomShapePtr aRectangleShape;
267   ListOfShape aSubs;
268
269   for(unsigned i = 0; i< aNbLines; i++)
270   {
271     FeaturePtr aLine = std::dynamic_pointer_cast<ModelAPI_Feature>(aLinesList->object(i));
272     ResultPtr aLineResult = aLine->lastResult();
273     if(!aLineResult.get())
274       continue;
275     aSubs.push_back(aLineResult->shape());
276   }
277
278   for(int i = 0; i< aDiagonalList->size(); i++)
279   {
280     FeaturePtr aDiagonal = std::dynamic_pointer_cast<ModelAPI_Feature>(aDiagonalList->object(i));
281     ResultPtr aDiagonalResult = aDiagonal->lastResult();
282     if(!aDiagonalResult.get())
283       continue;
284     aSubs.push_back(aDiagonalResult->shape());
285   }
286
287   FeaturePtr aCenterPointFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(refattr(CENTER_REF_ID())->object());
288   if(aCenterPointFeature)
289   {
290     ResultPtr aCenterResult = aCenterPointFeature->lastResult();
291     if(aCenterResult.get())
292       aSubs.push_back(aCenterResult->shape());
293   }
294
295   aRectangleShape = aSubs.empty() ? GeomShapePtr() : GeomAlgoAPI_CompoundBuilder::compound(aSubs);
296   std::shared_ptr<ModelAPI_ResultConstruction> aResult = document()->createConstruction(data(), 0);
297   aResult->setShape(aRectangleShape);
298   aResult->setIsInHistory(false);
299   setResult(aResult, 1);
300 }
301
302 void SketchPlugin_Rectangle::attributeChanged(const std::string& theID)
303 {
304   if (theID == START_ID() || theID == END_ID())
305   {
306     AttributeRefListPtr aLinesList = reflist(LINES_LIST_ID());
307     AttributeRefListPtr aNotToDumpList = reflist(NOT_TO_DUMP_LIST_ID());
308     unsigned  aNbLines = aLinesList->size();
309     if(aNbLines == 0)
310     {
311       SketchPlugin_Sketch* aSketch = sketch();
312       if(!aSketch) {
313         return;
314       }
315       /// Create first line to be able to create a coincidence with selected point/feature
316       FeaturePtr aLine = aSketch->addFeature(SketchPlugin_Line::ID());
317       aLinesList->append(aLine);
318       aNotToDumpList->append(aLine);
319
320       /// if rectangle has center, add 2 iagonals
321       std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
322           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(CENTER_ID()));
323       if(aCenterAttr->isInitialized())
324       {
325         AttributeRefListPtr aDiagonalList = reflist(DIAGONAL_LIST_ID());
326         for(int i = 0; i < 2; i++)
327         {
328           FeaturePtr aDiagonalLine = aSketch->addFeature(SketchPlugin_Line::ID());
329           aDiagonalLine->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
330           aDiagonalList->append(aDiagonalLine);
331           aNotToDumpList->append(aDiagonalLine);
332         }
333       }
334     }
335     std::shared_ptr<GeomDataAPI_Point2D> aStartPoint =
336         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(START_ID()));
337     std::shared_ptr<GeomDataAPI_Point2D> aEndPoint =
338         std::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(END_ID()));
339
340     if (aStartPoint->isInitialized() && aEndPoint->isInitialized())
341       updateLines();
342     else
343       updateStartPoint();
344   }
345
346   if (theID == AUXILIARY_ID())
347   {
348     bool anAuxiliary = data()->boolean(AUXILIARY_ID())->value();
349     AttributeRefListPtr aLinesList = reflist(LINES_LIST_ID());
350     unsigned aNbLines = aLinesList->size();
351
352     /// Update coordinates of rectangle lines
353     for(unsigned  i = 0; i < aNbLines; i++)
354     {
355       FeaturePtr aLine = std::dynamic_pointer_cast<ModelAPI_Feature>(aLinesList->object(i));
356       aLine->data()->boolean(AUXILIARY_ID())->setValue(anAuxiliary);
357     }
358   }
359 }