From 0b9a8ed5aa0787974bf1b9c7b5cedd1ca2c9e05d Mon Sep 17 00:00:00 2001 From: azv Date: Tue, 25 Apr 2017 11:31:09 +0300 Subject: [PATCH] Issue #2133: Edge with middle node constraint can be moved Move entities similar as FreeCAD (2 steps): 1. Initialize solver with initial positions of the feature and add temporary constraints. 2. Set new coordinates and then solve the set of constraints. --- .../PlaneGCSSolver_AttributeBuilder.cpp | 9 +- .../PlaneGCSSolver/PlaneGCSSolver_Solver.cpp | 26 ++- .../PlaneGCSSolver/PlaneGCSSolver_Solver.h | 5 + .../PlaneGCSSolver/PlaneGCSSolver_Tools.cpp | 6 +- .../PlaneGCSSolver/PlaneGCSSolver_Tools.h | 4 +- .../SketchSolver_ConstraintFixed.cpp | 196 ++++++++++-------- .../SketchSolver_ConstraintFixed.h | 13 +- src/SketchSolver/SketchSolver_Group.cpp | 15 +- 8 files changed, 165 insertions(+), 109 deletions(-) diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp index 1cae52072..a6feb1f9e 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp @@ -51,7 +51,8 @@ static EntityWrapperPtr createScalar(const AttributePtr& theAttribute, else aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_ScalarWrapper(createParameter(theStorage))); - aWrapper->setValue(aScalar->value()); + if (aScalar->isInitialized()) + aWrapper->setValue(aScalar->value()); return aWrapper; } @@ -66,9 +67,11 @@ static EntityWrapperPtr createPoint(const AttributePtr& theAttribute, GCSPointPtr aNewPoint(new GCS::Point); aNewPoint->x = createParameter(theStorage); - *(aNewPoint->x) = aPoint2D->x(); aNewPoint->y = createParameter(theStorage); - *(aNewPoint->y) = aPoint2D->y(); + if (aPoint2D->isInitialized()) { + *(aNewPoint->x) = aPoint2D->x(); + *(aNewPoint->y) = aPoint2D->y(); + } return EntityWrapperPtr(new PlaneGCSSolver_PointWrapper(aNewPoint)); } diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp index 47d783dce..eb8868409 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp @@ -11,6 +11,7 @@ PlaneGCSSolver_Solver::PlaneGCSSolver_Solver() : myEquationSystem(new GCS::System), myDiagnoseBeforeSolve(false), + myInitilized(false), myConfCollected(false), myDOF(0) { @@ -69,6 +70,18 @@ void PlaneGCSSolver_Solver::removeParameters(const GCS::SET_pD& theParams) } } +void PlaneGCSSolver_Solver::initialize() +{ + Events_LongOp::start(this); + if (myDiagnoseBeforeSolve) + diagnose(); + myEquationSystem->declareUnknowns(myParameters); + myEquationSystem->initSolution(); + Events_LongOp::end(this); + + myInitilized = true; +} + PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Solver::solve() { // clear list of conflicting constraints @@ -80,11 +93,15 @@ PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Solver::solve() if (myParameters.empty()) return STATUS_INCONSISTENT; + GCS::SolveStatus aResult = GCS::Success; Events_LongOp::start(this); - if (myDiagnoseBeforeSolve) - diagnose(); - // solve equations - GCS::SolveStatus aResult = (GCS::SolveStatus)myEquationSystem->solve(myParameters); + if (myInitilized) { + aResult = (GCS::SolveStatus)myEquationSystem->solve(); + } else { + if (myDiagnoseBeforeSolve) + diagnose(); + aResult = (GCS::SolveStatus)myEquationSystem->solve(myParameters); + } Events_LongOp::end(this); // collect information about conflicting constraints every time, @@ -104,6 +121,7 @@ PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Solver::solve() aStatus = STATUS_OK; } + myInitilized = false; return aStatus; } diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h index a5a411dfa..cb195ada3 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h @@ -42,6 +42,10 @@ public: /// \brief Release memory occupied by parameters void removeParameters(const GCS::SET_pD& theParams); + /// \brief Preliminary initialization of solver (useful for moving a feature). + /// When called, the solve() method does not reinitialize a set of constraints. + void initialize(); + /// \brief Solve the set of equations /// \return identifier whether solution succeeded SolveStatus solve(); @@ -69,6 +73,7 @@ private: std::shared_ptr myEquationSystem; ///< set of equations for solving in FreeGCS bool myDiagnoseBeforeSolve; ///< is the diagnostic necessary + bool myInitilized; ///< is the system already initialized GCS::SET_I myConflictingIDs; ///< list of IDs of conflicting constraints /// specifies the conflicting constraints are already collected diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp index 524088596..63813ba75 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp @@ -123,9 +123,11 @@ SolverConstraintPtr PlaneGCSSolver_Tools::createConstraint(ConstraintPtr theCons return SolverConstraintPtr(new SketchSolver_Constraint(theConstraint)); } -SolverConstraintPtr PlaneGCSSolver_Tools::createMovementConstraint(FeaturePtr theMovedFeature) +std::shared_ptr PlaneGCSSolver_Tools::createMovementConstraint( + FeaturePtr theMovedFeature) { - return SolverConstraintPtr(new SketchSolver_ConstraintFixed(theMovedFeature)); + return std::shared_ptr( + new SketchSolver_ConstraintFixed(theMovedFeature)); } diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.h index db4820107..4e43206c1 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.h @@ -8,6 +8,7 @@ #define PlaneGCSSolver_Tools_H_ #include +#include #include #include @@ -24,7 +25,8 @@ namespace PlaneGCSSolver_Tools SolverConstraintPtr createConstraint(ConstraintPtr theConstraint); /// \brief Creates temporary constraint to fix the feature after movement - SolverConstraintPtr createMovementConstraint(FeaturePtr theMovedFeature); + std::shared_ptr + createMovementConstraint(FeaturePtr theMovedFeature); /// \brief Creates new constraint using given parameters /// \param theConstraint [in] original constraint diff --git a/src/SketchSolver/SketchSolver_ConstraintFixed.cpp b/src/SketchSolver/SketchSolver_ConstraintFixed.cpp index 7cf8a2abe..9c4f23330 100644 --- a/src/SketchSolver/SketchSolver_ConstraintFixed.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintFixed.cpp @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include @@ -12,9 +14,10 @@ #include -// Find parameters of the feature that have been updated during the movement -static EntityWrapperPtr getChangedEntity(const FeaturePtr& theFeature, - const StoragePtr& theStorage); +// Verify the entities are equal +static bool isEqual(const EntityWrapperPtr& theEntity1, const EntityWrapperPtr& theEntity2); +// Convert entity to the list of parameters +static GCS::VEC_pD toParameters(const EntityWrapperPtr& theEntity); SketchSolver_ConstraintFixed::SketchSolver_ConstraintFixed(ConstraintPtr theConstraint) @@ -46,61 +49,21 @@ void SketchSolver_ConstraintFixed::process() return; } - EntityWrapperPtr aValue; - std::vector anEntities; - getAttributes(aValue, anEntities); - if (anEntities.empty()) + EntityWrapperPtr aBaseEntity; + getAttributes(aBaseEntity, myFixedEntity); + if (!aBaseEntity) { + moveFeature(); // remove myFixed entity myErrorMsg = SketchSolver_Error::ALREADY_FIXED(); + } if (!myErrorMsg.empty()) return; - fixFeature(anEntities.front()); + + fixFeature(aBaseEntity); } void SketchSolver_ConstraintFixed::fixFeature(EntityWrapperPtr theFeature) { - std::shared_ptr anEntity = - std::dynamic_pointer_cast(theFeature); - - GCS::VEC_pD aParameters; // parameters of entity to be fixed - - // Collect parameters for each type of entity - switch (theFeature->type()) { - case ENTITY_POINT: { - std::shared_ptr aPoint = - std::dynamic_pointer_cast(theFeature); - aParameters.push_back(aPoint->point()->x); - aParameters.push_back(aPoint->point()->y); - break; - } - case ENTITY_LINE: { - std::shared_ptr aLine = std::dynamic_pointer_cast(anEntity->entity()); - aParameters.push_back(aLine->p1.x); - aParameters.push_back(aLine->p1.y); - aParameters.push_back(aLine->p2.x); - aParameters.push_back(aLine->p2.y); - break; - } - case ENTITY_CIRCLE: { - std::shared_ptr aCircle = - std::dynamic_pointer_cast(anEntity->entity()); - aParameters.push_back(aCircle->center.x); - aParameters.push_back(aCircle->center.y); - aParameters.push_back(aCircle->rad); - break; - } - case ENTITY_ARC: { - myFixedValues.reserve(4); - std::shared_ptr anArc = std::dynamic_pointer_cast(anEntity->entity()); - aParameters.push_back(anArc->center.x); - aParameters.push_back(anArc->center.y); - aParameters.push_back(anArc->rad); - aParameters.push_back(anArc->startAngle); - aParameters.push_back(anArc->endAngle); - break; - } - default: - break; - } + GCS::VEC_pD aParameters = toParameters(theFeature); // Fix given list of parameters std::list aConstraints; @@ -109,7 +72,7 @@ void SketchSolver_ConstraintFixed::fixFeature(EntityWrapperPtr theFeature) for (int i = 0; anIt != aParameters.end(); ++anIt, ++i) { myFixedValues.push_back(**anIt); aConstraints.push_back( - GCSConstraintPtr(new GCS::ConstraintEqual(*anIt, &myFixedValues[i]))); + GCSConstraintPtr(new GCS::ConstraintEqual(&myFixedValues[i], *anIt))); } myConstraint = ConstraintWrapperPtr( @@ -121,9 +84,8 @@ void SketchSolver_ConstraintFixed::fixFeature(EntityWrapperPtr theFeature) myStorage->addTemporaryConstraint(myConstraint); } -void SketchSolver_ConstraintFixed::getAttributes( - EntityWrapperPtr& theValue, - std::vector& theAttributes) +void SketchSolver_ConstraintFixed::getAttributes(EntityWrapperPtr& theBaseEntity, + EntityWrapperPtr& theFixedEntity) { if (myBaseFeature) { // if the feature is copy, do not move it @@ -135,59 +97,113 @@ void SketchSolver_ConstraintFixed::getAttributes( } // The feature is fixed. - EntityWrapperPtr aSolverEntity = getChangedEntity(myBaseFeature, myStorage); - myStorage->update(myBaseFeature); - if (aSolverEntity) - theAttributes.push_back(aSolverEntity); + PlaneGCSSolver_FeatureBuilder aBuilder; + std::list aBaseAttr = myBaseFeature->data()->attributes(std::string()); + std::list::const_iterator anIt = aBaseAttr.begin(); + for (; anIt != aBaseAttr.end(); ++anIt) + aBuilder.createAttribute(*anIt); + theFixedEntity = aBuilder.createFeature(myBaseFeature); + + theBaseEntity = myStorage->entity(myBaseFeature); + if (isEqual(theBaseEntity, theFixedEntity)) + theBaseEntity = EntityWrapperPtr(); // do not want to fix already fixed entity + } else if (myBaseConstraint) { // Constraint Fixed is added by user. // Get the attribute of constraint (it should be alone in the list of constraints). + EntityWrapperPtr aValue; std::vector anAttributes; - SketchSolver_Constraint::getAttributes(theValue, anAttributes); + SketchSolver_Constraint::getAttributes(aValue, anAttributes); std::vector::const_iterator anIt = anAttributes.begin(); for (; anIt != anAttributes.end(); ++anIt) if (*anIt) - theAttributes.push_back(*anIt); + theBaseEntity = *anIt; } else myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); } +void SketchSolver_ConstraintFixed::moveFeature() +{ + if (!myFixedEntity) + return; + GCS::VEC_pD aFixedParams = toParameters(myFixedEntity); + for (int i = 0; i < aFixedParams.size() && i < myFixedValues.size(); ++i) + myFixedValues[i] = *(aFixedParams[i]); + // Remove fixed entity due to its parameters already copied into the constraint + PlaneGCSSolver_EntityDestroyer aDestroyer; + aDestroyer.remove(myFixedEntity); + std::dynamic_pointer_cast(myStorage)->removeParameters( + aDestroyer.parametersToRemove()); -// ==================== Auxiliary functions =============================== -static bool isSameCoordinates(const AttributePoint2DPtr& thePointAttr, - const PointWrapperPtr& thePointWrapper) -{ - GCSPointPtr aGCSPoint = thePointWrapper->point(); - return fabs(*aGCSPoint->x - thePointAttr->x()) < tolerance && - fabs(*aGCSPoint->y - thePointAttr->y()) < tolerance; + myFixedEntity = EntityWrapperPtr(); } -EntityWrapperPtr getChangedEntity(const FeaturePtr& theFeature, - const StoragePtr& theStorage) + + + +// ==================== Auxiliary functions =============================== +GCS::VEC_pD toParameters(const EntityWrapperPtr& theEntity) { - std::list aPoints = theFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); - std::list aChangedPoints; - - std::list::const_iterator aPIt = aPoints.begin(); - for (; aPIt != aPoints.end(); ++aPIt) { - AttributePoint2DPtr aPnt = std::dynamic_pointer_cast(*aPIt); - EntityWrapperPtr anEnt = theStorage->entity(*aPIt); - if (anEnt) { - PointWrapperPtr aPW = std::dynamic_pointer_cast(anEnt); - if (!isSameCoordinates(aPnt, aPW)) - aChangedPoints.push_back(anEnt); - } else { - theStorage->update(*aPIt); - aChangedPoints.push_back(theStorage->entity(*aPIt)); + GCS::VEC_pD aParameters; + if (!theEntity) + return aParameters; + + std::shared_ptr anEntity = + std::dynamic_pointer_cast(theEntity); + + // Collect parameters for each type of entity + switch (theEntity->type()) { + case ENTITY_POINT: { + std::shared_ptr aPoint = + std::dynamic_pointer_cast(theEntity); + aParameters.push_back(aPoint->point()->x); + aParameters.push_back(aPoint->point()->y); + break; } + case ENTITY_LINE: { + std::shared_ptr aLine = std::dynamic_pointer_cast(anEntity->entity()); + aParameters.push_back(aLine->p1.x); + aParameters.push_back(aLine->p1.y); + aParameters.push_back(aLine->p2.x); + aParameters.push_back(aLine->p2.y); + break; + } + case ENTITY_CIRCLE: { + std::shared_ptr aCircle = + std::dynamic_pointer_cast(anEntity->entity()); + aParameters.push_back(aCircle->center.x); + aParameters.push_back(aCircle->center.y); + aParameters.push_back(aCircle->rad); + break; + } + case ENTITY_ARC: { + std::shared_ptr anArc = std::dynamic_pointer_cast(anEntity->entity()); + aParameters.push_back(anArc->center.x); + aParameters.push_back(anArc->center.y); + aParameters.push_back(anArc->rad); + aParameters.push_back(anArc->startAngle); + aParameters.push_back(anArc->endAngle); + break; + } + default: + break; } - EntityWrapperPtr aChanged; - if (aChangedPoints.size() == 1) - aChanged = aChangedPoints.front(); - else if (!aChangedPoints.empty()) // update whole feature - aChanged = theStorage->entity(theFeature); - return aChanged; + return aParameters; +} + +bool isEqual(const EntityWrapperPtr& theEntity1, const EntityWrapperPtr& theEntity2) +{ + GCS::VEC_pD aParamList1 = toParameters(theEntity1); + GCS::VEC_pD aParamList2 = toParameters(theEntity2); + + GCS::VEC_pD::const_iterator anIt1 = aParamList1.begin(); + GCS::VEC_pD::const_iterator anIt2 = aParamList2.begin(); + for (; anIt1 != aParamList1.end() && anIt2 != aParamList2.end(); ++anIt1, ++anIt2) + if (fabs((**anIt1) - (**anIt2)) > tolerance) + return false; + + return anIt1 == aParamList1.end() && anIt2 == aParamList2.end(); } diff --git a/src/SketchSolver/SketchSolver_ConstraintFixed.h b/src/SketchSolver/SketchSolver_ConstraintFixed.h index 61b5ec824..7fc02b203 100644 --- a/src/SketchSolver/SketchSolver_ConstraintFixed.h +++ b/src/SketchSolver/SketchSolver_ConstraintFixed.h @@ -27,15 +27,19 @@ public: /// \brief Block or unblock events from this constraint virtual void blockEvents(bool isBlocked); + /// \brief Set coordinates of fixed feature to the values where it has been dragged. + /// Useful when the feature is being moved. + void moveFeature(); + protected: /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints virtual void process(); /// \brief Generate list of attributes of constraint in order useful for constraints - /// \param[out] theValue numerical characteristic of constraint (e.g. distance) - /// \param[out] theAttributes list of attributes to be filled - virtual void getAttributes(EntityWrapperPtr& theValue, - std::vector& theAttributes); + /// \param[out] theBaseEntity the entity which coordinates should be fixed + /// \param[out] theFixedEntity the entity containing fixed values + virtual void getAttributes(EntityWrapperPtr& theBaseEntity, + EntityWrapperPtr& theFixedEntity); /// \brief Fixed feature basing on its type /// \param theFeature [in] feature, converted to solver specific format @@ -46,6 +50,7 @@ private: ConstraintWrapperPtr myConstraint; std::vector myFixedValues; + EntityWrapperPtr myFixedEntity; }; #endif diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index cee34791d..a0a7d3624 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -125,13 +125,19 @@ bool SketchSolver_Group::moveFeature(FeaturePtr theFeature) } // Create temporary Fixed constraint - SolverConstraintPtr aConstraint = PlaneGCSSolver_Tools::createMovementConstraint(theFeature); + std::shared_ptr aConstraint = + PlaneGCSSolver_Tools::createMovementConstraint(theFeature); if (!aConstraint) return false; - aConstraint->process(myStorage, myIsEventsBlocked); - if (aConstraint->error().empty()) + SolverConstraintPtr(aConstraint)->process(myStorage, myIsEventsBlocked); + if (aConstraint->error().empty()) { setTemporary(aConstraint); - else + if (!myStorage->isEmpty()) + myStorage->setNeedToResolve(true); + + mySketchSolver->initialize(); + aConstraint->moveFeature(); + } else myStorage->notify(theFeature); return true; @@ -141,7 +147,6 @@ bool SketchSolver_Group::moveFeature(FeaturePtr theFeature) // Function: resolveConstraints // Class: SketchSolver_Group // Purpose: solve the set of constraints for the current group -#include // ============================================================================ bool SketchSolver_Group::resolveConstraints() { -- 2.39.2