]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchPlugin/SketchPlugin_ConstraintFillet.cpp
Salome HOME
Merge branch 'Dev_1.1.0' of newgeom:newgeom into Dev_1.1.0
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_ConstraintFillet.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
2
3 // File:    SketchPlugin_ConstraintFillet.cpp
4 // Created: 19 Mar 2015
5 // Author:  Artem ZHIDKOV
6
7 #include "SketchPlugin_ConstraintFillet.h"
8
9 #include <GeomAPI_Dir2d.h>
10 #include <GeomAPI_Pnt2d.h>
11 #include <GeomAPI_XY.h>
12 #include <GeomDataAPI_Point2D.h>
13 #include <ModelAPI_AttributeDouble.h>
14 #include <ModelAPI_AttributeRefAttr.h>
15 #include <ModelAPI_AttributeRefList.h>
16 #include <ModelAPI_Data.h>
17 #include <ModelAPI_Events.h>
18 #include <ModelAPI_ResultConstruction.h>
19 #include <ModelAPI_Session.h>
20
21 #include <SketchPlugin_Arc.h>
22 #include <SketchPlugin_Line.h>
23 #include <SketchPlugin_Sketch.h>
24 #include <SketchPlugin_ConstraintCoincidence.h>
25 #include <SketchPlugin_ConstraintTangent.h>
26 #include <SketchPlugin_ConstraintRadius.h>
27
28 #include <SketcherPrs_Factory.h>
29
30 #include <Config_PropManager.h>
31 #include <Events_Loop.h>
32
33 /// \brief Attract specified point on theNewArc to the attribute of theFeature
34 static void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute,
35   FeaturePtr theFeature, const std::string& theFeatureAttribute);
36
37
38 SketchPlugin_ConstraintFillet::SketchPlugin_ConstraintFillet()
39 {
40 }
41
42 void SketchPlugin_ConstraintFillet::initAttributes()
43 {
44   data()->addAttribute(SketchPlugin_Constraint::VALUE(), ModelAPI_AttributeDouble::typeId());
45   data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
46   data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
47   data()->addAttribute(SketchPlugin_Constraint::ENTITY_C(), ModelAPI_AttributeRefList::typeId());
48   // initialize attribute not applicable for user
49   data()->attribute(SketchPlugin_Constraint::ENTITY_C())->setInitialized();
50 }
51
52 void SketchPlugin_ConstraintFillet::execute()
53 {
54   std::shared_ptr<ModelAPI_Data> aData = data();
55   ResultConstructionPtr aRC;
56   // Check the base objects are initialized
57   double aFilletRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
58       aData->attribute(SketchPlugin_Constraint::VALUE()))->value();
59   AttributeRefAttrPtr aBaseA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
60       aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
61   AttributeRefAttrPtr aBaseB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
62       aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
63   if (!aBaseA->isInitialized() || !aBaseB->isInitialized() ||
64       !aBaseA->isObject() || !aBaseB->isObject())
65     return;
66   // Check the fillet shapes is not initialized yet
67   AttributeRefListPtr aRefListOfFillet = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
68       aData->attribute(SketchPlugin_Constraint::ENTITY_C()));
69   if (aRefListOfFillet->size() > 0) {
70     // update the Radius constraint
71     ObjectPtr aFilletArcObj = aRefListOfFillet->list().back();
72     aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aFilletArcObj);
73     FeaturePtr aFilletArcFeature = aRC ? aRC->document()->feature(aRC) : 
74       std::dynamic_pointer_cast<ModelAPI_Feature>(aFilletArcObj);
75
76     int aNbSubs = sketch()->numberOfSubs();
77     FeaturePtr aSubFeature;
78     for (int aSub = 0; aSub < aNbSubs; aSub++) {
79       aSubFeature = sketch()->subFeature(aSub);
80       if (aSubFeature->getKind() != SketchPlugin_ConstraintRadius::ID())
81         continue;
82       AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
83           aSubFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
84       if (!aRefAttr || !aRefAttr->isObject())
85         continue;
86       aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aRefAttr->object());
87       FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) : 
88         std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
89       if (aFeature == aFilletArcFeature) {
90         AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
91             aSubFeature->attribute(SketchPlugin_Constraint::VALUE()));
92         aRadius->setValue(aFilletRadius);
93       }
94     }
95     return;
96   }
97   // Obtain features for the base objects
98   FeaturePtr aFeatureA, aFeatureB;
99   aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseA->object());
100   if (aRC) aFeatureA = aRC->document()->feature(aRC);
101   aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseB->object());
102   if (aRC) aFeatureB = aRC->document()->feature(aRC);
103   if (!aFeatureA || !aFeatureB)
104     return;
105
106   // Create list of objects composing a fillet
107   // copy aFeatureA
108   FeaturePtr aNewFeatureA = sketch()->addFeature(aFeatureA->getKind());
109   aFeatureA->data()->copyTo(aNewFeatureA->data());
110   aNewFeatureA->execute();
111   aRefListOfFillet->append(aNewFeatureA);
112   // copy aFeatureB
113   FeaturePtr aNewFeatureB = sketch()->addFeature(aFeatureB->getKind());
114   aFeatureB->data()->copyTo(aNewFeatureB->data());
115   aNewFeatureB->execute();
116   aRefListOfFillet->append(aNewFeatureB);
117   // create filleting arc
118   FeaturePtr aNewArc = sketch()->addFeature(SketchPlugin_Arc::ID());
119   aRefListOfFillet->append(aNewArc);
120   aRefListOfFillet->setInitialized();
121
122   // Wait all constraints being created, then send update events
123   static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
124   bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
125   if (isUpdateFlushed)
126     Events_Loop::loop()->setFlushed(anUpdateEvent, false);
127
128   // Calculate arc attributes
129   static const int aNbFeatures = 2;
130   FeaturePtr aFeature[aNbFeatures] = {aNewFeatureA, aNewFeatureB};
131   std::shared_ptr<GeomAPI_Dir2d> aTangentDir[aNbFeatures]; // tangent directions of the features in coincident point
132   bool isStart[aNbFeatures]; // indicates which point the features share
133   std::shared_ptr<GeomAPI_Pnt2d> aStartEndPnt[aNbFeatures * 2]; // first pair of points relate to first feature, second pair -  to second
134   std::string aFeatAttributes[aNbFeatures * 2]; // attributes of features
135   for (int i = 0; i < aNbFeatures; i++) {
136     std::string aStartAttr, aEndAttr;
137     if (aFeature[i]->getKind() == SketchPlugin_Line::ID()) {
138       aStartAttr = SketchPlugin_Line::START_ID();
139       aEndAttr = SketchPlugin_Line::END_ID();
140     } else if (aFeature[i]->getKind() == SketchPlugin_Arc::ID()) {
141       aStartAttr = SketchPlugin_Arc::START_ID();
142       aEndAttr = SketchPlugin_Arc::END_ID();
143     } else { // wrong argument
144       aRefListOfFillet->remove(aNewFeatureA);
145       aRefListOfFillet->remove(aNewFeatureB);
146       aRefListOfFillet->remove(aNewArc);
147       return;
148     }
149     aFeatAttributes[2*i] = aStartAttr;
150     aStartEndPnt[2*i] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
151         aFeature[i]->attribute(aStartAttr))->pnt();
152     aFeatAttributes[2*i+1] = aEndAttr;
153     aStartEndPnt[2*i+1] = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
154         aFeature[i]->attribute(aEndAttr))->pnt();
155   }
156   for (int i = 0; i < aNbFeatures; i++) {
157     int j = aNbFeatures;
158     for (; j < 2 * aNbFeatures; j++)
159       if (aStartEndPnt[i]->distance(aStartEndPnt[j]) < 1.e-10) {
160         isStart[0] = i==0;
161         isStart[1] = j==aNbFeatures;
162         break;
163       }
164     if (j < 2 * aNbFeatures)
165       break;
166   }
167   // tangent directions of the features
168   for (int i = 0; i < aNbFeatures; i++) {
169     std::shared_ptr<GeomAPI_XY> aDir;
170     if (aFeature[i]->getKind() == SketchPlugin_Line::ID()) {
171       aDir = aStartEndPnt[2*i+1]->xy()->decreased(aStartEndPnt[2*i]->xy());
172       if (!isStart[i])
173         aDir = aDir->multiplied(-1.0);
174     } else if (aFeature[i]->getKind() == SketchPlugin_Arc::ID()) {
175       std::shared_ptr<GeomAPI_Pnt2d> aCenterPoint =
176           std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
177           aFeature[i]->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
178       aDir = isStart[i] ? aStartEndPnt[2*i]->xy() : aStartEndPnt[2*i+1]->xy();
179       aDir = aDir->decreased(aCenterPoint->xy());
180
181       double x = aDir->x();
182       double y = aDir->y();
183       aDir->setX(-y);
184       aDir->setY(x);
185       if (!isStart[i])
186         aDir = aDir->multiplied(-1.0);
187     }
188     aTangentDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir));
189   }
190   // By default, the start point of fillet arc is connected to FeatureA,
191   // and the end point - to FeatureB. But when the angle between TangentDirA and
192   // TangentDirB greater 180 degree, the sequaence of features need to be reversed.
193   double cosBA = aTangentDir[0]->cross(aTangentDir[1]); // cos(B-A), where A and B - angles between corresponding tanget direction and the X axis
194   bool isReversed = cosBA > 0.0;
195
196   std::shared_ptr<GeomAPI_Pnt2d> aSharedPoint = aStartEndPnt[isStart[0] ? 0 : 1];
197   std::shared_ptr<GeomAPI_Dir2d> aBisect(new GeomAPI_Dir2d(
198       aTangentDir[0]->xy()->added(aTangentDir[1]->xy())));
199   std::shared_ptr<GeomAPI_XY> aStep = aBisect->xy()->multiplied(aFilletRadius);
200   std::shared_ptr<GeomAPI_XY> aCenter = aSharedPoint->xy()->added(aStep);
201   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
202       aNewArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(
203       aCenter->x(), aCenter->y());
204   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
205       aNewArc->attribute(SketchPlugin_Arc::START_ID()))->setValue(
206       aCenter->x() - aStep->y(), aCenter->y() + aStep->x());
207   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
208       aNewArc->attribute(SketchPlugin_Arc::END_ID()))->setValue(
209       aCenter->x() + aStep->y(), aCenter->y() - aStep->x());
210   aNewArc->execute();
211
212   // Create list of additional constraints:
213   // 1. Coincidence of boundary points of features and fillet arc
214   // 1.1. coincidence
215   FeaturePtr aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
216   AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
217       aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
218   aRefAttr->setAttr(aNewArc->attribute(SketchPlugin_Arc::START_ID()));
219   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
220       aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
221   int aFeatInd = isReversed ? 1 : 0;
222   int anAttrInd = (isReversed ? 2 : 0) + (isStart[isReversed ? 1 : 0] ? 0 : 1);
223   aRefAttr->setAttr(aFeature[aFeatInd]->attribute(aFeatAttributes[anAttrInd]));
224   recalculateAttributes(aNewArc, SketchPlugin_Arc::START_ID(), aFeature[aFeatInd], aFeatAttributes[anAttrInd]);
225   aConstraint->execute();
226   ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
227   // 1.2. coincidence
228   aConstraint = sketch()->addFeature(SketchPlugin_ConstraintCoincidence::ID());
229   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
230       aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
231   aRefAttr->setAttr(aNewArc->attribute(SketchPlugin_Arc::END_ID()));
232   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
233       aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
234   aFeatInd = isReversed ? 0 : 1;
235   anAttrInd = (isReversed ? 0 : 2) + (isStart[isReversed ? 0 : 1] ? 0 : 1);
236   aRefAttr->setAttr(aFeature[aFeatInd]->attribute(aFeatAttributes[anAttrInd]));
237   recalculateAttributes(aNewArc, SketchPlugin_Arc::END_ID(), aFeature[aFeatInd], aFeatAttributes[anAttrInd]);
238   aConstraint->execute();
239   ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
240   // recalculate center of fillet arc
241   std::shared_ptr<GeomAPI_Pnt2d> aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
242       aNewArc->attribute(SketchPlugin_Arc::START_ID()))->pnt();
243   std::shared_ptr<GeomAPI_Pnt2d> aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
244       aNewArc->attribute(SketchPlugin_Arc::END_ID()))->pnt();
245   aCenter = aStartPoint->xy()->added(aEndPoint->xy())->multiplied(0.5);
246   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
247       aNewArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(
248       aCenter->x(), aCenter->y());
249   // 2. Fillet arc radius
250   aConstraint = sketch()->addFeature(SketchPlugin_ConstraintRadius::ID());
251   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
252       aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
253   aRefAttr->setObject(aNewArc->lastResult());
254   std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
255       aConstraint->attribute(SketchPlugin_Constraint::VALUE()))->setValue(aFilletRadius);
256   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
257       aConstraint->attribute(SketchPlugin_Constraint::FLYOUT_VALUE_PNT()))->setValue(
258       isStart[0] ? aStartEndPnt[0] : aStartEndPnt[1]);
259   aConstraint->execute();
260   ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
261   // 3. Tangency of fillet arc and features
262   for (int i = 0; i < aNbFeatures; i++) {
263     aConstraint = sketch()->addFeature(SketchPlugin_ConstraintTangent::ID());
264     aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
265         aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
266     aRefAttr->setObject(aNewArc->lastResult());
267     aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
268         aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
269     bool isArc = aFeature[i]->getKind() == SketchPlugin_Arc::ID();
270     aRefAttr->setObject(isArc ? aFeature[i]->lastResult() : aFeature[i]->firstResult());
271     aConstraint->execute();
272     ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
273   }
274
275   // make base features auxiliary
276   static Events_ID aRedisplayEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
277   aFeatureA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true);
278   aFeatureB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true);
279   ModelAPI_EventCreator::get()->sendUpdated(aFeatureA, aRedisplayEvent);
280   ModelAPI_EventCreator::get()->sendUpdated(aFeatureB, aRedisplayEvent);
281 ////  Events_Loop::loop()->flush(aRedisplayEvent);
282
283   // send events
284   if (isUpdateFlushed)
285     Events_Loop::loop()->setFlushed(anUpdateEvent, true);
286   Events_Loop::loop()->flush(anUpdateEvent);
287 }
288
289 AISObjectPtr SketchPlugin_ConstraintFillet::getAISObject(AISObjectPtr thePrevious)
290 {
291   if (!sketch())
292     return thePrevious;
293
294   AISObjectPtr anAIS = thePrevious;
295   /// TODO: Equal constraint presentation should be put here
296   return anAIS;
297 }
298
299
300
301 // =========   Auxiliary functions   =================
302 void recalculateAttributes(FeaturePtr theNewArc,  const std::string& theNewArcAttribute,
303                             FeaturePtr theFeature, const std::string& theFeatureAttribute)
304 {
305   std::shared_ptr<GeomAPI_Pnt2d> anArcPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
306       theNewArc->attribute(theNewArcAttribute))->pnt();
307   if (theFeature->getKind() == SketchPlugin_Line::ID()) {
308     std::shared_ptr<GeomAPI_Pnt2d> aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
309         theFeature->attribute(SketchPlugin_Line::START_ID()))->pnt();
310     std::shared_ptr<GeomAPI_Pnt2d> aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
311         theFeature->attribute(SketchPlugin_Line::END_ID()))->pnt();
312     std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(
313         aEndPoint->xy()->decreased(aStartPoint->xy())));
314     std::shared_ptr<GeomAPI_XY> aVec = anArcPoint->xy()->decreased(aStartPoint->xy());
315     double aDot = aVec->dot(aLineDir->xy());
316     aVec = aStartPoint->xy()->added(aLineDir->xy()->multiplied(aDot));
317     anArcPoint->setX(aVec->x());
318     anArcPoint->setY(aVec->y());
319   } else if (theFeature->getKind() == SketchPlugin_Arc::ID()) {
320     std::shared_ptr<GeomAPI_Pnt2d> aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
321         theFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
322     std::shared_ptr<GeomAPI_Pnt2d> aCenterPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
323         theFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
324     double aRadius = aStartPoint->distance(aCenterPoint);
325     std::shared_ptr<GeomAPI_Dir2d> aDir(new GeomAPI_Dir2d(
326         anArcPoint->xy()->decreased(aCenterPoint->xy())));
327     std::shared_ptr<GeomAPI_XY> aPoint = aCenterPoint->xy()->added(aDir->xy()->multiplied(aRadius));
328     anArcPoint->setX(aPoint->x());
329     anArcPoint->setY(aPoint->y());
330   } else
331     return;
332
333   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
334       theNewArc->attribute(theNewArcAttribute))->setValue(anArcPoint->x(), anArcPoint->y());
335   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
336       theFeature->attribute(theFeatureAttribute))->setValue(anArcPoint->x(), anArcPoint->y());
337 }