Salome HOME
setDisplayed has to be called in order to synchronize internal state of the object
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_ConstraintFillet.cpp
index 23d1858b66b1d247a9da7c2f18a034e74c92f5dd..5f23e1e8861bba3a45c05557cadb2b396ec8a694 100644 (file)
@@ -17,6 +17,7 @@
 #include <ModelAPI_Events.h>
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
 
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_Line.h>
@@ -30,6 +31,8 @@
 #include <Config_PropManager.h>
 #include <Events_Loop.h>
 
+static const std::string PREVIOUS_VALUE("FilletPreviousRadius");
+
 /// \brief Attract specified point on theNewArc to the attribute of theFeature
 static void recalculateAttributes(FeaturePtr theNewArc, const std::string& theNewArcAttribute,
   FeaturePtr theFeature, const std::string& theFeatureAttribute);
@@ -45,13 +48,23 @@ void SketchPlugin_ConstraintFillet::initAttributes()
   data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::typeId());
   data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefAttr::typeId());
   data()->addAttribute(SketchPlugin_Constraint::ENTITY_C(), ModelAPI_AttributeRefList::typeId());
+  data()->addAttribute(PREVIOUS_VALUE, ModelAPI_AttributeDouble::typeId());
   // initialize attribute not applicable for user
-  data()->attribute(SketchPlugin_Constraint::ENTITY_C())->setInitialized();
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_C());
+  data()->attribute(PREVIOUS_VALUE)->setInitialized();
+  std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(data()->attribute(PREVIOUS_VALUE))->setValue(0.0);
 }
 
 void SketchPlugin_ConstraintFillet::execute()
 {
+  // the viewer update should be blocked in order to avoid the temporaty fillet sub-features visualization
+  // before they are processed by the solver
+  //std::shared_ptr<Events_Message> aMsg = std::shared_ptr<Events_Message>(
+  //    new Events_Message(Events_Loop::eventByName(EVENT_UPDATE_VIEWER_BLOCKED)));
+  //Events_Loop::loop()->send(aMsg);
+
   std::shared_ptr<ModelAPI_Data> aData = data();
+  ResultConstructionPtr aRC;
   // Check the base objects are initialized
   double aFilletRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
       aData->attribute(SketchPlugin_Constraint::VALUE()))->value();
@@ -65,12 +78,45 @@ void SketchPlugin_ConstraintFillet::execute()
   // Check the fillet shapes is not initialized yet
   AttributeRefListPtr aRefListOfFillet = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
       aData->attribute(SketchPlugin_Constraint::ENTITY_C()));
-  if (aRefListOfFillet->size() > 0)
+  if (aRefListOfFillet->size() > 0) {
+    // update the Radius constraint
+    ObjectPtr aFilletArcObj = aRefListOfFillet->list().back();
+    aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aFilletArcObj);
+    FeaturePtr aFilletArcFeature = aRC ? aRC->document()->feature(aRC) : 
+      std::dynamic_pointer_cast<ModelAPI_Feature>(aFilletArcObj);
+
+    int aNbSubs = sketch()->numberOfSubs();
+    FeaturePtr aSubFeature;
+    for (int aSub = 0; aSub < aNbSubs; aSub++) {
+      aSubFeature = sketch()->subFeature(aSub);
+      if (aSubFeature->getKind() != SketchPlugin_ConstraintRadius::ID())
+        continue;
+      AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+          aSubFeature->attribute(SketchPlugin_Constraint::ENTITY_A()));
+      if (!aRefAttr || !aRefAttr->isObject())
+        continue;
+      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aRefAttr->object());
+      FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) : 
+        std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
+      if (aFeature == aFilletArcFeature) {
+        // Update radius constraint only if the value is changed in fillet's attribute
+        double aPrevRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+            aData->attribute(PREVIOUS_VALUE))->value();
+        if (aFilletRadius != aPrevRadius) {
+          AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+              aSubFeature->attribute(SketchPlugin_Constraint::VALUE()));
+          aRadius->setValue(aFilletRadius);
+          std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
+              aData->attribute(PREVIOUS_VALUE))->setValue(aFilletRadius);
+        }
+        break;
+      }
+    }
     return;
+  }
   // Obtain features for the base objects
   FeaturePtr aFeatureA, aFeatureB;
-  ResultConstructionPtr aRC =
-      std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseA->object());
+  aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseA->object());
   if (aRC) aFeatureA = aRC->document()->feature(aRC);
   aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aBaseB->object());
   if (aRC) aFeatureB = aRC->document()->feature(aRC);
@@ -82,16 +128,14 @@ void SketchPlugin_ConstraintFillet::execute()
   FeaturePtr aNewFeatureA = sketch()->addFeature(aFeatureA->getKind());
   aFeatureA->data()->copyTo(aNewFeatureA->data());
   aNewFeatureA->execute();
-  aRefListOfFillet->append(aNewFeatureA);
+  aRefListOfFillet->append(aNewFeatureA->firstResult());
   // copy aFeatureB
   FeaturePtr aNewFeatureB = sketch()->addFeature(aFeatureB->getKind());
   aFeatureB->data()->copyTo(aNewFeatureB->data());
   aNewFeatureB->execute();
-  aRefListOfFillet->append(aNewFeatureB);
-  // create filleting arc
+  aRefListOfFillet->append(aNewFeatureB->firstResult());
+  // create filleting arc (it will be attached to the list later)
   FeaturePtr aNewArc = sketch()->addFeature(SketchPlugin_Arc::ID());
-  aRefListOfFillet->append(aNewArc);
-  aRefListOfFillet->setInitialized();
 
   // Wait all constraints being created, then send update events
   static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
@@ -177,11 +221,13 @@ void SketchPlugin_ConstraintFillet::execute()
       aCenter->x(), aCenter->y());
   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
       aNewArc->attribute(SketchPlugin_Arc::START_ID()))->setValue(
-      aCenter->x() - aStep->y(), aCenter->y() + aStep->x());
+      aSharedPoint->x() - 1.e-5 * aStep->y(), aSharedPoint->y() + 1.e-5 * aStep->x());
   std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
       aNewArc->attribute(SketchPlugin_Arc::END_ID()))->setValue(
-      aCenter->x() + aStep->y(), aCenter->y() - aStep->x());
+      aSharedPoint->x() + 1.e-5 * aStep->y(), aSharedPoint->y() - 1.e-5 * aStep->x());
   aNewArc->execute();
+  // attach new arc to the list
+  aRefListOfFillet->append(aNewArc->lastResult());
 
   // Create list of additional constraints:
   // 1. Coincidence of boundary points of features and fillet arc
@@ -211,15 +257,6 @@ void SketchPlugin_ConstraintFillet::execute()
   recalculateAttributes(aNewArc, SketchPlugin_Arc::END_ID(), aFeature[aFeatInd], aFeatAttributes[anAttrInd]);
   aConstraint->execute();
   ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
-  // recalculate center of fillet arc
-  std::shared_ptr<GeomAPI_Pnt2d> aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aNewArc->attribute(SketchPlugin_Arc::START_ID()))->pnt();
-  std::shared_ptr<GeomAPI_Pnt2d> aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aNewArc->attribute(SketchPlugin_Arc::END_ID()))->pnt();
-  aCenter = aStartPoint->xy()->added(aEndPoint->xy())->multiplied(0.5);
-  std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aNewArc->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(
-      aCenter->x(), aCenter->y());
   // 2. Fillet arc radius
   aConstraint = sketch()->addFeature(SketchPlugin_ConstraintRadius::ID());
   aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
@@ -245,20 +282,19 @@ void SketchPlugin_ConstraintFillet::execute()
     aConstraint->execute();
     ModelAPI_EventCreator::get()->sendUpdated(aConstraint, anUpdateEvent);
   }
+  // make base features auxiliary
+  aFeatureA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true);
+  aFeatureB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true);
 
-  // send events
-  ModelAPI_EventCreator::get()->sendUpdated(FeaturePtr(this), anUpdateEvent);
+  // send events to update the sub-features by the solver
   if (isUpdateFlushed)
     Events_Loop::loop()->setFlushed(anUpdateEvent, true);
-  Events_Loop::loop()->flush(anUpdateEvent);
 
-  // make base features auxiliary
-  static Events_ID aRedisplayEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
-  aFeatureA->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true);
-  aFeatureB->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(true);
-  ModelAPI_EventCreator::get()->sendUpdated(aFeatureA, aRedisplayEvent);
-  ModelAPI_EventCreator::get()->sendUpdated(aFeatureB, aRedisplayEvent);
-  Events_Loop::loop()->flush(aRedisplayEvent);
+  // the viewer update should be unblocked in order after the fillet features
+  // are processed by the solver
+  //aMsg = std::shared_ptr<Events_Message>(
+  //              new Events_Message(Events_Loop::eventByName(EVENT_UPDATE_VIEWER_UNBLOCKED)));
+  //Events_Loop::loop()->send(aMsg);
 }
 
 AISObjectPtr SketchPlugin_ConstraintFillet::getAISObject(AISObjectPtr thePrevious)