From 29d446f4dd2969d80087745fe44adb5638d13de7 Mon Sep 17 00:00:00 2001 From: azv Date: Tue, 15 Dec 2015 11:55:25 +0300 Subject: [PATCH] First phase of SketchSolver refactoring 1. SketchSolver now is a base library for all other solvers 2. Created SolveSpaceSolver library to use SolveSpace. 3. Implemented minimal set of constraints: Coincidence, Fixed 4. Constraints: Horizontal, Vertical, Parallel, Perpendicular 5. Constraints: Distance, Length 6. Correct multi-coincidence of points 7. Constraints: Angle, Equal, Tangent 8. Replace list of base constraints in SketchSolver_Constraint by a single constraint 9. Constraint Mirror 10. Fix problem in arc movement 11. Multi-Rotation and Multi-Translation constraints 12. Process parametric values 13. Problem with mirror of an arc 14. Update multi-coincidence processing (several coincident points placed on single feature) --- src/Config/plugins.xml | 2 +- src/SketchPlugin/Test/TestConstraintRigid.py | 15 +- src/SketchSolver/CMakeLists.txt | 49 +- src/SketchSolver/SketchSolver.h | 16 + src/SketchSolver/SketchSolver_Builder.cpp | 265 +-- src/SketchSolver/SketchSolver_Builder.h | 137 +- src/SketchSolver/SketchSolver_Constraint.cpp | 761 ++----- src/SketchSolver/SketchSolver_Constraint.h | 201 +- .../SketchSolver_ConstraintAngle.cpp | 71 +- .../SketchSolver_ConstraintAngle.h | 7 +- .../SketchSolver_ConstraintCoincidence.cpp | 393 +--- .../SketchSolver_ConstraintCoincidence.h | 47 +- .../SketchSolver_ConstraintDistance.cpp | 120 +- .../SketchSolver_ConstraintDistance.h | 13 +- .../SketchSolver_ConstraintEqual.cpp | 60 +- .../SketchSolver_ConstraintEqual.h | 12 +- .../SketchSolver_ConstraintFillet.cpp | 208 -- .../SketchSolver_ConstraintFillet.h | 46 - .../SketchSolver_ConstraintFixed.cpp | 111 + .../SketchSolver_ConstraintFixed.h | 55 + .../SketchSolver_ConstraintLength.cpp | 48 +- .../SketchSolver_ConstraintLength.h | 13 +- .../SketchSolver_ConstraintMirror.cpp | 476 +---- .../SketchSolver_ConstraintMirror.h | 38 +- .../SketchSolver_ConstraintMovement.cpp | 214 +- .../SketchSolver_ConstraintMovement.h | 25 +- .../SketchSolver_ConstraintMulti.cpp | 335 +-- .../SketchSolver_ConstraintMulti.h | 47 +- .../SketchSolver_ConstraintMultiRotation.cpp | 185 +- .../SketchSolver_ConstraintMultiRotation.h | 27 +- ...ketchSolver_ConstraintMultiTranslation.cpp | 189 +- .../SketchSolver_ConstraintMultiTranslation.h | 34 +- .../SketchSolver_ConstraintParametric.cpp | 171 -- .../SketchSolver_ConstraintParametric.h | 59 - .../SketchSolver_ConstraintRigid.cpp | 393 ---- .../SketchSolver_ConstraintRigid.h | 76 - .../SketchSolver_ConstraintTangent.cpp | 122 +- .../SketchSolver_ConstraintTangent.h | 12 +- .../SketchSolver_FeatureStorage.cpp | 418 ---- .../SketchSolver_FeatureStorage.h | 78 - src/SketchSolver/SketchSolver_Group.cpp | 555 ++--- src/SketchSolver/SketchSolver_Group.h | 38 +- .../SketchSolver_IConstraintWrapper.h | 103 + .../SketchSolver_IEntityWrapper.h | 100 + .../SketchSolver_IParameterWrapper.h | 55 + src/SketchSolver/SketchSolver_ISolver.h | 50 + ...ntManager.cpp => SketchSolver_Manager.cpp} | 71 +- ...traintManager.h => SketchSolver_Manager.h} | 46 +- src/SketchSolver/SketchSolver_Storage.cpp | 1376 +++--------- src/SketchSolver/SketchSolver_Storage.h | 357 ++-- .../SolveSpaceSolver/CMakeLists.txt | 42 + .../SolveSpaceSolver_Builder.cpp | 845 ++++++++ .../SolveSpaceSolver_Builder.h | 140 ++ .../SolveSpaceSolver_ConstraintType.h | 75 + .../SolveSpaceSolver_ConstraintWrapper.cpp | 117 + .../SolveSpaceSolver_ConstraintWrapper.h | 61 + .../SolveSpaceSolver_EntityWrapper.cpp | 127 ++ .../SolveSpaceSolver_EntityWrapper.h | 57 + .../SolveSpaceSolver_ParameterWrapper.cpp | 47 + .../SolveSpaceSolver_ParameterWrapper.h | 55 + .../SolveSpaceSolver_Solver.cpp} | 56 +- .../SolveSpaceSolver_Solver.h} | 46 +- .../SolveSpaceSolver_Storage.cpp | 1879 +++++++++++++++++ .../SolveSpaceSolver_Storage.h | 280 +++ 64 files changed, 5702 insertions(+), 6425 deletions(-) delete mode 100644 src/SketchSolver/SketchSolver_ConstraintFillet.cpp delete mode 100644 src/SketchSolver/SketchSolver_ConstraintFillet.h create mode 100644 src/SketchSolver/SketchSolver_ConstraintFixed.cpp create mode 100644 src/SketchSolver/SketchSolver_ConstraintFixed.h delete mode 100644 src/SketchSolver/SketchSolver_ConstraintParametric.cpp delete mode 100644 src/SketchSolver/SketchSolver_ConstraintParametric.h delete mode 100644 src/SketchSolver/SketchSolver_ConstraintRigid.cpp delete mode 100644 src/SketchSolver/SketchSolver_ConstraintRigid.h delete mode 100644 src/SketchSolver/SketchSolver_FeatureStorage.cpp delete mode 100644 src/SketchSolver/SketchSolver_FeatureStorage.h create mode 100644 src/SketchSolver/SketchSolver_IConstraintWrapper.h create mode 100644 src/SketchSolver/SketchSolver_IEntityWrapper.h create mode 100644 src/SketchSolver/SketchSolver_IParameterWrapper.h create mode 100644 src/SketchSolver/SketchSolver_ISolver.h rename src/SketchSolver/{SketchSolver_ConstraintManager.cpp => SketchSolver_Manager.cpp} (88%) rename src/SketchSolver/{SketchSolver_ConstraintManager.h => SketchSolver_Manager.h} (76%) create mode 100644 src/SketchSolver/SolveSpaceSolver/CMakeLists.txt create mode 100644 src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.cpp create mode 100644 src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.h create mode 100644 src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintType.h create mode 100644 src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintWrapper.cpp create mode 100644 src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintWrapper.h create mode 100644 src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_EntityWrapper.cpp create mode 100644 src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_EntityWrapper.h create mode 100644 src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ParameterWrapper.cpp create mode 100644 src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ParameterWrapper.h rename src/SketchSolver/{SketchSolver_Solver.cpp => SolveSpaceSolver/SolveSpaceSolver_Solver.cpp} (63%) rename src/SketchSolver/{SketchSolver_Solver.h => SolveSpaceSolver/SolveSpaceSolver_Solver.h} (63%) create mode 100644 src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Storage.cpp create mode 100644 src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Storage.h diff --git a/src/Config/plugins.xml b/src/Config/plugins.xml index a8b4b2315..45903311b 100644 --- a/src/Config/plugins.xml +++ b/src/Config/plugins.xml @@ -12,7 +12,7 @@ - + diff --git a/src/SketchPlugin/Test/TestConstraintRigid.py b/src/SketchPlugin/Test/TestConstraintRigid.py index 6a3a352c9..b40ffcd42 100644 --- a/src/SketchPlugin/Test/TestConstraintRigid.py +++ b/src/SketchPlugin/Test/TestConstraintRigid.py @@ -112,7 +112,20 @@ assert (kLineBEnd == (aLineBEndPoint.x(), aLineBEndPoint.y())) assert (kLineCStart == (aLineCStartPoint.x(), aLineCStartPoint.y())) assert (kLineCEnd == (aLineCEndPoint.x(), aLineCEndPoint.y())) #========================================================================= -# Check that +# Check that moving line A does not affect lines +#========================================================================= +aSession.startOperation() +aLineAEndPoint.setValue(90., 0.) +aSession.finishOperation() +# Check that constarint keep features' values +assert (kLineAStart == (aLineAStartPoint.x(), aLineAStartPoint.y())) +assert (kLineAEnd == (aLineAEndPoint.x(), aLineAEndPoint.y())) +assert (kLineBStart == (aLineBStartPoint.x(), aLineBStartPoint.y())) +assert (kLineBEnd == (aLineBEndPoint.x(), aLineBEndPoint.y())) +assert (kLineCStart == (aLineCStartPoint.x(), aLineCStartPoint.y())) +assert (kLineCEnd == (aLineCEndPoint.x(), aLineCEndPoint.y())) +#========================================================================= +# Check that moving line B does not affect lines #========================================================================= aSession.startOperation() aLineBEndPoint.setValue(90., 150.) diff --git a/src/SketchSolver/CMakeLists.txt b/src/SketchSolver/CMakeLists.txt index 126fb212e..89ddc5710 100644 --- a/src/SketchSolver/CMakeLists.txt +++ b/src/SketchSolver/CMakeLists.txt @@ -1,60 +1,54 @@ ## Copyright (C) 2014-20xx CEA/DEN, EDF R&D INCLUDE(Common) -FIND_PACKAGE(SolveSpace REQUIRED) SET(PROJECT_HEADERS SketchSolver.h SketchSolver_Error.h - SketchSolver_Solver.h SketchSolver_Constraint.h SketchSolver_ConstraintAngle.h SketchSolver_ConstraintCoincidence.h SketchSolver_ConstraintDistance.h SketchSolver_ConstraintEqual.h - SketchSolver_ConstraintFillet.h SketchSolver_ConstraintLength.h SketchSolver_ConstraintMirror.h - SketchSolver_ConstraintRigid.h + SketchSolver_ConstraintFixed.h SketchSolver_ConstraintTangent.h SketchSolver_ConstraintMulti.h SketchSolver_ConstraintMultiRotation.h SketchSolver_ConstraintMultiTranslation.h SketchSolver_ConstraintMovement.h - SketchSolver_ConstraintParametric.h - SketchSolver_Builder.h SketchSolver_Group.h - SketchSolver_ConstraintManager.h + SketchSolver_Builder.h + SketchSolver_IConstraintWrapper.h + SketchSolver_IEntityWrapper.h + SketchSolver_IParameterWrapper.h + SketchSolver_ISolver.h + SketchSolver_Manager.h SketchSolver_Storage.h - SketchSolver_FeatureStorage.h ) SET(PROJECT_SOURCES - SketchSolver_Solver.cpp SketchSolver_Constraint.cpp SketchSolver_ConstraintAngle.cpp SketchSolver_ConstraintCoincidence.cpp SketchSolver_ConstraintDistance.cpp SketchSolver_ConstraintEqual.cpp - SketchSolver_ConstraintFillet.cpp SketchSolver_ConstraintLength.cpp SketchSolver_ConstraintMirror.cpp - SketchSolver_ConstraintRigid.cpp + SketchSolver_ConstraintFixed.cpp SketchSolver_ConstraintTangent.cpp SketchSolver_ConstraintMulti.cpp SketchSolver_ConstraintMultiRotation.cpp SketchSolver_ConstraintMultiTranslation.cpp - SketchSolver_ConstraintParametric.cpp SketchSolver_ConstraintMovement.cpp - SketchSolver_Builder.cpp SketchSolver_Group.cpp - SketchSolver_ConstraintManager.cpp + SketchSolver_Builder.cpp + SketchSolver_Manager.cpp SketchSolver_Storage.cpp - SketchSolver_FeatureStorage.cpp ) SET(PROJECT_LIBRARIES - ${SOLVESPACE_LIBRARIES} Config Events ModelAPI @@ -62,7 +56,6 @@ SET(PROJECT_LIBRARIES ) INCLUDE_DIRECTORIES( - ${SOLVESPACE_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/src/Config ${PROJECT_SOURCE_DIR}/src/SketchPlugin ${PROJECT_SOURCE_DIR}/src/ModelAPI @@ -73,10 +66,30 @@ INCLUDE_DIRECTORIES( ADD_DEFINITIONS(-DSKETCHSOLVER_EXPORTS) -ADD_LIBRARY(SketchSolver MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS} +ADD_LIBRARY(SketchSolver SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS} ) TARGET_LINK_LIBRARIES(SketchSolver ${PROJECT_LIBRARIES} ) INSTALL(TARGETS SketchSolver DESTINATION plugins) + + +# Include specific solvers +FIND_FILE(SSPath "SolveSpaceSolver/CMakeLists.txt" PATHS "${CMAKE_CURRENT_SOURCE_DIR}") +STRING(COMPARE NOTEQUAL ${SSPath} "SSPath-NOTFOUND" SSPath_FOUND) +FIND_FILE(GCSPath "PlainGCSSolver/CMakeLists.txt" PATHS "${CMAKE_CURRENT_SOURCE_DIR}") +STRING(COMPARE NOTEQUAL ${GCSPath} "GCSPath-NOTFOUND" GCSPath_FOUND) + +IF(${SSPath_FOUND} OR ${GCSPath_FOUND}) + IF(${SSPath_FOUND}) + MESSAGE(STATUS "SolveSpaceSolver plugin found in ${SSPath}") + ADD_SUBDIRECTORY(SolveSpaceSolver) + ENDIF() + IF(${GCSPath_FOUND}) + MESSAGE(STATUS "PlainGCSSolver plugin found in ${GCSPath}") + ADD_SUBDIRECTORY(PlainGCSSolver) + ENDIF() +ELSE() + MESSAGE(WARNING "No sketch solver plugin is found") +ENDIF() diff --git a/src/SketchSolver/SketchSolver.h b/src/SketchSolver/SketchSolver.h index cc5013f6e..56fa1dba2 100644 --- a/src/SketchSolver/SketchSolver.h +++ b/src/SketchSolver/SketchSolver.h @@ -3,6 +3,8 @@ #ifndef SKETCHSOLVER_H #define SKETCHSOLVER_H +#include + #if defined SKETCHSOLVER_EXPORTS #if defined WIN32 #define SKETCHSOLVER_EXPORT __declspec( dllexport ) @@ -22,4 +24,18 @@ const double tolerance = 1.e-10; #define PI 3.1415926535897932 +// Types for data entities enumeration +typedef size_t GroupID; +typedef size_t ParameterID; +typedef size_t EntityID; +typedef size_t ConstraintID; + +// Predefined values for identifiers +const GroupID GID_UNKNOWN = 0; +const GroupID GID_OUTOFGROUP = 1; + +const ParameterID PID_UNKNOWN = 0; +const EntityID EID_UNKNOWN = 0; +const ConstraintID CID_UNKNOWN = 0; + #endif diff --git a/src/SketchSolver/SketchSolver_Builder.cpp b/src/SketchSolver/SketchSolver_Builder.cpp index 78bfc59bb..c01e8817a 100644 --- a/src/SketchSolver/SketchSolver_Builder.cpp +++ b/src/SketchSolver/SketchSolver_Builder.cpp @@ -5,66 +5,40 @@ // Author: Artem ZHIDKOV #include "SketchSolver_Builder.h" -#include +#include #include #include #include #include -#include +#include #include #include -#include #include #include #include #include -#include -#include -#include -#include -#include -#include +#ifdef _DEBUG #include -#include -#include -#include #include #include +#include +#endif -#include -#include -#include -#include +#include #include #include #include -#include -#include #include #include -#include -#include -#include #include #include -#include #include #include #include -// Initialization of constraint builder self pointer -SketchSolver_Builder* SketchSolver_Builder::mySelf = 0; - -SketchSolver_Builder* SketchSolver_Builder::getInstance() -{ - if (!mySelf) - mySelf = new SketchSolver_Builder(); - return mySelf; -} - -SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theConstraint) +SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theConstraint) const { SolverConstraintPtr aResult; DataPtr aData = theConstraint->data(); @@ -106,26 +80,14 @@ SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theCons return SolverConstraintPtr(new SketchSolver_ConstraintDistance(theConstraint)); } else if (theConstraint->getKind() == SketchPlugin_ConstraintEqual::ID()) { return SolverConstraintPtr(new SketchSolver_ConstraintEqual(theConstraint)); - } else if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) { - return SolverConstraintPtr(new SketchSolver_ConstraintFillet(theConstraint)); - } 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)); } else if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) { return SolverConstraintPtr(new SketchSolver_ConstraintMirror(theConstraint)); - } else if (theConstraint->getKind() == SketchPlugin_ConstraintParallel::ID()) { - return SolverConstraintPtr(new SketchSolver_ConstraintParallel(theConstraint)); - } else if (theConstraint->getKind() == SketchPlugin_ConstraintPerpendicular::ID()) { - return SolverConstraintPtr(new SketchSolver_ConstraintPerpendicular(theConstraint)); - } else if (theConstraint->getKind() == SketchPlugin_ConstraintRadius::ID()) { - return SolverConstraintPtr(new SketchSolver_ConstraintRadius(theConstraint)); } else if (theConstraint->getKind() == SketchPlugin_ConstraintTangent::ID()) { return SolverConstraintPtr(new SketchSolver_ConstraintTangent(theConstraint)); - } else if (theConstraint->getKind() == SketchPlugin_ConstraintVertical::ID()) { - return SolverConstraintPtr(new SketchSolver_ConstraintVertical(theConstraint)); } else if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID()) { - return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theConstraint)); + return SolverConstraintPtr(new SketchSolver_ConstraintFixed(theConstraint)); } else if (theConstraint->getKind() == SketchPlugin_MultiTranslation::ID()) { return SolverConstraintPtr(new SketchSolver_ConstraintMultiTranslation(theConstraint)); } else if (theConstraint->getKind() == SketchPlugin_MultiRotation::ID()) { @@ -133,18 +95,19 @@ SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theCons } else if (theConstraint->getKind() == SketchPlugin_ConstraintAngle::ID()) { return SolverConstraintPtr(new SketchSolver_ConstraintAngle(theConstraint)); } - return aResult; + // All other types of constraints + return SolverConstraintPtr(new SketchSolver_Constraint(theConstraint)); } -SolverConstraintPtr SketchSolver_Builder::createRigidConstraint(FeaturePtr theFixedFeature) +SolverConstraintPtr SketchSolver_Builder::createFixedConstraint(FeaturePtr theFixedFeature) const { DataPtr aData = theFixedFeature->data(); if (!aData || !aData->isValid()) return SolverConstraintPtr(); - return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theFixedFeature)); + return SolverConstraintPtr(new SketchSolver_ConstraintFixed(theFixedFeature)); } -SolverConstraintPtr SketchSolver_Builder::createMovementConstraint(FeaturePtr theFixedFeature) +SolverConstraintPtr SketchSolver_Builder::createMovementConstraint(FeaturePtr theFixedFeature) const { DataPtr aData = theFixedFeature->data(); if (!aData || !aData->isValid()) @@ -152,185 +115,35 @@ SolverConstraintPtr SketchSolver_Builder::createMovementConstraint(FeaturePtr th return SolverConstraintPtr(new SketchSolver_ConstraintMovement(theFixedFeature)); } -SolverConstraintPtr SketchSolver_Builder::createParametricConstraint(AttributePtr theAttribute) +std::shared_ptr SketchSolver_Builder::point(EntityWrapperPtr theEntity) const { - return SolverConstraintPtr(new SketchSolver_ConstraintParametric(theAttribute)); + if (theEntity->type() != ENTITY_POINT) + return std::shared_ptr(); + + double aXY[2]; + std::list aParams = theEntity->parameters(); + std::list::const_iterator anIt = aParams.begin(); + for (int i = 0; i < 2 && anIt != aParams.end(); ++i, ++anIt) + aXY[i] = (*anIt)->value(); + if (anIt != aParams.end()) + return std::shared_ptr(); + + return std::shared_ptr(new GeomAPI_Pnt2d(aXY[0], aXY[1])); } - - -bool SketchSolver_Builder::createWorkplane( - CompositeFeaturePtr theSketch, - std::vector& theEntities, - std::vector& theParameters) +std::shared_ptr SketchSolver_Builder::line(EntityWrapperPtr theEntity) const { - DataPtr aSketchData = theSketch->data(); - if (!aSketchData || !aSketchData->isValid()) - return false; // the sketch is incorrect - - // Get parameters of workplane - std::shared_ptr aDirX = aSketchData->attribute( - SketchPlugin_Sketch::DIRX_ID()); - std::shared_ptr aNorm = aSketchData->attribute( - SketchPlugin_Sketch::NORM_ID()); - std::shared_ptr anOrigin = aSketchData->attribute( - SketchPlugin_Sketch::ORIGIN_ID()); - // Create SolveSpace entity corresponding to the sketch origin - if (!createEntity(anOrigin, theEntities, theParameters)) - return false; - Slvs_hEntity anOriginID = theEntities.back().h; - // Create SolveSpace entity corresponding the the sketch normal - if (!createNormal(aNorm, aDirX, theEntities, theParameters)) - return false; - Slvs_hEntity aNormalID = theEntities.back().h; - - // Create workplane - Slvs_hEntity aWorkplaneID = theEntities.back().h + 1; - Slvs_Entity aWorkplane = Slvs_MakeWorkplane(aWorkplaneID, SLVS_G_UNKNOWN, anOriginID, aNormalID); - theEntities.push_back(aWorkplane); - return true; + if (theEntity->type() != ENTITY_LINE) + return std::shared_ptr(); + + std::shared_ptr aPoints[2]; + std::list aSubs = theEntity->subEntities(); + std::list::const_iterator anIt = aSubs.begin(); + for (int i = 0; i < 2 && anIt != aSubs.end(); ++i, ++anIt) + aPoints[i] = point(*anIt); + if (anIt != aSubs.end()) + return std::shared_ptr(); + + return std::shared_ptr(new GeomAPI_Lin2d(aPoints[0], aPoints[1])); } -bool SketchSolver_Builder::createEntity( - AttributePtr theAttribute, - std::vector& theEntities, - std::vector& theParameters) -{ - Slvs_hEntity anEntID = theEntities.empty() ? 0 : theEntities.back().h; - Slvs_hParam aParamID = theParameters.empty() ? 0 : theParameters.back().h; - - // Point in 3D - std::shared_ptr aPoint = - std::dynamic_pointer_cast(theAttribute); - if (aPoint) { - theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->x())); - theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->y())); - theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->z())); - theEntities.push_back(Slvs_MakePoint3d(++anEntID, SLVS_G_UNKNOWN, - aParamID-2, aParamID-1, aParamID)); - return true; - } - // Point in 2D - std::shared_ptr aPoint2D = - std::dynamic_pointer_cast(theAttribute); - if (aPoint2D) { - theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint2D->x())); - theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint2D->y())); - theEntities.push_back(Slvs_MakePoint2d(++anEntID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN, - aParamID-1, aParamID)); - return true; - } - // Scalar value (used for the distance entities) - AttributeDoublePtr aScalar = std::dynamic_pointer_cast(theAttribute); - if (aScalar) { - theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aScalar->value())); - theEntities.push_back(Slvs_MakeDistance(++anEntID, SLVS_G_UNKNOWN, - SLVS_E_UNKNOWN, aParamID)); - return true; - } - // unknown attribute type - return false; -} - -bool SketchSolver_Builder::createEntity( - FeaturePtr theFeature, - std::vector& theEntities, - std::vector& theParameters) -{ - if (!theFeature->data()->isValid()) - return false; - - // SketchPlugin features - std::shared_ptr aFeature = std::dynamic_pointer_cast< - SketchPlugin_Feature>(theFeature); - if (!aFeature) - return false; - - // Verify the feature by its kind - const std::string& aFeatureKind = aFeature->getKind(); - DataPtr aData = aFeature->data(); - // Line - if (aFeatureKind == SketchPlugin_Line::ID()) { - AttributePtr aStart = aData->attribute(SketchPlugin_Line::START_ID()); - AttributePtr aEnd = aData->attribute(SketchPlugin_Line::END_ID()); - if (!aStart->isInitialized() || !aEnd->isInitialized()) - return false; - if (!createEntity(aStart, theEntities, theParameters) || - !createEntity(aEnd, theEntities, theParameters)) - return false; - Slvs_hEntity aLineID = theEntities.back().h + 1; - theEntities.push_back(Slvs_MakeLineSegment(aLineID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN, - aLineID-2, aLineID-1)); - } - // Circle - else if (aFeatureKind == SketchPlugin_Circle::ID()) { - AttributePtr aCenter = aData->attribute(SketchPlugin_Circle::CENTER_ID()); - AttributePtr aRadius = aData->attribute(SketchPlugin_Circle::RADIUS_ID()); - if (!aCenter->isInitialized() || !aRadius->isInitialized()) - return false; - if (!createEntity(aCenter, theEntities, theParameters) || - !createEntity(aRadius, theEntities, theParameters)) - return false; - Slvs_hEntity aCircID = theEntities.back().h; - theEntities.push_back(Slvs_MakeCircle(aCircID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN, aCircID-2, - SLVS_E_UNKNOWN, aCircID-1)); - } - // Arc - else if (aFeatureKind == SketchPlugin_Arc::ID()) { - AttributePtr aCenter = aData->attribute(SketchPlugin_Arc::CENTER_ID()); - AttributePtr aStart = aData->attribute(SketchPlugin_Arc::START_ID()); - AttributePtr aEnd = aData->attribute(SketchPlugin_Arc::END_ID()); - if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized()) - return false; - if (!createEntity(aCenter, theEntities, theParameters) || - !createEntity(aStart, theEntities, theParameters) || - !createEntity(aEnd, theEntities, theParameters)) - return false; - Slvs_hEntity anArcID = theEntities.back().h; - theEntities.push_back(Slvs_MakeArcOfCircle(anArcID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN, - SLVS_E_UNKNOWN, anArcID-3, anArcID-2, anArcID-1)); - } - // Point (it has low probability to be an attribute of constraint, so it is checked at the end) - else if (aFeatureKind == SketchPlugin_Point::ID()) { - AttributePtr aPoint = aData->attribute(SketchPlugin_Point::COORD_ID()); - if (!aPoint->isInitialized() || - !createEntity(aPoint, theEntities, theParameters)) - return false; - // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier. - // No need to add another entity. - } - return true; -} - -bool SketchSolver_Builder::createNormal( - AttributePtr theNormal, - AttributePtr theDirX, - std::vector& theEntities, - std::vector& theParameters) -{ - std::shared_ptr aNorm = std::dynamic_pointer_cast(theNormal); - std::shared_ptr aDirX = std::dynamic_pointer_cast(theDirX); - if (!aDirX || (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) || - !aNorm->isInitialized()) - return false; - // calculate Y direction - std::shared_ptr aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir()))); - - // quaternion parameters of normal vector - double qw, qx, qy, qz; - Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw, - &qx, &qy, &qz); - double aNormCoord[4] = { qw, qx, qy, qz }; - - // Create parameters of the normal - Slvs_hParam aCurParam = theParameters.back().h; - for (int i = 0; i < 4; i++) - theParameters.push_back(Slvs_MakeParam(++aCurParam, SLVS_G_UNKNOWN, aNormCoord[i])); - - // Create a normal - Slvs_hEntity aCurEntity = theEntities.back().h + 1; - Slvs_Entity aNormal = Slvs_MakeNormal3d(aCurEntity, SLVS_G_UNKNOWN, - aCurParam-3, aCurParam-2, aCurParam-1, aCurParam); - theEntities.push_back(aNormal); - return true; -} diff --git a/src/SketchSolver/SketchSolver_Builder.h b/src/SketchSolver/SketchSolver_Builder.h index 21beac319..3da7e2fd7 100644 --- a/src/SketchSolver/SketchSolver_Builder.h +++ b/src/SketchSolver/SketchSolver_Builder.h @@ -7,74 +7,109 @@ #ifndef SketchSolver_Builder_H_ #define SketchSolver_Builder_H_ -#include "SketchSolver.h" #include - #include -#include +#include +#include /** \class SketchSolver_Builder * \ingroup Plugins - * \brief Create bridges between SketchPlugin constraints and SolveSpace constraints + * \brief Abstract class for builders of solver's entities */ class SketchSolver_Builder { -private: - /// Default constructor - SketchSolver_Builder() {} - public: - /// \brief Returns single instance of builder - static SketchSolver_Builder* getInstance(); + /// \brief Creates a storage specific for used solver + virtual StoragePtr createStorage(const GroupID& theGroup) const = 0; + /// \brief Creates specific solver + virtual SolverPtr createSolver() const = 0; /// \brief Creates a solver's constraint using given SketchPlugin constraint /// or returns empty pointer if not all attributes are correct - SolverConstraintPtr createConstraint(ConstraintPtr theConstraint); + SolverConstraintPtr createConstraint(ConstraintPtr theConstraint) const; /// \brief Creates temporary constraint to fix the placement of the feature - SolverConstraintPtr createRigidConstraint(FeaturePtr theFixedFeature); + SolverConstraintPtr createFixedConstraint(FeaturePtr theFixedFeature) const; /// \brief Creates temporary constraint to fix the feature after movement - SolverConstraintPtr createMovementConstraint(FeaturePtr theFixedFeature); - - /// \brief Creates constraint for parametrically given attribute - SolverConstraintPtr createParametricConstraint(AttributePtr theAttribute); - - /// \brief Converts sketch parameters to the list of SolveSpace entities. - /// Identifiers of entities and parameters are local. They should be changed while adding into storage. - /// The sketch entity goes last. - /// \param[in] theSketch the element to be converted - /// \param[out] theEntities created list of entities - /// \param[out] theParameters created list of parameters of the entities - /// \return \c true if workplane created - bool createWorkplane(CompositeFeaturePtr theSketch, - std::vector& theEntities, - std::vector& theParameters); - - /// \brief Converts attribute to the list of entities. - /// Identifiers are local (see createWorkplane). - /// The main entity goes last. - bool createEntity(AttributePtr theAttribute, - std::vector& theEntities, - std::vector& theParameters); - /// \brief Converts feature to the list of entities. - /// Identifiers are local (see createWorkplane). - /// The main entity goes last. - bool createEntity(FeaturePtr theFeature, - std::vector& theEntities, - std::vector& theParameters); - - /// \brief Converts normal and OX direction to the list of entities representing a normal in SolveSpace. - /// Identifiers are local (see createWorkplane). - /// The main entity goes last. - bool createNormal(AttributePtr theNormal, - AttributePtr theDirX, - std::vector& theEntities, - std::vector& theParameters); - -private: - static SketchSolver_Builder* mySelf; + SolverConstraintPtr createMovementConstraint(FeaturePtr theFixedFeature) const; + + /// \brief Creates new constraint(s) using given parameters + /// \param theConstraint [in] original constraint + /// \param theGroupID [in] group the constraint belongs to + /// \param theSketchID [in] sketch the constraint belongs to + /// \param theType [in] type of constraint + /// \param theValue [in] numeric characteristic of constraint (e.g. distance or radius) if applicable + /// \param theEntity1 [in] first attribute of constraint + /// \param theEntity2 [in] second attribute of constraint + /// \param theEntity3 [in] third attribute of constraint + /// \param theEntity4 [in] fourth attribute of constraint + /// \return Created list of wrappers of constraints applicable for specific solver. + /// Most of constraint types lead to single constraint, but there are some kind of + /// constraints (e.g. mirror), which may produce couple of constraints. + virtual std::list + createConstraint(ConstraintPtr theConstraint, + const GroupID& theGroup, + const EntityID& theSketchID, + const SketchSolver_ConstraintType& theType, + const double& theValue, + const EntityWrapperPtr& theEntity1, + const EntityWrapperPtr& theEntity2 = EntityWrapperPtr(), + const EntityWrapperPtr& theEntity3 = EntityWrapperPtr(), + const EntityWrapperPtr& theEntity4 = EntityWrapperPtr()) const = 0; + + /// \brief Creates new multi-translation or multi-rotation constraint + /// \param theConstraint [in] original constraint + /// \param theGroupID [in] group the constraint belongs to + /// \param theSketchID [in] sketch the constraint belongs to + /// \param theType [in] type of constraint + /// \param theValue [in] numeric characteristic of constraint (angle for multi-rotation) if applicable + /// \param thePoint1 [in] center for multi-rotation or start point for multi-translation + /// \param thePoint2 [in] end point for multi-translation (empty for multi-rotation) + /// \param theTrsfEnt [in] list of transformed entities + virtual std::list + createConstraint(ConstraintPtr theConstraint, + const GroupID& theGroup, + const EntityID& theSketchID, + const SketchSolver_ConstraintType& theType, + const double& theValue, + const EntityWrapperPtr& thePoint1, + const EntityWrapperPtr& thePoint2, + const std::list& theTrsfEnt) const = 0; + + /// \brief Update flags for several kinds of constraints + virtual void adjustConstraint(ConstraintWrapperPtr theConstraint) const = 0; + + /// \brief Creates a feature using list of already created attributes + /// \param theFeature [in] feature to create + /// \param theAttributes [in] attributes of the feature + /// \param theGroupID [in] group the feature belongs to + /// \param theSketchID [in] sketch the feature belongs to + /// \return Created wrapper of the feature applicable for specific solver + virtual EntityWrapperPtr createFeature(FeaturePtr theFeature, + const std::list& theAttributes, + const GroupID& theGroupID, + const EntityID& theSketchID = EID_UNKNOWN) const = 0; + + /// \brief Creates an attribute + /// \param theAttribute [in] attribute to create + /// \param theGroup [in] group the attribute belongs to + /// \param theSketchID [in] sketch the attribute belongs to + /// \return Created wrapper of the attribute applicable for specific solver + virtual EntityWrapperPtr createAttribute(AttributePtr theAttribute, + const GroupID& theGroup, + const EntityID& theSketchID = EID_UNKNOWN) const = 0; + + + /// \brief Convert entity to point + /// \return empty pointer if the entity is not a point + SKETCHSOLVER_EXPORT std::shared_ptr point(EntityWrapperPtr theEntity) const; + /// \brief Convert entity to line + /// \return empty pointer if the entity is not a line + SKETCHSOLVER_EXPORT std::shared_ptr line(EntityWrapperPtr theEntity) const; }; +typedef std::shared_ptr BuilderPtr; + #endif diff --git a/src/SketchSolver/SketchSolver_Constraint.cpp b/src/SketchSolver/SketchSolver_Constraint.cpp index b4b888fa3..e5a2b695b 100644 --- a/src/SketchSolver/SketchSolver_Constraint.cpp +++ b/src/SketchSolver/SketchSolver_Constraint.cpp @@ -1,12 +1,27 @@ #include #include #include +#include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include #include #include @@ -18,303 +33,126 @@ SketchSolver_Constraint::SketchSolver_Constraint( ConstraintPtr theConstraint) : myBaseConstraint(theConstraint), - myGroup(0) -{ -} - -SketchSolver_Constraint::~SketchSolver_Constraint() + myGroupID(GID_UNKNOWN), + myType(CONSTRAINT_UNKNOWN) { - std::map::const_iterator anIt1 = myValueMap.begin(); - for (; anIt1 != myValueMap.end(); anIt1++) - myStorage->removeParameter(anIt1->second); - myValueMap.clear(); - - std::map::const_iterator anIt2 = myAttributeMap.begin(); - for (; anIt2 != myAttributeMap.end(); anIt2++) - myStorage->removeEntity(anIt2->second); - myAttributeMap.clear(); - - std::map::iterator anIt3 = myFeatureMap.begin(); - while (!myFeatureMap.empty()) { - std::shared_ptr aFeature = - std::dynamic_pointer_cast(anIt3->first); - Slvs_hEntity anEnt = anIt3->second; - std::map::iterator aRemIt = anIt3++; - myFeatureMap.erase(aRemIt); - if (!myGroup->isInteract(aFeature)) - myStorage->removeEntity(anEnt); - } - - std::vector::const_iterator anIt4 = mySlvsConstraints.begin(); - for (; anIt4 != mySlvsConstraints.end(); anIt4++) - myStorage->removeConstraint(*anIt4); - mySlvsConstraints.clear(); } -void SketchSolver_Constraint::setStorage(StoragePtr theStorage) +void SketchSolver_Constraint::process(StoragePtr theStorage, + const GroupID& theGroupID, + const EntityID& theSketchID) { myStorage = theStorage; + myGroupID = theGroupID; + mySketchID = theSketchID; + // Process constraint according to its type process(); } -void SketchSolver_Constraint::setGroup(SketchSolver_Group* theGroup) -{ - myGroup = theGroup; - process(); -} -void SketchSolver_Constraint::addFeature(FeaturePtr theFeature) -{ - int aType; - changeEntity(theFeature, aType); +SketchSolver_ConstraintType SketchSolver_Constraint::TYPE(ConstraintPtr theConstraint) +{ + const std::string& aType = theConstraint->getKind(); + if (aType == SketchPlugin_ConstraintCoincidence::ID()) + return CONSTRAINT_COINCIDENCE; + else if (aType == SketchPlugin_ConstraintRigid::ID()) + return CONSTRAINT_FIXED; + else if (aType == SketchPlugin_ConstraintHorizontal::ID()) + return CONSTRAINT_HORIZONTAL; + else if (aType == SketchPlugin_ConstraintVertical::ID()) + return CONSTRAINT_VERTICAL; + else if (aType == SketchPlugin_ConstraintAngle::ID()) + return CONSTRAINT_ANGLE; + else if (aType == SketchPlugin_ConstraintDistance::ID()) + return CONSTRAINT_DISTANCE; + else if (aType == SketchPlugin_ConstraintEqual::ID()) + return CONSTRAINT_EQUAL; + else if (aType == SketchPlugin_ConstraintLength::ID()) + return CONSTRAINT_PT_PT_DISTANCE; + else if (aType == SketchPlugin_ConstraintMirror::ID()) + return CONSTRAINT_SYMMETRIC; + else if (aType == SketchPlugin_ConstraintParallel::ID()) + return CONSTRAINT_PARALLEL; + else if (aType == SketchPlugin_ConstraintPerpendicular::ID()) + return CONSTRAINT_PERPENDICULAR; + else if (aType == SketchPlugin_ConstraintRadius::ID()) + return CONSTRAINT_RADIUS; + else if (aType == SketchPlugin_ConstraintTangent::ID()) + return CONSTRAINT_TANGENT; + return CONSTRAINT_UNKNOWN; } - void SketchSolver_Constraint::process() { cleanErrorMsg(); - if (!myBaseConstraint || !myStorage || myGroup == 0) { - /// TODO: Put error message here + if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) { + // Not enough parameters are assigned return; } - if (!mySlvsConstraints.empty()) // some data is changed, update constraint - update(myBaseConstraint); - int aConstrType = getType(); - double aValue = 0.0; - std::vector anAttributes; + SketchSolver_ConstraintType aConstrType = getType(); + double aValue; + std::vector anAttributes; getAttributes(aValue, anAttributes); if (!myErrorMsg.empty()) return; - if (aConstrType == SLVS_C_UNKNOWN) + if (anAttributes.empty()) { + myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); + return; + } + if (aConstrType == CONSTRAINT_UNKNOWN) aConstrType = getType(); - Slvs_hGroup aGroupID = myGroup->getId(); - Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId(); - Slvs_Constraint aConstraint; - if (mySlvsConstraints.empty()) - aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, aGroupID, aConstrType, aWorkplaneID, - aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]); - else { - aConstraint = myStorage->getConstraint(mySlvsConstraints[0]); - aConstraint.valA = aValue; - static const int aNbAttrs = 6; - Slvs_hEntity* aConstrAttrs[aNbAttrs] = { - &aConstraint.ptA, &aConstraint.ptB, - &aConstraint.entityA, &aConstraint.entityB, - &aConstraint.entityC, &aConstraint.entityD}; - std::vector::const_iterator anIter = anAttributes.begin(); - for (int i = 0; i < aNbAttrs && anIter != anAttributes.end(); i++, anIter++) - *(aConstrAttrs[i]) = *anIter; - } + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + std::list aNewConstraints = aBuilder->createConstraint( + myBaseConstraint, myGroupID, mySketchID, aConstrType, + aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]); + myStorage->addConstraint(myBaseConstraint, aNewConstraints); - Slvs_hConstraint anID = myStorage->addConstraint(aConstraint); - if (mySlvsConstraints.empty()) - mySlvsConstraints.push_back(anID); - else - mySlvsConstraints[0] = anID; adjustConstraint(); } -bool SketchSolver_Constraint::checkAttributesChanged(ConstraintPtr theConstraint) -{ - std::set aCurAttrs; // list of currently used attributes - std::vector::const_iterator aConstrIter = mySlvsConstraints.begin(); - for (; aConstrIter != mySlvsConstraints.end(); aConstrIter++) { - Slvs_Constraint aConstr = myStorage->getConstraint(*aConstrIter); - if (aConstr.ptA != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.ptA); - if (aConstr.ptB != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.ptB); - if (aConstr.entityA != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityA); - if (aConstr.entityB != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityB); - if (aConstr.entityC != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityC); - if (aConstr.entityD != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityD); - } - // Check the attrbutes of constraint are changed - ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint; - std::list anAttrList = aConstraint->data()->attributes(std::string()); - std::list::iterator anAttrIter = anAttrList.begin(); - for (; anAttrIter != anAttrList.end(); anAttrIter++) { - AttributeRefAttrPtr aRefAttr = - std::dynamic_pointer_cast(*anAttrIter); - if (aRefAttr) { - if (aRefAttr->isObject()) { - FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); - std::map::iterator aFIt = myFeatureMap.find(aFeature); - if (aFeature) { - if (aFIt == myFeatureMap.end()) - return true; - // Additional check the points of entity - if (aCurAttrs.find(aFIt->second) == aCurAttrs.end()) { - Slvs_Entity anEntity = myStorage->getEntity(aFIt->second); - bool isFound = false; - for (int i = 0; i < 4 && !isFound; i++) - if (anEntity.point[i] != SLVS_E_UNKNOWN && - aCurAttrs.find(anEntity.point[i]) != aCurAttrs.end()) - isFound = true; - if (!isFound) - return true; - } - } - } else if (aRefAttr->attr()) { - std::map::iterator anAIt = myAttributeMap.find(aRefAttr->attr()); - if (anAIt == myAttributeMap.end() || aCurAttrs.find(anAIt->second) == aCurAttrs.end()) - return true; - } - } - AttributeRefListPtr aRefList = - std::dynamic_pointer_cast(*anAttrIter); - if (aRefList) { - std::list anItems = aRefList->list(); - std::list::iterator anIt = anItems.begin(); - for (; anIt != anItems.end(); anIt++) { - FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt); - if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end()) - return true; - } - } - } - return false; -} - -void SketchSolver_Constraint::update(ConstraintPtr theConstraint) +void SketchSolver_Constraint::update() { cleanErrorMsg(); - bool needToRebuild = (theConstraint && theConstraint != myBaseConstraint); - if (!needToRebuild) - needToRebuild = checkAttributesChanged(theConstraint); - if (needToRebuild) { - if (theConstraint && theConstraint->getKind() != myBaseConstraint->getKind()) - return; - remove(myBaseConstraint); - if (theConstraint) - myBaseConstraint = theConstraint; - process(); - return; - } - // Update all attributes - int aType; - std::map aRelocationMap; - std::map::iterator aFeatIter = myFeatureMap.begin(); - 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++) { - Slvs_hEntity aPrevID = anAttrIter->second; - anAttrIter->second = changeEntity(anAttrIter->first, aType); - if (anAttrIter->second != aPrevID) - aRelocationMap[aPrevID] = anAttrIter->second; - } - - // Value if exists - DataPtr aData = myBaseConstraint->data(); - if (!aData) return; + std::list aWrapper = myStorage->constraint(myBaseConstraint); AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast( - myBaseConstraint->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); - if (aValueAttr) { - aConstraint.valA = aValue; - if (aConstraint.type == SLVS_C_DIAMETER) - aConstraint.valA *= 2.0; - } - 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); + myBaseConstraint->attribute(SketchPlugin_Constraint::VALUE())); + if (aValueAttr) { + std::list::iterator aWIt = aWrapper.begin(); + for (; aWIt != aWrapper.end(); ++aWIt) + (*aWIt)->setValue(aValueAttr->value()); } + myStorage->addConstraint(myBaseConstraint, aWrapper); + adjustConstraint(); } -bool SketchSolver_Constraint::remove(ConstraintPtr theConstraint) +bool SketchSolver_Constraint::remove() { cleanErrorMsg(); - if (theConstraint && theConstraint != myBaseConstraint) - return false; - if (mySlvsConstraints.empty()) - return true; - bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints.front()); - if (isFullyRemoved) { - myFeatureMap.clear(); - myAttributeMap.clear(); - myValueMap.clear(); - } else - cleanRemovedEntities(); - mySlvsConstraints.clear(); - return true; -} - -void SketchSolver_Constraint::cleanRemovedEntities() -{ - std::set aRemovedParams; - std::set aRemovedEntities; - std::set aRemovedConstraints; - myStorage->getRemoved(aRemovedParams, aRemovedEntities, aRemovedConstraints); - std::map::iterator aFeatIt = myFeatureMap.begin(); - while (aFeatIt != myFeatureMap.end()) { - if (aRemovedEntities.find(aFeatIt->second) == aRemovedEntities.end()) { - aFeatIt++; - continue; - } - std::map::iterator aTmpIter = aFeatIt++; - myFeatureMap.erase(aTmpIter); - } - std::map::iterator anAttrIt = myAttributeMap.begin(); - while (anAttrIt != myAttributeMap.end()) { - if (aRemovedEntities.find(anAttrIt->second) == aRemovedEntities.end()) { - anAttrIt++; - continue; - } - std::map::iterator aTmpIter = anAttrIt++; - myAttributeMap.erase(aTmpIter); - } - std::map::iterator aValIt = myValueMap.begin(); - while (aValIt != myValueMap.end()) { - if (aRemovedParams.find(aValIt->second) == aRemovedParams.end()) { - aValIt++; - continue; - } - std::map::iterator aTmpIter = aValIt++; - myValueMap.erase(aTmpIter); - } - for (size_t i = 0; i < mySlvsConstraints.size(); i++) - if (aRemovedConstraints.find(mySlvsConstraints[i]) != aRemovedConstraints.end()) { - mySlvsConstraints.erase(mySlvsConstraints.begin() + i); - i--; - } + return myStorage->removeConstraint(myBaseConstraint); } void SketchSolver_Constraint::getAttributes( double& theValue, - std::vector& theAttributes) + std::vector& theAttributes) { static const int anInitNbOfAttr = 4; - theAttributes.assign(anInitNbOfAttr, SLVS_E_UNKNOWN); + theAttributes.assign(anInitNbOfAttr, EntityWrapperPtr()); DataPtr aData = myBaseConstraint->data(); + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + + myType = TYPE(myBaseConstraint); AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Constraint::VALUE())); + aData->attribute(SketchPlugin_Constraint::VALUE())); theValue = aValueAttr ? aValueAttr->value() : 0.0; int aPtInd = 0; // index of first point in the list of attributes - int aEntInd = 2; // index of first antity in the list of attributes + int aEntInd = 2; // index of first entity in the list of attributes std::list aConstrAttrs = aData->attributes(ModelAPI_AttributeRefAttr::typeId()); std::list::iterator anIter = aConstrAttrs.begin(); for (; anIter != aConstrAttrs.end(); anIter++) { @@ -325,18 +163,13 @@ void SketchSolver_Constraint::getAttributes( return; } - int aType = SLVS_E_UNKNOWN; // type of created entity - Slvs_hEntity anEntity = myGroup->getAttributeId(aRefAttr); - if (anEntity == SLVS_E_UNKNOWN) - anEntity = changeEntity(aRefAttr, aType); - else { - Slvs_Entity anEnt = myStorage->getEntity(anEntity); - aType = anEnt.type; - } + myStorage->update(*anIter, myGroupID); + EntityWrapperPtr anEntity = myStorage->entity(*anIter); - if (aType == SLVS_E_UNKNOWN) + SketchSolver_EntityType aType = anEntity->type(); + if (aType == ENTITY_UNKNOWN) continue; - else if (aType == SLVS_E_POINT_IN_2D || aType == SLVS_E_POINT_IN_3D) + else if (aType == ENTITY_POINT) theAttributes[aPtInd++] = anEntity; // the point is created else { // another entity (not a point) is created if (aEntInd < anInitNbOfAttr) @@ -348,403 +181,45 @@ void SketchSolver_Constraint::getAttributes( } } -Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributeRefAttrPtr theAttribute, int& theType) -{ - // Convert the object of the attribute to the feature - FeaturePtr aFeature; - if (theAttribute->isObject() && theAttribute->object()) { - ResultConstructionPtr aRC = std::dynamic_pointer_cast( - theAttribute->object()); - if (!aRC) { - myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); - return SLVS_E_UNKNOWN; - } - std::shared_ptr aDoc = aRC->document(); - aFeature = aDoc->feature(aRC); - - return changeEntity(aFeature, theType); - } - - return changeEntity(theAttribute->attr(), theType); -} - -Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributePtr theEntity, int& theType) +bool SketchSolver_Constraint::isUsed(FeaturePtr theFeature) const { - Slvs_hEntity aResult = SLVS_E_UNKNOWN; - if (!theEntity || !isInitialized(theEntity)) { - myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); - return SLVS_E_UNKNOWN; - } + const std::list& aCList = myStorage->constraint(myBaseConstraint); + std::list::const_iterator aCIt = aCList.begin(); + for (; aCIt != aCList.end(); ++aCIt) + if ((*aCIt)->isUsed(theFeature)) + return true; - // If the entity is already in the group, try to find it - std::map, Slvs_hEntity>::const_iterator anEntIter = - myAttributeMap.find(theEntity); - Slvs_Entity aCurrentEntity; - aCurrentEntity.h = SLVS_E_UNKNOWN; - if (anEntIter != myAttributeMap.end()) - aCurrentEntity = myStorage->getEntity(anEntIter->second); - else { - aResult = myGroup->getAttributeId(theEntity); - if (aResult != SLVS_E_UNKNOWN) { - Slvs_Entity anEnt = myStorage->getEntity(aResult); - theType = anEnt.type; - myAttributeMap[theEntity] = aResult; - return aResult; - } - } + std::list anAttrList = theFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); + std::list::const_iterator anAttrIt = anAttrList.begin(); + for (; anAttrIt != anAttrList.end(); ++ anAttrIt) + if (isUsed(*anAttrIt)) + return true; - Slvs_hGroup aGroupID = myGroup->getId(); - // do not update entity from another group - if (aCurrentEntity.h != SLVS_E_UNKNOWN && aGroupID != aCurrentEntity.group) - return aCurrentEntity.h; - - // Point in 3D - std::shared_ptr aPoint = - std::dynamic_pointer_cast(theEntity); - if (aPoint) { - double aXYZ[3] = {aPoint->x(), aPoint->y(), aPoint->z()}; - Slvs_hParam aParams[3]; - for (int i = 0; i < 3; i++) { - Slvs_Param aPar = aCurrentEntity.h != SLVS_E_UNKNOWN ? - myStorage->getParameter(aCurrentEntity.param[i]) : - Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0); - aPar.val = aXYZ[i]; - aParams[i] = myStorage->addParameter(aPar); - } - - if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity - aCurrentEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, aGroupID, aParams[0], aParams[1], aParams[2]); - else { // update entity data - for (int i = 0; i < 3; i++) - aCurrentEntity.param[i] = aParams[i]; - } - aResult = myStorage->addEntity(aCurrentEntity); - } else { - // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error - Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId(); - if (aWorkplaneID == SLVS_E_UNKNOWN) - return SLVS_E_UNKNOWN; - - // Point in 2D - std::shared_ptr aPoint2D = - std::dynamic_pointer_cast(theEntity); - if (aPoint2D) { - double aXY[2] = {aPoint2D->x(), aPoint2D->y()}; - Slvs_hParam aParams[2]; - for (int i = 0; i < 2; i++) { - Slvs_Param aPar = aCurrentEntity.h != SLVS_E_UNKNOWN ? - myStorage->getParameter(aCurrentEntity.param[i]) : - Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0); - aPar.val = aXY[i]; - aParams[i] = myStorage->addParameter(aPar); - } - - if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity - aCurrentEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aParams[0], aParams[1]); - else { // update entity data - for (int i = 0; i < 2; i++) - aCurrentEntity.param[i] = aParams[i]; - } - aResult = myStorage->addEntity(aCurrentEntity); - } else { - // Scalar value (used for the distance entities) - AttributeDoublePtr aScalar = std::dynamic_pointer_cast(theEntity); - if (aScalar) { - Slvs_Param aParam = aCurrentEntity.h != SLVS_E_UNKNOWN ? - myStorage->getParameter(aCurrentEntity.param[0]) : - Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0); - aParam.val = aScalar->value(); - Slvs_hParam aValue = myStorage->addParameter(aParam); - - if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity - aCurrentEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aValue); - else - aCurrentEntity.param[0] = aValue; - aResult = myStorage->addEntity(aCurrentEntity); - } - } - } - - myAttributeMap[theEntity] = aResult; - theType = aCurrentEntity.type; - return aResult; -} - -Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& theType) -{ - Slvs_hEntity aResult = SLVS_E_UNKNOWN; - if (!theEntity || !theEntity->data() || !theEntity->data()->isValid()) - return SLVS_E_UNKNOWN; - // If the entity is already in the group, try to find it - std::map::const_iterator anEntIter = myFeatureMap.find(theEntity); - Slvs_Entity aCurrentEntity; - aCurrentEntity.h = SLVS_E_UNKNOWN; - if (anEntIter != myFeatureMap.end()) - aCurrentEntity = myStorage->getEntity(anEntIter->second); - else { - aResult = myGroup->getFeatureId(theEntity); - if (aResult != SLVS_E_UNKNOWN) { - Slvs_Entity anEnt = myStorage->getEntity(aResult); - theType = anEnt.type; - myFeatureMap[theEntity] = aResult; - return aResult; - } - } - - Slvs_hGroup aGroupID = myGroup->getId(); - // do not update entity from another group - if (aCurrentEntity.h != SLVS_E_UNKNOWN && aGroupID != aCurrentEntity.group) - return aCurrentEntity.h; - - Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId(); - DataPtr aData = theEntity->data(); - - // SketchPlugin features - const std::string& aFeatureKind = theEntity->getKind(); - AttributePtr anAttribute; - int anAttrType; - // Line - if (aFeatureKind == SketchPlugin_Line::ID()) { - anAttribute = aData->attribute(SketchPlugin_Line::START_ID()); - if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; - Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType); - - anAttribute = aData->attribute(SketchPlugin_Line::END_ID()); - if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; - Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType); - - if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity - aCurrentEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aStart, aEnd); - else { - aCurrentEntity.point[0] = aStart; - aCurrentEntity.point[1] = aEnd; - } - aResult = myStorage->addEntity(aCurrentEntity); - } - // Circle - else if (aFeatureKind == SketchPlugin_Circle::ID()) { - anAttribute = aData->attribute(SketchPlugin_Circle::CENTER_ID()); - if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; - Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType); - - anAttribute = aData->attribute(SketchPlugin_Circle::RADIUS_ID()); - if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; - Slvs_hEntity aRadius = changeEntity(anAttribute, anAttrType); - - if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity - Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID); - aCurrentEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, - aCenter, aWorkplane.normal, aRadius); - } else { - aCurrentEntity.point[0] = aCenter; - aCurrentEntity.distance = aRadius; - } - aResult = myStorage->addEntity(aCurrentEntity); - } - // Arc - else if (aFeatureKind == SketchPlugin_Arc::ID()) { - anAttribute = aData->attribute(SketchPlugin_Arc::CENTER_ID()); - if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; - Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType); - - anAttribute = aData->attribute(SketchPlugin_Arc::START_ID()); - if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; - Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType); - - anAttribute = aData->attribute(SketchPlugin_Arc::END_ID()); - if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; - Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType); - - if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity - Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID); - aCurrentEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, - aWorkplane.normal, aCenter, aStart, aEnd); - } else { - aCurrentEntity.point[0] = aCenter; - aCurrentEntity.point[1] = aStart; - aCurrentEntity.point[2] = aEnd; - } - 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 == SketchPlugin_Point::ID()) { - anAttribute = aData->attribute(SketchPlugin_Point::COORD_ID()); - if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; - // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier - aResult = changeEntity(anAttribute, anAttrType); - aCurrentEntity.type = SLVS_E_POINT_IN_3D; - } - - if (aResult != SLVS_E_UNKNOWN) { - myFeatureMap[theEntity] = aResult; - theType = aCurrentEntity.type; - } - return aResult; -} - -std::list SketchSolver_Constraint::constraints() const -{ - std::list aConstraints; - aConstraints.push_back(myBaseConstraint); - return aConstraints; + return false; } -void SketchSolver_Constraint::refresh() +bool SketchSolver_Constraint::isUsed(AttributePtr theAttribute) const { - cleanErrorMsg(); - std::map::iterator anAttrIter = myAttributeMap.begin(); - while (anAttrIter != myAttributeMap.end()) { - std::shared_ptr aPoint = - std::dynamic_pointer_cast(anAttrIter->first); - Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second); - if (anEntity.h == SLVS_E_UNKNOWN) { - std::map::iterator aTmpIter = anAttrIter++; - myAttributeMap.erase(aTmpIter); - continue; - } - if (aPoint) { - double aXYZ[3]; - for (int i = 0; i < 3; i++) { - Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]); - aXYZ[i] = aPar.val; - } - if (fabs(aPoint->x() - aXYZ[0]) > tolerance || - fabs(aPoint->y() - aXYZ[1]) > tolerance || - fabs(aPoint->z() - aXYZ[2]) > tolerance) - aPoint->setValue(aXYZ[0], aXYZ[1], aXYZ[2]); - } else { - // Point in 2D - std::shared_ptr aPoint2D = - std::dynamic_pointer_cast(anAttrIter->first); - if (aPoint2D) { - double aXY[2]; - for (int i = 0; i < 2; i++) { - Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]); - aXY[i] = aPar.val; - } - if (fabs(aPoint2D->x() - aXY[0]) > tolerance || - fabs(aPoint2D->y() - aXY[1]) > tolerance) - aPoint2D->setValue(aXY[0], aXY[1]); - } else { - // Scalar value (used for the distance entities) - AttributeDoublePtr aScalar = - std::dynamic_pointer_cast(anAttrIter->first); - if (aScalar) { - Slvs_Param aPar = myStorage->getParameter(anEntity.param[0]); - if (fabs(aScalar->value() - aPar.val) > tolerance) - aScalar->setValue(aPar.val); - } - } - } - anAttrIter++; + AttributePtr anAttribute = theAttribute; + AttributeRefAttrPtr aRefAttr = + std::dynamic_pointer_cast(anAttribute); + if (aRefAttr) { + if (aRefAttr->isObject()) + return isUsed(ModelAPI_Feature::feature(aRefAttr->object())); + else + anAttribute = aRefAttr->attr(); } - std::map::iterator aValIter = myValueMap.begin(); - for (; aValIter != myValueMap.end(); aValIter++) { - AttributeDoublePtr aScalar = - std::dynamic_pointer_cast(anAttrIter->first); - if (aScalar) { - Slvs_Param aPar = myStorage->getParameter(anAttrIter->second); - aScalar->setValue(aPar.val); - } - } -} - -Slvs_hEntity SketchSolver_Constraint::getId(FeaturePtr theFeature) const -{ - std::map::const_iterator aFIter = myFeatureMap.find(theFeature); - if (aFIter == myFeatureMap.end()) - return SLVS_E_UNKNOWN; - //// check the Feature is really in the storage - //Slvs_Entity anEntity = myStorage->getEntity(aFIter->second); - //if (anEntity.h == SLVS_E_UNKNOWN) { - // // rebuild feature - // int aType; - // anEntity.h = const_cast(this)->changeEntity(aFIter->first, aType); - // const_cast(this)->myFeatureMap[theFeature] = anEntity.h; - //} - //return anEntity.h; - return aFIter->second; -} - -Slvs_hEntity SketchSolver_Constraint::getId(AttributePtr theAttribute) const -{ - std::map::const_iterator anAttrIter = myAttributeMap.find(theAttribute); - if (anAttrIter == myAttributeMap.end()) - return SLVS_E_UNKNOWN; - return anAttrIter->second; -} - -bool SketchSolver_Constraint::isInitialized(AttributePtr theAttribute) -{ - if (theAttribute->isInitialized()) - return true; - myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); + const std::list& aCList = myStorage->constraint(myBaseConstraint); + std::list::const_iterator aCIt = aCList.begin(); + for (; aCIt != aCList.end(); ++aCIt) + if ((*aCIt)->isUsed(theAttribute)) + return true; return false; } - -void SketchSolver_Constraint::calculateMiddlePoint( - const Slvs_Entity& theEntity, double theCoeff, double& theX, double& theY) const -{ - if (theEntity.type == SLVS_E_LINE_SEGMENT) { - double aStartEndXY[2][2]; - Slvs_Entity aPoint; - for (int i = 0; i < 2; i++) { - aPoint = myStorage->getEntity(theEntity.point[i]); - for (int j = 0; j < 2; j++) - aStartEndXY[i][j] = myStorage->getParameter(aPoint.param[j]).val; - } - theX = (1.0 - theCoeff) * aStartEndXY[0][0] + theCoeff * aStartEndXY[1][0]; - theY = (1.0 - theCoeff) * aStartEndXY[0][1] + theCoeff * aStartEndXY[1][1]; - } else if (theEntity.type == SLVS_E_ARC_OF_CIRCLE) { - double anArcPoint[3][2]; - Slvs_Entity aPoint; - for (int i = 0; i < 3; i++) { - aPoint = myStorage->getEntity(theEntity.point[i]); - for (int j = 0; j < 2; j++) - anArcPoint[i][j] = myStorage->getParameter(aPoint.param[j]).val; - } - // project last point of arc on the arc - double x = anArcPoint[1][0] - anArcPoint[0][0]; - double y = anArcPoint[1][1] - anArcPoint[0][1]; - double aRad = sqrt(x*x + y*y); - x = anArcPoint[2][0] - anArcPoint[0][0]; - y = anArcPoint[2][1] - anArcPoint[0][1]; - double aNorm = sqrt(x*x + y*y); - if (aNorm >= tolerance) { - anArcPoint[2][0] = x * aRad / aNorm; - anArcPoint[2][1] = y * aRad / aNorm; - } - anArcPoint[1][0] -= anArcPoint[0][0]; - anArcPoint[1][1] -= anArcPoint[0][1]; - if (theCoeff < tolerance) { - theX = anArcPoint[0][0] + anArcPoint[1][0]; - theY = anArcPoint[0][1] + anArcPoint[1][1]; - return; - } else if (1 - theCoeff < tolerance) { - theX = anArcPoint[0][0] + anArcPoint[2][0]; - theY = anArcPoint[0][1] + anArcPoint[2][1]; - return; - } - - std::shared_ptr aStartDir(new GeomAPI_Dir2d(anArcPoint[1][0], anArcPoint[1][1])); - std::shared_ptr aEndDir(new GeomAPI_Dir2d(anArcPoint[2][0], anArcPoint[2][1])); - double anAngle = aStartDir->angle(aEndDir); - if (anAngle < 0) - anAngle += 2.0 * PI; - anAngle *= theCoeff; - double aCos = cos(anAngle); - double aSin = sin(anAngle); - theX = anArcPoint[0][0] + anArcPoint[1][0] * aCos - anArcPoint[1][1] * aSin; - theY = anArcPoint[0][1] + anArcPoint[1][0] * aSin + anArcPoint[1][1] * aCos; - } -} - void SketchSolver_Constraint::makeTemporary() const { - std::vector::const_iterator anIt = mySlvsConstraints.begin(); - for (; anIt != mySlvsConstraints.end(); anIt++) - myStorage->addTemporaryConstraint(*anIt); + myStorage->setTemporary(myBaseConstraint); } diff --git a/src/SketchSolver/SketchSolver_Constraint.h b/src/SketchSolver/SketchSolver_Constraint.h index 974143246..6f8a6fd79 100644 --- a/src/SketchSolver/SketchSolver_Constraint.h +++ b/src/SketchSolver/SketchSolver_Constraint.h @@ -18,218 +18,85 @@ #include #include -class SketchSolver_Group; - /** \class SketchSolver_Constraint * \ingroup Plugins - * \brief Stores mapping between SketchPlugin and SolveSpace constraints data + * \brief Converts SketchPlugin constraint to the constraint applicable for solver */ class SketchSolver_Constraint { protected: /// Default constructor - SketchSolver_Constraint() {} - /// Constructor based on SketchPlugin constraint - SketchSolver_Constraint(ConstraintPtr theConstraint); + SketchSolver_Constraint() + : myGroupID(GID_UNKNOWN), + myType(CONSTRAINT_UNKNOWN) + {} public: - virtual ~SketchSolver_Constraint(); + /// Constructor based on SketchPlugin constraint + SKETCHSOLVER_EXPORT SketchSolver_Constraint(ConstraintPtr theConstraint); + + virtual ~SketchSolver_Constraint() {} - /// \brief Initializes the storage of SolveSpace constraints - void setStorage(StoragePtr theStorage); - /// \brief Initializes group ID for this constraint - void setGroup(SketchSolver_Group* theGroup); + /// \brief Initializes parameters and start constraint creation + /// \param theStorage [in] storage where to place new constraint + /// \param theGroupID [in] group for constraint + /// \param theSketchID [in] sketch for constraint + void process(StoragePtr theStorage, const GroupID& theGroupID, const EntityID& theSketchID); /// \brief Update constraint - virtual void update(ConstraintPtr theConstraint = ConstraintPtr()); + SKETCHSOLVER_EXPORT virtual void update(); /// \brief Tries to remove constraint /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence) - virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr()); + SKETCHSOLVER_EXPORT virtual bool remove(); - /// \brief Update SketchPlugin attributes using the data obtained from SolveSpace entities - virtual void refresh(); + /// \brief Obtain a type of SketchPlugin constraint + SKETCHSOLVER_EXPORT static SketchSolver_ConstraintType TYPE(ConstraintPtr theConstraint); /// \brief Returns the type of constraint - virtual int getType() const = 0; + virtual SketchSolver_ConstraintType getType() const + { return myType; } /// \brief The constraint is made temporary void makeTemporary() const; - /// \brief Checks the constraint is used by current object - virtual bool hasConstraint(ConstraintPtr theConstraint) const - { return theConstraint == myBaseConstraint; } - - /// \brief Return list of SketchPlugin constraints attached to this object - virtual std::list constraints() const; - - /// \brief Return identifier of SolveSpace entity relating to the feature - Slvs_hEntity getId(FeaturePtr theFeature) const; - /// \brief Return identifier of SolveSpace entity relating to the attribute - Slvs_hEntity getId(AttributePtr theAttribute) const; - - /// \brief Adds a feature to constraint and create its analogue in SolveSpace - virtual void addFeature(FeaturePtr theFeature); + /// \brief Verify the feature or any its attribute is used by constraint + bool isUsed(FeaturePtr theFeature) const; + /// \brief Verify the attribute is used by constraint + bool isUsed(AttributePtr theAttribute) const; /// \brief Shows error message const std::string& error() const { return myErrorMsg; } protected: - /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints + /// \brief Converts SketchPlugin constraint to a list of solver's constraints virtual void process(); - /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints + /// \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(double& theValue, std::vector& theAttributes); - - /// \brief Verify the attributes of constraint are changed (and constraint need to rebuild) - /// \param[in] theConstraint constraint, which attributes should be checked (if NULL, the myBaseConstraint is used) - /// \return \c true if some attributes are changed - virtual bool checkAttributesChanged(ConstraintPtr theConstraint); + virtual void getAttributes(double& theValue, std::vector& theAttributes); /// \brief This method is used in derived objects to check consistency 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 - /// \return identifier of created/updated entity - Slvs_hEntity changeEntity(AttributeRefAttrPtr theAttribute, int& theType); - /// \brief Create or change SlveSpace entity according to the given attribute - Slvs_hEntity changeEntity(AttributePtr theAttribute, int& theType); - /// \brief Create or change SlveSpace entity according to the given feature - Slvs_hEntity changeEntity(FeaturePtr theFeature, int& theType); - - /// \brief Calculate middle point on the specified entity - /// \param[in] theEntity arc or line - /// \param[in] theCoeff is a value in [0.0, 1.0] which shows the position of the point on the entity (0.0 - start point, 1.0 - end point) - /// \param[out] theX X coordinate of middle point - /// \param[out] theY Y coordinate of middle point - void calculateMiddlePoint(const Slvs_Entity& theEntity, double theCoeff, - double& theX, double& theY) const; - - /// \brief Removes the links to unused entities - void cleanRemovedEntities(); - /// \brief Removes last error void cleanErrorMsg() { myErrorMsg.clear(); } -private: - /// \brief Sets error, if the attribute is not initialized - bool isInitialized(AttributePtr theAttribute); - protected: - SketchSolver_Group* myGroup; ///< the group which contains current constraint - ConstraintPtr myBaseConstraint; ///< SketchPlugin constraint - std::vector mySlvsConstraints; ///< list of indices of SolveSpace constraints, together which equivalent to SketchPlugin constraint - std::map myFeatureMap; ///< map feature to the entity it represents - std::map myAttributeMap; ///< map attribute to the corresponding entity - std::map myValueMap; ///< list of attributes, which represents single value (e.g. distance) used in constraint - StoragePtr myStorage; ///< storage, which contains all information about entities and constraints in current group - - std::string myErrorMsg; ///< error message -}; - -typedef std::shared_ptr SolverConstraintPtr; - - - -/** \class SketchSolver_ConstraintParallel - * \ingroup Plugins - * \brief Convert Parallel constraint to SolveSpace structure - */ -class SketchSolver_ConstraintParallel : public SketchSolver_Constraint -{ -public: - /// Constructor based on SketchPlugin constraint - SketchSolver_ConstraintParallel(ConstraintPtr theConstraint) : - SketchSolver_Constraint(theConstraint) - {} - - virtual int getType() const - { return SLVS_C_PARALLEL; } -}; - - -/** \class SketchSolver_ConstraintPerpendicular - * \ingroup Plugins - * \brief Convert Perpendicular constraint to SolveSpace structure - */ -class SketchSolver_ConstraintPerpendicular : public SketchSolver_Constraint -{ -public: - /// Constructor based on SketchPlugin constraint - SketchSolver_ConstraintPerpendicular(ConstraintPtr theConstraint) : - SketchSolver_Constraint(theConstraint) - {} + GroupID myGroupID; ///< identifier of the group, the constraint belongs to + EntityID mySketchID; ///< identifier of the sketch, the constraint belongs to + ConstraintPtr myBaseConstraint; ///< base SketchPlugin constraint + StoragePtr myStorage; ///< storage, which contains all information about entities and constraints + SketchSolver_ConstraintType myType; ///< type of constraint - virtual int getType() const - { return SLVS_C_PERPENDICULAR; } + std::string myErrorMsg; ///< error message }; - -/** \class SketchSolver_ConstraintHorizontal - * \ingroup Plugins - * \brief Convert Horizontal constraint to SolveSpace structure - */ -class SketchSolver_ConstraintHorizontal : public SketchSolver_Constraint -{ -public: - /// Constructor based on SketchPlugin constraint - SketchSolver_ConstraintHorizontal(ConstraintPtr theConstraint) : - SketchSolver_Constraint(theConstraint) - {} - - virtual int getType() const - { return SLVS_C_HORIZONTAL; } -}; - - -/** \class SketchSolver_ConstraintVertical - * \ingroup Plugins - * \brief Convert Vertical constraint to SolveSpace structure - */ -class SketchSolver_ConstraintVertical : public SketchSolver_Constraint -{ -public: - /// Constructor based on SketchPlugin constraint - SketchSolver_ConstraintVertical(ConstraintPtr theConstraint) : - SketchSolver_Constraint(theConstraint) - {} - - virtual int getType() const - { return SLVS_C_VERTICAL; } -}; - - -/** \class SketchSolver_ConstraintRadius - * \ingroup Plugins - * \brief Convert Radius constraint to SolveSpace structure - */ -class SketchSolver_ConstraintRadius : public SketchSolver_Constraint -{ -public: - /// Constructor based on SketchPlugin constraint - SketchSolver_ConstraintRadius(ConstraintPtr theConstraint) : - SketchSolver_Constraint(theConstraint) - {} - - virtual int getType() const - { return SLVS_C_DIAMETER; } - - virtual void adjustConstraint() - { - AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::VALUE())); - Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front()); - aConstraint.valA = 2.0 * aValueAttr->value(); - myStorage->updateConstraint(aConstraint); - } -}; +typedef std::shared_ptr SolverConstraintPtr; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintAngle.cpp b/src/SketchSolver/SketchSolver_ConstraintAngle.cpp index 10dbae165..553d5a803 100644 --- a/src/SketchSolver/SketchSolver_ConstraintAngle.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintAngle.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -8,7 +9,7 @@ #include void SketchSolver_ConstraintAngle::getAttributes( - double& theValue, std::vector& theAttributes) + double& theValue, std::vector& theAttributes) { SketchSolver_Constraint::getAttributes(theValue, theAttributes); @@ -19,25 +20,29 @@ void SketchSolver_ConstraintAngle::getAttributes( void SketchSolver_ConstraintAngle::adjustConstraint() { static const double aTol = 1000. * tolerance; - Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front()); + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + + ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front(); + if (fabs(myAngle - aConstraint->value()) < aTol) + return; + myAngle = aConstraint->value(); bool isFixed[2][2]; std::shared_ptr aPoints[2][2]; // start and end points of lines - Slvs_hConstraint aFixedConstraint; - Slvs_hEntity anEnt[2] = {aConstraint.entityA, aConstraint.entityB}; - for (int i = 0; i < 2; i++) { - const Slvs_Entity& aLine = myStorage->getEntity(anEnt[i]); - double aCoef = -1.0; - for (int j = 0; j < 2; j++, aCoef += 2.0) { - const Slvs_Entity& aPoint = myStorage->getEntity(aLine.point[j]); - double aCoords[2]; - for (int k = 0; k < 2; k++) - aCoords[k] = myStorage->getParameter(aPoint.param[k]).val; - isFixed[i][j] = myStorage->isPointFixed(aPoint.h, aFixedConstraint, true); - aPoints[i][j] = std::shared_ptr(new GeomAPI_Pnt2d(aCoords[0], aCoords[1])); + const std::list& aConstrLines = aConstraint->entities(); + std::list::const_iterator aCLIt = aConstrLines.begin(); + for (int i = 0; aCLIt != aConstrLines.end(); ++i, ++aCLIt) { + const std::list& aLinePoints = (*aCLIt)->subEntities(); + std::list::const_iterator aLPIt = aLinePoints.begin(); + for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt) { + isFixed[i][j] = ((*aLPIt)->group() != myGroupID); + aPoints[i][j] = aBuilder->point(*aLPIt); } } + if (isFixed[0][0] && isFixed[0][1] && isFixed[1][0] && isFixed[1][1]) + return; // both lines are fixed => no need to update them + std::shared_ptr aLine[2] = { std::shared_ptr(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])), std::shared_ptr(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1])) @@ -75,21 +80,6 @@ void SketchSolver_ConstraintAngle::adjustConstraint() } } - aConstraint.other = false; - for (int i = 0; i < 2; i++) - if (aLine[i]->direction()->dot(aDir[i]) < 0.0) - aConstraint.other = !aConstraint.other; - myStorage->updateConstraint(aConstraint); - - bool isChanged = fabs(myAngle - aConstraint.valA) > aTol; - // myAngle should be updated even if the angle of constraint is changed too little - myAngle = aConstraint.valA; - if (!isChanged) - return; // the angle was not changed, no need to recalculate positions of lines - - if (isFixed[0][0] && isFixed[0][1] && isFixed[1][0] && isFixed[1][1]) - return; // both lines are fixed => no need to update them - // Recalculate positions of lines to avoid conflicting constraints // while changing angle value several times double cosA = cos(myAngle * PI / 180.0); @@ -124,15 +114,18 @@ void SketchSolver_ConstraintAngle::adjustConstraint() } // Update positions of points - const Slvs_Entity& anUpdLine = myStorage->getEntity(anEnt[aLineToUpd]); - Slvs_Param aParam; - for (int i = 0; i < 2; i++) { - const Slvs_Entity& aPoint = myStorage->getEntity(anUpdLine.point[i]); - aParam = myStorage->getParameter(aPoint.param[0]); - aParam.val = aNewPoints[i]->x(); - myStorage->updateParameter(aParam); - aParam = myStorage->getParameter(aPoint.param[1]); - aParam.val = aNewPoints[i]->y(); - myStorage->updateParameter(aParam); + std::list::const_iterator anUpdLine = aConstrLines.begin(); + if (aLineToUpd > 0) ++anUpdLine; + const std::list& anUpdPoints = (*anUpdLine)->subEntities(); + std::list::const_iterator aPIt = anUpdPoints.begin(); + for (int i = 0; aPIt != anUpdPoints.end(); ++aPIt, ++i) { + double aCoord[2] = {aNewPoints[i]->x(), aNewPoints[i]->y()}; + const std::list& aParams = (*aPIt)->parameters(); + std::list::const_iterator aParIt = aParams.begin(); + for (int j = 0; aParIt != aParams.end(); ++j, ++aParIt) + (*aParIt)->setValue(aCoord[j]); } + + aBuilder->adjustConstraint(aConstraint); + myStorage->addConstraint(myBaseConstraint, aConstraint); } diff --git a/src/SketchSolver/SketchSolver_ConstraintAngle.h b/src/SketchSolver/SketchSolver_ConstraintAngle.h index 4d91aced4..3e979aa6d 100644 --- a/src/SketchSolver/SketchSolver_ConstraintAngle.h +++ b/src/SketchSolver/SketchSolver_ConstraintAngle.h @@ -22,17 +22,14 @@ public: myAngle(0.0) {} - virtual int getType() const - { return SLVS_C_ANGLE; } - /// \brief This method is used in derived objects to check consistence of constraint. virtual void adjustConstraint(); protected: - /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints + /// \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(double& theValue, std::vector& theAttributes); + virtual void getAttributes(double& theValue, std::vector& theAttributes); private: double myAngle; diff --git a/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp b/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp index e1242606e..b10d7e95d 100644 --- a/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp @@ -1,41 +1,31 @@ #include #include -#include - -#include -#include - -#include +#include void SketchSolver_ConstraintCoincidence::getAttributes( double& theValue, - std::vector& theAttributes) + std::vector& theAttributes) { SketchSolver_Constraint::getAttributes(theValue, theAttributes); - if (!myErrorMsg.empty() || theAttributes[0] == SLVS_E_UNKNOWN) + if (!myErrorMsg.empty() || !theAttributes[0]) { + theAttributes.clear(); return; + } - if (theAttributes[1] != SLVS_E_UNKNOWN) { - myType = SLVS_C_POINTS_COINCIDENT; - - // set coordinates of slave (second) point equal to the master (first) point - Slvs_Entity aFirst = myStorage->getEntity(theAttributes[0]); - Slvs_Entity aSecond = myStorage->getEntity(theAttributes[1]); - for (int i = 0; i < 4; i++) - if (aFirst.param[i] != SLVS_E_UNKNOWN && aSecond.param[i] != SLVS_E_UNKNOWN) { - Slvs_Param aPar1 = myStorage->getParameter(aFirst.param[i]); - Slvs_Param aPar2 = myStorage->getParameter(aSecond.param[i]); - aPar2.val = aPar1.val; - myStorage->updateParameter(aPar2); - } + if (theAttributes[1]) { + myType = CONSTRAINT_PT_PT_COINCIDENT; + // Set the slave (second) point the same as master (first) point. + // This will allow to skip adding point-point coincidence to the set of constraints + // and give us speed-up in solving the set of equations + myStorage->addCoincidentPoints(theAttributes[0], theAttributes[1]); } - else if (theAttributes[2] != SLVS_E_UNKNOWN) { + else if (theAttributes[2]) { // check the type of entity (line or circle) - Slvs_Entity anEnt = myStorage->getEntity(theAttributes[2]); - if (anEnt.type == SLVS_E_LINE_SEGMENT) - myType = SLVS_C_PT_ON_LINE; - else if (anEnt.type == SLVS_E_CIRCLE || anEnt.type == SLVS_E_ARC_OF_CIRCLE) - myType = SLVS_C_PT_ON_CIRCLE; + SketchSolver_EntityType anEntType = theAttributes[2]->type(); + if (anEntType == ENTITY_LINE) + myType = CONSTRAINT_PT_ON_LINE; + else if (anEntType == ENTITY_CIRCLE || anEntType == ENTITY_ARC) + myType = CONSTRAINT_PT_ON_CIRCLE; else myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); } else @@ -43,339 +33,26 @@ void SketchSolver_ConstraintCoincidence::getAttributes( } -bool SketchSolver_ConstraintCoincidence::hasConstraint(ConstraintPtr theConstraint) const -{ - if (myBaseConstraint == theConstraint) - return true; - return myExtraCoincidence.find(theConstraint) != myExtraCoincidence.end(); -} - -std::list SketchSolver_ConstraintCoincidence::constraints() const -{ - std::list aConstraints; - aConstraints.push_back(myBaseConstraint); - std::map::const_iterator anIt = myExtraCoincidence.begin(); - for (; anIt != myExtraCoincidence.end(); anIt++) - aConstraints.push_back(anIt->first); - return aConstraints; -} - -bool SketchSolver_ConstraintCoincidence::isCoincide( - std::shared_ptr theConstraint) const -{ - std::set::const_iterator anAttrIter = theConstraint->myCoincidentPoints.begin(); - for (; anAttrIter != theConstraint->myCoincidentPoints.end(); anAttrIter++) - if (myCoincidentPoints.find(*anAttrIter) != myCoincidentPoints.end()) - return true; - return false; -} - -void SketchSolver_ConstraintCoincidence::attach( - std::shared_ptr theConstraint) +static bool isBase(const std::list& theConstraints, AttributePtr theAttribute) { - cleanErrorMsg(); - // Remove constraints from theConstraint - std::vector::iterator aCIter = theConstraint->mySlvsConstraints.begin(); - for (; aCIter != theConstraint->mySlvsConstraints.end(); aCIter++) - theConstraint->myStorage->removeConstraint(*aCIter); - - if (myStorage == theConstraint->myStorage) { - // Clean removed items - std::set aRemParams; - std::set aRemEnts; - std::set aRemConstr; - theConstraint->myStorage->getRemoved(aRemParams, aRemEnts, aRemConstr); - - if (!aRemEnts.empty()) { - std::map::iterator aFeatIt = theConstraint->myFeatureMap.begin(); - while (aFeatIt != theConstraint->myFeatureMap.end()) { - if (aRemEnts.find(aFeatIt->second) != aRemEnts.end()) { - // remove feature - std::map::iterator aRemoveIt = aFeatIt++; - theConstraint->myFeatureMap.erase(aRemoveIt); - } else - ++aFeatIt; - } - std::map::iterator anAttrIt = theConstraint->myAttributeMap.begin(); - while (anAttrIt != theConstraint->myAttributeMap.end()) { - if (aRemEnts.find(anAttrIt->second) != aRemEnts.end()) { - // remove attribute - std::map::iterator aRemoveIt = anAttrIt++; - theConstraint->myAttributeMap.erase(aRemoveIt); - } else - ++anAttrIt; - } - } - } - - // Copy data. - addConstraint(theConstraint->myBaseConstraint); - std::map::iterator aConstrIter = - theConstraint->myExtraCoincidence.begin(); - for (; aConstrIter != theConstraint->myExtraCoincidence.end(); aConstrIter++) - addConstraint(aConstrIter->first); - // Clear the lists to not remove the entities on destruction - theConstraint->mySlvsConstraints.clear(); - theConstraint->myFeatureMap.clear(); - theConstraint->myAttributeMap.clear(); -} - -Slvs_hConstraint SketchSolver_ConstraintCoincidence::addConstraint( - Slvs_hEntity thePoint1, Slvs_hEntity thePoint2) -{ - if (thePoint1 == thePoint2) - return SLVS_E_UNKNOWN; - - bool hasDuplicated = myStorage->hasDuplicatedConstraint(); - Slvs_Constraint aNewConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), - SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(), 0.0, thePoint1, thePoint2, - SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - Slvs_hConstraint aNewID = myStorage->addConstraint(aNewConstraint); - if (!hasDuplicated && myStorage->hasDuplicatedConstraint()) { - // the duplicated constraint appears - myStorage->removeConstraint(aNewID); - return SLVS_E_UNKNOWN; - } - mySlvsConstraints.push_back(aNewID); - return aNewID; -} - -Slvs_hConstraint SketchSolver_ConstraintCoincidence::addPointOnEntity( - Slvs_hEntity thePoint, Slvs_hEntity theEntity) -{ - // Check the point is not coincident with boundaries of the entity - Slvs_Entity anEnt = myStorage->getEntity(theEntity); - int aPos = anEnt.type == SLVS_E_LINE_SEGMENT ? 0 : 1; - for (; anEnt.point[aPos] != SLVS_E_UNKNOWN; aPos++) - if (anEnt.point[aPos] == thePoint || - myStorage->isCoincident(anEnt.point[aPos], thePoint)) - return SLVS_E_UNKNOWN; - - bool hasDuplicated = myStorage->hasDuplicatedConstraint(); - Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front()); - Slvs_hConstraint aType = anEnt.type == SLVS_E_LINE_SEGMENT ? - SLVS_C_PT_ON_LINE : SLVS_C_PT_ON_CIRCLE; - Slvs_Constraint aNewConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), - aType, myGroup->getWorkplaneId(), 0.0, aBaseCoincidence.ptA, SLVS_E_UNKNOWN, - theEntity, SLVS_E_UNKNOWN); - Slvs_hConstraint aNewID = myStorage->addConstraint(aNewConstraint); - if (!hasDuplicated && myStorage->hasDuplicatedConstraint()) { - // the duplicated constraint appears - myStorage->removeConstraint(aNewID); - return SLVS_E_UNKNOWN; - } - mySlvsConstraints.push_back(aNewID); - return aNewID; -} - -void SketchSolver_ConstraintCoincidence::addConstraint(ConstraintPtr theConstraint) -{ - if (mySlvsConstraints.empty()) { - // This constraint is empty, rebuild it from scratch - myBaseConstraint = theConstraint; - process(); - return; - } - - std::list anAttrList = - theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId()); - std::list::iterator anIter = anAttrList.begin(); - std::vector aPoints; - Slvs_hEntity anEntity = SLVS_E_UNKNOWN; - int anEntType; - for (; anIter != anAttrList.end(); anIter++) { - Slvs_hEntity aPointID = SLVS_E_UNKNOWN; - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*anIter); - if (!aRefAttr) - continue; - - AttributePtr aPointAttr; - if (aRefAttr->isObject()) { - FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); - std::map::const_iterator aFeatFound = - myFeatureMap.find(aFeature); - if (aFeatFound != myFeatureMap.end()) - anEntity = aFeatFound->second; - else { - anEntity = myGroup->getFeatureId(aFeature); - if (anEntity == SLVS_E_UNKNOWN) - anEntity = changeEntity(aFeature, anEntType); - else { - myFeatureMap[aFeature] = anEntity; - // Obtain relations between attributes of the feature and SolveSpace entities - std::list anAttrList = - aFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); - std::list::iterator anIt = anAttrList.begin(); - for (; anIt != anAttrList.end(); ++anIt) { - Slvs_hEntity anAttrID = myGroup->getAttributeId(*anIt); - if (anAttrID != SLVS_E_UNKNOWN) - myAttributeMap[*anIt] = anAttrID; - } - } - } - // If the feature is a point, add it to the list of coincident points - if (aFeature->getKind() == SketchPlugin_Point::ID()) { - aPointID = anEntity; - anEntity = SLVS_E_UNKNOWN; - aPointAttr = aFeature->attribute(SketchPlugin_Point::COORD_ID()); - } - } else { - aPointAttr = aRefAttr->attr(); - std::map::const_iterator anAttrFound = - myAttributeMap.find(aPointAttr); - if (anAttrFound != myAttributeMap.end()) - aPointID = anAttrFound->second; - else { - aPointID = myGroup->getAttributeId(aPointAttr); - if (aPointID == SLVS_E_UNKNOWN) - aPointID = changeEntity(aPointAttr, anEntType); - } - } - - if (aPointAttr) { // the point is found - aPoints.push_back(aPointID); - myCoincidentPoints.insert(aPointAttr); - myAttributeMap[aPointAttr] = aPointID; - } - } - - Slvs_hConstraint aNewConstr = SLVS_E_UNKNOWN; - if (anEntity != SLVS_E_UNKNOWN) - aNewConstr = addPointOnEntity(aPoints.front(), anEntity); - else { // coincidence between two points - Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front()); - std::vector::const_iterator aPtIter = aPoints.begin(); - for (; aPtIter != aPoints.end(); aPtIter++) { - Slvs_hConstraint aC = addConstraint(aBaseCoincidence.ptA, *aPtIter); - if (aC != SLVS_E_UNKNOWN) - aNewConstr = aC; - } - } - myExtraCoincidence[theConstraint] = aNewConstr; -} - -void SketchSolver_ConstraintCoincidence::process() -{ - SketchSolver_Constraint::process(); - - // Fill the list of coincident points - std::list anAttrList = - myBaseConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId()); - std::list::iterator anIt = anAttrList.begin(); - for (; anIt != anAttrList.end(); anIt++) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*anIt); - if (!aRefAttr || aRefAttr->isObject()) - continue; - myCoincidentPoints.insert(aRefAttr->attr()); - } -} - -bool SketchSolver_ConstraintCoincidence::remove(ConstraintPtr theConstraint) -{ - cleanErrorMsg(); - if (mySlvsConstraints.empty()) - return true; - ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint; - int aPos = -1; // position of constraint in the list (-1 for base constraint) - std::map::iterator anExtraIt; - if (aConstraint != myBaseConstraint) { - anExtraIt = myExtraCoincidence.find(aConstraint); - if (anExtraIt == myExtraCoincidence.end()) - return false; // there is no constraint, which is specified to remove - else { - bool isEmpty = anExtraIt->second == SLVS_E_UNKNOWN; - if (!isEmpty) { - isEmpty = true; - for (aPos = 0; aPos < (int)mySlvsConstraints.size(); aPos++) - if (mySlvsConstraints[aPos] == anExtraIt->second) { - isEmpty = false; - break; - } - aPos -= 1; - } - myExtraCoincidence.erase(anExtraIt); - if (isEmpty) - return false; - } - } - - bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints[aPos+1]); - mySlvsConstraints.erase(mySlvsConstraints.begin() + (1+aPos)); - if (aPos < 0 && !myExtraCoincidence.empty()) { - anExtraIt = myExtraCoincidence.begin(); - // Remove invalid constraints - while (anExtraIt != myExtraCoincidence.end()) { - if (!anExtraIt->first->data() || !anExtraIt->first->data()->isValid()) { - std::map::iterator aTempIt = anExtraIt++; - if (aTempIt->first != SLVS_E_UNKNOWN) { - myStorage->removeConstraint(aTempIt->second); - std::vector::iterator anIt = mySlvsConstraints.begin(); - for (; anIt != mySlvsConstraints.end(); anIt++) - if (*anIt == aTempIt->second) { - mySlvsConstraints.erase(anIt); - break; - } - } - myExtraCoincidence.erase(aTempIt); - continue; - } - anExtraIt++; - } - // Find first non-extra conststraint - anExtraIt = myExtraCoincidence.begin(); - while (anExtraIt != myExtraCoincidence.end() && anExtraIt->second == SLVS_E_UNKNOWN) - anExtraIt++; - if (anExtraIt != myExtraCoincidence.end()) { - // Need to specify another base coincidence constraint - myBaseConstraint = anExtraIt->first; - myExtraCoincidence.erase(anExtraIt); - if (mySlvsConstraints.empty()) { - std::vector::iterator aCIter = mySlvsConstraints.begin(); - Slvs_Constraint aBase = myStorage->getConstraint(*aCIter); - for (++aCIter; aCIter != mySlvsConstraints.end(); aCIter++) { - Slvs_Constraint aConstr = myStorage->getConstraint(*aCIter); - aConstr.ptA = aBase.ptA; - myStorage->updateConstraint(aConstr); - } - } - } - } - // Clear removed attributes - std::set aParamRemoved; - std::set anEntRemoved; - std::set aConstrRemoved; - myStorage->getRemoved(aParamRemoved, anEntRemoved, aConstrRemoved); - std::map::iterator anAttrIter = myAttributeMap.begin(); - while (anAttrIter != myAttributeMap.end()) { - if (anEntRemoved.find(anAttrIter->second) != anEntRemoved.end()) { - std::map::iterator aTempIt = anAttrIter++; - myCoincidentPoints.erase(aTempIt->first); - myAttributeMap.erase(aTempIt); - continue; - } - anAttrIter++; + AttributePtr anAttribute = theAttribute; + FeaturePtr aFeature; + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(theAttribute); + if (aRefAttr) { + if (aRefAttr->isObject()) + aFeature = ModelAPI_Feature::feature(aRefAttr->object()); + else + anAttribute = aRefAttr->attr(); } - // Go through remaining extra coincidence and try to add or remove them - anExtraIt = myExtraCoincidence.begin(); - while (anExtraIt != myExtraCoincidence.end()) { - if (anExtraIt->first == SLVS_E_UNKNOWN) { - if (!anExtraIt->first->data() || !anExtraIt->first->data()->isValid()) { - std::map::iterator aTempIt = anExtraIt++; - myExtraCoincidence.erase(aTempIt); - continue; - } - if (mySlvsConstraints.empty()) { - myBaseConstraint = anExtraIt->first; - std::map::iterator aTempIt = anExtraIt++; - myExtraCoincidence.erase(aTempIt); - process(); - continue; - } else - addConstraint(anExtraIt->first); - } - anExtraIt++; + std::list::const_iterator aCIt = theConstraints.begin(); + for (; aCIt != theConstraints.end(); ++aCIt) { + std::list aSubs = (*aCIt)->entities(); + std::list::const_iterator aSIt = aSubs.begin(); + for (; aSIt != aSubs.end(); ++aSIt) + if ((aFeature && (*aSIt)->isBase(aFeature)) || + (!aFeature && (*aSIt)->isBase(anAttribute))) + return true; } - return mySlvsConstraints.empty(); + return false; } - diff --git a/src/SketchSolver/SketchSolver_ConstraintCoincidence.h b/src/SketchSolver/SketchSolver_ConstraintCoincidence.h index efb01572d..58b0d98df 100644 --- a/src/SketchSolver/SketchSolver_ConstraintCoincidence.h +++ b/src/SketchSolver/SketchSolver_ConstraintCoincidence.h @@ -9,7 +9,6 @@ #include "SketchSolver.h" #include -#include /** \class SketchSolver_ConstraintCoincidence * \ingroup Plugins @@ -19,53 +18,15 @@ class SketchSolver_ConstraintCoincidence : public SketchSolver_Constraint { public: /// Constructor based on SketchPlugin constraint - SketchSolver_ConstraintCoincidence(ConstraintPtr theConstraint) : - SketchSolver_Constraint(theConstraint), - myType(SLVS_C_UNKNOWN) + SKETCHSOLVER_EXPORT SketchSolver_ConstraintCoincidence(ConstraintPtr theConstraint) : + SketchSolver_Constraint(theConstraint) {} - virtual int getType() const - { return myType; } - - /// \brief Tries to remove constraint - /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence) - virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr()); - - /// \brief Checks the constraint is used by current object - virtual bool hasConstraint(ConstraintPtr theConstraint) const; - - /// \brief Return list of SketchPlugin constraints attached to this object - virtual std::list constraints() const; - - /// \brief Verifies the two Coincidence constraints are intersects (have shared point) - bool isCoincide(std::shared_ptr theConstraint) const; - - /// \brief Append all data of coincidence constaint to the current - void attach(std::shared_ptr theConstraint); - 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 SolveSpace constraints + /// \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(double& theValue, std::vector& theAttributes); - -private: - /// \brief Creates new coincidence constraint - Slvs_hConstraint addConstraint(Slvs_hEntity thePoint1, Slvs_hEntity thePoint2); - - /// \brief Create full SolveSpace structure according to given constraint - void addConstraint(ConstraintPtr theConstraint); - - /// \brief Create constraint of point concident to the line or circle - Slvs_hConstraint addPointOnEntity(Slvs_hEntity thePoint, Slvs_hEntity theEntity); - -private: - int myType; ///< type of constraint (applicable SLVS_C_POINTS_COINCIDENT or SLVS_C_PT_ON_LINE or SLVS_C_PT_ON_CIRCLE) - std::map myExtraCoincidence; ///< multiple coincidence of points - std::set myCoincidentPoints; ///< list of points under the Coincidence constraint + virtual void getAttributes(double& theValue, std::vector& theAttributes); }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintDistance.cpp b/src/SketchSolver/SketchSolver_ConstraintDistance.cpp index 63bd0ae7d..e82568d3e 100644 --- a/src/SketchSolver/SketchSolver_ConstraintDistance.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintDistance.cpp @@ -1,107 +1,75 @@ #include -#include #include +#include +#include +#include +#include #include #include -void SketchSolver_ConstraintDistance::process() +void SketchSolver_ConstraintDistance::getAttributes( + double& theValue, + std::vector& theAttributes) { - cleanErrorMsg(); - if (!myBaseConstraint || !myStorage || myGroup == 0) { - /// TODO: Put error message here + SketchSolver_Constraint::getAttributes(theValue, theAttributes); + if (!myErrorMsg.empty() || !theAttributes[0]) { + theAttributes.clear(); 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); + if (theAttributes[1]) + myType = CONSTRAINT_PT_PT_DISTANCE; + else if (theAttributes[2] && theAttributes[2]->type() == ENTITY_LINE) + myType = CONSTRAINT_PT_LINE_DISTANCE; + else + theAttributes.clear(); myPrevValue = 0.0; - adjustConstraint(); } void SketchSolver_ConstraintDistance::adjustConstraint() { // Adjust point-line distance - if (getType() != SLVS_C_PT_LINE_DISTANCE) + if (getType() != CONSTRAINT_PT_LINE_DISTANCE) return; // Check the sign of distance is changed - Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front()); - if (fabs(myPrevValue) == fabs(aConstraint.valA)) { - aConstraint.valA = myPrevValue; - myStorage->updateConstraint(aConstraint); + ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front(); + if (fabs(myPrevValue) == fabs(aConstraint->value())) { + aConstraint->setValue(myPrevValue); + myStorage->addConstraint(myBaseConstraint, aConstraint); return; } // Get constraint parameters and check the sign of constraint value - std::vector::iterator aCIter = mySlvsConstraints.begin(); - for (; aCIter != mySlvsConstraints.end(); aCIter++) { - 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 || myIsNegative) { - aConstraint.valA *= -1.0; - myStorage->updateConstraint(aConstraint); - myIsNegative = true; - } + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + std::shared_ptr aPoint; + std::shared_ptr aLine; + std::list aSubs = aConstraint->entities(); + std::list::const_iterator aSIt = aSubs.begin(); + for (; aSIt != aSubs.end(); ++aSIt) { + if ((*aSIt)->type() == ENTITY_POINT) + aPoint = aBuilder->point(*aSIt); + else if ((*aSIt)->type() == ENTITY_LINE) + aLine = aBuilder->line(*aSIt); + } + + std::shared_ptr aLineVec = aLine->direction()->xy(); + std::shared_ptr aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy()); + if (aPtLineVec->cross(aLineVec) * aConstraint->value() < 0.0 || myIsNegative) { + aConstraint->setValue(aConstraint->value() * (-1.0)); + myStorage->addConstraint(myBaseConstraint, aConstraint); + myIsNegative = true; } } -void SketchSolver_ConstraintDistance::update(ConstraintPtr theConstraint) +void SketchSolver_ConstraintDistance::update() { - Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front()); - myPrevValue = aConstraint.valA; - SketchSolver_Constraint::update(theConstraint); + ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front(); + myPrevValue = aConstraint->value(); + + SketchSolver_Constraint::update(); } diff --git a/src/SketchSolver/SketchSolver_ConstraintDistance.h b/src/SketchSolver/SketchSolver_ConstraintDistance.h index 5c1569f9a..b11e0a8a5 100644 --- a/src/SketchSolver/SketchSolver_ConstraintDistance.h +++ b/src/SketchSolver/SketchSolver_ConstraintDistance.h @@ -20,26 +20,23 @@ public: /// Constructor based on SketchPlugin constraint SketchSolver_ConstraintDistance(ConstraintPtr theConstraint) : SketchSolver_Constraint(theConstraint), - myType(SLVS_C_UNKNOWN), myIsNegative(false) {} /// \brief Update constraint - virtual void update(ConstraintPtr theConstraint = ConstraintPtr()); - - virtual int getType() const - {return myType; } + virtual void update(); 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(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(); private: - int myType; ///< type of constraint (applicable: SLVS_C_PT_PT_DISTANCE, SLVS_C_PT_LINE_DISTANCE) double myPrevValue; ///< previous value of distance (for correct calculation of a distance sign) bool myIsNegative; ///< \c true, if the point if placed rightside of line direction (SLVS_C_PT_LINE_DISTANCE only) }; diff --git a/src/SketchSolver/SketchSolver_ConstraintEqual.cpp b/src/SketchSolver/SketchSolver_ConstraintEqual.cpp index e91ca2cf0..a6120533e 100644 --- a/src/SketchSolver/SketchSolver_ConstraintEqual.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintEqual.cpp @@ -1,70 +1,54 @@ #include -#include #include - -void SketchSolver_ConstraintEqual::process() +void SketchSolver_ConstraintEqual::getAttributes( + double& theValue, + std::vector& theAttributes) { - cleanErrorMsg(); - if (!myBaseConstraint || !myStorage || myGroup == 0) { - /// TODO: Put error message here + SketchSolver_Constraint::getAttributes(theValue, theAttributes); + if (!myErrorMsg.empty() || !theAttributes[2] || !theAttributes[3]) { + theAttributes.clear(); 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 quantity of entities of each type int aNbLines = 0; int aNbArcs = 0; int aNbCircs = 0; bool isArcFirst = false; // in line-arc equivalence, the line should be first - std::vector::iterator anEntIter = anEntities.begin(); - for (; anEntIter != anEntities.end(); anEntIter++) { - Slvs_Entity anEnt = myStorage->getEntity(*anEntIter); - if (anEnt.type == SLVS_E_LINE_SEGMENT) - aNbLines++; - else if (anEnt.type == SLVS_E_CIRCLE) - aNbCircs++; - else if (anEnt.type == SLVS_E_ARC_OF_CIRCLE) { - aNbArcs++; + std::vector::iterator anAttrIt = theAttributes.begin() + 2; + for (; anAttrIt != theAttributes.end(); ++anAttrIt) { + SketchSolver_EntityType aType = (*anAttrIt)->type(); + if (aType == ENTITY_LINE) + ++aNbLines; + else if (aType == ENTITY_CIRCLE) + ++aNbCircs; + else if (aType == ENTITY_ARC) { + ++aNbArcs; isArcFirst = (aNbLines == 0); } } if (aNbLines + aNbArcs + aNbCircs != 2 || - (aNbLines == aNbCircs && aNbArcs == 0)) { + (aNbLines == aNbCircs && aNbArcs == 0)) { myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); return; } switch (aNbLines) { case 0: - myType = SLVS_C_EQUAL_RADIUS; + myType = CONSTRAINT_EQUAL_RADIUS; break; case 1: - myType = SLVS_C_EQUAL_LINE_ARC_LEN; + myType = CONSTRAINT_EQUAL_LINE_ARC; if (isArcFirst) { // change the order of arc and line - Slvs_hEntity aTmp = anEntities[2]; - anEntities[2] = anEntities[3]; - anEntities[3] = aTmp; + EntityWrapperPtr aTmp = theAttributes[2]; + theAttributes[2] = theAttributes[3]; + theAttributes[3] = aTmp; } break; default: - myType = SLVS_C_EQUAL_LENGTH_LINES; + myType = CONSTRAINT_EQUAL_LINES; break; } - - Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(), - getType(), myGroup->getWorkplaneId(), aValue, - anEntities[0], anEntities[1], anEntities[2], anEntities[3]); - aConstraint.h = myStorage->addConstraint(aConstraint); - mySlvsConstraints.push_back(aConstraint.h); - adjustConstraint(); } - diff --git a/src/SketchSolver/SketchSolver_ConstraintEqual.h b/src/SketchSolver/SketchSolver_ConstraintEqual.h index 2aca9c850..12e6a334e 100644 --- a/src/SketchSolver/SketchSolver_ConstraintEqual.h +++ b/src/SketchSolver/SketchSolver_ConstraintEqual.h @@ -22,15 +22,11 @@ public: SketchSolver_Constraint(theConstraint) {} - virtual int getType() const - { return myType; } - protected: - /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints - virtual void process(); - -private: - int myType; ///< type of constraint (applicable: SLVS_C_EQUAL_LENGTH_LINES, SLVS_C_EQUAL_RADIUS, SLVS_C_EQUAL_LINE_ARC_LEN) + /// \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(double& theValue, std::vector& theAttributes); }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintFillet.cpp b/src/SketchSolver/SketchSolver_ConstraintFillet.cpp deleted file mode 100644 index 3d53b9010..000000000 --- a/src/SketchSolver/SketchSolver_ConstraintFillet.cpp +++ /dev/null @@ -1,208 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include - - -void SketchSolver_ConstraintFillet::getAttributes( - double& theValue, std::vector& theAttributes) -{ - theAttributes.clear(); - - DataPtr aData = myBaseConstraint->data(); - AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Constraint::VALUE())); - theValue = aValueAttr ? aValueAttr->value() : 0.0; - - std::list aBaseAttrs = aData->attributes(ModelAPI_AttributeRefAttr::typeId()); - std::list::iterator anIter = aBaseAttrs.begin(); - for (; anIter != aBaseAttrs.end(); anIter++) { - AttributeRefAttrPtr aRefAttr = - std::dynamic_pointer_cast(*anIter); - if (!aRefAttr || !aRefAttr->isInitialized()) { - myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); - return; - } - - int aType = SLVS_E_UNKNOWN; // type of created entity - Slvs_hEntity anEntity = myGroup->getAttributeId(aRefAttr); - if (anEntity == SLVS_E_UNKNOWN) - anEntity = changeEntity(aRefAttr, aType); - - if (aType == SLVS_E_UNKNOWN) - continue; - theAttributes.push_back(anEntity); - } - - // Fillet objects - AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Constraint::ENTITY_C())); - if (!aFilletRefList || !aFilletRefList->isInitialized()) { - myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); - return; - } - std::list aFilletList = aFilletRefList->list(); - if (aFilletList.size() < theAttributes.size() + 1) { - myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); - return; - } - FeaturePtr aFilletFeature; - ResultConstructionPtr aRC; - int aType; - std::list::iterator aFilIter = aFilletList.begin(); - for (int indEnt = 0; aFilIter != aFilletList.end(); aFilIter++, indEnt++) { - aRC = std::dynamic_pointer_cast(*aFilIter); - aFilletFeature = aRC ? aRC->document()->feature(aRC) : - std::dynamic_pointer_cast(*aFilIter); - if (!aFilletFeature) { - myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); - return; - } - Slvs_hEntity anEntity = changeEntity(aFilletFeature, aType); - theAttributes.push_back(anEntity); - } -} - -void SketchSolver_ConstraintFillet::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 anEntID; - getAttributes(aValue, anEntID); - if (!myErrorMsg.empty()) - return; - - // Obtain the entities itself: - // First two are base entities - // Second two are trimmed them - // Last one is a fillet arc - std::vector anEntities; - std::vector::iterator anIt = anEntID.begin(); - for (; anIt != anEntID.end(); anIt++) - anEntities.push_back(myStorage->getEntity(*anIt)); - - // Check the base entities have a coincident point - Slvs_hEntity aPointsToFind[4]; - for (int i = 0; i < 2; i++) { - int aShift = anEntities[i].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0; - aPointsToFind[2*i] = anEntities[i].point[aShift]; - aPointsToFind[2*i+1]= anEntities[i].point[aShift+1]; - } - // Search coincident points - int aCoincInd[2]; // indices of coincident points on each entity (0 - first, 1 - last) - bool isPointFound = false; - for (int i = 0; i < 2 && !isPointFound; i++) - for (int j = 2; j < 4 && !isPointFound; j++) - if (myStorage->isEqual(aPointsToFind[i], aPointsToFind[j])) { - aCoincInd[0] = i; - aCoincInd[1] = j - 2; - isPointFound = true; - } - if (!isPointFound) { - // There is no coincident points between tangential objects. Generate error message - myErrorMsg = SketchSolver_Error::NO_COINCIDENT_POINTS(); - return; - } - - // For correct result, move floating points of fillet on the middle points of base objects - Slvs_Entity aPoint; - Slvs_Param aParam; - double anArcPoints[3][2]; - for (int i = 0; i < 2; i++) { - calculateMiddlePoint(anEntities[i], 0.1 + 0.8 * aCoincInd[i], anArcPoints[i+1][0], anArcPoints[i+1][1]); - aPoint = myStorage->getEntity(anEntities[i+2].point[aCoincInd[i]]); - for (int j = 0; j < 2; j++) { - aParam = myStorage->getParameter(aPoint.param[j]); - aParam.val = anArcPoints[i+1][j]; - aPoint.param[j] = myStorage->updateParameter(aParam); - } - } - anArcPoints[0][0] = 0.5 * (anArcPoints[1][0] + anArcPoints[2][0]); - anArcPoints[0][1] = 0.5 * (anArcPoints[1][1] + anArcPoints[2][1]); - // Check the arc is need to be reversed - double aSharedPoint[2]; - aPoint = myStorage->getEntity(aPointsToFind[aCoincInd[0]]); - for (int j = 0; j < 2; j++) - aSharedPoint[j] = myStorage->getParameter(aPoint.param[j]).val; - double aCross = (anArcPoints[1][0] - anArcPoints[0][0]) * (aSharedPoint[1] - anArcPoints[0][1]) - - (anArcPoints[1][1] - anArcPoints[0][1]) * (aSharedPoint[0] - anArcPoints[0][0]); - if (aCross < 0.0) { // reverse fillet arc - double aTmp; - for (int j = 0; j < 2; j++) { - aTmp = anArcPoints[1][j]; - anArcPoints[1][j] = anArcPoints[2][j]; - anArcPoints[2][j] = aTmp; - } - } - // update fillet arc coordinates - for (int indArcPt = 0; indArcPt < 3; indArcPt++) { - aPoint = myStorage->getEntity(anEntities.back().point[indArcPt]); - for (int j = 0; j < 2; j++) { - aParam = myStorage->getParameter(aPoint.param[j]); - aParam.val = anArcPoints[indArcPt][j]; - aPoint.param[j] = myStorage->updateParameter(aParam); - } - } - - for (int indEnt = 0; indEnt < 2; indEnt++) { - int aShift = anEntities[indEnt].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0; - // one point of fillet object should be coincident with the point on base, non-coincident with another base object - Slvs_hEntity aBaseID = anEntities[indEnt].point[1 - aCoincInd[indEnt] + aShift]; - Slvs_hEntity aFilletID = anEntities[2 + indEnt].point[1 - aCoincInd[indEnt] + aShift]; - Slvs_Constraint aCoincConstr = Slvs_MakeConstraint( - SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(), - 0.0, aBaseID, aFilletID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - aCoincConstr.h = myStorage->addConstraint(aCoincConstr); - mySlvsConstraints.push_back(aCoincConstr.h); - - // another point of fillet object should be placed on the base object - Slvs_Constraint aPonCurveConstr; - if (anEntities[indEnt].type == SLVS_E_ARC_OF_CIRCLE) { - // centers of arcs should be coincident - aBaseID = anEntities[indEnt].point[0]; - aFilletID = anEntities[2 + indEnt].point[0]; - aPonCurveConstr = Slvs_MakeConstraint( - SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(), - 0.0, aBaseID, aFilletID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - } else { - aFilletID = anEntities[2 + indEnt].point[aCoincInd[indEnt]]; - aPonCurveConstr = Slvs_MakeConstraint( - SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_ON_LINE, myGroup->getWorkplaneId(), - 0.0, aFilletID, SLVS_E_UNKNOWN, anEntities[indEnt].h, SLVS_E_UNKNOWN); - } - aPonCurveConstr.h = myStorage->addConstraint(aPonCurveConstr); - mySlvsConstraints.push_back(aPonCurveConstr.h); - } -} - -bool SketchSolver_ConstraintFillet::remove(ConstraintPtr theConstraint) -{ - cleanErrorMsg(); - if (theConstraint && theConstraint != myBaseConstraint) - return false; - bool isFullyRemoved = true; - std::vector::iterator aCIter = mySlvsConstraints.begin(); - for (; aCIter != mySlvsConstraints.end(); aCIter++) - isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved; - mySlvsConstraints.clear(); - - if (isFullyRemoved) { - myFeatureMap.clear(); - myAttributeMap.clear(); - myValueMap.clear(); - } else - cleanRemovedEntities(); - return true; -} - diff --git a/src/SketchSolver/SketchSolver_ConstraintFillet.h b/src/SketchSolver/SketchSolver_ConstraintFillet.h deleted file mode 100644 index 44caaf035..000000000 --- a/src/SketchSolver/SketchSolver_ConstraintFillet.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: SketchSolver_ConstraintFillet.h -// Created: 1 Apr 2015 -// Author: Artem ZHIDKOV - -#ifndef SketchSolver_ConstraintFillet_H_ -#define SketchSolver_ConstraintFillet_H_ - -#include "SketchSolver.h" -#include - -/** \class SketchSolver_ConstraintFillet - * \ingroup Plugins - * \brief Convert fillet constraint to SolveSpace structure - */ -class SketchSolver_ConstraintFillet : public SketchSolver_Constraint -{ -public: - /// Constructor based on SketchPlugin constraint - SketchSolver_ConstraintFillet(ConstraintPtr theConstraint) : - SketchSolver_Constraint(theConstraint) - {} - - virtual int getType() const - { return SLVS_C_FILLET; } - - /// \brief Tries to remove constraint - /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence) - virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr()); - -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 SolveSpace constraints - /// \param[out] theValue numerical characteristic of constraint (e.g. distance) - /// \param[out] theAttributes list of attributes to be filled - /// - /// Parameter theAttributes contains 5 elements: - /// Two first entities in theAttributes list correspond to base features of fillet, - /// the next two entities represent trimmed base features and the last one is a fillet arc. - virtual void getAttributes(double& theValue, std::vector& theAttributes); -}; - -#endif diff --git a/src/SketchSolver/SketchSolver_ConstraintFixed.cpp b/src/SketchSolver/SketchSolver_ConstraintFixed.cpp new file mode 100644 index 000000000..1417bde62 --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintFixed.cpp @@ -0,0 +1,111 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +SketchSolver_ConstraintFixed::SketchSolver_ConstraintFixed(ConstraintPtr theConstraint) + : SketchSolver_Constraint() +{ + myBaseConstraint = theConstraint; + myType = CONSTRAINT_FIXED; + myFixedAttribute = std::dynamic_pointer_cast( + theConstraint->attribute(SketchPlugin_ConstraintRigid::ENTITY_A())); +} + +SketchSolver_ConstraintFixed::SketchSolver_ConstraintFixed(FeaturePtr theFeature) + : SketchSolver_Constraint(), + myBaseFeature(theFeature) +{ + myType = CONSTRAINT_FIXED; + process(); +} + +void SketchSolver_ConstraintFixed::process() +{ + cleanErrorMsg(); + if ((!myBaseConstraint && !myBaseFeature) || !myStorage || myGroupID == GID_UNKNOWN) { + // Not enough parameters are assigned + return; + } + + ParameterWrapperPtr aValue; + std::vector anEntities; + getAttributes(aValue, anEntities); + if (!myErrorMsg.empty() || anEntities.empty()) + return; + fixFeature(anEntities.front()); +} + +void SketchSolver_ConstraintFixed::fixFeature(EntityWrapperPtr theFeature) +{ + // extract feature from the group + if (theFeature->baseAttribute()) + myStorage->update(theFeature->baseAttribute(), GID_OUTOFGROUP); + else + myStorage->update(theFeature->baseFeature(), GID_OUTOFGROUP); +} + +void SketchSolver_ConstraintFixed::getAttributes( + ParameterWrapperPtr& theValue, + std::vector& theAttributes) +{ + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + + EntityWrapperPtr aSolverEntity; + if (myBaseFeature) { + // The feature is fixed. + myStorage->update(myBaseFeature, myGroupID); + aSolverEntity = myStorage->entity(myBaseFeature); + } else if (myBaseConstraint) { + // Constraint Fixed is added by user. + // Get the attribute of constraint (it should be alone in the list of constraints). + AttributePtr anAttr = myBaseConstraint->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()); + AttributeRefAttrPtr aRefAttr = + std::dynamic_pointer_cast(anAttr); + if (!aRefAttr || !aRefAttr->isInitialized()) { + myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); + return; + } + + myStorage->update(anAttr, myGroupID); + aSolverEntity = myStorage->entity(anAttr); + } else + myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); + + if (aSolverEntity) + theAttributes.push_back(aSolverEntity); +} + + +bool SketchSolver_ConstraintFixed::remove() +{ + cleanErrorMsg(); + // Move fixed entities back to the current group + FeaturePtr aFeature = myBaseFeature; + if (myBaseConstraint && myFixedAttribute && myFixedAttribute->isObject()) + aFeature = ModelAPI_Feature::feature(myFixedAttribute->object()); + if (aFeature) + myStorage->update(aFeature, myGroupID); + + // Remove constraint or base feature + if (myBaseConstraint) { + bool isRemoved = false; + if (aFeature) + isRemoved = myStorage->removeEntity(aFeature); + return SketchSolver_Constraint::remove() || isRemoved; + } else if (myBaseFeature) + myStorage->removeEntity(myBaseFeature); + return true; +} diff --git a/src/SketchSolver/SketchSolver_ConstraintFixed.h b/src/SketchSolver/SketchSolver_ConstraintFixed.h new file mode 100644 index 000000000..518683755 --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintFixed.h @@ -0,0 +1,55 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_ConstraintFixed.h +// Created: 30 Mar 2015 +// Author: Artem ZHIDKOV + +#ifndef SketchSolver_ConstraintFixed_H_ +#define SketchSolver_ConstraintFixed_H_ + +#include "SketchSolver.h" +#include + +/** \class SketchSolver_ConstraintFixed + * \ingroup Plugins + * \brief Stores data of the Fixed constraint + * + * Fixed constraint may have NULL basic SketchPlugin constraint, + * because the Fixed constraint may be temporary for correct moving of objects. + * + * Fixed constraint does not create a constraint, but builds the entities in separate group, + * so they will not be moved while resolving the set of constraints. + */ +class SketchSolver_ConstraintFixed : public SketchSolver_Constraint +{ +public: + /// Creates constraint to manage the given constraint from plugin + SketchSolver_ConstraintFixed(ConstraintPtr theConstraint); + /// Creates temporary constraint based on feature + SketchSolver_ConstraintFixed(FeaturePtr theFeature); + + /// \brief Tries to remove constraint + /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence) + virtual bool remove(); + +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(ParameterWrapperPtr& theValue, std::vector& theAttributes); + + /// \brief Fixed feature basing on its type + /// \param theFeature [in] feature, converted to solver specific format + virtual void fixFeature(EntityWrapperPtr theFeature); + +protected: + FeaturePtr myBaseFeature; ///< fixed feature (when it is set, myBaseConstraint should be NULL) + +private: + AttributeRefAttrPtr myFixedAttribute; ///< attribute of a fixed constraint (for correct remove) +}; + +#endif diff --git a/src/SketchSolver/SketchSolver_ConstraintLength.cpp b/src/SketchSolver/SketchSolver_ConstraintLength.cpp index 06d854d17..5c3bbc088 100644 --- a/src/SketchSolver/SketchSolver_ConstraintLength.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintLength.cpp @@ -1,44 +1,26 @@ #include -#include #include -void SketchSolver_ConstraintLength::process() +void SketchSolver_ConstraintLength::getAttributes( + double& theValue, + std::vector& theAttributes) { - cleanErrorMsg(); - if (!myBaseConstraint || !myStorage || myGroup == 0) { - /// TODO: Put error message here + SketchSolver_Constraint::getAttributes(theValue, theAttributes); + if (!myErrorMsg.empty() || !theAttributes[2] || + theAttributes[2]->type() != ENTITY_LINE) { + theAttributes.clear(); 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; - } + // Get boundary points of line segment and create point-point distance constraint + std::list aSubs = theAttributes[2]->subEntities(); + theAttributes.assign(theAttributes.size(), EntityWrapperPtr()); + std::vector::iterator anAttrIt = theAttributes.begin(); + std::list::const_iterator aSubIt = aSubs.begin(); + for (; aSubIt != aSubs.end(); ++aSubIt, ++anAttrIt) + *anAttrIt = *aSubIt; - 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(); -} - -void SketchSolver_ConstraintLength::adjustConstraint() -{ - // No need to store the line, which length is constrained - // Upd: The line need to be stored to check that constraint - // is changed/unchanged during modifications in GUI - //myFeatureMap.clear(); + myType = CONSTRAINT_PT_PT_DISTANCE; } diff --git a/src/SketchSolver/SketchSolver_ConstraintLength.h b/src/SketchSolver/SketchSolver_ConstraintLength.h index f9c0da65c..0899d8b73 100644 --- a/src/SketchSolver/SketchSolver_ConstraintLength.h +++ b/src/SketchSolver/SketchSolver_ConstraintLength.h @@ -22,16 +22,11 @@ public: 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(); - - /// \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 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(double& theValue, std::vector& theAttributes); }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintMirror.cpp b/src/SketchSolver/SketchSolver_ConstraintMirror.cpp index 9d1477545..c496b719d 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMirror.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMirror.cpp @@ -1,34 +1,25 @@ #include -#include #include +#include -#include -#include #include -#include - -#include -#include - -#include void SketchSolver_ConstraintMirror::getAttributes( - Slvs_Entity& theMirrorLine, - std::vector& theBaseEntities, - std::vector& theMirrorEntities) + EntityWrapperPtr& theMirrorLine, + std::vector& theBaseEntities, + std::vector& theMirrorEntities) { - DataPtr aData = myBaseConstraint->data(); - AttributeRefAttrPtr aMirLineAttr = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - if (!aMirLineAttr || !aMirLineAttr->isInitialized() || !aMirLineAttr->isObject()) { + AttributePtr aMirLineAttr = myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()); + AttributeRefAttrPtr aMirLineRefAttr = + std::dynamic_pointer_cast(aMirLineAttr); + if (!aMirLineRefAttr || !aMirLineRefAttr->isInitialized() || !aMirLineRefAttr->isObject()) { myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); return; } - int aType = SLVS_E_UNKNOWN; // type of created entity - Slvs_hEntity anEntity = myGroup->getAttributeId(aMirLineAttr); - if (anEntity == SLVS_E_UNKNOWN) - anEntity = changeEntity(aMirLineAttr, aType); - theMirrorLine = myStorage->getEntity(anEntity); + + myType = TYPE(myBaseConstraint); + myStorage->update(aMirLineAttr, myGroupID); + theMirrorLine = myStorage->entity(aMirLineAttr); // Create SolveSpace entity for all features AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast( @@ -45,26 +36,17 @@ void SketchSolver_ConstraintMirror::getAttributes( std::list aMirroredList = aMirroredRefList->list(); FeaturePtr aFeature; - ResultConstructionPtr aRC; for (int i = 0; i < 2; i++) { std::list::iterator anIter = i == 0 ? aBaseList.begin() : aMirroredList.begin(); std::list::iterator aEndIter = i == 0 ? aBaseList.end() : aMirroredList.end(); - std::vector* aList = i == 0 ? &theBaseEntities : & theMirrorEntities; + std::vector* aList = i == 0 ? &theBaseEntities : & theMirrorEntities; for ( ; anIter != aEndIter; anIter++) { - aRC = std::dynamic_pointer_cast(*anIter); - aFeature = aRC ? aRC->document()->feature(aRC) : - std::dynamic_pointer_cast(*anIter); + aFeature = ModelAPI_Feature::feature(*anIter); if (!aFeature) continue; - anEntity = changeEntity(aFeature, aType); - // Sort entities by their type - std::vector::iterator anIt = aList->begin(); - for (; anIt != aList->end(); anIt++) - if (aType < anIt->type) - break; -// aList->push_back(myStorage->getEntity(anEntity)); - aList->insert(anIt, myStorage->getEntity(anEntity)); + myStorage->update(aFeature, myGroupID); + aList->push_back(myStorage->entity(aFeature)); } } @@ -75,16 +57,14 @@ void SketchSolver_ConstraintMirror::getAttributes( void SketchSolver_ConstraintMirror::process() { cleanErrorMsg(); - if (!myBaseConstraint || !myStorage || myGroup == 0) { - /// TODO: Put error message here + if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) { + // Not enough parameters are assigned return; } - if (!mySlvsConstraints.empty()) // some data is changed, update constraint - update(myBaseConstraint); - Slvs_Entity aMirrorLine; - std::vector aBaseList; - std::vector aMirrorList; + EntityWrapperPtr aMirrorLine; + std::vector aBaseList; + std::vector aMirrorList; getAttributes(aMirrorLine, aBaseList, aMirrorList); if (!myErrorMsg.empty()) return; @@ -94,389 +74,61 @@ void SketchSolver_ConstraintMirror::process() return; } - Slvs_Constraint aConstraint; - // Get coordinates of mirror line points for speed up - double aStartEnd[4]; - for (int i = 0; i < 2; i++) { - Slvs_Entity aPoint = myStorage->getEntity(aMirrorLine.point[i]); - for (int j = 0; j < 2; j++) - aStartEnd[2*i+j] = myStorage->getParameter(aPoint.param[j]).val; - } - - std::vector::iterator aBaseIter = aBaseList.begin(); - std::vector::iterator aMirrorIter = aMirrorList.begin(); - for (; aBaseIter != aBaseList.end(); aBaseIter++, aMirrorIter++) { - // Make aMirrorEnt parameters to be symmetric with aBaseEnt - makeMirrorEntity(*aBaseIter, *aMirrorIter, aStartEnd); - - if (aBaseIter->type == SLVS_E_POINT_IN_2D) { - aConstraint = Slvs_MakeConstraint( - SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), - 0.0, aBaseIter->h, aMirrorIter->h, aMirrorLine.h, SLVS_E_UNKNOWN); - aConstraint.h = myStorage->addConstraint(aConstraint); - mySlvsConstraints.push_back(aConstraint.h); - } else if (aBaseIter->type == SLVS_E_LINE_SEGMENT) { - for (int i = 0; i < 2; i++) { - aConstraint = Slvs_MakeConstraint( - SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0, - aBaseIter->point[i], aMirrorIter->point[i], aMirrorLine.h, SLVS_E_UNKNOWN); - aConstraint.h = myStorage->addConstraint(aConstraint); - mySlvsConstraints.push_back(aConstraint.h); - } - } else if (aBaseIter->type == SLVS_E_CIRCLE) { - aConstraint = Slvs_MakeConstraint( - SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0, - aBaseIter->point[0], aMirrorIter->point[0], aMirrorLine.h, SLVS_E_UNKNOWN); - aConstraint.h = myStorage->addConstraint(aConstraint); - mySlvsConstraints.push_back(aConstraint.h); - // Additional constraint for equal radii - Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint( - SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_EQUAL_RADIUS, myGroup->getWorkplaneId(), - 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseIter->h, aMirrorIter->h); - anEqRadConstr.h = myStorage->addConstraint(anEqRadConstr); - mySlvsConstraints.push_back(anEqRadConstr.h); - } else if (aBaseIter->type == SLVS_E_ARC_OF_CIRCLE) { - // Workaround to avoid problems in SolveSpace. - // The symmetry of two arcs will be done using symmetry of three points on these arcs: - // start point, end point, and any other point on the arc - Slvs_hEntity aBaseArcPoints[3] = { - aBaseIter->point[1], - aBaseIter->point[2], - SLVS_E_UNKNOWN}; - Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point - aMirrorIter->point[2], - aMirrorIter->point[1], - SLVS_E_UNKNOWN}; - - Slvs_Entity aBothArcs[2] = {*aBaseIter, *aMirrorIter}; - Slvs_hEntity aBothMiddlePoints[2]; - for (int i = 0; i < 2; i++) { - double x, y; - calculateMiddlePoint(aBothArcs[i], 0.5, x, y); - Slvs_Param aParamX = Slvs_MakeParam(SLVS_E_UNKNOWN, myGroup->getId(), x); - Slvs_Param aParamY = Slvs_MakeParam(SLVS_E_UNKNOWN, myGroup->getId(), y); - aParamX.h = myStorage->addParameter(aParamX); - aParamY.h = myStorage->addParameter(aParamY); - Slvs_Entity aPoint = Slvs_MakePoint2d(SLVS_E_UNKNOWN, myGroup->getId(), - myGroup->getWorkplaneId(), aParamX.h, aParamY.h); - aBothMiddlePoints[i] = myStorage->addEntity(aPoint); - // additional constraint point-on-curve - Slvs_Constraint aPonCircConstr = Slvs_MakeConstraint( - SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_ON_CIRCLE, myGroup->getWorkplaneId(), - 0.0, aBothMiddlePoints[i], SLVS_E_UNKNOWN, aBothArcs[i].h, SLVS_E_UNKNOWN); - aPonCircConstr.h = myStorage->addConstraint(aPonCircConstr); - mySlvsConstraints.push_back(aPonCircConstr.h); - if (i == 0) { - // additional constraint for the point to be in the middle of a base arc - Slvs_Entity aLine1 = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(), - myGroup->getWorkplaneId(), aBothArcs[i].point[1], aBothMiddlePoints[i]); - aLine1.h = myStorage->addEntity(aLine1); - Slvs_Entity aLine2 = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(), - myGroup->getWorkplaneId(), aBothArcs[i].point[2], aBothMiddlePoints[i]); - aLine2.h = myStorage->addEntity(aLine2); - Slvs_Constraint aMiddleConstr = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), - SLVS_C_EQUAL_LENGTH_LINES, myGroup->getWorkplaneId(), - 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aLine1.h, aLine2.h); - aMiddleConstr.h = myStorage->addConstraint(aMiddleConstr); - mySlvsConstraints.push_back(aMiddleConstr.h); - } - } - - aBaseArcPoints[2] = aBothMiddlePoints[0]; - aMirrorArcPoints[2] = aBothMiddlePoints[1]; - for (int ind = 0; ind < 3; ind++) { - Slvs_Constraint aConstraint = Slvs_MakeConstraint( - SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0, - aBaseArcPoints[ind], aMirrorArcPoints[ind], aMirrorLine.h, SLVS_E_UNKNOWN); - aConstraint.h = myStorage->addConstraint(aConstraint); - mySlvsConstraints.push_back(aConstraint.h); - } + std::list aNewConstraints; + SketchSolver_ConstraintType aConstrType = getType(); + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + std::list aMirConstrList; + + std::vector::iterator aBIt = aBaseList.begin(); + std::vector::iterator aMIt = aMirrorList.begin(); + for (; aBIt != aBaseList.end(); ++aBIt, ++aMIt) { + if ((*aBIt)->type() == ENTITY_ARC) { + // add new points on arcs and mirror them + EntityWrapperPtr aBasePnt = myStorage->calculateMiddlePoint(*aBIt, 0.5); + EntityWrapperPtr aMirrPnt = myStorage->calculateMiddlePoint(*aMIt, 0.5); + // point on base arc + aNewConstraints = aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID, + CONSTRAINT_PT_ON_CIRCLE, 0.0, aBasePnt, EntityWrapperPtr(), *aBIt); + aMirConstrList.insert(aMirConstrList.end(), aNewConstraints.begin(), aNewConstraints.end()); + // point on mirrored arc + aNewConstraints = aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID, + CONSTRAINT_PT_ON_CIRCLE, 0.0, aMirrPnt, EntityWrapperPtr(), *aMIt); + aMirConstrList.insert(aMirConstrList.end(), aNewConstraints.begin(), aNewConstraints.end()); + // mirror these points + aNewConstraints = aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID, + aConstrType, 0.0, aBasePnt, aMirrPnt, aMirrorLine); + aMirConstrList.insert(aMirConstrList.end(), aNewConstraints.begin(), aNewConstraints.end()); } + aNewConstraints = aBuilder->createConstraint( + myBaseConstraint, myGroupID, mySketchID, aConstrType, + 0.0, *aBIt, *aMIt, aMirrorLine); + aMirConstrList.insert(aMirConstrList.end(), aNewConstraints.begin(), aNewConstraints.end()); } + + myStorage->addConstraint(myBaseConstraint, aMirConstrList); } -void SketchSolver_ConstraintMirror::update(ConstraintPtr theConstraint) +void SketchSolver_ConstraintMirror::update() { cleanErrorMsg(); - if (!theConstraint || theConstraint == myBaseConstraint) { - AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_C())); - if (aMirroredRefList->size() != myNumberOfObjects) { - remove(myBaseConstraint); - process(); - return; - } + AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast( + myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_C())); + if (aMirroredRefList->size() != myNumberOfObjects) { + remove(); + process(); + return; } SketchSolver_Constraint::update(); } -bool SketchSolver_ConstraintMirror::remove(ConstraintPtr theConstraint) -{ - cleanErrorMsg(); - if (theConstraint && theConstraint != myBaseConstraint) - return false; - bool isFullyRemoved = true; - std::vector::iterator aCIter = mySlvsConstraints.begin(); - for (; aCIter != mySlvsConstraints.end(); aCIter++) - isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved; - mySlvsConstraints.clear(); - - std::map::iterator aFeatIt = myFeatureMap.begin(); - for (; aFeatIt != myFeatureMap.end(); aFeatIt++) - myStorage->removeEntity(aFeatIt->second); - - if (isFullyRemoved) { - myFeatureMap.clear(); - myAttributeMap.clear(); - myValueMap.clear(); - } else - cleanRemovedEntities(); - return true; -} - -bool SketchSolver_ConstraintMirror::checkAttributesChanged(ConstraintPtr theConstraint) -{ - // First of all, check the mirror line is changed. - // It may be changed to one of mirrored lines, which is already in this constraint - // (this case is not marked as attribute changing) - ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint; - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - if (!aRefAttr || !aRefAttr->isObject() || !aRefAttr->object()) - return true; - FeaturePtr aMirrorLine = ModelAPI_Feature::feature(aRefAttr->object()); - if (!aMirrorLine) - return true; - - std::map::iterator aMirrorIter = myFeatureMap.find(aMirrorLine); - if (aMirrorIter == myFeatureMap.end()) - return true; - - // Check the entity is not used as mirror line - std::vector::iterator aCIter = mySlvsConstraints.begin(); - for (; aCIter != mySlvsConstraints.end(); aCIter++) { - Slvs_Constraint aMirrorConstr = myStorage->getConstraint(*aCIter); - if (aMirrorConstr.type != SLVS_C_SYMMETRIC_LINE) - continue; - if (aMirrorConstr.entityA != aMirrorIter->second) - return true; - else break; // check just one symmetric constraint - } - - // Base verification - return SketchSolver_Constraint::checkAttributesChanged(theConstraint); -} - -void SketchSolver_ConstraintMirror::makeMirrorEntity( - const Slvs_Entity& theBase, - const Slvs_Entity& theMirror, - const double theMirrorLine[]) const -{ - Slvs_hEntity aBasePoint[4]; - Slvs_hEntity aMirrorPoint[4]; - for (int i = 0; i < 4; i++) { - aBasePoint[i] = theBase.point[i]; - aMirrorPoint[i] = theMirror.point[i]; - } - if (theBase.type == SLVS_E_ARC_OF_CIRCLE) { - Slvs_hEntity aTmp = aMirrorPoint[2]; - aMirrorPoint[2] = aMirrorPoint[1]; - aMirrorPoint[1] = aTmp; - adjustArcPoints(theBase); - } - if (theBase.type == SLVS_E_POINT_IN_2D || theBase.type == SLVS_E_POINT_IN_3D) { - aBasePoint[0] = theBase.h; - aMirrorPoint[0] = theMirror.h; - } - - // Mirror line parameters - std::shared_ptr aLinePoints[2]; - for (int i = 0; i < 2; i++) - aLinePoints[i] = std::shared_ptr( - new GeomAPI_XY(theMirrorLine[2*i], theMirrorLine[2*i+1])); - // direction of a mirror line - std::shared_ptr aDir = std::shared_ptr( - new GeomAPI_Dir2d(aLinePoints[1]->added(aLinePoints[0]->multiplied(-1.0)))); - // orthogonal direction - aDir = std::shared_ptr(new GeomAPI_Dir2d(aDir->y(), -aDir->x())); - - Slvs_hConstraint aFixed; // transient variable - for (int i = 0; i < 4; i++) { - if (aBasePoint[i] == SLVS_E_UNKNOWN || aMirrorPoint[i] == SLVS_E_UNKNOWN) - continue; - // check the mirror point is not fixed - if (myStorage->isPointFixed(aMirrorPoint[i], aFixed, true)) - continue; - - Slvs_Entity aPointEnt = myStorage->getEntity(aBasePoint[i]); - double aBaseX = myStorage->getParameter(aPointEnt.param[0]).val; - double aBaseY = myStorage->getParameter(aPointEnt.param[1]).val; - std::shared_ptr aPoint = std::shared_ptr(new GeomAPI_XY(aBaseX, aBaseY)); - - std::shared_ptr aVec = std::shared_ptr( - new GeomAPI_XY(aPoint->x() - aLinePoints[0]->x(), aPoint->y() - aLinePoints[0]->y())); - double aDist = aVec->dot(aDir->xy()); - aPoint = aPoint->added(aDir->xy()->multiplied(-2.0 * aDist)); - - Slvs_Entity aMirrorEnt = myStorage->getEntity(aMirrorPoint[i]); - Slvs_Param aParam = Slvs_MakeParam(aMirrorEnt.param[0], myGroup->getId(), aPoint->x()); - myStorage->updateParameter(aParam); - aParam = Slvs_MakeParam(aMirrorEnt.param[1], myGroup->getId(), aPoint->y()); - myStorage->updateParameter(aParam); - } -} - -void SketchSolver_ConstraintMirror::adjustArcPoints(const Slvs_Entity& theArc) const -{ - Slvs_Param aParam; - Slvs_Entity aPoint; - double anArcParams[3][2]; - for (int i = 0; i < 3; i++) { - aPoint = myStorage->getEntity(theArc.point[i]); - for (int j = 0; j < 2; j++) { - aParam = myStorage->getParameter(aPoint.param[j]); - anArcParams[i][j] = aParam.val; - if (i > 0) - anArcParams[i][j] -= anArcParams[0][j]; - } - } - double aRad2 = anArcParams[1][0] * anArcParams[1][0] + anArcParams[1][1] * anArcParams[1][1]; - double aDist2 = anArcParams[2][0] * anArcParams[2][0] + anArcParams[2][1] * anArcParams[2][1]; - if (std::fabs(aRad2 - aDist2) < tolerance) - return; // nothing to update (last point already on the arc) - if (aDist2 < tolerance) - return; // unable to update - double aCoeff = std::sqrt(aRad2 / aDist2); - anArcParams[2][0] *= aCoeff; - anArcParams[2][1] *= aCoeff; - - // Update last point - aPoint = myStorage->getEntity(theArc.point[2]); - for (int i = 0; i < 2; i++) { - aParam = Slvs_MakeParam(aPoint.param[i], myGroup->getId(), - anArcParams[0][i] + anArcParams[2][i]); - myStorage->updateParameter(aParam); - } -} - void SketchSolver_ConstraintMirror::adjustConstraint() { - AttributeRefAttrPtr aMirLineAttr = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - if (!aMirLineAttr || !aMirLineAttr->isInitialized() || !aMirLineAttr->isObject()) { - myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); - return; - } - ResultConstructionPtr aRC = - std::dynamic_pointer_cast(aMirLineAttr->object()); - FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) : - std::dynamic_pointer_cast(aMirLineAttr->object()); - std::map::iterator aMirLineIter = myFeatureMap.find(aFeature); - if (aMirLineIter == myFeatureMap.end()) - return; - Slvs_Entity aMirrorLine = myStorage->getEntity(aMirLineIter->second); - - Slvs_Constraint aMirror; - double aStartEnd[4]; - for (int i = 0; i < 2; i++) { - Slvs_Entity aPoint = myStorage->getEntity(aMirrorLine.point[i]); - for (int j = 0; j < 2; j++) - aStartEnd[2*i+j] = myStorage->getParameter(aPoint.param[j]).val; - } + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - // Calculate length of the mirror line and create temporary constraint - double aLength = sqrt((aStartEnd[2] - aStartEnd[0]) * (aStartEnd[2] - aStartEnd[0]) + - (aStartEnd[3] - aStartEnd[1]) * (aStartEnd[3] - aStartEnd[1])); - if (aLength < tolerance) { - if (myMirrorLineLength < 1.0) - myMirrorLineLength = 1.0; - } else - myMirrorLineLength = aLength; - std::list aDist = myStorage->getConstraintsByType(SLVS_C_PT_PT_DISTANCE); - std::list::const_iterator aDIt = aDist.begin(); - for (; aDIt != aDist.end(); ++aDIt) - if ((aDIt->ptA == aMirrorLine.point[0] && aDIt->ptB == aMirrorLine.point[1]) || - (aDIt->ptA == aMirrorLine.point[1] && aDIt->ptB == aMirrorLine.point[0])) - break; // length of mirror line is already set - if (aDIt == aDist.end()) { - // check the points of mirror line is not fixed - Slvs_hConstraint aFixed; - if (!myStorage->isPointFixed(aMirrorLine.point[0], aFixed, true) || - !myStorage->isPointFixed(aMirrorLine.point[1], aFixed, true)) { - // Add length constraint - aMirror = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_PT_DISTANCE, - myGroup->getWorkplaneId(), aLength, aMirrorLine.point[0], aMirrorLine.point[1], - SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - aMirror.h = myStorage->addConstraint(aMirror); - myStorage->addTemporaryConstraint(aMirror.h); - } - } - - // Search mirror between middle points on the arcs and recompute their coordinates - std::map aPointsOnCircles; - std::list aMirrorPonCirc; - std::list aPonCirc = myStorage->getConstraintsByType(SLVS_C_PT_ON_CIRCLE); - std::vector::iterator aConstrIter = mySlvsConstraints.begin(); - for (; aConstrIter != mySlvsConstraints.end(); aConstrIter++) { - aMirror = myStorage->getConstraint(*aConstrIter); - if (aMirror.type != SLVS_C_SYMMETRIC_LINE) - continue; - if (aMirror.entityA != aMirrorLine.h) - continue; // don't update another Mirror constraints - Slvs_Constraint aPonCircA, aPonCircB; - aPonCircA.h = SLVS_E_UNKNOWN; - aPonCircB.h = SLVS_E_UNKNOWN; - std::list::iterator aPtIter = aPonCirc.begin(); - for (; aPtIter != aPonCirc.end(); aPtIter++) { - if (aMirror.ptA == aPtIter->ptA) - aPonCircA = *aPtIter; - if (aMirror.ptB == aPtIter->ptA) - aPonCircB = *aPtIter; - } - if (aPonCircA.h == SLVS_E_UNKNOWN || aPonCircB.h == SLVS_E_UNKNOWN) - continue; - aMirrorPonCirc.push_back(aMirror); - // Store point IDs to avoid their recalculation twice - aPointsOnCircles[aPonCircA.ptA] = aPonCircA.entityA; - aPointsOnCircles[aPonCircB.ptA] = aPonCircB.entityA; - } - - // Recalculate positions of mirroring points - std::list aMirrorList = myStorage->getConstraintsByType(SLVS_C_SYMMETRIC_LINE); - std::list::iterator aMirIter = aMirrorList.begin(); - for (; aMirIter != aMirrorList.end(); aMirIter++) { - if (aMirIter->entityA != aMirrorLine.h) - continue; // don't update another Mirror constraints - if (aPointsOnCircles.find(aMirIter->ptA) != aPointsOnCircles.end()) - continue; // Avoid mirroring points on circles - Slvs_Entity aBase = myStorage->getEntity(aMirIter->ptA); - Slvs_Entity aMirror = myStorage->getEntity(aMirIter->ptB); - makeMirrorEntity(aBase, aMirror, aStartEnd); - } - - bool aNeedToResolve = myStorage->isNeedToResolve(); - for (aMirIter = aMirrorPonCirc.begin(); aMirIter != aMirrorPonCirc.end(); aMirIter++) { - // Make centers of arcs symmetric - Slvs_Entity aBaseArc = myStorage->getEntity(aPointsOnCircles[aMirIter->ptA]); - Slvs_Entity aBasePoint = myStorage->getEntity(aBaseArc.point[0]); - Slvs_Entity aMirrorArc = myStorage->getEntity(aPointsOnCircles[aMirIter->ptB]); - Slvs_Entity aMirrorPoint = myStorage->getEntity(aMirrorArc.point[0]); - makeMirrorEntity(aBasePoint, aMirrorPoint, aStartEnd); - // Calculate middle point for base arc and mirrored point on mirror arc - aBasePoint = myStorage->getEntity(aMirIter->ptA); - Slvs_Param aParamX = myStorage->getParameter(aBasePoint.param[0]); - Slvs_Param aParamY = myStorage->getParameter(aBasePoint.param[1]); - calculateMiddlePoint(aBaseArc, 0.5, aParamX.val, aParamY.val); - myStorage->updateParameter(aParamX); - myStorage->updateParameter(aParamY); - aMirrorPoint = myStorage->getEntity(aMirIter->ptB); - aParamX = myStorage->getParameter(aMirrorPoint.param[0]); - aParamY = myStorage->getParameter(aMirrorPoint.param[1]); - calculateMiddlePoint(aMirrorArc, 0.5, aParamX.val, aParamY.val); - myStorage->updateParameter(aParamX); - myStorage->updateParameter(aParamY); - } - // Restore previous value to avoid looped recalculations of sketch - myStorage->setNeedToResolve(aNeedToResolve); + const std::list& aConstraints = myStorage->constraint(myBaseConstraint); + std::list::const_iterator aCIt = aConstraints.begin(); + for (; aCIt != aConstraints.end(); ++aCIt) + if ((*aCIt)->type() == CONSTRAINT_SYMMETRIC) + aBuilder->adjustConstraint(*aCIt); } diff --git a/src/SketchSolver/SketchSolver_ConstraintMirror.h b/src/SketchSolver/SketchSolver_ConstraintMirror.h index f6aa365eb..9986fc2a0 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMirror.h +++ b/src/SketchSolver/SketchSolver_ConstraintMirror.h @@ -20,60 +20,36 @@ public: /// Constructor based on SketchPlugin constraint SketchSolver_ConstraintMirror(ConstraintPtr theConstraint) : SketchSolver_Constraint(theConstraint), - myNumberOfObjects(0), - myMirrorLineLength(0.0) + myNumberOfObjects(0) {} - virtual int getType() const - { return SLVS_C_SYMMETRIC_LINE; } - /// \brief Update constraint - virtual void update(ConstraintPtr theConstraint = ConstraintPtr()); - - /// \brief Tries to remove constraint - /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence) - virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr()); + virtual void update(); 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 SolveSpace constraints + /// \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(double& theValue, std::vector& theAttributes) + virtual void getAttributes(double& theValue, std::vector& theAttributes) { /* do nothing here */ } - /// \brief Verify the attributes of constraint are changed (and constraint need to rebuild) - /// \param[in] theConstraint constraint, which attributes should be checked (if NULL, the myBaseConstraint is used) - /// \return \c true if some attributes are changed - virtual bool checkAttributesChanged(ConstraintPtr theConstraint); - /// \brief Generate list of entities of mirror constraint /// \param[out] theMirrorLine entity corresponding to mirror line /// \param[out] theBaseEntities list of entities to mirror /// \param[out] theMirrorEntities list of mirrored entities - void getAttributes(Slvs_Entity& theMirrorLine, - std::vector& theBaseEntities, - std::vector& theMirrorEntities); + void getAttributes(EntityWrapperPtr& theMirrorLine, + std::vector& theBaseEntities, + std::vector& theMirrorEntities); /// \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(); -private: - /// \brief Change parameters of entities to be symmetric relative a line, - /// given by array of parameters (coordinates of first and last points) - void makeMirrorEntity(const Slvs_Entity& theBase, - const Slvs_Entity& theMirror, - const double theMirrorLine[]) const; - - /// \brief Precisely update last point to be on arc - void adjustArcPoints(const Slvs_Entity& theArc) const; - private: size_t myNumberOfObjects; ///< number of previously mirrored objects - double myMirrorLineLength; ///< length of mirror line (should be always greater than 0) }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintMovement.cpp b/src/SketchSolver/SketchSolver_ConstraintMovement.cpp index b97d1a754..85542cb42 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMovement.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMovement.cpp @@ -1,176 +1,98 @@ #include #include -#include +#include #include #include #include #include -SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(FeaturePtr theFeature) - : SketchSolver_ConstraintRigid(theFeature) -{ - process(); -} +#include + void SketchSolver_ConstraintMovement::process() { cleanErrorMsg(); - if (!myBaseFeature || !myStorage || myGroup == 0) { - /// TODO: Put error message here + if (!myBaseFeature || !myStorage || myGroupID == GID_UNKNOWN) { + // Not enough parameters are initialized return; } - if (!mySlvsConstraints.empty()) // some data is changed, update constraint - update(myBaseConstraint); - double aValue; - std::vector anEntities; - bool isFullyMoved; - getAttributes(aValue, anEntities, isFullyMoved); - if (!myErrorMsg.empty() || (myFeatureMap.empty() && myAttributeMap.empty())) + ParameterWrapperPtr aValue; + getAttributes(aValue, myMovedEntities); + if (!myErrorMsg.empty() || myMovedEntities.empty()) { + // Nothing to move, clear the feature to avoid changing its group + // after removing the Movement constraint. + myBaseFeature = FeaturePtr(); return; - - if (isFullyMoved) - fixFeature(); - else { - std::vector::iterator anEntIt = anEntities.begin(); - for (; anEntIt != anEntities.end(); ++anEntIt) - fixPoint(*anEntIt); } + + std::vector::iterator anEntIt = myMovedEntities.begin(); + for (; anEntIt != myMovedEntities.end(); ++anEntIt) + fixFeature(*anEntIt); } -void SketchSolver_ConstraintMovement::getAttributes( - double& theValue, - std::vector& theAttributes, - bool& theIsFullyMoved) +static std::list movedEntities( + EntityWrapperPtr theOld, StoragePtr theOldStorage, + EntityWrapperPtr theNew, StoragePtr theNewStorage) { - bool isComplexFeature = false; - theValue = 0.0; - theIsFullyMoved = true; - int aType = SLVS_E_UNKNOWN; // type of created entity - Slvs_hEntity anEntityID = SLVS_E_UNKNOWN; - Slvs_hEntity anEntMaxID = myStorage->entityMaxID(); - anEntityID = myGroup->getFeatureId(myBaseFeature); - if (anEntityID == SLVS_E_UNKNOWN) { - anEntityID = changeEntity(myBaseFeature, aType); - if (anEntityID == SLVS_E_UNKNOWN) { - myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); - return; - } - - // Check the entity is complex - Slvs_Entity anEntity = myStorage->getEntity(anEntityID); - if (anEntity.point[0] != SLVS_E_UNKNOWN) - isComplexFeature = true; - else // simple entity - theAttributes.push_back(anEntityID); + bool isFullyMoved = true; + std::list aMoved; + if (theOld->isEqual(theNew)) + return aMoved; + + std::list anOldSubs = theOld->subEntities(); + std::list aNewSubs = theNew->subEntities(); + std::list::const_iterator anOldIt = anOldSubs.begin(); + std::list::const_iterator aNewIt = aNewSubs.begin(); + for (; anOldIt != anOldSubs.end() && aNewIt != aNewSubs.end(); ++anOldIt, ++aNewIt) { + std::list aMovedSubs = movedEntities( + *anOldIt, theOldStorage, *aNewIt, theNewStorage); + if (aMovedSubs.size() != 1 || aMovedSubs.front() != *anOldIt) + isFullyMoved = false; + aMoved.insert(aMoved.end(), aMovedSubs.begin(), aMovedSubs.end()); } - else { - myFeatureMap[myBaseFeature] = anEntityID; - isComplexFeature = true; - } - - int aNbOutOfGroup = 0; - if (isComplexFeature) { - std::list aPoints = - myBaseFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); - std::list::iterator anIt = aPoints.begin(); - for (; anIt != aPoints.end(); ++anIt) { - std::map::const_iterator aFound = myAttributeMap.find(*anIt); - Slvs_hEntity anAttr = aFound != myAttributeMap.end() ? - aFound->second : myGroup->getAttributeId(*anIt); - Slvs_Entity anAttrEnt = myStorage->getEntity(anAttr); - - // Check the attribute changes coordinates - std::shared_ptr aPt = - std::dynamic_pointer_cast(*anIt); - // Check the entity is not lying in the current group or it is not moved - if (anAttr == SLVS_E_UNKNOWN || anAttrEnt.group != myGroup->getId() || - (anAttr <= anEntMaxID && !isMoved(aPt, anAttrEnt))) { - if (anAttrEnt.group == SLVS_G_OUTOFGROUP) - ++aNbOutOfGroup; - theIsFullyMoved = false; - } - else { - theAttributes.push_back(anAttr); - // update point coordinates - Slvs_Entity anAttrEnt = myStorage->getEntity(anAttr); - double aNewPos[2] = {aPt->x(), aPt->y()}; - for (int i = 0; i < 2; i++) { - Slvs_Param aParam = myStorage->getParameter(anAttrEnt.param[i]); - aParam.val = aNewPos[i]; - myStorage->updateParameter(aParam); - } - } - } - } - - // Additional checking, which leads to fix whole feature, if it has fixed points - if (!theIsFullyMoved) { - Slvs_Entity aFeature = myStorage->getEntity(anEntityID); - int aNbPoints = 4; - while (aNbPoints > 0 && aFeature.point[aNbPoints-1] == SLVS_E_UNKNOWN) - --aNbPoints; - if (aNbPoints == aNbOutOfGroup + (int)theAttributes.size()) { - theIsFullyMoved = true; - return; - } - } - - // Leave only points which are used in constraints - if (myStorage->isUsedByConstraints(anEntityID)) - return; - std::vector::iterator anIt = theAttributes.begin(); - while (anIt != theAttributes.end()) { - if (myStorage->isUsedByConstraints(*anIt)) - ++anIt; - else { - int aShift = anIt - theAttributes.begin(); - theAttributes.erase(anIt); - anIt = theAttributes.begin() + aShift; - } + if (isFullyMoved) { + aMoved.clear(); + aMoved.push_back(theOld); } + return aMoved; } -bool SketchSolver_ConstraintMovement::isMoved( - std::shared_ptr thePoint, const Slvs_Entity& theEntity) -{ - double aDeltaX = myStorage->getParameter(theEntity.param[0]).val; - double aDeltaY = myStorage->getParameter(theEntity.param[1]).val; - aDeltaX -= thePoint->x(); - aDeltaY -= thePoint->y(); - return aDeltaX * aDeltaX + aDeltaY * aDeltaY >= tolerance * tolerance; -} -void SketchSolver_ConstraintMovement::fixFeature() +void SketchSolver_ConstraintMovement::getAttributes( + ParameterWrapperPtr& theValue, + std::vector& theAttributes) { - Slvs_hEntity anEntID = fixedEntity(); - - std::string aKind; - std::map::const_iterator aFIt = myFeatureMap.begin(); - for (; aFIt != myFeatureMap.end() && aKind.empty(); ++aFIt) - if (aFIt->second == anEntID) - aKind = aFIt->first->getKind(); - std::map::const_iterator anAtIt = myAttributeMap.begin(); - for (; anAtIt != myAttributeMap.end() && aKind.empty(); ++anAtIt) - if (anAtIt->second == anEntID) - aKind = anAtIt->first->attributeType(); + // There will be build entities, according to the fixed feature, in the separate storage + // to check whether any point is moved + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + StoragePtr anOtherStorage = aBuilder->createStorage(myGroupID); + anOtherStorage->setSketch(myStorage->sketch()); + if (!anOtherStorage->update(myBaseFeature, myGroupID)) + return; + EntityWrapperPtr aNewEntity = anOtherStorage->entity(myBaseFeature); + EntityWrapperPtr anOldEntity = myStorage->entity(myBaseFeature); - if (aKind == SketchPlugin_Line::ID()) { - Slvs_Entity aLine = myStorage->getEntity(anEntID); - fixLine(aLine); - } - else if (aKind == SketchPlugin_Arc::ID()) { - Slvs_Entity anArc = myStorage->getEntity(anEntID); - fixArc(anArc); - } - else if (aKind == SketchPlugin_Circle::ID()) { - Slvs_Entity aCirc = myStorage->getEntity(anEntID); - fixCircle(aCirc); - } - else if (aKind == SketchPlugin_Point::ID() || aKind == GeomDataAPI_Point2D::typeId()) { - fixPoint(anEntID); + std::list aMoved; + if (aNewEntity && anOldEntity) + aMoved = movedEntities(anOldEntity, myStorage, aNewEntity, anOtherStorage); + else { + // get attributes moved + std::list anAttrList = + myBaseFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); + std::list::const_iterator anIt = anAttrList.begin(); + for (; anIt != anAttrList.end(); ++anIt) { + aNewEntity = anOtherStorage->entity(*anIt); + anOldEntity = myStorage->entity(*anIt); + if (!aNewEntity || !anOldEntity) + continue; + std::list aMovedAttr = movedEntities( + anOldEntity, myStorage, aNewEntity, anOtherStorage); + aMoved.insert(aMoved.end(), aMovedAttr.begin(), aMovedAttr.end()); + } } + theAttributes.clear(); + theAttributes.insert(theAttributes.begin(), aMoved.begin(), aMoved.end()); } - diff --git a/src/SketchSolver/SketchSolver_ConstraintMovement.h b/src/SketchSolver/SketchSolver_ConstraintMovement.h index dbec1b020..ba119beaa 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMovement.h +++ b/src/SketchSolver/SketchSolver_ConstraintMovement.h @@ -8,25 +8,25 @@ #define SketchSolver_ConstraintMovement_H_ #include "SketchSolver.h" -#include - -#include +#include /** \class SketchSolver_ConstraintMovement * \ingroup Plugins - * \brief Stores data of Rigid (Fixed) constraint for the moved feature only + * \brief Stores data to the Fixed constraint for the moved feature only */ -class SketchSolver_ConstraintMovement : public SketchSolver_ConstraintRigid +class SketchSolver_ConstraintMovement : public SketchSolver_ConstraintFixed { private: /// Creates constraint to manage the given constraint from plugin SketchSolver_ConstraintMovement(ConstraintPtr theConstraint) - : SketchSolver_ConstraintRigid(theConstraint) + : SketchSolver_ConstraintFixed(theConstraint) {} public: /// Creates temporary constraint based on feature - SketchSolver_ConstraintMovement(FeaturePtr theFeature); + SketchSolver_ConstraintMovement(FeaturePtr theFeature) + : SketchSolver_ConstraintFixed(theFeature) + {} protected: /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints @@ -34,16 +34,11 @@ protected: /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints /// \param[out] theValue numerical characteristic of constraint (e.g. distance) - /// \param[out] theAttributes list of attributes to be filled - /// \param[out] theIsFullyMoved shows that the feature is moved, in other case only one point of the feature is shifted - virtual void getAttributes(double& theValue, std::vector& theAttributes, bool& theIsFullyMoved); - - /// \brief Fixed feature basing on its type - virtual void fixFeature(); + /// \param[out] theAttributes list of attributes to be filled (list of moved entities or attributes) + virtual void getAttributes(ParameterWrapperPtr& theValue, std::vector& theAttributes); private: - /// \brief Check the coordinates of point are differ than coordinates of correponding SolveSpace entity - bool isMoved(std::shared_ptr thePoint, const Slvs_Entity& theEntity); + std::vector myMovedEntities; ///< list of entities that are moved }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintMulti.cpp b/src/SketchSolver/SketchSolver_ConstraintMulti.cpp index 5be0d2fe5..8f9e8c046 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMulti.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMulti.cpp @@ -1,137 +1,74 @@ #include -#include #include +#include -#include - -#include #include #include #include -#include - -#include -#include -#include - -void SketchSolver_ConstraintMulti::processEntities(const std::vector< std::vector >& theEntAndCopies) +void SketchSolver_ConstraintMulti::getEntitiesAndCopies( + std::list< std::list >& theEntAndCopies) { - // Keep all objects unchanged (only initial object may be changed by user) - myCircsAndCopies.clear(); - std::vector >::const_iterator anEntIt = theEntAndCopies.begin(); - std::vector::const_iterator aCpIt; - for (; anEntIt != theEntAndCopies.end(); ++anEntIt) { - std::vector aCircs; - aCpIt = anEntIt->begin(); - // Obtain initial points - Slvs_Entity anInitial = myStorage->getEntity(*aCpIt); - if (anInitial.type == SLVS_E_POINT_IN_2D || anInitial.type == SLVS_E_POINT_IN_3D) - myInitialPoints.insert(anInitial.h); - else { - for (int i = 0; i < 4 && anInitial.point[i] != SLVS_E_UNKNOWN; i++) - myInitialPoints.insert(anInitial.point[i]); - } - - // Fix the copies - for (++aCpIt; aCpIt != anEntIt->end(); ++aCpIt) { - const Slvs_Entity& anEntity = myStorage->getEntity(*aCpIt); - std::vector aNewConstr; - if (anEntity.type == SLVS_E_CIRCLE) { - aCircs.push_back(anEntity.distance); - // for circles we fix only center - aNewConstr = myStorage->fixEntity(anEntity.point[0]); - } else - aNewConstr = myStorage->fixEntity(*aCpIt); - if (anEntity.type == SLVS_E_ARC_OF_CIRCLE) - aCircs.push_back(anEntity.h); - mySlvsConstraints.insert(mySlvsConstraints.end(), aNewConstr.begin(), aNewConstr.end()); - } + DataPtr aData = myBaseConstraint->data(); + + // Lists of objects and number of copies + AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_Constraint::ENTITY_A())); + myNumberOfObjects = anInitialRefList->size(); + myNumberOfCopies = aData->integer(nameNbObjects())->value() - 1; + if (myNumberOfCopies <= 0) + return; - if (!aCircs.empty()) { - if (anInitial.type == SLVS_E_CIRCLE) - aCircs.insert(aCircs.begin(), anInitial.distance); - else - aCircs.insert(aCircs.begin(), anInitial.h); - myCircsAndCopies.push_back(aCircs); - } + AttributeRefListPtr aRefList = std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_Constraint::ENTITY_B())); + if (!aRefList || aRefList->size() == 0) { + myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); + return; } -} -void SketchSolver_ConstraintMulti::update(ConstraintPtr theConstraint) -{ - cleanErrorMsg(); - if (!theConstraint || theConstraint == myBaseConstraint) { - AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - AttributeIntegerPtr aNbObjects = myBaseConstraint->integer(nameNbObjects()); - if (anInitialRefList->size() != myNumberOfObjects || aNbObjects->value()-1 != myNumberOfCopies) { - remove(myBaseConstraint); - process(); - return; + FeaturePtr aFeature; + std::list anEntities; // list of transformed entities + std::list anObjectList = aRefList->list(); + std::list::iterator anObjIt = anObjectList.begin(); + 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; + + myStorage->update(aFeature); + anEntities.push_back(myStorage->entity(aFeature)); } + if (!anEntities.empty()) + theEntAndCopies.push_back(anEntities); } - - updateLocal(); - SketchSolver_Constraint::update(); } -bool SketchSolver_ConstraintMulti::remove(ConstraintPtr theConstraint) +void SketchSolver_ConstraintMulti::update() { - cleanErrorMsg(); - if (theConstraint && theConstraint != myBaseConstraint) - return false; - bool isFullyRemoved = true; - std::vector::iterator aCIter = mySlvsConstraints.begin(); - for (; aCIter != mySlvsConstraints.end(); aCIter++) - isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved; - mySlvsConstraints.clear(); - - std::map::iterator aFeatIt = myFeatureMap.begin(); - for (; aFeatIt != myFeatureMap.end(); aFeatIt++) - myStorage->removeEntity(aFeatIt->second); - myStorage->removeUnusedEntities(); - - std::map aFeatureMapCopy = myFeatureMap; - - if (isFullyRemoved) { - myFeatureMap.clear(); - myAttributeMap.clear(); - myValueMap.clear(); - } else - cleanRemovedEntities(); - - // Restore initial features - std::map::iterator aFIter = aFeatureMapCopy.begin(); - for (; aFIter != aFeatureMapCopy.end(); ++aFIter) - { - if (myFeatureMap.find(aFIter->first) != myFeatureMap.end()) - continue; // the feature was not removed - Slvs_hEntity anEntity = myGroup->getFeatureId(aFIter->first); - if (anEntity != SLVS_E_UNKNOWN) - myFeatureMap[aFIter->first] = anEntity; - } - - // Clear list of rotated points - myPointsAndCopies.clear(); - myInitialPoints.clear(); - - return true; + update(false); } -void SketchSolver_ConstraintMulti::addFeature(FeaturePtr theFeature) -{ - SketchSolver_Constraint::addFeature(theFeature); - std::map::iterator aFeatIt = myFeatureMap.find(theFeature); - if (aFeatIt == myFeatureMap.end()) +void SketchSolver_ConstraintMulti::update(bool isForce) +{ + cleanErrorMsg(); + AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast( + myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + AttributeIntegerPtr aNbObjects = myBaseConstraint->integer(nameNbObjects()); + if (anInitialRefList->size() != myNumberOfObjects || aNbObjects->value()-1 != myNumberOfCopies) { + remove(); + process(); return; + } - // store list of points of the feature - const Slvs_Entity& theEntity = myStorage->getEntity(aFeatIt->second); - for (int i = 0; i < 4; i++) - if (theEntity.point[i] != SLVS_E_UNKNOWN) - myPointsJustUpdated.insert(theEntity.point[i]); + // update derivative object + updateLocal(); + if (isForce) + myAdjusted = false; + // update parent object + SketchSolver_Constraint::update(); } void SketchSolver_ConstraintMulti::adjustConstraint() @@ -139,172 +76,12 @@ void SketchSolver_ConstraintMulti::adjustConstraint() if (myAdjusted) return; // constraint already adjusted, don't do it once again - double aRelCoord[2] = {0.0, 0.0}; // relative coordinates of point - double anAbsCoord[2] = {0.0, 0.0}; // absolute coordinates of point - - std::list aCoincident = myStorage->getConstraintsByType(SLVS_C_POINTS_COINCIDENT); - std::list::const_iterator aCoIt; - - // Update positions of all points to satisfy angles - std::vector< std::vector >::const_iterator aPointsIter = myPointsAndCopies.begin(); - std::vector::const_iterator aCopyIter; - for (; aPointsIter != myPointsAndCopies.end(); ++aPointsIter) { - aCopyIter = aPointsIter->begin(); - const Slvs_Entity& anInitial = myStorage->getEntity(*aCopyIter); - for (int i = 0; i < 2; i++) - anAbsCoord[i] = myStorage->getParameter(anInitial.param[i]).val; - getRelative(anAbsCoord[0], anAbsCoord[1], aRelCoord[0], aRelCoord[1]); - - // if the point is coincident with another one which is temporary fixed (moved by user), - // we will update its position correspondingly - Slvs_hConstraint aFixed; - for (aCoIt = aCoincident.begin(); aCoIt != aCoincident.end(); ++aCoIt) { - if ((aCoIt->ptA == anInitial.h && myInitialPoints.find(aCoIt->ptB) != myInitialPoints.end()) || - (aCoIt->ptB == anInitial.h && myInitialPoints.find(aCoIt->ptA) != myInitialPoints.end())) { - Slvs_hEntity anOtherId = aCoIt->ptA == anInitial.h ? aCoIt->ptB : aCoIt->ptA; - if (!myStorage->isTemporary(aFixed) && - myPointsJustUpdated.find(anOtherId) == myPointsJustUpdated.end()) - continue; // nothing to change - - const Slvs_Entity& anOtherPnt = myStorage->getEntity(anOtherId); - for (int i = 0; i < 2; i++) { - Slvs_Param anInitParam = myStorage->getParameter(anInitial.param[i]); - const Slvs_Param& anOtherParam = myStorage->getParameter(anOtherPnt.param[i]); - anInitParam.val = anOtherParam.val; - myStorage->updateParameter(anInitParam); - anAbsCoord[i] = anOtherParam.val; - } - getRelative(anAbsCoord[0], anAbsCoord[1], aRelCoord[0], aRelCoord[1]); - } - } - - // update copied points - aCopyIter = aPointsIter->begin(); - for (++aCopyIter; aCopyIter != aPointsIter->end(); ++aCopyIter) { - // transform coordinates - transformRelative(aRelCoord[0], aRelCoord[1]); - getAbsolute(aRelCoord[0], aRelCoord[1], anAbsCoord[0], anAbsCoord[1]); - - const Slvs_Entity& aTarget = myStorage->getEntity(*aCopyIter); - for (int i = 0; i < 2; i++) { - Slvs_Param aParam = myStorage->getParameter(aTarget.param[i]); - aParam.val = anAbsCoord[i]; - myStorage->updateParameter(aParam); - } - } - } - - std::list aDiamConstr; - for (aPointsIter = myCircsAndCopies.begin(); aPointsIter != myCircsAndCopies.end(); ++aPointsIter) { - aCopyIter = aPointsIter->begin(); - const Slvs_Entity& anInitial = myStorage->getEntity(*aCopyIter); - if (anInitial.type == SLVS_E_DISTANCE) { - const Slvs_Param& anInitRad = myStorage->getParameter(anInitial.param[0]); - for (++aCopyIter; aCopyIter != aPointsIter->end(); ++aCopyIter) { - const Slvs_Entity& aCopy = myStorage->getEntity(*aCopyIter); - Slvs_Param aCopyRad = myStorage->getParameter(aCopy.param[0]); - aCopyRad.val = anInitRad.val; - myStorage->updateParameter(aCopyRad); - } - } else if (anInitial.type == SLVS_E_ARC_OF_CIRCLE) { - const Slvs_Entity& aCenterEnt = myStorage->getEntity(anInitial.point[0]); - const Slvs_Entity& aStartEnt = myStorage->getEntity(anInitial.point[1]); + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - if (aDiamConstr.empty()) - aDiamConstr = myStorage->getConstraintsByType(SLVS_C_DIAMETER); - // Calculate diameter of initial arc - double aDiam = 0.0; - for (int i = 0; i < 2; i++) { - double d = myStorage->getParameter(aStartEnt.param[i]).val - - myStorage->getParameter(aCenterEnt.param[i]).val; - aDiam += d * d; - } - aDiam = sqrt(aDiam) * 2.0; - // Update the Diameter constraints of copied arcs - for (++aCopyIter; aCopyIter != aPointsIter->end(); ++aCopyIter) { - std::list::iterator aDCIt = aDiamConstr.begin(); - for (; aDCIt != aDiamConstr.end(); ++aDCIt) - if (aDCIt->entityA == *aCopyIter) { - aDCIt->valA = aDiam; - myStorage->updateConstraint(*aDCIt); - aDiamConstr.erase(aDCIt); - break; - } - } - } - } - - myPointsJustUpdated.clear(); + 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); myAdjusted = true; } - -void SketchSolver_ConstraintMulti::checkCoincidence() -{ - std::vector< std::vector > aFilteredPoints; // points are filtered by their positions - - std::vector< std::vector >::const_iterator aPCIt = myPointsAndCopies.begin(); - std::vector::const_iterator aCIt; - for (; aPCIt != myPointsAndCopies.end(); ++aPCIt) { - aCIt = aPCIt->begin(); - // Skip first element, focus the copies only - for (++aCIt; aCIt != aPCIt->end(); ++aCIt) { - std::vector< std::vector >::iterator aFilterIt = aFilteredPoints.begin(); - for (; aFilterIt != aFilteredPoints.end(); ++aFilterIt) - if (myStorage->isEqual(*aCIt, aFilterIt->front())) { - aFilterIt->push_back(*aCIt); - break; - } - if (aFilterIt == aFilteredPoints.end()) { - std::vector aNewFilter(1, *aCIt); - aFilteredPoints.push_back(aNewFilter); - } - } - } - - // Check the coicidence of filtered points and remove extra fixation. - // Also check separated points which are not fixed. - std::vector< std::vector >::iterator aFPIt = aFilteredPoints.begin(); - for (; aFPIt != aFilteredPoints.end(); ++aFPIt) { - if (aFPIt->size() <= 1) - continue; - std::vector::iterator anIt1, anIt2; - for (anIt1 = aFPIt->begin(); anIt1 != aFPIt->end(); ++anIt1) { - for (anIt2 = anIt1 + 1; anIt2 != aFPIt->end(); ++anIt2) { - Slvs_hConstraint aFixed1, aFixed2; - bool isFixed1 = myStorage->isPointFixed(*anIt1, aFixed1); - bool isFixed2 = myStorage->isPointFixed(*anIt2, aFixed2); - if (myStorage->isCoincident(*anIt1, *anIt2)) { - if (!isFixed1 && isFixed2) { - Slvs_hEntity aTmp = *anIt1; - *anIt1 = *anIt2; - *anIt2 = aTmp; - } else if (isFixed1 && isFixed2) { - // remove fixing of the second point - myStorage->removeConstraint(aFixed2); - std::vector::iterator aRemoveIt = mySlvsConstraints.begin(); - for (; aRemoveIt != mySlvsConstraints.end(); ++aRemoveIt) - if (*aRemoveIt == aFixed2) { - mySlvsConstraints.erase(aRemoveIt); - break; - } - } - } else { - bool isFixed[2] = { - myStorage->isPointFixed(*anIt1, aFixed1, true), - myStorage->isPointFixed(*anIt2, aFixed2, true) - }; - - Slvs_hEntity aPoint[2] = {*anIt1, *anIt2}; - for (int i = 0; i < 2; i++) - if (!isFixed[i]) { - Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(), - SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0, - aPoint[i], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - aConstraint.h = myStorage->addConstraint(aConstraint); - mySlvsConstraints.push_back(aConstraint.h); - } - } - } - } - } -} diff --git a/src/SketchSolver/SketchSolver_ConstraintMulti.h b/src/SketchSolver/SketchSolver_ConstraintMulti.h index 4786ee430..70fe5e781 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMulti.h +++ b/src/SketchSolver/SketchSolver_ConstraintMulti.h @@ -27,29 +27,10 @@ public: myAdjusted(false) {} - virtual int getType() const - { return SLVS_C_UNKNOWN; } - /// \brief Update constraint - virtual void update(ConstraintPtr theConstraint = ConstraintPtr()); - - /// \brief Tries to remove constraint - /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence) - virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr()); - - /// \brief Adds a feature to constraint and create its analogue in SolveSpace - virtual void addFeature(FeaturePtr theFeature); - - /// \brief Update SketchPlugin attributes using the data obtained from SolveSpace entities - virtual void refresh() - { - myAdjusted = false; - SketchSolver_Constraint::refresh(); - } - - /// \brief Verifies, the coincidence between points of copied entities appears or disappears, - /// and removes or adds fixing of corresponding points. - void checkCoincidence(); + virtual void update(); + /// \brief Update constraint + void update(bool isForce); protected: /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints @@ -57,12 +38,12 @@ protected: { /* do nothing here */ } /// \brief Collect entities and their copies, like circles and arcs - void processEntities(const std::vector< std::vector >& theEntAndCopies); + void getEntitiesAndCopies(std::list< std::list >& theEntAndCopies); /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints /// \param[out] theValue numerical characteristic of constraint (e.g. distance) /// \param[out] theAttributes list of attributes to be filled - virtual void getAttributes(double& theValue, std::vector& theAttributes) + virtual void getAttributes(double& theValue, std::vector& theAttributes) { /* do nothing here */ } /// \brief This method is used in derived objects to check consistence of constraint. @@ -73,24 +54,10 @@ 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: - size_t myNumberOfObjects; ///< number of previous initial objects - size_t myNumberOfCopies; ///< number of previous copies of initial objects - - std::vector< std::vector > myPointsAndCopies; ///< list of initial points and their copies - std::vector< std::vector > myCircsAndCopies; ///< list of circles and their copies (to change their radii together) - - std::set myPointsJustUpdated; ///< list of points touched by user - std::set myInitialPoints; ///< list of points containing initial objects + int myNumberOfObjects; ///< number of previous initial objects + int myNumberOfCopies; ///< number of previous copies of initial objects bool myAdjusted; ///< the constraint is already adjusted (to not do it several times) }; diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp index 7608460c4..597d313eb 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp @@ -1,25 +1,14 @@ #include -#include #include +#include -#include #include -#include -#include -#include -#include -#include - -#include -#include - #include void SketchSolver_ConstraintMultiRotation::getAttributes( - Slvs_hEntity& theCenter, double& theAngle, - std::vector< std::vector >& thePoints, - std::vector< std::vector >& theEntities) + EntityWrapperPtr& theCenter, double& theAngle, + std::list< std::list >& theEntities) { DataPtr aData = myBaseConstraint->data(); theAngle = std::dynamic_pointer_cast( @@ -30,106 +19,42 @@ void SketchSolver_ConstraintMultiRotation::getAttributes( myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); return; } - int aType = SLVS_E_UNKNOWN; // type of created entity - Slvs_hEntity anEntityID = myGroup->getAttributeId(aCenterAttr); - if (anEntityID == SLVS_E_UNKNOWN) - anEntityID = changeEntity(aCenterAttr, aType); - theCenter = anEntityID; - - // Lists of objects and number of copies - AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Constraint::ENTITY_A())); - myNumberOfObjects = anInitialRefList->size(); - myNumberOfCopies = (size_t) aData->integer(SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID())->value() - 1; - if (myNumberOfCopies <= 0) - return; - AttributeRefListPtr aRefList = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); - if (!aRefList) { - myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); - return; - } - // Obtain all points of initial features and store them into separate lists - // containing their translated copies. - // Also all circles and arc collected too, because they will be constrained by equal radii. - FeaturePtr aFeature; - ResultConstructionPtr aRC; - static const size_t MAX_POINTS = 3; - std::vector aPoints[MAX_POINTS]; // lists of points of features - std::vector anEntities; - std::list anObjectList = aRefList->list(); - std::list::iterator anObjectIter = anObjectList.begin(); - while (anObjectIter != anObjectList.end()) { - for (size_t i = 0; i < MAX_POINTS; ++i) - aPoints[i].clear(); - anEntities.clear(); - - for (size_t i = 0; i <= myNumberOfCopies && anObjectIter != anObjectList.end(); i++, anObjectIter++) { - aFeature = ModelAPI_Feature::feature(*anObjectIter); - if (!aFeature) - continue; - anEntityID = changeEntity(aFeature, aType); - anEntities.push_back(anEntityID); - Slvs_Entity anEntity = myStorage->getEntity(anEntityID); - switch (aType) { - case SLVS_E_POINT_IN_2D: - case SLVS_E_POINT_IN_3D: - aPoints[0].push_back(anEntityID); - break; - case SLVS_E_LINE_SEGMENT: - aPoints[0].push_back(anEntity.point[0]); // start point of line - aPoints[1].push_back(anEntity.point[1]); // end point of line - break; - case SLVS_E_CIRCLE: - aPoints[0].push_back(anEntity.point[0]); // center of circle - break; - case SLVS_E_ARC_OF_CIRCLE: - aPoints[0].push_back(anEntity.point[0]); // center of arc - aPoints[1].push_back(anEntity.point[1]); // start point of arc - aPoints[2].push_back(anEntity.point[2]); // end point of arc - break; - default: - myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); - return; - } - } - - for (size_t i = 0; i < MAX_POINTS; ++i) - if (!aPoints[i].empty()) - thePoints.push_back(aPoints[i]); - if (!anEntities.empty()) - theEntities.push_back(anEntities); - } + myType = CONSTRAINT_MULTI_ROTATION; + + myStorage->update(aCenterAttr, GID_OUTOFGROUP); + theCenter = myStorage->entity(aCenterAttr); + + getEntitiesAndCopies(theEntities); } void SketchSolver_ConstraintMultiRotation::process() { cleanErrorMsg(); - if (!myBaseConstraint || !myStorage || myGroup == 0) { + if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) { /// TODO: Put error message here return; } - if (!mySlvsConstraints.empty()) // some data is changed, update constraint - update(myBaseConstraint); - std::vector > anEntitiesAndCopies; - getAttributes(myRotationCenter, myAngle, myPointsAndCopies, anEntitiesAndCopies); + EntityWrapperPtr aRotationCenter; + std::list > anEntitiesAndCopies; + getAttributes(aRotationCenter, myAngle, anEntitiesAndCopies); if (!myErrorMsg.empty()) return; - // Set the rotation center unchanged during constraint recalculation - Slvs_Constraint aConstraint; - if (!myStorage->isPointFixed(myRotationCenter, aConstraint.h, true)) { - aConstraint = Slvs_MakeConstraint( - SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0, - myRotationCenter, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - aConstraint.h = myStorage->addConstraint(aConstraint); - mySlvsConstraints.push_back(aConstraint.h); + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + std::list aRotConstraints; + + std::list< std::list >::iterator anEntIt = anEntitiesAndCopies.begin(); + for (; anEntIt != anEntitiesAndCopies.end(); ++anEntIt) { + std::list aNewConstraints = + aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID, myType, + myAngle, aRotationCenter, EntityWrapperPtr(), *anEntIt); + aRotConstraints.insert(aRotConstraints.end(), aNewConstraints.begin(), aNewConstraints.end()); } + myStorage->addConstraint(myBaseConstraint, aRotConstraints); myAdjusted = false; - processEntities(anEntitiesAndCopies); adjustConstraint(); } @@ -141,6 +66,13 @@ void SketchSolver_ConstraintMultiRotation::updateLocal() myAdjusted = false; // update angle value myAngle = aValue; + + // update center + AttributePtr aCenterAttr = myBaseConstraint->attribute(SketchPlugin_MultiRotation::CENTER_ID()); + if (myStorage->update(aCenterAttr, myGroupID)) { + myStorage->update(aCenterAttr, GID_UNKNOWN); + myAdjusted = false; + } } void SketchSolver_ConstraintMultiRotation::adjustConstraint() @@ -149,64 +81,15 @@ void SketchSolver_ConstraintMultiRotation::adjustConstraint() myStorage->setNeedToResolve(false); return; } - if (myAdjusted) - return; - std::list aCoincident = myStorage->getConstraintsByType(SLVS_C_POINTS_COINCIDENT); - std::list::const_iterator aCoIt; - - // Check overconstrained on rotation center (if it is coincident with other fixed point) - Slvs_hConstraint aFixedCenter; - if (myStorage->isPointFixed(myRotationCenter, aFixedCenter, false)) { - Slvs_hConstraint aFixed; - for (aCoIt = aCoincident.begin(); aCoIt != aCoincident.end(); ++aCoIt) - if ((aCoIt->ptA == myRotationCenter && myStorage->isPointFixed(aCoIt->ptB, aFixed, true)) || - (aCoIt->ptB == myRotationCenter && myStorage->isPointFixed(aCoIt->ptA, aFixed, true))) { - // Un-fix the center - myStorage->removeConstraint(aFixedCenter); - std::vector::iterator aSCIt = mySlvsConstraints.begin(); - for (; aSCIt != mySlvsConstraints.end(); ++aSCIt) - if (*aSCIt == aFixedCenter) { - mySlvsConstraints.erase(aSCIt); - break; - } - } - } - - // Obtain coordinates of rotation center - Slvs_Entity aRotCenter = myStorage->getEntity(myRotationCenter); - myCenterCoord[0] = myStorage->getParameter(aRotCenter.param[0]).val; - myCenterCoord[1] = myStorage->getParameter(aRotCenter.param[1]).val; - - myRotationVal[0] = sin(myAngle * PI / 180.0); - myRotationVal[1] = cos(myAngle * PI / 180.0); + const std::list& aConstraints = myStorage->constraint(myBaseConstraint); + std::list::const_iterator aCIt = aConstraints.begin(); + for (; aCIt != aConstraints.end(); ++aCIt) + (*aCIt)->setValue(myAngle); 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 86966e522..6aad12d63 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h +++ b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h @@ -22,21 +22,16 @@ public: SketchSolver_ConstraintMulti(theConstraint) {} - virtual int getType() const - { return SLVS_C_MULTI_ROTATION; } - protected: /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints virtual void process(); /// \brief Generate list of rotated entities - /// \param[out] theCenter ID of central point of rotation + /// \param[out] theCenter central point of rotation /// \param[out] theAngle rotation angle - /// \param[out] thePoints list of IDs of initial points and their rotated copies - /// \param[out] theEntities list of IDs of entities and their rotated copies - void getAttributes(Slvs_hEntity& theCenter, double& theAngle, - std::vector< std::vector >& thePoints, - std::vector< std::vector >& theEntities); + /// \param[out] theEntities list of entities and their rotated copies + void getAttributes(EntityWrapperPtr& theCenter, double& theAngle, + std::list< std::list >& theEntities); /// \brief This method is used in derived objects to check consistence of constraint. virtual void adjustConstraint(); @@ -44,24 +39,10 @@ protected: /// \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); - private: /// \brief Returns name of NUMBER_OF_COPIES parameter for corresponding feature virtual const std::string& nameNbObjects(); - -private: - Slvs_hEntity myRotationCenter; ///< ID of center of rotation double myAngle; ///< angle of rotation - - double myCenterCoord[2]; ///< coordinates of rotation center - double myRotationVal[2]; ///< sinus and cosinus of rotation angle }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp index 02b872c6e..d6960c015 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp @@ -1,27 +1,13 @@ #include -#include #include +#include -#include #include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - void SketchSolver_ConstraintMultiTranslation::getAttributes( - Slvs_hEntity& theStartPoint, Slvs_hEntity& theEndPoint, - std::vector< std::vector >& thePoints, - std::vector< std::vector >& theEntities) + EntityWrapperPtr& theStartPoint, EntityWrapperPtr& theEndPoint, + std::list< std::list >& theEntities) { DataPtr aData = myBaseConstraint->data(); AttributePtr aStartPointAttr = aData->attribute(SketchPlugin_MultiTranslation::START_POINT_ID()); @@ -32,176 +18,47 @@ void SketchSolver_ConstraintMultiTranslation::getAttributes( return; } - int aType = SLVS_E_UNKNOWN; // type of created entity - Slvs_hEntity anEntityID = myGroup->getAttributeId(aStartPointAttr); - if (anEntityID == SLVS_E_UNKNOWN) - anEntityID = changeEntity(aStartPointAttr, aType); - theStartPoint = anEntityID; - anEntityID = myGroup->getAttributeId(aEndPointAttr); - if (anEntityID == SLVS_E_UNKNOWN) - anEntityID = changeEntity(aEndPointAttr, aType); - theEndPoint = anEntityID; - - // Lists of objects and number of copies - AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Constraint::ENTITY_A())); - myNumberOfObjects = anInitialRefList->size(); - myNumberOfCopies = (size_t) aData->integer(SketchPlugin_MultiTranslation::NUMBER_OF_OBJECTS_ID())->value() - 1; - if (myNumberOfCopies <= 0) - return; - - AttributeRefListPtr aRefList = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); - if (!aRefList) { - myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); - return; - } + myType = CONSTRAINT_MULTI_TRANSLATION; - // Obtain all points of initial features and store them into separate lists - // containing their translated copies. - // Also all circles and arc collected too, because they will be constrained by equal radii. - FeaturePtr aFeature; - ResultConstructionPtr aRC; - static const size_t MAX_POINTS = 3; - std::vector aPoints[MAX_POINTS]; // lists of points of features - std::vector anEntities; // list of translated entities - std::list anObjectList = aRefList->list(); - std::list::iterator anObjectIter = anObjectList.begin(); - while (anObjectIter != anObjectList.end()) { - for (size_t i = 0; i < MAX_POINTS; i++) - aPoints[i].clear(); - anEntities.clear(); + myStorage->update(aStartPointAttr); + theStartPoint = myStorage->entity(aStartPointAttr); + myStorage->update(aEndPointAttr); + theEndPoint = myStorage->entity(aEndPointAttr); - for (size_t i = 0; i <= myNumberOfCopies && anObjectIter != anObjectList.end(); i++, anObjectIter++) { - aFeature = ModelAPI_Feature::feature(*anObjectIter); - if (!aFeature) - continue; - anEntityID = changeEntity(aFeature, aType); - anEntities.push_back(anEntityID); - Slvs_Entity anEntity = myStorage->getEntity(anEntityID); - switch (aType) { - case SLVS_E_POINT_IN_2D: - case SLVS_E_POINT_IN_3D: - aPoints[0].push_back(anEntityID); - break; - case SLVS_E_LINE_SEGMENT: - aPoints[0].push_back(anEntity.point[0]); // start point of line - aPoints[1].push_back(anEntity.point[1]); // end point of line - break; - case SLVS_E_CIRCLE: - aPoints[0].push_back(anEntity.point[0]); // center of circle - break; - case SLVS_E_ARC_OF_CIRCLE: - aPoints[0].push_back(anEntity.point[0]); // center of arc - aPoints[1].push_back(anEntity.point[1]); // start point of arc - aPoints[2].push_back(anEntity.point[2]); // end point of arc - break; - default: - myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); - return; - } - } + getEntitiesAndCopies(theEntities); - for (size_t i = 0; i < MAX_POINTS; ++i) - if (!aPoints[i].empty()) - thePoints.push_back(aPoints[i]); - if (!anEntities.empty()) - theEntities.push_back(anEntities); - } } void SketchSolver_ConstraintMultiTranslation::process() { cleanErrorMsg(); - if (!myBaseConstraint || !myStorage || myGroup == 0) { + if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) { /// TODO: Put error message here return; } - if (!mySlvsConstraints.empty()) // some data is changed, update constraint - update(myBaseConstraint); - Slvs_hEntity aStartPoint, aEndPoint; - std::vector > anEntitiesAndCopies; - getAttributes(aStartPoint, aEndPoint, myPointsAndCopies, anEntitiesAndCopies); + EntityWrapperPtr aStartPoint, aEndPoint; + std::list > anEntitiesAndCopies; + getAttributes(aStartPoint, aEndPoint, anEntitiesAndCopies); if (!myErrorMsg.empty()) return; - // Create translation line - if (myTranslationLine == SLVS_E_UNKNOWN) { - Slvs_Entity aTranslationLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(), - myGroup->getWorkplaneId(), aStartPoint, aEndPoint); - aTranslationLine.h = myStorage->addEntity(aTranslationLine); - myTranslationLine = aTranslationLine.h; - } else { - Slvs_Entity aTranslationLine = myStorage->getEntity(myTranslationLine); - if (aTranslationLine.point[0] != aStartPoint || aTranslationLine.point[1] != aEndPoint) { - aTranslationLine.point[0] = aStartPoint; - aTranslationLine.point[1] = aEndPoint; - myStorage->updateEntity(aTranslationLine); - } + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + std::list aTransConstraints; + + std::list< std::list >::iterator anEntIt = anEntitiesAndCopies.begin(); + for (; anEntIt != anEntitiesAndCopies.end(); ++anEntIt) { + std::list aNewConstraints = + aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID, myType, + 0.0, aStartPoint, aEndPoint, *anEntIt); + aTransConstraints.insert(aTransConstraints.end(), aNewConstraints.begin(), aNewConstraints.end()); } + myStorage->addConstraint(myBaseConstraint, aTransConstraints); myAdjusted = false; - processEntities(anEntitiesAndCopies); adjustConstraint(); } -void SketchSolver_ConstraintMultiTranslation::adjustConstraint() -{ - if (myAdjusted) - return; - - Slvs_Entity aTranslationLine = myStorage->getEntity(myTranslationLine); - Slvs_hConstraint aFixed; // temporary variable - // Set the translation line unchanged during constraint recalculation - for (int i = 0; i < 2; i++) { - if (myStorage->isPointFixed(aTranslationLine.point[i], aFixed, true)) - continue; - Slvs_Constraint aConstraint = Slvs_MakeConstraint( - SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0, - aTranslationLine.point[i], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - aConstraint.h = myStorage->addConstraint(aConstraint); - myStorage->addTemporaryConstraint(aConstraint.h); - } - - // Check if the distance between point is 0, no need to resolve constraints (just wait another values) - double aXY[4]; - for (int i = 0; i < 2; i++) { - Slvs_Entity aPnt = myStorage->getEntity(aTranslationLine.point[i]); - aXY[2*i] = myStorage->getParameter(aPnt.param[0]).val; - aXY[2*i+1] = myStorage->getParameter(aPnt.param[1]).val; - } - myDelta[0] = aXY[2] - aXY[0]; - myDelta[1] = aXY[3] - aXY[1]; - if (fabs(myDelta[0]) + fabs(myDelta[1]) < tolerance) { - myStorage->setNeedToResolve(false); - return; - } - - 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]; -} - const std::string& SketchSolver_ConstraintMultiTranslation::nameNbObjects() { return SketchPlugin_MultiTranslation::NUMBER_OF_OBJECTS_ID(); diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h index c9f10147d..0e0c2faf1 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h +++ b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h @@ -19,49 +19,27 @@ class SketchSolver_ConstraintMultiTranslation : public SketchSolver_ConstraintMu public: /// Constructor based on SketchPlugin constraint SketchSolver_ConstraintMultiTranslation(ConstraintPtr theConstraint) : - SketchSolver_ConstraintMulti(theConstraint), - myTranslationLine(SLVS_E_UNKNOWN) + SketchSolver_ConstraintMulti(theConstraint) {} - virtual int getType() const - { return SLVS_C_MULTI_TRANSLATION; } - protected: /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints virtual void process(); /// \brief Generate list of translated entities - /// \param[out] theStartPoint ID of start point of translation - /// \param[out] theEndPoint ID of final point of translation - /// \param[out] thePoints list of IDs of initial points and their translated copies - /// \param[out] theEntities list of IDs of entities and their translated copies - void getAttributes(Slvs_hEntity& theStartPoint, Slvs_hEntity& theEndPoint, - std::vector< std::vector >& thePoints, - std::vector< std::vector >& theEntities); - - /// \brief This method is used in derived objects to check consistence of constraint. - virtual void adjustConstraint(); + /// \param[out] theStartPoint start point of translation + /// \param[out] theEndPoint final point of translation + /// \param[out] theEntities list of entities and their translated copies + void getAttributes(EntityWrapperPtr& theStartPoint, EntityWrapperPtr& theEndPoint, + std::list< std::list >& theEntities); /// \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); - private: /// \brief Returns name of NUMBER_OF_COPIES parameter for corresponding feature virtual const std::string& nameNbObjects(); - -private: - Slvs_hEntity myTranslationLine; ///< ID of translation line - - double myDelta[2]; ///< increment of translation }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintParametric.cpp b/src/SketchSolver/SketchSolver_ConstraintParametric.cpp deleted file mode 100644 index bd533ce8e..000000000 --- a/src/SketchSolver/SketchSolver_ConstraintParametric.cpp +++ /dev/null @@ -1,171 +0,0 @@ -#include -#include -#include - -#include - -SketchSolver_ConstraintParametric::SketchSolver_ConstraintParametric(AttributePtr theAttribute) - : SketchSolver_ConstraintRigid(ConstraintPtr()), - myBaseAttribute(theAttribute) -{ - process(); -} - -void SketchSolver_ConstraintParametric::process() -{ - cleanErrorMsg(); - if (!myBaseAttribute || !myStorage || myGroup == 0) { - /// TODO: Put error message here - return; - } - if (!mySlvsConstraints.empty()) // some data is changed, update constraint - update(myBaseConstraint); - - Slvs_hEntity anAttrID; - getAttributes(anAttrID); - if (!myErrorMsg.empty() || (myFeatureMap.empty() && myAttributeMap.empty())) - return; - - myHorizLineID = SLVS_E_UNKNOWN; - myVertLineID = SLVS_E_UNKNOWN; - - std::shared_ptr aPoint = - std::dynamic_pointer_cast(myBaseAttribute); - if (!aPoint) - return; - if (!aPoint->textX().empty()) { - // Create vertical line with fixed boundary point - Slvs_Entity aLine = createLine(aPoint->x(), -100.0, aPoint->x(), 100.0); - // Place point on line - Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(), - SLVS_C_PT_ON_LINE, myGroup->getWorkplaneId(), 0.0, anAttrID, SLVS_E_UNKNOWN, - aLine.h, SLVS_E_UNKNOWN); - aConstraint.h = myStorage->addConstraint(aConstraint); - mySlvsConstraints.push_back(aConstraint.h); - myVertLineID = aLine.h; - myX = aPoint->x(); - } - if (!aPoint->textY().empty()) { - // Create horizontal line with fixed boundary points - Slvs_Entity aLine = createLine(-100.0, aPoint->y(), 100.0, aPoint->y()); - // Place point on line - Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(), - SLVS_C_PT_ON_LINE, myGroup->getWorkplaneId(), 0.0, anAttrID, SLVS_E_UNKNOWN, - aLine.h, SLVS_E_UNKNOWN); - aConstraint.h = myStorage->addConstraint(aConstraint); - mySlvsConstraints.push_back(aConstraint.h); - myHorizLineID = aLine.h; - myY = aPoint->y(); - } -} - - -void SketchSolver_ConstraintParametric::getAttributes(Slvs_hEntity& theAttributeID) -{ - int aType = SLVS_E_UNKNOWN; // type of created entity - theAttributeID = SLVS_E_UNKNOWN; - theAttributeID = myGroup->getAttributeId(myBaseAttribute); - if (theAttributeID == SLVS_E_UNKNOWN) { - theAttributeID = changeEntity(myBaseAttribute, aType); - if (theAttributeID == SLVS_E_UNKNOWN) { - myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); - return; - } - } - else - myAttributeMap[myBaseAttribute] = theAttributeID; -} - - -void SketchSolver_ConstraintParametric::update(ConstraintPtr theConstraint) -{ - cleanErrorMsg(); - if (!theConstraint || theConstraint == myBaseConstraint) { - std::shared_ptr aPoint = - std::dynamic_pointer_cast(myBaseAttribute); - if (aPoint && ((!aPoint->textX().empty() && myVertLineID == SLVS_E_UNKNOWN) || - (!aPoint->textY().empty() && myHorizLineID == SLVS_E_UNKNOWN))) { - remove(); - process(); - return; - } - } - adjustConstraint(); -} - -void SketchSolver_ConstraintParametric::refresh() -{ - Slvs_hEntity aBasePointID = myAttributeMap[myBaseAttribute]; - const Slvs_Entity& aBasePoint = myStorage->getEntity(aBasePointID); - double aXY[2]; - aXY[0] = myVertLineID != SLVS_E_UNKNOWN ? myX : myStorage->getParameter(aBasePoint.param[0]).val; - aXY[1] = myHorizLineID != SLVS_E_UNKNOWN ? myY : myStorage->getParameter(aBasePoint.param[1]).val; - - std::list aCoincidence = myStorage->getConstraintsByType(SLVS_C_POINTS_COINCIDENT); - std::list::const_iterator aCIt = aCoincidence.begin(); - for (; aCIt != aCoincidence.end(); ++aCIt) { - if (aCIt->ptA != aBasePointID && aCIt->ptB != aBasePointID) - continue; - Slvs_hEntity anOtherPointID = aCIt->ptA == aBasePointID ? aCIt->ptB : aCIt->ptA; - const Slvs_Entity& aPoint = myStorage->getEntity(anOtherPointID); - for (int i = 0; i < 2; i++) { - Slvs_Param aParam = myStorage->getParameter(aPoint.param[i]); - aParam.val = aXY[i]; - myStorage->updateParameter(aParam); - } - } -} - -void SketchSolver_ConstraintParametric::adjustConstraint() -{ - std::shared_ptr aPoint = - std::dynamic_pointer_cast(myBaseAttribute); - if (!aPoint) - return; - - if (!aPoint->textX().empty()) { - const Slvs_Entity& aLine = myStorage->getEntity(myVertLineID); - const Slvs_Entity& aStartPoint = myStorage->getEntity(aLine.point[0]); - Slvs_Param aParX = myStorage->getParameter(aStartPoint.param[0]); - aParX.val = aPoint->x(); - myStorage->updateParameter(aParX); - myX = aParX.val; - } - if (!aPoint->textY().empty()) { - const Slvs_Entity& aLine = myStorage->getEntity(myHorizLineID); - const Slvs_Entity& aStartPoint = myStorage->getEntity(aLine.point[0]); - Slvs_Param aParY = myStorage->getParameter(aStartPoint.param[1]); - aParY.val = aPoint->y(); - myStorage->updateParameter(aParY); - myY = aParY.val; - } -} - - -Slvs_Entity SketchSolver_ConstraintParametric::createLine( - double theStartX, double theStartY, double theEndX, double theEndY) -{ - // Start point - Slvs_Param aParX = Slvs_MakeParam(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP, theStartX); - Slvs_Param aParY = Slvs_MakeParam(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP, theStartY); - aParX.h = myStorage->addParameter(aParX); - aParY.h = myStorage->addParameter(aParY); - Slvs_Entity aStartPoint = Slvs_MakePoint2d(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP, - myGroup->getWorkplaneId(), aParX.h, aParY.h); - aStartPoint.h = myStorage->addEntity(aStartPoint); - - // End point - aParX = Slvs_MakeParam(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP, theEndX); - aParY = Slvs_MakeParam(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP, theEndY); - aParX.h = myStorage->addParameter(aParX); - aParY.h = myStorage->addParameter(aParY); - Slvs_Entity aEndPoint = Slvs_MakePoint2d(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP, - myGroup->getWorkplaneId(), aParX.h, aParY.h); - aEndPoint.h = myStorage->addEntity(aEndPoint); - - // Line - Slvs_Entity aLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP, - myGroup->getWorkplaneId(), aStartPoint.h, aEndPoint.h); - aLine.h = myStorage->addEntity(aLine); - return aLine; -} diff --git a/src/SketchSolver/SketchSolver_ConstraintParametric.h b/src/SketchSolver/SketchSolver_ConstraintParametric.h deleted file mode 100644 index 3a25d96ff..000000000 --- a/src/SketchSolver/SketchSolver_ConstraintParametric.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: SketchSolver_ConstraintParametric.h -// Created: 15 Jun 2015 -// Author: Artem ZHIDKOV - -#ifndef SketchSolver_ConstraintParametric_H_ -#define SketchSolver_ConstraintParametric_H_ - -#include "SketchSolver.h" -#include - -/** \class SketchSolver_ConstraintParametric - * \ingroup Plugins - * \brief Stores data of Rigid (Fixed) constraint for the attribute - * which coordinates are given by parametric expression - */ -class SketchSolver_ConstraintParametric : public SketchSolver_ConstraintRigid -{ -private: - /// Creates constraint to manage the given constraint from plugin - SketchSolver_ConstraintParametric() - : SketchSolver_ConstraintRigid(ConstraintPtr()) - {} - -public: - /// Creates temporary constraint based on feature - SketchSolver_ConstraintParametric(AttributePtr theAttribute); - - /// \brief Update constraint - virtual void update(ConstraintPtr theConstraint = ConstraintPtr()); - - /// \brief Update points coincident with parametric one - virtual void refresh(); - -protected: - /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints - virtual void process(); - - /// \brief Convert attribute to the entity - /// \param[out] theAttributeID identifier of the entity related to the attribute - virtual void getAttributes(Slvs_hEntity& theAttributeID); - - /// \brief This method is used in derived objects to check consistence of constraint. - virtual void adjustConstraint(); - -private: - /// \brief Create SolveSpace line with given coordinates - /// \return created line - Slvs_Entity createLine(double theStartX, double theStartY, double theEndX, double theEndY); - -private: - AttributePtr myBaseAttribute; ///< attribute given by expression - Slvs_hEntity myHorizLineID; ///< identifier of horizontal line, containing the point - Slvs_hEntity myVertLineID; ///< identifier of vertical line, containing the point - double myX, myY; -}; - -#endif diff --git a/src/SketchSolver/SketchSolver_ConstraintRigid.cpp b/src/SketchSolver/SketchSolver_ConstraintRigid.cpp deleted file mode 100644 index ed8ae3712..000000000 --- a/src/SketchSolver/SketchSolver_ConstraintRigid.cpp +++ /dev/null @@ -1,393 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -SketchSolver_ConstraintRigid::SketchSolver_ConstraintRigid(FeaturePtr theFeature) - : SketchSolver_Constraint(), - myBaseFeature(theFeature) -{ - process(); -} - -void SketchSolver_ConstraintRigid::process() -{ - cleanErrorMsg(); - if ((!myBaseConstraint && !myBaseFeature) || !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() || (myFeatureMap.empty() && myAttributeMap.empty())) - return; - fixFeature(); -} - -void SketchSolver_ConstraintRigid::update(ConstraintPtr theConstraint) -{ - cleanErrorMsg(); - if (theConstraint && theConstraint == myBaseConstraint && - theConstraint->getKind() == myBaseConstraint->getKind() && - checkAttributesChanged(theConstraint)) { - // remove previous constraint and set the given one - remove(myBaseConstraint); - myBaseConstraint = theConstraint; - process(); - } -} - -static void fixEntity(StoragePtr theStorage, const Slvs_hEntity& theEntID) -{ - Slvs_Entity anEntity = theStorage->getEntity(theEntID); - anEntity.group = SLVS_G_OUTOFGROUP; - theStorage->updateEntity(anEntity); - // move out of group all sub-entities - for (int i = 0; i < 4; ++i) - if (anEntity.point[i] != SLVS_E_UNKNOWN) - fixEntity(theStorage, anEntity.point[i]); - // move out of group the radius of circle - if (anEntity.distance != SLVS_E_UNKNOWN) - fixEntity(theStorage, anEntity.distance); - // move out of group parameters - for (int i = 0; i < 4; ++i) - if (anEntity.param[i] != SLVS_E_UNKNOWN) { - Slvs_Param aParam = theStorage->getParameter(anEntity.param[i]); - aParam.group = SLVS_G_OUTOFGROUP; - theStorage->updateParameter(aParam); - } -} - -void SketchSolver_ConstraintRigid::fixFeature() -{ - Slvs_hEntity anEntID = fixedEntity(); - if (anEntID != SLVS_E_UNKNOWN) - fixEntity(myStorage, anEntID); -} - -Slvs_hEntity SketchSolver_ConstraintRigid::fixedEntity() const -{ - Slvs_hEntity anEntID = SLVS_E_UNKNOWN; - if (myBaseConstraint) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - if (aRefAttr->isObject()) { - FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); - std::map::const_iterator aFound = myFeatureMap.find(aFeature); - if (aFound != myFeatureMap.end()) - anEntID = aFound->second; - } else { - std::map::const_iterator aFound = myAttributeMap.find(aRefAttr->attr()); - if (aFound != myAttributeMap.end()) - anEntID = aFound->second; - } - } - else if (myBaseFeature) { - std::map::const_iterator aFound = myFeatureMap.find(myBaseFeature); - if (aFound != myFeatureMap.end()) - anEntID = aFound->second; - } - return anEntID; -} - -void SketchSolver_ConstraintRigid::getAttributes( - double& theValue, - std::vector& theAttributes) -{ - theValue = 0.0; - int aType = SLVS_E_UNKNOWN; // type of created entity - Slvs_hEntity anEntityID = SLVS_E_UNKNOWN; - if (myBaseConstraint) { - // Get the attribute of constraint - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_ConstraintRigid::ENTITY_A())); - if (!aRefAttr || !aRefAttr->isInitialized()) { - myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); - return; - } - anEntityID = myGroup->getAttributeId(aRefAttr); - if (anEntityID == SLVS_E_UNKNOWN) - anEntityID = changeEntity(aRefAttr, aType); - } else { - anEntityID = myGroup->getFeatureId(myBaseFeature); - if (anEntityID == SLVS_E_UNKNOWN) - anEntityID = changeEntity(myBaseFeature, aType); - else - myFeatureMap[myBaseFeature] = anEntityID; - } - - if (anEntityID == SLVS_E_UNKNOWN) { - myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); - return; - } - - // Check the entity is complex - Slvs_Entity anEntity = myStorage->getEntity(anEntityID); - if (anEntity.point[0] != SLVS_E_UNKNOWN) { - for (int i = 0; i < 4 && anEntity.point[i]; i++) - theAttributes.push_back(anEntity.point[i]); - } else // simple entity - theAttributes.push_back(anEntityID); -} - - -bool SketchSolver_ConstraintRigid::remove(ConstraintPtr theConstraint) -{ - cleanErrorMsg(); - if (theConstraint && theConstraint != myBaseConstraint) - return false; - bool isFullyRemoved = true; - - std::vector::iterator aCIter = mySlvsConstraints.begin(); - for (; aCIter != mySlvsConstraints.end(); ++aCIter) - isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved; - - std::map::iterator aFIter = myFeatureMap.begin(); - for (; aFIter != myFeatureMap.end(); ++aFIter) - isFullyRemoved = myStorage->removeEntity(aFIter->second) && isFullyRemoved; - - std::map::iterator anAtIter = myAttributeMap.begin(); - for (; anAtIter != myAttributeMap.end(); ++anAtIter) - isFullyRemoved = myStorage->removeEntity(anAtIter->second) && isFullyRemoved; - - if (isFullyRemoved) { - myFeatureMap.clear(); - myAttributeMap.clear(); - myValueMap.clear(); - mySlvsConstraints.clear(); - } else - cleanRemovedEntities(); - return true; -} - -Slvs_hConstraint SketchSolver_ConstraintRigid::fixPoint(const Slvs_hEntity& thePointID) -{ - if (thePointID == SLVS_E_UNKNOWN) - return SLVS_C_UNKNOWN; - - Slvs_Constraint aConstraint; - Slvs_hConstraint aConstrID = SLVS_E_UNKNOWN; - bool isFixed = myStorage->isPointFixed(thePointID, aConstrID, true); - bool isForceUpdate = (isFixed && !myBaseConstraint && - myStorage->isTemporary(aConstrID)); - if (!isForceUpdate) { // create new constraint - if (isFixed) return aConstrID; - aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), - 0.0, thePointID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - aConstraint.h = myStorage->addConstraint(aConstraint); - mySlvsConstraints.push_back(aConstraint.h); - if (!myBaseConstraint) - myStorage->addConstraintWhereDragged(aConstraint.h); - } else { // update already existent constraint - if (!isFixed || aConstrID == SLVS_C_UNKNOWN || myBaseConstraint) - return SLVS_C_UNKNOWN; - aConstraint = myStorage->getConstraint(aConstrID); - aConstraint.ptA = thePointID; - myStorage->addConstraint(aConstraint); - if (!myBaseConstraint) - myStorage->addConstraintWhereDragged(aConstraint.h); - } - return aConstraint.h; -} - -void SketchSolver_ConstraintRigid::fixLine(const Slvs_Entity& theLine) -{ - Slvs_Constraint anEqual; - if (myStorage->isAxisParallel(theLine.h)) { - // Fix one point and a line length - Slvs_hConstraint aFixed; - if (!myStorage->isPointFixed(theLine.point[0], aFixed, true) && - !myStorage->isPointFixed(theLine.point[1], aFixed, true)) - fixPoint(theLine.point[0]); - if (!myStorage->isUsedInEqual(theLine.h, anEqual)) { - // Check the distance is not set yet - std::list aDistConstr = myStorage->getConstraintsByType(SLVS_C_PT_PT_DISTANCE); - std::list::const_iterator aDIt = aDistConstr.begin(); - for (; aDIt != aDistConstr.end(); aDIt++) - if ((aDIt->ptA == theLine.point[0] && aDIt->ptB == theLine.point[1]) || - (aDIt->ptA == theLine.point[1] && aDIt->ptB == theLine.point[0])) - return; - // Calculate distance between points on the line - double aCoords[4]; - for (int i = 0; i < 2; i++) { - Slvs_Entity aPnt = myStorage->getEntity(theLine.point[i]); - for (int j = 0; j < 2; j++) { - Slvs_Param aParam = myStorage->getParameter(aPnt.param[j]); - aCoords[2*i+j] = aParam.val; - } - } - double aLength = sqrt((aCoords[2] - aCoords[0]) * (aCoords[2] - aCoords[0]) + - (aCoords[3] - aCoords[1]) * (aCoords[3] - aCoords[1])); - // fix line length - Slvs_Constraint aDistance = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), - SLVS_C_PT_PT_DISTANCE, myGroup->getWorkplaneId(), aLength, - theLine.point[0], theLine.point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - aDistance.h = myStorage->addConstraint(aDistance); - mySlvsConstraints.push_back(aDistance.h); - } - return; - } - else if (myStorage->isUsedInEqual(theLine.h, anEqual)) { - // Check another entity of Equal is already fixed - Slvs_hEntity anOtherEntID = anEqual.entityA == theLine.h ? anEqual.entityB : anEqual.entityA; - if (myStorage->isEntityFixed(anOtherEntID, true)) { - // Fix start point of the line (if end point is not fixed yet) ... - Slvs_hConstraint anEndFixedID = SLVS_E_UNKNOWN; - bool isFixed = myStorage->isPointFixed(theLine.point[1], anEndFixedID, true); - if (isFixed == SLVS_E_UNKNOWN) - fixPoint(theLine.point[0]); - // ... and create fixed point lying on this line - Slvs_hEntity aPointToCopy = anEndFixedID == SLVS_E_UNKNOWN ? theLine.point[1] : theLine.point[0]; - // Firstly, search already fixed point on line - bool isPonLineFixed = false; - Slvs_hEntity aFixedPoint; - std::list aPonLineList = myStorage->getConstraintsByType(SLVS_C_PT_ON_LINE); - std::list::const_iterator aPLIter = aPonLineList.begin(); - for (; aPLIter != aPonLineList.end() && !isPonLineFixed; aPLIter++) - if (aPLIter->entityA == theLine.h) { - isPonLineFixed = myStorage->isPointFixed(aPLIter->ptA, anEndFixedID); - aFixedPoint = aPLIter->ptA; - } - - if (isPonLineFixed) { // update existent constraint - myStorage->copyEntity(aPointToCopy, aFixedPoint); - } else { // create new constraint - Slvs_hEntity aCopied = myStorage->copyEntity(aPointToCopy); - Slvs_Constraint aPonLine = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_ON_LINE, - myGroup->getWorkplaneId(), 0.0, aCopied, SLVS_E_UNKNOWN, theLine.h, SLVS_E_UNKNOWN); - aPonLine.h = myStorage->addConstraint(aPonLine); - mySlvsConstraints.push_back(aPonLine.h); - fixPoint(aCopied); - } - return; - } - } - - for (int i = 0; i < 2; i++) - fixPoint(theLine.point[i]); -} - -void SketchSolver_ConstraintRigid::fixCircle(const Slvs_Entity& theCircle) -{ - bool isFixRadius = true; - // Verify the arc is under Equal constraint - Slvs_Constraint anEqual; - if (myStorage->isUsedInEqual(theCircle.h, anEqual)) { - // Check another entity of Equal is already fixed - Slvs_hEntity anOtherEntID = anEqual.entityA == theCircle.h ? anEqual.entityB : anEqual.entityA; - if (myStorage->isEntityFixed(anOtherEntID, true)) - isFixRadius = false; - } - - fixPoint(theCircle.point[0]); - - if (isFixRadius) { - // Search the radius is already fixed - std::list aDiamConstr = myStorage->getConstraintsByType(SLVS_C_DIAMETER); - std::list::const_iterator aDiamIter = aDiamConstr.begin(); - for (; aDiamIter != aDiamConstr.end(); aDiamIter++) - if (aDiamIter->entityA == theCircle.h) - return; - - // Fix radius of a circle - AttributeDoublePtr aRadiusAttr = std::dynamic_pointer_cast( - myFeatureMap.begin()->first->attribute(SketchPlugin_Circle::RADIUS_ID())); - Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_DIAMETER, - myGroup->getWorkplaneId(), aRadiusAttr->value() * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, - myFeatureMap.begin()->second, SLVS_E_UNKNOWN); - aFixedR.h = myStorage->addConstraint(aFixedR); - mySlvsConstraints.push_back(aFixedR.h); - } -} - -void SketchSolver_ConstraintRigid::fixArc(const Slvs_Entity& theArc) -{ - bool isFixRadius = true; - std::list aPointsToFix; - aPointsToFix.push_back(theArc.point[1]); - aPointsToFix.push_back(theArc.point[2]); - - // Verify the arc is under Equal constraint - Slvs_Constraint anEqual; - if (myStorage->isUsedInEqual(theArc.h, anEqual)) { - // Check another entity of Equal is already fixed - Slvs_hEntity anOtherEntID = anEqual.entityA == theArc.h ? anEqual.entityB : anEqual.entityA; - if (myStorage->isEntityFixed(anOtherEntID, true)) { - isFixRadius = false; - Slvs_Entity anOtherEntity = myStorage->getEntity(anOtherEntID); - if (anOtherEntity.type == SLVS_E_LINE_SEGMENT) { - aPointsToFix.pop_back(); - aPointsToFix.push_back(theArc.point[0]); - } - } - } - - Slvs_hConstraint aConstrID; - int aNbPointsToFix = 2; // number of fixed points for the arc - if (myStorage->isPointFixed(theArc.point[0], aConstrID, true)) - aNbPointsToFix--; - - // Radius of the arc - FeaturePtr aFeature = myFeatureMap.begin()->first; - std::shared_ptr aCenter = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt(); - std::shared_ptr aStart = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt(); - double aRadius = aCenter->distance(aStart); - - // Update end point of the arc to be on a curve - std::shared_ptr anEnd = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt(); - double aDistance = anEnd->distance(aCenter); - std::shared_ptr aDir = anEnd->xy()->decreased(aCenter->xy()); - if (aDistance < tolerance) - aDir = aStart->xy()->decreased(aCenter->xy())->multiplied(-1.0); - else - aDir = aDir->multiplied(aRadius / aDistance); - double xy[2] = {aCenter->x() + aDir->x(), aCenter->y() + aDir->y()}; - Slvs_Entity aEndPoint = myStorage->getEntity(theArc.point[2]); - for (int i = 0; i < 2; i++) { - Slvs_Param aParam = myStorage->getParameter(aEndPoint.param[i]); - aParam.val = xy[i]; - myStorage->updateParameter(aParam); - } - - std::list::iterator aPtIt = aPointsToFix.begin(); - for (; aNbPointsToFix > 0; aPtIt++, aNbPointsToFix--) - fixPoint(*aPtIt); - - if (isFixRadius) { - // Fix radius of the arc - bool isExists = false; - std::list aDiamConstraints = myStorage->getConstraintsByType(SLVS_C_DIAMETER); - std::list::iterator anIt = aDiamConstraints.begin(); - for (; anIt != aDiamConstraints.end() && !isExists; anIt++) - if (anIt->entityA == theArc.h) - isExists = true; - if (!isExists) { - Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_DIAMETER, - myGroup->getWorkplaneId(), aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, - myFeatureMap.begin()->second, SLVS_E_UNKNOWN); - aFixedR.h = myStorage->addConstraint(aFixedR); - mySlvsConstraints.push_back(aFixedR.h); - if (!myBaseConstraint) - myStorage->addConstraintWhereDragged(aFixedR.h); - } - } -} diff --git a/src/SketchSolver/SketchSolver_ConstraintRigid.h b/src/SketchSolver/SketchSolver_ConstraintRigid.h deleted file mode 100644 index adac8c6a3..000000000 --- a/src/SketchSolver/SketchSolver_ConstraintRigid.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: SketchSolver_ConstraintRigid.h -// Created: 30 Mar 2015 -// Author: Artem ZHIDKOV - -#ifndef SketchSolver_ConstraintRigid_H_ -#define SketchSolver_ConstraintRigid_H_ - -#include "SketchSolver.h" -#include - -/** \class SketchSolver_ConstraintRigid - * \ingroup Plugins - * \brief Stores data of Rigid (Fixed) constraint - * - * Rigid constraint may have NULL basic SketchPlugin constraint, - * because the Rigid constraint may be temporary for correct moving of objects. - * - * Rigid constraint does not create a constraint, but builds the entities in separate group, - * so they will not be moved while resolving the set of constraints. - */ -class SketchSolver_ConstraintRigid : public SketchSolver_Constraint -{ -public: - /// Creates constraint to manage the given constraint from plugin - SketchSolver_ConstraintRigid(ConstraintPtr theConstraint) - : SketchSolver_Constraint(theConstraint) - {} - /// Creates temporary constraint based on feature - SketchSolver_ConstraintRigid(FeaturePtr theFeature); - - /// \brief Update constraint - virtual void update(ConstraintPtr theConstraint = ConstraintPtr()); - - /// \brief Tries to remove constraint - /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence) - virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr()); - - /// \brief Returns the type of constraint - virtual int getType() const - { return SLVS_C_WHERE_DRAGGED; } - -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 SolveSpace constraints - /// \param[out] theValue numerical characteristic of constraint (e.g. distance) - /// \param[out] theAttributes list of attributes to be filled - virtual void getAttributes(double& theValue, std::vector& theAttributes); - - /// \brief Fixed feature basing on its type - virtual void fixFeature(); - - /// \brief Fix given point - /// \return ID of the Fixed constraint - Slvs_hConstraint fixPoint(const Slvs_hEntity& thePointID); - - /// \brief Returns ID of fixed entity - Slvs_hEntity fixedEntity() const; - - /// \brief Fixing line position (start and end points) - void fixLine(const Slvs_Entity& theLine); - /// \brief Fixing circle (center and radius) - void fixCircle(const Slvs_Entity& theCircle); - /// \brief The arc is fixed differently to avoid SolveSpace problems (overconstraint) - /// - /// There will be fixed start and end points and the radius of the arc. - void fixArc(const Slvs_Entity& theArc); - -protected: - FeaturePtr myBaseFeature; ///< fixed feature (when it is set, myBaseConstraint should be NULL) -}; - -#endif diff --git a/src/SketchSolver/SketchSolver_ConstraintTangent.cpp b/src/SketchSolver/SketchSolver_ConstraintTangent.cpp index 865065411..bf551e43c 100644 --- a/src/SketchSolver/SketchSolver_ConstraintTangent.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintTangent.cpp @@ -1,84 +1,80 @@ #include -#include #include +#include +#include -void SketchSolver_ConstraintTangent::process() + +/// \brief Check whether the entities has only one shared point +static bool hasSingleCoincidence(EntityWrapperPtr theEntity1, EntityWrapperPtr theEntity2) { - cleanErrorMsg(); - if (!myBaseConstraint || !myStorage || myGroup == 0) { - /// TODO: Put error message here - return; + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + + const std::list& aPoints1 = theEntity1->subEntities(); + const std::list& aPoints2 = theEntity2->subEntities(); + + std::list::const_iterator aStartIt1 = aPoints1.begin(); + if (theEntity1->type() == ENTITY_ARC) ++aStartIt1; // skip center of arc + std::list::const_iterator aStartIt2 = aPoints2.begin(); + if (theEntity2->type() == ENTITY_ARC) ++aStartIt2; // skip center of arc + + int aNbCoinc = 0; + std::list::const_iterator anIt1, anIt2; + for (anIt1 = aStartIt1; anIt1 != aPoints1.end(); ++anIt1) { + std::shared_ptr aPt1 = aBuilder->point(*anIt1); + for (anIt2 = aStartIt2; anIt2 != aPoints2.end(); ++anIt2) { + std::shared_ptr aPt2 = aBuilder->point(*anIt2); + if (aPt1->distance(aPt2) < tolerance) + ++aNbCoinc; + } } - if (!mySlvsConstraints.empty()) // some data is changed, update constraint - update(myBaseConstraint); + return aNbCoinc == 1; +} + - double aValue; - std::vector anEntID; - getAttributes(aValue, anEntID); - if (!myErrorMsg.empty()) +void SketchSolver_ConstraintTangent::getAttributes( + double& theValue, + std::vector& theAttributes) +{ + SketchSolver_Constraint::getAttributes(theValue, theAttributes); + if (!myErrorMsg.empty() || !theAttributes[2] || !theAttributes[3]) { + theAttributes.clear(); return; + } + // Check the quantity of entities of each type and their order (arcs first) int aNbLines = 0; int aNbArcs = 0; - Slvs_Entity anEntities[2]; - myType = SLVS_C_CURVE_CURVE_TANGENT; - std::vector::iterator anEntIter = anEntID.begin(); - for (; anEntIter != anEntID.end(); anEntIter++) { - Slvs_Entity anEnt = myStorage->getEntity(*anEntIter); - if (anEnt.type == SLVS_E_LINE_SEGMENT) { - if (aNbLines == 0) - anEntities[1 + aNbLines] = anEnt; - aNbLines++; - myType = SLVS_C_ARC_LINE_TANGENT; - } - else if (anEnt.type == SLVS_E_ARC_OF_CIRCLE) { - if (aNbArcs < 2) - anEntities[aNbArcs] = anEnt; - aNbArcs++; + bool isSwap = false; // whether need to swap arguments (arc goes before line) + std::vector::iterator anEntIt = theAttributes.begin() + 2; + for (; anEntIt != theAttributes.end(); ++anEntIt) { + if ((*anEntIt)->type() == ENTITY_LINE) + ++aNbLines; + else if ((*anEntIt)->type() == ENTITY_ARC) { + ++aNbArcs; + isSwap = aNbLines > 0; } } - if (aNbLines + aNbArcs != 2) { - myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); - return; - } else if (aNbArcs < 1) { + if (aNbArcs < 1) { myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE(); return; } - - // It is necessary to identify which points of entities are coincident - int aSlvsOtherFlag = 0; - int aSlvsOther2Flag = 0; - // Obtain start and end points of entities - Slvs_hEntity aPointsToFind[4]; - for (int i = 0; i < 2; i++) { - int aShift = anEntities[i].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0; - aPointsToFind[2*i] = anEntities[i].point[aShift]; - aPointsToFind[2*i+1]= anEntities[i].point[aShift+1]; - } - // Search coincident points - bool isPointFound = false; - for (int i = 0; i < 2 && !isPointFound; i++) - for (int j = 2; j < 4 && !isPointFound; j++) - if (myStorage->isEqual(aPointsToFind[i], aPointsToFind[j])) { - aSlvsOtherFlag = i; - aSlvsOther2Flag = j - 2; - isPointFound = true; - } - if (!isPointFound) { - // There is no coincident points between tangential objects. Generate error message - myErrorMsg = SketchSolver_Error::NO_COINCIDENT_POINTS(); + if (aNbLines == 1 && aNbArcs == 1) + myType = CONSTRAINT_TANGENT_ARC_LINE; + else if (aNbArcs == 2) + myType = CONSTRAINT_TANGENT_ARC_ARC; + else { + myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); return; } - Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(), - getType(), myGroup->getWorkplaneId(), aValue, - SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, anEntities[0].h, anEntities[1].h); - aConstraint.other = aSlvsOtherFlag; - aConstraint.other2 = aSlvsOther2Flag; - aConstraint.h = myStorage->addConstraint(aConstraint); - mySlvsConstraints.push_back(aConstraint.h); - adjustConstraint(); -} + if (!hasSingleCoincidence(theAttributes[2], theAttributes[3])) + myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); + if (isSwap) { + EntityWrapperPtr aTemp = theAttributes[2]; + theAttributes[2] = theAttributes[3]; + theAttributes[3] = aTemp; + } +} diff --git a/src/SketchSolver/SketchSolver_ConstraintTangent.h b/src/SketchSolver/SketchSolver_ConstraintTangent.h index a6c744e44..e1716bf74 100644 --- a/src/SketchSolver/SketchSolver_ConstraintTangent.h +++ b/src/SketchSolver/SketchSolver_ConstraintTangent.h @@ -22,15 +22,11 @@ public: SketchSolver_Constraint(theConstraint) {} - virtual int getType() const - { return myType; } - protected: - /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints - virtual void process(); - -private: - int myType; ///< type of constraint (applicable: SLVS_C_ARC_LINE_TANGENT, SLVS_C_CURVE_CURVE_TANGENT) + /// \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(double& theValue, std::vector& theAttributes); }; #endif diff --git a/src/SketchSolver/SketchSolver_FeatureStorage.cpp b/src/SketchSolver/SketchSolver_FeatureStorage.cpp deleted file mode 100644 index 34d07b2bf..000000000 --- a/src/SketchSolver/SketchSolver_FeatureStorage.cpp +++ /dev/null @@ -1,418 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: SketchSolver_FeatureStorage.cpp -// Created: 23 Mar 2015 -// Author: Artem ZHIDKOV - -#include - -#include -#include -#include -#include - -void SketchSolver_FeatureStorage::changeConstraint(ConstraintPtr theConstraint) -{ - std::list anAttributes = theConstraint->data()->attributes(std::string()); - std::list::iterator anIter = anAttributes.begin(); - for (; anIter != anAttributes.end(); anIter++) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*anIter); - if (aRefAttr) { - if (!aRefAttr->isObject()) { - changeAttribute(aRefAttr->attr(), theConstraint); - continue; - } - ResultConstructionPtr aRC = std::dynamic_pointer_cast( - aRefAttr->object()); - FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) : - std::dynamic_pointer_cast(aRefAttr->object()); - if (aFeature) - changeFeature(aFeature, theConstraint); - continue; - } - AttributeRefListPtr aRefList = std::dynamic_pointer_cast(*anIter); - if (aRefList) { - std::list aList = aRefList->list(); - std::list::iterator aListIter = aList.begin(); - for (; aListIter != aList.end(); aListIter++) { - ResultConstructionPtr aRC = std::dynamic_pointer_cast( - *aListIter); - FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) : - std::dynamic_pointer_cast(*aListIter); - if (aFeature) - changeFeature(aFeature, theConstraint); - } - continue; - } - changeAttribute(*anIter, theConstraint); - } - myConstraints.insert(theConstraint); -} - -void SketchSolver_FeatureStorage::removeConstraint(ConstraintPtr theConstraint) -{ - DataPtr aData = theConstraint->data(); - if (aData) { // Constraint has data. Iterate through its attributes and remove them - std::list anAttributes = aData->attributes(std::string()); - std::list::iterator anIter = anAttributes.begin(); - for (; anIter != anAttributes.end(); anIter++) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*anIter); - if (aRefAttr) { - if (!aRefAttr->isObject()) { - removeAttribute(aRefAttr->attr(), theConstraint); - continue; - } - ResultConstructionPtr aRC = std::dynamic_pointer_cast( - aRefAttr->object()); - FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) : - std::dynamic_pointer_cast(aRefAttr->object()); - if (aFeature) - removeFeature(aFeature, theConstraint); - continue; - } - AttributeRefListPtr aRefList = std::dynamic_pointer_cast(*anIter); - if (aRefList) { - std::list aList = aRefList->list(); - std::list::iterator aListIter = aList.begin(); - for (; aListIter != aList.end(); aListIter++) { - ResultConstructionPtr aRC = std::dynamic_pointer_cast( - *aListIter); - FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) : - std::dynamic_pointer_cast(*aListIter); - if (aFeature) - removeFeature(aFeature, theConstraint); - } - continue; - } - removeAttribute(*anIter, theConstraint); - } - } else { // Constraint has no data. Search the links on it in the lists of back references for features and attributes - std::set::iterator aCIter; - MapFeatureConstraint::iterator aFeatIter = myFeatures.begin(); - while (aFeatIter != myFeatures.end()) { - aCIter = aFeatIter->second.find(theConstraint); - if (aCIter != aFeatIter->second.end()) { - FeaturePtr aFeature = aFeatIter->first; - aFeatIter++; - removeFeature(aFeature, theConstraint); - continue; - } - aFeatIter++; - } - std::set::iterator aFIter; - MapAttributeFeature::iterator anAttrIter = myAttributes.begin(); - while (anAttrIter != myAttributes.end()) { - aFIter = anAttrIter->second.find(theConstraint); - if (aFIter != anAttrIter->second.end()) { - anAttrIter->second.erase(aFIter); - if (anAttrIter->second.empty()) { - MapAttributeFeature::iterator aTmpIter = anAttrIter; // stores iterator for the next element, while the current is deleting - aTmpIter++; - myAttributes.erase(anAttrIter); - anAttrIter = aTmpIter; - continue; - } - } - anAttrIter++; - } - } - myConstraints.erase(theConstraint); -} - -bool SketchSolver_FeatureStorage::isInteract(ConstraintPtr theConstraint) const -{ - if (myConstraints.empty() || myConstraints.find(theConstraint) != myConstraints.end()) - return true; - - DataPtr aData = theConstraint->data(); - if (!aData) - return false; - - std::list anAttributes = aData->attributes(std::string()); - std::list::iterator anIter = anAttributes.begin(); - for (; anIter != anAttributes.end(); anIter++) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*anIter); - if (aRefAttr) { - if (!aRefAttr->isObject()) { - if (isInteract(aRefAttr->attr())) - return true; - continue; - } - ResultConstructionPtr aRC = std::dynamic_pointer_cast( - aRefAttr->object()); - FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) : - std::dynamic_pointer_cast(aRefAttr->object()); - if (aFeature) - if (isInteract(aFeature)) - return true; - continue; - } - AttributeRefListPtr aRefList = std::dynamic_pointer_cast(*anIter); - if (aRefList) { - std::list aList = aRefList->list(); - std::list::iterator aListIter = aList.begin(); - for (; aListIter != aList.end(); aListIter++) { - ResultConstructionPtr aRC = std::dynamic_pointer_cast( - *aListIter); - FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) : - std::dynamic_pointer_cast(*aListIter); - if (aFeature) - if (isInteract(aFeature)) - return true; - } - continue; - } - if (isInteract(*anIter)) - return true; - } - return false; -} - - -void SketchSolver_FeatureStorage::changeFeature(FeaturePtr theFeature) -{ - std::list anAttributes = theFeature->data()->attributes(std::string()); - std::list::iterator anIter = anAttributes.begin(); - for (; anIter != anAttributes.end(); anIter++) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*anIter); - if (aRefAttr) { - if (!aRefAttr->isObject()) - changeAttribute(aRefAttr->attr(), theFeature); - continue; - } - changeAttribute(*anIter, theFeature); - } - if (myFeatures.find(theFeature) == myFeatures.end()) - myFeatures[theFeature] = std::set(); -} - -void SketchSolver_FeatureStorage::changeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint) -{ - // Change all attributes of the feature - changeFeature(theFeature); - // Add back reference feature to constraint - myFeatures[theFeature].insert(theConstraint); -} - -void SketchSolver_FeatureStorage::removeFeature(FeaturePtr theFeature) -{ - MapFeatureConstraint::iterator aFeatIter = myFeatures.find(theFeature); - if (aFeatIter == myFeatures.end()) - return; // no such feature - - std::set aConstraints = aFeatIter->second; - std::set::iterator aCIter = aConstraints.begin(); - for (; aCIter != aConstraints.end(); aCIter++) - removeFeature(theFeature, *aCIter); -} - -void SketchSolver_FeatureStorage::removeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint) -{ - MapFeatureConstraint::iterator aFeatIter = myFeatures.find(theFeature); - if (aFeatIter == myFeatures.end()) - return; // no such feature - - if (theFeature->data()) { - std::list anAttributes = theFeature->data()->attributes(std::string()); - std::list::iterator anIter = anAttributes.begin(); - for (; anIter != anAttributes.end(); anIter++) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*anIter); - if (aRefAttr) { - if (!aRefAttr->isObject()) - removeAttribute(aRefAttr->attr(), theFeature); - continue; - } - removeAttribute(*anIter, theFeature); - } - } else { - // iterate on attributes to find items refered to theFeature - MapAttributeFeature::iterator anIter = myAttributes.begin(); - while (anIter != myAttributes.end()) { - if (anIter->second.find(theFeature) != anIter->second.end()) { - anIter->second.erase(theFeature); - if (anIter->second.empty()) { - MapAttributeFeature::iterator aDeadIter = anIter++; - myAttributes.erase(aDeadIter); - continue; - } - } - anIter++; - } - } - - aFeatIter->second.erase(theConstraint); - if (aFeatIter->second.empty()) - myFeatures.erase(aFeatIter); -} - -bool SketchSolver_FeatureStorage::isInteract(FeaturePtr theFeature) const -{ - if (myFeatures.find(theFeature) != myFeatures.end()) - return true; - if (!theFeature->data() || !theFeature->data()->isValid()) - return false; - - std::list anAttributes = theFeature->data()->attributes(std::string()); - std::list::iterator anIter = anAttributes.begin(); - for (; anIter != anAttributes.end(); anIter++) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*anIter); - if (aRefAttr) { - if (!aRefAttr->isObject()) - if (isInteract(aRefAttr->attr())) - return true; - continue; - } - if (isInteract(*anIter)) - return true; - } - return false; -} - - -void SketchSolver_FeatureStorage::changeAttribute(AttributePtr theAttribute) -{ - if (myAttributes.find(theAttribute) == myAttributes.end()) - myAttributes[theAttribute] = std::set(); -} - -void SketchSolver_FeatureStorage::changeAttribute(AttributePtr theAttribute, FeaturePtr theFeature) -{ - MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute); - if (anAttrIter == myAttributes.end()) { - std::set aFeatures; - aFeatures.insert(theFeature); - myAttributes[theAttribute] = aFeatures; - return; - } - anAttrIter->second.insert(theFeature); -} - -void SketchSolver_FeatureStorage::removeAttribute(AttributePtr theAttribute) -{ - MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute); - if (anAttrIter == myAttributes.end()) - return; - - std::set aFeatures = anAttrIter->second; - std::set::iterator aFeatIter = aFeatures.begin(); - for (; aFeatIter != aFeatures.end(); aFeatIter++) - removeAttribute(theAttribute, *aFeatIter); -} - -void SketchSolver_FeatureStorage::removeAttribute(AttributePtr theAttribute, FeaturePtr theFeature) -{ - MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute); - if (anAttrIter == myAttributes.end()) - return; // no such attribute - - anAttrIter->second.erase(theFeature); - if (!anAttrIter->second.empty()) - return; - - // Check there is no features containing such attribute - MapFeatureConstraint::iterator aFeatIter = myFeatures.begin(); - for (; aFeatIter != myFeatures.end(); aFeatIter++) { - DataPtr aData = aFeatIter->first->data(); - if (!aData || !aData->isValid()) - continue; - std::list anAttrList = aData->attributes(GeomDataAPI_Point2D::typeId()); - std::list::iterator anAtIt = anAttrList.begin(); - for (; anAtIt != anAttrList.end(); anAtIt++) { - std::shared_ptr aPoint = - std::dynamic_pointer_cast(*anAtIt); - if (aPoint == theAttribute) - anAttrIter->second.insert(aFeatIter->first); - } - } - if (anAttrIter->second.empty()) - myAttributes.erase(anAttrIter); -} - -bool SketchSolver_FeatureStorage::isInteract(AttributePtr theAttribute) const -{ - return myAttributes.find(theAttribute) != myAttributes.end(); -} - - -bool SketchSolver_FeatureStorage::isConsistent() const -{ - // Check the constraints are valid - std::set::const_iterator aCIter = myConstraints.begin(); - for (; aCIter != myConstraints.end(); aCIter++) - if (!(*aCIter)->data() || !(*aCIter)->data()->isValid()) - return false; - // Check the features are valid - MapFeatureConstraint::const_iterator aFIter = myFeatures.begin(); - for (; aFIter != myFeatures.end(); aFIter++) - if (!aFIter->first->data() || !aFIter->first->data()->isValid()) - return false; - return true; -} - -std::set SketchSolver_FeatureStorage::getConstraints(FeaturePtr theFeature) const -{ - std::set aResult; - MapFeatureConstraint::const_iterator aFeatIter = myFeatures.find(theFeature); - if (aFeatIter != myFeatures.end()) - aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end()); - - std::list anAttributes = theFeature->data()->attributes(std::string()); - std::list::const_iterator anAttrIter = anAttributes.begin(); - for (; anAttrIter != anAttributes.end(); anAttrIter++) { - MapAttributeFeature::const_iterator anIt = myAttributes.find(*anAttrIter); - if (anIt == myAttributes.end()) - continue; - std::set::const_iterator aFIter = anIt->second.begin(); - for (; aFIter != anIt->second.end(); aFIter++) { - aFeatIter = myFeatures.find(*aFIter); - if (aFeatIter != myFeatures.end()) - aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end()); - else { - ConstraintPtr aConstraint = std::dynamic_pointer_cast(*aFIter); - if (aConstraint) - aResult.insert(aConstraint); - } - } - } - return aResult; -} - -std::set SketchSolver_FeatureStorage::getConstraints(AttributePtr theAttribute) const -{ - std::set aResult; - MapAttributeFeature::const_iterator anIt = myAttributes.find(theAttribute); - if (anIt == myAttributes.end()) - return aResult; - std::set::const_iterator aFIter = anIt->second.begin(); - MapFeatureConstraint::const_iterator aFeatIter; - for (; aFIter != anIt->second.end(); aFIter++) { - aFeatIter = myFeatures.find(*aFIter); - if (aFeatIter != myFeatures.end()) - aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end()); - else { - ConstraintPtr aConstraint = std::dynamic_pointer_cast(*aFIter); - if (aConstraint) - aResult.insert(aConstraint); - } - } - return aResult; -} - -void SketchSolver_FeatureStorage::blockEvents(bool isBlocked) const -{ - std::set::iterator aCIter = myConstraints.begin(); - for (; aCIter != myConstraints.end(); aCIter++) - if ((*aCIter)->data() && (*aCIter)->data()->isValid()) - (*aCIter)->data()->blockSendAttributeUpdated(isBlocked); - - MapFeatureConstraint::const_iterator aFIter = myFeatures.begin(); - for (; aFIter != myFeatures.end(); aFIter++) - if (aFIter->first->data() && aFIter->first->data()->isValid()) - aFIter->first->data()->blockSendAttributeUpdated(isBlocked); - - MapAttributeFeature::const_iterator anAtIter = myAttributes.begin(); - for (; anAtIter != myAttributes.end(); anAtIter++) - if (anAtIter->first->owner() && anAtIter->first->owner()->data() && - anAtIter->first->owner()->data()->isValid()) - anAtIter->first->owner()->data()->blockSendAttributeUpdated(isBlocked); -} diff --git a/src/SketchSolver/SketchSolver_FeatureStorage.h b/src/SketchSolver/SketchSolver_FeatureStorage.h deleted file mode 100644 index 2cb36ba81..000000000 --- a/src/SketchSolver/SketchSolver_FeatureStorage.h +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: SketchSolver_FeatureStorage.h -// Created: 23 Mar 2015 -// Author: Artem ZHIDKOV - -#ifndef SketchSolver_FeatureStorage_H_ -#define SketchSolver_FeatureStorage_H_ - -#include -#include -#include - -#include -#include - -typedef std::map > MapFeatureConstraint; -typedef std::map > MapAttributeFeature; - -/** \class SketchSolver_FeatureStorage - * \ingroup Plugins - * \brief Collects information about SketchPlugin constraints used in specific group - */ -class SketchSolver_FeatureStorage -{ -public: - SketchSolver_FeatureStorage() {} - - /// \brief Adds or changes a constraint and all features it uses in the storage - void changeConstraint(ConstraintPtr theConstraint); - /// \brief Removes a constraint and all its features not used by other constraints - void removeConstraint(ConstraintPtr theConstraint); - /// \brief Verifies a constraint is used in the current storage - bool isInteract(ConstraintPtr theConstraint) const; - - /// \brief Adds or changes a feature in the storage - void changeFeature(FeaturePtr theFeature); - /// \brief Adds or changes a feature in the storage. The feature is used in specified constraint - void changeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint); - /// \brief Removes a feature - void removeFeature(FeaturePtr theFeature); - /// \brief Removes a feature according to a given constraint - void removeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint); - /// \brief Verifies a feature is used in the current storage - bool isInteract(FeaturePtr theFeature) const; - - /// \brief Adds or changes an attribute in the storage - void changeAttribute(AttributePtr theAttribute); - /// \brief Adds or changes a attribute in the storage. - /// The attribute is used in specified feature or constraint (theFeature) - void changeAttribute(AttributePtr theAttribute, FeaturePtr theFeature); - /// \brief Removes an attribute - void removeAttribute(AttributePtr theAttribute); - /// \brief Removes an attribute according to a given feature - void removeAttribute(AttributePtr theAttribute, FeaturePtr theFeature); - /// \brief Verifies an attribute is used in the current storage - bool isInteract(AttributePtr theAttribute) const; - - /// \brief Check the features is not removed - bool isConsistent() const; - - /// \brief Prepares list of constraints, which using specified feature or its attributes - std::set getConstraints(FeaturePtr theFeature) const; - /// \brief Prepares list of constraints, which using specified attribute - std::set getConstraints(AttributePtr theAttribute) const; - - /// \brief Block/unblock events of changing attributes of the features - void blockEvents(bool isBlocked) const; - -private: - std::set myConstraints; ///< list of SketchPlugin constraints used in the current group - MapFeatureConstraint myFeatures; ///< list of features used in the group and corresponding constraints which use the feature - MapAttributeFeature myAttributes; ///< list of attributes used in the group and corresponding features which are based on the attribute -}; - -typedef std::shared_ptr FeatureStoragePtr; - -#endif // SketchSolver_FeatureStorage_H_ diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index 9ad17d750..5b242b632 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -6,29 +6,19 @@ #include "SketchSolver_Group.h" -#include #include #include #include #include +#include #include #include -#include -#include -#include -#include -#include -#include -#include #include -#include #include -#include #include #include -#include #include #include #include @@ -43,16 +33,8 @@ #include #include #include -#include #include #include -#include - -#include -#include -#include -#include -#include #include #include @@ -63,9 +45,9 @@ class GroupIndexer { public: /// \brief Return vacant index - static Slvs_hGroup NEW_GROUP() { return ++myGroupIndex; } + static GroupID NEW_GROUP() { return ++myGroupIndex; } /// \brief Removes the index - static void REMOVE_GROUP(const Slvs_hGroup& theIndex) { + static void REMOVE_GROUP(const GroupID& theIndex) { if (myGroupIndex == theIndex) myGroupIndex--; } @@ -73,10 +55,10 @@ public: private: GroupIndexer() {}; - static Slvs_hGroup myGroupIndex; ///< index of the group + static GroupID myGroupIndex; ///< index of the group }; -Slvs_hGroup GroupIndexer::myGroupIndex = SLVS_G_OUTOFGROUP; +GroupID GroupIndexer::myGroupIndex = GID_OUTOFGROUP; static void sendMessage(const char* theMessageName) @@ -98,12 +80,8 @@ SketchSolver_Group::SketchSolver_Group( myPrevSolved(true) { // Initialize workplane - myWorkplaneID = SLVS_E_UNKNOWN; -#ifndef NDEBUG - assert(addWorkplane(theWorkplane)); -#else + myWorkplaneID = EID_UNKNOWN; addWorkplane(theWorkplane); -#endif } SketchSolver_Group::~SketchSolver_Group() @@ -127,85 +105,13 @@ bool SketchSolver_Group::isBaseWorkplane(CompositeFeaturePtr theWorkplane) const // Class: SketchSolver_Group // Purpose: verify are there any entities in the group used by given constraint // ============================================================================ -bool SketchSolver_Group::isInteract( - std::shared_ptr theFeature) const +bool SketchSolver_Group::isInteract(FeaturePtr theFeature) const { // Empty group interacts with everything - if (isEmpty()) return true; - ConstraintPtr aConstraint = std::dynamic_pointer_cast(theFeature); - if (aConstraint) - return myFeatureStorage->isInteract(aConstraint); - return myFeatureStorage->isInteract(std::dynamic_pointer_cast(theFeature)); -} - -// check the entity is really exists -static void checkEntity(StoragePtr theStorage, Slvs_hEntity& theEntity) -{ - if (theEntity == SLVS_E_UNKNOWN) - return; - Slvs_Entity anEnt = theStorage->getEntity(theEntity); - theEntity = anEnt.h; -} - -// ============================================================================ -// Function: getFeatureId -// Class: SketchSolver_Group -// Purpose: Find the identifier of the feature, if it already exists in the group -// ============================================================================ -Slvs_hEntity SketchSolver_Group::getFeatureId(FeaturePtr theFeature) const -{ - Slvs_hEntity aResult = SLVS_E_UNKNOWN; - if (!myFeatureStorage) - return aResult; - // Obtain regular constraints interacting with the feature and find its ID - ConstraintConstraintMap::const_iterator aCIter = myConstraints.begin(); - for (; aCIter != myConstraints.end(); ++aCIter) { - aResult = aCIter->second->getId(theFeature); - checkEntity(myStorage, aResult); - if (aResult != SLVS_E_UNKNOWN) - return aResult; - } - // The feature is not found, check it in the temporary constraints - std::set::iterator aTmpCIter = myTempConstraints.begin(); - for (; aTmpCIter != myTempConstraints.end() && aResult == SLVS_E_UNKNOWN; ++aTmpCIter) { - aResult = (*aTmpCIter)->getId(theFeature); - checkEntity(myStorage, aResult); - } - return aResult; -} - -// ============================================================================ -// Function: getAttributeId -// Class: SketchSolver_Group -// Purpose: Find the identifier of the attribute, if it already exists in the group -// ============================================================================ -Slvs_hEntity SketchSolver_Group::getAttributeId(AttributePtr theAttribute) const -{ - Slvs_hEntity aResult = SLVS_E_UNKNOWN; - if (!myFeatureStorage) - return aResult; - // Obtain regular constraints interacting with the attribute and find its ID - ConstraintConstraintMap::const_iterator aCIter = myConstraints.begin(); - for (; aCIter != myConstraints.end(); ++aCIter) { - aResult = aCIter->second->getId(theAttribute); - checkEntity(myStorage, aResult); - if (aResult != SLVS_E_UNKNOWN) - return aResult; - } - // The attribute is not found, check it in the temporary constraints - std::set::const_iterator aTmpCIter = myTempConstraints.begin(); - for (; aTmpCIter != myTempConstraints.end() && aResult == SLVS_E_UNKNOWN; ++aTmpCIter) { - aResult = (*aTmpCIter)->getId(theAttribute); - checkEntity(myStorage, aResult); - } - // Last chance to find attribute in parametric constraints - std::map::const_iterator aParIter = - myParametricConstraints.find(theAttribute); - if (aParIter != myParametricConstraints.end()) { - aResult = aParIter->second->getId(theAttribute); - checkEntity(myStorage, aResult); - } - return aResult; + if (isEmpty()) + return true; + // Check interaction with the storage + return myStorage->isInteract(theFeature); } // ============================================================================ @@ -217,7 +123,7 @@ bool SketchSolver_Group::changeConstraint( std::shared_ptr theConstraint) { // There is no workplane yet, something wrong - if (myWorkplaneID == SLVS_E_UNKNOWN) + if (myWorkplaneID == EID_UNKNOWN) return false; if (!theConstraint || !theConstraint->data()) @@ -226,131 +132,42 @@ bool SketchSolver_Group::changeConstraint( if (!checkFeatureValidity(theConstraint)) return false; + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + bool isNewConstraint = myConstraints.find(theConstraint) == myConstraints.end(); if (isNewConstraint) { // Add constraint to the current group - SolverConstraintPtr aConstraint = - SketchSolver_Builder::getInstance()->createConstraint(theConstraint); + SolverConstraintPtr aConstraint = aBuilder->createConstraint(theConstraint); if (!aConstraint) return false; - aConstraint->setGroup(this); - aConstraint->setStorage(myStorage); + aConstraint->process(myStorage, getId(), getWorkplaneId()); if (!aConstraint->error().empty()) { if (aConstraint->error() == SketchSolver_Error::NOT_INITIALIZED()) return false; // some attribute are not initialized yet, don't show message Events_Error::send(aConstraint->error(), this); } - - // Additional verification of coincidence of several points - if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { - bool hasMultiCoincidence = false; - ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); - for (; aCIter != myConstraints.end(); ++aCIter) { - std::shared_ptr aCoincidence = - std::dynamic_pointer_cast(aCIter->second); - if (!aCoincidence) - continue; - std::shared_ptr aCoinc2 = - std::dynamic_pointer_cast(aConstraint); - if (aCoincidence != aCoinc2 && aCoincidence->isCoincide(aCoinc2)) { - aCoinc2->attach(aCoincidence); - // update other coincidences - ConstraintConstraintMap::iterator anIt = aCIter; - for (++anIt; anIt != myConstraints.end(); ++anIt) - if (anIt->second == aCIter->second) - anIt->second = aCoinc2; - aCIter->second = aCoinc2; - hasMultiCoincidence = true; - } - } - - if (hasMultiCoincidence) - notifyMultiConstraints(); - } myConstraints[theConstraint] = aConstraint; } else myConstraints[theConstraint]->update(); - // Fix base features for fillet - if (isNewConstraint && theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) { - std::list anAttrList = - theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId()); - std::list::iterator anAttrIter = anAttrList.begin(); - for (; anAttrIter != anAttrList.end(); anAttrIter++) { - AttributeRefAttrPtr aRefAttr = - std::dynamic_pointer_cast(*anAttrIter); - if (!aRefAttr || !aRefAttr->isObject()) - continue; - FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); - SolverConstraintPtr aConstraint = - SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature); - if (!aConstraint) - continue; - aConstraint->setGroup(this); - aConstraint->setStorage(myStorage); - setTemporary(aConstraint); - } - } // Fix mirror line if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) { AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( theConstraint->attribute(SketchPlugin_ConstraintMirror::ENTITY_A())); if (aRefAttr && aRefAttr->isObject()) { - FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); + std::shared_ptr aFeature = + std::dynamic_pointer_cast( + ModelAPI_Feature::feature(aRefAttr->object())); if (aFeature) { - SolverConstraintPtr aConstraint = - SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature); + SolverConstraintPtr aConstraint = aBuilder->createFixedConstraint(aFeature); if (aConstraint) { - aConstraint->setGroup(this); - aConstraint->setStorage(myStorage); + aConstraint->process(myStorage, getId(), getWorkplaneId()); setTemporary(aConstraint); } } } } - - if (!myFeatureStorage) - myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage); - myFeatureStorage->changeConstraint(theConstraint); - - // Check the attributes of constraint are given by parametric expression - std::list anAttributes = - theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId()); - std::list::iterator anAttrIt = anAttributes.begin(); - for (; anAttrIt != anAttributes.end(); ++anAttrIt) { - AttributeRefAttrPtr aRefAttr = - std::dynamic_pointer_cast(*anAttrIt); - if (!aRefAttr) - continue; - - std::shared_ptr aPoint; - if (aRefAttr->isObject()) { - FeaturePtr aFeat = ModelAPI_Feature::feature(aRefAttr->object()); - if (aFeat->getKind() != SketchPlugin_Point::ID()) - continue; - aPoint = std::dynamic_pointer_cast( - aFeat->attribute(SketchPlugin_Point::COORD_ID())); - } else - aPoint = std::dynamic_pointer_cast(aRefAttr->attr()); - - if (!aPoint || (aPoint->textX().empty() && aPoint->textY().empty())) - continue; - - std::map::iterator aFound = - myParametricConstraints.find(aPoint); - if (aFound == myParametricConstraints.end()) { - SolverConstraintPtr aConstraint = - SketchSolver_Builder::getInstance()->createParametricConstraint(aPoint); - if (!aConstraint) - continue; - aConstraint->setGroup(this); - aConstraint->setStorage(myStorage); - myParametricConstraints[aPoint] = aConstraint; - } else - aFound->second->update(); - } - return true; } @@ -378,105 +195,37 @@ void SketchSolver_Group::updateConstraints() myChangedConstraints.clear(); } -bool SketchSolver_Group::updateFeature(std::shared_ptr theFeature) +bool SketchSolver_Group::updateFeature(FeaturePtr theFeature) { if (!checkFeatureValidity(theFeature)) return false; - - std::set aConstraints = - myFeatureStorage->getConstraints(std::dynamic_pointer_cast(theFeature)); - if (aConstraints.empty()) - return false; - std::set::iterator aCIter = aConstraints.begin(); - for (; aCIter != aConstraints.end(); aCIter++) { - ConstraintConstraintMap::iterator aSolConIter = myConstraints.find(*aCIter); - if (aSolConIter == myConstraints.end() || !aSolConIter->first->data() || - !aSolConIter->first->data()->isValid()) - continue; - myFeatureStorage->changeFeature(theFeature, aSolConIter->first); - - aSolConIter->second->addFeature(theFeature); - myChangedConstraints.insert(aSolConIter->first); - } - - // Search attributes of the feature in the set of parametric constraints and update them - std::list anAttrList = - theFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); - std::list::iterator anAttrIt = anAttrList.begin(); - for (; anAttrIt != anAttrList.end(); ++anAttrIt) { - std::map::iterator aFound = - myParametricConstraints.find(*anAttrIt); - if (aFound != myParametricConstraints.end()) - aFound->second->update(); - else { - std::shared_ptr aPoint = - std::dynamic_pointer_cast(*anAttrIt); - if (aPoint && (!aPoint->textX().empty() || !aPoint->textY().empty())) { - // Create new parametric constraint - SolverConstraintPtr aConstraint = - SketchSolver_Builder::getInstance()->createParametricConstraint(*anAttrIt); - if (!aConstraint) - continue; - aConstraint->setGroup(this); - aConstraint->setStorage(myStorage); - myParametricConstraints[*anAttrIt] = aConstraint; - } - } - } - return true; + myStorage->refresh(true); + return myStorage->update(theFeature); } -void SketchSolver_Group::moveFeature(std::shared_ptr theFeature) +void SketchSolver_Group::moveFeature(FeaturePtr theFeature) { - // Firstly, create temporary rigid constraint - SolverConstraintPtr aConstraint = - SketchSolver_Builder::getInstance()->createMovementConstraint(theFeature); + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + + // Firstly, revert changes in the fixed entities + myStorage->refresh(true); + + // Secondly, search attributes of the feature in the list of the Multi constraints and update them + ConstraintConstraintMap::iterator aCIt = myConstraints.begin(); + for (; aCIt != myConstraints.end(); ++aCIt) { + if ((aCIt->second->getType() == CONSTRAINT_MULTI_ROTATION || + aCIt->second->getType() == CONSTRAINT_MULTI_TRANSLATION) + && aCIt->second->isUsed(theFeature)) + std::dynamic_pointer_cast(aCIt->second)->update(true); + } + + // Then, create temporary rigid constraint + SolverConstraintPtr aConstraint = aBuilder->createMovementConstraint(theFeature); if (!aConstraint) return; - aConstraint->setGroup(this); - aConstraint->setStorage(myStorage); + aConstraint->process(myStorage, getId(), getWorkplaneId()); if (aConstraint->error().empty()) setTemporary(aConstraint); - // Secondly, update the feature - updateFeature(theFeature); -} - -// ============================================================================ -// Function: fixFeaturesList -// Class: SketchSolver_Group -// Purpose: Apply temporary rigid constraints for the list of features -// ============================================================================ -void SketchSolver_Group::fixFeaturesList(AttributeRefListPtr theList) -{ - std::list aList = theList->list(); - std::list::iterator anIt = aList.begin(); - std::list aFeatures; - // Sort features, at begining there are features used by Equal constraint - for (; anIt != aList.end(); anIt++) { - if (!(*anIt)) - continue; - FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt); - std::set aConstraints = myFeatureStorage->getConstraints(aFeature); - std::set::iterator aCIter = aConstraints.begin(); - for (; aCIter != aConstraints.end(); aCIter++) - if ((*aCIter)->getKind() == SketchPlugin_ConstraintEqual::ID()) - break; - if (aCIter != aConstraints.end()) - aFeatures.push_front(aFeature); - else - aFeatures.push_back(aFeature); - } - - std::list::iterator aFeatIter = aFeatures.begin(); - for (; aFeatIter != aFeatures.end(); aFeatIter++) { - SolverConstraintPtr aConstraint = - SketchSolver_Builder::getInstance()->createRigidConstraint(*aFeatIter); - if (!aConstraint) - continue; - aConstraint->setGroup(this); - aConstraint->setStorage(myStorage); - setTemporary(aConstraint); - } } // ============================================================================ @@ -486,11 +235,14 @@ void SketchSolver_Group::fixFeaturesList(AttributeRefListPtr theList) // ============================================================================ bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch) { - if (myWorkplaneID != SLVS_E_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID()) + if (myWorkplaneID != EID_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID()) return false; // the workplane already exists or the function parameter is not Sketch mySketch = theSketch; - updateWorkplane(); + if (!updateWorkplane()) { + mySketch = CompositeFeaturePtr(); + return false; + } return true; } @@ -501,55 +253,17 @@ bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch) // ============================================================================ bool SketchSolver_Group::updateWorkplane() { + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); if (!myStorage) // Create storage if not exists - myStorage = StoragePtr(new SketchSolver_Storage); - SketchSolver_Builder* aBuilder = SketchSolver_Builder::getInstance(); + myStorage = aBuilder->createStorage(getId()); - std::vector anEntities; - std::vector aParams; - if (!aBuilder->createWorkplane(mySketch, anEntities, aParams)) - return false; - - if (myWorkplaneID == SLVS_E_UNKNOWN) { - myWorkplaneID = anEntities.back().h; - // Add new workplane elements - std::vector::iterator aParIter = aParams.begin(); - for (; aParIter != aParams.end(); aParIter++) { - aParIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage - aParIter->group = SLVS_G_OUTOFGROUP; - aParIter->h = myStorage->addParameter(*aParIter); - } - std::vector::iterator anEntIter = anEntities.begin(); - for (; anEntIter != anEntities.end(); anEntIter++) { - anEntIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage - anEntIter->group = SLVS_G_OUTOFGROUP; - anEntIter->wrkpl = myWorkplaneID; - for (int i = 0; i < 4; i++) - if (anEntIter->param[i] != SLVS_E_UNKNOWN) - anEntIter->param[i] = aParams[anEntIter->param[i]-1].h; - for (int i = 0; i < 4; i++) - if (anEntIter->point[i] != SLVS_E_UNKNOWN) - anEntIter->point[i] = anEntities[anEntIter->point[i]-1].h; - anEntIter->h = myStorage->addEntity(*anEntIter); - } - } else { - // Update existent workplane - const Slvs_Entity& aWP = myStorage->getEntity(myWorkplaneID); - const Slvs_Entity& anOrigin = myStorage->getEntity(aWP.point[0]); - const Slvs_Entity& aNormal = myStorage->getEntity(aWP.normal); - // Get parameters and update them - Slvs_hParam aWPParams[7] = { - anOrigin.param[0], anOrigin.param[1], anOrigin.param[2], - aNormal.param[0], aNormal.param[1], aNormal.param[2], aNormal.param[3] - }; - std::vector::iterator aParIter = aParams.begin(); - for (int i = 0; aParIter != aParams.end(); aParIter++, i++) { - Slvs_Param aParam = myStorage->getParameter(aWPParams[i]); - aParam.val = aParIter->val; - myStorage->updateParameter(aParam); - } + // sketch should be unchanged, set it out of current group + bool isUpdated = myStorage->update(FeaturePtr(mySketch), GID_OUTOFGROUP); + if (isUpdated) { + EntityWrapperPtr anEntity = myStorage->entity(FeaturePtr(mySketch)); + myWorkplaneID = anEntity->id(); } - return myWorkplaneID > 0; + return isUpdated; } // ============================================================================ @@ -565,33 +279,36 @@ bool SketchSolver_Group::resolveConstraints() bool aResolved = false; bool isGroupEmpty = isEmpty(); if (myStorage->isNeedToResolve() && !isGroupEmpty) { - myConstrSolver.setGroupID(myID); - myConstrSolver.calculateFailedConstraints(false); - myStorage->initializeSolver(myConstrSolver); + if (!mySketchSolver) + mySketchSolver = SketchSolver_Manager::instance()->builder()->createSolver(); - int aResult = SLVS_RESULT_OKAY; + mySketchSolver->setGroup(myID); + mySketchSolver->calculateFailedConstraints(false); + myStorage->initializeSolver(mySketchSolver); + + SketchSolver_SolveStatus aResult = STATUS_OK; try { if (myStorage->hasDuplicatedConstraint()) - aResult = SLVS_RESULT_INCONSISTENT; + aResult = STATUS_INCONSISTENT; else { // To avoid overconstraint situation, we will remove temporary constraints one-by-one // and try to find the case without overconstraint bool isLastChance = false; - int aNbTemp = myStorage->numberTemporary(); + size_t aNbTemp = myStorage->nbTemporary(); while (true) { - aResult = myConstrSolver.solve(); - if (aResult == SLVS_RESULT_OKAY || isLastChance) + aResult = mySketchSolver->solve(); + if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET || isLastChance) break; - if (aNbTemp <= 0) { + if (aNbTemp == 0) { // try to update parameters and resolve once again ConstraintConstraintMap::iterator aConstrIt = myConstraints.begin(); for (; aConstrIt != myConstraints.end(); ++aConstrIt) aConstrIt->second->update(); isLastChance = true; } else - aNbTemp = myStorage->deleteTemporaryConstraint(); - myConstrSolver.calculateFailedConstraints(true); // something failed => need to find it - myStorage->initializeSolver(myConstrSolver); + aNbTemp = myStorage->removeTemporary(); + mySketchSolver->calculateFailedConstraints(true); // something failed => need to find it + myStorage->initializeSolver(mySketchSolver); } } } catch (...) { @@ -604,17 +321,8 @@ bool SketchSolver_Group::resolveConstraints() } return false; } - if (aResult == SLVS_RESULT_OKAY) { // solution succeeded, store results into correspondent attributes - myFeatureStorage->blockEvents(true); - // First refresh parametric constraints to satisfy parameters - std::map::iterator aParIter = myParametricConstraints.begin(); - for (; aParIter != myParametricConstraints.end(); ++aParIter) - aParIter->second->refresh(); - // Update all other constraints - ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin(); - for (; aConstrIter != myConstraints.end(); ++aConstrIter) - aConstrIter->second->refresh(); - myFeatureStorage->blockEvents(false); + if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET) { // solution succeeded, store results into correspondent attributes + myStorage->refresh(); if (!myPrevSolved) { getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(""); // the error message should be changed before sending the message @@ -633,15 +341,15 @@ bool SketchSolver_Group::resolveConstraints() aResolved = true; } else if (!isGroupEmpty) { - myFeatureStorage->blockEvents(true); // Check there are constraints Fixed. If they exist, update parameters by stored values ConstraintConstraintMap::iterator aCIt = myConstraints.begin(); for (; aCIt != myConstraints.end(); ++aCIt) if (aCIt->first->getKind() == SketchPlugin_ConstraintRigid::ID()) { - aCIt->second->refresh(); aResolved = true; + break; } - myFeatureStorage->blockEvents(false); + if (aCIt != myConstraints.end()) + myStorage->refresh(); } removeTemporaryConstraints(); myStorage->setNeedToResolve(false); @@ -658,8 +366,6 @@ void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup) // If specified group is empty, no need to merge if (theGroup.isEmpty()) return; - if (!myFeatureStorage) - myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage); std::set aConstraints; ConstraintConstraintMap::const_iterator aConstrIter = theGroup.myConstraints.begin(); @@ -681,27 +387,27 @@ void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup) // Class: SketchSolver_Group // Purpose: divide the group into several subgroups // ============================================================================ -void SketchSolver_Group::splitGroup(std::vector& theCuts) +void SketchSolver_Group::splitGroup(std::list& theCuts) { + // New storage will be used in trimmed way to store the list of constraint interacted together. + StoragePtr aNewStorage = SketchSolver_Manager::instance()->builder()->createStorage(getId()); + std::list aDummyVec; // empty vector to avoid creation of solver's constraints + // Obtain constraints, which should be separated - FeatureStoragePtr aNewFeatStorage(new SketchSolver_FeatureStorage); - std::vector anUnusedConstraints; + std::list anUnusedConstraints; ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); for ( ; aCIter != myConstraints.end(); aCIter++) { - std::list aBaseConstraints = aCIter->second->constraints(); - std::list::iterator anIter = aBaseConstraints.begin(); - for (; anIter != aBaseConstraints.end(); anIter++) - if (aNewFeatStorage->isInteract(*anIter)) { - aNewFeatStorage->changeConstraint(*anIter); - } else - anUnusedConstraints.push_back(*anIter); + if (aNewStorage->isInteract(FeaturePtr(aCIter->first))) + aNewStorage->addConstraint(aCIter->first, aDummyVec); + else + anUnusedConstraints.push_back(aCIter->first); } // Check the unused constraints once again, because they may become interacted with new storage since adding constraints - std::vector::iterator aUnuseIt = anUnusedConstraints.begin(); + std::list::iterator aUnuseIt = anUnusedConstraints.begin(); while (aUnuseIt != anUnusedConstraints.end()) { - if (aNewFeatStorage->isInteract(*aUnuseIt)) { - aNewFeatStorage->changeConstraint(*aUnuseIt); + if (aNewStorage->isInteract(FeaturePtr(*aUnuseIt))) { + aNewStorage->addConstraint(*aUnuseIt, aDummyVec); anUnusedConstraints.erase(aUnuseIt); aUnuseIt = anUnusedConstraints.begin(); continue; @@ -709,13 +415,13 @@ void SketchSolver_Group::splitGroup(std::vector& theCuts) aUnuseIt++; } - std::vector::iterator aCutsIter; + std::list::iterator aCutsIter; aUnuseIt = anUnusedConstraints.begin(); - for ( ; aUnuseIt != anUnusedConstraints.end(); aUnuseIt++) { + for ( ; aUnuseIt != anUnusedConstraints.end(); ++aUnuseIt) { // Remove unused constraints removeConstraint(*aUnuseIt); // Try to append constraint to already existent group - for (aCutsIter = theCuts.begin(); aCutsIter != theCuts.end(); aCutsIter++) + for (aCutsIter = theCuts.begin(); aCutsIter != theCuts.end(); ++aCutsIter) if ((*aCutsIter)->isInteract(*aUnuseIt)) { (*aCutsIter)->changeConstraint(*aUnuseIt); break; @@ -725,11 +431,17 @@ void SketchSolver_Group::splitGroup(std::vector& theCuts) SketchSolver_Group* aGroup = new SketchSolver_Group(mySketch); aGroup->changeConstraint(*aUnuseIt); theCuts.push_back(aGroup); + } else { + // Find other groups interacting with constraint + std::list::iterator aBaseGroupIt = aCutsIter; + for (++aCutsIter; aCutsIter != theCuts.end(); ++aCutsIter) + if ((*aCutsIter)->isInteract(*aUnuseIt)) { + (*aBaseGroupIt)->mergeGroups(**aCutsIter); + std::list::iterator aRemoveIt = aCutsIter--; + theCuts.erase(aRemoveIt); + } } } - - // Update feature storage - myFeatureStorage = aNewFeatStorage; } // ============================================================================ @@ -739,12 +451,24 @@ void SketchSolver_Group::splitGroup(std::vector& theCuts) // ============================================================================ bool SketchSolver_Group::isConsistent() { - if (!myFeatureStorage) // no one constraint is initialized yet + if (isEmpty()) // no one constraint is initialized yet return true; - bool aResult = myFeatureStorage->isConsistent(); + // Check the features and constraint is the storage are valid + bool aResult = myStorage->isConsistent(); + if (aResult) { + // additional check of consistency of the Fixed constraint, + // because they are not added to the storage + ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); + for (; aCIter != myConstraints.end(); ++aCIter) + if (aCIter->first->getKind() == SketchPlugin_ConstraintRigid::ID() && + (!aCIter->first->data() || !aCIter->first->data()->isValid())) { + aResult = false; + break; + } + } if (!aResult) { - // remove invalid entities + // remove invalid constraints std::set anInvalidConstraints; ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); for (; aCIter != myConstraints.end(); ++aCIter) { @@ -754,6 +478,8 @@ bool SketchSolver_Group::isConsistent() std::set::const_iterator aRemoveIt = anInvalidConstraints.begin(); for (; aRemoveIt != anInvalidConstraints.end(); ++aRemoveIt) removeConstraint(*aRemoveIt); + // remove invalid features + myStorage->removeInvalidEntities(); } return aResult; } @@ -769,16 +495,15 @@ void SketchSolver_Group::removeTemporaryConstraints() std::set::iterator aTmpIt = myTempConstraints.begin(); for (; aTmpIt != myTempConstraints.end(); ++aTmpIt) (*aTmpIt)->remove(); - myTempConstraints.clear(); - while (myStorage->numberTemporary()) - myStorage->deleteTemporaryConstraint(); - // Clean lists of removed entities in the storage - std::set aRemPar; - std::set aRemEnt; - std::set aRemCon; - myStorage->getRemoved(aRemPar, aRemEnt, aRemCon); + size_t aNbTemp = myStorage->nbTemporary(); + if (aNbTemp > 0) + myStorage->removeTemporary(aNbTemp); + + if (!myTempConstraints.empty()) + myStorage->verifyFixed(); myStorage->setNeedToResolve(false); + myTempConstraints.clear(); } // ============================================================================ @@ -789,20 +514,16 @@ void SketchSolver_Group::removeTemporaryConstraints() void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint) { bool isFullyRemoved = true; - myFeatureStorage->removeConstraint(theConstraint); ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); for (; aCIter != myConstraints.end(); aCIter++) - if (aCIter->second->hasConstraint(theConstraint)) { - if (!aCIter->second->remove(theConstraint)) // the constraint is not fully removed + if (aCIter->first == theConstraint) { + if (!aCIter->second->remove()) // the constraint is not fully removed isFullyRemoved = false; break; } if (aCIter == myConstraints.end()) return; - // Remove entities not used by constraints - myStorage->removeUnusedEntities(); - if (isFullyRemoved) myConstraints.erase(aCIter); else if (aCIter != myConstraints.end() && @@ -817,7 +538,7 @@ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint) } if (aCIter->first != theConstraint) aMultiCoinc.push_back(aCIter->first); - aCIter->second->remove(aCIter->first); + aCIter->second->remove(); ConstraintConstraintMap::iterator aRemoveIt = aCIter++; myConstraints.erase(aRemoveIt); } @@ -825,8 +546,6 @@ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint) std::list::iterator anIt = aMultiCoinc.begin(); for (; anIt != aMultiCoinc.end(); ++anIt) changeConstraint(*anIt); - - notifyMultiConstraints(); } } @@ -845,7 +564,7 @@ bool SketchSolver_Group::isComplexConstraint(FeaturePtr theConstraint) // ============================================================================ // Function: setTemporary // Class: SketchSolver_Group -// Purpose: append given constraint to th group of temporary constraints +// Purpose: append given constraint to the group of temporary constraints // ============================================================================ void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint) { @@ -869,24 +588,6 @@ bool SketchSolver_Group::checkFeatureValidity(FeaturePtr theFeature) return aFactory->validate(theFeature); } -// ============================================================================ -// Function: notifyMultiConstraints -// Class: SketchSolver_Group -// Purpose: Update Multi-Translation/-Rotation constraints due to multi coincidence appears/disappears -// ============================================================================ -void SketchSolver_Group::notifyMultiConstraints() -{ - ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); - for (; aCIter != myConstraints.end(); ++aCIter) { - if (aCIter->first->getKind() == SketchPlugin_MultiRotation::ID() || - aCIter->first->getKind() == SketchPlugin_MultiTranslation::ID()) { - std::shared_ptr aMulti = - std::dynamic_pointer_cast(aCIter->second); - aMulti->checkCoincidence(); - } - } -} - diff --git a/src/SketchSolver/SketchSolver_Group.h b/src/SketchSolver/SketchSolver_Group.h index 507386d03..4eb67e619 100644 --- a/src/SketchSolver/SketchSolver_Group.h +++ b/src/SketchSolver/SketchSolver_Group.h @@ -10,18 +10,14 @@ #include "SketchSolver.h" #include #include -#include -#include +#include #include -#include #include -#include #include #include #include -#include #include typedef std::map ConstraintConstraintMap; @@ -42,22 +38,17 @@ class SketchSolver_Group ~SketchSolver_Group(); /// \brief Returns group's unique identifier - inline const Slvs_hGroup& getId() const + inline const GroupID& getId() const { return myID; } /// \brief Returns identifier of the workplane - inline const Slvs_hEntity& getWorkplaneId() const + inline const EntityID& getWorkplaneId() const { return myWorkplaneID; } - /// \brief Find the identifier of the feature, if it already exists in the group - Slvs_hEntity getFeatureId(FeaturePtr theFeature) const; - /// \brief Find the identifier of the attribute, if it already exists in the group - Slvs_hEntity getAttributeId(AttributePtr theAttribute) const; - /// \brief Returns true if the group has no constraints yet inline bool isEmpty() const { @@ -82,19 +73,19 @@ class SketchSolver_Group /** \brief Updates the data corresponding the specified feature * \param[in] theFeature the feature to be updated */ - bool updateFeature(std::shared_ptr theFeature); + bool updateFeature(FeaturePtr 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 */ - void moveFeature(std::shared_ptr theFeature); + void moveFeature(FeaturePtr theFeature); /** \brief Verifies the feature attributes are used in this group * \param[in] theFeature constraint or any other object for verification of interaction * \return \c true if some of attributes are used in current group */ - bool isInteract(std::shared_ptr theFeature) const; + bool isInteract(FeaturePtr theFeature) const; /** \brief Verifies the specified feature is equal to the base workplane for this group * \param[in] theWorkplane the feature to be compared with base workplane @@ -126,7 +117,7 @@ class SketchSolver_Group /** \brief Cut from the group several subgroups, which are not connected to the current one by any constraint * \param[out] theCuts enlarge this list by newly created groups */ - void splitGroup(std::vector& theCuts); + void splitGroup(std::list& theCuts); /** \brief Start solution procedure if necessary and update attributes of features * \return \c false when no need to solve constraints @@ -155,10 +146,7 @@ private: */ bool addWorkplane(CompositeFeaturePtr theSketch); - /// \brief Apply temporary rigid constraints for the list of features - void fixFeaturesList(AttributeRefListPtr theList); - - /// \brief Append given constraint to th group of temporary constraints + /// \brief Append given constraint to the group of temporary constraints void setTemporary(SolverConstraintPtr theConstraint); /// \brief Verifies is the feature valid @@ -167,12 +155,9 @@ private: /// \brief Update just changed constraints void updateConstraints(); - /// \brief Update Multi-Translation/-Rotation constraints due to multi coincidence appears/disappears - void notifyMultiConstraints(); - private: - Slvs_hGroup myID; ///< Index of the group - Slvs_hEntity myWorkplaneID; ///< Index of workplane, the group is based on + GroupID myID; ///< Index of the group + EntityID myWorkplaneID; ///< Index of workplane, the group is based on CompositeFeaturePtr mySketch; ///< Sketch is equivalent to workplane ConstraintConstraintMap myConstraints; ///< List of constraints std::set myTempConstraints; ///< List of temporary constraints @@ -180,9 +165,8 @@ private: std::set myChangedConstraints; ///< List of just updated constraints StoragePtr myStorage; ///< Container for the set of SolveSpace constraints and their entities - FeatureStoragePtr myFeatureStorage; ///< Container for the set of SketchPlugin features and their dependencies - SketchSolver_Solver myConstrSolver; ///< Solver for set of equations obtained by constraints + SolverPtr mySketchSolver; ///< Solver for set of equations obtained by constraints bool myPrevSolved; ///< Indicates that previous solving was done correctly }; diff --git a/src/SketchSolver/SketchSolver_IConstraintWrapper.h b/src/SketchSolver/SketchSolver_IConstraintWrapper.h new file mode 100644 index 000000000..a0dd5261b --- /dev/null +++ b/src/SketchSolver/SketchSolver_IConstraintWrapper.h @@ -0,0 +1,103 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_IConstraintWrapper.h +// Created: 30 Nov 2015 +// Author: Artem ZHIDKOV + +#ifndef SketchSolver_IConstraintWrapper_H_ +#define SketchSolver_IConstraintWrapper_H_ + +#include + +#include + +#include +#include + +/// Types of constraints +enum SketchSolver_ConstraintType { + CONSTRAINT_UNKNOWN = 0, + CONSTRAINT_COINCIDENCE, // base coincidence if we don't know exact type yet + CONSTRAINT_PT_PT_COINCIDENT, + CONSTRAINT_PT_ON_LINE, + CONSTRAINT_PT_ON_CIRCLE, + CONSTRAINT_DISTANCE, // base distance if we don't know the measured objects yet + CONSTRAINT_PT_PT_DISTANCE, + CONSTRAINT_PT_LINE_DISTANCE, + CONSTRAINT_RADIUS, + CONSTRAINT_ANGLE, + CONSTRAINT_FIXED, + CONSTRAINT_HORIZONTAL, + CONSTRAINT_VERTICAL, + CONSTRAINT_PARALLEL, + CONSTRAINT_PERPENDICULAR, + CONSTRAINT_SYMMETRIC, + CONSTRAINT_EQUAL, // base equality if we don't know the measured objects yet + CONSTRAINT_EQUAL_LINES, + CONSTRAINT_EQUAL_LINE_ARC, + CONSTRAINT_EQUAL_RADIUS, + CONSTRAINT_TANGENT, // base tangency if we don't know the measured objects yet + CONSTRAINT_TANGENT_ARC_LINE, + CONSTRAINT_TANGENT_ARC_ARC, + CONSTRAINT_MULTI_TRANSLATION, + CONSTRAINT_MULTI_ROTATION +}; + +/** + * Wrapper providing operations with constraints regardless the solver. + */ +class SketchSolver_IConstraintWrapper +{ +public: + virtual ~SketchSolver_IConstraintWrapper() {} + + /// \brief Return base feature + const ConstraintPtr& baseConstraint() const + { return myBaseConstraint; } + + /// \brief Return ID of current entity + virtual ConstraintID id() const = 0; + + /// \brief Change group for the constraint + virtual void setGroup(const GroupID& theGroup) = 0; + /// \brief Return identifier of the group the constraint belongs to + virtual GroupID group() const = 0; + + /// \brief Return type of current entity + virtual SketchSolver_ConstraintType type() const = 0; + + /// \brief Assign list of constrained objects + void setEntities(const std::list& theEntities) + { myConstrained = theEntities; } + /// \brief Return list of constrained objects + const std::list& entities() const + { return myConstrained; } + + /// \brief Assign numeric parameter of constraint + virtual void setValue(const double& theValue) + { myValue = theValue; } + /// \brief Return numeric parameter of constraint + const double& value() const + { return myValue; } + + /// \brief Verify the feature is used in the constraint + virtual bool isUsed(FeaturePtr theFeature) const = 0; + /// \brief Verify the attribute is used in the constraint + virtual bool isUsed(AttributePtr theAttribute) const = 0; + + /// \brief Compare current constraint with other + virtual bool isEqual(const std::shared_ptr& theOther) = 0; + + /// \brief Update values of parameters of this constraint by the parameters of given one + /// \return \c true if some parameters change their values + virtual bool update(const std::shared_ptr& theOther) = 0; + +protected: + ConstraintPtr myBaseConstraint; + std::list myConstrained; + double myValue; +}; + +typedef std::shared_ptr ConstraintWrapperPtr; + +#endif diff --git a/src/SketchSolver/SketchSolver_IEntityWrapper.h b/src/SketchSolver/SketchSolver_IEntityWrapper.h new file mode 100644 index 000000000..49f4d796e --- /dev/null +++ b/src/SketchSolver/SketchSolver_IEntityWrapper.h @@ -0,0 +1,100 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_IEntityWrapper.h +// Created: 30 Nov 2015 +// Author: Artem ZHIDKOV + +#ifndef SketchSolver_IEntityWrapper_H_ +#define SketchSolver_IEntityWrapper_H_ + +#include +#include + +#include +#include + +#include +#include + +/// Types of entities +enum SketchSolver_EntityType { + ENTITY_UNKNOWN = 0, + ENTITY_SCALAR, + ENTITY_POINT, + ENTITY_NORMAL, + ENTITY_LINE, + ENTITY_CIRCLE, + ENTITY_ARC, + ENTITY_SKETCH +}; + +/** + * Wrapper providing operations with entities regardless the solver. + */ +class SketchSolver_IEntityWrapper +{ +public: + virtual ~SketchSolver_IEntityWrapper() {} + + /// \brief Return base feature + const FeaturePtr& baseFeature() const + { return myBaseFeature; } + /// \brief Return base attribute + const AttributePtr& baseAttribute() const + { return myBaseAttribute; } + + /// \brief Check the feature is basis for this wrapper + bool isBase(FeaturePtr theFeature) const + { return myBaseFeature && myBaseFeature == theFeature; } + /// \brief Check the attribute is basis for this wrapper + bool isBase(AttributePtr theAttribute) const + { return myBaseAttribute && myBaseAttribute == theAttribute; } + + /// \brief Assign list of parameters for this entity + void setParameters(const std::list& theParams) + { myParameters = theParams; } + /// \brief Return list of parameters + const std::list& parameters() const + { return myParameters; } + + /// \brief Assign list of sub-entities + void setSubEntities(const std::list >& theEntities) + { mySubEntities = theEntities; } + /// \brief Return list of sub-entities + const std::list >& subEntities() const + { return mySubEntities; } + + /// \brief Return ID of current entity + virtual EntityID id() const = 0; + + /// \brief Change group for the entity + virtual void setGroup(const GroupID& theGroup) = 0; + /// \brief Return identifier of the group the entity belongs to + virtual GroupID group() const = 0; + + /// \brief Return type of current entity + virtual SketchSolver_EntityType type() const = 0; + + /// \brief Verify the feature is used in the entity + virtual bool isUsed(FeaturePtr theFeature) const = 0; + /// \brief Verify the attribute is used in the entity + virtual bool isUsed(AttributePtr theAttribute) const = 0; + + /// \brief Compare current entity with other + virtual bool isEqual(const std::shared_ptr& theOther) = 0; + + /// \brief Update values of parameters of this entity by the parameters of given one + /// \return \c true if some parameters change their values + virtual bool update(const std::shared_ptr& theOther) = 0; + +protected: + FeaturePtr myBaseFeature; + AttributePtr myBaseAttribute; + + std::list myParameters; + std::list > mySubEntities; +}; + +typedef std::shared_ptr EntityWrapperPtr; + +#endif diff --git a/src/SketchSolver/SketchSolver_IParameterWrapper.h b/src/SketchSolver/SketchSolver_IParameterWrapper.h new file mode 100644 index 000000000..751e3464b --- /dev/null +++ b/src/SketchSolver/SketchSolver_IParameterWrapper.h @@ -0,0 +1,55 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_IParameterWrapper.h +// Created: 1 Dec 2015 +// Author: Artem ZHIDKOV + +#ifndef SketchSolver_IParameterWrapper_H_ +#define SketchSolver_IParameterWrapper_H_ + +#include + +#include + +/** + * Wrapper providing operations with parameters regardless the solver. + */ +class SketchSolver_IParameterWrapper +{ +public: + virtual ~SketchSolver_IParameterWrapper() {} + + /// \brief Return ID of current parameter + virtual ParameterID id() const = 0; + + /// \brief Change group for the parameter + virtual void setGroup(const GroupID& theGroup) = 0; + /// \brief Return identifier of the group the parameter belongs to + virtual GroupID group() const = 0; + + /// \brief Change value of parameter + virtual void setValue(double theValue) = 0; + /// \brief Return value of parameter + virtual double value() const = 0; + + /// \brief Set or unset flag the parameter is given by expression + void setIsParametric(bool isParametric) + { myIsParametric = isParametric; } + /// \brief Show the parameter is an expression + bool isParametric() const + { return myIsParametric; } + + /// \brief Compare current parameter with other + virtual bool isEqual(const std::shared_ptr& theOther) = 0; + + /// \brief Update value of parameter by the given one + /// \return \c true if the value of parameter is changed + virtual bool update(const std::shared_ptr& theOther) = 0; + +protected: + bool myIsParametric; ///< indicate the parameter is given by parametric expression +}; + +typedef std::shared_ptr ParameterWrapperPtr; + +#endif diff --git a/src/SketchSolver/SketchSolver_ISolver.h b/src/SketchSolver/SketchSolver_ISolver.h new file mode 100644 index 000000000..75ddbfdf4 --- /dev/null +++ b/src/SketchSolver/SketchSolver_ISolver.h @@ -0,0 +1,50 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_ISolver.h +// Created: 30 Nov 2015 +// Author: Artem ZHIDKOV + +#ifndef SketchSolver_ISolver_H_ +#define SketchSolver_ISolver_H_ + +#include + +#include + +/// The result of constraints solution +enum SketchSolver_SolveStatus { + STATUS_OK, + STATUS_INCONSISTENT, + STATUS_EMPTYSET, + STATUS_FAILED // set if no one other status is applicable +}; + + +/** + * Interface providing operations to solve sketches. + */ +class SketchSolver_ISolver +{ +public: + virtual ~SketchSolver_ISolver() {} + + /// \brief Changes the ID of the group to solve + void setGroup(const GroupID& theGroupID) + { myGroup = theGroupID; } + + /// \brief Set or unset the flag which allows to find all failed constraints + void calculateFailedConstraints(bool theSic) + { myFindFaileds = theSic; } + + /// \brief Solve the set of equations + /// \return identifier whether solution succeeded + virtual SketchSolver_SolveStatus solve() = 0; + +protected: + GroupID myGroup; ///< ID of the group to be solved + bool myFindFaileds; ///< flag to find conflicting or inappropriate constraints +}; + +typedef std::shared_ptr SolverPtr; + +#endif diff --git a/src/SketchSolver/SketchSolver_ConstraintManager.cpp b/src/SketchSolver/SketchSolver_Manager.cpp similarity index 88% rename from src/SketchSolver/SketchSolver_ConstraintManager.cpp rename to src/SketchSolver/SketchSolver_Manager.cpp index 682bbf23a..442cf15c2 100644 --- a/src/SketchSolver/SketchSolver_ConstraintManager.cpp +++ b/src/SketchSolver/SketchSolver_Manager.cpp @@ -1,10 +1,10 @@ // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -// File: SketchSolver_ConstraintManager.cpp +// File: SketchSolver_Manager.cpp // Created: 08 May 2014 // Author: Artem ZHIDKOV -#include "SketchSolver_ConstraintManager.h" +#include "SketchSolver_Manager.h" #include #include @@ -29,23 +29,23 @@ #include // Initialization of constraint manager self pointer -SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::_self = 0; +SketchSolver_Manager* SketchSolver_Manager::mySelf = 0; /// Global constraint manager object -SketchSolver_ConstraintManager* myManager = SketchSolver_ConstraintManager::Instance(); +SketchSolver_Manager* myManager = SketchSolver_Manager::instance(); // ======================================================== -// ========= SketchSolver_ConstraintManager =============== +// ========= SketchSolver_Manager =============== // ======================================================== -SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::Instance() +SketchSolver_Manager* SketchSolver_Manager::instance() { - if (!_self) - _self = new SketchSolver_ConstraintManager(); - return _self; + if (!mySelf) + mySelf = new SketchSolver_Manager(); + return mySelf; } -SketchSolver_ConstraintManager::SketchSolver_ConstraintManager() +SketchSolver_Manager::SketchSolver_Manager() { myGroups.clear(); myIsComputed = false; @@ -57,17 +57,26 @@ SketchSolver_ConstraintManager::SketchSolver_ConstraintManager() Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED)); } -SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager() +SketchSolver_Manager::~SketchSolver_Manager() { myGroups.clear(); } +void SketchSolver_Manager::setBuilder(BuilderPtr theBuilder) +{ + myBuilder = theBuilder; +} + +BuilderPtr SketchSolver_Manager::builder() +{ + return myBuilder; +} + // ============================================================================ // Function: processEvent -// Class: SketchSolver_Session // Purpose: listen the event loop and process the message // ============================================================================ -void SketchSolver_ConstraintManager::processEvent( +void SketchSolver_Manager::processEvent( const std::shared_ptr& theMessage) { if (myIsComputed) @@ -108,7 +117,7 @@ void SketchSolver_ConstraintManager::processEvent( std::dynamic_pointer_cast(*aFeatIter); if (!aFeature) continue; - hasProperFeature = changeConstraintOrEntity(aFeature) || hasProperFeature; + hasProperFeature = changeFeature(aFeature) || hasProperFeature; } } @@ -129,7 +138,7 @@ void SketchSolver_ConstraintManager::processEvent( if (aFGrIter != aFeatureGroups.end()) { std::vector::iterator aGroupIter = myGroups.begin(); - std::vector aSeparatedGroups; + std::list aSeparatedGroups; while (aGroupIter != myGroups.end()) { if (!(*aGroupIter)->isWorkplaneValid()) { // the group should be removed delete *aGroupIter; @@ -151,10 +160,9 @@ void SketchSolver_ConstraintManager::processEvent( // ============================================================================ // Function: changeWorkplane -// Class: SketchSolver_Session // Purpose: update workplane by given parameters of the sketch // ============================================================================ -bool SketchSolver_ConstraintManager::changeWorkplane(CompositeFeaturePtr theSketch) +bool SketchSolver_Manager::changeWorkplane(CompositeFeaturePtr theSketch) { bool aResult = true; // changed when a workplane wrongly updated bool isUpdated = false; @@ -163,8 +171,7 @@ bool SketchSolver_ConstraintManager::changeWorkplane(CompositeFeaturePtr theSket for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) if ((*aGroupIter)->isBaseWorkplane(theSketch)) { isUpdated = true; - if (!(*aGroupIter)->updateWorkplane()) - aResult = false; + aResult = false; } // If the workplane is not updated, so this is a new workplane if (!isUpdated) { @@ -181,14 +188,12 @@ bool SketchSolver_ConstraintManager::changeWorkplane(CompositeFeaturePtr theSket // ============================================================================ // Function: changeConstraintOrEntity -// Class: SketchSolver_Session // Purpose: create/update the constraint or the feature and place it into appropriate group // ============================================================================ -bool SketchSolver_ConstraintManager::changeConstraintOrEntity( - std::shared_ptr theFeature) +bool SketchSolver_Manager::changeFeature(std::shared_ptr theFeature) { // Search the groups which this feature touches - std::set aGroups; + std::set aGroups; findGroups(theFeature, aGroups); std::shared_ptr aConstraint = @@ -210,7 +215,7 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity( myGroups.push_back(aGroup); return true; } else if (aGroups.size() == 1) { // Only one group => add feature into it - Slvs_hGroup aGroupId = *(aGroups.begin()); + GroupID aGroupId = *(aGroups.begin()); std::vector::iterator aGroupIter; for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) if ((*aGroupIter)->getId() == aGroupId) { @@ -220,7 +225,7 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity( return (*aGroupIter)->changeConstraint(aConstraint); } } else if (aGroups.size() > 1) { // Several groups applicable for this feature => need to merge them - std::set::const_iterator aGroupsIter = aGroups.begin(); + std::set::const_iterator aGroupsIter = aGroups.begin(); // Search first group std::vector::iterator aFirstGroupIter; @@ -261,11 +266,9 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity( // ============================================================================ // Function: moveEntity -// Class: SketchSolver_Session // Purpose: update element moved on the sketch, which is used by constraints // ============================================================================ -void SketchSolver_ConstraintManager::moveEntity( - std::shared_ptr theFeature) +void SketchSolver_Manager::moveEntity(std::shared_ptr theFeature) { std::vector::iterator aGroupIt = myGroups.begin(); for (; aGroupIt != myGroups.end(); aGroupIt++) @@ -275,12 +278,11 @@ void SketchSolver_ConstraintManager::moveEntity( // ============================================================================ // Function: findGroups -// Class: SketchSolver_Session // Purpose: search groups of entities interacting with given feature // ============================================================================ -void SketchSolver_ConstraintManager::findGroups( +void SketchSolver_Manager::findGroups( std::shared_ptr theFeature, - std::set& theGroupIDs) const + std::set& theGroupIDs) const { std::shared_ptr aWP = findWorkplane(theFeature); @@ -301,10 +303,9 @@ void SketchSolver_ConstraintManager::findGroups( // ============================================================================ // Function: findWorkplane -// Class: SketchSolver_Session // Purpose: search workplane containing given feature // ============================================================================ -std::shared_ptr SketchSolver_ConstraintManager +std::shared_ptr SketchSolver_Manager ::findWorkplane(std::shared_ptr theFeature) const { // Already verified workplanes @@ -334,10 +335,9 @@ std::shared_ptr SketchSolver_ConstraintManager // ============================================================================ // Function: resolveConstraints -// Class: SketchSolver_Session // Purpose: change entities according to available constraints // ============================================================================ -void SketchSolver_ConstraintManager::resolveConstraints(const bool theForceUpdate) +void SketchSolver_Manager::resolveConstraints(const bool theForceUpdate) { myIsComputed = true; bool needToUpdate = false; @@ -364,4 +364,3 @@ void SketchSolver_ConstraintManager::resolveConstraints(const bool theForceUpdat if (needToUpdate || theForceUpdate) Events_Loop::loop()->flush(anUpdateEvent); } - diff --git a/src/SketchSolver/SketchSolver_ConstraintManager.h b/src/SketchSolver/SketchSolver_Manager.h similarity index 76% rename from src/SketchSolver/SketchSolver_ConstraintManager.h rename to src/SketchSolver/SketchSolver_Manager.h index a2d7ffaff..8ceddc79a 100644 --- a/src/SketchSolver/SketchSolver_ConstraintManager.h +++ b/src/SketchSolver/SketchSolver_Manager.h @@ -1,28 +1,23 @@ // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -// File: SketchSolver_ConstraintManager.h +// File: SketchSolver_Manager.h // Created: 08 May 2014 // Author: Artem ZHIDKOV -#ifndef SketchSolver_ConstraintManager_H_ -#define SketchSolver_ConstraintManager_H_ +#ifndef SketchSolver_Manager_H_ +#define SketchSolver_Manager_H_ #include "SketchSolver.h" -#include #include +#include #include #include -#include -#include - -#include -#include #include #include -/** \class SketchSolver_ConstraintManager +/** \class SketchSolver_Manager * \ingroup Plugins * \brief Listens the changes of SketchPlugin features and transforms the Constraint * feature into the format understandable by SolveSpace library. @@ -33,28 +28,34 @@ * * \remark This is a singleton. */ -class SketchSolver_ConstraintManager : public Events_Listener +class SketchSolver_Manager : public Events_Listener { - public: +public: /** \brief Main method to create constraint manager * \return pointer to the singleton */ - static SketchSolver_ConstraintManager* Instance(); + SKETCHSOLVER_EXPORT static SketchSolver_Manager* instance(); /** \brief Implementation of Event Listener method * \param[in] theMessage the data of the event */ virtual void processEvent(const std::shared_ptr& theMessage); - protected: - SketchSolver_ConstraintManager(); - ~SketchSolver_ConstraintManager(); + /// \brief Initialize builder for solver's data structure entities + /// \param theBuilder [in] solver's specific builder + SKETCHSOLVER_EXPORT void setBuilder(BuilderPtr theBuilder); + /// \brief Returns the builder specific for the solver + BuilderPtr builder(); + +protected: + SketchSolver_Manager(); + ~SketchSolver_Manager(); /** \brief Adds or updates a constraint or an entity in the suitable group * \param[in] theFeature sketch feature to be changed * \return \c true if the feature changed successfully */ - bool changeConstraintOrEntity(std::shared_ptr theFeature); + bool changeFeature(std::shared_ptr theFeature); /** \brief Removes a constraint from the manager * \param[in] theConstraint constraint to be removed @@ -86,24 +87,25 @@ class SketchSolver_ConstraintManager : public Events_Listener */ void resolveConstraints(const bool theForceUpdate); - private: +private: /** \brief Searches list of groups which interact with specified feature * \param[in] theFeature object to be found * \param[out] theGroups list of group indexes interacted with the feature */ void findGroups(std::shared_ptr theFeature, - std::set& theGroupIDs) const; + std::set& theGroupIDs) const; - /** \brief Searches in the list of groups the workplane which constains specified feature + /** \brief Searches in the list of groups the workplane which contains specified feature * \param[in] theFeature object to be found * \return workplane containing the feature */ std::shared_ptr findWorkplane( std::shared_ptr theFeature) const; - private: - static SketchSolver_ConstraintManager* _self; ///< Self pointer to implement singleton functionality +private: + static SketchSolver_Manager* mySelf; ///< Self pointer to implement singleton functionality std::vector myGroups; ///< Groups of constraints + BuilderPtr myBuilder; ///< Builder for solver's entities /// true if computation is performed and all "updates" are generated by this algo /// and needs no recomputation bool myIsComputed; diff --git a/src/SketchSolver/SketchSolver_Storage.cpp b/src/SketchSolver/SketchSolver_Storage.cpp index 58cd67418..eecc86653 100644 --- a/src/SketchSolver/SketchSolver_Storage.cpp +++ b/src/SketchSolver/SketchSolver_Storage.cpp @@ -1,1222 +1,340 @@ // Copyright (C) 2014-20xx CEA/DEN, EDF R&D // File: SketchSolver_Storage.cpp -// Created: 18 Mar 2015 +// Created: 30 Nov 2015 // Author: Artem ZHIDKOV #include +#include -#include -#include -#include +#include +#include +#include +#include -/** \brief Search the entity/parameter with specified ID in the list of elements - * \param[in] theEntityID unique ID of the element - * \param[in] theEntities list of elements - * \return position of the found element or -1 if the element is not found - */ -template -static int Search(const uint32_t& theEntityID, const std::vector& theEntities); -/// \brief Compare two parameters to be different -static bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2); -/// \brief Compare two entities to be different -static bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2); -/// \brief Compare two constriants to be different -static bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2); +/// \brief Verify two vectors of constraints are equal. +/// Vectors differ by the order of elements are equal. +static bool isEqual(const std::list& theCVec1, + const std::list& theCVec2); -SketchSolver_Storage::SketchSolver_Storage() - : myParamMaxID(SLVS_E_UNKNOWN), - myEntityMaxID(SLVS_E_UNKNOWN), - myConstrMaxID(SLVS_C_UNKNOWN), - myFixed(SLVS_E_UNKNOWN), - myNeedToResolve(false), - myDuplicatedConstraint(false) +void SketchSolver_Storage::addConstraint(ConstraintPtr theConstraint, + ConstraintWrapperPtr theSolverConstraint) { + std::list aConstrList(1, theSolverConstraint); + addConstraint(theConstraint, aConstrList); } -Slvs_hParam SketchSolver_Storage::addParameter(const Slvs_Param& theParam) +void SketchSolver_Storage::addConstraint( + ConstraintPtr theConstraint, + std::list theSolverConstraints) { - if (theParam.h > 0 && theParam.h <= myParamMaxID) { - // parameter is already used, rewrite it - return updateParameter(theParam); - } - - Slvs_Param aParam = theParam; - if (aParam.h > myParamMaxID) - myParamMaxID = aParam.h; - else - aParam.h = ++myParamMaxID; - myParameters.push_back(aParam); - myNeedToResolve = true; - return aParam.h; -} + std::map >::const_iterator + aFound = myConstraintMap.find(theConstraint); + if (aFound == myConstraintMap.end() || !isEqual(aFound->second, theSolverConstraints)) + setNeedToResolve(true); -Slvs_hParam SketchSolver_Storage::updateParameter(const Slvs_Param& theParam) -{ - if (theParam.h > 0 && theParam.h <= myParamMaxID) { - // parameter already used, rewrite it - int aPos = Search(theParam.h, myParameters); - if (aPos >= 0 && aPos < (int)myParameters.size()) { - if (IsNotEqual(myParameters[aPos], theParam)) - myUpdatedParameters.insert(theParam.h); - myParameters[aPos] = theParam; - return theParam.h; - } + // Do not add point-point coincidence, because it is already made by setting + // the same parameters for both points + if (!theSolverConstraints.empty() && + theSolverConstraints.front()->type() != CONSTRAINT_PT_PT_COINCIDENT) { + std::list::iterator aCIt = theSolverConstraints.begin(); + for (; aCIt != theSolverConstraints.end(); ++aCIt) + update(*aCIt); } - - // Parameter is not found, add new one - Slvs_Param aParam = theParam; - aParam.h = 0; - return addParameter(aParam); + myConstraintMap[theConstraint] = theSolverConstraints; } -bool SketchSolver_Storage::removeParameter(const Slvs_hParam& theParamID) +void SketchSolver_Storage::addEntity(FeaturePtr theFeature, + EntityWrapperPtr theSolverEntity) { - int aPos = Search(theParamID, myParameters); - if (aPos >= 0 && aPos < (int)myParameters.size()) { - // Firstly, search the parametes is not used elsewhere - std::vector::const_iterator anEntIter = myEntities.begin(); - for (; anEntIter != myEntities.end(); anEntIter++) { - for (int i = 0; i < 4; i++) - if (anEntIter->param[i] == theParamID) - return false; - } - // Remove parameter - myParameters.erase(myParameters.begin() + aPos); - myParamMaxID = myParameters.empty() ? SLVS_E_UNKNOWN : myParameters.back().h; - myNeedToResolve = true; - myRemovedParameters.insert(theParamID); - return true; - } - return false; -} - -const Slvs_Param& SketchSolver_Storage::getParameter(const Slvs_hParam& theParamID) const -{ - int aPos = Search(theParamID, myParameters); - if (aPos >= 0 && aPos < (int)myParameters.size()) - return myParameters[aPos]; + std::map::const_iterator aFound = myFeatureMap.find(theFeature); + if (aFound == myFeatureMap.end() || !aFound->second->isEqual(theSolverEntity)) + setNeedToResolve(true); // the entity is new or modified - // Parameter is not found, return empty object - static Slvs_Param aDummy; - aDummy.h = 0; - return aDummy; + myFeatureMap[theFeature] = theSolverEntity; } - -Slvs_hEntity SketchSolver_Storage::addEntity(const Slvs_Entity& theEntity) +void SketchSolver_Storage::addEntity(AttributePtr theAttribute, + EntityWrapperPtr theSolverEntity) { - if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) { - // Entity is already used, rewrite it - return updateEntity(theEntity); - } + std::map::const_iterator aFound = myAttributeMap.find(theAttribute); + if (aFound == myAttributeMap.end() || !aFound->second->isEqual(theSolverEntity)) + setNeedToResolve(true); // the entity is new or modified - Slvs_Entity aEntity = theEntity; - if (aEntity.h > myEntityMaxID) - myEntityMaxID = aEntity.h; - else - aEntity.h = ++myEntityMaxID; - myEntities.push_back(aEntity); - myNeedToResolve = true; - return aEntity.h; + myAttributeMap[theAttribute] = theSolverEntity; } -Slvs_hEntity SketchSolver_Storage::updateEntity(const Slvs_Entity& theEntity) -{ - if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) { - // Entity already used, rewrite it - int aPos = Search(theEntity.h, myEntities); - if (aPos >= 0 && aPos < (int)myEntities.size()) { - myNeedToResolve = myNeedToResolve || IsNotEqual(myEntities[aPos], theEntity); - myEntities[aPos] = theEntity; - return theEntity.h; - } - } - - // Entity is not found, add new one - Slvs_Entity aEntity = theEntity; - aEntity.h = 0; - return addEntity(aEntity); -} - -bool SketchSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID) -{ - bool aResult = true; - int aPos = Search(theEntityID, myEntities); - if (aPos >= 0 && aPos < (int)myEntities.size()) { - // Firstly, check the entity and its attributes is not used elsewhere - std::set anEntAndSubs; - anEntAndSubs.insert(theEntityID); - for (int i = 0; i < 4; i++) - if (myEntities[aPos].point[i] != SLVS_E_UNKNOWN) - anEntAndSubs.insert(myEntities[aPos].point[i]); - - std::vector::const_iterator anEntIter = myEntities.begin(); - for (; anEntIter != myEntities.end(); anEntIter++) { - for (int i = 0; i < 4; i++) - if (anEntAndSubs.find(anEntIter->point[i]) != anEntAndSubs.end()) - return false; - if (anEntAndSubs.find(anEntIter->distance) != anEntAndSubs.end()) - return false; - } - std::vector::const_iterator aConstrIter = myConstraints.begin(); - for (; aConstrIter != myConstraints.end(); aConstrIter++) { - Slvs_hEntity anEntIDs[6] = {aConstrIter->ptA, aConstrIter->ptB, - aConstrIter->entityA, aConstrIter->entityB, - aConstrIter->entityC, aConstrIter->entityD}; - for (int i = 0; i < 6; i++) - if (anEntAndSubs.find(anEntIDs[i]) != anEntAndSubs.end()) - return false; - } - // 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++) - if (anEntity.param[i] != SLVS_E_UNKNOWN) - aResult = removeParameter(anEntity.param[i]) && aResult; - for (int i = 0; i < 4; i++) - if (anEntity.point[i] != SLVS_E_UNKNOWN) - 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; -} -void SketchSolver_Storage::removeUnusedEntities() +bool SketchSolver_Storage::update(FeaturePtr theFeature, const GroupID& theGroup) { - std::set anUnusedEntities; - std::vector::const_iterator aEIt = myEntities.begin(); - for (; aEIt != myEntities.end(); ++aEIt) { - if (aEIt->h == aEIt->wrkpl) { - // don't remove workplane - anUnusedEntities.erase(aEIt->point[0]); - anUnusedEntities.erase(aEIt->normal); - continue; + bool isUpdated = false; + EntityWrapperPtr aRelated = entity(theFeature); + if (!aRelated) { // Feature is not exist, create it + std::list aSubs; + // Firstly, create/update its attributes + std::list anAttrs = + theFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); + std::list::const_iterator anIt = anAttrs.begin(); + for (; anIt != anAttrs.end(); ++anIt) { + isUpdated = update(*anIt, theGroup) || isUpdated; + aSubs.push_back(entity(*anIt)); } - anUnusedEntities.insert(aEIt->h); - } - - std::vector::const_iterator aCIt = myConstraints.begin(); - for (; aCIt != myConstraints.end(); ++aCIt) { - Slvs_hEntity aSubs[6] = { - aCIt->entityA, aCIt->entityB, - aCIt->entityC, aCIt->entityD, - aCIt->ptA, aCIt->ptB}; - for (int i = 0; i < 6; i++) { - if (aSubs[i] != SLVS_E_UNKNOWN) { - anUnusedEntities.erase(aSubs[i]); - int aPos = Search(aSubs[i], myEntities); - if (aPos >= 0 && aPos < (int)myEntities.size()) { - for (int j = 0; j < 4; j++) - if (myEntities[aPos].point[j] != SLVS_E_UNKNOWN) - anUnusedEntities.erase(myEntities[aPos].point[j]); - if (myEntities[aPos].distance != SLVS_E_UNKNOWN) - anUnusedEntities.erase(myEntities[aPos].distance); - } - } + // If the feature is a circle, add its radius as a sub + if (theFeature->getKind() == SketchPlugin_Circle::ID()) { + AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID()); + isUpdated = update(aRadius, theGroup) || isUpdated; + aSubs.push_back(entity(aRadius)); } - } - - std::set::const_iterator anEntIt = anUnusedEntities.begin(); - while (anEntIt != anUnusedEntities.end()) { - int aPos = Search(*anEntIt, myEntities); - if (aPos < 0 && aPos >= (int)myEntities.size()) - continue; - Slvs_Entity anEntity = myEntities[aPos]; - // Remove entity if and only if all its parameters unused - bool isUsed = false; - if (anEntity.distance != SLVS_E_UNKNOWN && - anUnusedEntities.find(anEntity.distance) == anUnusedEntities.end()) - isUsed = true; - for (int i = 0; i < 4 && !isUsed; i++) - if (anEntity.point[i] != SLVS_E_UNKNOWN && - anUnusedEntities.find(anEntity.point[i]) == anUnusedEntities.end()) - isUsed = true; - if (isUsed) { - anUnusedEntities.erase(anEntity.distance); - for (int i = 0; i < 4; i++) - if (anEntity.point[i] != SLVS_E_UNKNOWN) - anUnusedEntities.erase(anEntity.point[i]); - std::set::iterator aRemoveIt = anEntIt++; - anUnusedEntities.erase(aRemoveIt); - continue; + // If the feature if circle or arc, we need to add normal of the sketch to the list of subs + if (theFeature->getKind() == SketchPlugin_Arc::ID() || + theFeature->getKind() == SketchPlugin_Circle::ID()) { + EntityWrapperPtr aNormal = getNormal(); + if (aNormal) aSubs.push_back(aNormal); } - ++anEntIt; - } - - for (anEntIt = anUnusedEntities.begin(); anEntIt != anUnusedEntities.end(); ++anEntIt) { - int aPos = Search(*anEntIt, myEntities); - if (aPos >= 0 && aPos < (int)myEntities.size()) { - // Remove entity 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) - removeParameter(anEntity.distance); - for (int i = 0; i < 4; i++) - if (anEntity.param[i] != SLVS_E_UNKNOWN) - removeParameter(anEntity.param[i]); - for (int i = 0; i < 4; i++) - if (anEntity.point[i] != SLVS_E_UNKNOWN) - removeEntity(anEntity.point[i]); - myRemovedEntities.insert(*anEntIt); - if (anEntity.type == SLVS_E_POINT_IN_2D || anEntity.type == SLVS_E_POINT_IN_3D) - removeCoincidentPoint(*anEntIt); - } - } - - if (!anUnusedEntities.empty()) - myNeedToResolve = true; -} - -bool SketchSolver_Storage::isUsedByConstraints(const Slvs_hEntity& theEntityID) const -{ - std::vector::const_iterator aCIt = myConstraints.begin(); - for (; aCIt != myConstraints.end(); ++aCIt) { - Slvs_hEntity aSubs[6] = { - aCIt->entityA, aCIt->entityB, - aCIt->entityC, aCIt->entityD, - aCIt->ptA, aCIt->ptB}; - for (int i = 0; i < 6; i++) - if (aSubs[i] != SLVS_E_UNKNOWN && aSubs[i] == theEntityID) - return true; - } - return false; -} - -const Slvs_Entity& SketchSolver_Storage::getEntity(const Slvs_hEntity& theEntityID) const -{ - int aPos = Search(theEntityID, myEntities); - if (aPos >= 0 && aPos < (int)myEntities.size()) - return myEntities[aPos]; - - // Entity is not found, return empty object - static Slvs_Entity aDummy; - aDummy.h = SLVS_E_UNKNOWN; - return aDummy; -} - -Slvs_hEntity SketchSolver_Storage::copyEntity(const Slvs_hEntity& theCopied) -{ - int aPos = Search(theCopied, myEntities); - if (aPos < 0 || aPos >= (int)myEntities.size()) - return SLVS_E_UNKNOWN; - - Slvs_Entity aCopy = myEntities[aPos]; - aCopy.h = SLVS_E_UNKNOWN; - int i = 0; - while (aCopy.point[i] != SLVS_E_UNKNOWN) { - aCopy.point[i] = copyEntity(aCopy.point[i]); - i++; - } - if (aCopy.param[0] != SLVS_E_UNKNOWN) { - aPos = Search(aCopy.param[0], myParameters); - i = 0; - while (aCopy.param[i] != SLVS_E_UNKNOWN) { - Slvs_Param aNewParam = myParameters[aPos]; - aNewParam.h = SLVS_E_UNKNOWN; - aCopy.param[i] = addParameter(aNewParam); - i++; - aPos++; - } - } - return addEntity(aCopy); -} - -void SketchSolver_Storage::copyEntity(const Slvs_hEntity& theFrom, const Slvs_hEntity& theTo) -{ - int aPosFrom = Search(theFrom, myEntities); - int aPosTo = Search(theTo, myEntities); - if (aPosFrom < 0 || aPosFrom >= (int)myEntities.size() || - aPosTo < 0 || aPosTo >= (int)myEntities.size()) - return; - - Slvs_Entity aEntFrom = myEntities[aPosFrom]; - Slvs_Entity aEntTo = myEntities[aPosTo]; - int i = 0; - while (aEntFrom.point[i] != SLVS_E_UNKNOWN) { - copyEntity(aEntFrom.point[i], aEntTo.point[i]); - i++; - } - if (aEntFrom.param[0] != SLVS_E_UNKNOWN) { - aPosFrom = Search(aEntFrom.param[0], myParameters); - aPosTo = Search(aEntTo.param[0], myParameters); - i = 0; - while (aEntFrom.param[i] != SLVS_E_UNKNOWN) { - myParameters[aPosTo++].val = myParameters[aPosFrom++].val; - i++; - } - } -} - - -bool SketchSolver_Storage::isPointFixed( - const Slvs_hEntity& thePointID, Slvs_hConstraint& theFixed, bool theAccurate) const -{ - // Search the set of coincident points - std::set aCoincident; - aCoincident.insert(thePointID); - std::vector< std::set >::const_iterator aCPIter = myCoincidentPoints.begin(); - for (; aCPIter != myCoincidentPoints.end(); aCPIter++) - if (aCPIter->find(thePointID) != aCPIter->end()) { - aCoincident = *aCPIter; - break; - } - - // Check whether one of coincident points is out-of-group - std::set::const_iterator aCoincIt = aCoincident.begin(); - for (; aCoincIt != aCoincident.end(); ++aCoincIt) { - Slvs_Entity aPoint = getEntity(*aCoincIt); - if (aPoint.group == SLVS_G_OUTOFGROUP) - return true; - } - - // Search the Rigid constraint - theFixed = SLVS_C_UNKNOWN; - std::vector::const_iterator aConstrIter = myConstraints.begin(); - for (; aConstrIter != myConstraints.end(); aConstrIter++) - if (aConstrIter->type == SLVS_C_WHERE_DRAGGED && - aCoincident.find(aConstrIter->ptA) != aCoincident.end()) { - theFixed = aConstrIter->h; - if (aConstrIter->ptA == thePointID) - return true; - } - if (theFixed != SLVS_C_UNKNOWN) - return true; - - if (theAccurate) { - // Try to find the fixed entity which uses such point or its coincidence - std::vector::const_iterator anEntIter = myEntities.begin(); - for (; anEntIter != myEntities.end(); anEntIter++) { - for (int i = 0; i < 4; i++) { - Slvs_hEntity aPt = anEntIter->point[i]; - if (aPt != SLVS_E_UNKNOWN && - (aPt == thePointID || aCoincident.find(aPt) != aCoincident.end())) { - if (isEntityFixed(anEntIter->h, true)) - return true; - } - } - } - } - return SLVS_E_UNKNOWN; -} - -bool SketchSolver_Storage::isEntityFixed(const Slvs_hEntity& theEntityID, bool theAccurate) const -{ - int aPos = Search(theEntityID, myEntities); - if (aPos < 0 || aPos >= (int)myEntities.size()) - return false; - - // Firstly, find how many points are under Rigid constraint - int aNbFixed = 0; - for (int i = 0; i < 4; i++) { - Slvs_hEntity aPoint = myEntities[aPos].point[i]; - if (aPoint == SLVS_E_UNKNOWN) - continue; - - std::set aCoincident; - aCoincident.insert(aPoint); - std::vector< std::set >::const_iterator aCPIter = myCoincidentPoints.begin(); - for (; aCPIter != myCoincidentPoints.end(); aCPIter++) - if (aCPIter->find(aPoint) != aCPIter->end()) { - aCoincident = *aCPIter; - break; - } - - // Search the Rigid constraint - std::vector::const_iterator aConstrIter = myConstraints.begin(); - for (; aConstrIter != myConstraints.end(); aConstrIter++) - if (aConstrIter->type == SLVS_C_WHERE_DRAGGED && - aCoincident.find(aConstrIter->ptA) != aCoincident.end()) - aNbFixed++; - } - - std::list aList; - std::list::iterator anIt; - Slvs_hConstraint aTempID; // used in isPointFixed() method - - if (myEntities[aPos].type == SLVS_E_LINE_SEGMENT) { - if (aNbFixed == 2) - return true; - else if (aNbFixed == 0 || !theAccurate) - return false; - // Additional check (the line may be fixed if it is used by different constraints): - // 1. The line is used in Equal constraint, another entity is fixed and there is a fixed point on line - aList = getConstraintsByType(SLVS_C_PT_ON_LINE); - for (anIt = aList.begin(); anIt != aList.end(); anIt++) - if (anIt->entityA == theEntityID && isPointFixed(anIt->ptA, aTempID)) - break; - if (anIt != aList.end()) { - aList = getConstraintsByType(SLVS_C_EQUAL_LENGTH_LINES); - aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN)); - for (anIt = aList.begin(); anIt != aList.end(); anIt++) - if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) { - Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA; - if (isEntityFixed(anOther, false)) - return true; - } - } - // 2. The line is used in Parallel/Perpendicular/Vertical/Horizontal and Length constraints - aList = getConstraintsByType(SLVS_C_PARALLEL); - aList.splice(aList.end(), getConstraintsByType(SLVS_C_PERPENDICULAR)); - aList.splice(aList.end(), getConstraintsByType(SLVS_C_VERTICAL)); - aList.splice(aList.end(), getConstraintsByType(SLVS_C_HORIZONTAL)); - for (anIt = aList.begin(); anIt != aList.end(); anIt++) - if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) { - Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA; - if (isEntityFixed(anOther, false)) - break; - } - if (anIt != aList.end()) { - aList = getConstraintsByType(SLVS_C_PT_PT_DISTANCE); - for (anIt = aList.begin(); anIt != aList.end(); anIt++) - if ((anIt->ptA == myEntities[aPos].point[0] && anIt->ptB == myEntities[aPos].point[1]) || - (anIt->ptA == myEntities[aPos].point[1] && anIt->ptB == myEntities[aPos].point[0])) - return true; - } - // 3. Another verifiers ... - } else if (myEntities[aPos].type == SLVS_E_CIRCLE) { - if (aNbFixed == 0) + // Secondly, convert feature + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + aRelated = aBuilder->createFeature(theFeature, aSubs, theGroup); + if (!aRelated) return false; - // Search for Diameter constraint - aList = getConstraintsByType(SLVS_C_DIAMETER); - for (anIt = aList.begin(); anIt != aList.end(); anIt++) - if (anIt->entityA == theEntityID) - return true; - if (!theAccurate) - return false; - // Additional check (the circle may be fixed if it is used by different constraints): - // 1. The circle is used in Equal constraint and another entity is fixed - aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS); - for (anIt = aList.begin(); anIt != aList.end(); anIt++) - if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) { - Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA; - if (isEntityFixed(anOther, false)) - return true; - } - // 2. Another verifiers ... - } else if (myEntities[aPos].type == SLVS_E_ARC_OF_CIRCLE) { - if (aNbFixed > 2) - return true; - else if (aNbFixed <= 1) - return false; - // Search for Diameter constraint - aList = getConstraintsByType(SLVS_C_DIAMETER); - for (anIt = aList.begin(); anIt != aList.end(); anIt++) - if (anIt->entityA == theEntityID) - return true; - if (!theAccurate) - return false; - // Additional check (the arc may be fixed if it is used by different constraints): - // 1. The arc is used in Equal constraint and another entity is fixed - aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS); - aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN)); - for (anIt = aList.begin(); anIt != aList.end(); anIt++) - if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) { - Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA; - if (isEntityFixed(anOther, false)) - return true; - } - // 2. Another verifiers ... - } - return false; -} - - -Slvs_hConstraint SketchSolver_Storage::addConstraint(const Slvs_Constraint& theConstraint) -{ - if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) { - // Constraint is already used, rewrite it - return updateConstraint(theConstraint); - } - - Slvs_Constraint aConstraint = theConstraint; - - // Find a constraint with same type uses same arguments to show user overconstraint situation - std::vector::iterator aCIt = myConstraints.begin(); - for (; aCIt != myConstraints.end(); aCIt++) { - if (aConstraint.type != aCIt->type) - continue; - if (aConstraint.ptA == aCIt->ptA && aConstraint.ptB == aCIt->ptB && - aConstraint.entityA == aCIt->entityA && aConstraint.entityB == aCIt->entityB && - aConstraint.entityC == aCIt->entityC && aConstraint.entityD == aCIt->entityD) - myDuplicatedConstraint = true; - } - - if (aConstraint.h > myConstrMaxID) - myConstrMaxID = aConstraint.h; - else - aConstraint.h = ++myConstrMaxID; - myConstraints.push_back(aConstraint); - myNeedToResolve = true; - if (aConstraint.type == SLVS_C_POINTS_COINCIDENT) - addCoincidentPoints(aConstraint.ptA, aConstraint.ptB); - return aConstraint.h; + addEntity(theFeature, aRelated); + } else if (theGroup != GID_UNKNOWN) + changeGroup(aRelated, theGroup); + return update(aRelated) || isUpdated; } -Slvs_hConstraint SketchSolver_Storage::updateConstraint(const Slvs_Constraint& theConstraint) +bool SketchSolver_Storage::update(AttributePtr theAttribute, const GroupID& theGroup) { - if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) { - // Constraint already used, rewrite it - int aPos = Search(theConstraint.h, myConstraints); - 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; - } + AttributePtr anAttribute = theAttribute; + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(anAttribute); + if (aRefAttr) { + if (aRefAttr->isObject()) { + FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); + return update(aFeature, theGroup); + } else + anAttribute = aRefAttr->attr(); } - // Constraint is not found, add new one - Slvs_Constraint aConstraint = theConstraint; - aConstraint.h = 0; - return addConstraint(aConstraint); + EntityWrapperPtr aRelated = entity(anAttribute); + if (!aRelated) { // Attribute is not exist, create it + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + aRelated = aBuilder->createAttribute(anAttribute, theGroup); + if (!aRelated) + return false; + addEntity(anAttribute, aRelated); + } else if (theGroup != GID_UNKNOWN) + changeGroup(aRelated, theGroup); + return update(aRelated); } -bool SketchSolver_Storage::removeConstraint(const Slvs_hConstraint& theConstraintID) -{ - bool aResult = true; - int aPos = Search(theConstraintID, myConstraints); - 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); - if (aConstraint.type == SLVS_C_POINTS_COINCIDENT) - removeCoincidence(aConstraint); - // Remove all entities - Slvs_hEntity anEntities[6] = {aConstraint.ptA, aConstraint.ptB, - aConstraint.entityA, aConstraint.entityB, - aConstraint.entityC, aConstraint.entityD}; - for (int i = 0; i < 6; i++) - if (anEntities[i] != SLVS_E_UNKNOWN) - aResult = removeEntity(anEntities[i]) && aResult; - // remove temporary fixed point, if available - if (myFixed == theConstraintID) - myFixed = SLVS_E_UNKNOWN; - if (myDuplicatedConstraint) { - // Check the duplicated constraints are still available - myDuplicatedConstraint = false; - std::vector::const_iterator anIt1 = myConstraints.begin(); - std::vector::const_iterator anIt2 = myConstraints.begin(); - for (; anIt1 != myConstraints.end() && !myDuplicatedConstraint; anIt1++) - for (anIt2 = anIt1+1; anIt2 != myConstraints.end() && !myDuplicatedConstraint; anIt2++) { - if (anIt1->type != anIt2->type) - continue; - if (anIt1->ptA == anIt2->ptA && anIt1->ptB == anIt2->ptB && - anIt1->entityA == anIt2->entityA && anIt1->entityB == anIt2->entityB && - anIt1->entityC == anIt2->entityC && anIt1->entityD == anIt2->entityD) - myDuplicatedConstraint = true; - } - } - } - return aResult; -} -const Slvs_Constraint& SketchSolver_Storage::getConstraint(const Slvs_hConstraint& theConstraintID) const +const std::list& SketchSolver_Storage::constraint( + const ConstraintPtr& theConstraint) const { - int aPos = Search(theConstraintID, myConstraints); - if (aPos >= 0 && aPos < (int)myConstraints.size()) - return myConstraints[aPos]; + static std::list aDummy; - // Constraint is not found, return empty object - static Slvs_Constraint aDummy; - aDummy.h = 0; + std::map>::const_iterator + aFound = myConstraintMap.find(theConstraint); + if (aFound != myConstraintMap.end()) + return aFound->second; return aDummy; } -std::list SketchSolver_Storage::getConstraintsByType(int theConstraintType) const -{ - std::list aResult; - std::vector::const_iterator aCIter = myConstraints.begin(); - for (; aCIter != myConstraints.end(); aCIter++) - if (aCIter->type == theConstraintType) - aResult.push_back(*aCIter); - return aResult; -} - - -void SketchSolver_Storage::addConstraintWhereDragged(const Slvs_hConstraint& theConstraintID) -{ - if (myFixed != SLVS_E_UNKNOWN) - return; // the point is already fixed - int aPos = Search(theConstraintID, myConstraints); - if (aPos >= 0 && aPos < (int)myConstraints.size()) - myFixed = theConstraintID; -} - -void SketchSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID) +const EntityWrapperPtr& SketchSolver_Storage::entity(const FeaturePtr& theFeature) const { - myTemporaryConstraints.insert(theConstraintID); -} + static EntityWrapperPtr aDummy; -void SketchSolver_Storage::removeTemporaryConstraints() -{ - myTemporaryConstraints.clear(); -} - -int SketchSolver_Storage::deleteTemporaryConstraint() -{ - if (myTemporaryConstraints.empty()) - return 0; - // Search the point-on-line or a non-rigid constraint - std::set::iterator aCIt = myTemporaryConstraints.begin(); - for (; aCIt != myTemporaryConstraints.end(); aCIt++) { - int aPos = Search(*aCIt, myConstraints); - if (aPos >= (int)myConstraints.size() || myConstraints[aPos].type != SLVS_C_WHERE_DRAGGED) - break; - std::vector::iterator anIt = myConstraints.begin(); - for (; anIt != myConstraints.end(); anIt++) - if (anIt->type == SLVS_C_PT_ON_LINE && anIt->ptA == myConstraints[aPos].ptA) - break; - if (anIt != myConstraints.end()) - break; - } - if (aCIt == myTemporaryConstraints.end()) - aCIt = myTemporaryConstraints.begin(); - bool aNewFixed = (*aCIt == myFixed); - removeConstraint(*aCIt); - myTemporaryConstraints.erase(aCIt); - if (aNewFixed) { - for (aCIt = myTemporaryConstraints.begin(); aCIt != myTemporaryConstraints.end(); aCIt++) { - int aPos = Search(*aCIt, myConstraints); - if (myConstraints[aPos].type == SLVS_C_WHERE_DRAGGED) { - myFixed = *aCIt; - break; - } - } - } - return (int)myTemporaryConstraints.size(); -} - -bool SketchSolver_Storage::isTemporary(const Slvs_hConstraint& theConstraintID) const -{ - return myTemporaryConstraints.find(theConstraintID) != myTemporaryConstraints.end(); -} - - -void SketchSolver_Storage::getRemoved( - std::set& theParameters, - std::set& theEntities, - std::set& theConstraints) -{ - theParameters = myRemovedParameters; - theEntities = myRemovedEntities; - theConstraints = myRemovedConstraints; - - myRemovedParameters.clear(); - myRemovedEntities.clear(); - myRemovedConstraints.clear(); + std::map::const_iterator aFound = myFeatureMap.find(theFeature); + if (aFound != myFeatureMap.end()) + return aFound->second; + return aDummy; } -void SketchSolver_Storage::initializeSolver(SketchSolver_Solver& theSolver) +const EntityWrapperPtr& SketchSolver_Storage::entity(const AttributePtr& theAttribute) const { - theSolver.setParameters(myParameters.data(), (int)myParameters.size()); - theSolver.setEntities(myEntities.data(), (int)myEntities.size()); + static EntityWrapperPtr aDummy; - // 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()); -} + std::map::const_iterator + aFound = myAttributeMap.find(theAttribute); + if (aFound != myAttributeMap.end()) + return aFound->second; -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; - } else - aFoundIter = aCIter; - 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); + AttributeRefAttrPtr aRefAttr = + std::dynamic_pointer_cast(theAttribute); + if (aRefAttr) { + if (aRefAttr->isObject()) { + FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); + return entity(aFeature); + } else + return entity(aRefAttr->attr()); } + return aDummy; } -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; - } -} - -void SketchSolver_Storage::removeCoincidence(const Slvs_Constraint& theCoincidence) +bool SketchSolver_Storage::isInteract(const FeaturePtr& theFeature) const { - // Find set of coincident points - std::vector< std::set >::iterator aCIt = myCoincidentPoints.begin(); - for (; aCIt != myCoincidentPoints.end(); ++aCIt) - if (aCIt->find(theCoincidence.ptA) != aCIt->end() || - aCIt->find(theCoincidence.ptB) != aCIt->end()) - break; - if (aCIt == myCoincidentPoints.end()) - return; - - // Leave only the points which are still coincident - std::set aRemainCoincidence; - std::vector::const_iterator aConstrIt = myConstraints.begin(); - for (; aConstrIt != myConstraints.end(); ++aConstrIt) { - if (aConstrIt->type != SLVS_C_POINTS_COINCIDENT) - continue; - if (aCIt->find(aConstrIt->ptA) != aCIt->end() || - aCIt->find(aConstrIt->ptB) != aCIt->end()) { - aRemainCoincidence.insert(aConstrIt->ptA); - aRemainCoincidence.insert(aConstrIt->ptB); - } - } - if (aRemainCoincidence.size() <= 1) - myCoincidentPoints.erase(aCIt); - else - aCIt->swap(aRemainCoincidence); -} + if (!theFeature) + return false; + if (myConstraintMap.empty()) + return true; // empty storage interacts with each feature -bool SketchSolver_Storage::isCoincident( - const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const -{ - std::vector< std::set >::const_iterator aCIter = myCoincidentPoints.begin(); - for (; aCIter != myCoincidentPoints.end(); aCIter++) - if (aCIter->find(thePoint1) != aCIter->end() && aCIter->find(thePoint2) != aCIter->end()) + ConstraintPtr aConstraint = std::dynamic_pointer_cast(theFeature); + if (aConstraint) { + if (myConstraintMap.find(aConstraint) != myConstraintMap.end()) return true; - return false; -} - -bool SketchSolver_Storage::isEqual( - const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const -{ - if (isCoincident(thePoint1, thePoint2)) + } else if (myFeatureMap.find(theFeature) != myFeatureMap.end()) return true; - // Precise checking of coincidence: verify that points have equal coordinates - int aEnt1Pos = Search(thePoint1, myEntities); - int aEnt2Pos = Search(thePoint2, myEntities); - if (aEnt1Pos >= 0 && aEnt1Pos < (int)myEntities.size() && - aEnt2Pos >= 0 && aEnt2Pos < (int)myEntities.size()) { - double aDist[2]; - int aParamPos; - for (int i = 0; i < 2; i++) { - aParamPos = Search(myEntities[aEnt1Pos].param[i], myParameters); - aDist[i] = myParameters[aParamPos].val; - aParamPos = Search(myEntities[aEnt2Pos].param[i], myParameters); - aDist[i] -= myParameters[aParamPos].val; - } - if (aDist[0] * aDist[0] + aDist[1] * aDist[1] < tolerance * tolerance) + std::list anAttrList = theFeature->data()->attributes(std::string()); + std::list::const_iterator anIt = anAttrList.begin(); + for (; anIt != anAttrList.end(); ++anIt) + if (isInteract(*anIt)) return true; - } + return false; } - -std::vector SketchSolver_Storage::fixEntity(const Slvs_hEntity& theEntity) +bool SketchSolver_Storage::isInteract(const AttributePtr& theAttribute) const { - std::vector aNewConstraints; + if (!theAttribute) + return false; - int aPos = Search(theEntity, myEntities); - if (aPos >= 0 && aPos < (int)myEntities.size()) { - switch (myEntities[aPos].type) { - case SLVS_E_POINT_IN_2D: - case SLVS_E_POINT_IN_3D: - fixPoint(myEntities[aPos], aNewConstraints); - break; - case SLVS_E_LINE_SEGMENT: - fixLine(myEntities[aPos], aNewConstraints); - break; - case SLVS_E_CIRCLE: - fixCircle(myEntities[aPos], aNewConstraints); - break; - case SLVS_E_ARC_OF_CIRCLE: - fixArc(myEntities[aPos], aNewConstraints); - break; - default: - break; - } - } + AttributeRefAttrPtr aRefAttr = + std::dynamic_pointer_cast(theAttribute); + if (!aRefAttr) + return myAttributeMap.find(theAttribute) != myAttributeMap.end(); + if (!aRefAttr->isObject()) + return myAttributeMap.find(aRefAttr->attr()) != myAttributeMap.end(); - return aNewConstraints; + FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); + return isInteract(aFeature); } -void SketchSolver_Storage::fixPoint(const Slvs_Entity& thePoint, - std::vector& theCreated) +bool SketchSolver_Storage::isConsistent() const { - Slvs_Constraint aConstraint; - Slvs_hConstraint aConstrID = SLVS_E_UNKNOWN; - bool isFixed = isPointFixed(thePoint.h, aConstrID, true); - bool isForceUpdate = (isFixed && isTemporary(aConstrID)); - if (!isForceUpdate) { // create new constraint - if (isFixed) return; - aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, thePoint.group, SLVS_C_WHERE_DRAGGED, thePoint.wrkpl, - 0.0, thePoint.h, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - aConstraint.h = addConstraint(aConstraint); - theCreated.push_back(aConstraint.h); - } else { // update already existent constraint - if (!isFixed || aConstrID == SLVS_E_UNKNOWN) - return; - int aPos = Search(aConstrID, myConstraints); - if (aPos >= 0 && aPos < (int)myConstraints.size()) - myConstraints[aPos].ptA = thePoint.h; - } + // Check the constraints are valid + std::map >::const_iterator + aCIter = myConstraintMap.begin(); + for (; aCIter != myConstraintMap.end(); ++aCIter) + if (!aCIter->first->data() || !aCIter->first->data()->isValid()) + return false; + // Check the features are valid + std::map::const_iterator aFIter = myFeatureMap.begin(); + for (; aFIter != myFeatureMap.end(); aFIter++) + if (!aFIter->first->data() || !aFIter->first->data()->isValid()) + return false; + return true; +} + +void SketchSolver_Storage::removeInvalidEntities() +{ + // Remove invalid constraints + std::list anInvalidConstraints; + std::map >::const_iterator + aCIter = myConstraintMap.begin(); + for (; aCIter != myConstraintMap.end(); ++aCIter) + if (!aCIter->first->data() || !aCIter->first->data()->isValid()) + anInvalidConstraints.push_back(aCIter->first); + std::list::const_iterator anInvCIt = anInvalidConstraints.begin(); + for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt) + removeConstraint(*anInvCIt); + // Remove invalid features + std::list anInvalidFeatures; + std::map::const_iterator aFIter = myFeatureMap.begin(); + for (; aFIter != myFeatureMap.end(); aFIter++) + if (!aFIter->first->data() || !aFIter->first->data()->isValid()) + anInvalidFeatures.push_back(aFIter->first); + std::list::const_iterator anInvFIt = anInvalidFeatures.begin(); + for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt) + removeEntity(*anInvFIt); +} + +EntityWrapperPtr SketchSolver_Storage::getNormal() const +{ + EntityWrapperPtr aSketch = sketch(); + if (!aSketch) + return aSketch; + + // Find normal entity + const std::list& aSketchSubs = aSketch->subEntities(); + std::list::const_iterator aSIt = aSketchSubs.begin(); + for (; aSIt != aSketchSubs.end(); ++aSIt) + if ((*aSIt)->type() == ENTITY_NORMAL) + return *aSIt; + return EntityWrapperPtr(); +} + +const EntityWrapperPtr& SketchSolver_Storage::sketch() const +{ + static EntityWrapperPtr aDummySketch; + + std::map::const_iterator aFIt = myFeatureMap.begin(); + for (; aFIt != myFeatureMap.end(); ++aFIt) + if (aFIt->second->type() == ENTITY_SKETCH) + break; + if (aFIt == myFeatureMap.end()) + return aDummySketch; + return aFIt->second; } -void SketchSolver_Storage::fixLine(const Slvs_Entity& theLine, - std::vector& theCreated) +void SketchSolver_Storage::setSketch(const EntityWrapperPtr& theSketch) { - Slvs_Entity aPoint[2] = { - getEntity(theLine.point[0]), - getEntity(theLine.point[1]) - }; - - Slvs_Constraint anEqual; - if (isAxisParallel(theLine.h)) { - // Fix one point and a line length - Slvs_hConstraint aFixed; - if (!isPointFixed(theLine.point[0], aFixed, true) && - !isPointFixed(theLine.point[1], aFixed, true)) - fixPoint(aPoint[0], theCreated); - if (!isUsedInEqual(theLine.h, anEqual)) { - // Check the distance is not set yet - std::vector::const_iterator aDistIt = myConstraints.begin(); - for (; aDistIt != myConstraints.end(); ++aDistIt) - if ((aDistIt->type == SLVS_C_PT_PT_DISTANCE) && - ((aDistIt->ptA == theLine.point[0] && aDistIt->ptB == theLine.point[1]) || - (aDistIt->ptA == theLine.point[1] && aDistIt->ptB == theLine.point[0]))) - return; - // Calculate distance between points on the line - double aCoords[4]; - for (int i = 0; i < 2; i++) - for (int j = 0; j < 2; j++) { - Slvs_Param aParam = getParameter(aPoint[i].param[j]); - aCoords[2*i+j] = aParam.val; - } - - double aLength = sqrt((aCoords[2] - aCoords[0]) * (aCoords[2] - aCoords[0]) + - (aCoords[3] - aCoords[1]) * (aCoords[3] - aCoords[1])); - // fix line length - Slvs_Constraint aDistance = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theLine.group, - SLVS_C_PT_PT_DISTANCE, theLine.wrkpl, aLength, - theLine.point[0], theLine.point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - aDistance.h = addConstraint(aDistance); - theCreated.push_back(aDistance.h); - } + if (sketch()) return; - } - else if (isUsedInEqual(theLine.h, anEqual)) { - // Check another entity of Equal is already fixed - Slvs_hEntity anOtherEntID = anEqual.entityA == theLine.h ? anEqual.entityB : anEqual.entityA; - if (isEntityFixed(anOtherEntID, true)) { - // Fix start point of the line (if end point is not fixed yet) ... - Slvs_hConstraint anEndFixedID = SLVS_E_UNKNOWN; - bool isFixed = isPointFixed(theLine.point[1], anEndFixedID, true); - if (isFixed == SLVS_E_UNKNOWN) - fixPoint(aPoint[0], theCreated); - // ... and create fixed point lying on this line - Slvs_hEntity aPointToCopy = anEndFixedID == SLVS_E_UNKNOWN ? theLine.point[1] : theLine.point[0]; - // Firstly, search already fixed point on line - bool isPonLineFixed = false; - Slvs_hEntity aFixedPoint; - std::vector::const_iterator aPLIter = myConstraints.begin(); - for (; aPLIter != myConstraints.end() && !isPonLineFixed; ++aPLIter) - if (aPLIter->type == SLVS_C_PT_ON_LINE && aPLIter->entityA == theLine.h) { - isPonLineFixed = isPointFixed(aPLIter->ptA, anEndFixedID); - aFixedPoint = aPLIter->ptA; - } - - if (isPonLineFixed) { // update existent constraint - copyEntity(aPointToCopy, aFixedPoint); - } else { // create new constraint - Slvs_hEntity aCopied = copyEntity(aPointToCopy); - Slvs_Constraint aPonLine = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theLine.group, SLVS_C_PT_ON_LINE, - theLine.wrkpl, 0.0, aCopied, SLVS_E_UNKNOWN, theLine.h, SLVS_E_UNKNOWN); - aPonLine.h = addConstraint(aPonLine); - theCreated.push_back(aPonLine.h); - fixPoint(getEntity(aCopied), theCreated); - } - return; - } - } - - // Fix both points - for (int i = 0; i < 2; i++) - fixPoint(aPoint[i], theCreated); + addEntity(FeaturePtr(), theSketch); } -void SketchSolver_Storage::fixCircle(const Slvs_Entity& theCircle, - std::vector& theCreated) +void SketchSolver_Storage::blockEvents(bool isBlocked) const { - bool isFixRadius = true; - // Verify the arc is under Equal constraint - Slvs_Constraint anEqual; - if (isUsedInEqual(theCircle.h, anEqual)) { - // Check another entity of Equal is already fixed - Slvs_hEntity anOtherEntID = anEqual.entityA == theCircle.h ? anEqual.entityB : anEqual.entityA; - if (isEntityFixed(anOtherEntID, true)) - isFixRadius = false; - } + std::map >::const_iterator + aCIter = myConstraintMap.begin(); + for (; aCIter != myConstraintMap.end(); aCIter++) + if (aCIter->first->data() && aCIter->first->data()->isValid()) + aCIter->first->data()->blockSendAttributeUpdated(isBlocked); - fixPoint(getEntity(theCircle.point[0]), theCreated); + std::map::const_iterator aFIter = myFeatureMap.begin(); + for (; aFIter != myFeatureMap.end(); aFIter++) + if (aFIter->first->data() && aFIter->first->data()->isValid()) + aFIter->first->data()->blockSendAttributeUpdated(isBlocked); - if (isFixRadius) { - // Search the radius is already fixed - std::vector::const_iterator aDiamIter = myConstraints.begin(); - for (; aDiamIter != myConstraints.end(); ++aDiamIter) - if (aDiamIter->type == SLVS_C_DIAMETER && aDiamIter->entityA == theCircle.h) - return; - - // Fix radius of a circle - const Slvs_Entity& aRadEnt = getEntity(theCircle.distance); - double aRadius = getParameter(aRadEnt.param[0]).val; - Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theCircle.group, SLVS_C_DIAMETER, - theCircle.wrkpl, aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, theCircle.h, SLVS_E_UNKNOWN); - aFixedR.h = addConstraint(aFixedR); - theCreated.push_back(aFixedR.h); - } + std::map::const_iterator anAtIter = myAttributeMap.begin(); + for (; anAtIter != myAttributeMap.end(); anAtIter++) + if (anAtIter->first->owner() && anAtIter->first->owner()->data() && + anAtIter->first->owner()->data()->isValid()) + anAtIter->first->owner()->data()->blockSendAttributeUpdated(isBlocked); } -void SketchSolver_Storage::fixArc(const Slvs_Entity& theArc, - std::vector& theCreated) -{ - Slvs_Entity aPoint[3] = { - getEntity(theArc.point[0]), - getEntity(theArc.point[1]), - getEntity(theArc.point[2]) - }; - - bool isFixRadius = true; - std::list aPointsToFix; - aPointsToFix.push_back(aPoint[1]); - aPointsToFix.push_back(aPoint[2]); - - // Verify the arc is under Equal constraint - Slvs_Constraint anEqual; - if (isUsedInEqual(theArc.h, anEqual)) { - // Check another entity of Equal is already fixed - Slvs_hEntity anOtherEntID = anEqual.entityA == theArc.h ? anEqual.entityB : anEqual.entityA; - if (isEntityFixed(anOtherEntID, true)) { - isFixRadius = false; - Slvs_Entity anOtherEntity = getEntity(anOtherEntID); - if (anOtherEntity.type == SLVS_E_LINE_SEGMENT) { - aPointsToFix.pop_back(); - aPointsToFix.push_back(aPoint[0]); - } - } - } - - Slvs_hConstraint aConstrID; - int aNbPointsToFix = 2; // number of fixed points for the arc - if (isPointFixed(theArc.point[0], aConstrID, true)) - aNbPointsToFix--; - - double anArcPoints[3][2]; - for (int i = 0; i < 3; i++) { - const Slvs_Entity& aPointOnArc = getEntity(theArc.point[i]); - for (int j = 0; j < 2; j++) - anArcPoints[i][j] = getParameter(aPointOnArc.param[j]).val; - } - - // Radius of the arc - std::shared_ptr aCenter(new GeomAPI_Pnt2d(anArcPoints[0][0], anArcPoints[0][1])); - std::shared_ptr aStart(new GeomAPI_Pnt2d(anArcPoints[1][0], anArcPoints[1][1])); - double aRadius = aCenter->distance(aStart); - // Update end point of the arc to be on a curve - std::shared_ptr anEnd(new GeomAPI_Pnt2d(anArcPoints[2][0], anArcPoints[2][1])); - double aDistance = anEnd->distance(aCenter); - std::shared_ptr aDir = anEnd->xy()->decreased(aCenter->xy()); - if (aDistance < tolerance) - aDir = aStart->xy()->decreased(aCenter->xy())->multiplied(-1.0); - else - aDir = aDir->multiplied(aRadius / aDistance); - double xy[2] = {aCenter->x() + aDir->x(), aCenter->y() + aDir->y()}; - const Slvs_Entity& aEndPoint = getEntity(theArc.point[2]); - for (int i = 0; i < 2; i++) { - Slvs_Param aParam = getParameter(aEndPoint.param[i]); - aParam.val = xy[i]; - updateParameter(aParam); - } - - std::list::iterator aPtIt = aPointsToFix.begin(); - for (; aNbPointsToFix > 0; aPtIt++, aNbPointsToFix--) - fixPoint(*aPtIt, theCreated); - - if (isFixRadius) { - // Fix radius of the arc - bool isExists = false; - std::vector::iterator anIt = myConstraints.begin(); - for (; anIt != myConstraints.end() && !isExists; ++anIt) - if (anIt->type == SLVS_C_DIAMETER && anIt->entityA == theArc.h) - isExists = true; - if (!isExists) { - Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theArc.group, SLVS_C_DIAMETER, - theArc.wrkpl, aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, theArc.h, SLVS_E_UNKNOWN); - aFixedR.h = addConstraint(aFixedR); - theCreated.push_back(aFixedR.h); - } - } -} -bool SketchSolver_Storage::isAxisParallel(const Slvs_hEntity& theEntity) const -{ - std::vector::const_iterator anIter = myConstraints.begin(); - for (; anIter != myConstraints.end(); anIter++) - if ((anIter->type == SLVS_C_HORIZONTAL || anIter->type == SLVS_C_VERTICAL) && - anIter->entityA == theEntity) - return true; - return false; -} -bool SketchSolver_Storage::isUsedInEqual( - const Slvs_hEntity& theEntity, Slvs_Constraint& theEqual) const -{ - // Check the entity is used in Equal constraint - std::vector::const_iterator anEqIter = myConstraints.begin(); - for (; anEqIter != myConstraints.end(); anEqIter++) - if ((anEqIter->type == SLVS_C_EQUAL_LENGTH_LINES || - anEqIter->type == SLVS_C_EQUAL_LINE_ARC_LEN || - anEqIter->type == SLVS_C_EQUAL_RADIUS) && - (anEqIter->entityA == theEntity || anEqIter->entityB == theEntity)) { - theEqual = *anEqIter; - return true; - } - return false; -} -bool SketchSolver_Storage::isNeedToResolve() +// ============== Auxiliary functions ==================================== +bool isEqual(const std::list& theCVec1, + const std::list& theCVec2) { - if (myConstraints.empty()) + if (theCVec1.size() != theCVec2.size()) return false; - if (!myNeedToResolve) { - // Verify the updated parameters are used in constraints - std::set aPoints; - std::vector::const_iterator anEntIt = myEntities.begin(); - for (; anEntIt != myEntities.end(); ++anEntIt) { - for (int i = 0; i < 4 && anEntIt->param[i] != SLVS_E_UNKNOWN; ++i) - if (myUpdatedParameters.find(anEntIt->param[i]) != myUpdatedParameters.end()) { - aPoints.insert(anEntIt->h); - break; - } - } - std::set anEntities = aPoints; - for (anEntIt = myEntities.begin(); anEntIt != myEntities.end(); ++anEntIt) { - for (int i = 0; i < 4 && anEntIt->point[i] != SLVS_E_UNKNOWN; ++i) - if (aPoints.find(anEntIt->point[i]) != aPoints.end()) { - anEntities.insert(anEntIt->h); - break; - } - } - - std::vector::const_iterator aCIt = myConstraints.begin(); - for (; aCIt != myConstraints.end() && !myNeedToResolve; ++aCIt) { - Slvs_hEntity anAttrs[6] = - {aCIt->ptA, aCIt->ptB, aCIt->entityA, aCIt->entityB, aCIt->entityC, aCIt->entityD}; - for (int i = 0; i < 6; i++) - if (anAttrs[i] != SLVS_E_UNKNOWN && anEntities.find(anAttrs[i]) != anEntities.end()) { - myNeedToResolve = true; - break; - } - } + std::list aChecked(theCVec2.size(), false); + std::list::const_iterator anIt1 = theCVec1.begin(); + for (; anIt1 != theCVec1.end(); ++anIt1) { + std::list::const_iterator anIt2 = theCVec2.begin(); + std::list::iterator aCheckIt = aChecked.begin(); + while (aCheckIt != aChecked.end() && *aCheckIt) { + ++aCheckIt; + ++anIt2; + } + for (; anIt2 != theCVec2.end(); ++anIt2, ++aCheckIt) + if (!(*aCheckIt) && (*anIt1)->isEqual(*anIt2)) { + *aCheckIt = true; + break; + } + // the same constraint is not found + if (anIt2 == theCVec2.end()) + return false; } - - myUpdatedParameters.clear(); - return myNeedToResolve; -} - - - - - - -// ======================================================== -// ========= Auxiliary functions =============== -// ======================================================== - -template -int Search(const uint32_t& theEntityID, const std::vector& theEntities) -{ - int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0; - int aVecSize = theEntities.size(); - if (theEntities.empty()) - return 1; - while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID) - aResIndex--; - while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID) - aResIndex++; - if (aResIndex == -1 || (aResIndex < aVecSize && theEntities[aResIndex].h != theEntityID)) - aResIndex = aVecSize; - return aResIndex; -} - -bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2) -{ - return fabs(theParam1.val - theParam2.val) > tolerance; -} - -bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2) -{ - int i = 0; - for (; theEntity1.param[i] != 0 && i < 4; i++) - if (theEntity1.param[i] != theEntity2.param[i]) - return true; - i = 0; - for (; theEntity1.point[i] != 0 && i < 4; i++) - if (theEntity1.point[i] != theEntity2.point[i]) - return true; - return false; -} - -bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2) -{ - return theConstraint1.ptA != theConstraint2.ptA || - theConstraint1.ptB != theConstraint2.ptB || - theConstraint1.entityA != theConstraint2.entityA || - theConstraint1.entityB != theConstraint2.entityB || - theConstraint1.entityC != theConstraint2.entityC || - theConstraint1.entityD != theConstraint2.entityD || - fabs(theConstraint1.valA - theConstraint2.valA) > tolerance; + return true; } diff --git a/src/SketchSolver/SketchSolver_Storage.h b/src/SketchSolver/SketchSolver_Storage.h index bb270d77d..3369fc7ae 100644 --- a/src/SketchSolver/SketchSolver_Storage.h +++ b/src/SketchSolver/SketchSolver_Storage.h @@ -1,218 +1,203 @@ // Copyright (C) 2014-20xx CEA/DEN, EDF R&D // File: SketchSolver_Storage.h -// Created: 18 Mar 2015 +// Created: 30 Nov 2015 // Author: Artem ZHIDKOV #ifndef SketchSolver_Storage_H_ #define SketchSolver_Storage_H_ -#include "SketchSolver.h" -#include +#include +#include +#include +#include +#include -#include -#include -#include -#include +#include +#include +#include +#include /** \class SketchSolver_Storage * \ingroup Plugins - * \brief Contains all necessary data in SolveSpace format to solve a single group of constraints + * \brief Interface to map SketchPlugin features to the entities of corresponding solver. */ class SketchSolver_Storage { -public: +private: SketchSolver_Storage(); + SketchSolver_Storage(const SketchSolver_Storage&); + SketchSolver_Storage& operator=(const SketchSolver_Storage&); - /** \brief Add new parameter to the current group - * \param[in] theParam SolveSpace parameter - * \return the ID of added parameter - */ - Slvs_hParam addParameter(const Slvs_Param& theParam); - /** \brief Updates parameter in the current group. If the ID of parameter is zero, the new item will be added - * \param[in] theParam SolveSpace parameter - * \return the ID of updated/added parameter - */ - Slvs_hParam updateParameter(const Slvs_Param& theParam); - /** \brief Removes the parameter by its ID - * \param[in] theParamID index of parameter to be removed - * \return \c true if the parameter was successfully removed - */ - bool removeParameter(const Slvs_hParam& theParamID); - /// \brief Returns the parameter by its ID - const Slvs_Param& getParameter(const Slvs_hParam& theParamID) const; - - /** \brief Add new entity to the current group - * \param[in] theEntity SolveSpace entity - * \return the ID of added entity - */ - Slvs_hEntity addEntity(const Slvs_Entity& theEntity); - /** \brief Updates entity in the current group. If the ID of entity is zero, the new item will be added - * \param[in] theEntity SolveSpace entity - * \return the ID of updated/added entity - */ - Slvs_hEntity updateEntity(const Slvs_Entity& theEntity); - /** \brief Removes the entity by its ID. All parameters used in this entity, - * and not used in other constraints, will be removed too. - * \param[in] theEntityID index of entity to be removed - * \return \c true if the entity was successfully removed - */ - bool removeEntity(const Slvs_hEntity& theEntityID); - /** \brief Remove all entities, which are not used in constraints - */ - void removeUnusedEntities(); - /// \brief Returns the entity by its ID - const Slvs_Entity& getEntity(const Slvs_hEntity& theEntityID) const; - /// \brief Makes a full copy of the given entity - Slvs_hEntity copyEntity(const Slvs_hEntity& theCopied); - /// \brief Copy one entity to another - void copyEntity(const Slvs_hEntity& theFrom, const Slvs_hEntity& theTo); - /// \brief Check the entity is used in constraints - bool isUsedByConstraints(const Slvs_hEntity& theEntityID) const; - /// \brief Returns maximal ID of entities in this storage - const Slvs_hEntity& entityMaxID() const - { return myEntityMaxID; } - - /// \brief Verifies the current point or another coincident one is fixed - /// \param[in] thePointID entity to be checked fixed - /// \param[out] theFixed ID of constraint - /// \param[in] theAccurate if \c true, the calculation will be made for all type of constraints, - /// if \c false, only the point is verified - /// \return \c true if the point is fixed - bool isPointFixed(const Slvs_hEntity& thePointID, Slvs_hConstraint& theFixed, bool theAccurate = false) const; - /// \brief Verifies the current entity is fully fixed (may not be changed by constraints) - /// \param[in] theEntityID entity to be checked fixed - /// \param[in] theAccurate if \c true, the calculation will be made for all type of constraints, - /// if \c false, only points are verified - /// \return \c true if the entity is fixed - bool isEntityFixed(const Slvs_hEntity& theEntityID, bool theAccurate = false) const; - - /** \brief Add new constraint to the current group - * \param[in] theConstraint SolveSpace's constraint - * \return the ID of added constraint - */ - Slvs_hConstraint addConstraint(const Slvs_Constraint& theConstraint); - /** \brief Updates constraint in the current group. - * If the ID of constraint is zero, the new item will be added - * \param[in] theConstraint SolveSpace constraint - * \return the ID of updated/added constraint - */ - Slvs_hConstraint updateConstraint(const Slvs_Constraint& theConstraint); - /** \brief Removes the constraint by its ID. All entities and parameters depending on this - * constraint, which are not used in other constraints, will be removed too. - * \param[in] theConstraintID index of constraint to be removed - * \return \c true if the constraint was successfully removed - */ - bool removeConstraint(const Slvs_hConstraint& theConstraintID); - /// \brief Returns the constraint by its ID - const Slvs_Constraint& getConstraint(const Slvs_hConstraint& theConstraintID) const; - /// \brief Returns list of constraints of specified type - std::list getConstraintsByType(int theConstraintType) const; - /// \brief Returns quantity of constraints in this storage - size_t nbConstraints() const - { return myConstraints.size(); } - - /// \brief Attach constraint SLVS_C_WHERE_DRAGGED to this storage. It need to make precise calculations - void addConstraintWhereDragged(const Slvs_hConstraint& theConstraintID); - - /// \brief Add transient constraint - void addTemporaryConstraint(const Slvs_hConstraint& theConstraintID); - /// \brief Remove all transient constraints - void removeTemporaryConstraints(); - /// \brief Remove one temporary constraint. Preferable to remove the points under Point-on-Line constraint - /// \return Number of remaining temporary constraints - int deleteTemporaryConstraint(); - /// \brief Checks the constraint is temporary - bool isTemporary(const Slvs_hConstraint& theConstraintID) const; - /// \brief Number of temporary constraints - int numberTemporary() const - { return (int)myTemporaryConstraints.size(); } +public: + SketchSolver_Storage(const GroupID& theGroup) + : myGroupID(theGroup), + myNeedToResolve(false) + {} + + /// \brief Change mapping between constraint from SketchPlugin and + /// a constraint applicable for corresponding solver. + /// \param theConstraint [in] original SketchPlugin constraint + /// \param theSolverConstraint [in] solver's constraints + SKETCHSOLVER_EXPORT void addConstraint(ConstraintPtr theConstraint, + ConstraintWrapperPtr theSolverConstraints); + /// \brief Change mapping between constraint from SketchPlugin and + /// the list of constraints applicable for corresponding solver. + /// \param theConstraint [in] original SketchPlugin constraint + /// \param theSolverConstraints [in] list of solver's constraints + SKETCHSOLVER_EXPORT + void addConstraint(ConstraintPtr theConstraint, + std::list theSolverConstraints); + + /// \brief Convert feature to the form applicable for specific solver and map it + /// \param theFeature [in] feature to convert + /// \param theGroup [in] id of the group where the feature should be placed + /// \return \c true if the feature has been created or updated + SKETCHSOLVER_EXPORT bool update(FeaturePtr theFeature, const GroupID& theGroup = GID_UNKNOWN); + /// \brief Convert attribute to the form applicable for specific solver and map it + /// \param theFeature [in] feature to convert + /// \return \c true if the attribute has been created or updated + SKETCHSOLVER_EXPORT bool update(AttributePtr theAttribute, const GroupID& theGroup = GID_UNKNOWN); + + /// \brief Returns constraint related to corresponding constraint + SKETCHSOLVER_EXPORT + const std::list& constraint(const ConstraintPtr& theConstraint) const; + + /// \brief Returns entity related to corresponding feature + SKETCHSOLVER_EXPORT const EntityWrapperPtr& entity(const FeaturePtr& theFeature) const; + /// \brief Returns entity related to corresponding attribute + SKETCHSOLVER_EXPORT const EntityWrapperPtr& entity(const AttributePtr& theAttribute) const; + + /// \brief Return parsed sketch entity + const EntityWrapperPtr& sketch() const; + /// \brief Set parsed sketch entity. + /// Be careful, this method does not update fields of the storage specific for the solver. + /// Does not update if the sketch already exists. + void setSketch(const EntityWrapperPtr& theSketch); + + /// \brief Mark two points as coincident + virtual void addCoincidentPoints(EntityWrapperPtr theMaster, EntityWrapperPtr theSlave) = 0; + + /// \brief Shows the storage has any constraint twice + virtual bool hasDuplicatedConstraint() const = 0; + + /// \brief Removes constraint from the storage + /// \return \c true if the constraint and all its parameters are removed successfully + virtual bool removeConstraint(ConstraintPtr theConstraint) = 0; + /// \brief Removes feature from the storage + /// \return \c true if the feature and its attributes are removed successfully; + /// \c false if the feature or any it attribute is used by remaining constraints. + virtual bool removeEntity(FeaturePtr theFeature) = 0; + /// \brief Removes attribute from the storage + /// \return \c true if the attribute is not used by remaining features and constraints + virtual bool removeEntity(AttributePtr theAttribute) = 0; + + /// \brief Remove all features became invalid + SKETCHSOLVER_EXPORT void removeInvalidEntities(); + + /// \brief Mark specified constraint as temporary + virtual void setTemporary(ConstraintPtr theConstraint) = 0; + /// \brief Returns number of temporary constraints + virtual size_t nbTemporary() const = 0; + /// \brief Remove temporary constraints + /// \param theNbConstraints [in] number of temporary constraints to be deleted + /// \return number of remaining temporary constraints + virtual size_t removeTemporary(size_t theNbConstraints = 1) = 0; + + /// \brief Check whether the feature or its attributes are used by this storage + /// \param theFeature [in] feature to be checked + /// \return \c true if the feature interacts with the storage + bool isInteract(const FeaturePtr& theFeature) const; + /// \brief Check whether the attribute is used by this storage + /// \param theAttribute [in] attribute to be checked + /// \return \c true if the attribute interacts with the storage + bool isInteract(const AttributePtr& theAttribute) const; + + /// \brief Check the features is not removed + bool isConsistent() const; /// \brief Shows the sketch should be resolved - bool isNeedToResolve(); - - /// \brief Shows the storage has the same constraint twice - bool hasDuplicatedConstraint() const - { return myDuplicatedConstraint; } - + virtual bool isNeedToResolve() + { return myNeedToResolve; } /// \brief Changes the flag of group to be resolved void setNeedToResolve(bool theFlag) { myNeedToResolve = theFlag; } - /// \brief Returns lists of removed elements - void getRemoved(std::set& theParameters, - std::set& theEntities, - std::set& theConstraints); - - /// \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); - /// \brief Remove point-point coincidence - void removeCoincidence(const Slvs_Constraint& theCoincidence); - -public: - /// \brief Check two points are coincident - bool isCoincident(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const; - - /// \brief Check two points are coincident or have same coordinates - bool isEqual(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const; - - /// \brief Check the entity is horizontal of vertical - bool isAxisParallel(const Slvs_hEntity& theEntity) const; - - /// \brief Verifies the entity is used in any equal constraint - /// \param[in] theEntity entity to be found - /// \param[out] theEqual constraint, which uses the entity - /// \return \c true, if the Equal constrait is found - bool isUsedInEqual(const Slvs_hEntity& theEntity, Slvs_Constraint& theEqual) const; - - /// \brief Fixes specified entity - /// \param theEntity ID of the entity to be fixed - /// \return List of created constraints - std::vector fixEntity(const Slvs_hEntity& theEntity); + /// \brief Initialize solver by constraints, entities and parameters + virtual void initializeSolver(SolverPtr theSolver) = 0; + + /// \brief Update SketchPlugin features after resolving constraints + /// \param theFixedOnly [in] if \c true the fixed points will be updated only + virtual void refresh(bool theFixedOnly = false) const = 0; + + /// \brief Check if some parameters or entities are returned + /// to the current group after removing temporary constraints + virtual void verifyFixed() = 0; + + /// \brief Calculate point on theBase entity. Value theCoeff is in [0.0 .. 1.0] and + /// shows the distance from the start point. + virtual EntityWrapperPtr calculateMiddlePoint(EntityWrapperPtr theBase, + double theCoeff) = 0; + +protected: + /// \brief Change mapping feature from SketchPlugin and + /// the entity applicable for corresponding solver. + /// \param theFeature [in] original SketchPlugin feature + /// \param theSolverEntity [in] solver's entity, created outside + SKETCHSOLVER_EXPORT + void addEntity(FeaturePtr theFeature, + EntityWrapperPtr theSolverEntity); + + /// \brief Change mapping attribute of a feature and the entity applicable for corresponding solver. + /// \param theAttribute [in] original attribute + /// \param theSolverEntity [in] solver's entity, created outside + SKETCHSOLVER_EXPORT + void addEntity(AttributePtr theAttribute, + EntityWrapperPtr theSolverEntity); + + /// \brief Update constraint's data + /// \return \c true if any value is updated + virtual bool update(ConstraintWrapperPtr& theConstraint) = 0; + /// \brief Update entity's data + /// \return \c true if any value is updated + virtual bool update(EntityWrapperPtr& theEntity) = 0; + /// \brief Update parameter's data + /// \return \c true if the value of parameter is updated + virtual bool update(ParameterWrapperPtr& theParameter) = 0; + + /// \brief Remove constraint + /// \return \c true if the constraint and all its parameters are removed successfully + virtual bool remove(ConstraintWrapperPtr theConstraint) = 0; + /// \brief Remove entity + /// \return \c true if the entity and all its parameters are removed successfully + virtual bool remove(EntityWrapperPtr theEntity) = 0; + /// \brief Remove parameter + /// \return \c true if the parameter has been removed + virtual bool remove(ParameterWrapperPtr theParameter) = 0; + + /// \brief Update the group for the given entity, its sub-entities and parameters + virtual void changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup) = 0; + /// \brief Update the group for the given parameter + virtual void changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup) = 0; + + /// \brief Block or unblock events when refreshing features + SKETCHSOLVER_EXPORT void blockEvents(bool isBlocked) const; private: - /// \brief Fixes specified point - /// \param [in] thePoint point to be fixed - /// \param [out] theCreated list of the Fixed constraints created - void fixPoint(const Slvs_Entity& thePoint, std::vector& theCreated); - /// \brief Fixes specified line - /// \param [in] theLine line to be fixed - /// \param [out] theCreated list of the Fixed constraints created - void fixLine(const Slvs_Entity& theLine, std::vector& theCreated); - /// \brief Fixes specified circle - /// \param [in] theCircle circle to be fixed - /// \param [out] theCreated list of the Fixed constraints created - void fixCircle(const Slvs_Entity& theCircle, std::vector& theCreated); - /// \brief Fixes specified arc - /// \param [in] theArc arc to be fixed - /// \param [out] theCreated list of the Fixed constraints created - void fixArc(const Slvs_Entity& theArc, std::vector& theCreated); + /// \brief Find the normal of the sketch + EntityWrapperPtr getNormal() const; -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 (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 (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 (sorted by the identifier) +protected: + GroupID myGroupID; ///< identifier of the group, this storage belongs to - std::vector< std::set > myCoincidentPoints; ///< lists of coincident points - Slvs_hConstraint myFixed; ///< identifier of one of temporary constraints to fix separate point + /// map SketchPlugin constraint to a list of solver's constraints + std::map > myConstraintMap; + /// map SketchPlugin feature to solver's entity + std::map myFeatureMap; + /// map attribute to solver's entity + std::map myAttributeMap; bool myNeedToResolve; ///< parameters are changed and group needs to be resolved - bool myDuplicatedConstraint; ///< shows the storage has same constraint twice - - std::set myTemporaryConstraints; ///< list of transient constraints - std::set myRemovedParameters; ///< list of just removed parameters (cleared when returning to applicant) - std::set myRemovedEntities; ///< list of just removed entities (cleared when returning to applicant) - std::set myRemovedConstraints; ///< list of just removed constraints (cleared when returning to applicant) - std::set myUpdatedParameters; ///< list of just updated parameters (cleared when isNeedToResolve() called) }; typedef std::shared_ptr StoragePtr; diff --git a/src/SketchSolver/SolveSpaceSolver/CMakeLists.txt b/src/SketchSolver/SolveSpaceSolver/CMakeLists.txt new file mode 100644 index 000000000..cda6e3bc1 --- /dev/null +++ b/src/SketchSolver/SolveSpaceSolver/CMakeLists.txt @@ -0,0 +1,42 @@ +## Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +FIND_PACKAGE(SolveSpace REQUIRED) + +SET(PROJECT_HEADERS + SolveSpaceSolver_Solver.h + SolveSpaceSolver_Builder.h + SolveSpaceSolver_Storage.h + SolveSpaceSolver_EntityWrapper.h + SolveSpaceSolver_ParameterWrapper.h + SolveSpaceSolver_ConstraintWrapper.h + SolveSpaceSolver_ConstraintType.h +) + +SET(PROJECT_SOURCES + SolveSpaceSolver_Solver.cpp + SolveSpaceSolver_Builder.cpp + SolveSpaceSolver_Storage.cpp + SolveSpaceSolver_EntityWrapper.cpp + SolveSpaceSolver_ParameterWrapper.cpp + SolveSpaceSolver_ConstraintWrapper.cpp +) + +SET(PROJECT_LIBRARIES + ${SOLVESPACE_LIBRARIES} + SketchSolver + ModelAPI + GeomAPI +) + +INCLUDE_DIRECTORIES( + ${SOLVESPACE_INCLUDE_DIRS} + ${PROJECT_SOURCE_DIR}/src/SketchSolver + ${PROJECT_SOURCE_DIR}/src/SketchPlugin + ${PROJECT_SOURCE_DIR}/src/ModelAPI + ${PROJECT_SOURCE_DIR}/src/GeomAPI + ${PROJECT_SOURCE_DIR}/src/GeomDataAPI +) + +ADD_LIBRARY(SolveSpaceSolver MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS}) +TARGET_LINK_LIBRARIES(SolveSpaceSolver ${PROJECT_LIBRARIES}) +INSTALL(TARGETS SolveSpaceSolver DESTINATION plugins) diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.cpp b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.cpp new file mode 100644 index 000000000..eabf9f6ae --- /dev/null +++ b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.cpp @@ -0,0 +1,845 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SolveSpaceSolver_Builder.cpp +// Created: 25 Mar 2015 +// Author: Artem ZHIDKOV + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + + +static EntityWrapperPtr createLine(FeaturePtr theFeature, + const std::list& theAttributes, + const GroupID& theGroupID, + const EntityID& theSketchID); +static EntityWrapperPtr createCircle(FeaturePtr theFeature, + const std::list& theAttributes, + const GroupID& theGroupID, + const EntityID& theSketchID); +static EntityWrapperPtr createArc(FeaturePtr theFeature, + const std::list& theAttributes, + const GroupID& theGroupID, + const EntityID& theSketchID); + +/// \brief Set flags of constraint to identify which points are coincident in the Tangency +/// (for more information, see SolveSpace documentation) +static void adjustTangency(ConstraintWrapperPtr theConstraint); +/// \brief Set flags for angle constraint +static void adjustAngle(ConstraintWrapperPtr theConstraint); +/// \brief Update mirror points +static void adjustMirror(ConstraintWrapperPtr theConstraint); +/// \brief Update positions of rotated features +static void adjustMultiRotation(ConstraintWrapperPtr theConstraint); +/// \brief Update positions of translated features +static void adjustMultiTranslation(ConstraintWrapperPtr theConstraint); + +/// \brief Transform points to be symmetric regarding to the mirror line +static void makeMirrorPoints(EntityWrapperPtr theOriginal, + EntityWrapperPtr theMirrored, + EntityWrapperPtr theMirrorLine); + + + +// Initialization of constraint builder self pointer +BuilderPtr SolveSpaceSolver_Builder::mySelf = SolveSpaceSolver_Builder::getInstance(); + +BuilderPtr SolveSpaceSolver_Builder::getInstance() +{ + if (!mySelf) { + mySelf = BuilderPtr(new SolveSpaceSolver_Builder); + SketchSolver_Manager::instance()->setBuilder(mySelf); + } + return mySelf; +} + +StoragePtr SolveSpaceSolver_Builder::createStorage(const GroupID& theGroup) const +{ + return StoragePtr(new SolveSpaceSolver_Storage(theGroup)); +} + +SolverPtr SolveSpaceSolver_Builder::createSolver() const +{ + return SolverPtr(new SolveSpaceSolver_Solver); +} + + +std::list SolveSpaceSolver_Builder::createConstraint( + ConstraintPtr theConstraint, + const GroupID& theGroupID, + const EntityID& theSketchID, + const SketchSolver_ConstraintType& theType, + const double& theValue, + const EntityWrapperPtr& thePoint1, + const EntityWrapperPtr& thePoint2, + const EntityWrapperPtr& theEntity1, + const EntityWrapperPtr& theEntity2) const +{ + if (theType == CONSTRAINT_SYMMETRIC) + return createMirror(theConstraint, theGroupID, theSketchID, + thePoint1, thePoint2, theEntity1); + + int aType = ConstraintType::toSolveSpace(theType); + if (aType == SLVS_C_UNKNOWN) + return std::list(); + + Slvs_hEntity aSlvsEntities[4] = {SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN}; + EntityWrapperPtr anOriginal[4] = {thePoint1, thePoint2, theEntity1, theEntity2}; + std::list aConstrAttrList; // to be filled + for (int i = 0; i < 4; ++i) { + if (!anOriginal[i]) + continue; + aSlvsEntities[i] = (Slvs_hEntity)anOriginal[i]->id(); + if (aSlvsEntities[i] == SLVS_E_UNKNOWN) + return std::list(); // entity is not added into a storage, constraint can not be created + aConstrAttrList.push_back(anOriginal[i]); + } + + Slvs_Constraint aConstraint = Slvs_MakeConstraint( + SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID, + theValue, aSlvsEntities[0], aSlvsEntities[1], aSlvsEntities[2], aSlvsEntities[3]); + ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint)); + aResult->setValue(theValue); + aResult->setEntities(aConstrAttrList); + adjustConstraint(aResult); + + return std::list(1, aResult); +} + +std::list SolveSpaceSolver_Builder::createConstraint( + ConstraintPtr theConstraint, + const GroupID& theGroupID, + const EntityID& theSketchID, + const SketchSolver_ConstraintType& theType, + const double& theValue, + const EntityWrapperPtr& thePoint1, + const EntityWrapperPtr& thePoint2, + const std::list& theTrsfEnt) const +{ + if (theType != CONSTRAINT_MULTI_ROTATION && theType != CONSTRAINT_MULTI_TRANSLATION) + return std::list(); + + int aType = ConstraintType::toSolveSpace(theType); + if (aType == SLVS_C_UNKNOWN) + return std::list(); + + Slvs_Constraint aConstraint = + Slvs_MakeConstraint(SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID, + theValue, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); + + std::list aConstrAttrList = theTrsfEnt; + if (thePoint2) + aConstrAttrList.push_front(thePoint2); + aConstrAttrList.push_front(thePoint1); + + ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint)); + aResult->setValue(theValue); + aResult->setEntities(aConstrAttrList); + return std::list(1, aResult); +} + + +std::list SolveSpaceSolver_Builder::createMirror( + ConstraintPtr theConstraint, + const GroupID& theGroupID, + const EntityID& theSketchID, + const EntityWrapperPtr& theEntity1, + const EntityWrapperPtr& theEntity2, + const EntityWrapperPtr& theMirrorLine) const +{ + Slvs_Constraint aConstraint; + std::list aResult; + std::list aConstrAttrList; + if (theEntity1->type() == ENTITY_POINT) { + if (theEntity2->group() == theGroupID) // theEntity2 is not fixed + makeMirrorPoints(theEntity1, theEntity2, theMirrorLine); + + aConstraint = Slvs_MakeConstraint( + SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, SLVS_C_SYMMETRIC_LINE, (Slvs_hEntity)theSketchID, + 0.0, (Slvs_hEntity)theEntity1->id(), (Slvs_hEntity)theEntity2->id(), + (Slvs_hEntity)theMirrorLine->id(), SLVS_E_UNKNOWN); + + aConstrAttrList.push_back(theEntity1); + aConstrAttrList.push_back(theEntity2); + aConstrAttrList.push_back(theMirrorLine); + + ConstraintWrapperPtr aWrapper(new SolveSpaceSolver_ConstraintWrapper( + theConstraint, aConstraint)); + aWrapper->setEntities(aConstrAttrList); + aResult.push_back(aWrapper); + } + else if (theEntity1->type() == ENTITY_LINE) { + const std::list& aPoints1 = theEntity1->subEntities(); + const std::list& aPoints2 = theEntity2->subEntities(); + std::list::const_iterator anIt1 = aPoints1.begin(); + std::list::const_iterator anIt2 = aPoints2.begin(); + for (; anIt1 != aPoints1.end() && anIt2 != aPoints2.end(); ++anIt1, ++anIt2) { + std::list aMrrList = + createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine); + aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end()); + } + } + else if (theEntity1->type() == ENTITY_CIRCLE) { + const std::list& aPoints1 = theEntity1->subEntities(); + std::list::const_iterator anIt1 = aPoints1.begin(); + for (; anIt1 != aPoints1.end(); ++anIt1) + if ((*anIt1)->type() == ENTITY_POINT) + break; + const std::list& aPoints2 = theEntity2->subEntities(); + std::list::const_iterator anIt2 = aPoints2.begin(); + for (; anIt2 != aPoints2.end(); ++anIt2) + if ((*anIt2)->type() == ENTITY_POINT) + break; + + std::list aMrrList = + createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine); + aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end()); + + // Additional constraint for equal radii + aMrrList = createConstraint(theConstraint, theGroupID, theSketchID, CONSTRAINT_EQUAL_RADIUS, + 0.0, EntityWrapperPtr(), EntityWrapperPtr(), theEntity1, theEntity2); + aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end()); + } + else if (theEntity1->type() == ENTITY_ARC) { + // Do not allow mirrored arc recalculate its position until coordinated of all points recalculated + FeaturePtr aMirrArc = theEntity2->baseFeature(); + aMirrArc->data()->blockSendAttributeUpdated(true); + + std::list aMrrList; + std::list::const_iterator anIt1 = theEntity1->subEntities().begin(); + std::list::const_iterator anIt2 = theEntity2->subEntities().begin(); + if ((*anIt2)->group() == theGroupID) // mirrored point is not fixed + makeMirrorPoints(theEntity1->subEntities().front(), + theEntity2->subEntities().front(), theMirrorLine); + + // Workaround to avoid problems in SolveSpace. + // The symmetry of two arcs will be done using symmetry of three points on these arcs: + // start point, end point, and any other point on the arc + std::list aBaseArcPoints(++anIt1, theEntity1->subEntities().end()); + std::list aMirrorArcPoints(++anIt2, theEntity2->subEntities().end()); + // indices of points of arc, center corresponds center, first point corresponds last point + aMirrorArcPoints.reverse(); + + anIt1 = aBaseArcPoints.begin(); + anIt2 = aMirrorArcPoints.begin(); + for (; anIt1 != aBaseArcPoints.end(); ++anIt1, ++anIt2) { + aMrrList = createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine); + aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end()); + } + // Restore event sending + aMirrArc->data()->blockSendAttributeUpdated(false); + } + return aResult; +} + +void SolveSpaceSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstraint) const +{ + SketchSolver_ConstraintType aType = theConstraint->type(); + // Update flags in constraints + if (aType == CONSTRAINT_TANGENT_ARC_ARC || aType == CONSTRAINT_TANGENT_ARC_LINE) + adjustTangency(theConstraint); + else if (aType == CONSTRAINT_ANGLE) + adjustAngle(theConstraint); + else if (aType == CONSTRAINT_SYMMETRIC) + adjustMirror(theConstraint); + else if (aType == CONSTRAINT_MULTI_ROTATION) + adjustMultiRotation(theConstraint); + else if (aType == CONSTRAINT_MULTI_TRANSLATION) + adjustMultiTranslation(theConstraint); +} + +EntityWrapperPtr SolveSpaceSolver_Builder::createFeature( + FeaturePtr theFeature, + const std::list& theAttributes, + const GroupID& theGroupID, + const EntityID& theSketchID) const +{ + static EntityWrapperPtr aDummy; + if (!theFeature->data()->isValid()) + return aDummy; + + // Sketch + CompositeFeaturePtr aSketch = std::dynamic_pointer_cast(theFeature); + if (aSketch) + return createSketchEntity(aSketch, theGroupID); + + // SketchPlugin features + std::shared_ptr aFeature = + std::dynamic_pointer_cast(theFeature); + if (!aFeature) + return aDummy; + + // Verify the feature by its kind + const std::string& aFeatureKind = aFeature->getKind(); + // Line + if (aFeatureKind == SketchPlugin_Line::ID()) + return createLine(theFeature, theAttributes, theGroupID, theSketchID); + // Circle + else if (aFeatureKind == SketchPlugin_Circle::ID()) + return createCircle(theFeature, theAttributes,theGroupID, theSketchID); + // Arc + else if (aFeatureKind == SketchPlugin_Arc::ID()) + return createArc(theFeature, theAttributes,theGroupID, theSketchID); + // Point (it has low probability to be an attribute of constraint, so it is checked at the end) + else if (aFeatureKind == SketchPlugin_Point::ID()) { + AttributePtr aPoint = theFeature->attribute(SketchPlugin_Point::COORD_ID()); + if (!aPoint->isInitialized()) + return aDummy; + EntityWrapperPtr aSub = createAttribute(aPoint, theGroupID, theSketchID); + if (!aSub) + return aDummy; + + const Slvs_Entity& aSubEnt = + std::dynamic_pointer_cast(aSub)->entity(); + EntityWrapperPtr aNewEntity(new SolveSpaceSolver_EntityWrapper(theFeature, aSubEnt)); + aNewEntity->setSubEntities(std::list(1, aSub)); + return aNewEntity; + } + + // wrong entity + return aDummy; +} + +EntityWrapperPtr SolveSpaceSolver_Builder::createAttribute( + AttributePtr theAttribute, + const GroupID& theGroupID, + const EntityID& theSketchID) const +{ + AttributePtr anAttribute = theAttribute; + AttributeRefAttrPtr aRefAttr = + std::dynamic_pointer_cast(anAttribute); + if (aRefAttr) { + if (aRefAttr->isObject()) { + // do not create features here + return EntityWrapperPtr(); + } else + anAttribute = aRefAttr->attr(); + } + + std::list aParameters; + Slvs_Entity anEntity; + anEntity.type = 0; + + // Point in 3D + std::shared_ptr aPoint = + std::dynamic_pointer_cast(theAttribute); + if (aPoint) { + aParameters.push_back(createParameter(theGroupID, aPoint->x(), !aPoint->textX().empty())); + aParameters.push_back(createParameter(theGroupID, aPoint->y(), !aPoint->textY().empty())); + aParameters.push_back(createParameter(theGroupID, aPoint->z(), !aPoint->textZ().empty())); + // Create entity (parameters are not filled) + anEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, + SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); + } else { + // Point in 2D + std::shared_ptr aPoint2D = + std::dynamic_pointer_cast(theAttribute); + if (aPoint2D) { + aParameters.push_back(createParameter(theGroupID, aPoint2D->x(), !aPoint2D->textX().empty())); + aParameters.push_back(createParameter(theGroupID, aPoint2D->y(), !aPoint2D->textY().empty())); + // Create entity (parameters are not filled) + anEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, + (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); + } else { + // Scalar value (used for the distance entities) + AttributeDoublePtr aScalar = + std::dynamic_pointer_cast(theAttribute); + if (aScalar) { + aParameters.push_back(createParameter(theGroupID, aScalar->value(), !aScalar->text().empty())); + // Create entity (parameter is not filled) + anEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, + (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN); + } + } + } + + if (anEntity.type == 0) { + // unknown attribute type + return EntityWrapperPtr(); + } + + EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theAttribute, anEntity)); + aResult->setParameters(aParameters); + return aResult; +} + + + +EntityWrapperPtr SolveSpaceSolver_Builder::createSketchEntity( + CompositeFeaturePtr theSketch, + const GroupID& theGroupID) const +{ + DataPtr aSketchData = theSketch->data(); + if (!aSketchData || !aSketchData->isValid()) + return EntityWrapperPtr(); // the sketch is incorrect + + // Get parameters of workplane + AttributePtr aDirX = aSketchData->attribute(SketchPlugin_Sketch::DIRX_ID()); + AttributePtr aNorm = aSketchData->attribute(SketchPlugin_Sketch::NORM_ID()); + AttributePtr anOrigin = aSketchData->attribute(SketchPlugin_Sketch::ORIGIN_ID()); + if (!anOrigin->isInitialized() || !aNorm->isInitialized() || !aDirX->isInitialized()) + return EntityWrapperPtr(); + + EntityWrapperPtr aNewEnt; + std::list aSubs; + + // Create SolveSpace entity corresponding to the sketch origin + aNewEnt = createAttribute(anOrigin, theGroupID); + if (!aNewEnt) + return EntityWrapperPtr(); + aSubs.push_back(aNewEnt); + + // Create SolveSpace entity corresponding the the sketch normal + aNewEnt = createNormal(aNorm, aDirX, theGroupID); + if (!aNewEnt) + return EntityWrapperPtr(); + aSubs.push_back(aNewEnt); + + // Create workplane + Slvs_Entity aWorkplane = Slvs_MakeWorkplane(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, + SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); + + aNewEnt = EntityWrapperPtr( + new SolveSpaceSolver_EntityWrapper(FeaturePtr(theSketch), aWorkplane)); + aNewEnt->setSubEntities(aSubs); + return aNewEnt; +} + +EntityWrapperPtr SolveSpaceSolver_Builder::createNormal( + AttributePtr theNormal, + AttributePtr theDirX, + const GroupID& theGroupID) const +{ + std::shared_ptr aNorm = std::dynamic_pointer_cast(theNormal); + std::shared_ptr aDirX = std::dynamic_pointer_cast(theDirX); + if (!aDirX || !aNorm || + (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) || + !aNorm->isInitialized()) + return EntityWrapperPtr(); + // calculate Y direction + std::shared_ptr aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir()))); + + // quaternion parameters of normal vector + double qw, qx, qy, qz; + Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw, + &qx, &qy, &qz); + double aNormCoord[4] = { qw, qx, qy, qz }; + + // Create parameters of the normal + std::list aParameters; + for (int i = 0; i < 4; i++) + aParameters.push_back(createParameter(theGroupID, aNormCoord[i])); + + // Create a normal with empty parameters + Slvs_Entity aNormalEnt = Slvs_MakeNormal3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, + SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); + EntityWrapperPtr aNormal(new SolveSpaceSolver_EntityWrapper(theNormal, aNormalEnt)); + aNormal->setParameters(aParameters); + return aNormal; +} + +ParameterWrapperPtr SolveSpaceSolver_Builder::createParameter( + const GroupID& theGroup, const double theValue, const bool theExpr) const +{ + Slvs_Param aParam = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroup, theValue); + ParameterWrapperPtr aWrapper(new SolveSpaceSolver_ParameterWrapper(aParam)); + aWrapper->setIsParametric(theExpr); + return aWrapper; +} + + + + + +// ================ Auxiliary functions ========================== +EntityWrapperPtr createLine(FeaturePtr theFeature, + const std::list& theAttributes, + const GroupID& theGroupID, + const EntityID& theSketchID) +{ + EntityWrapperPtr aNewEntity; + std::list aSubs; + + AttributePtr aStart = theFeature->attribute(SketchPlugin_Line::START_ID()); + AttributePtr aEnd = theFeature->attribute(SketchPlugin_Line::END_ID()); + if (!aStart->isInitialized() || !aEnd->isInitialized()) + return aNewEntity; + + EntityWrapperPtr aStartEnt, aEndEnt; + std::list::const_iterator anIt = theAttributes.begin(); + for (; anIt != theAttributes.end(); ++anIt) { + std::shared_ptr aSlvsEntity = + std::dynamic_pointer_cast(*anIt); + if (aSlvsEntity->isBase(aStart)) + aStartEnt = aSlvsEntity; + else if (aSlvsEntity->isBase(aEnd)) + aEndEnt = aSlvsEntity; + } + if (!aStartEnt || !aEndEnt) + return aNewEntity; + + aSubs.push_back(aStartEnt); + aSubs.push_back(aEndEnt); + Slvs_Entity anEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, + (Slvs_hEntity)theSketchID, (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id()); + + aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity)); + aNewEntity->setSubEntities(aSubs); + return aNewEntity; +} + +EntityWrapperPtr createCircle(FeaturePtr theFeature, + const std::list& theAttributes, + const GroupID& theGroupID, + const EntityID& theSketchID) +{ + EntityWrapperPtr aNewEntity; + std::list aSubs; + + AttributePtr aCenter = theFeature->attribute(SketchPlugin_Circle::CENTER_ID()); + AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID()); + if (!aCenter->isInitialized() || !aRadius->isInitialized()) + return aNewEntity; + + EntityWrapperPtr aCenterEnt, aRadiusEnt, aNormalEnt; + std::list::const_iterator anIt = theAttributes.begin(); + for (; anIt != theAttributes.end(); ++anIt) { + std::shared_ptr aSlvsEntity = + std::dynamic_pointer_cast(*anIt); + if (aSlvsEntity->isBase(aCenter)) + aCenterEnt = aSlvsEntity; + else if (aSlvsEntity->isBase(aRadius)) + aRadiusEnt = aSlvsEntity; + else if (aSlvsEntity->type() == ENTITY_NORMAL) + aNormalEnt = aSlvsEntity; + } + if (!aCenterEnt || !aRadiusEnt || !aNormalEnt) + return aNewEntity; + + aSubs.push_back(aCenterEnt); + aSubs.push_back(aRadiusEnt); + Slvs_Entity anEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, + (Slvs_hEntity)theSketchID, (Slvs_hEntity)aCenterEnt->id(), + (Slvs_hEntity)aNormalEnt->id(), (Slvs_hEntity)aRadiusEnt->id()); + + aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity)); + aNewEntity->setSubEntities(aSubs); + return aNewEntity; +} + +EntityWrapperPtr createArc(FeaturePtr theFeature, + const std::list& theAttributes, + const GroupID& theGroupID, + const EntityID& theSketchID) +{ + EntityWrapperPtr aNewEntity; + std::list aSubs; + + AttributePtr aCenter = theFeature->attribute(SketchPlugin_Arc::CENTER_ID()); + AttributePtr aStart = theFeature->attribute(SketchPlugin_Arc::START_ID()); + AttributePtr aEnd = theFeature->attribute(SketchPlugin_Arc::END_ID()); + if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized()) + return aNewEntity; + + EntityWrapperPtr aCenterEnt, aStartEnt, aEndEnt, aNormalEnt; + std::list::const_iterator anIt = theAttributes.begin(); + for (; anIt != theAttributes.end(); ++anIt) { + std::shared_ptr aSlvsEntity = + std::dynamic_pointer_cast(*anIt); + if (aSlvsEntity->isBase(aCenter)) + aCenterEnt = aSlvsEntity; + else if (aSlvsEntity->isBase(aStart)) + aStartEnt = aSlvsEntity; + else if (aSlvsEntity->isBase(aEnd)) + aEndEnt = aSlvsEntity; + else if (aSlvsEntity->type() == ENTITY_NORMAL) + aNormalEnt = aSlvsEntity; + } + if (!aCenterEnt || !aStartEnt || !aEndEnt || !aNormalEnt) + return aNewEntity; + + aSubs.push_back(aCenterEnt); + aSubs.push_back(aStartEnt); + aSubs.push_back(aEndEnt); + Slvs_Entity anEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, + (Slvs_hEntity)theSketchID, (Slvs_hEntity)aNormalEnt->id(), + (Slvs_hEntity)aCenterEnt->id(), (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id()); + + aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity)); + aNewEntity->setSubEntities(aSubs); + return aNewEntity; +} + + +void adjustTangency(ConstraintWrapperPtr theConstraint) +{ + BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance(); + + std::shared_ptr aConstraint = + std::dynamic_pointer_cast(theConstraint); + + // Collect start, end points of entities + std::shared_ptr aStartEntPoints[2][2]; + bool isCoinc[2][2] = {false}; + const std::list& aSubs = aConstraint->entities(); + std::list::const_iterator aSIt = aSubs.begin(); + for (int i = 0; aSIt != aSubs.end(); ++aSIt, ++i) { + const std::list& aPoints = (*aSIt)->subEntities(); + std::list::const_iterator aPIt = aPoints.begin(); + if ((*aSIt)->type() == ENTITY_ARC) + ++aPIt; + for (int j = 0; aPIt != aPoints.end(); ++aPIt, ++j) { + aStartEntPoints[i][j] = aBuilder->point(*aPIt); + if (i > 0) { // check coincidence + for (int k = 0; k < 2; ++k) + if (aStartEntPoints[i][j]->distance(aStartEntPoints[0][k]) < tolerance) + isCoinc[0][k] = isCoinc[i][j] = true; + } + } + } + + Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint(); + if (isCoinc[0][0] == false && isCoinc[0][1] == true) + aSlvsConstraint.other = 1; + else aSlvsConstraint.other = 0; + if (isCoinc[1][0] == false && isCoinc[1][1] == true) + aSlvsConstraint.other2 = 1; + else aSlvsConstraint.other2 = 0; +} + +void adjustAngle(ConstraintWrapperPtr theConstraint) +{ + BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance(); + + std::shared_ptr aConstraint = + std::dynamic_pointer_cast(theConstraint); + + std::shared_ptr aPoints[2][2]; // start and end points of lines + const std::list& aConstrLines = aConstraint->entities(); + std::list::const_iterator aCLIt = aConstrLines.begin(); + for (int i = 0; aCLIt != aConstrLines.end(); ++i, ++aCLIt) { + const std::list& aLinePoints = (*aCLIt)->subEntities(); + std::list::const_iterator aLPIt = aLinePoints.begin(); + for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt) + aPoints[i][j] = aBuilder->point(*aLPIt); + } + + std::shared_ptr aLine[2] = { + std::shared_ptr(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])), + std::shared_ptr(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1])) + }; + std::shared_ptr anIntersection = aLine[0]->intersect(aLine[1]); + if (!anIntersection) + return; + double aDist[2][2]; + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + aDist[i][j] = anIntersection->distance(aPoints[i][j]); + if (fabs(aDist[i][j]) <= tolerance) + aDist[i][j] = 0.0; + } + if (aDist[i][0] > tolerance && aDist[i][1] > tolerance && + aDist[i][0] + aDist[i][1] < aPoints[i][0]->distance(aPoints[i][1]) + 2.0 * tolerance) { + // the intersection point is an inner point of the line, + // we change the sign of distance till start point to calculate correct coordinates + // after rotation + aDist[i][0] *= -1.0; + } + } + std::shared_ptr aDir[2]; + for (int i = 0; i < 2; i++) { + if (aDist[i][1] > fabs(aDist[i][0])) + aDir[i] = std::shared_ptr(new GeomAPI_Dir2d( + aPoints[i][1]->xy()->decreased(anIntersection->xy()))); + else { + aDir[i] = std::shared_ptr(new GeomAPI_Dir2d( + aPoints[i][0]->xy()->decreased(anIntersection->xy()))); + // main direction is opposite => change signs + if (aDist[i][0] < 0.0) { + aDist[i][0] *= -1.0; + aDist[i][1] *= -1.0; + } + } + } + + Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint(); + aSlvsConstraint.other = false; + for (int i = 0; i < 2; i++) + if (aLine[i]->direction()->dot(aDir[i]) < 0.0) + aSlvsConstraint.other = !aSlvsConstraint.other; +} + +void adjustMirror(ConstraintWrapperPtr theConstraint) +{ + std::vector aPoints; + EntityWrapperPtr aMirrorLine; + + const std::list& aSubs = theConstraint->entities(); + std::list::const_iterator anIt = aSubs.begin(); + for (; anIt != aSubs.end(); ++anIt) { + if ((*anIt)->type() == ENTITY_POINT) + aPoints.push_back(*anIt); + else if ((*anIt)->type() == ENTITY_LINE) + aMirrorLine = *anIt; + } + + makeMirrorPoints(aPoints[0], aPoints[1], aMirrorLine); +} + +void makeMirrorPoints(EntityWrapperPtr theOriginal, + EntityWrapperPtr theMirrored, + EntityWrapperPtr theMirrorLine) +{ + BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance(); + + std::shared_ptr aMirrorLine = aBuilder->line(theMirrorLine); + std::shared_ptr aMLDir = aMirrorLine->direction(); + // orthogonal direction + aMLDir = std::shared_ptr(new GeomAPI_Dir2d(aMLDir->y(), -aMLDir->x())); + + std::shared_ptr aPoint = aBuilder->point(theOriginal); + std::shared_ptr aVec = aPoint->xy()->decreased(aMirrorLine->location()->xy()); + double aDist = aVec->dot(aMLDir->xy()); + aVec = aPoint->xy()->added(aMLDir->xy()->multiplied(-2.0 * aDist)); + double aCoord[2] = {aVec->x(), aVec->y()}; + std::list::const_iterator aMIt = theMirrored->parameters().begin(); + for (int i = 0; aMIt != theMirrored->parameters().end(); ++aMIt, ++i) + (*aMIt)->setValue(aCoord[i]); + + // update corresponding attribute + AttributePtr anAttr = std::dynamic_pointer_cast(theMirrored)->baseAttribute(); + if (anAttr) { + std::shared_ptr aMirroredPnt = std::dynamic_pointer_cast(anAttr); + aMirroredPnt->setValue(aCoord[0], aCoord[1]); + } +} + +static void rotate(EntityWrapperPtr theSource, EntityWrapperPtr theDest, + std::shared_ptr theCenter, + double theSin, double theCos) +{ + std::shared_ptr aSource = + std::dynamic_pointer_cast(theSource); + std::shared_ptr aDest = + std::dynamic_pointer_cast(theDest); + + if (theSource->type() == ENTITY_POINT) { + // Rotate single point + std::shared_ptr aSrcAttr = + std::dynamic_pointer_cast(aSource->baseAttribute()); + std::shared_ptr aDstAttr = + std::dynamic_pointer_cast(aDest->baseAttribute()); + if (aSrcAttr && aDstAttr) { + std::shared_ptr aVec = aSrcAttr->pnt()->xy()->decreased(theCenter->xy()); + double aNewX = aVec->x() * theCos - aVec->y() * theSin; + double aNewY = aVec->x() * theSin + aVec->y() * theCos; + aDstAttr->setValue(theCenter->x() + aNewX, theCenter->y() + aNewY); + } + return; + } + + FeaturePtr aDestFeature = aDest->baseFeature(); + if (aDestFeature) + aDestFeature->data()->blockSendAttributeUpdated(true); + + // Rotate points of the feature + const std::list& aSrcSubs = theSource->subEntities(); + const std::list& aDstSubs = theDest->subEntities(); + std::list::const_iterator aSrcIt, aDstIt; + for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin(); + aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt) + rotate(*aSrcIt, *aDstIt, theCenter, theSin, theCos); + + if (aDestFeature) + aDestFeature->data()->blockSendAttributeUpdated(false); +} + +static void translate(EntityWrapperPtr theSource, EntityWrapperPtr theDest, + std::shared_ptr theDelta) +{ + std::shared_ptr aSource = + std::dynamic_pointer_cast(theSource); + std::shared_ptr aDest = + std::dynamic_pointer_cast(theDest); + + if (theSource->type() == ENTITY_POINT) { + // Translate single point + std::shared_ptr aSrcAttr = + std::dynamic_pointer_cast(aSource->baseAttribute()); + std::shared_ptr aDstAttr = + std::dynamic_pointer_cast(aDest->baseAttribute()); + if (aSrcAttr && aDstAttr) + aDstAttr->setValue(aSrcAttr->x() + theDelta->x(), aSrcAttr->y() + theDelta->y()); + return; + } + + FeaturePtr aDestFeature = aDest->baseFeature(); + if (aDestFeature) + aDestFeature->data()->blockSendAttributeUpdated(true); + + // Translate points of the feature + const std::list& aSrcSubs = theSource->subEntities(); + const std::list& aDstSubs = theDest->subEntities(); + std::list::const_iterator aSrcIt, aDstIt; + for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin(); + aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt) + translate(*aSrcIt, *aDstIt, theDelta); + + if (aDestFeature) + aDestFeature->data()->blockSendAttributeUpdated(false); +} + +void adjustMultiRotation(ConstraintWrapperPtr theConstraint) +{ + BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance(); + + double anAngleRad = theConstraint->value() * PI / 180.0; + double aSin = sin(anAngleRad); + double aCos = cos(anAngleRad); + + const std::list& aSubs = theConstraint->entities(); + std::list::const_iterator aSIt = aSubs.begin(); + + std::shared_ptr aCenter = aBuilder->point(*aSIt++); + std::list::const_iterator aPrevIt = aSIt++; + for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt) + rotate(*aPrevIt, *aSIt, aCenter, aSin, aCos); +} + +void adjustMultiTranslation(ConstraintWrapperPtr theConstraint) +{ + BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance(); + + const std::list& aSubs = theConstraint->entities(); + std::list::const_iterator aSIt = aSubs.begin(); + + std::shared_ptr aStartPnt = aBuilder->point(*aSIt++); + std::shared_ptr aEndPnt = aBuilder->point(*aSIt++); + std::shared_ptr aDelta = aEndPnt->xy()->decreased(aStartPnt->xy()); + + std::list::const_iterator aPrevIt = aSIt++; + for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt) + translate(*aPrevIt, *aSIt, aDelta); +} diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.h b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.h new file mode 100644 index 000000000..f55330ad2 --- /dev/null +++ b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.h @@ -0,0 +1,140 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SolveSpaceSolver_Builder.h +// Created: 25 Mar 2015 +// Author: Artem ZHIDKOV + +#ifndef SolveSpaceSolver_Builder_H_ +#define SolveSpaceSolver_Builder_H_ + +#include +#include + +#include + +#include + +/** \class SolveSpaceSolver_Builder + * \ingroup Plugins + * \brief Create bridges between SketchPlugin constraints and SolveSpace constraints + */ +class SolveSpaceSolver_Builder : public SketchSolver_Builder +{ +private: + /// Default constructor + SolveSpaceSolver_Builder() {} + +public: + /// \brief Returns single instance of builder + static BuilderPtr getInstance(); + + /// \brief Creates a storage specific for used solver + virtual StoragePtr createStorage(const GroupID& theGroup) const; + /// \brief Creates specific solver + virtual SolverPtr createSolver() const; + + /// \brief Creates new constraint(s) using given parameters + /// \param theConstraint [in] original constraint + /// \param theGroupID [in] group the constraint belongs to + /// \param theSketchID [in] sketch the constraint belongs to + /// \param theType [in] type of constraint + /// \param theValue [in] numeric characteristic of constraint (e.g. distance or radius) if applicable + /// \param theEntity1 [in] first attribute of constraint + /// \param theEntity2 [in] second attribute of constraint + /// \param theEntity3 [in] third attribute of constraint + /// \param theEntity4 [in] fourth attribute of constraint + /// \return Created list of wrappers of constraints applicable for specific solver. + /// Most of constraint types lead to single constraint, but there are some kind of + /// constraints (e.g. mirror), which may produce couple of constraints. + virtual std::list + createConstraint(ConstraintPtr theConstraint, + const GroupID& theGroupID, + const EntityID& theSketchID, + const SketchSolver_ConstraintType& theType, + const double& theValue, + const EntityWrapperPtr& theEntity1, + const EntityWrapperPtr& theEntity2 = EntityWrapperPtr(), + const EntityWrapperPtr& theEntity3 = EntityWrapperPtr(), + const EntityWrapperPtr& theEntity4 = EntityWrapperPtr()) const; + + /// \brief Creates new multi-translation or multi-rotation constraint + /// \param theConstraint [in] original constraint + /// \param theGroupID [in] group the constraint belongs to + /// \param theSketchID [in] sketch the constraint belongs to + /// \param theType [in] type of constraint + /// \param theValue [in] numeric characteristic of constraint (angle for multi-rotation) if applicable + /// \param thePoint1 [in] center for multi-rotation or start point for multi-translation + /// \param thePoint2 [in] end point for multi-translation (empty for multi-rotation) + /// \param theTrsfEnt [in] list of transformed entities + virtual std::list + createConstraint(ConstraintPtr theConstraint, + const GroupID& theGroupID, + const EntityID& theSketchID, + const SketchSolver_ConstraintType& theType, + const double& theValue, + const EntityWrapperPtr& thePoint1, + const EntityWrapperPtr& thePoint2, + const std::list& theTrsfEnt) const; + + /// \brief Update flags for several kinds of constraints + virtual void adjustConstraint(ConstraintWrapperPtr theConstraint) const; + + /// \brief Creates a feature using list of already created attributes + /// \param theFeature [in] feature to create + /// \param theAttributes [in] attributes of the feature + /// \param theGroupID [in] group the feature belongs to + /// \param theSketchID [in] sketch the feature belongs to + /// \return Created wrapper of the feature applicable for specific solver + virtual EntityWrapperPtr createFeature(FeaturePtr theFeature, + const std::list& theAttributes, + const GroupID& theGroupID, + const EntityID& theSketchID = EID_UNKNOWN) const; + + /// \brief Creates an attribute + /// \param theAttribute [in] attribute to create + /// \param theGroup [in] group the attribute belongs to + /// \param theSketchID [in] sketch the attribute belongs to + /// \return Created wrapper of the attribute applicable for specific solver + virtual EntityWrapperPtr createAttribute(AttributePtr theAttribute, + const GroupID& theGroup, + const EntityID& theSketchID = EID_UNKNOWN) const; + +private: + /// \brief Create necessary constraints to make two object symmetric relatively a given line + std::list createMirror(ConstraintPtr theConstraint, + const GroupID& theGroupID, + const EntityID& theSketchID, + const EntityWrapperPtr& theEntity1, + const EntityWrapperPtr& theEntity2, + const EntityWrapperPtr& theMirrorLine) const; + + /// \brief Converts sketch parameters to the entity applicable for the solver. + /// \param theSketch [in] the element to be converted + /// \param theGroupID [in] group where the sketch should be created + /// \return Entity respective the sketch or empty pointer, it the sketch has incorrect attributes + EntityWrapperPtr createSketchEntity(CompositeFeaturePtr theSketch, + const GroupID& theGroupID) const; + + /// \brief Converts two axes of sketch's trihedron to the normal entity + /// \param theNormal [in] direction of the normal of the sketch + /// \param theDirX [in] direction of the X axis of the sketch + /// \param theGroupID [in] group, the normal belongs to + /// \return Created entity or empty pointer, if there are incorrect attributes + EntityWrapperPtr createNormal(AttributePtr theNormal, + AttributePtr theDirX, + const GroupID& theGroupID) const; + + /// \brief Converts a value to SolveSpace parameter + /// \param theGroup [in] group to store parameter + /// \param theValue [in] value of parameter + /// \param theExpr [in] shows the parameter is given by expression + /// \return Created parameter's wrapper + ParameterWrapperPtr createParameter(const GroupID& theGroup, + const double theValue = 0.0, + const bool theExpr = false) const; + +private: + static BuilderPtr mySelf; +}; + +#endif diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintType.h b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintType.h new file mode 100644 index 000000000..a38939bd4 --- /dev/null +++ b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintType.h @@ -0,0 +1,75 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SolveSpaceSolver_ConstraintType.h +// Created: 8 Dec 2015 +// Author: Artem ZHIDKOV + +#ifndef SolveSpaceSolver_ConstraintType_H_ +#define SolveSpaceSolver_ConstraintType_H_ + +#include +#include + +namespace ConstraintType +{ + /// \brief Convert constraint type from SketchSolver to SolveSpace + static int toSolveSpace(SketchSolver_ConstraintType theType) + { + switch (theType) { + case CONSTRAINT_PT_PT_COINCIDENT: return SLVS_C_POINTS_COINCIDENT; + case CONSTRAINT_PT_ON_LINE: return SLVS_C_PT_ON_LINE; + case CONSTRAINT_PT_ON_CIRCLE: return SLVS_C_PT_ON_CIRCLE; + case CONSTRAINT_PT_PT_DISTANCE: return SLVS_C_PT_PT_DISTANCE; + case CONSTRAINT_PT_LINE_DISTANCE: return SLVS_C_PT_LINE_DISTANCE; + case CONSTRAINT_ANGLE: return SLVS_C_ANGLE; + case CONSTRAINT_RADIUS: return SLVS_C_DIAMETER; + case CONSTRAINT_FIXED: return SLVS_C_WHERE_DRAGGED; + case CONSTRAINT_HORIZONTAL: return SLVS_C_HORIZONTAL; + case CONSTRAINT_VERTICAL: return SLVS_C_VERTICAL; + case CONSTRAINT_PARALLEL: return SLVS_C_PARALLEL; + case CONSTRAINT_PERPENDICULAR: return SLVS_C_PERPENDICULAR; + case CONSTRAINT_SYMMETRIC: return SLVS_C_SYMMETRIC_LINE; + case CONSTRAINT_EQUAL_LINES: return SLVS_C_EQUAL_LENGTH_LINES; + case CONSTRAINT_EQUAL_LINE_ARC: return SLVS_C_EQUAL_LINE_ARC_LEN; + case CONSTRAINT_EQUAL_RADIUS: return SLVS_C_EQUAL_RADIUS; + case CONSTRAINT_TANGENT_ARC_LINE: return SLVS_C_ARC_LINE_TANGENT; + case CONSTRAINT_TANGENT_ARC_ARC: return SLVS_C_CURVE_CURVE_TANGENT; + case CONSTRAINT_MULTI_ROTATION: return SLVS_C_MULTI_ROTATION; + case CONSTRAINT_MULTI_TRANSLATION: return SLVS_C_MULTI_TRANSLATION; + default: break; + } + return SLVS_C_UNKNOWN; + } + + /// \brief Convert constraint type from SolveSpace to SketchSolver + static SketchSolver_ConstraintType fromSolveSpace(int theType) + { + switch (theType) { + case SLVS_C_POINTS_COINCIDENT: return CONSTRAINT_PT_PT_COINCIDENT; + case SLVS_C_PT_ON_LINE: return CONSTRAINT_PT_ON_LINE; + case SLVS_C_PT_ON_CIRCLE: return CONSTRAINT_PT_ON_CIRCLE; + case SLVS_C_PT_PT_DISTANCE: return CONSTRAINT_PT_PT_DISTANCE; + case SLVS_C_PT_LINE_DISTANCE: return CONSTRAINT_PT_LINE_DISTANCE; + case SLVS_C_EQUAL_LENGTH_LINES: return CONSTRAINT_EQUAL_LINES; + case SLVS_C_EQUAL_LINE_ARC_LEN: return CONSTRAINT_EQUAL_LINE_ARC; + case SLVS_C_SYMMETRIC_LINE: return CONSTRAINT_SYMMETRIC; + case SLVS_C_HORIZONTAL: return CONSTRAINT_HORIZONTAL; + case SLVS_C_VERTICAL: return CONSTRAINT_VERTICAL; + case SLVS_C_DIAMETER: return CONSTRAINT_RADIUS; + case SLVS_C_ANGLE: return CONSTRAINT_ANGLE; + case SLVS_C_PARALLEL: return CONSTRAINT_PARALLEL; + case SLVS_C_PERPENDICULAR: return CONSTRAINT_PERPENDICULAR; + case SLVS_C_ARC_LINE_TANGENT: return CONSTRAINT_TANGENT_ARC_LINE; + case SLVS_C_EQUAL_RADIUS: return CONSTRAINT_EQUAL_RADIUS; + case SLVS_C_WHERE_DRAGGED: return CONSTRAINT_FIXED; + case SLVS_C_CURVE_CURVE_TANGENT: return CONSTRAINT_TANGENT_ARC_ARC; + case SLVS_C_MULTI_ROTATION: return CONSTRAINT_MULTI_ROTATION; + case SLVS_C_MULTI_TRANSLATION: return CONSTRAINT_MULTI_TRANSLATION; + default: break; + } + return CONSTRAINT_UNKNOWN; + } +} + + +#endif diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintWrapper.cpp b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintWrapper.cpp new file mode 100644 index 000000000..8419b9a2e --- /dev/null +++ b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintWrapper.cpp @@ -0,0 +1,117 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SolveSpaceSolver_ConstraintWrapper.cpp +// Created: 2 Dec 2015 +// Author: Artem ZHIDKOV + +#include +#include +#include + +SolveSpaceSolver_ConstraintWrapper::SolveSpaceSolver_ConstraintWrapper( + const ConstraintPtr& theOriginal, + const Slvs_Constraint& theConstraint) + : mySlvsConstraint(theConstraint) +{ + myBaseConstraint = theOriginal; + myValue = mySlvsConstraint.valA; +} + +ConstraintID SolveSpaceSolver_ConstraintWrapper::id() const +{ + return (ConstraintID)mySlvsConstraint.h; +} + +void SolveSpaceSolver_ConstraintWrapper::setGroup(const GroupID& theGroup) +{ + mySlvsConstraint.group = (Slvs_hGroup)theGroup; + std::list::iterator aSubsIt = myConstrained.begin(); + for (; aSubsIt != myConstrained.end(); ++aSubsIt) + (*aSubsIt)->setGroup(theGroup); +} + +SketchSolver_ConstraintType SolveSpaceSolver_ConstraintWrapper::type() const +{ + return ConstraintType::fromSolveSpace(mySlvsConstraint.type); +} + +void SolveSpaceSolver_ConstraintWrapper::setValue(const double& theValue) +{ + double aValue = theValue; + if (type() == CONSTRAINT_RADIUS) + aValue *= 2.0; // NOTE: SolveSpace uses constraint DIAMETER + + SketchSolver_IConstraintWrapper::setValue(aValue); +} + +bool SolveSpaceSolver_ConstraintWrapper::isUsed(FeaturePtr theFeature) const +{ + std::list::const_iterator anIt = myConstrained.begin(); + for (; anIt != myConstrained.end(); ++anIt) + if ((*anIt)->isUsed(theFeature)) + return true; + return false; +} + +bool SolveSpaceSolver_ConstraintWrapper::isUsed(AttributePtr theAttribute) const +{ + std::list::const_iterator anIt = myConstrained.begin(); + for (; anIt != myConstrained.end(); ++anIt) + if ((*anIt)->isUsed(theAttribute)) + return true; + return false; +} + +bool SolveSpaceSolver_ConstraintWrapper::isEqual(const ConstraintWrapperPtr& theOther) +{ + const Slvs_Constraint anOtherConstraint = + std::dynamic_pointer_cast(theOther)->constraint(); + if (mySlvsConstraint.type != anOtherConstraint.type) + return false; + + // Verify SolveSpace entities. If they are equal, no need additional checking of parameters. + if (mySlvsConstraint.group == anOtherConstraint.group && + mySlvsConstraint.ptA == anOtherConstraint.ptA && + mySlvsConstraint.ptB == anOtherConstraint.ptB && + mySlvsConstraint.entityA == anOtherConstraint.entityA && + mySlvsConstraint.entityB == anOtherConstraint.entityB && + mySlvsConstraint.entityC == anOtherConstraint.entityC && + mySlvsConstraint.entityD == anOtherConstraint.entityD && + fabs(mySlvsConstraint.valA - anOtherConstraint.valA) < tolerance) { + return true; + } + + // Verify equality of values + if (fabs(myValue - theOther->value()) > tolerance) + return false; + + // Verify equality of entities + const std::list& anOtherSubs = theOther->entities(); + if (myConstrained.size() != anOtherSubs.size()) + return false; + std::list::const_iterator aMySubsIt = myConstrained.begin(); + std::list::const_iterator anOtherSubsIt = anOtherSubs.begin(); + for (; aMySubsIt != myConstrained.end(); ++aMySubsIt, ++anOtherSubsIt) + if (!(*aMySubsIt)->isEqual(*anOtherSubsIt)) + return false; + return true; +} + +bool SolveSpaceSolver_ConstraintWrapper::update(const ConstraintWrapperPtr& theOther) +{ + bool isUpdated = false; + + std::list aMySubs = entities(); + std::list anOtherSubs = theOther->entities(); + std::list::const_iterator aMySubsIt = aMySubs.begin(); + std::list::const_iterator anOtherSubsIt = anOtherSubs.begin(); + for (; aMySubsIt != aMySubs.end() && anOtherSubsIt != anOtherSubs.end(); + ++aMySubsIt, ++anOtherSubsIt) + isUpdated = (*aMySubsIt)->update(*anOtherSubsIt) || isUpdated; + + if (fabs(value() - theOther->value()) > tolerance) { + myValue = theOther->value(); + isUpdated = true; + } + return isUpdated; +} diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintWrapper.h b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintWrapper.h new file mode 100644 index 000000000..b7ff49992 --- /dev/null +++ b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintWrapper.h @@ -0,0 +1,61 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SolveSpaceSolver_ConstraintWrapper.h +// Created: 2 Dec 2015 +// Author: Artem ZHIDKOV + +#ifndef SolveSpaceSolver_ConstraintWrapper_H_ +#define SolveSpaceSolver_ConstraintWrapper_H_ + +#include +#include + + +/** + * Wrapper providing operations with SovleSpace constraints. + */ +class SolveSpaceSolver_ConstraintWrapper : public SketchSolver_IConstraintWrapper +{ +public: + SolveSpaceSolver_ConstraintWrapper(const ConstraintPtr& theOriginal, + const Slvs_Constraint& theConstraint); + + /// \brief Return SolveSpace constraint + const Slvs_Constraint& constraint() const + { return mySlvsConstraint; } + /// \brief Return SolveSpace constraint to change + Slvs_Constraint& changeConstraint() + { return mySlvsConstraint; } + + /// \brief Return ID of current entity + virtual ConstraintID id() const; + + /// \brief Change group for the constraint + virtual void setGroup(const GroupID& theGroup); + /// \brief Return identifier of the group the constraint belongs to + virtual GroupID group() const + { return (GroupID)mySlvsConstraint.group; } + + /// \brief Return type of current entity + virtual SketchSolver_ConstraintType type() const; + + /// \brief Assign numeric parameter of constraint + virtual void setValue(const double& theValue); + + /// \brief Verify the feature is used in the constraint + virtual bool isUsed(FeaturePtr theFeature) const; + /// \brief Verify the attribute is used in the constraint + virtual bool isUsed(AttributePtr theAttribute) const; + + /// \brief Compare current constraint with other + virtual bool isEqual(const ConstraintWrapperPtr& theOther); + + /// \brief Update values of parameters of this constraint by the parameters of given one + /// \return \c true if some parameters change their values + virtual bool update(const std::shared_ptr& theOther); + +private: + Slvs_Constraint mySlvsConstraint; +}; + +#endif diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_EntityWrapper.cpp b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_EntityWrapper.cpp new file mode 100644 index 000000000..1cb81157d --- /dev/null +++ b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_EntityWrapper.cpp @@ -0,0 +1,127 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SolveSpaceSolver_EntityWrapper.cpp +// Created: 2 Dec 2015 +// Author: Artem ZHIDKOV + +#include + +SolveSpaceSolver_EntityWrapper::SolveSpaceSolver_EntityWrapper( + const FeaturePtr theFeature, const Slvs_Entity& theEntity) + : myEntity(theEntity) +{ + myBaseFeature = theFeature; +} + +SolveSpaceSolver_EntityWrapper::SolveSpaceSolver_EntityWrapper( + const AttributePtr theAttribute, const Slvs_Entity& theEntity) + : myEntity(theEntity) +{ + myBaseAttribute = theAttribute; +} + +EntityID SolveSpaceSolver_EntityWrapper::id() const +{ + return (EntityID)myEntity.h; +} + +void SolveSpaceSolver_EntityWrapper::setGroup(const GroupID& theGroup) +{ + myEntity.group = (Slvs_hGroup)theGroup; + std::list::iterator aSubsIt = mySubEntities.begin(); + for (; aSubsIt != mySubEntities.end(); ++aSubsIt) + (*aSubsIt)->setGroup(theGroup); + std::list::iterator aPIt = myParameters.begin(); + for (; aPIt != myParameters.end(); ++aPIt) + (*aPIt)->setGroup(theGroup); +} + +SketchSolver_EntityType SolveSpaceSolver_EntityWrapper::type() const +{ + switch (myEntity.type) { + case SLVS_E_POINT_IN_3D: + case SLVS_E_POINT_IN_2D: return ENTITY_POINT; + case SLVS_E_LINE_SEGMENT: return ENTITY_LINE; + case SLVS_E_CIRCLE: return ENTITY_CIRCLE; + case SLVS_E_ARC_OF_CIRCLE: return ENTITY_ARC; + case SLVS_E_NORMAL_IN_3D: + case SLVS_E_NORMAL_IN_2D: return ENTITY_NORMAL; + case SLVS_E_DISTANCE: return ENTITY_SCALAR; + case SLVS_E_WORKPLANE: return ENTITY_SKETCH; + default: break; + } + return ENTITY_UNKNOWN; +} + +bool SolveSpaceSolver_EntityWrapper::isUsed(FeaturePtr theFeature) const +{ + if (isBase(theFeature)) + return true; + + std::list::const_iterator anIt = mySubEntities.begin(); + for (; anIt != mySubEntities.end(); ++anIt) + if ((*anIt)->isUsed(theFeature)) + return true; + return false; +} + +bool SolveSpaceSolver_EntityWrapper::isUsed(AttributePtr theAttribute) const +{ + if (isBase(theAttribute)) + return true; + + std::list::const_iterator anIt = mySubEntities.begin(); + for (; anIt != mySubEntities.end(); ++anIt) + if ((*anIt)->isUsed(theAttribute)) + return true; + return false; +} + +bool SolveSpaceSolver_EntityWrapper::isEqual(const EntityWrapperPtr& theOther) +{ + if (type() != theOther->type()) + return false; + + // Verify Equality of sub-entities + const std::list& anOtherSubs = theOther->subEntities(); + if (mySubEntities.size() != anOtherSubs.size()) + return false; + std::list::const_iterator aMySubsIt = mySubEntities.begin(); + std::list::const_iterator anOtherSubsIt = anOtherSubs.begin(); + for (; aMySubsIt != mySubEntities.end(); ++aMySubsIt, ++anOtherSubsIt) + if (!(*aMySubsIt)->isEqual(*anOtherSubsIt)) + return false; + + // Verify equality of parameters + const std::list& anOtherParams = theOther->parameters(); + if (myParameters.size() != anOtherParams.size()) + return false; + std::list::const_iterator aMyIt = myParameters.begin(); + std::list::const_iterator anOtherIt = anOtherParams.begin(); + for (; aMyIt != myParameters.end(); ++aMyIt, ++anOtherIt) + if (!(*aMyIt)->isEqual(*anOtherIt)) + return false; + return true; +} + +bool SolveSpaceSolver_EntityWrapper::update(const EntityWrapperPtr& theOther) +{ + bool isUpdated = false; + + std::list aMySubs = subEntities(); + std::list anOtherSubs = theOther->subEntities(); + std::list::const_iterator aMySubsIt = aMySubs.begin(); + std::list::const_iterator anOtherSubsIt = anOtherSubs.begin(); + for (; aMySubsIt != aMySubs.end() && anOtherSubsIt != anOtherSubs.end(); + ++aMySubsIt, ++anOtherSubsIt) + isUpdated = (*aMySubsIt)->update(*anOtherSubsIt) || isUpdated; + + std::list aMyParams = parameters(); + std::list anOtherParams = theOther->parameters(); + std::list::const_iterator aMyParIt = aMyParams.begin(); + std::list::const_iterator anOtherParIt = anOtherParams.begin(); + for (; aMyParIt != aMyParams.end() && anOtherParIt != anOtherParams.end(); + ++aMyParIt, ++anOtherParIt) + isUpdated = (*aMyParIt)->update(*anOtherParIt); + return isUpdated; +} diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_EntityWrapper.h b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_EntityWrapper.h new file mode 100644 index 000000000..566625f91 --- /dev/null +++ b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_EntityWrapper.h @@ -0,0 +1,57 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SolveSpaceSolver_EntityWrapper.h +// Created: 2 Dec 2015 +// Author: Artem ZHIDKOV + +#ifndef SolveSpaceSolver_EntityWrapper_H_ +#define SolveSpaceSolver_EntityWrapper_H_ + +#include +#include + +/** + * Wrapper providing operations with SolveSpace entities. + */ +class SolveSpaceSolver_EntityWrapper : public SketchSolver_IEntityWrapper +{ +public: + SolveSpaceSolver_EntityWrapper(const FeaturePtr theFeature, const Slvs_Entity& theEntity); + SolveSpaceSolver_EntityWrapper(const AttributePtr theAttribute, const Slvs_Entity& theEntity); + + /// \brief Return SolveSpace entity + const Slvs_Entity& entity() const + { return myEntity; } + /// \brief Return SolveSpace entity to change + Slvs_Entity& changeEntity() + { return myEntity; } + + /// \brief Return ID of current entity + virtual EntityID id() const; + + /// \brief Change group for the entity + virtual void setGroup(const GroupID& theGroup); + /// \brief Return identifier of the group the entity belongs to + virtual GroupID group() const + { return (GroupID)myEntity.group; } + + /// \brief Return type of current entity + virtual SketchSolver_EntityType type() const; + + /// \brief Verify the feature is used in the entity + virtual bool isUsed(FeaturePtr theFeature) const; + /// \brief Verify the attribute is used in the entity + virtual bool isUsed(AttributePtr theAttribute) const; + + /// \brief Compare current entity with other + virtual bool isEqual(const EntityWrapperPtr& theOther); + + /// \brief Update values of parameters of this entity by the parameters of given one + /// \return \c true if some parameters change their values + virtual bool update(const std::shared_ptr& theOther); + +private: + Slvs_Entity myEntity; +}; + +#endif diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ParameterWrapper.cpp b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ParameterWrapper.cpp new file mode 100644 index 000000000..1f2c7d451 --- /dev/null +++ b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ParameterWrapper.cpp @@ -0,0 +1,47 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SolveSpaceSolver_ParameterWrapper.cpp +// Created: 2 Dec 2015 +// Author: Artem ZHIDKOV + +#include + +#include + +SolveSpaceSolver_ParameterWrapper::SolveSpaceSolver_ParameterWrapper(const Slvs_Param& theParam) + : myParameter(theParam) +{ +} + +ParameterID SolveSpaceSolver_ParameterWrapper::id() const +{ + return (ParameterID)myParameter.h; +} + +void SolveSpaceSolver_ParameterWrapper::setValue(double theValue) +{ + myParameter.val = theValue; +} + +double SolveSpaceSolver_ParameterWrapper::value() const +{ + return myParameter.val; +} + +bool SolveSpaceSolver_ParameterWrapper::isEqual(const ParameterWrapperPtr& theOther) +{ + std::shared_ptr anOtherParam = + std::dynamic_pointer_cast(theOther); + return anOtherParam && fabs(value() - anOtherParam->value()) < tolerance; +} + +bool SolveSpaceSolver_ParameterWrapper::update(const ParameterWrapperPtr& theOther) +{ + std::shared_ptr anOther = + std::dynamic_pointer_cast(theOther); + if (fabs(value() - anOther->value()) < tolerance) + return false; + myParameter.val = anOther->value(); + myIsParametric = theOther->isParametric(); + return true; +} diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ParameterWrapper.h b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ParameterWrapper.h new file mode 100644 index 000000000..da82e6549 --- /dev/null +++ b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ParameterWrapper.h @@ -0,0 +1,55 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SolveSpaceSolver_ParameterWrapper.h +// Created: 2 Dec 2015 +// Author: Artem ZHIDKOV + +#ifndef SolveSpaceSolver_ParameterWrapper_H_ +#define SolveSpaceSolver_ParameterWrapper_H_ + +#include +#include + +/** + * Wrapper providing operations with parameters in SolveSpace. + */ +class SolveSpaceSolver_ParameterWrapper : public SketchSolver_IParameterWrapper +{ +public: + SolveSpaceSolver_ParameterWrapper(const Slvs_Param& theParam); + + /// \brief Return SolveSpace parameter + const Slvs_Param& parameter() const + { return myParameter; } + /// \brief Return SolveSpace parameter to change + Slvs_Param& changeParameter() + { return myParameter; } + + /// \brief Return ID of current parameter + virtual ParameterID id() const; + + /// \brief Change group for the parameter + virtual void setGroup(const GroupID& theGroup) + { myParameter.group = (Slvs_hGroup)theGroup; } + + /// \brief Return identifier of the group the parameter belongs to + virtual GroupID group() const + { return (GroupID)myParameter.group; } + + /// \brief Change value of parameter + virtual void setValue(double theValue); + /// \brief Return value of parameter + virtual double value() const; + + /// \brief Compare current parameter with other + virtual bool isEqual(const ParameterWrapperPtr& theOther); + + /// \brief Update value of parameter by the given one + /// \return \c true if the value of parameter is changed + virtual bool update(const std::shared_ptr& theOther); + +private: + Slvs_Param myParameter; +}; + +#endif diff --git a/src/SketchSolver/SketchSolver_Solver.cpp b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Solver.cpp similarity index 63% rename from src/SketchSolver/SketchSolver_Solver.cpp rename to src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Solver.cpp index 36979d747..de1cc3edd 100644 --- a/src/SketchSolver/SketchSolver_Solver.cpp +++ b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Solver.cpp @@ -1,15 +1,14 @@ // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -// File: SketchSolver_Solver.cpp +// File: SolveSpaceSolver_Solver.cpp // Created: 07 May 2014 // Author: Artem ZHIDKOV -#include "SketchSolver_Solver.h" +#include "SolveSpaceSolver_Solver.h" #include -SketchSolver_Solver::SketchSolver_Solver() +SolveSpaceSolver_Solver::SolveSpaceSolver_Solver() { - myGroupID = 0; // Nullify all elements of the set of equations myEquationsSystem.param = 0; myEquationsSystem.params = 0; @@ -30,7 +29,7 @@ SketchSolver_Solver::SketchSolver_Solver() myEquationsSystem.calculateFaileds = 0; } -SketchSolver_Solver::~SketchSolver_Solver() +SolveSpaceSolver_Solver::~SolveSpaceSolver_Solver() { if (myEquationsSystem.constraint) delete[] myEquationsSystem.constraint; @@ -40,26 +39,26 @@ SketchSolver_Solver::~SketchSolver_Solver() myEquationsSystem.failed = 0; } -void SketchSolver_Solver::setParameters(Slvs_Param* theParameters, int theSize) +void SolveSpaceSolver_Solver::setParameters(Slvs_Param* theParameters, int theSize) { myEquationsSystem.param = theParameters; myEquationsSystem.params = theSize; } -void SketchSolver_Solver::setDraggedParameters(const Slvs_hParam* theDragged) +void SolveSpaceSolver_Solver::setDraggedParameters(const Slvs_hParam* theDragged) { for (unsigned int i = 0; i < 4; i++) myEquationsSystem.dragged[i] = theDragged[i]; } -void SketchSolver_Solver::setEntities(Slvs_Entity* theEntities, int theSize) +void SolveSpaceSolver_Solver::setEntities(Slvs_Entity* theEntities, int theSize) { myEquationsSystem.entity = theEntities; myEquationsSystem.entities = theSize; } -void SketchSolver_Solver::setConstraints(Slvs_Constraint* theConstraints, int theSize) +void SolveSpaceSolver_Solver::setConstraints(Slvs_Constraint* theConstraints, int theSize) { if (!myEquationsSystem.constraint) { myEquationsSystem.constraint = new Slvs_Constraint[theSize]; @@ -81,32 +80,29 @@ void SketchSolver_Solver::setConstraints(Slvs_Constraint* theConstraints, int th } -int SketchSolver_Solver::solve() +SketchSolver_SolveStatus SolveSpaceSolver_Solver::solve() { if (myEquationsSystem.constraints <= 0) - return SLVS_RESULT_EMPTY_SET; + return STATUS_EMPTYSET; + + myEquationsSystem.calculateFaileds = myFindFaileds ? 1 : 0; Events_LongOp::start(this); - Slvs_Solve(&myEquationsSystem, myGroupID); + Slvs_Solve(&myEquationsSystem, myGroup); Events_LongOp::end(this); - return myEquationsSystem.result; -} - -bool SketchSolver_Solver::getResult(std::vector& theParameters) -{ - if (myEquationsSystem.result != SLVS_RESULT_OKAY) - return false; - - if (theParameters.size() != myEquationsSystem.params) - return false; // number of parameters is not the same - - std::vector::iterator aParamIter = theParameters.begin(); - for (int i = 0; i < myEquationsSystem.params; i++, aParamIter++) { - if (myEquationsSystem.param[i].h != aParamIter->h) - return false; // sequence of parameters was changed - aParamIter->val = myEquationsSystem.param[i].val; + SketchSolver_SolveStatus aStatus; + switch (myEquationsSystem.result) { + case SLVS_RESULT_OKAY: + aStatus = STATUS_OK; + break; + case SLVS_RESULT_INCONSISTENT: + case SLVS_RESULT_DIDNT_CONVERGE: + case SLVS_RESULT_TOO_MANY_UNKNOWNS: + aStatus = STATUS_INCONSISTENT; + break; + default: + aStatus = STATUS_FAILED; } - - return true; + return aStatus; } diff --git a/src/SketchSolver/SketchSolver_Solver.h b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Solver.h similarity index 63% rename from src/SketchSolver/SketchSolver_Solver.h rename to src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Solver.h index 52ac18f98..c853970a3 100644 --- a/src/SketchSolver/SketchSolver_Solver.h +++ b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Solver.h @@ -1,15 +1,15 @@ // Copyright (C) 2014-20xx CEA/DEN, EDF R&D -// File: SketchSolver_Solver.h +// File: SolveSpaceSolver_Solver.h // Created: 07 May 2014 // Author: Artem ZHIDKOV -#ifndef SketchSolver_Solver_H_ -#define SketchSolver_Solver_H_ +#ifndef SolveSpaceSolver_Solver_H_ +#define SolveSpaceSolver_Solver_H_ -#include "SketchSolver.h" +#include -// Need to be defined before including SolveSpace to avoid additional dependances on Windows platform +// Need to be defined before including SolveSpace to avoid additional dependences on Windows platform #if defined(WIN32) && !defined(HAVE_C99_INTEGER_TYPES) typedef unsigned int UINT32; #else @@ -20,8 +20,6 @@ typedef unsigned int UINT32; #include -#define SLVS_RESULT_EMPTY_SET -1 - // Unknown constraint (for error reporting) #define SLVS_C_UNKNOWN 0 // Fillet constraint identifier @@ -37,21 +35,15 @@ typedef unsigned int UINT32; // Group ID to store external objects #define SLVS_G_OUTOFGROUP 1 -/** - * The main class that performs the high-level operations for connection to the SolveSpace. +/** \class SolveSpaceSolver_Solver + * \ingroup Plugins + * \brief Performs high-level operations to solve sketch in SolveSpace. */ -class SketchSolver_Solver +class SolveSpaceSolver_Solver : public SketchSolver_ISolver { public: - SketchSolver_Solver(); - ~SketchSolver_Solver(); - - /** \brief Initialize the ID of the group - */ - inline void setGroupID(Slvs_hGroup theGroupID) - { - myGroupID = theGroupID; - } + SolveSpaceSolver_Solver(); + virtual ~SolveSpaceSolver_Solver(); /** \brief Change array of parameters * \param[in] theParameters pointer to the array of parameters @@ -77,25 +69,13 @@ class SketchSolver_Solver */ void setDraggedParameters(const Slvs_hParam* theDragged); - /** \brief Set or unset the flag which allows to find all failed constraints - */ - void calculateFailedConstraints(bool theSic) - { myEquationsSystem.calculateFaileds = theSic ? 1 : 0; } - /** \brief Solve the set of equations * \return identifier whether solution succeeded */ - int solve(); - - /** \brief Updates the list of parameters by calculated values - * \param[in,out] theParameters parameters to be updated - * \return \c true if parameters are updated correctly - */ - bool getResult(std::vector& theParameters); + virtual SketchSolver_SolveStatus solve(); private: - Slvs_hGroup myGroupID; ///< identifier of the group to be solved - Slvs_System myEquationsSystem; ///< set of equations for solving in SolveSpace + Slvs_System myEquationsSystem; ///< set of equations for solving in SolveSpace }; #endif diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Storage.cpp b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Storage.cpp new file mode 100644 index 000000000..2a6fb95bf --- /dev/null +++ b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Storage.cpp @@ -0,0 +1,1879 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SolveSpaceSolver_Storage.cpp +// Created: 18 Mar 2015 +// Author: Artem ZHIDKOV + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/** \brief Search the entity/parameter with specified ID in the list of elements + * \param[in] theEntityID unique ID of the element + * \param[in] theEntities list of elements + * \return position of the found element or -1 if the element is not found + */ +template +static int Search(const uint32_t& theEntityID, const std::vector& theEntities); + +/// \brief Compare two parameters to be different +static bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2); +/// \brief Compare two entities to be different +static bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2); +/// \brief Compare two constraints to be different +static bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2); + + +SolveSpaceSolver_Storage::SolveSpaceSolver_Storage(const GroupID& theGroup) + : SketchSolver_Storage(theGroup), + myWorkplaneID(SLVS_E_UNKNOWN), + myParamMaxID(SLVS_E_UNKNOWN), + myEntityMaxID(SLVS_E_UNKNOWN), + myConstrMaxID(SLVS_C_UNKNOWN), + myFixed(SLVS_E_UNKNOWN), + myDuplicatedConstraint(false) +{ +} + +bool SolveSpaceSolver_Storage::update(ConstraintWrapperPtr& theConstraint) +{ + bool isUpdated = false; + std::shared_ptr aConstraint = + std::dynamic_pointer_cast(theConstraint); + Slvs_Constraint aSlvsConstr = getConstraint((Slvs_hConstraint)aConstraint->id()); + if (aSlvsConstr.h == SLVS_C_UNKNOWN) + aSlvsConstr = aConstraint->constraint(); + + // update value of constraint if exist + if (fabs(aSlvsConstr.valA - theConstraint->value()) > tolerance) { + aSlvsConstr.valA = theConstraint->value(); + isUpdated = true; + } + + // update constrained entities + Slvs_hEntity* aPnts[2] = {&aSlvsConstr.ptA, &aSlvsConstr.ptB}; + Slvs_hEntity* anEnts[4] = {&aSlvsConstr.entityA, &aSlvsConstr.entityB, + &aSlvsConstr.entityC, &aSlvsConstr.entityD}; + int aPtInd = 0; + int aEntInd = 0; + + std::list anEntities = theConstraint->entities(); + std::list::iterator anIt = anEntities.begin(); + for (; anIt != anEntities.end(); ++anIt) { + isUpdated = update(*anIt) || isUpdated; + + Slvs_hEntity anID = (Slvs_hEntity)(*anIt)->id(); + if ((*anIt)->type() == ENTITY_POINT) { + if (*(aPnts[aPtInd]) != anID) { + *(aPnts[aPtInd]) = anID; + isUpdated = true; + } + ++aPtInd; + } else { + if (*(anEnts[aEntInd]) != anID) { + *(anEnts[aEntInd]) = anID; + isUpdated = true; + } + ++aEntInd; + } + } + + // update constraint itself (do not update constraints Multi) + if (aSlvsConstr.type != SLVS_C_MULTI_ROTATION && aSlvsConstr.type != SLVS_C_MULTI_TRANSLATION) { + if (aSlvsConstr.wrkpl == SLVS_E_UNKNOWN && myWorkplaneID != SLVS_E_UNKNOWN) + aSlvsConstr.wrkpl = myWorkplaneID; + if (aSlvsConstr.group == SLVS_G_UNKNOWN) + aSlvsConstr.group = (Slvs_hGroup)myGroupID; + Slvs_hConstraint aConstrID = updateConstraint(aSlvsConstr); + if (aSlvsConstr.h == SLVS_C_UNKNOWN) { + aConstraint->changeConstraint() = getConstraint(aConstrID); + isUpdated = true; + } + } + return isUpdated; +} + +bool SolveSpaceSolver_Storage::update(EntityWrapperPtr& theEntity) +{ + bool isUpdated = false; + std::shared_ptr anEntity = + std::dynamic_pointer_cast(theEntity); + Slvs_Entity aSlvsEnt = getEntity((Slvs_hEntity)anEntity->id()); + if (aSlvsEnt.h == SLVS_E_UNKNOWN) + aSlvsEnt = anEntity->entity(); + + std::list aParams = theEntity->parameters(); + std::list::iterator aPIt; + // if the entity is an attribute, need to update its coordinates + if (anEntity->baseAttribute()) { + BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance(); + EntityWrapperPtr anUpdAttr = aBuilder->createAttribute(anEntity->baseAttribute(), GID_UNKNOWN); + if (anUpdAttr) { + std::list anUpdParams = anUpdAttr->parameters(); + std::list::iterator anUpdIt = anUpdParams.begin(); + for (aPIt = aParams.begin(); aPIt != aParams.end() && anUpdIt != anUpdParams.end(); + ++aPIt, ++anUpdIt) { + (*aPIt)->update(*anUpdIt); + } + } + } + + // update parameters + int anInd = 0; + for (aPIt = aParams.begin(); aPIt != aParams.end(); ++aPIt, ++anInd) { + assert(anInd < 4); + isUpdated = update(*aPIt) || isUpdated; + if (aSlvsEnt.param[anInd] != (Slvs_hEntity)(*aPIt)->id()) { + isUpdated = true; + aSlvsEnt.param[anInd] = (Slvs_hEntity)(*aPIt)->id(); + } + } + + // update sub-entities + std::list aSubEntities = theEntity->subEntities(); + std::list::iterator aSIt = aSubEntities.begin(); + for (anInd = 0; aSIt != aSubEntities.end(); ++aSIt, ++anInd) { + assert(anInd < 4); + isUpdated = update(*aSIt) || isUpdated; + + Slvs_hEntity anID = Slvs_hEntity((*aSIt)->id()); + if ((*aSIt)->type() == ENTITY_NORMAL) + aSlvsEnt.normal = anID; + else if ((*aSIt)->type() == ENTITY_SCALAR) + aSlvsEnt.distance = anID; + else if (aSlvsEnt.point[anInd] != anID) { + aSlvsEnt.point[anInd] = anID; + isUpdated = true; + } + } + + // update entity itself + if (aSlvsEnt.wrkpl == SLVS_E_UNKNOWN && myWorkplaneID != SLVS_E_UNKNOWN) + aSlvsEnt.wrkpl = myWorkplaneID; + if (aSlvsEnt.group == SLVS_G_UNKNOWN) + aSlvsEnt.group = (Slvs_hGroup)myGroupID; + Slvs_hEntity anEntID = updateEntity(aSlvsEnt); + if (aSlvsEnt.h == SLVS_E_UNKNOWN) { + anEntity->changeEntity() = getEntity(anEntID); + isUpdated = true; + + if (anEntity->type() == ENTITY_SKETCH) + storeWorkplane(anEntity); + } + return isUpdated; +} + +bool SolveSpaceSolver_Storage::update(ParameterWrapperPtr& theParameter) +{ + std::shared_ptr aParameter = + std::dynamic_pointer_cast(theParameter); + const Slvs_Param& aParam = getParameter((Slvs_hParam)aParameter->id()); + if (aParam.h != SLVS_E_UNKNOWN && fabs(aParam.val - aParameter->value()) < tolerance) + return false; + Slvs_Param aParamToUpd = aParameter->parameter(); + if (aParamToUpd.group == SLVS_G_UNKNOWN) + aParamToUpd.group = aParameter->isParametric() ? (Slvs_hGroup)GID_OUTOFGROUP : (Slvs_hGroup)myGroupID; + Slvs_hParam anID = updateParameter(aParamToUpd); + if (aParam.h == SLVS_E_UNKNOWN) // new parameter + aParameter->changeParameter() = getParameter(anID); + return true; +} + +void SolveSpaceSolver_Storage::storeWorkplane(EntityWrapperPtr theSketch) +{ + myWorkplaneID = (Slvs_hEntity)theSketch->id(); + + // Update sub-entities of the sketch + std::list aSubEntities = theSketch->subEntities(); + std::list::iterator aSIt = aSubEntities.begin(); + for (; aSIt != aSubEntities.end(); ++aSIt) { + std::shared_ptr aSub = + std::dynamic_pointer_cast(*aSIt); + aSub->changeEntity().wrkpl = myWorkplaneID; + } + + // Update all stored entities + std::vector::iterator anIt = myEntities.begin(); + for (; anIt != myEntities.end(); ++anIt) + anIt->wrkpl = myWorkplaneID; +} + +void SolveSpaceSolver_Storage::changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup) +{ + std::list aParams = theEntity->parameters(); + std::list::iterator aPIt = aParams.begin(); + for (; aPIt != aParams.end(); ++aPIt) + changeGroup(*aPIt, theGroup); + + std::list aSubs = theEntity->subEntities(); + std::list::iterator aSIt = aSubs.begin(); + for (; aSIt != aSubs.end(); ++aSIt) + changeGroup(*aSIt, theGroup); + + if (theEntity->group() != theGroup) { + theEntity->setGroup(theGroup); + int aPos = Search((Slvs_hEntity)theEntity->id(), myEntities); + if (aPos >= 0 && aPos < (int)myEntities.size()) { + myEntities[aPos].group = (Slvs_hGroup)theGroup; + setNeedToResolve(true); + } + } +} + +void SolveSpaceSolver_Storage::changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup) +{ + GroupID aGroup = theGroup; + if (theParam->isParametric()) + aGroup = GID_OUTOFGROUP; + if (theParam->group() == aGroup) + return; + + theParam->setGroup(aGroup); + int aPos = Search((Slvs_hParam)theParam->id(), myParameters); + if (aPos >= 0 && aPos < (int)myParameters.size()) { + myParameters[aPos].group = (Slvs_hGroup)aGroup; + setNeedToResolve(true); + } +} + +void SolveSpaceSolver_Storage::addCoincidentPoints( + EntityWrapperPtr theMaster, EntityWrapperPtr theSlave) +{ + if (theMaster->type() != ENTITY_POINT || theSlave->type() != ENTITY_POINT) + return; + + // Search available coincidence + CoincidentPointsMap::iterator aMasterFound = myCoincidentPoints.find(theMaster); + CoincidentPointsMap::iterator aSlaveFound = myCoincidentPoints.find(theSlave); + if (aMasterFound == myCoincidentPoints.end() && aSlaveFound == myCoincidentPoints.end()) { + // try to find master and slave points in the lists of slaves of already existent coincidences + CoincidentPointsMap::iterator anIt = myCoincidentPoints.begin(); + for (; anIt != myCoincidentPoints.end(); ++anIt) { + if (anIt->second.find(theMaster) != anIt->second.end()) + aMasterFound = anIt; + else if (anIt->second.find(theSlave) != anIt->second.end()) + aSlaveFound = anIt; + + if (aMasterFound != myCoincidentPoints.end() && aSlaveFound != myCoincidentPoints.end()) + break; + } + } + + if (aMasterFound == myCoincidentPoints.end()) { + // create new group + myCoincidentPoints[theMaster] = std::set(); + aMasterFound = myCoincidentPoints.find(theMaster); + } else if (aMasterFound == aSlaveFound) + return; // already coincident + + if (aSlaveFound != myCoincidentPoints.end()) { + // A slave has been found, we need to attach all points coincident with it to the new master + std::set aNewSlaves = aSlaveFound->second; + aNewSlaves.insert(aSlaveFound->first); + myCoincidentPoints.erase(aSlaveFound); + + std::set::const_iterator aSlIt = aNewSlaves.begin(); + for (; aSlIt != aNewSlaves.end(); ++aSlIt) + addCoincidentPoints(theMaster, *aSlIt); + } else { + // Update the slave if it was used in constraints and features + replaceInFeatures(theSlave, theMaster); + replaceInConstraints(theSlave, theMaster); + + // Remove slave entity + removeEntity((Slvs_hEntity)theSlave->id()); + + std::shared_ptr aPointMaster = + std::dynamic_pointer_cast(theMaster); + std::shared_ptr aPointSlave = + std::dynamic_pointer_cast(theSlave); + aPointSlave->changeEntity() = aPointMaster->entity(); + aPointSlave->setParameters(aPointMaster->parameters()); + + aMasterFound->second.insert(theSlave); + } +} + +void SolveSpaceSolver_Storage::replaceInFeatures( + EntityWrapperPtr theSource, EntityWrapperPtr theDest) +{ + std::map::const_iterator anIt = myFeatureMap.begin(); + for (; anIt != myFeatureMap.end(); ++anIt) { + bool isUpdated = false; + std::list aSubs = anIt->second->subEntities(); + std::list::iterator aSubIt = aSubs.begin(); + for (; aSubIt != aSubs.end(); ++aSubIt) + if ((*aSubIt)->id() == theSource->id()) { + (*aSubIt)->update(theDest); + isUpdated = true; + } + + if (!isUpdated) + continue; + + std::shared_ptr aWrapper = + std::dynamic_pointer_cast(anIt->second); + // update SolveSpace entity + Slvs_Entity anEnt = aWrapper->entity(); + for (int i = 0; i < 4; ++i) + if (anEnt.point[i] == (Slvs_hEntity)theSource->id()) + anEnt.point[i] = (Slvs_hEntity)theDest->id(); + anEnt.h = updateEntity(anEnt); + aWrapper->changeEntity() = anEnt; + + // update sub-entities + aWrapper->setSubEntities(aSubs); + } +} + +void SolveSpaceSolver_Storage::replaceInConstraints( + EntityWrapperPtr theSource, EntityWrapperPtr theDest) +{ + std::map >::const_iterator + anIt = myConstraintMap.begin(); + std::list::const_iterator aCIt; + for (; anIt != myConstraintMap.end(); ++anIt) + for (aCIt = anIt->second.begin(); aCIt != anIt->second.end(); ++aCIt) { + // Do not process coincidence between points + // (these constraints are stored to keep the structure of constraints). + if ((*aCIt)->type() == CONSTRAINT_PT_PT_COINCIDENT) + continue; + + bool isUpdated = false; + std::list aSubs = (*aCIt)->entities(); + std::list::iterator aSubIt = aSubs.begin(); + for (; aSubIt != aSubs.end(); ++aSubIt) + if ((*aSubIt)->id() == theSource->id()) { + (*aSubIt)->update(theDest); + isUpdated = true; + } + + if (!isUpdated) + continue; + + std::shared_ptr aWrapper = + std::dynamic_pointer_cast(*aCIt); + // change constraint entities + Slvs_Constraint aConstr = aWrapper->constraint(); + if (aConstr.ptA == (Slvs_hEntity)theSource->id()) + aConstr.ptA = (Slvs_hEntity)theDest->id(); + if (aConstr.ptB == (Slvs_hEntity)theSource->id()) + aConstr.ptB = (Slvs_hEntity)theDest->id(); + + // check the constraint is duplicated + std::vector::const_iterator aSlvsCIt = myConstraints.begin(); + for (; aSlvsCIt != myConstraints.end(); ++aSlvsCIt) + if (aConstr.h != aSlvsCIt->h && + aConstr.type == aSlvsCIt->type && + aConstr.ptA == aSlvsCIt->ptA && aConstr.ptB == aSlvsCIt->ptB && + aConstr.entityA == aSlvsCIt->entityA && aConstr.entityB == aSlvsCIt->entityB && + aConstr.entityC == aSlvsCIt->entityC && aConstr.entityD == aSlvsCIt->entityD) { + removeConstraint(aConstr.h); + aConstr = *aSlvsCIt; + break; + } + + if (aSlvsCIt != myConstraints.end()) { + // constraint is duplicated, search its wrapper to add the mapping + std::map >::const_iterator + anIt2 = myConstraintMap.begin(); + std::list::const_iterator aCIt2; + for (; anIt2 != myConstraintMap.end(); ++anIt2) + for (aCIt2 = anIt2->second.begin(); aCIt2 != anIt2->second.end(); ++aCIt2) + if ((Slvs_hConstraint)(*aCIt2)->id() == aConstr.h) { + addSameConstraints(*aCIt2, aWrapper); + break; + } + } else + aConstr.h = updateConstraint(aConstr); + aWrapper->changeConstraint() = aConstr; + + // update sub-entities + aWrapper->setEntities(aSubs); + } +} + +void SolveSpaceSolver_Storage::addSameConstraints(ConstraintWrapperPtr theConstraint1, + ConstraintWrapperPtr theConstraint2) +{ + SameConstraintMap::iterator anIt = myEqualConstraints.begin(); + for (; anIt != myEqualConstraints.end(); ++anIt) { + if (anIt->find(theConstraint1) != anIt->end()) { + anIt->insert(theConstraint2); + return; + } + else if (anIt->find(theConstraint2) != anIt->end()) { + anIt->insert(theConstraint1); + return; + } + } + // group not found => create new one + std::set aNewGroup; + aNewGroup.insert(theConstraint1); + aNewGroup.insert(theConstraint2); + myEqualConstraints.push_back(aNewGroup); +} + + +EntityWrapperPtr SolveSpaceSolver_Storage::calculateMiddlePoint( + EntityWrapperPtr theBase, double theCoeff) +{ + BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance(); + + std::shared_ptr aMidPoint; + if (theBase->type() == ENTITY_LINE) { + std::shared_ptr aPoints[2]; + const std::list& aSubs = theBase->subEntities(); + std::list::const_iterator anIt = aSubs.begin(); + for (int i = 0; i < 2; ++i, ++anIt) + aPoints[i] = aBuilder->point(*anIt); + aMidPoint = aPoints[0]->xy()->multiplied(1.0 - theCoeff)->added( + aPoints[1]->xy()->multiplied(theCoeff)); + } + else if (theBase->type() == ENTITY_ARC) { + double theX, theY; + double anArcPoint[3][2]; + const std::list& aSubs = theBase->subEntities(); + std::list::const_iterator anIt = aSubs.begin(); + for (int i = 0; i < 3; ++i, ++anIt) { + std::shared_ptr aPoint = aBuilder->point(*anIt); + anArcPoint[i][0] = aPoint->x(); + anArcPoint[i][1] = aPoint->y(); + } + // project last point of arc on the arc + double x = anArcPoint[1][0] - anArcPoint[0][0]; + double y = anArcPoint[1][1] - anArcPoint[0][1]; + double aRad = sqrt(x*x + y*y); + x = anArcPoint[2][0] - anArcPoint[0][0]; + y = anArcPoint[2][1] - anArcPoint[0][1]; + double aNorm = sqrt(x*x + y*y); + if (aNorm >= tolerance) { + anArcPoint[2][0] = x * aRad / aNorm; + anArcPoint[2][1] = y * aRad / aNorm; + } + anArcPoint[1][0] -= anArcPoint[0][0]; + anArcPoint[1][1] -= anArcPoint[0][1]; + if (theCoeff < tolerance) { + theX = anArcPoint[0][0] + anArcPoint[1][0]; + theY = anArcPoint[0][1] + anArcPoint[1][1]; + } else if (1 - theCoeff < tolerance) { + theX = anArcPoint[0][0] + anArcPoint[2][0]; + theY = anArcPoint[0][1] + anArcPoint[2][1]; + } else { + std::shared_ptr aStartDir(new GeomAPI_Dir2d(anArcPoint[1][0], anArcPoint[1][1])); + std::shared_ptr aEndDir(new GeomAPI_Dir2d(anArcPoint[2][0], anArcPoint[2][1])); + double anAngle = aStartDir->angle(aEndDir); + if (anAngle < 0) + anAngle += 2.0 * PI; + anAngle *= theCoeff; + double aCos = cos(anAngle); + double aSin = sin(anAngle); + theX = anArcPoint[0][0] + anArcPoint[1][0] * aCos - anArcPoint[1][1] * aSin; + theY = anArcPoint[0][1] + anArcPoint[1][0] * aSin + anArcPoint[1][1] * aCos; + } + aMidPoint = std::shared_ptr(new GeomAPI_XY(theX, theY)); + } + + if (!aMidPoint) + return EntityWrapperPtr(); + + std::list aParameters; + Slvs_Param aParam1 = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)myGroupID, aMidPoint->x()); + aParam1.h = addParameter(aParam1); + aParameters.push_back(ParameterWrapperPtr(new SolveSpaceSolver_ParameterWrapper(aParam1))); + Slvs_Param aParam2 = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)myGroupID, aMidPoint->y()); + aParam2.h = addParameter(aParam2); + aParameters.push_back(ParameterWrapperPtr(new SolveSpaceSolver_ParameterWrapper(aParam2))); + // Create entity (parameters are not filled) + Slvs_Entity anEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, (Slvs_hGroup)myGroupID, + (Slvs_hEntity)myWorkplaneID, aParam1.h, aParam2.h); + anEntity.h = addEntity(anEntity); + + EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(AttributePtr(), anEntity)); + aResult->setParameters(aParameters); + return aResult; +} + + + + + + +Slvs_hParam SolveSpaceSolver_Storage::addParameter(const Slvs_Param& theParam) +{ + if (theParam.h > 0 && theParam.h <= myParamMaxID) { + // parameter is already used, rewrite it + return updateParameter(theParam); + } + + Slvs_Param aParam = theParam; + if (aParam.h > myParamMaxID) + myParamMaxID = aParam.h; + else + aParam.h = ++myParamMaxID; + myParameters.push_back(aParam); + myNeedToResolve = true; + return aParam.h; +} + +Slvs_hParam SolveSpaceSolver_Storage::updateParameter(const Slvs_Param& theParam) +{ + if (theParam.h > 0 && theParam.h <= myParamMaxID) { + // parameter already used, rewrite it + int aPos = Search(theParam.h, myParameters); + if (aPos >= 0 && aPos < (int)myParameters.size()) { + if (IsNotEqual(myParameters[aPos], theParam)) { + myUpdatedParameters.insert(theParam.h); + setNeedToResolve(true); + } + myParameters[aPos] = theParam; + return theParam.h; + } + } + + // Parameter is not found, add new one + Slvs_Param aParam = theParam; + aParam.h = 0; + return addParameter(aParam); +} + +bool SolveSpaceSolver_Storage::removeParameter(const Slvs_hParam& theParamID) +{ + int aPos = Search(theParamID, myParameters); + if (aPos >= 0 && aPos < (int)myParameters.size()) { + // Firstly, search the parameter is not used elsewhere + std::vector::const_iterator anEntIter = myEntities.begin(); + for (; anEntIter != myEntities.end(); anEntIter++) { + for (int i = 0; i < 4; i++) + if (anEntIter->param[i] == theParamID) + return false; + } + // Remove parameter + myParameters.erase(myParameters.begin() + aPos); + myParamMaxID = myParameters.empty() ? SLVS_E_UNKNOWN : myParameters.back().h; + myNeedToResolve = true; + } + return true; +} + +const Slvs_Param& SolveSpaceSolver_Storage::getParameter(const Slvs_hParam& theParamID) const +{ + int aPos = Search(theParamID, myParameters); + if (aPos >= 0 && aPos < (int)myParameters.size()) + return myParameters[aPos]; + + // Parameter is not found, return empty object + static Slvs_Param aDummy; + aDummy.h = 0; + return aDummy; +} + + +Slvs_hEntity SolveSpaceSolver_Storage::addEntity(const Slvs_Entity& theEntity) +{ + if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) { + // Entity is already used, rewrite it + return updateEntity(theEntity); + } + + Slvs_Entity aEntity = theEntity; + if (aEntity.h > myEntityMaxID) + myEntityMaxID = aEntity.h; + else + aEntity.h = ++myEntityMaxID; + myEntities.push_back(aEntity); + myNeedToResolve = true; + return aEntity.h; +} + +Slvs_hEntity SolveSpaceSolver_Storage::updateEntity(const Slvs_Entity& theEntity) +{ + if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) { + // Entity already used, rewrite it + int aPos = Search(theEntity.h, myEntities); + if (aPos >= 0 && aPos < (int)myEntities.size()) { + myNeedToResolve = myNeedToResolve || IsNotEqual(myEntities[aPos], theEntity); + myEntities[aPos] = theEntity; + return theEntity.h; + } + } + + // Entity is not found, add new one + Slvs_Entity aEntity = theEntity; + aEntity.h = 0; + return addEntity(aEntity); +} + +bool SolveSpaceSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID) +{ + bool aResult = true; + int aPos = Search(theEntityID, myEntities); + if (aPos >= 0 && aPos < (int)myEntities.size()) { + // Firstly, check the entity and its attributes is not used elsewhere + std::set anEntAndSubs; + anEntAndSubs.insert(theEntityID); + for (int i = 0; i < 4; i++) + if (myEntities[aPos].point[i] != SLVS_E_UNKNOWN) + anEntAndSubs.insert(myEntities[aPos].point[i]); + + std::vector::const_iterator anEntIter = myEntities.begin(); + for (; anEntIter != myEntities.end(); anEntIter++) { + if (anEntAndSubs.find(anEntIter->h) != anEntAndSubs.end()) + continue; + for (int i = 0; i < 4; i++) + if (anEntAndSubs.find(anEntIter->point[i]) != anEntAndSubs.end()) + return false; + if (anEntAndSubs.find(anEntIter->distance) != anEntAndSubs.end()) + return false; + } + std::vector::const_iterator aConstrIter = myConstraints.begin(); + for (; aConstrIter != myConstraints.end(); aConstrIter++) { + Slvs_hEntity anEntIDs[6] = {aConstrIter->ptA, aConstrIter->ptB, + aConstrIter->entityA, aConstrIter->entityB, + aConstrIter->entityC, aConstrIter->entityD}; + for (int i = 0; i < 6; i++) + if (anEntAndSubs.find(anEntIDs[i]) != anEntAndSubs.end()) + return false; + } + // 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++) + if (anEntity.param[i] != SLVS_E_UNKNOWN) + aResult = removeParameter(anEntity.param[i]) && aResult; + for (int i = 0; i < 4; i++) + if (anEntity.point[i] != SLVS_E_UNKNOWN) + aResult = removeEntity(anEntity.point[i]) && aResult; + myNeedToResolve = true; + } + return aResult; +} + +void SolveSpaceSolver_Storage::removeUnusedEntities() +{ + std::set anUnusedEntities; + std::vector::const_iterator aEIt = myEntities.begin(); + for (; aEIt != myEntities.end(); ++aEIt) { + if (aEIt->h == aEIt->wrkpl) { + // don't remove workplane + anUnusedEntities.erase(aEIt->point[0]); + anUnusedEntities.erase(aEIt->normal); + continue; + } + anUnusedEntities.insert(aEIt->h); + } + + std::vector::const_iterator aCIt = myConstraints.begin(); + for (; aCIt != myConstraints.end(); ++aCIt) { + Slvs_hEntity aSubs[6] = { + aCIt->entityA, aCIt->entityB, + aCIt->entityC, aCIt->entityD, + aCIt->ptA, aCIt->ptB}; + for (int i = 0; i < 6; i++) { + if (aSubs[i] != SLVS_E_UNKNOWN) { + anUnusedEntities.erase(aSubs[i]); + int aPos = Search(aSubs[i], myEntities); + if (aPos >= 0 && aPos < (int)myEntities.size()) { + for (int j = 0; j < 4; j++) + if (myEntities[aPos].point[j] != SLVS_E_UNKNOWN) + anUnusedEntities.erase(myEntities[aPos].point[j]); + if (myEntities[aPos].distance != SLVS_E_UNKNOWN) + anUnusedEntities.erase(myEntities[aPos].distance); + } + } + } + } + + std::set::const_iterator anEntIt = anUnusedEntities.begin(); + while (anEntIt != anUnusedEntities.end()) { + int aPos = Search(*anEntIt, myEntities); + if (aPos < 0 && aPos >= (int)myEntities.size()) + continue; + Slvs_Entity anEntity = myEntities[aPos]; + // Remove entity if and only if all its parameters unused + bool isUsed = false; + if (anEntity.distance != SLVS_E_UNKNOWN && + anUnusedEntities.find(anEntity.distance) == anUnusedEntities.end()) + isUsed = true; + for (int i = 0; i < 4 && !isUsed; i++) + if (anEntity.point[i] != SLVS_E_UNKNOWN && + anUnusedEntities.find(anEntity.point[i]) == anUnusedEntities.end()) + isUsed = true; + if (isUsed) { + anUnusedEntities.erase(anEntity.distance); + for (int i = 0; i < 4; i++) + if (anEntity.point[i] != SLVS_E_UNKNOWN) + anUnusedEntities.erase(anEntity.point[i]); + std::set::iterator aRemoveIt = anEntIt++; + anUnusedEntities.erase(aRemoveIt); + continue; + } + ++anEntIt; + } + + for (anEntIt = anUnusedEntities.begin(); anEntIt != anUnusedEntities.end(); ++anEntIt) { + int aPos = Search(*anEntIt, myEntities); + if (aPos >= 0 && aPos < (int)myEntities.size()) { + // Remove entity 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) + removeParameter(anEntity.distance); + for (int i = 0; i < 4; i++) + if (anEntity.param[i] != SLVS_E_UNKNOWN) + removeParameter(anEntity.param[i]); + for (int i = 0; i < 4; i++) + if (anEntity.point[i] != SLVS_E_UNKNOWN) + removeEntity(anEntity.point[i]); + } + } + + if (!anUnusedEntities.empty()) + myNeedToResolve = true; +} + +bool SolveSpaceSolver_Storage::isUsedByConstraints(const Slvs_hEntity& theEntityID) const +{ + std::vector::const_iterator aCIt = myConstraints.begin(); + for (; aCIt != myConstraints.end(); ++aCIt) { + Slvs_hEntity aSubs[6] = { + aCIt->entityA, aCIt->entityB, + aCIt->entityC, aCIt->entityD, + aCIt->ptA, aCIt->ptB}; + for (int i = 0; i < 6; i++) + if (aSubs[i] != SLVS_E_UNKNOWN && aSubs[i] == theEntityID) + return true; + } + return false; +} + +const Slvs_Entity& SolveSpaceSolver_Storage::getEntity(const Slvs_hEntity& theEntityID) const +{ + int aPos = Search(theEntityID, myEntities); + if (aPos >= 0 && aPos < (int)myEntities.size()) + return myEntities[aPos]; + + // Entity is not found, return empty object + static Slvs_Entity aDummy; + aDummy.h = SLVS_E_UNKNOWN; + return aDummy; +} + +Slvs_hEntity SolveSpaceSolver_Storage::copyEntity(const Slvs_hEntity& theCopied) +{ + int aPos = Search(theCopied, myEntities); + if (aPos < 0 || aPos >= (int)myEntities.size()) + return SLVS_E_UNKNOWN; + + Slvs_Entity aCopy = myEntities[aPos]; + aCopy.h = SLVS_E_UNKNOWN; + int i = 0; + while (aCopy.point[i] != SLVS_E_UNKNOWN) { + aCopy.point[i] = copyEntity(aCopy.point[i]); + i++; + } + if (aCopy.param[0] != SLVS_E_UNKNOWN) { + aPos = Search(aCopy.param[0], myParameters); + i = 0; + while (aCopy.param[i] != SLVS_E_UNKNOWN) { + Slvs_Param aNewParam = myParameters[aPos]; + aNewParam.h = SLVS_E_UNKNOWN; + aCopy.param[i] = addParameter(aNewParam); + i++; + aPos++; + } + } + return addEntity(aCopy); +} + +void SolveSpaceSolver_Storage::copyEntity(const Slvs_hEntity& theFrom, const Slvs_hEntity& theTo) +{ + int aPosFrom = Search(theFrom, myEntities); + int aPosTo = Search(theTo, myEntities); + if (aPosFrom < 0 || aPosFrom >= (int)myEntities.size() || + aPosTo < 0 || aPosTo >= (int)myEntities.size()) + return; + + Slvs_Entity aEntFrom = myEntities[aPosFrom]; + Slvs_Entity aEntTo = myEntities[aPosTo]; + int i = 0; + while (aEntFrom.point[i] != SLVS_E_UNKNOWN) { + copyEntity(aEntFrom.point[i], aEntTo.point[i]); + i++; + } + if (aEntFrom.param[0] != SLVS_E_UNKNOWN) { + aPosFrom = Search(aEntFrom.param[0], myParameters); + aPosTo = Search(aEntTo.param[0], myParameters); + i = 0; + while (aEntFrom.param[i] != SLVS_E_UNKNOWN) { + myParameters[aPosTo++].val = myParameters[aPosFrom++].val; + i++; + } + } +} + + +bool SolveSpaceSolver_Storage::isPointFixed( + const Slvs_hEntity& thePointID, Slvs_hConstraint& theFixed, bool theAccurate) const +{ + // Search the set of coincident points + std::set aCoincident; + aCoincident.insert(thePointID); + + // Check whether one of coincident points is out-of-group + std::set::const_iterator aCoincIt = aCoincident.begin(); + for (; aCoincIt != aCoincident.end(); ++aCoincIt) { + Slvs_Entity aPoint = getEntity(*aCoincIt); + if (aPoint.group == SLVS_G_OUTOFGROUP) + return true; + } + + // Search the Rigid constraint + theFixed = SLVS_C_UNKNOWN; + std::vector::const_iterator aConstrIter = myConstraints.begin(); + for (; aConstrIter != myConstraints.end(); aConstrIter++) + if (aConstrIter->type == SLVS_C_WHERE_DRAGGED && + aCoincident.find(aConstrIter->ptA) != aCoincident.end()) { + theFixed = aConstrIter->h; + if (aConstrIter->ptA == thePointID) + return true; + } + if (theFixed != SLVS_C_UNKNOWN) + return true; + + if (theAccurate) { + // Try to find the fixed entity which uses such point or its coincidence + std::vector::const_iterator anEntIter = myEntities.begin(); + for (; anEntIter != myEntities.end(); anEntIter++) { + for (int i = 0; i < 4; i++) { + Slvs_hEntity aPt = anEntIter->point[i]; + if (aPt != SLVS_E_UNKNOWN && + (aPt == thePointID || aCoincident.find(aPt) != aCoincident.end())) { + if (isEntityFixed(anEntIter->h, true)) + return true; + } + } + } + } + return SLVS_E_UNKNOWN; +} + +bool SolveSpaceSolver_Storage::isEntityFixed(const Slvs_hEntity& theEntityID, bool theAccurate) const +{ + int aPos = Search(theEntityID, myEntities); + if (aPos < 0 || aPos >= (int)myEntities.size()) + return false; + + // Firstly, find how many points are under Rigid constraint + int aNbFixed = 0; + for (int i = 0; i < 4; i++) { + Slvs_hEntity aPoint = myEntities[aPos].point[i]; + if (aPoint == SLVS_E_UNKNOWN) + continue; + + std::set aCoincident; + aCoincident.insert(aPoint); + + // Search the Rigid constraint + std::vector::const_iterator aConstrIter = myConstraints.begin(); + for (; aConstrIter != myConstraints.end(); aConstrIter++) + if (aConstrIter->type == SLVS_C_WHERE_DRAGGED && + aCoincident.find(aConstrIter->ptA) != aCoincident.end()) + aNbFixed++; + } + + std::list aList; + std::list::iterator anIt; + Slvs_hConstraint aTempID; // used in isPointFixed() method + + if (myEntities[aPos].type == SLVS_E_LINE_SEGMENT) { + if (aNbFixed == 2) + return true; + else if (aNbFixed == 0 || !theAccurate) + return false; + // Additional check (the line may be fixed if it is used by different constraints): + // 1. The line is used in Equal constraint, another entity is fixed and there is a fixed point on line + aList = getConstraintsByType(SLVS_C_PT_ON_LINE); + for (anIt = aList.begin(); anIt != aList.end(); anIt++) + if (anIt->entityA == theEntityID && isPointFixed(anIt->ptA, aTempID)) + break; + if (anIt != aList.end()) { + aList = getConstraintsByType(SLVS_C_EQUAL_LENGTH_LINES); + aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN)); + for (anIt = aList.begin(); anIt != aList.end(); anIt++) + if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) { + Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA; + if (isEntityFixed(anOther, false)) + return true; + } + } + // 2. The line is used in Parallel/Perpendicular/Vertical/Horizontal and Length constraints + aList = getConstraintsByType(SLVS_C_PARALLEL); + aList.splice(aList.end(), getConstraintsByType(SLVS_C_PERPENDICULAR)); + aList.splice(aList.end(), getConstraintsByType(SLVS_C_VERTICAL)); + aList.splice(aList.end(), getConstraintsByType(SLVS_C_HORIZONTAL)); + for (anIt = aList.begin(); anIt != aList.end(); anIt++) + if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) { + Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA; + if (isEntityFixed(anOther, false)) + break; + } + if (anIt != aList.end()) { + aList = getConstraintsByType(SLVS_C_PT_PT_DISTANCE); + for (anIt = aList.begin(); anIt != aList.end(); anIt++) + if ((anIt->ptA == myEntities[aPos].point[0] && anIt->ptB == myEntities[aPos].point[1]) || + (anIt->ptA == myEntities[aPos].point[1] && anIt->ptB == myEntities[aPos].point[0])) + return true; + } + // 3. Another verifiers ... + } else if (myEntities[aPos].type == SLVS_E_CIRCLE) { + if (aNbFixed == 0) + return false; + // Search for Diameter constraint + aList = getConstraintsByType(SLVS_C_DIAMETER); + for (anIt = aList.begin(); anIt != aList.end(); anIt++) + if (anIt->entityA == theEntityID) + return true; + if (!theAccurate) + return false; + // Additional check (the circle may be fixed if it is used by different constraints): + // 1. The circle is used in Equal constraint and another entity is fixed + aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS); + for (anIt = aList.begin(); anIt != aList.end(); anIt++) + if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) { + Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA; + if (isEntityFixed(anOther, false)) + return true; + } + // 2. Another verifiers ... + } else if (myEntities[aPos].type == SLVS_E_ARC_OF_CIRCLE) { + if (aNbFixed > 2) + return true; + else if (aNbFixed <= 1) + return false; + // Search for Diameter constraint + aList = getConstraintsByType(SLVS_C_DIAMETER); + for (anIt = aList.begin(); anIt != aList.end(); anIt++) + if (anIt->entityA == theEntityID) + return true; + if (!theAccurate) + return false; + // Additional check (the arc may be fixed if it is used by different constraints): + // 1. The arc is used in Equal constraint and another entity is fixed + aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS); + aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN)); + for (anIt = aList.begin(); anIt != aList.end(); anIt++) + if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) { + Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA; + if (isEntityFixed(anOther, false)) + return true; + } + // 2. Another verifiers ... + } + return false; +} + + +Slvs_hConstraint SolveSpaceSolver_Storage::addConstraint(const Slvs_Constraint& theConstraint) +{ + if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) { + // Constraint is already used, rewrite it + return updateConstraint(theConstraint); + } + + Slvs_Constraint aConstraint = theConstraint; + + // Find a constraint with same type uses same arguments to show user overconstraint situation + std::vector::iterator aCIt = myConstraints.begin(); + for (; aCIt != myConstraints.end(); aCIt++) { + if (aConstraint.type != aCIt->type) + continue; + if (aConstraint.ptA == aCIt->ptA && aConstraint.ptB == aCIt->ptB && + aConstraint.entityA == aCIt->entityA && aConstraint.entityB == aCIt->entityB && + aConstraint.entityC == aCIt->entityC && aConstraint.entityD == aCIt->entityD) + myDuplicatedConstraint = true; + } + + if (aConstraint.h > myConstrMaxID) + myConstrMaxID = aConstraint.h; + else + aConstraint.h = ++myConstrMaxID; + myConstraints.push_back(aConstraint); + myNeedToResolve = true; + return aConstraint.h; +} + +Slvs_hConstraint SolveSpaceSolver_Storage::updateConstraint(const Slvs_Constraint& theConstraint) +{ + if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) { + // Constraint already used, rewrite it + int aPos = Search(theConstraint.h, myConstraints); + if (aPos >= 0 && aPos < (int)myConstraints.size()) { + myNeedToResolve = myNeedToResolve || IsNotEqual(myConstraints[aPos], theConstraint); + myConstraints[aPos] = theConstraint; + return theConstraint.h; + } + } + + // Constraint is not found, add new one + Slvs_Constraint aConstraint = theConstraint; + aConstraint.h = 0; + return addConstraint(aConstraint); +} + +bool SolveSpaceSolver_Storage::removeConstraint(const Slvs_hConstraint& theConstraintID) +{ + bool aResult = true; + int aPos = Search(theConstraintID, myConstraints); + 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; + + // Remove all entities + Slvs_hEntity anEntities[6] = {aConstraint.ptA, aConstraint.ptB, + aConstraint.entityA, aConstraint.entityB, + aConstraint.entityC, aConstraint.entityD}; + for (int i = 0; i < 6; i++) + if (anEntities[i] != SLVS_E_UNKNOWN) + aResult = removeEntity(anEntities[i]) && aResult; + // remove temporary fixed point, if available + if (myFixed == theConstraintID) + myFixed = SLVS_E_UNKNOWN; + if (myDuplicatedConstraint) { + // Check the duplicated constraints are still available + myDuplicatedConstraint = false; + std::vector::const_iterator anIt1 = myConstraints.begin(); + std::vector::const_iterator anIt2 = myConstraints.begin(); + for (; anIt1 != myConstraints.end() && !myDuplicatedConstraint; anIt1++) + for (anIt2 = anIt1+1; anIt2 != myConstraints.end() && !myDuplicatedConstraint; anIt2++) { + if (anIt1->type != anIt2->type) + continue; + if (anIt1->ptA == anIt2->ptA && anIt1->ptB == anIt2->ptB && + anIt1->entityA == anIt2->entityA && anIt1->entityB == anIt2->entityB && + anIt1->entityC == anIt2->entityC && anIt1->entityD == anIt2->entityD) + myDuplicatedConstraint = true; + } + } + } + return aResult; +} + +const Slvs_Constraint& SolveSpaceSolver_Storage::getConstraint(const Slvs_hConstraint& theConstraintID) const +{ + int aPos = Search(theConstraintID, myConstraints); + if (aPos >= 0 && aPos < (int)myConstraints.size()) + return myConstraints[aPos]; + + // Constraint is not found, return empty object + static Slvs_Constraint aDummy; + aDummy.h = 0; + return aDummy; +} + +std::list SolveSpaceSolver_Storage::getConstraintsByType(int theConstraintType) const +{ + std::list aResult; + std::vector::const_iterator aCIter = myConstraints.begin(); + for (; aCIter != myConstraints.end(); aCIter++) + if (aCIter->type == theConstraintType) + aResult.push_back(*aCIter); + return aResult; +} + + +void SolveSpaceSolver_Storage::addConstraintWhereDragged(const Slvs_hConstraint& theConstraintID) +{ + if (myFixed != SLVS_E_UNKNOWN) + return; // the point is already fixed + int aPos = Search(theConstraintID, myConstraints); + if (aPos >= 0 && aPos < (int)myConstraints.size()) + myFixed = theConstraintID; +} + +void SolveSpaceSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID) +{ + myTemporaryConstraints.insert(theConstraintID); +} + +void SolveSpaceSolver_Storage::removeAllTemporary() +{ + myTemporaryConstraints.clear(); +} + +size_t SolveSpaceSolver_Storage::removeTemporary(size_t theNbConstraints) +{ + if (myTemporaryConstraints.empty()) + return 0; + // Search the point-on-line or a non-rigid constraint + std::set::iterator aCIt = myTemporaryConstraints.begin(); + for (; aCIt != myTemporaryConstraints.end(); aCIt++) { + int aPos = Search(*aCIt, myConstraints); + if (aPos >= (int)myConstraints.size() || myConstraints[aPos].type != SLVS_C_WHERE_DRAGGED) + break; + std::vector::iterator anIt = myConstraints.begin(); + for (; anIt != myConstraints.end(); anIt++) + if (anIt->type == SLVS_C_PT_ON_LINE && anIt->ptA == myConstraints[aPos].ptA) + break; + if (anIt != myConstraints.end()) + break; + } + if (aCIt == myTemporaryConstraints.end()) + aCIt = myTemporaryConstraints.begin(); + bool aNewFixed = false; + + size_t aNbRemain = theNbConstraints; + while (aNbRemain > 0 && aCIt != myTemporaryConstraints.end()) { + aNewFixed = aNewFixed || (*aCIt == myFixed); + --aNbRemain; + + std::set::iterator aRemoveIt = aCIt++; + removeConstraint(*aRemoveIt); + myTemporaryConstraints.erase(aRemoveIt); + if (aCIt == myTemporaryConstraints.end()) + aCIt = myTemporaryConstraints.begin(); + } + + if (aNewFixed) { + for (aCIt = myTemporaryConstraints.begin(); aCIt != myTemporaryConstraints.end(); aCIt++) { + int aPos = Search(*aCIt, myConstraints); + if (myConstraints[aPos].type == SLVS_C_WHERE_DRAGGED) { + myFixed = *aCIt; + break; + } + } + } + return myTemporaryConstraints.size(); +} + +bool SolveSpaceSolver_Storage::isTemporary(const Slvs_hConstraint& theConstraintID) const +{ + return myTemporaryConstraints.find(theConstraintID) != myTemporaryConstraints.end(); +} + + + +void SolveSpaceSolver_Storage::initializeSolver(SolverPtr theSolver) +{ + std::shared_ptr aSolver = + std::dynamic_pointer_cast(theSolver); + if (!aSolver) + return; + + if (myConstraints.empty()) { + // Adjust all arc to place their points correctly + std::vector::const_iterator anEntIt = myEntities.begin(); + for (; anEntIt != myEntities.end(); ++anEntIt) + if (anEntIt->type == SLVS_E_ARC_OF_CIRCLE) + adjustArc(*anEntIt); + } + + aSolver->setParameters(myParameters.data(), (int)myParameters.size()); + aSolver->setEntities(myEntities.data(), (int)myEntities.size()); + + // 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); + aSolver->setDraggedParameters(myEntities[aPos].param); + } + aSolver->setConstraints(aConstraints.data(), (int)aConstraints.size()); +} + + +bool SolveSpaceSolver_Storage::isEqual( + const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const +{ + // Precise checking of coincidence: verify that points have equal coordinates + int aEnt1Pos = Search(thePoint1, myEntities); + int aEnt2Pos = Search(thePoint2, myEntities); + if (aEnt1Pos >= 0 && aEnt1Pos < (int)myEntities.size() && + aEnt2Pos >= 0 && aEnt2Pos < (int)myEntities.size()) { + double aDist[2]; + int aParamPos; + for (int i = 0; i < 2; i++) { + aParamPos = Search(myEntities[aEnt1Pos].param[i], myParameters); + aDist[i] = myParameters[aParamPos].val; + aParamPos = Search(myEntities[aEnt2Pos].param[i], myParameters); + aDist[i] -= myParameters[aParamPos].val; + } + if (aDist[0] * aDist[0] + aDist[1] * aDist[1] < tolerance * tolerance) + return true; + } + return false; +} + + +std::vector SolveSpaceSolver_Storage::fixEntity(const Slvs_hEntity& theEntity) +{ + std::vector aNewConstraints; + + int aPos = Search(theEntity, myEntities); + if (aPos >= 0 && aPos < (int)myEntities.size()) { + switch (myEntities[aPos].type) { + case SLVS_E_POINT_IN_2D: + case SLVS_E_POINT_IN_3D: + fixPoint(myEntities[aPos], aNewConstraints); + break; + case SLVS_E_LINE_SEGMENT: + fixLine(myEntities[aPos], aNewConstraints); + break; + case SLVS_E_CIRCLE: + fixCircle(myEntities[aPos], aNewConstraints); + break; + case SLVS_E_ARC_OF_CIRCLE: + fixArc(myEntities[aPos], aNewConstraints); + break; + default: + break; + } + } + + return aNewConstraints; +} + +void SolveSpaceSolver_Storage::fixPoint(const Slvs_Entity& thePoint, + std::vector& theCreated) +{ + Slvs_Constraint aConstraint; + Slvs_hConstraint aConstrID = SLVS_E_UNKNOWN; + bool isFixed = isPointFixed(thePoint.h, aConstrID, true); + bool isForceUpdate = (isFixed && isTemporary(aConstrID)); + if (!isForceUpdate) { // create new constraint + if (isFixed) return; + aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, thePoint.group, SLVS_C_WHERE_DRAGGED, thePoint.wrkpl, + 0.0, thePoint.h, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); + aConstraint.h = addConstraint(aConstraint); + theCreated.push_back(aConstraint.h); + } else { // update already existent constraint + if (!isFixed || aConstrID == SLVS_E_UNKNOWN) + return; + int aPos = Search(aConstrID, myConstraints); + if (aPos >= 0 && aPos < (int)myConstraints.size()) + myConstraints[aPos].ptA = thePoint.h; + } +} + +void SolveSpaceSolver_Storage::fixLine(const Slvs_Entity& theLine, + std::vector& theCreated) +{ + Slvs_Entity aPoint[2] = { + getEntity(theLine.point[0]), + getEntity(theLine.point[1]) + }; + + Slvs_Constraint anEqual; + if (isAxisParallel(theLine.h)) { + // Fix one point and a line length + Slvs_hConstraint aFixed; + if (!isPointFixed(theLine.point[0], aFixed, true) && + !isPointFixed(theLine.point[1], aFixed, true)) + fixPoint(aPoint[0], theCreated); + if (!isUsedInEqual(theLine.h, anEqual)) { + // Check the distance is not set yet + std::vector::const_iterator aDistIt = myConstraints.begin(); + for (; aDistIt != myConstraints.end(); ++aDistIt) + if ((aDistIt->type == SLVS_C_PT_PT_DISTANCE) && + ((aDistIt->ptA == theLine.point[0] && aDistIt->ptB == theLine.point[1]) || + (aDistIt->ptA == theLine.point[1] && aDistIt->ptB == theLine.point[0]))) + return; + // Calculate distance between points on the line + double aCoords[4]; + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) { + Slvs_Param aParam = getParameter(aPoint[i].param[j]); + aCoords[2*i+j] = aParam.val; + } + + double aLength = sqrt((aCoords[2] - aCoords[0]) * (aCoords[2] - aCoords[0]) + + (aCoords[3] - aCoords[1]) * (aCoords[3] - aCoords[1])); + // fix line length + Slvs_Constraint aDistance = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theLine.group, + SLVS_C_PT_PT_DISTANCE, theLine.wrkpl, aLength, + theLine.point[0], theLine.point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); + aDistance.h = addConstraint(aDistance); + theCreated.push_back(aDistance.h); + } + return; + } + else if (isUsedInEqual(theLine.h, anEqual)) { + // Check another entity of Equal is already fixed + Slvs_hEntity anOtherEntID = anEqual.entityA == theLine.h ? anEqual.entityB : anEqual.entityA; + if (isEntityFixed(anOtherEntID, true)) { + // Fix start point of the line (if end point is not fixed yet) ... + Slvs_hConstraint anEndFixedID = SLVS_E_UNKNOWN; + bool isFixed = isPointFixed(theLine.point[1], anEndFixedID, true); + if (isFixed == SLVS_E_UNKNOWN) + fixPoint(aPoint[0], theCreated); + // ... and create fixed point lying on this line + Slvs_hEntity aPointToCopy = anEndFixedID == SLVS_E_UNKNOWN ? theLine.point[1] : theLine.point[0]; + // Firstly, search already fixed point on line + bool isPonLineFixed = false; + Slvs_hEntity aFixedPoint; + std::vector::const_iterator aPLIter = myConstraints.begin(); + for (; aPLIter != myConstraints.end() && !isPonLineFixed; ++aPLIter) + if (aPLIter->type == SLVS_C_PT_ON_LINE && aPLIter->entityA == theLine.h) { + isPonLineFixed = isPointFixed(aPLIter->ptA, anEndFixedID); + aFixedPoint = aPLIter->ptA; + } + + if (isPonLineFixed) { // update existent constraint + copyEntity(aPointToCopy, aFixedPoint); + } else { // create new constraint + Slvs_hEntity aCopied = copyEntity(aPointToCopy); + Slvs_Constraint aPonLine = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theLine.group, SLVS_C_PT_ON_LINE, + theLine.wrkpl, 0.0, aCopied, SLVS_E_UNKNOWN, theLine.h, SLVS_E_UNKNOWN); + aPonLine.h = addConstraint(aPonLine); + theCreated.push_back(aPonLine.h); + fixPoint(getEntity(aCopied), theCreated); + } + return; + } + } + + // Fix both points + for (int i = 0; i < 2; i++) + fixPoint(aPoint[i], theCreated); +} + +void SolveSpaceSolver_Storage::fixCircle(const Slvs_Entity& theCircle, + std::vector& theCreated) +{ + bool isFixRadius = true; + // Verify the arc is under Equal constraint + Slvs_Constraint anEqual; + if (isUsedInEqual(theCircle.h, anEqual)) { + // Check another entity of Equal is already fixed + Slvs_hEntity anOtherEntID = anEqual.entityA == theCircle.h ? anEqual.entityB : anEqual.entityA; + if (isEntityFixed(anOtherEntID, true)) + isFixRadius = false; + } + + fixPoint(getEntity(theCircle.point[0]), theCreated); + + if (isFixRadius) { + // Search the radius is already fixed + std::vector::const_iterator aDiamIter = myConstraints.begin(); + for (; aDiamIter != myConstraints.end(); ++aDiamIter) + if (aDiamIter->type == SLVS_C_DIAMETER && aDiamIter->entityA == theCircle.h) + return; + + // Fix radius of a circle + const Slvs_Entity& aRadEnt = getEntity(theCircle.distance); + double aRadius = getParameter(aRadEnt.param[0]).val; + Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theCircle.group, SLVS_C_DIAMETER, + theCircle.wrkpl, aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, theCircle.h, SLVS_E_UNKNOWN); + aFixedR.h = addConstraint(aFixedR); + theCreated.push_back(aFixedR.h); + } +} + +void SolveSpaceSolver_Storage::fixArc(const Slvs_Entity& theArc, + std::vector& theCreated) +{ + Slvs_Entity aPoint[3] = { + getEntity(theArc.point[0]), + getEntity(theArc.point[1]), + getEntity(theArc.point[2]) + }; + + bool isFixRadius = true; + std::list aPointsToFix; + aPointsToFix.push_back(aPoint[1]); + aPointsToFix.push_back(aPoint[2]); + + // Verify the arc is under Equal constraint + Slvs_Constraint anEqual; + if (isUsedInEqual(theArc.h, anEqual)) { + // Check another entity of Equal is already fixed + Slvs_hEntity anOtherEntID = anEqual.entityA == theArc.h ? anEqual.entityB : anEqual.entityA; + if (isEntityFixed(anOtherEntID, true)) { + isFixRadius = false; + Slvs_Entity anOtherEntity = getEntity(anOtherEntID); + if (anOtherEntity.type == SLVS_E_LINE_SEGMENT) { + aPointsToFix.pop_back(); + aPointsToFix.push_back(aPoint[0]); + } + } + } + + Slvs_hConstraint aConstrID; + int aNbPointsToFix = 2; // number of fixed points for the arc + if (isPointFixed(theArc.point[0], aConstrID, true)) + aNbPointsToFix--; + + double anArcPoints[3][2]; + for (int i = 0; i < 3; i++) { + const Slvs_Entity& aPointOnArc = getEntity(theArc.point[i]); + for (int j = 0; j < 2; j++) + anArcPoints[i][j] = getParameter(aPointOnArc.param[j]).val; + } + + // Radius of the arc + std::shared_ptr aCenter(new GeomAPI_Pnt2d(anArcPoints[0][0], anArcPoints[0][1])); + std::shared_ptr aStart(new GeomAPI_Pnt2d(anArcPoints[1][0], anArcPoints[1][1])); + double aRadius = aCenter->distance(aStart); + + // Update end point of the arc to be on a curve + std::shared_ptr anEnd(new GeomAPI_Pnt2d(anArcPoints[2][0], anArcPoints[2][1])); + double aDistance = anEnd->distance(aCenter); + std::shared_ptr aDir = anEnd->xy()->decreased(aCenter->xy()); + if (aDistance < tolerance) + aDir = aStart->xy()->decreased(aCenter->xy())->multiplied(-1.0); + else + aDir = aDir->multiplied(aRadius / aDistance); + double xy[2] = {aCenter->x() + aDir->x(), aCenter->y() + aDir->y()}; + const Slvs_Entity& aEndPoint = getEntity(theArc.point[2]); + for (int i = 0; i < 2; i++) { + Slvs_Param aParam = getParameter(aEndPoint.param[i]); + aParam.val = xy[i]; + updateParameter(aParam); + } + + std::list::iterator aPtIt = aPointsToFix.begin(); + for (; aNbPointsToFix > 0; aPtIt++, aNbPointsToFix--) + fixPoint(*aPtIt, theCreated); + + if (isFixRadius) { + // Fix radius of the arc + bool isExists = false; + std::vector::iterator anIt = myConstraints.begin(); + for (; anIt != myConstraints.end() && !isExists; ++anIt) + if (anIt->type == SLVS_C_DIAMETER && anIt->entityA == theArc.h) + isExists = true; + if (!isExists) { + Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theArc.group, SLVS_C_DIAMETER, + theArc.wrkpl, aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, theArc.h, SLVS_E_UNKNOWN); + aFixedR.h = addConstraint(aFixedR); + theCreated.push_back(aFixedR.h); + } + } +} + + +bool SolveSpaceSolver_Storage::isAxisParallel(const Slvs_hEntity& theEntity) const +{ + std::vector::const_iterator anIter = myConstraints.begin(); + for (; anIter != myConstraints.end(); anIter++) + if ((anIter->type == SLVS_C_HORIZONTAL || anIter->type == SLVS_C_VERTICAL) && + anIter->entityA == theEntity) + return true; + return false; +} + +bool SolveSpaceSolver_Storage::isUsedInEqual( + const Slvs_hEntity& theEntity, Slvs_Constraint& theEqual) const +{ + // Check the entity is used in Equal constraint + std::vector::const_iterator anEqIter = myConstraints.begin(); + for (; anEqIter != myConstraints.end(); anEqIter++) + if ((anEqIter->type == SLVS_C_EQUAL_LENGTH_LINES || + anEqIter->type == SLVS_C_EQUAL_LINE_ARC_LEN || + anEqIter->type == SLVS_C_EQUAL_RADIUS) && + (anEqIter->entityA == theEntity || anEqIter->entityB == theEntity)) { + theEqual = *anEqIter; + return true; + } + return false; +} + +void SolveSpaceSolver_Storage::setTemporary(ConstraintPtr theConstraint) +{ + // TODO +} + +bool SolveSpaceSolver_Storage::removeConstraint(ConstraintPtr theConstraint) +{ + std::map >::iterator + aFound = myConstraintMap.find(theConstraint); + if (aFound == myConstraintMap.end()) + return true; // no constraint, already deleted + + // Remove constraint + std::list aConstrList = aFound->second; + myConstraintMap.erase(aFound); + // Remove SolveSpace constraints + bool isFullyRemoved = true; + std::list::iterator anIt = aConstrList.begin(); + while (anIt != aConstrList.end()) { + if (remove(*anIt)) { + std::list::iterator aRemoveIt = anIt++; + aConstrList.erase(aRemoveIt); + } else { + isFullyRemoved = false; + ++anIt; + } + } + if (!isFullyRemoved) + myConstraintMap[theConstraint] = aConstrList; + return isFullyRemoved; +} + +template +static bool isUsed(ConstraintWrapperPtr theConstraint, ENT_TYPE theEntity) +{ + std::list::const_iterator anEntIt = theConstraint->entities().begin(); + for (; anEntIt != theConstraint->entities().end(); ++anEntIt) + if (std::dynamic_pointer_cast(*anEntIt)->isBase(theEntity)) + return true; + return false; +} + +static bool isUsed(EntityWrapperPtr theFeature, AttributePtr theSubEntity) +{ + std::list::const_iterator aSubIt = theFeature->subEntities().begin(); + for (; aSubIt != theFeature->subEntities().end(); ++aSubIt) + if (std::dynamic_pointer_cast(*aSubIt)->isBase(theSubEntity)) + return true; + return false; +} + +bool SolveSpaceSolver_Storage::isUsed(FeaturePtr theFeature) const +{ + std::map >::const_iterator + aCIt = myConstraintMap.begin(); + std::list::const_iterator aCWIt; + for (; aCIt != myConstraintMap.end(); ++aCIt) + for (aCWIt = aCIt->second.begin(); aCWIt != aCIt->second.end(); ++aCWIt) + if (::isUsed(*aCWIt, theFeature)) + return true; + // check attributes + std::list anAttrList = theFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); + std::list::const_iterator anIt = anAttrList.begin(); + for (; anIt != anAttrList.end(); ++anIt) + if (isUsed(*anIt)) + return true; + return false; +} + +bool SolveSpaceSolver_Storage::isUsed(AttributePtr theAttribute) const +{ + AttributePtr anAttribute = theAttribute; + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(anAttribute); + if (aRefAttr) { + if (aRefAttr->isObject()) + return isUsed(ModelAPI_Feature::feature(aRefAttr->object())); + else + anAttribute = aRefAttr->attr(); + } + + std::map >::const_iterator + aCIt = myConstraintMap.begin(); + std::list::const_iterator aCWIt; + for (; aCIt != myConstraintMap.end(); ++aCIt) + for (aCWIt = aCIt->second.begin(); aCWIt != aCIt->second.end(); ++aCWIt) + if (::isUsed(*aCWIt, anAttribute)) + return true; + return false; +} + + +bool SolveSpaceSolver_Storage::removeEntity(FeaturePtr theFeature) +{ + std::map::iterator aFound = myFeatureMap.find(theFeature); + if (aFound == myFeatureMap.end()) + return false; // feature not found, nothing to delete + + // Check the feature is not used by constraints + if (isUsed(theFeature)) + return false; // the feature is used, don't remove it + + // Remove feature + EntityWrapperPtr anEntity = aFound->second; + myFeatureMap.erase(aFound); + if (remove(anEntity)) + return true; + // feature is not removed, revert operation + myFeatureMap[theFeature] = anEntity; + return false; +} + +bool SolveSpaceSolver_Storage::removeEntity(AttributePtr theAttribute) +{ + std::map::iterator aFound = myAttributeMap.find(theAttribute); + if (aFound == myAttributeMap.end()) + return false; // attribute not found, nothing to delete + + // Check the attribute is not used by constraints + if (isUsed(theAttribute)) + return false; // the attribute is used, don't remove it + // Check the attribute is not used by other features + std::map::const_iterator aFIt = myFeatureMap.begin(); + for (; aFIt != myFeatureMap.end(); ++aFIt) + if (::isUsed(aFIt->second, theAttribute)) // the attribute is used, don't remove it + return false; + + // Remove attribute + EntityWrapperPtr anEntity = aFound->second; + myAttributeMap.erase(aFound); + if (remove(anEntity)) + return true; + // attribute is not removed, revert operation + myAttributeMap[theAttribute] = anEntity; + return false; +} + + +bool SolveSpaceSolver_Storage::remove(ConstraintWrapperPtr theConstraint) +{ + std::shared_ptr aConstraint = + std::dynamic_pointer_cast(theConstraint); + + // verify whether the constraint has duplicated + SameConstraintMap::iterator anEqIt = myEqualConstraints.begin(); + for (; anEqIt != myEqualConstraints.end(); ++anEqIt) + if (anEqIt->find(aConstraint) != anEqIt->end()) { + anEqIt->erase(aConstraint); + break; + } + if (anEqIt != myEqualConstraints.end()) + return true; + + bool isFullyRemoved = removeConstraint((Slvs_hConstraint)aConstraint->id()); + + std::list::const_iterator anIt = aConstraint->entities().begin(); + for (; anIt != aConstraint->entities().end(); ++anIt) { + std::shared_ptr anEntity = + std::dynamic_pointer_cast(*anIt); + FeaturePtr aBaseFeature = anEntity->baseFeature(); + if (aBaseFeature) + isFullyRemoved = removeEntity(aBaseFeature) && isFullyRemoved; + else + isFullyRemoved = removeEntity(anEntity->baseAttribute()) && isFullyRemoved; + } + + return isFullyRemoved; +} + +bool SolveSpaceSolver_Storage::remove(EntityWrapperPtr theEntity) +{ + std::shared_ptr anEntity = + std::dynamic_pointer_cast(theEntity); + bool isFullyRemoved = removeEntity((Slvs_hEntity)anEntity->id()); + + std::list::const_iterator anEntIt = anEntity->subEntities().begin(); + for (; anEntIt != anEntity->subEntities().end(); ++anEntIt) { + std::shared_ptr aSubEntity = + std::dynamic_pointer_cast(*anEntIt); + FeaturePtr aBaseFeature = aSubEntity->baseFeature(); + if (aBaseFeature) + isFullyRemoved = removeEntity(aBaseFeature) && isFullyRemoved; + else + isFullyRemoved = removeEntity(aSubEntity->baseAttribute()) && isFullyRemoved; + } + + std::list::const_iterator aParIt = anEntity->parameters().begin(); + for (; aParIt != anEntity->parameters().end(); ++aParIt) + isFullyRemoved = remove(*aParIt) && isFullyRemoved; + return isFullyRemoved; +} + +bool SolveSpaceSolver_Storage::remove(ParameterWrapperPtr theParameter) +{ + return removeParameter((Slvs_hParam)theParameter->id()); +} + + +void SolveSpaceSolver_Storage::refresh(bool theFixedOnly) const +{ + blockEvents(true); + + std::map::const_iterator anIt = myAttributeMap.begin(); + std::list aParams; + std::list::const_iterator aParIt; + for (; anIt != myAttributeMap.end(); ++anIt) { + // update parameter wrappers and obtain values of attributes + aParams = anIt->second->parameters(); + double aCoords[3]; + bool isUpd[3] = {false}; + int i = 0; + for (aParIt = aParams.begin(); i < 3 && aParIt != aParams.end(); ++aParIt, ++i) { + std::shared_ptr aWrapper = + std::dynamic_pointer_cast(*aParIt); + if (!theFixedOnly || aWrapper->group() == GID_OUTOFGROUP || aWrapper->isParametric()) { + aWrapper->changeParameter().val = getParameter((Slvs_hParam)aWrapper->id()).val; + aCoords[i] = aWrapper->value(); + isUpd[i] = true; + } + } + if (!isUpd[0] && !isUpd[1] && !isUpd[2]) + continue; // nothing is updated + + std::shared_ptr aPoint2D = + std::dynamic_pointer_cast(anIt->first); + if (aPoint2D) { + if ((isUpd[0] && fabs(aPoint2D->x() - aCoords[0]) > tolerance) || + (isUpd[1] && fabs(aPoint2D->y() - aCoords[1]) > tolerance)) { + if (!isUpd[0]) aCoords[0] = aPoint2D->x(); + if (!isUpd[1]) aCoords[1] = aPoint2D->y(); + aPoint2D->setValue(aCoords[0], aCoords[1]); + // Find points coincident with this one (probably not in GID_OUTOFGROUP) + std::map::const_iterator aLocIt = + theFixedOnly ? myAttributeMap.begin() : anIt; + for (++aLocIt; aLocIt != myAttributeMap.end(); ++aLocIt) + if (anIt->second->id() == aLocIt->second->id()) { + aPoint2D = std::dynamic_pointer_cast(aLocIt->first); + aPoint2D->setValue(aCoords[0], aCoords[1]); + } + } + continue; + } + AttributeDoublePtr aScalar = std::dynamic_pointer_cast(anIt->first); + if (aScalar) { + if (isUpd[0] && fabs(aScalar->value() - aCoords[0]) > tolerance) + aScalar->setValue(aCoords[0]); + continue; + } + std::shared_ptr aPoint = + std::dynamic_pointer_cast(anIt->first); + if (aPoint) { + if ((isUpd[0] && fabs(aPoint->x() - aCoords[0]) > tolerance) || + (isUpd[1] && fabs(aPoint->y() - aCoords[1]) > tolerance) || + (isUpd[2] && fabs(aPoint->z() - aCoords[2]) > tolerance)) + if (!isUpd[0]) aCoords[0] = aPoint->x(); + if (!isUpd[1]) aCoords[1] = aPoint->y(); + if (!isUpd[2]) aCoords[2] = aPoint->z(); + aPoint->setValue(aCoords[0], aCoords[1], aCoords[2]); + continue; + } + } + + blockEvents(false); +} + +void SolveSpaceSolver_Storage::verifyFixed() +{ + std::map::iterator anAttrIt = myAttributeMap.begin(); + for (; anAttrIt != myAttributeMap.end(); ++anAttrIt) { + const std::list& aParameters = anAttrIt->second->parameters(); + std::list::const_iterator aParIt = aParameters.begin(); + for (; aParIt != aParameters.end(); ++aParIt) + if ((*aParIt)->group() == GID_OUTOFGROUP) { + Slvs_Param aParam = getParameter((Slvs_hParam)(*aParIt)->id()); + if (aParam.group != (Slvs_hParam)GID_OUTOFGROUP) { + aParam.group = (Slvs_hParam)GID_OUTOFGROUP; + updateParameter(aParam); + } + } + } +} + + +void SolveSpaceSolver_Storage::adjustArc(const Slvs_Entity& theArc) +{ + double anArcPoints[3][2]; + double aDist[3] = {0.0}; + bool isFixed[3] = {false}; + for (int i = 0; i < 3; ++i) { + Slvs_Entity aPoint = getEntity(theArc.point[i]); + isFixed[i] = (aPoint.group != (Slvs_hGroup)myGroupID); + anArcPoints[i][0] = getParameter(aPoint.param[0]).val; + anArcPoints[i][1] = getParameter(aPoint.param[1]).val; + if (i > 0) { + anArcPoints[i][0] -= anArcPoints[0][0]; + anArcPoints[i][1] -= anArcPoints[0][1]; + aDist[i] = sqrt(anArcPoints[i][0] * anArcPoints[i][0] + + anArcPoints[i][1] * anArcPoints[i][1]); + } + } + + if (fabs(aDist[1] - aDist[2]) < tolerance) + return; + + int anInd = 2; + while (anInd > 0 && isFixed[anInd]) + --anInd; + if (anInd < 1) + return; // adjust only start or end point of the arc + + anArcPoints[anInd][0] /= aDist[anInd]; + anArcPoints[anInd][1] /= aDist[anInd]; + + Slvs_Entity aPoint = getEntity(theArc.point[anInd]); + for (int i = 0; i < 2; ++i) { + Slvs_Param aParam = getParameter(aPoint.param[i]); + aParam.val = anArcPoints[0][i] + aDist[3-anInd] * anArcPoints[anInd][i]; + updateParameter(aParam); + } +} + + + + + + + +// ======================================================== +// ========= Auxiliary functions =============== +// ======================================================== + +template +int Search(const uint32_t& theEntityID, const std::vector& theEntities) +{ + int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0; + int aVecSize = theEntities.size(); + if (theEntities.empty()) + return 1; + while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID) + aResIndex--; + while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID) + aResIndex++; + if (aResIndex == -1 || (aResIndex < aVecSize && theEntities[aResIndex].h != theEntityID)) + aResIndex = aVecSize; + return aResIndex; +} + +bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2) +{ + return fabs(theParam1.val - theParam2.val) > tolerance; +} + +bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2) +{ + int i = 0; + for (; theEntity1.param[i] != 0 && i < 4; i++) + if (theEntity1.param[i] != theEntity2.param[i]) + return true; + i = 0; + for (; theEntity1.point[i] != 0 && i < 4; i++) + if (theEntity1.point[i] != theEntity2.point[i]) + return true; + return false; +} + +bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2) +{ + return theConstraint1.ptA != theConstraint2.ptA || + theConstraint1.ptB != theConstraint2.ptB || + theConstraint1.entityA != theConstraint2.entityA || + theConstraint1.entityB != theConstraint2.entityB || + theConstraint1.entityC != theConstraint2.entityC || + theConstraint1.entityD != theConstraint2.entityD || + fabs(theConstraint1.valA - theConstraint2.valA) > tolerance; +} diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Storage.h b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Storage.h new file mode 100644 index 000000000..7136648b1 --- /dev/null +++ b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Storage.h @@ -0,0 +1,280 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SolveSpaceSolver_Storage.h +// Created: 18 Mar 2015 +// Author: Artem ZHIDKOV + +#ifndef SolveSpaceSolver_Storage_H_ +#define SolveSpaceSolver_Storage_H_ + +#include +#include + +#include +#include +#include +#include + +typedef std::map > CoincidentPointsMap; +typedef std::list< std::set > SameConstraintMap; + +/** \class SolveSpaceSolver_Storage + * \ingroup Plugins + * \brief Contains all necessary data in SolveSpace format to solve a single group of constraints + */ +class SolveSpaceSolver_Storage : public SketchSolver_Storage +{ +public: + SolveSpaceSolver_Storage(const GroupID& theGroup); + +// ============= Inherited from SketchSolver_Storage ============= + + /// \brief Update constraint's data + /// \return \c true if any value is updated + virtual bool update(ConstraintWrapperPtr& theConstraint); + /// \brief Update entity's data + /// \return \c true if any value is updated + virtual bool update(EntityWrapperPtr& theEntity); + /// \brief Update parameter's data + /// \return \c true if the value of parameter is updated + virtual bool update(ParameterWrapperPtr& theParameter); + + /// \brief Removes constraint from the storage + /// \return \c true if the constraint and all its parameters are remove successfully + virtual bool removeConstraint(ConstraintPtr theConstraint); + /// \brief Removes feature from the storage + /// \return \c true if the feature and its attributes are removed successfully; + /// \c false if the feature or any it attribute is used by remaining constraints. + virtual bool removeEntity(FeaturePtr theFeature); + /// \brief Removes attribute from the storage + /// \return \c true if the attribute is not used by remaining features and constraints + virtual bool removeEntity(AttributePtr theAttribute); + + /// \brief Update SketchPlugin features after resolving constraints + /// \param theFixedOnly [in] if \c true the fixed points will be updated only + virtual void refresh(bool theFixedOnly = false) const; + + /// \brief Check if some parameters or entities are returned + /// to the current group after removing temporary constraints + virtual void verifyFixed(); + + /// \brief Mark two points as coincident + virtual void addCoincidentPoints(EntityWrapperPtr theMaster, EntityWrapperPtr theSlave); + + /// \brief Calculate point on theBase entity. Value theCoeff is in [0.0 .. 1.0] and + /// shows the distance from the start point. + virtual EntityWrapperPtr calculateMiddlePoint(EntityWrapperPtr theBase, double theCoeff); + +protected: + /// \brief Remove constraint + /// \return \c true if the constraint and all its parameters are removed successfully + virtual bool remove(ConstraintWrapperPtr theConstraint); + /// \brief Remove entity + /// \return \c true if the entity and all its parameters are removed successfully + virtual bool remove(EntityWrapperPtr theEntity); + /// \brief Remove parameter + /// \return \c true if the parameter has been removed + virtual bool remove(ParameterWrapperPtr theParameter); + + /// \brief Update the group for the given entity, its sub-entities and parameters + virtual void changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup); + /// \brief Update the group for the given parameter + virtual void changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup); + + +// ============= Own methods ============= +public: + /// \brief Obtain and store identifier of sketch + void storeWorkplane(EntityWrapperPtr theSketch); + + /** \brief Add new parameter to the current group + * \param[in] theParam SolveSpace parameter + * \return the ID of added parameter + */ + Slvs_hParam addParameter(const Slvs_Param& theParam); + /** \brief Updates parameter in the current group. If the ID of parameter is zero, the new item will be added + * \param[in] theParam SolveSpace parameter + * \return the ID of updated/added parameter + */ + Slvs_hParam updateParameter(const Slvs_Param& theParam); + /** \brief Removes the parameter by its ID + * \param[in] theParamID index of parameter to be removed + * \return \c true if the parameter was successfully removed + */ + bool removeParameter(const Slvs_hParam& theParamID); + /// \brief Returns the parameter by its ID + const Slvs_Param& getParameter(const Slvs_hParam& theParamID) const; + + /** \brief Add new entity to the current group + * \param[in] theEntity SolveSpace entity + * \return the ID of added entity + */ + Slvs_hEntity addEntity(const Slvs_Entity& theEntity); + /** \brief Updates entity in the current group. If the ID of entity is zero, the new item will be added + * \param[in] theEntity SolveSpace entity + * \return the ID of updated/added entity + */ + Slvs_hEntity updateEntity(const Slvs_Entity& theEntity); + /** \brief Removes the entity by its ID. All parameters used in this entity, + * and not used in other constraints, will be removed too. + * \param[in] theEntityID index of entity to be removed + * \return \c true if the entity was successfully removed + */ + bool removeEntity(const Slvs_hEntity& theEntityID); + /** \brief Remove all entities, which are not used in constraints + */ + void removeUnusedEntities(); + /// \brief Returns the entity by its ID + const Slvs_Entity& getEntity(const Slvs_hEntity& theEntityID) const; + /// \brief Makes a full copy of the given entity + Slvs_hEntity copyEntity(const Slvs_hEntity& theCopied); + /// \brief Copy one entity to another + void copyEntity(const Slvs_hEntity& theFrom, const Slvs_hEntity& theTo); + /// \brief Check the entity is used in constraints + bool isUsedByConstraints(const Slvs_hEntity& theEntityID) const; + /// \brief Returns maximal ID of entities in this storage + const Slvs_hEntity& entityMaxID() const + { return myEntityMaxID; } + + /// \brief Verifies the current point or another coincident one is fixed + /// \param[in] thePointID entity to be checked fixed + /// \param[out] theFixed ID of constraint + /// \param[in] theAccurate if \c true, the calculation will be made for all type of constraints, + /// if \c false, only the point is verified + /// \return \c true if the point is fixed + bool isPointFixed(const Slvs_hEntity& thePointID, Slvs_hConstraint& theFixed, bool theAccurate = false) const; + /// \brief Verifies the current entity is fully fixed (may not be changed by constraints) + /// \param[in] theEntityID entity to be checked fixed + /// \param[in] theAccurate if \c true, the calculation will be made for all type of constraints, + /// if \c false, only points are verified + /// \return \c true if the entity is fixed + bool isEntityFixed(const Slvs_hEntity& theEntityID, bool theAccurate = false) const; + + /** \brief Add new constraint to the current group + * \param[in] theConstraint SolveSpace's constraint + * \return the ID of added constraint + */ + Slvs_hConstraint addConstraint(const Slvs_Constraint& theConstraint); + /** \brief Updates constraint in the current group. + * If the ID of constraint is zero, the new item will be added + * \param[in] theConstraint SolveSpace constraint + * \return the ID of updated/added constraint + */ + Slvs_hConstraint updateConstraint(const Slvs_Constraint& theConstraint); + /** \brief Removes the constraint by its ID. All entities and parameters depending on this + * constraint, which are not used in other constraints, will be removed too. + * \param[in] theConstraintID index of constraint to be removed + * \return \c true if the constraint was successfully removed + */ + bool removeConstraint(const Slvs_hConstraint& theConstraintID); + /// \brief Returns the constraint by its ID + const Slvs_Constraint& getConstraint(const Slvs_hConstraint& theConstraintID) const; + /// \brief Returns list of constraints of specified type + std::list getConstraintsByType(int theConstraintType) const; + /// \brief Returns quantity of constraints in this storage + size_t nbConstraints() const + { return myConstraints.size(); } + + /// \brief Attach constraint SLVS_C_WHERE_DRAGGED to this storage. It need to make precise calculations + void addConstraintWhereDragged(const Slvs_hConstraint& theConstraintID); + + /// \brief Add transient constraint + void addTemporaryConstraint(const Slvs_hConstraint& theConstraintID); + /// \brief Mark specified constraint as temporary + virtual void setTemporary(ConstraintPtr theConstraint); + /// \brief Remove all transient constraints + void removeAllTemporary(); + /// \brief Remove temporary constraint s. Preferable to remove the points under Point-on-Line constraint + /// \param theNbConstraints [in] number of temporary constraints to be deleted + /// \return Number of remaining temporary constraints + virtual size_t removeTemporary(size_t theNbConstraints); + /// \brief Checks the constraint is temporary + bool isTemporary(const Slvs_hConstraint& theConstraintID) const; + /// \brief Number of temporary constraints + virtual size_t nbTemporary() const + { return myTemporaryConstraints.size(); } + + /// \brief Shows the storage has the same constraint twice + virtual bool hasDuplicatedConstraint() const + { return myDuplicatedConstraint; } + + /// \brief Initialize constraint solver by the entities collected by current storage + virtual void initializeSolver(SolverPtr theSolver); + +public: + /// \brief Check two points are coincident or have same coordinates + bool isEqual(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const; + + /// \brief Check the entity is horizontal of vertical + bool isAxisParallel(const Slvs_hEntity& theEntity) const; + + /// \brief Verifies the entity is used in any equal constraint + /// \param[in] theEntity entity to be found + /// \param[out] theEqual constraint, which uses the entity + /// \return \c true, if the Equal constrait is found + bool isUsedInEqual(const Slvs_hEntity& theEntity, Slvs_Constraint& theEqual) const; + + /// \brief Fixes specified entity + /// \param theEntity ID of the entity to be fixed + /// \return List of created constraints + std::vector fixEntity(const Slvs_hEntity& theEntity); + +private: + /// \brief Fixes specified point + /// \param [in] thePoint point to be fixed + /// \param [out] theCreated list of the Fixed constraints created + void fixPoint(const Slvs_Entity& thePoint, std::vector& theCreated); + /// \brief Fixes specified line + /// \param [in] theLine line to be fixed + /// \param [out] theCreated list of the Fixed constraints created + void fixLine(const Slvs_Entity& theLine, std::vector& theCreated); + /// \brief Fixes specified circle + /// \param [in] theCircle circle to be fixed + /// \param [out] theCreated list of the Fixed constraints created + void fixCircle(const Slvs_Entity& theCircle, std::vector& theCreated); + /// \brief Fixes specified arc + /// \param [in] theArc arc to be fixed + /// \param [out] theCreated list of the Fixed constraints created + void fixArc(const Slvs_Entity& theArc, std::vector& theCreated); + + /// \brief Update arc points to be on circle sharp. + void adjustArc(const Slvs_Entity& theArc); + + /// \brief Verify the feature or any its attribute is used by constraint + bool isUsed(FeaturePtr theFeature) const; + /// \brief Verify the attribute is used by constraint + bool isUsed(AttributePtr theAttirubute) const; + + /// \brief Replace sub-entity theSource in all features by theDest + void replaceInFeatures(EntityWrapperPtr theSource, EntityWrapperPtr theDest); + /// \brief Replace constrained entity theSource by theDest in all constraints; + void replaceInConstraints(EntityWrapperPtr theSource, EntityWrapperPtr theDest); + + /// \brief Add pair of constraints which have same representation in SolveSpace notation. + /// + /// These constraints may be different and become the same after the substitution + /// of point coincidence. + void addSameConstraints(ConstraintWrapperPtr theConstraint1, ConstraintWrapperPtr theConstraint2); + +private: + Slvs_hEntity myWorkplaneID; ///< identifier of workplane + + 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 (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 (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 (sorted by the identifier) + + CoincidentPointsMap myCoincidentPoints; ///< lists of coincident points (first is a master point, second is a set of slaves) + Slvs_hConstraint myFixed; ///< identifier of one of temporary constraints to fix separate point + + bool myDuplicatedConstraint; ///< shows the storage has same constraint twice + + std::set myTemporaryConstraints; ///< list of transient constraints + std::set myUpdatedParameters; ///< list of just updated parameters (cleared when isNeedToResolve() called) + + SameConstraintMap myEqualConstraints; ///< list of groups of equal constraints +}; + +#endif -- 2.39.2