Avoid adding copied entities of MultiRotation and MultiTranslation constraints into solver to decrease number of used unknowns and constraints.
#include <SketchSolver_Error.h>
#include <SketchSolver_Manager.h>
+#include <GeomDataAPI_Point2D.h>
#include <ModelAPI_AttributeInteger.h>
#include <ModelAPI_AttributeRefAttr.h>
#include <ModelAPI_AttributeRefList.h>
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Line.h>
-void SketchSolver_ConstraintMulti::getEntitiesAndCopies(
- std::list< std::list<EntityWrapperPtr> >& theEntAndCopies)
+void SketchSolver_ConstraintMulti::getEntities(std::list<EntityWrapperPtr>& theEntities)
{
myAdjusted = false;
DataPtr aData = myBaseConstraint->data();
}
FeaturePtr aFeature;
- std::list<EntityWrapperPtr> anEntities; // list of transformed entities
std::list<ObjectPtr> anObjectList = aRefList->list();
std::list<ObjectPtr>::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
}
}
void SketchSolver_ConstraintMulti::adjustConstraint()
{
- if (myAdjusted)
- return; // constraint already adjusted, don't do it once again
+ AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+ 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<ObjectPtr> anObjectList = aRefList->list();
+ std::list<ObjectPtr>::iterator anObjIt = anObjectList.begin();
+ while (anObjIt != anObjectList.end()) {
+ aFeature = ModelAPI_Feature::feature(*anObjIt++);
+ if (!aFeature)
+ continue;
- const std::list<ConstraintWrapperPtr>& aConstraints = myStorage->constraint(myBaseConstraint);
- std::list<ConstraintWrapperPtr>::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<double> aX, aY;
+ std::list<double>::iterator aXIt, aYIt;
+ double aXCoord, aYCoord;
+ EntityWrapperPtr anEntity = myStorage->entity(aFeature);
+ std::list<EntityWrapperPtr> aSubs = anEntity->subEntities();
+ std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
+ for (; aSIt != aSubs.end(); ++aSIt) {
+ if ((*aSIt)->type() != ENTITY_POINT)
+ continue;
+ std::list<ParameterWrapperPtr> 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<AttributePtr> 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<AttributePtr>::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<GeomDataAPI_Point2D> aPoint2D =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*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;
}
virtual void process()
{ /* do nothing here */ }
- /// \brief Collect entities and their copies, like circles and arcs
- void getEntitiesAndCopies(std::list< std::list<EntityWrapperPtr> >& theEntAndCopies);
+ /// \brief Collect entities which translated or rotated (not their copies)
+ void getEntities(std::list<EntityWrapperPtr>& theEntities);
/// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
/// \param[out] theValue numerical characteristic of constraint (e.g. distance)
/// \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
void SketchSolver_ConstraintMultiRotation::getAttributes(
EntityWrapperPtr& theCenter, double& theAngle,
- bool& theFullValue,
- std::list< std::list<EntityWrapperPtr> >& theEntities)
+ bool& theFullValue, std::list<EntityWrapperPtr>& theEntities)
{
DataPtr aData = myBaseConstraint->data();
theAngle = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
AttributeStringPtr aMethodTypeAttr = aData->string(SketchPlugin_MultiRotation::ANGLE_TYPE());
theFullValue = aMethodTypeAttr->value() != "SingleAngle";
- getEntitiesAndCopies(theEntities);
+ getEntities(theEntities);
}
void SketchSolver_ConstraintMultiRotation::process()
EntityWrapperPtr aRotationCenter;
bool isFullValue;
- std::list<std::list<EntityWrapperPtr> > anEntitiesAndCopies;
- getAttributes(aRotationCenter, myAngle, isFullValue, anEntitiesAndCopies);
+ std::list<EntityWrapperPtr> aBaseEntities;
+ getAttributes(aRotationCenter, myAngle, isFullValue, aBaseEntities);
if (!myErrorMsg.empty())
return;
BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
std::list<ConstraintWrapperPtr> aRotConstraints;
- std::list< std::list<EntityWrapperPtr> >::iterator anEntIt = anEntitiesAndCopies.begin();
- for (; anEntIt != anEntitiesAndCopies.end(); ++anEntIt) {
+ std::list<EntityWrapperPtr>::iterator anEntIt = aBaseEntities.begin();
+ for (; anEntIt != aBaseEntities.end(); ++anEntIt) {
std::list<ConstraintWrapperPtr> aNewConstraints =
aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID, myType,
- myAngle, isFullValue, aRotationCenter, EntityWrapperPtr(), *anEntIt);
+ myAngle, isFullValue, aRotationCenter, EntityWrapperPtr(), std::list<EntityWrapperPtr>(1, *anEntIt));
aRotConstraints.insert(aRotConstraints.end(), aNewConstraints.begin(), aNewConstraints.end());
}
myStorage->addConstraint(myBaseConstraint, aRotConstraints);
void SketchSolver_ConstraintMultiRotation::adjustConstraint()
{
+ if (myAdjusted)
+ return;
+
if (fabs(myAngle) < tolerance) {
myStorage->setNeedToResolve(false);
return;
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<ParameterWrapperPtr> 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();
/// \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<EntityWrapperPtr> >& theEntities);
+ std::list<EntityWrapperPtr>& theEntities);
/// \brief This method is used in derived objects to check consistence of constraint.
virtual void adjustConstraint();
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
void SketchSolver_ConstraintMultiTranslation::getAttributes(
EntityWrapperPtr& theStartPoint, EntityWrapperPtr& theEndPoint,
- bool& theFullValue, std::list< std::list<EntityWrapperPtr> >& theEntities)
+ bool& theFullValue, std::list<EntityWrapperPtr>& theEntities)
{
DataPtr aData = myBaseConstraint->data();
AttributePtr aStartPointAttr = aData->attribute(SketchPlugin_MultiTranslation::START_POINT_ID());
AttributeStringPtr aMethodTypeAttr = aData->string(SketchPlugin_MultiTranslation::VALUE_TYPE());
theFullValue = aMethodTypeAttr->value() != "SingleValue";
- getEntitiesAndCopies(theEntities);
+ getEntities(theEntities);
}
void SketchSolver_ConstraintMultiTranslation::process()
EntityWrapperPtr aStartPoint, aEndPoint;
bool aFullValue;
- std::list<std::list<EntityWrapperPtr> > anEntitiesAndCopies;
- getAttributes(aStartPoint, aEndPoint, aFullValue, anEntitiesAndCopies);
+ std::list<EntityWrapperPtr> aBaseEntities;
+ getAttributes(aStartPoint, aEndPoint, aFullValue, aBaseEntities);
if (!myErrorMsg.empty())
return;
BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
std::list<ConstraintWrapperPtr> aTransConstraints;
- std::list< std::list<EntityWrapperPtr> >::iterator anEntIt = anEntitiesAndCopies.begin();
- for (; anEntIt != anEntitiesAndCopies.end(); ++anEntIt) {
+ std::list<EntityWrapperPtr>::iterator anEntIt = aBaseEntities.begin();
+ for (; anEntIt != aBaseEntities.end(); ++anEntIt) {
std::list<ConstraintWrapperPtr> aNewConstraints =
aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID, myType,
- 0.0, aFullValue, aStartPoint, aEndPoint, *anEntIt);
+ 0.0, aFullValue, aStartPoint, aEndPoint, std::list<EntityWrapperPtr>(1, *anEntIt));
aTransConstraints.insert(aTransConstraints.end(), aNewConstraints.begin(), aNewConstraints.end());
}
}
}
+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<ParameterWrapperPtr> aStartParams = aStart->parameters();
+ EntityWrapperPtr aEnd = myStorage->entity(
+ myBaseConstraint->attribute(SketchPlugin_MultiTranslation::END_POINT_ID()));
+ std::list<ParameterWrapperPtr> 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];
+}
+
/// \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<EntityWrapperPtr> >& theEntities);
+ bool& theFullValue, std::list<EntityWrapperPtr>& 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();
AttributePoint2DPtr myStartPointAttribute;
AttributePoint2DPtr myEndPointAttribute;
bool myIsFullValue;
+
+ double myDelta[2]; ///< increment of translation
};
#endif
#include <set>
#include <memory>
+static const Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
+
// Initialization of constraint manager self pointer
SketchSolver_Manager* SketchSolver_Manager::mySelf = 0;
std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
std::set<ObjectPtr> aFeatures = anUpdateMsg->objects();
+ bool isUpdateFlushed = stopSendUpdate();
// Shows the message has at least one feature applicable for solver
bool hasProperFeature = false;
}
}
+ 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<ModelAPI_ObjectDeletedMessage> aDeleteMsg =
std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
// 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<SketchSolver_Group*>::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);
}
void moveEntity(std::shared_ptr<SketchPlugin_Feature> 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
std::shared_ptr<ModelAPI_CompositeFeature> findWorkplane(
std::shared_ptr<SketchPlugin_Feature> 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<SketchSolver_Group*> myGroups; ///< Groups of constraints