From 9ea97108f0859c83264c469256f065e7e5b36512 Mon Sep 17 00:00:00 2001 From: azv Date: Tue, 31 Mar 2015 17:20:40 +0300 Subject: [PATCH] SketchSolver library refactoring 1. Implemented distance and length constraints --- src/SketchSolver/CMakeLists.txt | 4 + src/SketchSolver/SketchSolver_Builder.cpp | 4 +- src/SketchSolver/SketchSolver_Constraint.cpp | 54 ++++++-- src/SketchSolver/SketchSolver_Constraint.h | 21 +--- .../SketchSolver_ConstraintDistance.cpp | 87 +++++++++++++ .../SketchSolver_ConstraintDistance.h | 38 ++++++ .../SketchSolver_ConstraintLength.cpp | 36 ++++++ .../SketchSolver_ConstraintLength.h | 35 ++++++ .../SketchSolver_ConstraintManager.cpp | 4 +- .../SketchSolver_ConstraintRigid.cpp | 22 +++- src/SketchSolver/SketchSolver_Error.h | 6 + src/SketchSolver/SketchSolver_Group.cpp | 97 ++++----------- src/SketchSolver/SketchSolver_Group.h | 11 +- src/SketchSolver/SketchSolver_Solver.cpp | 14 ++- src/SketchSolver/SketchSolver_Storage.cpp | 116 +++++++++++++++--- src/SketchSolver/SketchSolver_Storage.h | 21 +++- 16 files changed, 439 insertions(+), 131 deletions(-) create mode 100644 src/SketchSolver/SketchSolver_ConstraintDistance.cpp create mode 100644 src/SketchSolver/SketchSolver_ConstraintDistance.h create mode 100644 src/SketchSolver/SketchSolver_ConstraintLength.cpp create mode 100644 src/SketchSolver/SketchSolver_ConstraintLength.h diff --git a/src/SketchSolver/CMakeLists.txt b/src/SketchSolver/CMakeLists.txt index fed46c0ec..334ee0451 100644 --- a/src/SketchSolver/CMakeLists.txt +++ b/src/SketchSolver/CMakeLists.txt @@ -9,6 +9,8 @@ SET(PROJECT_HEADERS SketchSolver_Solver.h SketchSolver_Constraint.h SketchSolver_ConstraintCoincidence.h + SketchSolver_ConstraintDistance.h + SketchSolver_ConstraintLength.h SketchSolver_ConstraintRigid.h SketchSolver_Builder.h SketchSolver_Group.h @@ -21,6 +23,8 @@ SET(PROJECT_SOURCES SketchSolver_Solver.cpp SketchSolver_Constraint.cpp SketchSolver_ConstraintCoincidence.cpp + SketchSolver_ConstraintDistance.cpp + SketchSolver_ConstraintLength.cpp SketchSolver_ConstraintRigid.cpp SketchSolver_Builder.cpp SketchSolver_Group.cpp diff --git a/src/SketchSolver/SketchSolver_Builder.cpp b/src/SketchSolver/SketchSolver_Builder.cpp index 67fbdc1f2..4f0d05ab1 100644 --- a/src/SketchSolver/SketchSolver_Builder.cpp +++ b/src/SketchSolver/SketchSolver_Builder.cpp @@ -6,6 +6,8 @@ #include "SketchSolver_Builder.h" #include +#include +#include #include #include @@ -65,7 +67,7 @@ SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theCons } else if (theConstraint->getKind() == SketchPlugin_ConstraintHorizontal::ID()) { return SolverConstraintPtr(new SketchSolver_ConstraintHorizontal(theConstraint)); } else if (theConstraint->getKind() == SketchPlugin_ConstraintLength::ID()) { -//// return SolverConstraintPtr(new SketchSolver_ConstraintLength(theConstraint)); + return SolverConstraintPtr(new SketchSolver_ConstraintLength(theConstraint)); } else if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) { //// return SolverConstraintPtr(new SketchSolver_ConstraintMirror(theConstraint)); } else if (theConstraint->getKind() == SketchPlugin_ConstraintParallel::ID()) { diff --git a/src/SketchSolver/SketchSolver_Constraint.cpp b/src/SketchSolver/SketchSolver_Constraint.cpp index d8d3df086..2cdd24eb7 100644 --- a/src/SketchSolver/SketchSolver_Constraint.cpp +++ b/src/SketchSolver/SketchSolver_Constraint.cpp @@ -97,6 +97,7 @@ void SketchSolver_Constraint::process() mySlvsConstraints.push_back(anID); else mySlvsConstraints[0] = anID; + adjustConstraint(); } void SketchSolver_Constraint::update(ConstraintPtr theConstraint) @@ -110,13 +111,48 @@ void SketchSolver_Constraint::update(ConstraintPtr theConstraint) process(); } + // Update all attributes int aType; + std::map aRelocationMap; std::map::iterator aFeatIter = myFeatureMap.begin(); - for (; aFeatIter != myFeatureMap.end(); aFeatIter++) + for (; aFeatIter != myFeatureMap.end(); aFeatIter++) { + Slvs_hEntity aPrevID = aFeatIter->second; aFeatIter->second = changeEntity(aFeatIter->first, aType); + if (aFeatIter->second != aPrevID) + aRelocationMap[aPrevID] = aFeatIter->second; + } std::map::iterator anAttrIter = myAttributeMap.begin(); - for (; anAttrIter != myAttributeMap.end(); anAttrIter++) + for (; anAttrIter != myAttributeMap.end(); anAttrIter++) { + Slvs_hEntity aPrevID = anAttrIter->second; anAttrIter->second = changeEntity(anAttrIter->first, aType); + if (anAttrIter->second != aPrevID) + aRelocationMap[aPrevID] = anAttrIter->second; + } + + // Value if exists + AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast( + myBaseConstraint->data()->attribute(SketchPlugin_Constraint::VALUE())); + double aValue = aValueAttr ? aValueAttr->value() : 0.0; + + // Update constraint + std::vector::iterator aCIter = mySlvsConstraints.begin(); + for (; aCIter != mySlvsConstraints.end(); aCIter++) { + Slvs_Constraint aConstraint = myStorage->getConstraint(*aCIter); + aConstraint.valA = aValue; + Slvs_hEntity* aCoeffs[6] = { + &aConstraint.ptA, &aConstraint.ptB, + &aConstraint.entityA, &aConstraint.entityB, + &aConstraint.entityC, &aConstraint.entityD}; + for (int i = 0; i < 6; i++) { + if (*(aCoeffs[i]) == SLVS_E_UNKNOWN) + continue; + std::map::iterator aFound = aRelocationMap.find(*(aCoeffs[i])); + if (aFound != aRelocationMap.end()) + *(aCoeffs[i]) = aFound->second; + } + *aCIter = myStorage->addConstraint(aConstraint); + } + adjustConstraint(); } bool SketchSolver_Constraint::remove(ConstraintPtr theConstraint) @@ -363,7 +399,7 @@ Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& th int anAttrType; // Line - if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) { + if (aFeatureKind == SketchPlugin_Line::ID()) { anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID()); if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType); @@ -381,7 +417,7 @@ Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& th aResult = myStorage->addEntity(aCurrentEntity); } // Circle - else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) { + else if (aFeatureKind == SketchPlugin_Circle::ID()) { anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID()); if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType); @@ -401,7 +437,7 @@ Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& th aResult = myStorage->addEntity(aCurrentEntity); } // Arc - else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) { + else if (aFeatureKind == SketchPlugin_Arc::ID()) { anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID()); if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType); @@ -426,7 +462,7 @@ Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& th aResult = myStorage->addEntity(aCurrentEntity); } // Point (it has low probability to be an attribute of constraint, so it is checked at the end) - else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) { + else if (aFeatureKind == SketchPlugin_Point::ID()) { anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID()); if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier @@ -435,8 +471,10 @@ Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& th } } - myFeatureMap[theEntity] = aResult; - theType = aCurrentEntity.type; + if (aResult != SLVS_E_UNKNOWN) { + myFeatureMap[theEntity] = aResult; + theType = aCurrentEntity.type; + } return aResult; } diff --git a/src/SketchSolver/SketchSolver_Constraint.h b/src/SketchSolver/SketchSolver_Constraint.h index b7925d66c..6a57f6b21 100644 --- a/src/SketchSolver/SketchSolver_Constraint.h +++ b/src/SketchSolver/SketchSolver_Constraint.h @@ -76,6 +76,11 @@ protected: /// \param[out] theAttributes list of attributes to be filled virtual void getAttributes(double& theValue, std::vector& theAttributes); + /// \brief This method is used in derived objects to check consistence of constraint. + /// E.g. the distance between line and point may be signed. + virtual void adjustConstraint() + {} + /// \brief Create or change SlveSpace entity according to the given attribute /// \param[in] theAttribute reference to the entity to be changed /// \param[out] theType type of created entity @@ -109,22 +114,6 @@ typedef std::shared_ptr SolverConstraintPtr; -/** \class SketchSolver_ConstraintDistance - * \ingroup Plugins - * \brief Convert distance constraint to SolveSpace structure - */ -class SketchSolver_ConstraintDistance : public SketchSolver_Constraint -{ -public: - SketchSolver_ConstraintDistance(ConstraintPtr theConstraint) : - SketchSolver_Constraint(theConstraint) - {} - - virtual int getType() const - { return SLVS_C_PT_PT_DISTANCE; } -}; - - /** \class SketchSolver_ConstraintParallel * \ingroup Plugins * \brief Convert Parallel constraint to SolveSpace structure diff --git a/src/SketchSolver/SketchSolver_ConstraintDistance.cpp b/src/SketchSolver/SketchSolver_ConstraintDistance.cpp new file mode 100644 index 000000000..51f0d7359 --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintDistance.cpp @@ -0,0 +1,87 @@ +#include +#include +#include + +#include + + +void SketchSolver_ConstraintDistance::process() +{ + cleanErrorMsg(); + if (!myBaseConstraint || !myStorage || myGroup == 0) { + /// TODO: Put error message here + return; + } + if (!mySlvsConstraints.empty()) // some data is changed, update constraint + update(myBaseConstraint); + + double aValue; + std::vector anEntities; + getAttributes(aValue, anEntities); + if (!myErrorMsg.empty()) + return; + + // Obtain entities to identify the type of distance + static const int aNbPoints = 2; + Slvs_hEntity aPoint[aNbPoints] = {SLVS_E_UNKNOWN, SLVS_E_UNKNOWN}; + Slvs_hEntity aLine = SLVS_E_UNKNOWN; + myType = SLVS_C_PT_PT_DISTANCE; + int aPtPos = 0; + std::vector::iterator anEntIter = anEntities.begin(); + for (; anEntIter != anEntities.end(); anEntIter++) { + if (*anEntIter == SLVS_E_UNKNOWN) + continue; + Slvs_Entity anEnt = myStorage->getEntity(*anEntIter); + if (anEnt.type == SLVS_E_POINT_IN_2D || anEnt.type == SLVS_E_POINT_IN_3D) { + if (aPtPos >= aNbPoints) { + myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); + return; + } + aPoint[aPtPos++] = *anEntIter; + } + else if (anEnt.type == SLVS_E_LINE_SEGMENT) { + if (myType == SLVS_C_PT_LINE_DISTANCE) { + myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); + return; + } + aLine = *anEntIter; + myType = SLVS_C_PT_LINE_DISTANCE; + } + } + + Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(), + getType(), myGroup->getWorkplaneId(), aValue, aPoint[0], aPoint[1], aLine, SLVS_E_UNKNOWN); + aConstraint.h = myStorage->addConstraint(aConstraint); + mySlvsConstraints.push_back(aConstraint.h); + adjustConstraint(); +} + +void SketchSolver_ConstraintDistance::adjustConstraint() +{ + if (getType() != SLVS_C_PT_LINE_DISTANCE) + return; + + // Get constraint parameters and check the sign of constraint value + std::vector::iterator aCIter = mySlvsConstraints.begin(); + for (; aCIter != mySlvsConstraints.end(); aCIter++) { + Slvs_Constraint aConstraint = myStorage->getConstraint(*aCIter); + Slvs_Entity aLine = myStorage->getEntity(aConstraint.entityA); + // Obtain point and line coordinates + Slvs_hEntity aPointID[3] = {aConstraint.ptA, aLine.point[0], aLine.point[1]}; + std::shared_ptr aPoints[3]; + for (int i = 0; i < 3; i++) { + Slvs_Entity aPoint = myStorage->getEntity(aPointID[i]); + Slvs_Param aParams[2] = { + myStorage->getParameter(aPoint.param[0]), + myStorage->getParameter(aPoint.param[1])}; + aPoints[i] = std::shared_ptr(new GeomAPI_XY(aParams[0].val, aParams[1].val)); + } + std::shared_ptr aLineVec = aPoints[2]->decreased(aPoints[1]); + std::shared_ptr aPtLineVec = aPoints[0]->decreased(aPoints[1]); + if (aPtLineVec->cross(aLineVec) * aConstraint.valA < 0.0) { + aConstraint.valA *= -1.0; + myStorage->updateConstraint(aConstraint); + } + } +} + diff --git a/src/SketchSolver/SketchSolver_ConstraintDistance.h b/src/SketchSolver/SketchSolver_ConstraintDistance.h new file mode 100644 index 000000000..48cadbfca --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintDistance.h @@ -0,0 +1,38 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_ConstraintDistance.h +// Created: 31 Mar 2015 +// Author: Artem ZHIDKOV + +#ifndef SketchSolver_ConstraintDistance_H_ +#define SketchSolver_ConstraintDistance_H_ + +#include "SketchSolver.h" +#include + +/** \class SketchSolver_ConstraintDistance + * \ingroup Plugins + * \brief Convert distance constraint to SolveSpace structure + */ +class SketchSolver_ConstraintDistance : public SketchSolver_Constraint +{ +public: + SketchSolver_ConstraintDistance(ConstraintPtr theConstraint) : + SketchSolver_Constraint(theConstraint), myType(SLVS_C_UNKNOWN) + {} + + virtual int getType() const + {return myType; } + +protected: + /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints + virtual void process(); + + /// \brief Verifies the sign of the distance between line and point and change it if necessary + virtual void adjustConstraint(); + +private: + int myType; ///< type of constraint (applicable: SLVS_C_PT_PT_DISTANCE, SLVS_C_PT_LINE_DISTANCE) +}; + +#endif diff --git a/src/SketchSolver/SketchSolver_ConstraintLength.cpp b/src/SketchSolver/SketchSolver_ConstraintLength.cpp new file mode 100644 index 000000000..3d1d1bf22 --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintLength.cpp @@ -0,0 +1,36 @@ +#include +#include +#include + + +void SketchSolver_ConstraintLength::process() +{ + cleanErrorMsg(); + if (!myBaseConstraint || !myStorage || myGroup == 0) { + /// TODO: Put error message here + return; + } + if (!mySlvsConstraints.empty()) // some data is changed, update constraint + update(myBaseConstraint); + + double aValue; + std::vector anEntities; + getAttributes(aValue, anEntities); + if (!myErrorMsg.empty()) + return; + + // Check the entity is a line + Slvs_Entity aLine = myStorage->getEntity(anEntities[2]); + if (aLine.type != SLVS_E_LINE_SEGMENT){ + myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); + return; + } + + Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(), + getType(), myGroup->getWorkplaneId(), aValue, + aLine.point[0], aLine.point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); + aConstraint.h = myStorage->addConstraint(aConstraint); + mySlvsConstraints.push_back(aConstraint.h); + adjustConstraint(); +} + diff --git a/src/SketchSolver/SketchSolver_ConstraintLength.h b/src/SketchSolver/SketchSolver_ConstraintLength.h new file mode 100644 index 000000000..176c6948e --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintLength.h @@ -0,0 +1,35 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_ConstraintLength.h +// Created: 31 Mar 2015 +// Author: Artem ZHIDKOV + +#ifndef SketchSolver_ConstraintLength_H_ +#define SketchSolver_ConstraintLength_H_ + +#include "SketchSolver.h" +#include + +/** \class SketchSolver_ConstraintLength + * \ingroup Plugins + * \brief Convert length constraint to SolveSpace structure + */ +class SketchSolver_ConstraintLength : public SketchSolver_Constraint +{ +public: + SketchSolver_ConstraintLength(ConstraintPtr theConstraint) : + SketchSolver_Constraint(theConstraint) + {} + + virtual int getType() const + { return SLVS_C_PT_PT_DISTANCE; } + +protected: + /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints + virtual void process(); + +private: + int myType; ///< type of constraint (applicable: SLVS_C_PT_PT_DISTANCE, SLVS_C_PT_LINE_DISTANCE) +}; + +#endif diff --git a/src/SketchSolver/SketchSolver_ConstraintManager.cpp b/src/SketchSolver/SketchSolver_ConstraintManager.cpp index 1e80079c9..2dbd6c57d 100644 --- a/src/SketchSolver/SketchSolver_ConstraintManager.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintManager.cpp @@ -224,7 +224,8 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity( for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) if ((*aGroupIter)->getId() == aGroupId) { // If the group is empty, the feature is not added (the constraint only) -//// if (!aConstraint && !(*aGroupIter)->isEmpty()) + if (!aConstraint && !(*aGroupIter)->isEmpty()) + return (*aGroupIter)->updateFeature(theFeature); //// return (*aGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN; return (*aGroupIter)->changeConstraint(aConstraint); } @@ -261,6 +262,7 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity( if (aConstraint) return (*aFirstGroupIter)->changeConstraint(aConstraint); + return (*aFirstGroupIter)->updateFeature(theFeature); //// return (*aFirstGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN; } diff --git a/src/SketchSolver/SketchSolver_ConstraintRigid.cpp b/src/SketchSolver/SketchSolver_ConstraintRigid.cpp index 02ba819a8..12815acf3 100644 --- a/src/SketchSolver/SketchSolver_ConstraintRigid.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintRigid.cpp @@ -30,7 +30,13 @@ void SketchSolver_ConstraintRigid::process() bool isEmpty = aConstrIter == mySlvsConstraints.end(); std::vector::const_iterator anEntIter = anEntities.begin(); for (; anEntIter != anEntities.end(); anEntIter++) { - if (isEmpty) { // create new constraint + if (*anEntIter == SLVS_E_UNKNOWN) + continue; + Slvs_hConstraint aConstrID = myStorage->isPointFixed(*anEntIter); + bool isForceUpdate = (aConstrID != SLVS_E_UNKNOWN && !myBaseConstraint); + if (isEmpty && !isForceUpdate) { // create new constraint + if (aConstrID != SLVS_E_UNKNOWN) + continue; // the coincident point is already fixed aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), aValue, *anEntIter, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); aConstraint.h = myStorage->addConstraint(aConstraint); @@ -38,11 +44,17 @@ void SketchSolver_ConstraintRigid::process() if (!myBaseConstraint) myStorage->addTemporaryConstraint(aConstraint.h); } else { // update already existent constraint - aConstraint = myStorage->getConstraint(*aConstrIter); + if (aConstrID == SLVS_E_UNKNOWN || myBaseConstraint) + aConstrID = *aConstrIter; + aConstraint = myStorage->getConstraint(aConstrID); aConstraint.ptA = *anEntIter; myStorage->addConstraint(aConstraint); - aConstrIter++; - isEmpty = aConstrIter == mySlvsConstraints.end(); + if (!myBaseConstraint) + myStorage->addTemporaryConstraint(aConstraint.h); + if (!isEmpty) { + aConstrIter++; + isEmpty = aConstrIter == mySlvsConstraints.end(); + } } } } @@ -59,7 +71,7 @@ void SketchSolver_ConstraintRigid::getAttributes( // Get the attribute of constraint AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( myBaseConstraint->attribute(SketchPlugin_ConstraintRigid::ENTITY_A())); - if (!aRefAttr) { + if (!aRefAttr || !aRefAttr->isInitialized()) { myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); return; } diff --git a/src/SketchSolver/SketchSolver_Error.h b/src/SketchSolver/SketchSolver_Error.h index 0ef01476e..dfae098bf 100644 --- a/src/SketchSolver/SketchSolver_Error.h +++ b/src/SketchSolver/SketchSolver_Error.h @@ -35,6 +35,12 @@ class SketchSolver_Error static const std::string MY_ERROR_VALUE("Attribute is not initialized"); return MY_ERROR_VALUE; } + /// Constraint has wrong attributes + inline static const std::string& INCORRECT_ATTRIBUTE() + { + static const std::string MY_ERROR_VALUE("Incorrect attribute"); + return MY_ERROR_VALUE; + } }; #endif diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index f5b0ee387..493fdbf37 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -156,41 +156,6 @@ Slvs_hEntity SketchSolver_Group::getAttributeId(AttributePtr theAttribute) const return aCIter->second->getId(theAttribute); } - -////// ============================================================================ -////// Function: checkConstraintConsistence -////// Class: SketchSolver_Group -////// Purpose: verifies and changes parameters of the constraint -////// ============================================================================ -////void SketchSolver_Group::checkConstraintConsistence(Slvs_Constraint& theConstraint) -////{ -//// if (theConstraint.type == SLVS_C_PT_LINE_DISTANCE) { -//// // Get constraint parameters and check the sign of constraint value -//// -//// // point coordinates -//// int aPtPos = Search(theConstraint.ptA, myEntities); -//// int aPtParamPos = Search(myEntities[aPtPos].param[0], myParams); -//// std::shared_ptr aPoint( -//// new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val)); -//// -//// // line coordinates -//// int aLnPos = Search(theConstraint.entityA, myEntities); -//// aPtPos = Search(myEntities[aLnPos].point[0], myEntities); -//// aPtParamPos = Search(myEntities[aPtPos].param[0], myParams); -//// std::shared_ptr aStart( -//// new GeomAPI_XY(-myParams[aPtParamPos].val, -myParams[aPtParamPos + 1].val)); -//// aPtPos = Search(myEntities[aLnPos].point[1], myEntities); -//// aPtParamPos = Search(myEntities[aPtPos].param[0], myParams); -//// std::shared_ptr aEnd( -//// new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val)); -//// -//// aEnd = aEnd->added(aStart); -//// aPoint = aPoint->added(aStart); -//// if (aPoint->cross(aEnd) * theConstraint.valA < 0.0) -//// theConstraint.valA *= -1.0; -//// } -////} - // ============================================================================ // Function: changeConstraint // Class: SketchSolver_Group @@ -453,15 +418,23 @@ bool SketchSolver_Group::changeConstraint( return true; } -void SketchSolver_Group::moveFeature(std::shared_ptr theFeature) + +bool SketchSolver_Group::updateFeature(std::shared_ptr theFeature) { std::set aConstraints = myFeatureStorage->getConstraints(theFeature); + if (aConstraints.empty()) + return false; std::set::iterator aCIter = aConstraints.begin(); for (; aCIter != aConstraints.end(); aCIter++) { ConstraintConstraintMap::iterator aSolConIter = myConstraints.find(*aCIter); aSolConIter->second->update(); } + return true; +} +void SketchSolver_Group::moveFeature(std::shared_ptr theFeature) +{ + updateFeature(theFeature); // Temporary rigid constraint SolverConstraintPtr aConstraint = SketchSolver_Builder::getInstance()->createRigidConstraint(theFeature); @@ -1417,46 +1390,24 @@ bool SketchSolver_Group::updateWorkplane() // ============================================================================ bool SketchSolver_Group::resolveConstraints() { - if (!myStorage->isNeedToResolve() || isEmpty()) - return false; + bool aResolved = false; + if (myStorage->isNeedToResolve() && !isEmpty()) { + myConstrSolver.setGroupID(myID); + myStorage->initializeSolver(myConstrSolver); - myConstrSolver.setGroupID(myID); - myStorage->initializeSolver(myConstrSolver); - -//// theSolver.setDraggedParameters(myTempPointWhereDragged); -//// - int aResult = myConstrSolver.solve(); - if (aResult == SLVS_RESULT_OKAY) { // solution succeeded, store results into correspondent attributes - ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin(); - for (; aConstrIter != myConstraints.end(); aConstrIter++) - aConstrIter->second->refresh(); - -//// // Obtain result into the same list of parameters -//// if (!myConstrSolver.getResult(myParams)) -//// return true; -//// -//// // We should go through the attributes map, because only attributes have valued parameters -//// std::map, Slvs_hEntity>::iterator anEntIter = -//// myEntityAttrMap.begin(); -//// for (; anEntIter != myEntityAttrMap.end(); anEntIter++) { -//// if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get()) -//// anEntIter->first->owner()->data()->blockSendAttributeUpdated(true); -//// if (updateAttribute(anEntIter->first, anEntIter->second)) -//// updateRelatedConstraints(anEntIter->first); -//// } -//// updateFilletConstraints(); -//// // unblock all features then -//// for (anEntIter = myEntityAttrMap.begin(); anEntIter != myEntityAttrMap.end(); anEntIter++) { -//// if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get()) -//// anEntIter->first->owner()->data()->blockSendAttributeUpdated(false); -//// } - } else if (!myConstraints.empty()) - Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this); + int aResult = myConstrSolver.solve(); + if (aResult == SLVS_RESULT_OKAY) { // solution succeeded, store results into correspondent attributes + ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin(); + for (; aConstrIter != myConstraints.end(); aConstrIter++) + aConstrIter->second->refresh(); + } else if (!myConstraints.empty()) + Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this); + myStorage->setNeedToResolve(false); + aResolved = true; + } removeTemporaryConstraints(); -//// myNeedToSolve = false; - myStorage->setNeedToResolve(false); - return true; + return aResolved; } // ============================================================================ diff --git a/src/SketchSolver/SketchSolver_Group.h b/src/SketchSolver/SketchSolver_Group.h index 68317fd0a..6e53af522 100644 --- a/src/SketchSolver/SketchSolver_Group.h +++ b/src/SketchSolver/SketchSolver_Group.h @@ -91,6 +91,11 @@ class SketchSolver_Group //// */ //// bool changeFilletConstraint(std::shared_ptr theConstraint); + /** \brief Updates the data corresponding the specified feature + * \param[in] theFeature the feature to be updated + */ + bool updateFeature(std::shared_ptr theFeature); + /** \brief Updates the data corresponding the specified feature moved in GUI. * Additional Fixed constraints are created. * \param[in] theFeature the feature to be updated @@ -240,12 +245,6 @@ private: //// */ //// bool addCoincidentPoints(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2); //// -//// /** \brief Verifies and changes parameters of constriant, -//// * e.g. sign of the distance between line and point -//// * \param[in,out] theConstraint SolveSpace constraint to be verified -//// */ -//// void checkConstraintConsistence(Slvs_Constraint& theConstraint); -//// //// /** \brief Change entities parameters to make them symmetric relating to the mirror line //// * \param[in] theBase entity to be mirrored //// * \param[in] theMirror a mirrored object diff --git a/src/SketchSolver/SketchSolver_Solver.cpp b/src/SketchSolver/SketchSolver_Solver.cpp index 650e11c2d..0e7b1761c 100644 --- a/src/SketchSolver/SketchSolver_Solver.cpp +++ b/src/SketchSolver/SketchSolver_Solver.cpp @@ -31,6 +31,8 @@ SketchSolver_Solver::SketchSolver_Solver() SketchSolver_Solver::~SketchSolver_Solver() { + if (myEquationsSystem.constraint) + delete[] myEquationsSystem.constraint; if (myEquationsSystem.failed) delete[] myEquationsSystem.failed; } @@ -56,8 +58,16 @@ void SketchSolver_Solver::setEntities(Slvs_Entity* theEntities, int theSize) void SketchSolver_Solver::setConstraints(Slvs_Constraint* theConstraints, int theSize) { - myEquationsSystem.constraint = theConstraints; - myEquationsSystem.constraints = theSize; + if (!myEquationsSystem.constraint) { + myEquationsSystem.constraint = new Slvs_Constraint[theSize]; + myEquationsSystem.constraints = theSize; + } + else if (myEquationsSystem.constraints != theSize) { + delete[] myEquationsSystem.constraint; + myEquationsSystem.constraint = new Slvs_Constraint[theSize]; + myEquationsSystem.constraints = theSize; + } + memcpy(myEquationsSystem.constraint, theConstraints, theSize * sizeof(Slvs_Constraint)); } diff --git a/src/SketchSolver/SketchSolver_Storage.cpp b/src/SketchSolver/SketchSolver_Storage.cpp index d56d98d85..687e6ea11 100644 --- a/src/SketchSolver/SketchSolver_Storage.cpp +++ b/src/SketchSolver/SketchSolver_Storage.cpp @@ -26,6 +26,7 @@ SketchSolver_Storage::SketchSolver_Storage() : myParamMaxID(SLVS_E_UNKNOWN), myEntityMaxID(SLVS_E_UNKNOWN), myConstrMaxID(SLVS_C_UNKNOWN), + myFixed(SLVS_E_UNKNOWN), myNeedToResolve(false) { } @@ -78,6 +79,7 @@ bool SketchSolver_Storage::removeParameter(const Slvs_hParam& theParamID) } // Remove parameter myParameters.erase(myParameters.begin() + aPos); + myParamMaxID = myParameters.empty() ? SLVS_E_UNKNOWN : myParameters.back().h; myNeedToResolve = true; myRemovedParameters.insert(theParamID); return true; @@ -159,6 +161,7 @@ bool SketchSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID) // The entity is not used, remove it and its parameters Slvs_Entity anEntity = myEntities[aPos]; myEntities.erase(myEntities.begin() + aPos); + myEntityMaxID = myEntities.empty() ? SLVS_E_UNKNOWN : myEntities.back().h; if (anEntity.distance != SLVS_E_UNKNOWN) aResult = aResult && removeParameter(anEntity.distance); for (int i = 0; i < 4; i++) @@ -169,6 +172,8 @@ bool SketchSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID) aResult = removeEntity(anEntity.point[i]) && aResult; myNeedToResolve = true; myRemovedEntities.insert(theEntityID); + if (anEntity.type == SLVS_E_POINT_IN_2D || anEntity.type == SLVS_E_POINT_IN_3D) + removeCoincidentPoint(theEntityID); } return aResult; } @@ -185,6 +190,31 @@ const Slvs_Entity& SketchSolver_Storage::getEntity(const Slvs_hEntity& theEntity return aDummy; } +Slvs_hConstraint SketchSolver_Storage::isPointFixed(const Slvs_hEntity& thePointID) const +{ + // Search the set of coincident points + std::vector< std::set >::const_iterator aCPIter = myCoincidentPoints.begin(); + for (; aCPIter != myCoincidentPoints.end(); aCPIter++) + if (aCPIter->find(thePointID) != aCPIter->end()) + break; + if (aCPIter == myCoincidentPoints.end()) { + std::vector::const_iterator aConstrIter = myConstraints.begin(); + for (; aConstrIter != myConstraints.end(); aConstrIter++) + if (aConstrIter->type == SLVS_C_WHERE_DRAGGED && + aConstrIter->ptA == thePointID) + return aConstrIter->h; + return SLVS_E_UNKNOWN; + } + + // Search the Rigid constraint + std::vector::const_iterator aConstrIter = myConstraints.begin(); + for (; aConstrIter != myConstraints.end(); aConstrIter++) + if (aConstrIter->type == SLVS_C_WHERE_DRAGGED && + aCPIter->find(aConstrIter->ptA) != aCPIter->end()) + return aConstrIter->h; + return SLVS_E_UNKNOWN; +} + Slvs_hConstraint SketchSolver_Storage::addConstraint(const Slvs_Constraint& theConstraint) { @@ -200,6 +230,8 @@ Slvs_hConstraint SketchSolver_Storage::addConstraint(const Slvs_Constraint& theC aConstraint.h = ++myConstrMaxID; myConstraints.push_back(aConstraint); myNeedToResolve = true; + if (aConstraint.type == SLVS_C_POINTS_COINCIDENT) + addCoincidentPoints(aConstraint.ptA, aConstraint.ptB); return aConstraint.h; } @@ -211,6 +243,8 @@ Slvs_hConstraint SketchSolver_Storage::updateConstraint(const Slvs_Constraint& t if (aPos >= 0 && aPos < (int)myConstraints.size()) { myNeedToResolve = myNeedToResolve || IsNotEqual(myConstraints[aPos], theConstraint); myConstraints[aPos] = theConstraint; + if (theConstraint.type == SLVS_C_POINTS_COINCIDENT) + addCoincidentPoints(theConstraint.ptA, theConstraint.ptB); return theConstraint.h; } } @@ -228,6 +262,7 @@ bool SketchSolver_Storage::removeConstraint(const Slvs_hConstraint& theConstrain if (aPos >= 0 && aPos < (int)myConstraints.size()) { Slvs_Constraint aConstraint = myConstraints[aPos]; myConstraints.erase(myConstraints.begin() + aPos); + myConstrMaxID = myConstraints.empty() ? SLVS_E_UNKNOWN : myConstraints.back().h; myNeedToResolve = true; myRemovedConstraints.insert(theConstraintID); // Remove all entities @@ -235,16 +270,11 @@ bool SketchSolver_Storage::removeConstraint(const Slvs_hConstraint& theConstrain aConstraint.entityA, aConstraint.entityB, aConstraint.entityC, aConstraint.entityD}; for (int i = 0; i < 6; i++) - if (anEntities[i] != SLVS_E_UNKNOWN) { + if (anEntities[i] != SLVS_E_UNKNOWN) aResult = removeEntity(anEntities[i]) && aResult; - // remove temporary fixed points, if exists - std::vector::iterator aFPIt = myFixedPoints.begin(); - for (; aFPIt != myFixedPoints.end(); aFPIt++) - if (*aFPIt == anEntities[i]) { - myFixedPoints.erase(aFPIt); - break; - } - } + // remove temporary fixed point, if available + if (myFixed == theConstraintID) + myFixed = SLVS_E_UNKNOWN; } return aResult; } @@ -263,8 +293,11 @@ const Slvs_Constraint& SketchSolver_Storage::getConstraint(const Slvs_hConstrain void SketchSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID) { + if (myFixed != SLVS_E_UNKNOWN) + return; // the point is already fixed int aPos = Search(theConstraintID, myConstraints); - myFixedPoints.push_back(myConstraints[aPos].ptA); + if (aPos >= 0 && aPos < (int)myConstraints.size()) + myFixed = theConstraintID; } void SketchSolver_Storage::getRemoved( @@ -285,15 +318,70 @@ void SketchSolver_Storage::initializeSolver(SketchSolver_Solver& theSolver) { theSolver.setParameters(myParameters.data(), (int)myParameters.size()); theSolver.setEntities(myEntities.data(), (int)myEntities.size()); - theSolver.setConstraints(myConstraints.data(), (int)myConstraints.size()); - // initialize fixed points - if (!myFixedPoints.empty()) { - int aPos = Search(myFixedPoints.front(), myEntities); + // Copy constraints excluding the fixed one + std::vector aConstraints = myConstraints; + if (myFixed != SLVS_E_UNKNOWN) { + Slvs_hEntity aFixedPoint = SLVS_E_UNKNOWN; + std::vector::iterator anIt = aConstraints.begin(); + for (; anIt != aConstraints.end(); anIt++) + if (anIt->h == myFixed) { + aFixedPoint = anIt->ptA; + aConstraints.erase(anIt); + break; + } + // set dragged parameters + int aPos = Search(aFixedPoint, myEntities); theSolver.setDraggedParameters(myEntities[aPos].param); } + theSolver.setConstraints(aConstraints.data(), (int)aConstraints.size()); } +void SketchSolver_Storage::addCoincidentPoints( + const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) +{ + std::vector< std::set >::iterator aCIter = myCoincidentPoints.begin(); + std::vector< std::set >::iterator aFoundIter = myCoincidentPoints.end(); // already found coincidence + bool isFound = false; + for (; aCIter != myCoincidentPoints.end(); aCIter++) { + bool isFirstFound = aCIter->find(thePoint1) != aCIter->end(); + bool isSecondFound = aCIter->find(thePoint2) != aCIter->end(); + isFound = isFound || isFirstFound || isSecondFound; + if (isFirstFound && isSecondFound) + break; // already coincident + else if (isFirstFound || isSecondFound) { + if (aFoundIter != myCoincidentPoints.end()) { + // merge two sets + aFoundIter->insert(aCIter->begin(), aCIter->end()); + myCoincidentPoints.erase(aCIter); + break; + } + aCIter->insert(thePoint1); + aCIter->insert(thePoint2); + } + } + // coincident points not found + if (!isFound) { + std::set aNewSet; + aNewSet.insert(thePoint1); + aNewSet.insert(thePoint2); + myCoincidentPoints.push_back(aNewSet); + } +} + +void SketchSolver_Storage::removeCoincidentPoint(const Slvs_hEntity& thePoint) +{ + std::vector< std::set >::iterator aCIter = myCoincidentPoints.begin(); + for (; aCIter != myCoincidentPoints.end(); aCIter++) + if (aCIter->find(thePoint) != aCIter->end()) { + aCIter->erase(thePoint); + if (aCIter->size() <= 1) + myCoincidentPoints.erase(aCIter); + break; + } +} + + // ======================================================== // ========= Auxiliary functions =============== diff --git a/src/SketchSolver/SketchSolver_Storage.h b/src/SketchSolver/SketchSolver_Storage.h index 0317f930f..fe206107e 100644 --- a/src/SketchSolver/SketchSolver_Storage.h +++ b/src/SketchSolver/SketchSolver_Storage.h @@ -60,8 +60,12 @@ public: /// \brief Returns the entity by its ID const Slvs_Entity& getEntity(const Slvs_hEntity& theEntityID) const; + /// \brief Verifies the current point or another coincident one is fixed + /// \return the ID of the Fixed constraint or SLVS_E_UNKNOWN + Slvs_hConstraint isPointFixed(const Slvs_hEntity& thePointID) const; + /** \brief Add new constraint to the current group - * \param[in] theConstraint SolveSpace constraint + * \param[in] theConstraint SolveSpace's constraint * \return the ID of added constraint */ Slvs_hConstraint addConstraint(const Slvs_Constraint& theConstraint); @@ -99,15 +103,22 @@ public: /// \brief Initialize constraint solver by the entities collected by current storage void initializeSolver(SketchSolver_Solver& theSolver); +private: + /// \brief Store coincident points + void addCoincidentPoints(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2); + /// \brief Remove point from lists of coincidence + void removeCoincidentPoint(const Slvs_hEntity& thePoint); + private: Slvs_hParam myParamMaxID; ///< current parameter index (may differs with the number of parameters) - std::vector myParameters; ///< list of parameters used in the current group of constraints + std::vector myParameters; ///< list of parameters used in the current group of constraints (sorted by the identifier) Slvs_hEntity myEntityMaxID; ///< current entity index (may differs with the number of entities) - std::vector myEntities; ///< list of entities used in the current group of constraints + std::vector myEntities; ///< list of entities used in the current group of constraints (sorted by the identifier) Slvs_hConstraint myConstrMaxID; ///< current constraint index (may differs with the number of constraints) - std::vector myConstraints; ///< list of constraints used in the current group + std::vector myConstraints; ///< list of constraints used in the current group (sorted by the identifier) - std::vector myFixedPoints; ///< identifiers of entities which relate to temporary constraints + std::vector< std::set > myCoincidentPoints; ///< lists of coincident points + Slvs_hConstraint myFixed; ///< identifier of one of temporary constraints to fix separate point bool myNeedToResolve; ///< parameters are changed and group needs to be resolved -- 2.39.2