From: azv Date: Fri, 15 Jan 2016 13:45:46 +0000 (+0300) Subject: PlaneGCS hangs up (issue #1183) X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=aa916bdf3f4c79bd0c1a01adf1c6748ac18d92f2;p=modules%2Fshaper.git PlaneGCS hangs up (issue #1183) Avoid adding copied entities of MultiRotation and MultiTranslation constraints into solver to decrease number of used unknowns and constraints. --- diff --git a/src/SketchSolver/SketchSolver_ConstraintMulti.cpp b/src/SketchSolver/SketchSolver_ConstraintMulti.cpp index 9db1b64e0..d2135179c 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMulti.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMulti.cpp @@ -2,12 +2,14 @@ #include #include +#include #include #include #include +#include +#include -void SketchSolver_ConstraintMulti::getEntitiesAndCopies( - std::list< std::list >& theEntAndCopies) +void SketchSolver_ConstraintMulti::getEntities(std::list& theEntities) { myAdjusted = false; DataPtr aData = myBaseConstraint->data(); @@ -28,24 +30,20 @@ void SketchSolver_ConstraintMulti::getEntitiesAndCopies( } FeaturePtr aFeature; - std::list anEntities; // list of transformed entities std::list anObjectList = aRefList->list(); std::list::iterator anObjIt = anObjectList.begin(); if ((myNumberOfCopies + 1) * myNumberOfObjects != aRefList->size()) // execute for the feature is not called yet myNumberOfCopies = aRefList->size() / myNumberOfObjects - 1; while (anObjIt != anObjectList.end()) { - anEntities.clear(); - for (int i = 0; i <= myNumberOfCopies && anObjIt != anObjectList.end(); ++i, ++anObjIt) { - aFeature = ModelAPI_Feature::feature(*anObjIt); - if (!aFeature) - continue; + aFeature = ModelAPI_Feature::feature(*anObjIt++); + if (!aFeature) + continue; - myStorage->update(aFeature); - anEntities.push_back(myStorage->entity(aFeature)); - } - if (!anEntities.empty()) - theEntAndCopies.push_back(anEntities); + myStorage->update(aFeature); + theEntities.push_back(myStorage->entity(aFeature)); + for (int i = 0; i < myNumberOfCopies && anObjIt != anObjectList.end(); ++i, ++anObjIt) + ; // just skip copied features } } @@ -77,16 +75,78 @@ void SketchSolver_ConstraintMulti::update(bool isForce) void SketchSolver_ConstraintMulti::adjustConstraint() { - if (myAdjusted) - return; // constraint already adjusted, don't do it once again + AttributeRefListPtr aRefList = std::dynamic_pointer_cast( + myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + if (!aRefList || aRefList->size() == 0) { + myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); + return; + } - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + FeaturePtr aFeature; + std::list anObjectList = aRefList->list(); + std::list::iterator anObjIt = anObjectList.begin(); + while (anObjIt != anObjectList.end()) { + aFeature = ModelAPI_Feature::feature(*anObjIt++); + if (!aFeature) + continue; - const std::list& aConstraints = myStorage->constraint(myBaseConstraint); - std::list::const_iterator anIt = aConstraints.begin(); - for (; anIt != aConstraints.end(); ++anIt) - aBuilder->adjustConstraint(*anIt); - myStorage->addConstraint(myBaseConstraint, aConstraints); + // Fill lists of coordinates of points composing a feature + std::list aX, aY; + std::list::iterator aXIt, aYIt; + double aXCoord, aYCoord; + EntityWrapperPtr anEntity = myStorage->entity(aFeature); + std::list aSubs = anEntity->subEntities(); + std::list::const_iterator aSIt = aSubs.begin(); + for (; aSIt != aSubs.end(); ++aSIt) { + if ((*aSIt)->type() != ENTITY_POINT) + continue; + std::list aParameters = (*aSIt)->parameters(); + aXCoord = aParameters.front()->value(); + aYCoord = aParameters.back()->value(); + getRelative(aXCoord, aYCoord, aXCoord, aYCoord); + aX.push_back(aXCoord); + aY.push_back(aYCoord); + } + + // Calculate positions of copied features + for (int i = 0; i < myNumberOfCopies && anObjIt != anObjectList.end(); ++i, ++anObjIt) { + aFeature = ModelAPI_Feature::feature(*anObjIt); + if (!aFeature) + continue; + anEntity = myStorage->entity(aFeature); + + if (!anEntity || !myStorage->isEventsBlocked()) + aFeature->data()->blockSendAttributeUpdated(true); + + std::list aPoints; + if (aFeature->getKind() == SketchPlugin_Arc::ID()) { + aPoints.push_back(aFeature->attribute(SketchPlugin_Arc::CENTER_ID())); + aPoints.push_back(aFeature->attribute(SketchPlugin_Arc::START_ID())); + aPoints.push_back(aFeature->attribute(SketchPlugin_Arc::END_ID())); + } else if (aFeature->getKind() == SketchPlugin_Line::ID()) { + aPoints.push_back(aFeature->attribute(SketchPlugin_Line::START_ID())); + aPoints.push_back(aFeature->attribute(SketchPlugin_Line::END_ID())); + } else + aPoints = aFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); + + std::list::iterator aPtIt = aPoints.begin(); + for (aXIt = aX.begin(), aYIt = aY.begin(); aPtIt != aPoints.end(); ++aXIt, ++aYIt, ++aPtIt) { + transformRelative(*aXIt, *aYIt); + getAbsolute(*aXIt, *aYIt, aXCoord, aYCoord); + + std::shared_ptr aPoint2D = + std::dynamic_pointer_cast(*aPtIt); + aPoint2D->setValue(aXCoord, aYCoord); + } + + // update feature in the storage if it is used by another constraints + if (anEntity) + myStorage->update(aFeature); + + if (!anEntity || !myStorage->isEventsBlocked()) + aFeature->data()->blockSendAttributeUpdated(false); + } + } myAdjusted = true; } diff --git a/src/SketchSolver/SketchSolver_ConstraintMulti.h b/src/SketchSolver/SketchSolver_ConstraintMulti.h index 70fe5e781..16db54dbd 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMulti.h +++ b/src/SketchSolver/SketchSolver_ConstraintMulti.h @@ -37,8 +37,8 @@ protected: virtual void process() { /* do nothing here */ } - /// \brief Collect entities and their copies, like circles and arcs - void getEntitiesAndCopies(std::list< std::list >& theEntAndCopies); + /// \brief Collect entities which translated or rotated (not their copies) + void getEntities(std::list& theEntities); /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints /// \param[out] theValue numerical characteristic of constraint (e.g. distance) @@ -54,6 +54,14 @@ protected: /// \brief Returns name of NUMBER_OF_COPIES parameter for corresponding feature virtual const std::string& nameNbObjects() = 0; + +protected: + /// \brief Convert absolute coordinates to relative coordinates + virtual void getRelative(double theAbsX, double theAbsY, double& theRelX, double& theRelY) = 0; + /// \brief Convert relative coordinates to absolute coordinates + virtual void getAbsolute(double theRelX, double theRelY, double& theAbsX, double& theAbsY) = 0; + /// \brief Apply transformation for relative coordinates + virtual void transformRelative(double& theX, double& theY) = 0; protected: int myNumberOfObjects; ///< number of previous initial objects diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp index a322e66be..e2839f7b9 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp @@ -10,8 +10,7 @@ void SketchSolver_ConstraintMultiRotation::getAttributes( EntityWrapperPtr& theCenter, double& theAngle, - bool& theFullValue, - std::list< std::list >& theEntities) + bool& theFullValue, std::list& theEntities) { DataPtr aData = myBaseConstraint->data(); theAngle = std::dynamic_pointer_cast( @@ -31,7 +30,7 @@ void SketchSolver_ConstraintMultiRotation::getAttributes( AttributeStringPtr aMethodTypeAttr = aData->string(SketchPlugin_MultiRotation::ANGLE_TYPE()); theFullValue = aMethodTypeAttr->value() != "SingleAngle"; - getEntitiesAndCopies(theEntities); + getEntities(theEntities); } void SketchSolver_ConstraintMultiRotation::process() @@ -44,19 +43,19 @@ void SketchSolver_ConstraintMultiRotation::process() EntityWrapperPtr aRotationCenter; bool isFullValue; - std::list > anEntitiesAndCopies; - getAttributes(aRotationCenter, myAngle, isFullValue, anEntitiesAndCopies); + std::list aBaseEntities; + getAttributes(aRotationCenter, myAngle, isFullValue, aBaseEntities); if (!myErrorMsg.empty()) return; BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); std::list aRotConstraints; - std::list< std::list >::iterator anEntIt = anEntitiesAndCopies.begin(); - for (; anEntIt != anEntitiesAndCopies.end(); ++anEntIt) { + std::list::iterator anEntIt = aBaseEntities.begin(); + for (; anEntIt != aBaseEntities.end(); ++anEntIt) { std::list aNewConstraints = aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID, myType, - myAngle, isFullValue, aRotationCenter, EntityWrapperPtr(), *anEntIt); + myAngle, isFullValue, aRotationCenter, EntityWrapperPtr(), std::list(1, *anEntIt)); aRotConstraints.insert(aRotConstraints.end(), aNewConstraints.begin(), aNewConstraints.end()); } myStorage->addConstraint(myBaseConstraint, aRotConstraints); @@ -124,6 +123,9 @@ void SketchSolver_ConstraintMultiRotation::updateLocal() void SketchSolver_ConstraintMultiRotation::adjustConstraint() { + if (myAdjusted) + return; + if (fabs(myAngle) < tolerance) { myStorage->setNeedToResolve(false); return; @@ -134,9 +136,42 @@ void SketchSolver_ConstraintMultiRotation::adjustConstraint() for (; aCIt != aConstraints.end(); ++aCIt) (*aCIt)->setValue(myAngle); + // Obtain coordinates of rotation center + EntityWrapperPtr aRotCenter = myStorage->entity( + myBaseConstraint->attribute(SketchPlugin_MultiRotation::CENTER_ID())); + std::list aParams = aRotCenter->parameters(); + myCenterCoord[0] = aParams.front()->value(); + myCenterCoord[1] = aParams.back()->value(); + + myRotationVal[0] = sin(myAngle * PI / 180.0); + myRotationVal[1] = cos(myAngle * PI / 180.0); + SketchSolver_ConstraintMulti::adjustConstraint(); } +void SketchSolver_ConstraintMultiRotation::getRelative( + double theAbsX, double theAbsY, double& theRelX, double& theRelY) +{ + theRelX = theAbsX - myCenterCoord[0]; + theRelY = theAbsY - myCenterCoord[1]; +} + +void SketchSolver_ConstraintMultiRotation::getAbsolute( + double theRelX, double theRelY, double& theAbsX, double& theAbsY) +{ + theAbsX = theRelX + myCenterCoord[0]; + theAbsY = theRelY + myCenterCoord[1]; +} + +void SketchSolver_ConstraintMultiRotation::transformRelative(double& theX, double& theY) +{ + // rotate direction + // myRotationVal[0] = sinA, myRotationVal[1] = cosA + double aTemp = theX * myRotationVal[1] - theY * myRotationVal[0]; + theY = theX * myRotationVal[0] + theY * myRotationVal[1]; + theX = aTemp; +} + const std::string& SketchSolver_ConstraintMultiRotation::nameNbObjects() { return SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID(); diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h index 6d241f92d..69e792bcc 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h +++ b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h @@ -32,9 +32,9 @@ protected: /// \param[out] theCenter central point of rotation /// \param[out] theAngle rotation angle /// \param[out] theFullValue applying translation using the disstance as a full or single value - /// \param[out] theEntities list of entities and their rotated copies + /// \param[out] theEntities list of base entities void getAttributes(EntityWrapperPtr& theCenter, double& theAngle, bool& theFullValue, - std::list< std::list >& theEntities); + std::list& theEntities); /// \brief This method is used in derived objects to check consistence of constraint. virtual void adjustConstraint(); @@ -43,12 +43,23 @@ protected: virtual void updateLocal(); private: + /// \brief Convert absolute coordinates to relative coordinates + virtual void getRelative(double theAbsX, double theAbsY, double& theRelX, double& theRelY); + /// \brief Convert relative coordinates to absolute coordinates + virtual void getAbsolute(double theRelX, double theRelY, double& theAbsX, double& theAbsY); + /// \brief Apply transformation for relative coordinates + virtual void transformRelative(double& theX, double& theY); + /// \brief Returns name of NUMBER_OF_COPIES parameter for corresponding feature virtual const std::string& nameNbObjects(); +private: AttributePoint2DPtr myCenterPointAttribute; ///< a center of rotation double myAngle; ///< angle of rotation bool myIsFullValue; ///< value whether the angle is a full or single for objects + + double myCenterCoord[2]; ///< coordinates of rotation center + double myRotationVal[2]; ///< sinus and cosine of rotation angle }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp index 5d0b01931..dd740003a 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp @@ -10,7 +10,7 @@ void SketchSolver_ConstraintMultiTranslation::getAttributes( EntityWrapperPtr& theStartPoint, EntityWrapperPtr& theEndPoint, - bool& theFullValue, std::list< std::list >& theEntities) + bool& theFullValue, std::list& theEntities) { DataPtr aData = myBaseConstraint->data(); AttributePtr aStartPointAttr = aData->attribute(SketchPlugin_MultiTranslation::START_POINT_ID()); @@ -31,7 +31,7 @@ void SketchSolver_ConstraintMultiTranslation::getAttributes( AttributeStringPtr aMethodTypeAttr = aData->string(SketchPlugin_MultiTranslation::VALUE_TYPE()); theFullValue = aMethodTypeAttr->value() != "SingleValue"; - getEntitiesAndCopies(theEntities); + getEntities(theEntities); } void SketchSolver_ConstraintMultiTranslation::process() @@ -44,8 +44,8 @@ void SketchSolver_ConstraintMultiTranslation::process() EntityWrapperPtr aStartPoint, aEndPoint; bool aFullValue; - std::list > anEntitiesAndCopies; - getAttributes(aStartPoint, aEndPoint, aFullValue, anEntitiesAndCopies); + std::list aBaseEntities; + getAttributes(aStartPoint, aEndPoint, aFullValue, aBaseEntities); if (!myErrorMsg.empty()) return; @@ -55,11 +55,11 @@ void SketchSolver_ConstraintMultiTranslation::process() BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); std::list aTransConstraints; - std::list< std::list >::iterator anEntIt = anEntitiesAndCopies.begin(); - for (; anEntIt != anEntitiesAndCopies.end(); ++anEntIt) { + std::list::iterator anEntIt = aBaseEntities.begin(); + for (; anEntIt != aBaseEntities.end(); ++anEntIt) { std::list aNewConstraints = aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID, myType, - 0.0, aFullValue, aStartPoint, aEndPoint, *anEntIt); + 0.0, aFullValue, aStartPoint, aEndPoint, std::list(1, *anEntIt)); aTransConstraints.insert(aTransConstraints.end(), aNewConstraints.begin(), aNewConstraints.end()); } @@ -136,3 +136,42 @@ void SketchSolver_ConstraintMultiTranslation::updateLocal() } } +void SketchSolver_ConstraintMultiTranslation::adjustConstraint() +{ + if (myAdjusted) + return; + + // Obtain delta between start and end points of translation + EntityWrapperPtr aStart = myStorage->entity( + myBaseConstraint->attribute(SketchPlugin_MultiTranslation::START_POINT_ID())); + std::list aStartParams = aStart->parameters(); + EntityWrapperPtr aEnd = myStorage->entity( + myBaseConstraint->attribute(SketchPlugin_MultiTranslation::END_POINT_ID())); + std::list aEndParams = aEnd->parameters(); + myDelta[0] = aEndParams.front()->value() - aStartParams.front()->value(); + myDelta[1] = aEndParams.back()->value() - aStartParams.back()->value(); + + SketchSolver_ConstraintMulti::adjustConstraint(); +} + +void SketchSolver_ConstraintMultiTranslation::getRelative( + double theAbsX, double theAbsY, double& theRelX, double& theRelY) +{ + theRelX = theAbsX; + theRelY = theAbsY; +} + +void SketchSolver_ConstraintMultiTranslation::getAbsolute( + double theRelX, double theRelY, double& theAbsX, double& theAbsY) +{ + theAbsX = theRelX; + theAbsY = theRelY; +} + +void SketchSolver_ConstraintMultiTranslation::transformRelative(double& theX, double& theY) +{ + // translate coordinates + theX += myDelta[0]; + theY += myDelta[1]; +} + diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h index ef9938a9c..59cb06f93 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h +++ b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h @@ -31,15 +31,25 @@ protected: /// \brief Generate list of translated entities /// \param[out] theStartPoint start point of translation /// \param[out] theEndPoint final point of translation - /// \param[out] theFullValue applying translation using the disstance as a full or single value - /// \param[out] theEntities list of entities and their translated copies + /// \param[out] theFullValue applying translation using the distance as a full or single value + /// \param[out] theEntities list of base entities void getAttributes(EntityWrapperPtr& theStartPoint, EntityWrapperPtr& theEndPoint, - bool& theFullValue, std::list< std::list >& theEntities); + bool& theFullValue, std::list& theEntities); + + /// \brief This method is used in derived objects to check consistence of constraint. + virtual void adjustConstraint(); /// \brief Update parameters (called from base class) virtual void updateLocal(); private: + /// \brief Convert absolute coordinates to relative coordinates + virtual void getRelative(double theAbsX, double theAbsY, double& theRelX, double& theRelY); + /// \brief Convert relative coordinates to absolute coordinates + virtual void getAbsolute(double theRelX, double theRelY, double& theAbsX, double& theAbsY); + /// \brief Apply transformation for relative coordinates + virtual void transformRelative(double& theX, double& theY); + /// \brief Returns name of NUMBER_OF_COPIES parameter for corresponding feature virtual const std::string& nameNbObjects(); @@ -47,6 +57,8 @@ private: AttributePoint2DPtr myStartPointAttribute; AttributePoint2DPtr myEndPointAttribute; bool myIsFullValue; + + double myDelta[2]; ///< increment of translation }; #endif diff --git a/src/SketchSolver/SketchSolver_Manager.cpp b/src/SketchSolver/SketchSolver_Manager.cpp index 354a3d9d8..ba8b2ea17 100644 --- a/src/SketchSolver/SketchSolver_Manager.cpp +++ b/src/SketchSolver/SketchSolver_Manager.cpp @@ -28,6 +28,8 @@ #include #include +static const Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); + // Initialization of constraint manager self pointer SketchSolver_Manager* SketchSolver_Manager::mySelf = 0; @@ -89,6 +91,7 @@ void SketchSolver_Manager::processEvent( std::dynamic_pointer_cast(theMessage); std::set aFeatures = anUpdateMsg->objects(); + bool isUpdateFlushed = stopSendUpdate(); // Shows the message has at least one feature applicable for solver bool hasProperFeature = false; @@ -122,9 +125,18 @@ void SketchSolver_Manager::processEvent( } } + bool needToUpdate = false; // Solve the set of constraints if (hasProperFeature) - resolveConstraints(isMovedEvt); // send update for movement in any case + needToUpdate = resolveConstraints(); + + // Features may be updated => now send events, but for all changed at once + if (isUpdateFlushed) + allowSendUpdate(); + // send update for movement in any case + if (needToUpdate || isMovedEvt) + Events_Loop::loop()->flush(anUpdateEvent); + } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) { std::shared_ptr aDeleteMsg = std::dynamic_pointer_cast(theMessage); @@ -342,30 +354,27 @@ std::shared_ptr SketchSolver_Manager // Function: resolveConstraints // Purpose: change entities according to available constraints // ============================================================================ -void SketchSolver_Manager::resolveConstraints(const bool theForceUpdate) +bool SketchSolver_Manager::resolveConstraints() { - //myIsComputed = true; bool needToUpdate = false; - static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); - // to avoid redisplay of each segment on update by solver one by one in the viewer - bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent); - if (isUpdateFlushed) { - Events_Loop::loop()->setFlushed(anUpdateEvent, false); - } - std::vector::iterator aGroupIter; for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) if ((*aGroupIter)->resolveConstraints()) needToUpdate = true; + return needToUpdate; +} - // Features may be updated => now send events, but for all changed at once +bool SketchSolver_Manager::stopSendUpdate() const +{ + // to avoid redisplay of each segment on update by solver one by one in the viewer + bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent); if (isUpdateFlushed) { - Events_Loop::loop()->setFlushed(anUpdateEvent, true); + Events_Loop::loop()->setFlushed(anUpdateEvent, false); } - // Must be before flush because on "Updated" flush the results may be produced - // and the creation event is appeared with many new objects. If myIsComputed these - // events are missed in processEvents and some elements are not added. - //myIsComputed = false; - if (needToUpdate || theForceUpdate) - Events_Loop::loop()->flush(anUpdateEvent); + return isUpdateFlushed; +} + +void SketchSolver_Manager::allowSendUpdate() const +{ + Events_Loop::loop()->setFlushed(anUpdateEvent, true); } diff --git a/src/SketchSolver/SketchSolver_Manager.h b/src/SketchSolver/SketchSolver_Manager.h index 8ceddc79a..6883cd448 100644 --- a/src/SketchSolver/SketchSolver_Manager.h +++ b/src/SketchSolver/SketchSolver_Manager.h @@ -83,9 +83,9 @@ protected: void moveEntity(std::shared_ptr theFeature); /** \brief Goes through the list of groups and solve the constraints - * \param theForceUpdate flushes the update event in any case: something changed or not + * \return \c true, if groups are resolved, and features should be updated (send the Update event) */ - void resolveConstraints(const bool theForceUpdate); + bool resolveConstraints(); private: /** \brief Searches list of groups which interact with specified feature @@ -102,6 +102,12 @@ private: std::shared_ptr findWorkplane( std::shared_ptr theFeature) const; + /// \brief Stop sending the Update event until all features updated + /// \return \c true, if the last flushed event is Update + bool stopSendUpdate() const; + /// \brief Allow to send the Update event + void allowSendUpdate() const; + private: static SketchSolver_Manager* mySelf; ///< Self pointer to implement singleton functionality std::vector myGroups; ///< Groups of constraints