#include "SketchSolver_ConstraintManager.h"
#include <Events_Loop.h>
-#include <GeomDataAPI_Dir.h>
-#include <GeomDataAPI_Point.h>
-#include <GeomDataAPI_Point2D.h>
#include <ModelAPI_AttributeDouble.h>
#include <ModelAPI_AttributeRefList.h>
#include <ModelAPI_Data.h>
-#include <Model_Events.h>
+#include <ModelAPI_Events.h>
+
#include <SketchPlugin_Constraint.h>
-#include <SketchPlugin_ConstraintCoincidence.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
#include <SketchPlugin_Sketch.h>
+
+// Initialization of constraint manager self pointer
SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::_self = 0;
-/// Global constaint manager object
+/// Global constraint manager object
SketchSolver_ConstraintManager* myManager = SketchSolver_ConstraintManager::Instance();
-/// This value is used to give unique index to the groups
-static Slvs_hGroup myGroupIndexer = 0;
-
-/** \brief Makes transformation from ModelAPI_Attribute to the list of parameters' values
- * \remark Convertion of normal in 3D needs two attributes (coordinate axis of transversal plane)
- * \param[in,out] theParams list of converted values which appended to incoming list
- * \param[in] theAttr attribute to be converted
- * \param[in] theNormExtraAttr additional attribute for conversion of a normal
- */
-static void ConvertAttributeToParamList(
- std::vector<double>& theParams,
- boost::shared_ptr<ModelAPI_Attribute> theAttr,
- boost::shared_ptr<ModelAPI_Attribute> theNormExtraAttr = boost::shared_ptr<ModelAPI_Attribute>());
-
-/** \brief Search the entity/parameter with specified ID in the list of elements
- * \param[in] theEntityID unique ID of the element
- * \param[in] theEntities list of elements
- * \return position of the found element or -1 if the element is not found
- */
-template <typename T>
-static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
-
// ========================================================
// ========= SketchSolver_ConstraintManager ===============
myGroups.clear();
// Register in event loop
- Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_CREATED));
- Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
- Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_DELETED));
+ Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
+ Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+ Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
+ Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED));
}
SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
myGroups.clear();
}
+// ============================================================================
+// Function: processEvent
+// Class: SketchSolver_PluginManager
+// Purpose: listen the event loop and process the message
+// ============================================================================
void SketchSolver_ConstraintManager::processEvent(const Events_Message* theMessage)
{
- if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED))
+ if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED) ||
+ theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED) ||
+ theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED))
{
- const Model_FeatureUpdatedMessage* aCreateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
+ const ModelAPI_ObjectUpdatedMessage* anUpdateMsg =
+ dynamic_cast<const ModelAPI_ObjectUpdatedMessage*>(theMessage);
+ std::set< ObjectPtr > aFeatures = anUpdateMsg->features();
- // Only sketches and constraints can be added by Create event
- boost::shared_ptr<SketchPlugin_Sketch> aSketch =
- boost::dynamic_pointer_cast<SketchPlugin_Sketch>(aCreateMsg->feature());
- if (aSketch)
+ bool isModifiedEvt =
+ theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED);
+ if (!isModifiedEvt)
{
- addWorkplane(aSketch);
- return ;
- }
- boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
- boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aCreateMsg->feature());
- if (aConstraint)
- {
- addConstraint(aConstraint);
- return ;
+ std::set< ObjectPtr >::iterator aFeatIter;
+ for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++)
+ {
+ FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(*aFeatIter);
+ if (!aFeature) continue;
+ // Only sketches and constraints can be added by Create event
+ const std::string& aFeatureKind = aFeature->getKind();
+ if (aFeatureKind.compare(SketchPlugin_Sketch::ID()) == 0)
+ {
+ boost::shared_ptr<SketchPlugin_Feature> aSketch =
+ boost::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
+ if (aSketch)
+ changeWorkplane(aSketch);
+ continue;
+ }
+ boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
+ boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aFeature);
+ if (aConstraint)
+ changeConstraint(aConstraint);
+ else
+ {
+ // Sketch plugin features can be only updated
+ boost::shared_ptr<SketchPlugin_Feature> aSFeature =
+ boost::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
+ if (aSFeature)
+ updateEntity(aSFeature);
+ }
+ }
}
+
+ // Solve the set of constraints
+ resolveConstraints();
}
- else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_DELETED))
- {
- const Model_FeatureDeletedMessage* aDeleteMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
- /// \todo Implement deleting objects on event
- }
- else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED))
+ else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED))
{
- const Model_FeatureUpdatedMessage* aUpdateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
-
- boost::shared_ptr<SketchPlugin_Sketch> aSketch =
- boost::dynamic_pointer_cast<SketchPlugin_Sketch>(aUpdateMsg->feature());
- if (aSketch)
- {
- updateWorkplane(aSketch);
- return ;
- }
-
- boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
- boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aUpdateMsg->feature());
- if (aConstraint)
+ const ModelAPI_ObjectDeletedMessage* aDeleteMsg =
+ dynamic_cast<const ModelAPI_ObjectDeletedMessage*>(theMessage);
+ const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
+
+ // Find SketchPlugin_Sketch::ID() in groups. The constraint groups should be updated when an object removed from Sketch
+ std::set<std::string>::const_iterator aFGrIter;
+ for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
+ if (aFGrIter->compare(SketchPlugin_Sketch::ID()) == 0)
+ break;
+
+ if (aFGrIter != aFeatureGroups.end())
{
-// updateConstraint(aConstraint);
- return ;
+ std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter = myGroups.begin();
+ std::vector<SketchSolver_ConstraintGroup*> aSeparatedGroups;
+ while (aGroupIter != myGroups.end())
+ {
+ if (!(*aGroupIter)->isWorkplaneValid())
+ { // the group should be removed
+ delete *aGroupIter;
+ int aShift = aGroupIter - myGroups.begin();
+ myGroups.erase(aGroupIter);
+ aGroupIter = myGroups.begin() + aShift;
+ continue;
+ }
+ if ((*aGroupIter)->updateGroup())
+ { // some constraints were removed, try to split the group
+ (*aGroupIter)->splitGroup(aSeparatedGroups);
+ }
+ aGroupIter++;
+ }
+ if (aSeparatedGroups.size() > 0)
+ myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end());
}
-
- boost::shared_ptr<SketchPlugin_Feature> aFeature =
- boost::dynamic_pointer_cast<SketchPlugin_Feature>(aUpdateMsg->feature());
-// if (aFeature)
-// updateEntity(aFeature);
}
}
-
-bool SketchSolver_ConstraintManager::addWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch)
-{
- // Check the specified workplane is already used
- std::vector<SketchSolver_ConstraintGroup>::const_iterator aGroupIter;
- for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
- if (aGroupIter->isBaseWorkplane(theSketch))
- return true;
- // Create new group for workplane
- SketchSolver_ConstraintGroup aNewGroup(theSketch);
- // Verify that the group is created successfully
- if (!aNewGroup.isBaseWorkplane(theSketch))
- return false;
- myGroups.push_back(aNewGroup);
- return true;
-}
-
-bool SketchSolver_ConstraintManager::updateWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch)
+// ============================================================================
+// Function: changeWorkplane
+// Class: SketchSolver_PluginManager
+// Purpose: update workplane by given parameters of the sketch
+// ============================================================================
+bool SketchSolver_ConstraintManager::changeWorkplane(boost::shared_ptr<SketchPlugin_Feature> theSketch)
{
bool aResult = true; // changed when a workplane wrongly updated
bool isUpdated = false;
// Try to update specified workplane in all groups
- std::vector<SketchSolver_ConstraintGroup>::iterator aGroupIter;
+ std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
- if (aGroupIter->isBaseWorkplane(theSketch))
+ if ((*aGroupIter)->isBaseWorkplane(theSketch))
{
isUpdated = true;
- if (!aGroupIter->updateWorkplane(theSketch))
+ if (!(*aGroupIter)->updateWorkplane())
aResult = false;
}
- // If the workplane is not updates, so this is a new workplane
+ // If the workplane is not updated, so this is a new workplane
if (!isUpdated)
- return addWorkplane(theSketch);
+ {
+ SketchSolver_ConstraintGroup* aNewGroup = new SketchSolver_ConstraintGroup(theSketch);
+ // Verify that the group is created successfully
+ if (!aNewGroup->isBaseWorkplane(theSketch))
+ {
+ delete aNewGroup;
+ return false;
+ }
+ myGroups.push_back(aNewGroup);
+ }
return aResult;
}
-bool SketchSolver_ConstraintManager::addConstraint(
+// ============================================================================
+// Function: changeConstraint
+// Class: SketchSolver_PluginManager
+// Purpose: create/update the constraint and place it into appropriate group
+// ============================================================================
+bool SketchSolver_ConstraintManager::changeConstraint(
boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
{
- // Search the groups which this constraint touchs
- std::vector<Slvs_hGroup> aGroups;
+ // Search the groups which this constraint touches
+ std::set<Slvs_hGroup> aGroups;
findGroups(theConstraint, aGroups);
// Process the groups list
if (aGroups.size() == 0)
{ // There are no groups applicable for this constraint => create new one
- boost::shared_ptr<SketchPlugin_Sketch> aWP = findWorkplaneForConstraint(theConstraint);
+ boost::shared_ptr<SketchPlugin_Feature> aWP = findWorkplaneForConstraint(theConstraint);
if (!aWP) return false;
- SketchSolver_ConstraintGroup aGroup(aWP);
- aGroup.addConstraint(theConstraint);
+ SketchSolver_ConstraintGroup* aGroup = new SketchSolver_ConstraintGroup(aWP);
+ if (!aGroup->changeConstraint(theConstraint))
+ {
+ delete aGroup;
+ return false;
+ }
myGroups.push_back(aGroup);
return true;
}
else if (aGroups.size() == 1)
{ // Only one group => add constraint into it
Slvs_hGroup aGroupId = *(aGroups.begin());
- std::vector<SketchSolver_ConstraintGroup>::iterator aGroupIter;
+ std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
- if (aGroupIter->getId() == aGroupId)
- return aGroupIter->addConstraint(theConstraint);
+ if ((*aGroupIter)->getId() == aGroupId)
+ return (*aGroupIter)->changeConstraint(theConstraint);
}
else if (aGroups.size() > 1)
{ // Several groups applicable for this constraint => need to merge them
- /// \todo Implement merging of groups
+ std::set<Slvs_hGroup>::const_iterator aGroupsIter = aGroups.begin();
+
+ // Search first group
+ std::vector<SketchSolver_ConstraintGroup*>::iterator aFirstGroupIter;
+ for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
+ if ((*aFirstGroupIter)->getId() == *aGroupsIter)
+ break;
+ if (aFirstGroupIter == myGroups.end())
+ return false;
+
+ // Append other groups to the first one
+ std::vector<SketchSolver_ConstraintGroup*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
+ for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++)
+ {
+ for ( ; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
+ if ((*anOtherGroupIter)->getId() == *aGroupsIter)
+ break;
+ if (anOtherGroupIter == myGroups.end())
+ { // Group disappears
+ anOtherGroupIter = aFirstGroupIter + 1;
+ continue;
+ }
+
+ (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter);
+ int aShiftFirst = aFirstGroupIter - myGroups.begin();
+ int aShiftOther = anOtherGroupIter - myGroups.begin();
+ delete *anOtherGroupIter;
+ myGroups.erase(anOtherGroupIter);
+ aFirstGroupIter = myGroups.begin() + aShiftFirst;
+ anOtherGroupIter = myGroups.begin() + aShiftOther;
+ }
+
+ return (*aFirstGroupIter)->changeConstraint(theConstraint);
}
// Something goes wrong
return false;
}
-
-void SketchSolver_ConstraintManager::findGroups(
- boost::shared_ptr<SketchPlugin_Constraint> theConstraint,
- std::vector<Slvs_hGroup>& theGroupIDs) const
+// ============================================================================
+// Function: updateEntity
+// Class: SketchSolver_PluginManager
+// Purpose: update any element on the sketch, which is used by constraints
+// ============================================================================
+void SketchSolver_ConstraintManager::updateEntity(boost::shared_ptr<SketchPlugin_Feature> theFeature)
{
- std::vector<SketchSolver_ConstraintGroup>::const_iterator aGroupIter;
- for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
- if (aGroupIter->isInteract(theConstraint))
- theGroupIDs.push_back(aGroupIter->getId());
-}
-
-boost::shared_ptr<SketchPlugin_Sketch> SketchSolver_ConstraintManager::findWorkplaneForConstraint(
- boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
-{
- std::vector<SketchSolver_ConstraintGroup>::const_iterator aGroupIter;
- for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+ // Create list of attributes depending on type of the feature
+ std::vector<std::string> anAttrList;
+ const std::string& aFeatureKind = theFeature->getKind();
+ // Point
+ if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0)
+ anAttrList.push_back(SketchPlugin_Point::COORD_ID());
+ // Line
+ else if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0)
{
- boost::shared_ptr<SketchPlugin_Sketch> aWP = aGroupIter->getWorkplane();
- boost::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures =
- boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aWP->data()->attribute(SKETCH_ATTR_FEATURES));
- std::list< boost::shared_ptr<ModelAPI_Feature> > aFeaturesList = aWPFeatures->list();
- std::list< boost::shared_ptr<ModelAPI_Feature> >::const_iterator anIter;
- for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
- if (*anIter == theConstraint)
- return aWP; // workplane is found
+ anAttrList.push_back(SketchPlugin_Line::START_ID());
+ anAttrList.push_back(SketchPlugin_Line::END_ID());
}
-
- return boost::shared_ptr<SketchPlugin_Sketch>();
-}
-
-
-
-// ========================================================
-// ========= SketchSolver_ConstraintGroup ===============
-// ========================================================
-
-SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::
- SketchSolver_ConstraintGroup(boost::shared_ptr<SketchPlugin_Sketch> theWorkplane)
- : myID(++myGroupIndexer),
- myParamMaxID(0),
- myEntityMaxID(0),
- myConstrMaxID(0),
- myConstraintMap()
-{
- myParams.clear();
- myEntities.clear();
- myConstraints.clear();
-
- // Nullify all elements of the set of equations
- myConstrSet.param = 0;
- myConstrSet.entity = 0;
- myConstrSet.constraint = 0;
- myConstrSet.failed = 0;
-
- // Initialize workplane
- myWorkplane.h = 0;
- addWorkplane(theWorkplane);
-}
-
-SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup()
-{
- myParams.clear();
- myEntities.clear();
- myConstraints.clear();
- myConstraintMap.clear();
-
- if (myConstrSet.param)
- delete [] myConstrSet.param;
- if (myConstrSet.entity)
- delete [] myConstrSet.entity;
- if (myConstrSet.constraint)
- delete [] myConstrSet.constraint;
- if (myConstrSet.failed)
- delete [] myConstrSet.failed;
-}
-
-bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isBaseWorkplane(
- boost::shared_ptr<SketchPlugin_Sketch> theWorkplane) const
-{
- return theWorkplane == mySketch;
-}
-
-bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isInteract(
- boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
-{
- /// \todo Should be implemented
- return false;
-}
-
-bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addConstraint(
- boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
-{
- // There is no workplane yet, something wrong
- if (myWorkplane.h == 0)
- return false;
-
- // Get constraint type and verify the constraint parameters are correct
- int aConstrType = getConstraintType(theConstraint);
- if (aConstrType == SLVS_C_UNKNOWN)
- return false;
-
- // Create constraint parameters
- double aDistance = 0.0; // scalar value of the constraint
- boost::shared_ptr<ModelAPI_AttributeDouble> aDistAttr =
- boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theConstraint->data()->attribute(CONSTRAINT_ATTR_VALUE));
- if (aDistAttr)
- aDistance = aDistAttr->value();
-
- Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
+ // Circle
+ else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0)
{
- boost::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr =
- boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[indAttr])
- );
- aConstrEnt[indAttr] = addEntity(aConstrAttr->attr());
+ anAttrList.push_back(SketchPlugin_Circle::CENTER_ID());
+ anAttrList.push_back(SketchPlugin_Circle::RADIUS_ID());
}
-
- // Create SolveSpace constraint structure
- Slvs_Constraint aConstraint =
- Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, myWorkplane.h,
- aDistance, aConstrEnt[0], aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
- myConstraints.push_back(aConstraint);
- myConstraintMap[theConstraint] = *(myConstraints.rbegin());
-
- return true;
-}
-
-Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addEntity(
- boost::shared_ptr<ModelAPI_Attribute> theEntity)
-{
- // Look over supported types of entities
-
- // Point in 3D
- boost::shared_ptr<GeomDataAPI_Point> aPoint =
- boost::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
- if (aPoint)
+ // Arc
+ else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0)
{
- Slvs_hParam aX = addParameter(aPoint->x());
- Slvs_hParam aY = addParameter(aPoint->y());
- Slvs_hParam aZ = addParameter(aPoint->z());
- Slvs_Entity aPtEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
- myEntities.push_back(aPtEntity);
- return aPtEntity.h;
+ anAttrList.push_back(SketchPlugin_Arc::CENTER_ID());
+ anAttrList.push_back(SketchPlugin_Arc::START_ID());
+ anAttrList.push_back(SketchPlugin_Arc::END_ID());
}
+ /// \todo Other types of features should be implemented
- // Point in 2D
- boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
- boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
- if (aPoint2D)
+ // Check changing of feature's attributes (go through the groups and search usage of the attributes)
+ std::vector<std::string>::const_iterator anAttrIter;
+ for (anAttrIter = anAttrList.begin(); anAttrIter != anAttrList.end(); anAttrIter++)
{
- // The 2D points are created on workplane. So, if there is no workplane yet, then error
- if (myWorkplane.h == 0)
- return 0;
- Slvs_hParam aU = addParameter(aPoint2D->x());
- Slvs_hParam aV = addParameter(aPoint2D->y());
- Slvs_Entity aPt2DEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
- myEntities.push_back(aPt2DEntity);
- return aPt2DEntity.h;
+ std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
+ for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+ {
+ if ((*aGroupIter)->isEmpty())
+ continue;
+ boost::shared_ptr<ModelAPI_Attribute> anAttribute =
+ boost::dynamic_pointer_cast<ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter));
+ (*aGroupIter)->updateEntityIfPossible(anAttribute);
+ }
}
- /// \todo Other types of entities
-
- // Unsupported or wrong entity type
- return 0;
-}
-
-Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addNormal(
- boost::shared_ptr<ModelAPI_Attribute> theDirX,
- boost::shared_ptr<ModelAPI_Attribute> theDirY)
-{
- // Convert axes to the coordinates of normal
- std::vector<double> aNormCoord;
- ConvertAttributeToParamList(aNormCoord, theDirX, theDirY);
-
- // Create a normal
- Slvs_hParam aNormParams[4];
- for (int i = 0; i < 4; i++)
- aNormParams[i] = addParameter(aNormCoord[i]);
- Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID,
- aNormParams[0], aNormParams[1], aNormParams[2], aNormParams[3]);
- myEntities.push_back(aNormal);
- return aNormal.h;
+ std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
+ for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+ if (!(*aGroupIter)->isEmpty())
+ (*aGroupIter)->updateRelatedConstraints(theFeature);
}
-bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addWorkplane(
- boost::shared_ptr<SketchPlugin_Sketch> theSketch)
-{
- if (myWorkplane.h)
- return false; // the workplane already exists
-
- // Get parameters of workplane
- boost::shared_ptr<ModelAPI_Attribute> aDirX = theSketch->data()->attribute(SKETCH_ATTR_DIRX);
- boost::shared_ptr<ModelAPI_Attribute> aDirY = theSketch->data()->attribute(SKETCH_ATTR_DIRY);
- boost::shared_ptr<ModelAPI_Attribute> anOrigin = theSketch->data()->attribute(SKETCH_ATTR_ORIGIN);
- // Transform them into SolveSpace format
- Slvs_hEntity aNormalWP = addNormal(aDirX, aDirY);
- if (!aNormalWP) return false;
- Slvs_hEntity anOriginWP = addEntity(anOrigin);
- if (!anOriginWP) return false;
- // Create workplane
- myWorkplane = Slvs_MakeWorkplane(++myEntityMaxID, myID, anOriginWP, aNormalWP);
- mySketch = theSketch;
- // Workplane should be added to the list of entities
- myEntities.push_back(myWorkplane);
- return true;
-}
-
-bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateWorkplane(
- boost::shared_ptr<SketchPlugin_Sketch> theSketch)
+// ============================================================================
+// Function: findGroups
+// Class: SketchSolver_PluginManager
+// Purpose: search groups of entities interacting with given constraint
+// ============================================================================
+void SketchSolver_ConstraintManager::findGroups(
+ boost::shared_ptr<SketchPlugin_Constraint> theConstraint,
+ std::set<Slvs_hGroup>& theGroupIDs) const
{
- // Renew Sketch pointer
- mySketch = theSketch;
-
- // Get parameters of workplane
- boost::shared_ptr<ModelAPI_Attribute> aDirX = theSketch->data()->attribute(SKETCH_ATTR_DIRX);
- boost::shared_ptr<ModelAPI_Attribute> aDirY = theSketch->data()->attribute(SKETCH_ATTR_DIRY);
- boost::shared_ptr<ModelAPI_Attribute> anOrig = theSketch->data()->attribute(SKETCH_ATTR_ORIGIN);
- // Transform them to lists of coordinates
- std::vector<double> aNormal;
- ConvertAttributeToParamList(aNormal, aDirX, aDirY);
- std::vector<double> anOrigin;
- ConvertAttributeToParamList(anOrigin, anOrig);
-
- // Search the normal and the origin in the parameters list and update their values.
- // Remark: entities are sorted in the vector, so the most probable position
- // of the entity is equal to identifier the entity
-
- // search normal
- int aEntPos = Search(myWorkplane.normal, myEntities);
- if (aEntPos < 0) return false;
- // search first parameter of normal
- int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
- if (aParamPos < 0) return false;
- std::vector<Slvs_Param>::iterator aParamIter = myParams.begin() + aParamPos;
- // change normal parameters
- std::vector<double>::iterator anIter;
- for (anIter = aNormal.begin(); anIter != aNormal.end(); anIter++, aParamIter++)
- aParamIter->val = *anIter;
-
- // search origin
- aEntPos = Search(myWorkplane.point[0], myEntities);
- if (aEntPos < 0) return false;
- // search first parameter of origin
- aParamPos = Search(myEntities[aEntPos].param[0], myParams);
- if (aParamPos < 0) return false;
- aParamIter = myParams.begin() + aParamPos;
- // change origin's parameters
- for (anIter = anOrigin.begin(); anIter != anOrigin.end(); anIter++, aParamIter++)
- aParamIter->val = *anIter;
-
- return true;
-}
+ boost::shared_ptr<SketchPlugin_Feature> aWP = findWorkplaneForConstraint(theConstraint);
-
-Slvs_hParam SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addParameter(double theParam)
-{
- Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
- myParams.push_back(aParam);
- return aParam.h;
-}
-
-int SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::getConstraintType(
- const boost::shared_ptr<SketchPlugin_Constraint>& theConstraint) const
-{
- // Constraint for coincidence of two points
- boost::shared_ptr<SketchPlugin_ConstraintCoincidence> aPtEquiv =
- boost::dynamic_pointer_cast<SketchPlugin_ConstraintCoincidence>(theConstraint);
- if (aPtEquiv)
- {
- // Verify the constraint has only two attributes and they are points
- int aPt2d = 0; // bit-mapped field, each bit indicates whether the attribute is 2D point
- int aPt3d = 0; // bit-mapped field, the same information for 3D points
- for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
+ SketchSolver_ConstraintGroup* anEmptyGroup = 0; // appropriate empty group for specified constraint
+ std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
+ for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+ if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theConstraint))
{
- boost::shared_ptr<ModelAPI_AttributeRefAttr> anAttr =
- boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[indAttr])
- );
- // Verify the attribute is a 2D point
- boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
- boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
- if (aPoint2D)
- {
- aPt2d |= (1 << indAttr);
- continue;
- }
- // Verify the attribute is a 3D point
- boost::shared_ptr<GeomDataAPI_Point> aPoint3D =
- boost::dynamic_pointer_cast<GeomDataAPI_Point>(anAttr->attr());
- if (aPoint3D)
- {
- aPt3d |= (1 << indAttr);
- continue;
- }
- // Attribute neither 2D nor 3D point is not supported by this type of constraint
- return SLVS_C_UNKNOWN;
+ if (!(*aGroupIter)->isEmpty())
+ theGroupIDs.insert((*aGroupIter)->getId());
+ else if (!anEmptyGroup)
+ anEmptyGroup = *aGroupIter;
}
- // The constrained points should be in first and second positions,
- // so the expected value of aPt2d or aPt3d is 3
- if ((aPt2d == 3 && aPt3d == 0) || (aPt2d == 0 && aPt3d == 3))
- return SLVS_C_POINTS_COINCIDENT;
- // Constraint parameters are wrong
- return SLVS_C_UNKNOWN;
- }
-
- /// \todo Implement other kind of constrtaints
- return SLVS_C_UNKNOWN;
+ // When only empty group is found, use it
+ if (anEmptyGroup && theGroupIDs.empty())
+ theGroupIDs.insert(anEmptyGroup->getId());
}
-
-
-// ========================================================
-// ========= Auxiliary functions ===============
-// ========================================================
-
-void ConvertAttributeToParamList(
- std::vector<double>& theParams,
- boost::shared_ptr<ModelAPI_Attribute> theAttr,
- boost::shared_ptr<ModelAPI_Attribute> theNormExtraAttr)
+// ============================================================================
+// Function: findWorkplaneForConstraint
+// Class: SketchSolver_PluginManager
+// Purpose: search workplane containing given constraint
+// ============================================================================
+boost::shared_ptr<SketchPlugin_Feature> SketchSolver_ConstraintManager::findWorkplaneForConstraint(
+ boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
{
- // Point in 3D
- boost::shared_ptr<GeomDataAPI_Point> aPoint =
- boost::dynamic_pointer_cast<GeomDataAPI_Point>(theAttr);
- if (aPoint)
- {
- theParams.push_back(aPoint->x());
- theParams.push_back(aPoint->y());
- theParams.push_back(aPoint->z());
- return ;
- }
-
- // Point in 2D
- boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
- boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttr);
- if (aPoint2D)
- {
- theParams.push_back(aPoint2D->x());
- theParams.push_back(aPoint2D->y());
- return ;
- }
+ // Already verified workplanes
+ std::set< boost::shared_ptr<SketchPlugin_Feature> > aVerified;
- // Normal in 3D
- boost::shared_ptr<GeomDataAPI_Dir> aDirX =
- boost::dynamic_pointer_cast<GeomDataAPI_Dir>(theAttr);
- boost::shared_ptr<GeomDataAPI_Dir> aDirY =
- boost::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormExtraAttr);
- if (aDirX && aDirY)
+ std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
+ for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
{
- // quaternion parameters of normal vector
- double qw, qx, qy, qz;
- Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(),
- aDirY->x(), aDirY->y(), aDirY->z(),
- &qw, &qx, &qy, &qz);
- theParams.push_back(qw);
- theParams.push_back(qx);
- theParams.push_back(qy);
- theParams.push_back(qz);
+ boost::shared_ptr<SketchPlugin_Feature> aWP = (*aGroupIter)->getWorkplane();
+ if (aVerified.find(aWP) != aVerified.end())
+ continue;
+
+ boost::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures =
+ boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aWP->data()->attribute(SketchPlugin_Sketch::FEATURES_ID()));
+ std::list< ObjectPtr >& aFeaturesList = aWPFeatures->list();
+ std::list< ObjectPtr >::const_iterator anIter;
+ for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
+ if (*anIter == theConstraint)
+ return aWP; // workplane is found
+ aVerified.insert(aWP);
}
- /// \todo Other types of entities
+ return boost::shared_ptr<SketchPlugin_Feature>();
}
-template <typename T>
-int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
+// ============================================================================
+// Function: resolveConstraints
+// Class: SketchSolver_PluginManager
+// Purpose: change entities according to available constraints
+// ============================================================================
+void SketchSolver_ConstraintManager::resolveConstraints()
{
- std::vector<T>::const_iterator aEntIter = theEntities.begin() + theEntityID - 1;
- while (aEntIter != theEntities.end() && aEntIter->h > theEntityID)
- aEntIter--;
- while (aEntIter != theEntities.end() && aEntIter->h < theEntityID)
- aEntIter++;
- if (aEntIter == theEntities.end())
- return -1;
- return aEntIter - theEntities.begin();
+ std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
+ for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+ (*aGroupIter)->resolveConstraints();
+
+ // Features may be updated => send events
+ Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
}