#include <SketchPlugin_Constraint.h>
#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
#include <SketchPlugin_Sketch.h>
#include <math.h>
if (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);
+
+ // Solve the set of constraints
+ ResolveConstraints();
+ }
}
else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_DELETED))
{
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())
+ if (!(*aGroupIter)->updateWorkplane())
aResult = false;
}
// If the workplane is not updated, so this is a new workplane
if (!isUpdated)
{
- SketchSolver_ConstraintGroup aNewGroup(theSketch);
+ SketchSolver_ConstraintGroup* aNewGroup = new SketchSolver_ConstraintGroup(theSketch);
// Verify that the group is created successfully
- if (!aNewGroup.isBaseWorkplane(theSketch))
+ if (!aNewGroup->isBaseWorkplane(theSketch))
+ {
+ delete aNewGroup;
return false;
+ }
myGroups.push_back(aNewGroup);
}
return aResult;
{ // 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);
- if (!aGroup.changeConstraint(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->changeConstraint(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();
+}
+
// ========================================================
myEntityMaxID(0),
myConstrMaxID(0),
myConstraintMap(),
- myNeedToSolve(false)
+ 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);
}
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(
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;
}
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() && aConstrIter->valA != aDistance)
+ {
+ 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])
);
+ 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;
}
if (aPoint2D)
{
// The 2D points are created on workplane. So, if there is no workplane yet, then error
- if (myWorkplane.h == 0)
- return 0;
+ if (myWorkplane.h == SLVS_E_UNKNOWN)
+ return SLVS_E_UNKNOWN;
Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter);
Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter);
/// \todo Other types of entities
// Unsupported or wrong entity type
- return 0;
+ return SLVS_E_UNKNOWN;
}
Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::changeNormal(
if (!aDirX || !aDirY ||
(fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) ||
(fabs(aDirY->x()) + fabs(aDirY->y()) + fabs(aDirY->z()) < tolerance))
- return 0;
+ return SLVS_E_UNKNOWN;
// quaternion parameters of normal vector
double qw, qx, qy, qz;
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
+
+ myNeedToSolve = false;
+}
+
+
+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>(theAttribute);
+ if (aPoint)
+ {
+ 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>(theAttribute);
+ if (aPoint2D)
+ {
+ aPoint2D->setValue(myParams[aFirstParamPos].val,
+ myParams[aFirstParamPos+1].val);
+ return ;
+ }
+
+ /// \todo Support other types of entities
+}
+
+void SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateEntityIfPossible(
+ boost::shared_ptr<ModelAPI_Attribute> theEntity)
+{
+ if (myEntityMap.find(theEntity) != myEntityMap.end())
+ changeEntity(theEntity);
+}
+
// ========================================================
#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>
// Unknown constraint (for error reporting)
#define SLVS_C_UNKNOWN 0
+// Unknown entity
+#define SLVS_E_UNKNOWN 0
/** \class SketchSolver_ConstraintManager
* \ingroup DataModel
/** \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
};
*/
bool updateWorkplane();
+ /** \brief If the entity is in this group it will updated
+ * \param[in] theEntity attribute, which values should update SolveSpace entity
+ */
+ void updateEntityIfPossible(boost::shared_ptr<ModelAPI_Attribute> theEntity);
+
+ /** \brief Start solution procedure if necessary and update attributes of features
+ */
+ void ResolveConstraints();
+
protected:
/** \brief Adds or updates an entity in the group
*
*/
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);
+
private:
/** \brief Creates a workplane from the sketch parameters
* \param[in] theSketch parameters of workplane are the attributes of this sketch
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>
+ std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_hConstraint>
myConstraintMap; ///< The map between SketchPlugin and SolveSpace constraints
std::map<boost::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>
myEntityMap; ///< The map between parameters of constraints and their equivalent SolveSpace entities
// Author: Artem ZHIDKOV
#include "SketchSolver_Solver.h"
+
+SketchSolver_Solver::SketchSolver_Solver()
+{
+ // Nullify all elements of the set of equations
+ myEquationsSystem.param = 0;
+ myEquationsSystem.params = 0;
+ myEquationsSystem.entity = 0;
+ myEquationsSystem.entities = 0;
+ myEquationsSystem.constraint = 0;
+ myEquationsSystem.constraints = 0;
+ myEquationsSystem.failed = 0;
+ myEquationsSystem.faileds = 0;
+
+ // If the set of constraints is inconsistent,
+ // the failed field will contain wrong constraints
+ myEquationsSystem.calculateFaileds = 1;
+}
+
+SketchSolver_Solver::~SketchSolver_Solver()
+{
+ if (myEquationsSystem.param)
+ delete [] myEquationsSystem.param;
+ if (myEquationsSystem.entity)
+ delete [] myEquationsSystem.entity;
+ if (myEquationsSystem.constraint)
+ delete [] myEquationsSystem.constraint;
+ if (myEquationsSystem.failed)
+ delete [] myEquationsSystem.failed;
+}
+
+void SketchSolver_Solver::setParameters(const std::vector<Slvs_Param>& theParameters)
+{
+ if (theParameters.size() != myEquationsSystem.params) // number of parameters was changed => reallocate the memory
+ {
+ if (myEquationsSystem.param)
+ delete [] myEquationsSystem.param;
+ myEquationsSystem.params = theParameters.size();
+ myEquationsSystem.param = new Slvs_Param[theParameters.size()];
+ }
+
+ // Copy data
+ std::vector<Slvs_Param>::const_iterator aParamIter = theParameters.begin();
+ for (int i = 0; i < myEquationsSystem.params; i++, aParamIter++)
+ myEquationsSystem.param[i] = *aParamIter;
+}
+
+void SketchSolver_Solver::setEntities(const std::vector<Slvs_Entity>& theEntities)
+{
+ if (theEntities.size() != myEquationsSystem.entities) // number of entities was changed => reallocate the memory
+ {
+ if (myEquationsSystem.entity)
+ delete [] myEquationsSystem.entity;
+ myEquationsSystem.entities = theEntities.size();
+ myEquationsSystem.entity = new Slvs_Entity[theEntities.size()];
+ }
+
+ // Copy data
+ std::vector<Slvs_Entity>::const_iterator aEntIter = theEntities.begin();
+ for (int i = 0; i < myEquationsSystem.entities; i++, aEntIter++)
+ myEquationsSystem.entity[i] = *aEntIter;
+}
+
+void SketchSolver_Solver::setConstraints(const std::vector<Slvs_Constraint>& theConstraints)
+{
+ if (theConstraints.size() != myEquationsSystem.constraints) // number of constraints was changed => reallocate the memory
+ {
+ if (myEquationsSystem.constraint)
+ delete [] myEquationsSystem.constraint;
+ myEquationsSystem.constraints = theConstraints.size();
+ myEquationsSystem.constraint = new Slvs_Constraint[theConstraints.size()];
+ }
+
+ // Copy data
+ std::vector<Slvs_Constraint>::const_iterator aConstrIter = theConstraints.begin();
+ for (int i = 0; i < myEquationsSystem.constraints; i++, aConstrIter++)
+ myEquationsSystem.constraint[i] = *aConstrIter;
+}
+
+int SketchSolver_Solver::solve()
+{
+ if (myEquationsSystem.constraints <= 0)
+ return SLVS_RESULT_EMPTY_SET;
+
+ Slvs_Solve(&myEquationsSystem, myGroupID);
+
+ return myEquationsSystem.result;
+}
+
+bool SketchSolver_Solver::getResult(std::vector<Slvs_Param>& theParameters)
+{
+ if (myEquationsSystem.result != SLVS_RESULT_OKAY)
+ return false;
+
+ if (theParameters.size() != myEquationsSystem.params)
+ return false; // number of parameters is not the same
+
+ std::vector<Slvs_Param>::iterator aParamIter = theParameters.begin();
+ for (int i = 0; i < myEquationsSystem.params; i++, aParamIter++)
+ {
+ if (myEquationsSystem.param[i].h != aParamIter->h)
+ return false; // sequence of parameters was changed
+ aParamIter->val = myEquationsSystem.param[i].val;
+ }
+
+ return true;
+}