#include <SketchPlugin_Constraint.h>
#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
#include <SketchPlugin_Sketch.h>
+#include <math.h>
+
+/// Tolerance for value of parameters
+const double tolerance = 1.e-10;
+
+// Initialization of constraint manager self pointer
SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::_self = 0;
/// Global constaint manager object
/// 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
static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
+
// ========================================================
// ========= SketchSolver_ConstraintManager ===============
// ========================================================
void SketchSolver_ConstraintManager::processEvent(const Events_Message* theMessage)
{
- if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED))
- {
- const Model_FeatureUpdatedMessage* aCreateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
-
- // 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)
- {
- addWorkplane(aSketch);
- return ;
- }
- boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
- boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aCreateMsg->feature());
- if (aConstraint)
- {
- addConstraint(aConstraint);
- return ;
- }
- }
- 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))
+ if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED) ||
+ theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED))
{
const Model_FeatureUpdatedMessage* aUpdateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
+ // Only sketches and constraints can be added by Create event
boost::shared_ptr<SketchPlugin_Sketch> aSketch =
boost::dynamic_pointer_cast<SketchPlugin_Sketch>(aUpdateMsg->feature());
if (aSketch)
{
- updateWorkplane(aSketch);
+ changeWorkplane(aSketch);
return ;
}
-
boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aUpdateMsg->feature());
if (aConstraint)
{
-// updateConstraint(aConstraint);
+ changeConstraint(aConstraint);
+
+ // Solve the set of constraints
+ ResolveConstraints();
return ;
}
+ /// \todo Implement feature update handling
boost::shared_ptr<SketchPlugin_Feature> aFeature =
boost::dynamic_pointer_cast<SketchPlugin_Feature>(aUpdateMsg->feature());
-// if (aFeature)
-// updateEntity(aFeature);
- }
-}
-
+ 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;
+ // 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
+ }
}
-bool SketchSolver_ConstraintManager::updateWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch)
+bool SketchSolver_ConstraintManager::changeWorkplane(boost::shared_ptr<SketchPlugin_Sketch> 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(
+bool SketchSolver_ConstraintManager::changeConstraint(
boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
{
// Search the groups which this constraint touchs
{ // There are no groups applicable for this constraint => create new one
boost::shared_ptr<SketchPlugin_Sketch> 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
return false;
}
+void SketchSolver_ConstraintManager::updateEntity(boost::shared_ptr<SketchPlugin_Feature> theFeature)
+{
+ // Create list of attributes depending on type of the feature
+ std::vector<std::string> anAttrList;
+ // Point
+ boost::shared_ptr<SketchPlugin_Point> aPoint =
+ boost::dynamic_pointer_cast<SketchPlugin_Point>(theFeature);
+ if (aPoint)
+ anAttrList.push_back(POINT_ATTR_COORD);
+ // Line
+ boost::shared_ptr<SketchPlugin_Line> aLine =
+ boost::dynamic_pointer_cast<SketchPlugin_Line>(theFeature);
+ if (aLine)
+ {
+ anAttrList.push_back(LINE_ATTR_START);
+ anAttrList.push_back(LINE_ATTR_END);
+ }
+ /// \todo Other types of features should be implemented
+
+ // 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++)
+ {
+ std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
+ for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+ {
+ boost::shared_ptr<ModelAPI_Attribute> anAttribute =
+ boost::dynamic_pointer_cast<ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter));
+ (*aGroupIter)->updateEntityIfPossible(anAttribute);
+ }
+ }
+}
+
void SketchSolver_ConstraintManager::findGroups(
boost::shared_ptr<SketchPlugin_Constraint> theConstraint,
std::vector<Slvs_hGroup>& theGroupIDs) const
{
- std::vector<SketchSolver_ConstraintGroup>::const_iterator aGroupIter;
+ boost::shared_ptr<SketchPlugin_Sketch> aWP = findWorkplaneForConstraint(theConstraint);
+
+ std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
- if (aGroupIter->isInteract(theConstraint))
- theGroupIDs.push_back(aGroupIter->getId());
+ if (aWP == (*aGroupIter)->getWorkplane() && (*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;
+ std::vector<SketchSolver_ConstraintGroup*>::const_iterator aGroupIter;
for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
{
- boost::shared_ptr<SketchPlugin_Sketch> aWP = aGroupIter->getWorkplane();
+ 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();
return boost::shared_ptr<SketchPlugin_Sketch>();
}
+void SketchSolver_ConstraintManager::ResolveConstraints()
+{
+ std::vector<SketchSolver_ConstraintGroup*>::iterator aGroupIter;
+ for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+ (*aGroupIter)->ResolveConstraints();
+}
+
// ========================================================
myParamMaxID(0),
myEntityMaxID(0),
myConstrMaxID(0),
- myConstraintMap()
+ myConstraintMap(),
+ myNeedToSolve(false),
+ myConstrSolver()
{
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;
+ myWorkplane.h = SLVS_E_UNKNOWN;
addWorkplane(theWorkplane);
}
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;
+ // If the group with maximal identifier is deleted, decrease the indexer
+ if (myID == myGroupIndexer)
+ myGroupIndexer--;
}
bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isBaseWorkplane(
bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isInteract(
boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
{
+ // Check the group is empty
+ if (myWorkplane.h != SLVS_E_UNKNOWN && myConstraints.empty())
+ return true;
+
/// \todo Should be implemented
return false;
}
-bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addConstraint(
+bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::changeConstraint(
boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
{
// There is no workplane yet, something wrong
- if (myWorkplane.h == 0)
+ if (myWorkplane.h == SLVS_E_UNKNOWN)
return false;
+ // Search this constraint in the current group to update it
+ std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>::const_iterator
+ aConstrMapIter = myConstraintMap.find(theConstraint);
+ std::vector<Slvs_Constraint>::iterator aConstrIter;
+ if (aConstrMapIter != myConstraintMap.end())
+ {
+ int aConstrPos = Search(aConstrMapIter->second, myConstraints);
+ aConstrIter = myConstraints.begin() + aConstrPos;
+ }
+
// Get constraint type and verify the constraint parameters are correct
int aConstrType = getConstraintType(theConstraint);
- if (aConstrType == SLVS_C_UNKNOWN)
+ if (aConstrType == SLVS_C_UNKNOWN ||
+ (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
return false;
// Create constraint parameters
boost::shared_ptr<ModelAPI_AttributeDouble> aDistAttr =
boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theConstraint->data()->attribute(CONSTRAINT_ATTR_VALUE));
if (aDistAttr)
+ {
aDistance = aDistAttr->value();
+ if (aConstrMapIter != myConstraintMap.end() && fabs(aConstrIter->valA - aDistance) > tolerance)
+ {
+ myNeedToSolve = true;
+ aConstrIter->valA = aDistance;
+ }
+ }
Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint
for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
{
+ aConstrEnt[indAttr] = SLVS_E_UNKNOWN;
boost::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr =
boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[indAttr])
);
- aConstrEnt[indAttr] = addEntity(aConstrAttr->attr());
+ if (!aConstrAttr) continue;
+ aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr());
}
- // 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());
-
+ if (aConstrMapIter == myConstraintMap.end())
+ {
+ // 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] = aConstraint.h;
+ }
return true;
}
-Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addEntity(
+Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::changeEntity(
boost::shared_ptr<ModelAPI_Attribute> theEntity)
{
+ // If the entity is already in the group, try to find it
+ std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
+ aEntIter = myEntityMap.find(theEntity);
+ std::vector<Slvs_Param>::const_iterator aParamIter; // looks at first parameter of already existent entity or at the end of vector otherwise
+ if (aEntIter == myEntityMap.end()) // no such entity => should be created
+ aParamIter = myParams.end();
+ else
+ { // the entity already exists
+ int aEntPos = Search(aEntIter->second, myEntities);
+ int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
+ aParamIter = myParams.begin() + aParamPos;
+ }
+
// Look over supported types of entities
// Point in 3D
boost::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
if (aPoint)
{
- Slvs_hParam aX = addParameter(aPoint->x());
- Slvs_hParam aY = addParameter(aPoint->y());
- Slvs_hParam aZ = addParameter(aPoint->z());
+ Slvs_hParam aX = changeParameter(aPoint->x(), aParamIter);
+ Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter);
+ Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter);
+
+ if (aEntIter != myEntityMap.end()) // the entity already exists
+ return aEntIter->second;
+
+ // New entity
Slvs_Entity aPtEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
myEntities.push_back(aPtEntity);
+ myEntityMap[theEntity] = aPtEntity.h;
return aPtEntity.h;
}
if (aPoint2D)
{
// 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());
+ if (myWorkplane.h == SLVS_E_UNKNOWN)
+ return SLVS_E_UNKNOWN;
+ Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter);
+ Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter);
+
+ if (aEntIter != myEntityMap.end()) // the entity already exists
+ return aEntIter->second;
+
+ // New entity
Slvs_Entity aPt2DEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
myEntities.push_back(aPt2DEntity);
+ myEntityMap[theEntity] = aPt2DEntity.h;
return aPt2DEntity.h;
}
/// \todo Other types of entities
// Unsupported or wrong entity type
- return 0;
+ return SLVS_E_UNKNOWN;
}
-Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addNormal(
+Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::changeNormal(
boost::shared_ptr<ModelAPI_Attribute> theDirX,
- boost::shared_ptr<ModelAPI_Attribute> theDirY)
+ boost::shared_ptr<ModelAPI_Attribute> theDirY,
+ boost::shared_ptr<ModelAPI_Attribute> theNorm)
{
- // Convert axes to the coordinates of normal
- std::vector<double> aNormCoord;
- ConvertAttributeToParamList(aNormCoord, theDirX, theDirY);
-
- // Create a normal
+ boost::shared_ptr<GeomDataAPI_Dir> aDirX =
+ boost::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
+ boost::shared_ptr<GeomDataAPI_Dir> aDirY =
+ boost::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirY);
+ if (!aDirX || !aDirY ||
+ (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) ||
+ (fabs(aDirY->x()) + fabs(aDirY->y()) + fabs(aDirY->z()) < tolerance))
+ return SLVS_E_UNKNOWN;
+
+ // 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);
+ double aNormCoord[4] = {qw, qx, qy, qz};
+
+ // Try to find existent normal
+ std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
+ aEntIter = myEntityMap.find(theNorm);
+ std::vector<Slvs_Param>::const_iterator aParamIter; // looks at first parameter of already existent entity or at the end of vector otherwise
+ if (aEntIter == myEntityMap.end()) // no such entity => should be created
+ aParamIter = myParams.end();
+ else
+ { // the entity already exists, update it
+ int aEntPos = Search(aEntIter->second, myEntities);
+ int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
+ aParamIter = myParams.begin() + aParamPos;
+ }
+
+ // Change parameters of the normal
Slvs_hParam aNormParams[4];
for (int i = 0; i < 4; i++)
- aNormParams[i] = addParameter(aNormCoord[i]);
+ aNormParams[i] = changeParameter(aNormCoord[i], aParamIter);
+
+ if (aEntIter != myEntityMap.end()) // the entity already exists
+ return aEntIter->second;
+
+ // Create a normal
Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID,
aNormParams[0], aNormParams[1], aNormParams[2], aNormParams[3]);
myEntities.push_back(aNormal);
+ myEntityMap[theNorm] = aNormal.h;
return aNormal.h;
}
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;
+ return updateWorkplane();
}
-bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateWorkplane(
- boost::shared_ptr<SketchPlugin_Sketch> theSketch)
+bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateWorkplane()
{
- // 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;
+ boost::shared_ptr<ModelAPI_Attribute> aDirX = mySketch->data()->attribute(SKETCH_ATTR_DIRX);
+ boost::shared_ptr<ModelAPI_Attribute> aDirY = mySketch->data()->attribute(SKETCH_ATTR_DIRY);
+ boost::shared_ptr<ModelAPI_Attribute> aNorm = mySketch->data()->attribute(SKETCH_ATTR_NORM);
+ boost::shared_ptr<ModelAPI_Attribute> anOrigin = mySketch->data()->attribute(SKETCH_ATTR_ORIGIN);
+ // Transform them into SolveSpace format
+ Slvs_hEntity aNormalWP = changeNormal(aDirX, aDirY, aNorm);
+ if (!aNormalWP) return false;
+ Slvs_hEntity anOriginWP = changeEntity(anOrigin);
+ if (!anOriginWP) return false;
+ if (!myWorkplane.h)
+ {
+ // Create workplane
+ myWorkplane = Slvs_MakeWorkplane(++myEntityMaxID, myID, anOriginWP, aNormalWP);
+ // Workplane should be added to the list of entities
+ myEntities.push_back(myWorkplane);
+ }
return true;
}
-Slvs_hParam SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addParameter(double theParam)
+Slvs_hParam SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::changeParameter(
+ const double& theParam,
+ std::vector<Slvs_Param>::const_iterator& thePrmIter)
{
+ if (thePrmIter != myParams.end())
+ { // Parameter should be updated
+ int aParamPos = thePrmIter - myParams.begin();
+ if (fabs(thePrmIter->val - theParam) > tolerance)
+ {
+ myNeedToSolve = true; // parameter is changed, need to resolve constraints
+ myParams[aParamPos].val = theParam;
+ }
+ thePrmIter++;
+ return myParams[aParamPos].h;
+ }
+
+ // Newly created parameter
Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
myParams.push_back(aParam);
+ myNeedToSolve = true;
+ // The list of parameters is changed, move iterator to the end of the list to avoid problems
+ thePrmIter = myParams.end();
return aParam.h;
}
boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[indAttr])
);
+ if (!anAttr) continue;
// Verify the attribute is a 2D point
boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
return SLVS_C_UNKNOWN;
}
+void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::ResolveConstraints()
+{
+ if (!myNeedToSolve)
+ return;
+
+ myConstrSolver.setGroupID(myID);
+ myConstrSolver.setParameters(myParams);
+ myConstrSolver.setEntities(myEntities);
+ myConstrSolver.setConstraints(myConstraints);
+
+ if (myConstrSolver.solve() == SLVS_RESULT_OKAY)
+ { // solution succeeded, store results into correspondent attributes
+ // Obtain result into the same list of parameters
+ if (!myConstrSolver.getResult(myParams))
+ return;
+
+ std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::iterator
+ anEntIter = myEntityMap.begin();
+ for ( ; anEntIter != myEntityMap.end(); anEntIter++)
+ updateAttribute(anEntIter->first, anEntIter->second);
+ }
+ /// \todo Implement error handling
+ removeTemporaryConstraints();
+ myNeedToSolve = false;
+}
-// ========================================================
-// ========= Auxiliary functions ===============
-// ========================================================
-void ConvertAttributeToParamList(
- std::vector<double>& theParams,
- boost::shared_ptr<ModelAPI_Attribute> theAttr,
- boost::shared_ptr<ModelAPI_Attribute> theNormExtraAttr)
+void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateAttribute(
+ boost::shared_ptr<ModelAPI_Attribute> theAttribute,
+ const Slvs_hEntity& theEntityID)
{
+ // Search the position of the first parameter of the entity
+ int anEntPos = Search(theEntityID, myEntities);
+ int aFirstParamPos = Search(myEntities[anEntPos].param[0], myParams);
+
+ // Look over supported types of entities
+
// Point in 3D
boost::shared_ptr<GeomDataAPI_Point> aPoint =
- boost::dynamic_pointer_cast<GeomDataAPI_Point>(theAttr);
+ boost::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
if (aPoint)
{
- theParams.push_back(aPoint->x());
- theParams.push_back(aPoint->y());
- theParams.push_back(aPoint->z());
+ aPoint->setValue(myParams[aFirstParamPos].val,
+ myParams[aFirstParamPos+1].val,
+ myParams[aFirstParamPos+2].val);
return ;
}
// Point in 2D
boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
- boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttr);
+ boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
if (aPoint2D)
{
- theParams.push_back(aPoint2D->x());
- theParams.push_back(aPoint2D->y());
+ aPoint2D->setValue(myParams[aFirstParamPos].val,
+ myParams[aFirstParamPos+1].val);
return ;
}
- // 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)
+ /// \todo Support other types of entities
+}
+
+void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateEntityIfPossible(
+ boost::shared_ptr<ModelAPI_Attribute> theEntity)
+{
+ if (myEntityMap.find(theEntity) != myEntityMap.end())
{
- // 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);
+ // If the attribute is a point and it is changed (the group needs to rebuild),
+ // probably user has dragged this point into this position,
+ // so it is necessary to add constraint which will quarantee the point will not change
+
+ // Store myNeedToSolve flag to verify the entity is really changed
+ bool aNeedToSolveCopy = myNeedToSolve;
+ myNeedToSolve = false;
+
+ changeEntity(theEntity);
+
+ if (myNeedToSolve) // the entity is changed
+ {
+ // Verify the entity is a point and add temporary constraint of permanency
+ boost::shared_ptr<GeomDataAPI_Point> aPoint =
+ boost::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
+ boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+ boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
+ if (aPoint || aPoint2D)
+ addTemporaryConstraintWhereDragged(theEntity);
+ }
+
+ // Restore flag of changes
+ myNeedToSolve = myNeedToSolve || aNeedToSolveCopy;
}
+}
- /// \todo Other types of entities
+void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addTemporaryConstraintWhereDragged(
+ boost::shared_ptr<ModelAPI_Attribute> theEntity)
+{
+ // Find identifier of the entity
+ std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator
+ anEntIter = myEntityMap.find(theEntity);
+
+ // Create WHERE_DRAGGED constraint
+ Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED,
+ myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0);
+ myConstraints.push_back(aWDConstr);
+ myTempConstraints.push_back(aWDConstr.h);
+}
+
+void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::removeTemporaryConstraints()
+{
+ std::list<Slvs_hConstraint>::reverse_iterator aTmpConstrIter;
+ for (aTmpConstrIter = myTempConstraints.rbegin(); aTmpConstrIter != myTempConstraints.rend(); aTmpConstrIter++)
+ {
+ int aConstrPos = Search(*aTmpConstrIter, myConstraints);
+ myConstraints.erase(myConstraints.begin() + aConstrPos);
+
+ // If the removing constraint has higher index, decrease the indexer
+ if (*aTmpConstrIter == myConstrMaxID)
+ myConstrMaxID--;
+ }
+ myTempConstraints.clear();
}
+
+
+// ========================================================
+// ========= Auxiliary functions ===============
+// ========================================================
+
template <typename T>
int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
{
return -1;
return aEntIter - theEntities.begin();
}
-
#define SketchSolver_ConstraintManager_Headerfile
#include "SketchSolver.h"
+#include <SketchSolver_Solver.h>
#include <Events_Listener.h>
#include <SketchPlugin_Constraint.h>
-// Need to be defined before including SolveSpace to avoid additional dependances on Windows platform
-#if defined(WIN32) && !defined(HAVE_C99_INTEGER_TYPES)
-typedef unsigned int UINT32;
-#endif
#include <string.h>
#include <slvs.h>
+#include <list>
#include <map>
#include <vector>
// Unknown constraint (for error reporting)
#define SLVS_C_UNKNOWN 0
+// Unknown entity
+#define SLVS_E_UNKNOWN 0
/** \class SketchSolver_ConstraintManager
* \ingroup DataModel
SketchSolver_ConstraintManager();
~SketchSolver_ConstraintManager();
- /** \brief Adds a constraint into the manager
- * \param[in] theConstraint constraint to be added
- * \return \c true if the constraint added successfully
+ /** \brief Adds or updates a constraint in the suitable group
+ * \param[in] theConstraint constraint to be changed
+ * \return \c true if the constraint changed successfully
*/
- bool addConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
+ bool changeConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
/** \brief Removes a constraint from the manager
* \param[in] theConstraint constraint to be removed
*/
bool removeConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
- /** \brief Updates a constraint
- * \param[in] theConstraint constraint to be updated
- * \return \c true if the constraint was updated
+ /** \brief Adds or updates a workplane in the manager
+ * \param[in] theSketch the feature to create or update workplane
+ * \return \c true if the workplane cahnged successfully
*/
- bool updateConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
-
- /** \brief Adds a workplane into the manager
- * \param[in] theSketch the feature to create workplane
- * \return \c true if the workplane added successfully
- */
- bool addWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch);
+ bool changeWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch);
/** \brief Removes a workplane from the manager.
* All groups based on such workplane will be removed too.
*/
bool removeWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch);
- /** \brief Updates a workplane
- * \param[in] theSketch workplane to be updated
- * \return \c true if the workplane was updated
- */
- bool updateWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch);
-
/** \brief Updates entity which is neither workplane nor constraint
* \param[in] theFeature entity to be updated
- * \return \c true if the entity updated successfully
*/
- bool updateEntity(boost::shared_ptr<SketchPlugin_Feature> theFeature);
+ void updateEntity(boost::shared_ptr<SketchPlugin_Feature> theFeature);
+
+ /** \brief Goes through the list of groups and solve the constraints
+ */
+ void ResolveConstraints();
private:
class SketchSolver_ConstraintGroup;
private:
static SketchSolver_ConstraintManager* _self; ///< Self pointer to implement singleton functionality
- std::vector<SketchSolver_ConstraintGroup> myGroups; ///< Groups of constraints
+ std::vector<SketchSolver_ConstraintGroup*> myGroups; ///< Groups of constraints
};
const Slvs_hGroup& getId() const
{return myID;}
- /** \brief Adds a constraint into the group
- * \param[in] theConstraint constraint to be added
- * \return \c true if the constraint added successfully
+ /** \brief Adds or updates a constraint in the group
+ * \param[in] theConstraint constraint to be changed
+ * \return \c true if the constraint added or updated successfully
*/
- bool addConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
+ bool changeConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
/** \brief Removes a constraint into the group
* \param[in] theConstraint constraint to be removed
boost::shared_ptr<SketchPlugin_Sketch> getWorkplane() const
{ return mySketch; }
- /** \brief Update parameters of workplane. Should be called when Update event is coming
- * \param[in] theWorkplane workplane to be updated
- * \return \c true if workplane updated successfully
+ /** \brief Update parameters of workplane. Should be called when Update event is coming.
+ * \return \c true if workplane updated successfully, \c false if workplane parameters are not consistent
+ */
+ bool updateWorkplane();
+
+ /** \brief If the entity is in this group it will updated
+ * \param[in] theEntity attribute, which values should update SolveSpace entity
*/
- bool updateWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theWorkplane);
+ void updateEntityIfPossible(boost::shared_ptr<ModelAPI_Attribute> theEntity);
+
+ /** \brief Start solution procedure if necessary and update attributes of features
+ */
+ void ResolveConstraints();
protected:
- /** \brief Adds an entity into the group
+ /** \brief Adds or updates an entity in the group
*
* The parameters of entity will be parsed and added to the list of SolveSpace parameters.
* Parameters of certain entity will be placed sequentially in the list.
*
* \param[in] theEntity the object of constraint
- * \return identifier of created entity or 0 if entity was not added
+ * \return identifier of changed entity or 0 if entity could not be changed
*/
- Slvs_hEntity addEntity(boost::shared_ptr<ModelAPI_Attribute> theEntity);
+ Slvs_hEntity changeEntity(boost::shared_ptr<ModelAPI_Attribute> theEntity);
- /** \brief Adds a normal into the group
+ /** \brief Adds or updates a normal in the group
*
* Normal is a special entity in SolveSpace, which defines a direction in 3D and
* a rotation about this direction. So, SolveSpace represents normals as unit quaternions.
*
* \param[in] theDirX first coordinate axis of the plane
* \param[in] theDirY second coordinate axis of the plane
- * \return identifier of created normal
+ * \param[in] theNorm attribute for the normal (used to identify newly created entity)
+ * \return identifier of created or updated normal
*/
- Slvs_hEntity addNormal(boost::shared_ptr<ModelAPI_Attribute> theDirX,
- boost::shared_ptr<ModelAPI_Attribute> theDirY);
-
- /** \brief Adds a parameter into the group
- * \param[in] theParam parameter to be added
- * \return identifier of created parameter or 0 if it was not added
+ Slvs_hEntity changeNormal(boost::shared_ptr<ModelAPI_Attribute> theDirX,
+ boost::shared_ptr<ModelAPI_Attribute> theDirY,
+ boost::shared_ptr<ModelAPI_Attribute> theNorm);
+
+ /** \brief Adds or updates a parameter in the group
+ * \param[in] theParam the value of parameter
+ * \param[in] thePrmIter the cell in the list of parameters which should be changed
+ * (the iterator will be increased if it does not reach the end of the list)
+ * \return identifier of changed parameter; when the parameter cannot be created, returned ID is 0
*/
- Slvs_hParam addParameter(double theParam);
+ Slvs_hParam changeParameter(const double& theParam,
+ std::vector<Slvs_Param>::const_iterator& thePrmIter);
/** \brief Compute constraint type according to SolveSpace identifiers
* and verify that constraint parameters are correct
*/
int getConstraintType(const boost::shared_ptr<SketchPlugin_Constraint>& theConstraint) const;
+ /** \brief Change values of attribute by parameters received from SolveSpace solver
+ * \param[in,out] theAttribute pointer to the attribute to be changed
+ * \param[in] theEntityID identifier of SolveSpace entity, which contains updated data
+ */
+ void updateAttribute(boost::shared_ptr<ModelAPI_Attribute> theAttribute, const Slvs_hEntity& theEntityID);
+
+ /** \brief Adds a constraint for a point which should not be changed during computations
+ * \param[in] theEntity the base for the constraint
+ */
+ void addTemporaryConstraintWhereDragged(boost::shared_ptr<ModelAPI_Attribute> theEntity);
+
+ /** \brief Remove all temporary constraint after computation finished
+ */
+ void removeTemporaryConstraints();
+
private:
/** \brief Creates a workplane from the sketch parameters
* \param[in] theSketch parameters of workplane are the attributes of this sketch
- * \return \c true if success
+ * \return \c true if success, \c false if workplane parameters are not consistent
*/
bool addWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch);
Slvs_hEntity myEntityMaxID; ///< Actual maximal ID of entities (not equal to myEntities size)
std::vector<Slvs_Constraint> myConstraints; ///< List of constraints in SolveSpace format
Slvs_hConstraint myConstrMaxID; ///< Actual maximal ID of constraints (not equal to myConstraints size)
- Slvs_System myConstrSet; ///< SolveSpace's set of equations obtained by constraints
+ bool myNeedToSolve; ///< Indicator that something changed in the group and constraint system need to be rebuilt
+
+ SketchSolver_Solver myConstrSolver; ///< Solver for set of equations obtained by constraints
// SketchPlugin entities
boost::shared_ptr<SketchPlugin_Sketch> mySketch; ///< Equivalent to workplane
- std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_Constraint>
- myConstraintMap; ///< The map between SketchPlugin and SolveSpace constraints
+ std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>
+ myConstraintMap; ///< The map between SketchPlugin and SolveSpace constraints
+ std::list<Slvs_hConstraint> myTempConstraints; ///< The list of identifiers of temporary constraints
+ std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>
+ myEntityMap; ///< The map between parameters of constraints and their equivalent SolveSpace entities
};
#endif