From: azv Date: Tue, 15 Dec 2015 08:48:27 +0000 (+0300) Subject: Revert "First phase of SketchSolver refactoring" X-Git-Tag: V_2.1.0~183 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=8f10db487ef409d859a62aa6e2235a17d9b56723;p=modules%2Fshaper.git Revert "First phase of SketchSolver refactoring" This reverts commit 7beb3c7ae26709576c42b01255e2530fc866c1fa. --- diff --git a/src/Config/plugins.xml b/src/Config/plugins.xml index 45903311b..a8b4b2315 100644 --- a/src/Config/plugins.xml +++ b/src/Config/plugins.xml @@ -12,7 +12,7 @@ - + diff --git a/src/SketchSolver/CMakeLists.txt b/src/SketchSolver/CMakeLists.txt index 79094bf2f..126fb212e 100644 --- a/src/SketchSolver/CMakeLists.txt +++ b/src/SketchSolver/CMakeLists.txt @@ -1,56 +1,60 @@ ## 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_ConstraintFixed.h + SketchSolver_ConstraintRigid.h SketchSolver_ConstraintTangent.h SketchSolver_ConstraintMulti.h SketchSolver_ConstraintMultiRotation.h SketchSolver_ConstraintMultiTranslation.h SketchSolver_ConstraintMovement.h -# SketchSolver_ConstraintParametric.h - SketchSolver_Group.h + SketchSolver_ConstraintParametric.h SketchSolver_Builder.h - SketchSolver_IConstraintWrapper.h - SketchSolver_IEntityWrapper.h - SketchSolver_IParameterWrapper.h - SketchSolver_ISolver.h - SketchSolver_Manager.h + SketchSolver_Group.h + SketchSolver_ConstraintManager.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_ConstraintFixed.cpp + SketchSolver_ConstraintRigid.cpp SketchSolver_ConstraintTangent.cpp SketchSolver_ConstraintMulti.cpp SketchSolver_ConstraintMultiRotation.cpp SketchSolver_ConstraintMultiTranslation.cpp + SketchSolver_ConstraintParametric.cpp SketchSolver_ConstraintMovement.cpp -# SketchSolver_ConstraintParametric.cpp - SketchSolver_Group.cpp SketchSolver_Builder.cpp - SketchSolver_Manager.cpp + SketchSolver_Group.cpp + SketchSolver_ConstraintManager.cpp SketchSolver_Storage.cpp + SketchSolver_FeatureStorage.cpp ) SET(PROJECT_LIBRARIES + ${SOLVESPACE_LIBRARIES} Config Events ModelAPI @@ -58,6 +62,7 @@ SET(PROJECT_LIBRARIES ) INCLUDE_DIRECTORIES( + ${SOLVESPACE_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/src/Config ${PROJECT_SOURCE_DIR}/src/SketchPlugin ${PROJECT_SOURCE_DIR}/src/ModelAPI @@ -68,30 +73,10 @@ INCLUDE_DIRECTORIES( ADD_DEFINITIONS(-DSKETCHSOLVER_EXPORTS) -ADD_LIBRARY(SketchSolver SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS} +ADD_LIBRARY(SketchSolver MODULE ${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 56fa1dba2..cc5013f6e 100644 --- a/src/SketchSolver/SketchSolver.h +++ b/src/SketchSolver/SketchSolver.h @@ -3,8 +3,6 @@ #ifndef SKETCHSOLVER_H #define SKETCHSOLVER_H -#include - #if defined SKETCHSOLVER_EXPORTS #if defined WIN32 #define SKETCHSOLVER_EXPORT __declspec( dllexport ) @@ -24,18 +22,4 @@ 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 323bdb056..78bfc59bb 100644 --- a/src/SketchSolver/SketchSolver_Builder.cpp +++ b/src/SketchSolver/SketchSolver_Builder.cpp @@ -5,53 +5,66 @@ // 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 -#ifdef _DEBUG +#include +#include +#include +#include #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 #include #include +#include +#include +#include #include #include +#include #include #include #include -SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theConstraint) const +// 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 aResult; DataPtr aData = theConstraint->data(); @@ -93,14 +106,26 @@ 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_ConstraintFixed(theConstraint)); + return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theConstraint)); } else if (theConstraint->getKind() == SketchPlugin_MultiTranslation::ID()) { return SolverConstraintPtr(new SketchSolver_ConstraintMultiTranslation(theConstraint)); } else if (theConstraint->getKind() == SketchPlugin_MultiRotation::ID()) { @@ -108,19 +133,18 @@ SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theCons } else if (theConstraint->getKind() == SketchPlugin_ConstraintAngle::ID()) { return SolverConstraintPtr(new SketchSolver_ConstraintAngle(theConstraint)); } - // All other types of constraints - return SolverConstraintPtr(new SketchSolver_Constraint(theConstraint)); + return aResult; } -SolverConstraintPtr SketchSolver_Builder::createFixedConstraint(FeaturePtr theFixedFeature) const +SolverConstraintPtr SketchSolver_Builder::createRigidConstraint(FeaturePtr theFixedFeature) { DataPtr aData = theFixedFeature->data(); if (!aData || !aData->isValid()) return SolverConstraintPtr(); - return SolverConstraintPtr(new SketchSolver_ConstraintFixed(theFixedFeature)); + return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theFixedFeature)); } -SolverConstraintPtr SketchSolver_Builder::createMovementConstraint(FeaturePtr theFixedFeature) const +SolverConstraintPtr SketchSolver_Builder::createMovementConstraint(FeaturePtr theFixedFeature) { DataPtr aData = theFixedFeature->data(); if (!aData || !aData->isValid()) @@ -128,40 +152,185 @@ SolverConstraintPtr SketchSolver_Builder::createMovementConstraint(FeaturePtr th return SolverConstraintPtr(new SketchSolver_ConstraintMovement(theFixedFeature)); } -////SolverConstraintPtr SketchSolver_Builder::createParametricConstraint(AttributePtr theAttribute) -////{ -//// return SolverConstraintPtr(new SketchSolver_ConstraintParametric(theAttribute)); -////} +SolverConstraintPtr SketchSolver_Builder::createParametricConstraint(AttributePtr theAttribute) +{ + return SolverConstraintPtr(new SketchSolver_ConstraintParametric(theAttribute)); +} + + + +bool SketchSolver_Builder::createWorkplane( + CompositeFeaturePtr theSketch, + std::vector& theEntities, + std::vector& theParameters) +{ + 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; -std::shared_ptr SketchSolver_Builder::point(EntityWrapperPtr theEntity) const + // 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; +} + +bool SketchSolver_Builder::createEntity( + AttributePtr theAttribute, + std::vector& theEntities, + std::vector& theParameters) { - 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])); + 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; } -std::shared_ptr SketchSolver_Builder::line(EntityWrapperPtr theEntity) const +bool SketchSolver_Builder::createEntity( + FeaturePtr theFeature, + std::vector& theEntities, + std::vector& theParameters) { - 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])); + 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 ebac79ffd..21beac319 100644 --- a/src/SketchSolver/SketchSolver_Builder.h +++ b/src/SketchSolver/SketchSolver_Builder.h @@ -7,112 +7,74 @@ #ifndef SketchSolver_Builder_H_ #define SketchSolver_Builder_H_ +#include "SketchSolver.h" #include + #include -#include -#include +#include /** \class SketchSolver_Builder * \ingroup Plugins - * \brief Abstract class for builders of solver's entities + * \brief Create bridges between SketchPlugin constraints and SolveSpace constraints */ class SketchSolver_Builder { +private: + /// Default constructor + SketchSolver_Builder() {} + public: - /// \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 Returns single instance of builder + static SketchSolver_Builder* getInstance(); /// \brief Creates a solver's constraint using given SketchPlugin constraint /// or returns empty pointer if not all attributes are correct - SolverConstraintPtr createConstraint(ConstraintPtr theConstraint) const; + SolverConstraintPtr createConstraint(ConstraintPtr theConstraint); /// \brief Creates temporary constraint to fix the placement of the feature - SolverConstraintPtr createFixedConstraint(FeaturePtr theFixedFeature) const; + SolverConstraintPtr createRigidConstraint(FeaturePtr theFixedFeature); /// \brief Creates temporary constraint to fix the feature after movement - SolverConstraintPtr createMovementConstraint(FeaturePtr theFixedFeature) const; - -//// /// \brief Creates constraint for parametrically given attribute -//// SolverConstraintPtr createParametricConstraint(AttributePtr theAttribute) 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; + 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; }; -typedef std::shared_ptr BuilderPtr; - #endif diff --git a/src/SketchSolver/SketchSolver_Constraint.cpp b/src/SketchSolver/SketchSolver_Constraint.cpp index 4792c51ff..b4b888fa3 100644 --- a/src/SketchSolver/SketchSolver_Constraint.cpp +++ b/src/SketchSolver/SketchSolver_Constraint.cpp @@ -1,27 +1,12 @@ #include #include #include -#include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include #include #include @@ -33,188 +18,303 @@ SketchSolver_Constraint::SketchSolver_Constraint( ConstraintPtr theConstraint) : myBaseConstraint(theConstraint), - myGroupID(GID_UNKNOWN), - myType(CONSTRAINT_UNKNOWN) + myGroup(0) { } -void SketchSolver_Constraint::process(StoragePtr theStorage, - const GroupID& theGroupID, - const EntityID& theSketchID) +SketchSolver_Constraint::~SketchSolver_Constraint() +{ + 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) { myStorage = theStorage; - myGroupID = theGroupID; - mySketchID = theSketchID; - // Process constraint according to its type process(); } +void SketchSolver_Constraint::setGroup(SketchSolver_Group* theGroup) +{ + myGroup = theGroup; + process(); +} -SketchSolver_ConstraintType SketchSolver_Constraint::TYPE(ConstraintPtr theConstraint) +void SketchSolver_Constraint::addFeature(FeaturePtr theFeature) { - 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; + int aType; + changeEntity(theFeature, aType); } + void SketchSolver_Constraint::process() { cleanErrorMsg(); - if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) { - // Not enough parameters are assigned + if (!myBaseConstraint || !myStorage || myGroup == 0) { + /// TODO: Put error message here return; } -//// if (!myConstraints.empty()) // some data is changed, update constraint -//// update(); + if (!mySlvsConstraints.empty()) // some data is changed, update constraint + update(myBaseConstraint); - SketchSolver_ConstraintType aConstrType = getType(); - double aValue; - std::vector anAttributes; + int aConstrType = getType(); + double aValue = 0.0; + std::vector anAttributes; getAttributes(aValue, anAttributes); if (!myErrorMsg.empty()) return; - if (anAttributes.empty()) { - myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); - return; - } - if (aConstrType == CONSTRAINT_UNKNOWN) + if (aConstrType == SLVS_C_UNKNOWN) aConstrType = getType(); - 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_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; + } + 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() +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) { 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; + } - std::list aWrapper = myStorage->constraint(myBaseConstraint); - AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::VALUE())); - if (aValueAttr) { - std::list::iterator aWIt = aWrapper.begin(); - for (; aWIt != aWrapper.end(); ++aWIt) - (*aWIt)->setValue(aValueAttr->value()); + // 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; } - myStorage->addConstraint(myBaseConstraint, aWrapper); + // Value if exists + DataPtr aData = myBaseConstraint->data(); + if (!aData) return; + 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); + } adjustConstraint(); } -bool SketchSolver_Constraint::remove() +bool SketchSolver_Constraint::remove(ConstraintPtr theConstraint) { cleanErrorMsg(); - return myStorage->removeConstraint(myBaseConstraint); + 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--; + } } void SketchSolver_Constraint::getAttributes( double& theValue, - std::vector& theAttributes) + std::vector& theAttributes) { static const int anInitNbOfAttr = 4; - theAttributes.assign(anInitNbOfAttr, EntityWrapperPtr()); + theAttributes.assign(anInitNbOfAttr, SLVS_E_UNKNOWN); 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 entity in the list of attributes + int aEntInd = 2; // index of first antity in the list of attributes std::list aConstrAttrs = aData->attributes(ModelAPI_AttributeRefAttr::typeId()); std::list::iterator anIter = aConstrAttrs.begin(); for (; anIter != aConstrAttrs.end(); anIter++) { @@ -225,13 +325,18 @@ void SketchSolver_Constraint::getAttributes( return; } - myStorage->update(*anIter, myGroupID); - EntityWrapperPtr anEntity = myStorage->entity(*anIter); + 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; + } - SketchSolver_EntityType aType = anEntity->type(); - if (aType == ENTITY_UNKNOWN) + if (aType == SLVS_E_UNKNOWN) continue; - else if (aType == ENTITY_POINT) + else if (aType == SLVS_E_POINT_IN_2D || aType == SLVS_E_POINT_IN_3D) theAttributes[aPtInd++] = anEntity; // the point is created else { // another entity (not a point) is created if (aEntInd < anInitNbOfAttr) @@ -243,415 +348,403 @@ void SketchSolver_Constraint::getAttributes( } } -bool SketchSolver_Constraint::isUsed(FeaturePtr theFeature) const +Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributeRefAttrPtr theAttribute, int& theType) { - 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; - - 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; + // 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 false; + return changeEntity(aFeature, theType); + } + + return changeEntity(theAttribute->attr(), theType); +} + +Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributePtr theEntity, int& theType) +{ + Slvs_hEntity aResult = SLVS_E_UNKNOWN; + if (!theEntity || !isInitialized(theEntity)) { + myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); + return SLVS_E_UNKNOWN; + } + + // 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; + } + } + + 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; } -bool SketchSolver_Constraint::isUsed(AttributePtr theAttribute) const +Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& theType) { - 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(); + 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; +} - 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; +std::list SketchSolver_Constraint::constraints() const +{ + std::list aConstraints; + aConstraints.push_back(myBaseConstraint); + return aConstraints; +} + +void SketchSolver_Constraint::refresh() +{ + 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++; + } + + 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(); return false; } -////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) -////{ -//// Slvs_hEntity aResult = SLVS_E_UNKNOWN; -//// if (!theEntity || !isInitialized(theEntity)) { -//// myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); -//// return SLVS_E_UNKNOWN; -//// } -//// -//// // 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; -//// } -//// } -//// -//// 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; -////} -//// -////bool SketchSolver_Constraint::hasConstraint(ConstraintPtr theConstraint) const -////{ -//// std::list::const_iterator anIt = myConstraints.begin(); -//// for (; anIt != myConstraints.end(); ++anIt) -//// if (*anIt == theConstraint) -//// return true; -//// return false; -////} -//// -////void SketchSolver_Constraint::refresh() -////{ -//// 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++; -//// } -//// -//// 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); -//// } -//// } -////} - -////bool SketchSolver_Constraint::isInitialized(AttributePtr theAttribute) -////{ -//// if (theAttribute->isInitialized()) -//// return true; -//// myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); -//// 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::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 { - myStorage->setTemporary(myBaseConstraint); + std::vector::const_iterator anIt = mySlvsConstraints.begin(); + for (; anIt != mySlvsConstraints.end(); anIt++) + myStorage->addTemporaryConstraint(*anIt); } diff --git a/src/SketchSolver/SketchSolver_Constraint.h b/src/SketchSolver/SketchSolver_Constraint.h index d1ea3e1b5..974143246 100644 --- a/src/SketchSolver/SketchSolver_Constraint.h +++ b/src/SketchSolver/SketchSolver_Constraint.h @@ -18,193 +18,218 @@ #include #include +class SketchSolver_Group; + /** \class SketchSolver_Constraint * \ingroup Plugins - * \brief Converts SketchPlugin constraint to the constraint applicable for solver + * \brief Stores mapping between SketchPlugin and SolveSpace constraints data */ class SketchSolver_Constraint { protected: /// Default constructor - SketchSolver_Constraint() - : myGroupID(GID_UNKNOWN), - myType(CONSTRAINT_UNKNOWN) - {} - -public: + SketchSolver_Constraint() {} /// Constructor based on SketchPlugin constraint - SKETCHSOLVER_EXPORT SketchSolver_Constraint(ConstraintPtr theConstraint); + SketchSolver_Constraint(ConstraintPtr theConstraint); - virtual ~SketchSolver_Constraint() {} +public: + virtual ~SketchSolver_Constraint(); - /// \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 Initializes the storage of SolveSpace constraints + void setStorage(StoragePtr theStorage); + /// \brief Initializes group ID for this constraint + void setGroup(SketchSolver_Group* theGroup); /// \brief Update constraint - SKETCHSOLVER_EXPORT virtual void update(); + 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) - SKETCHSOLVER_EXPORT virtual bool remove(); + virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr()); - /// \brief Obtain a type of SketchPlugin constraint - SKETCHSOLVER_EXPORT static SketchSolver_ConstraintType TYPE(ConstraintPtr theConstraint); + /// \brief Update SketchPlugin attributes using the data obtained from SolveSpace entities + virtual void refresh(); /// \brief Returns the type of constraint -//// virtual SketchSolver_ConstraintType getType() const = 0; - virtual SketchSolver_ConstraintType getType() const - { return myType; } + virtual int getType() const = 0; /// \brief The constraint is made temporary void makeTemporary() const; - /// \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 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 Checks the constraint is used by current object -//// SKETCHSOLVER_EXPORT virtual bool hasConstraint(ConstraintPtr theConstraint) const; -//// -//// /// \brief Return list of SketchPlugin constraints attached to this object -//// virtual const std::list& constraints() const -//// { return myConstraints; } + /// \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 Shows error message const std::string& error() const { return myErrorMsg; } protected: - /// \brief Converts SketchPlugin constraint to a list of solver's constraints + /// \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 + /// \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); -//// /// \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 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 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(); } -protected: - 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 +private: + /// \brief Sets error, if the attribute is not initialized + bool isInitialized(AttributePtr theAttribute); - std::string myErrorMsg; ///< error message +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) -//// {} -//// -//// virtual int getType() const -//// { return SLVS_C_PERPENDICULAR; } -////}; -//// -//// -/////** \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); -//// } -////}; +/** \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) + {} + + virtual int getType() const + { return SLVS_C_PERPENDICULAR; } +}; + + +/** \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); + } +}; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintAngle.cpp b/src/SketchSolver/SketchSolver_ConstraintAngle.cpp index 903805060..10dbae165 100644 --- a/src/SketchSolver/SketchSolver_ConstraintAngle.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintAngle.cpp @@ -1,5 +1,4 @@ #include -#include #include #include @@ -9,7 +8,7 @@ #include void SketchSolver_ConstraintAngle::getAttributes( - double& theValue, std::vector& theAttributes) + double& theValue, std::vector& theAttributes) { SketchSolver_Constraint::getAttributes(theValue, theAttributes); @@ -20,31 +19,25 @@ void SketchSolver_ConstraintAngle::getAttributes( void SketchSolver_ConstraintAngle::adjustConstraint() { static const double aTol = 1000. * tolerance; - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - - ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front(); - if (fabs(myAngle - aConstraint->value()) < aTol) - return; - myAngle = aConstraint->value(); - -//// Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front()); + Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front()); bool isFixed[2][2]; 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) { - isFixed[i][j] = ((*aLPIt)->group() != myGroupID); - aPoints[i][j] = aBuilder->point(*aLPIt); + 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])); } } - 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])) @@ -82,17 +75,20 @@ 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 + 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 @@ -128,18 +124,15 @@ void SketchSolver_ConstraintAngle::adjustConstraint() } // Update positions of points - 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]); + 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); } - - aBuilder->adjustConstraint(aConstraint); - myStorage->addConstraint(myBaseConstraint, aConstraint); } diff --git a/src/SketchSolver/SketchSolver_ConstraintAngle.h b/src/SketchSolver/SketchSolver_ConstraintAngle.h index 3e979aa6d..4d91aced4 100644 --- a/src/SketchSolver/SketchSolver_ConstraintAngle.h +++ b/src/SketchSolver/SketchSolver_ConstraintAngle.h @@ -22,14 +22,17 @@ 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 constraints + /// \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); private: double myAngle; diff --git a/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp b/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp index d2bd86a99..e1242606e 100644 --- a/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp @@ -1,36 +1,41 @@ #include #include -#include +#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]) { - theAttributes.clear(); + if (!myErrorMsg.empty() || theAttributes[0] == SLVS_E_UNKNOWN) return; - } - 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]); + 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); + } } - else if (theAttributes[2]) { + else if (theAttributes[2] != SLVS_E_UNKNOWN) { // check the type of entity (line or 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; + 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; else myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); } else @@ -38,364 +43,339 @@ void SketchSolver_ConstraintCoincidence::getAttributes( } -static bool isBase(const std::list& theConstraints, AttributePtr theAttribute) +bool SketchSolver_ConstraintCoincidence::hasConstraint(ConstraintPtr theConstraint) const { - 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(); + 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) +{ + 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; + } + } } - 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; + // 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()); } - return false; } -////bool SketchSolver_ConstraintCoincidence::isCoincide( -//// std::shared_ptr theConstraint) const -////{ -//// std::list::const_iterator anOtherCIt = theConstraint->myConstraints.begin(); -//// for (; anOtherCIt != theConstraint->myConstraints.end(); ++anOtherCIt) { -//// std::list::const_iterator aCIt = myConstraints.begin(); -//// for (; aCIt != myConstraints.end(); ++aCIt) { -//// std::list aWrappers = myStorage->constraint(*aCIt); -//// if (isBase(aWrappers, (*anOtherCIt)->attribute(SketchPlugin_Constraint::ENTITY_A())) || -//// (isBase(aWrappers, (*anOtherCIt)->attribute(SketchPlugin_Constraint::ENTITY_B())))) -//// return true; -//// } -//// } -//// return false; -////} -//// -////void SketchSolver_ConstraintCoincidence::attach( -//// std::shared_ptr theConstraint) -////{ -//// cleanErrorMsg(); -//// ConstraintWrapperPtr aFirstConstraint = myStorage->constraint(myConstraints.front()).front(); -//// EntityWrapperPtr aMasterPoint = aFirstConstraint->entities().front(); -//// -//// // Set points from theConstraint equal to master point -//// const std::list& anOtherConstraints = theConstraint->myConstraints; -//// std::list::const_iterator anOtherCIt = anOtherConstraints.begin(); -//// bool isFirstUpd = false; -//// for (; anOtherCIt != anOtherConstraints.end(); ++anOtherCIt) { -//// std::list aSolverConstraints = myStorage->constraint(*anOtherCIt); -//// std::list::iterator aSCIt = aSolverConstraints.begin(); -//// // First point in each constraint is the same (master point of theConstraint), -//// // it should be updated only once. -//// if (!isFirstUpd) { -//// EntityWrapperPtr anOtherMasterPoint = (*aSCIt)->entities().front(); -//// myStorage->addCoincidentPoints(aMasterPoint, anOtherMasterPoint); -//// isFirstUpd = true; -//// } -//// // Update all slave points -//// for (; aSCIt != aSolverConstraints.end(); ++aSCIt) { -//// std::list aSubs = (*aSCIt)->entities(); -//// std::list::iterator aSubIt = aSubs.begin(); -//// for (++aSubIt; aSubIt != aSubs.end(); ++aSubIt) -//// myStorage->addCoincidentPoints(aMasterPoint, *aSubIt); -//// } -//// // add constraint to myConstraints -//// myConstraints.push_back(*anOtherCIt); -//// } -//// -//// // 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(); -////} +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; + } + } -////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; -////} + 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++; + } -////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++; -//// } -//// -//// // 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++; -//// } -//// return mySlvsConstraints.empty(); -////} + // 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++; + } + return mySlvsConstraints.empty(); +} diff --git a/src/SketchSolver/SketchSolver_ConstraintCoincidence.h b/src/SketchSolver/SketchSolver_ConstraintCoincidence.h index 5ff02a1b6..efb01572d 100644 --- a/src/SketchSolver/SketchSolver_ConstraintCoincidence.h +++ b/src/SketchSolver/SketchSolver_ConstraintCoincidence.h @@ -9,6 +9,7 @@ #include "SketchSolver.h" #include +#include /** \class SketchSolver_ConstraintCoincidence * \ingroup Plugins @@ -18,54 +19,53 @@ class SketchSolver_ConstraintCoincidence : public SketchSolver_Constraint { public: /// Constructor based on SketchPlugin constraint - SKETCHSOLVER_EXPORT SketchSolver_ConstraintCoincidence(ConstraintPtr theConstraint) : - SketchSolver_Constraint(theConstraint) + SketchSolver_ConstraintCoincidence(ConstraintPtr theConstraint) : + SketchSolver_Constraint(theConstraint), + myType(SLVS_C_UNKNOWN) {} -//// /// \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 constraint to the current -//// void attach(std::shared_ptr 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 Converts SketchPlugin constraint to a list of SolveSpace constraints + virtual void process(); - /// \brief Generate list of attributes of constraint in order useful for constraints + /// \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 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); -//// -////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 coincident 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); + +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 }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintDistance.cpp b/src/SketchSolver/SketchSolver_ConstraintDistance.cpp index e82568d3e..63bd0ae7d 100644 --- a/src/SketchSolver/SketchSolver_ConstraintDistance.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintDistance.cpp @@ -1,75 +1,107 @@ #include +#include #include -#include -#include -#include -#include #include #include -void SketchSolver_ConstraintDistance::getAttributes( - double& theValue, - std::vector& theAttributes) +void SketchSolver_ConstraintDistance::process() { - SketchSolver_Constraint::getAttributes(theValue, theAttributes); - if (!myErrorMsg.empty() || !theAttributes[0]) { - theAttributes.clear(); + cleanErrorMsg(); + if (!myBaseConstraint || !myStorage || myGroup == 0) { + /// TODO: Put error message here return; } + if (!mySlvsConstraints.empty()) // some data is changed, update constraint + update(myBaseConstraint); - 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(); + 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); myPrevValue = 0.0; + adjustConstraint(); } void SketchSolver_ConstraintDistance::adjustConstraint() { // Adjust point-line distance - if (getType() != CONSTRAINT_PT_LINE_DISTANCE) + if (getType() != SLVS_C_PT_LINE_DISTANCE) return; // Check the sign of distance is changed - ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front(); - if (fabs(myPrevValue) == fabs(aConstraint->value())) { - aConstraint->setValue(myPrevValue); - myStorage->addConstraint(myBaseConstraint, aConstraint); + Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front()); + if (fabs(myPrevValue) == fabs(aConstraint.valA)) { + aConstraint.valA = myPrevValue; + myStorage->updateConstraint(aConstraint); return; } // Get constraint parameters and check the sign of constraint value - 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; + 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; + } } } -void SketchSolver_ConstraintDistance::update() +void SketchSolver_ConstraintDistance::update(ConstraintPtr theConstraint) { - ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front(); - myPrevValue = aConstraint->value(); - - SketchSolver_Constraint::update(); + Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front()); + myPrevValue = aConstraint.valA; + SketchSolver_Constraint::update(theConstraint); } diff --git a/src/SketchSolver/SketchSolver_ConstraintDistance.h b/src/SketchSolver/SketchSolver_ConstraintDistance.h index b11e0a8a5..5c1569f9a 100644 --- a/src/SketchSolver/SketchSolver_ConstraintDistance.h +++ b/src/SketchSolver/SketchSolver_ConstraintDistance.h @@ -20,23 +20,26 @@ 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(); + virtual void update(ConstraintPtr theConstraint = ConstraintPtr()); + + virtual int getType() const + {return myType; } protected: - /// \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 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(); 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 a6120533e..e91ca2cf0 100644 --- a/src/SketchSolver/SketchSolver_ConstraintEqual.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintEqual.cpp @@ -1,54 +1,70 @@ #include +#include #include -void SketchSolver_ConstraintEqual::getAttributes( - double& theValue, - std::vector& theAttributes) + +void SketchSolver_ConstraintEqual::process() { - SketchSolver_Constraint::getAttributes(theValue, theAttributes); - if (!myErrorMsg.empty() || !theAttributes[2] || !theAttributes[3]) { - theAttributes.clear(); + cleanErrorMsg(); + if (!myBaseConstraint || !myStorage || myGroup == 0) { + /// TODO: Put error message here return; } + if (!mySlvsConstraints.empty()) // some data is changed, update constraint + update(myBaseConstraint); + + double aValue; + std::vector anEntities; + getAttributes(aValue, anEntities); + if (!myErrorMsg.empty()) + return; // Check the 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 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; + 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++; 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 = CONSTRAINT_EQUAL_RADIUS; + myType = SLVS_C_EQUAL_RADIUS; break; case 1: - myType = CONSTRAINT_EQUAL_LINE_ARC; + myType = SLVS_C_EQUAL_LINE_ARC_LEN; if (isArcFirst) { // change the order of arc and line - EntityWrapperPtr aTmp = theAttributes[2]; - theAttributes[2] = theAttributes[3]; - theAttributes[3] = aTmp; + Slvs_hEntity aTmp = anEntities[2]; + anEntities[2] = anEntities[3]; + anEntities[3] = aTmp; } break; default: - myType = CONSTRAINT_EQUAL_LINES; + myType = SLVS_C_EQUAL_LENGTH_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 12e6a334e..2aca9c850 100644 --- a/src/SketchSolver/SketchSolver_ConstraintEqual.h +++ b/src/SketchSolver/SketchSolver_ConstraintEqual.h @@ -22,11 +22,15 @@ public: SketchSolver_Constraint(theConstraint) {} + virtual int getType() const + { return myType; } + protected: - /// \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 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) }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintFillet.cpp b/src/SketchSolver/SketchSolver_ConstraintFillet.cpp new file mode 100644 index 000000000..3d53b9010 --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintFillet.cpp @@ -0,0 +1,208 @@ +#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 new file mode 100644 index 000000000..44caaf035 --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintFillet.h @@ -0,0 +1,46 @@ +// 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 deleted file mode 100644 index 3e7a9f9db..000000000 --- a/src/SketchSolver/SketchSolver_ConstraintFixed.cpp +++ /dev/null @@ -1,375 +0,0 @@ -#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; - } -//// if (!mySlvsConstraints.empty()) // some data is changed, update constraint -//// update(myBaseConstraint); - - ParameterWrapperPtr aValue; - std::vector anEntities; - getAttributes(aValue, anEntities); - if (!myErrorMsg.empty() || anEntities.empty()) - return; - fixFeature(anEntities.front()); -} - -////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_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); -} - -////Slvs_hEntity SketchSolver_ConstraintFixed::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_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; -} - -////Slvs_hConstraint SketchSolver_ConstraintFixed::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_ConstraintFixed::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_ConstraintFixed::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_ConstraintFixed::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_ConstraintFixed.h b/src/SketchSolver/SketchSolver_ConstraintFixed.h deleted file mode 100644 index 0c9f2436e..000000000 --- a/src/SketchSolver/SketchSolver_ConstraintFixed.h +++ /dev/null @@ -1,71 +0,0 @@ -// 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); - -//// /// \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) - -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 5c3bbc088..06d854d17 100644 --- a/src/SketchSolver/SketchSolver_ConstraintLength.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintLength.cpp @@ -1,26 +1,44 @@ #include +#include #include -void SketchSolver_ConstraintLength::getAttributes( - double& theValue, - std::vector& theAttributes) +void SketchSolver_ConstraintLength::process() { - SketchSolver_Constraint::getAttributes(theValue, theAttributes); - if (!myErrorMsg.empty() || !theAttributes[2] || - theAttributes[2]->type() != ENTITY_LINE) { - theAttributes.clear(); + cleanErrorMsg(); + if (!myBaseConstraint || !myStorage || myGroup == 0) { + /// TODO: Put error message here return; } + if (!mySlvsConstraints.empty()) // some data is changed, update constraint + update(myBaseConstraint); - // 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; + 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; + } - myType = CONSTRAINT_PT_PT_DISTANCE; + 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(); } diff --git a/src/SketchSolver/SketchSolver_ConstraintLength.h b/src/SketchSolver/SketchSolver_ConstraintLength.h index 0899d8b73..f9c0da65c 100644 --- a/src/SketchSolver/SketchSolver_ConstraintLength.h +++ b/src/SketchSolver/SketchSolver_ConstraintLength.h @@ -22,11 +22,16 @@ public: SketchSolver_Constraint(theConstraint) {} + virtual int getType() const + { return SLVS_C_PT_PT_DISTANCE; } + protected: - /// \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 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(); }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintManager.cpp b/src/SketchSolver/SketchSolver_ConstraintManager.cpp new file mode 100644 index 000000000..682bbf23a --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintManager.cpp @@ -0,0 +1,367 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_ConstraintManager.cpp +// Created: 08 May 2014 +// Author: Artem ZHIDKOV + +#include "SketchSolver_ConstraintManager.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// Initialization of constraint manager self pointer +SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::_self = 0; + +/// Global constraint manager object +SketchSolver_ConstraintManager* myManager = SketchSolver_ConstraintManager::Instance(); + + +// ======================================================== +// ========= SketchSolver_ConstraintManager =============== +// ======================================================== +SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::Instance() +{ + if (!_self) + _self = new SketchSolver_ConstraintManager(); + return _self; +} + +SketchSolver_ConstraintManager::SketchSolver_ConstraintManager() +{ + myGroups.clear(); + myIsComputed = false; + + // Register in event loop + Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED)); + Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); + Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED)); + Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED)); +} + +SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager() +{ + myGroups.clear(); +} + +// ============================================================================ +// Function: processEvent +// Class: SketchSolver_Session +// Purpose: listen the event loop and process the message +// ============================================================================ +void SketchSolver_ConstraintManager::processEvent( + const std::shared_ptr& theMessage) +{ + if (myIsComputed) + return; + if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED) + || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED) + || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) { + std::shared_ptr anUpdateMsg = + std::dynamic_pointer_cast(theMessage); + std::set aFeatures = anUpdateMsg->objects(); + + // Shows the message has at least one feature applicable for solver + bool hasProperFeature = false; + + bool isMovedEvt = theMessage->eventID() + == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED); + if (isMovedEvt) { + std::set::iterator aFeatIter; + for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) { + std::shared_ptr aSFeature = + std::dynamic_pointer_cast(*aFeatIter); + if (aSFeature) { + moveEntity(aSFeature); + hasProperFeature = true; + } + } + } else { + std::list aSketchFeatures = SketchSolver_Group::selectApplicableFeatures(aFeatures); + std::list::iterator aFeatIter = aSketchFeatures.begin(); + for (; aFeatIter != aSketchFeatures.end(); ++aFeatIter) { + if ((*aFeatIter)->getKind() == SketchPlugin_Sketch::ID()) { + std::shared_ptr aSketch = + std::dynamic_pointer_cast(*aFeatIter); + hasProperFeature = changeWorkplane(aSketch) || hasProperFeature; + continue; + } + std::shared_ptr aFeature = + std::dynamic_pointer_cast(*aFeatIter); + if (!aFeature) + continue; + hasProperFeature = changeConstraintOrEntity(aFeature) || hasProperFeature; + } + } + + // Solve the set of constraints + if (hasProperFeature) + resolveConstraints(isMovedEvt); // send update for movement in any case + } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) { + std::shared_ptr aDeleteMsg = + std::dynamic_pointer_cast(theMessage); + const std::set& aFeatureGroups = aDeleteMsg->groups(); + + // Find SketchPlugin_Sketch::ID() in groups. The constraint groups should be updated when an object removed from Sketch + std::set::const_iterator aFGrIter; + for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++) + if (aFGrIter->compare(ModelAPI_ResultConstruction::group()) == 0 || + aFGrIter->compare(ModelAPI_Feature::group()) == 0) + break; + + if (aFGrIter != aFeatureGroups.end()) { + std::vector::iterator aGroupIter = myGroups.begin(); + std::vector aSeparatedGroups; + while (aGroupIter != myGroups.end()) { + if (!(*aGroupIter)->isWorkplaneValid()) { // the group should be removed + delete *aGroupIter; + int aShift = aGroupIter - myGroups.begin(); + myGroups.erase(aGroupIter); + aGroupIter = myGroups.begin() + aShift; + continue; + } + if (!(*aGroupIter)->isConsistent()) { // some constraints were removed, try to split the group + (*aGroupIter)->splitGroup(aSeparatedGroups); + } + aGroupIter++; + } + if (aSeparatedGroups.size() > 0) + myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end()); + } + } +} + +// ============================================================================ +// Function: changeWorkplane +// Class: SketchSolver_Session +// Purpose: update workplane by given parameters of the sketch +// ============================================================================ +bool SketchSolver_ConstraintManager::changeWorkplane(CompositeFeaturePtr theSketch) +{ + bool aResult = true; // changed when a workplane wrongly updated + bool isUpdated = false; + // Try to update specified workplane in all groups + std::vector::iterator aGroupIter; + for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) + if ((*aGroupIter)->isBaseWorkplane(theSketch)) { + isUpdated = true; + if (!(*aGroupIter)->updateWorkplane()) + aResult = false; + } + // If the workplane is not updated, so this is a new workplane + if (!isUpdated) { + SketchSolver_Group* aNewGroup = new SketchSolver_Group(theSketch); + // Verify that the group is created successfully + if (!aNewGroup->isBaseWorkplane(theSketch) || !aNewGroup->isWorkplaneValid()) { + delete aNewGroup; + return false; + } + myGroups.push_back(aNewGroup); + } + return aResult; +} + +// ============================================================================ +// 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) +{ + // Search the groups which this feature touches + std::set aGroups; + findGroups(theFeature, aGroups); + + std::shared_ptr aConstraint = + std::dynamic_pointer_cast(theFeature); + + // Process the groups list + if (aGroups.size() == 0) { + // There are no groups applicable for this constraint => create new one + // The group will be created only for constraints, not for features + if (!aConstraint) return false; + std::shared_ptr aWP = findWorkplane(aConstraint); + if (!aWP) + return false; + SketchSolver_Group* aGroup = new SketchSolver_Group(aWP); + if (!aGroup->changeConstraint(aConstraint)) { + delete aGroup; + return false; + } + myGroups.push_back(aGroup); + return true; + } else if (aGroups.size() == 1) { // Only one group => add feature into it + Slvs_hGroup aGroupId = *(aGroups.begin()); + std::vector::iterator aGroupIter; + for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) + if ((*aGroupIter)->getId() == aGroupId) { + // If the group is empty, the feature is not added (the constraint only) + if (!aConstraint && !(*aGroupIter)->isEmpty()) + return (*aGroupIter)->updateFeature(theFeature); + 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(); + + // Search first group + std::vector::iterator aFirstGroupIter; + for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++) + if ((*aFirstGroupIter)->getId() == *aGroupsIter) + break; + if (aFirstGroupIter == myGroups.end()) + return false; + + // Append other groups to the first one + std::vector::iterator anOtherGroupIter = aFirstGroupIter + 1; + for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) { + for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++) + if ((*anOtherGroupIter)->getId() == *aGroupsIter) + break; + if (anOtherGroupIter == myGroups.end()) { // Group disappears + anOtherGroupIter = aFirstGroupIter + 1; + continue; + } + + (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter); + int aShiftFirst = aFirstGroupIter - myGroups.begin(); + int aShiftOther = anOtherGroupIter - myGroups.begin(); + delete *anOtherGroupIter; + myGroups.erase(anOtherGroupIter); + aFirstGroupIter = myGroups.begin() + aShiftFirst; + anOtherGroupIter = myGroups.begin() + aShiftOther; + } + + if (aConstraint) + return (*aFirstGroupIter)->changeConstraint(aConstraint); + return (*aFirstGroupIter)->updateFeature(theFeature); + } + + // Something goes wrong + return false; +} + +// ============================================================================ +// 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) +{ + std::vector::iterator aGroupIt = myGroups.begin(); + for (; aGroupIt != myGroups.end(); aGroupIt++) + if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature)) + (*aGroupIt)->moveFeature(theFeature); +} + +// ============================================================================ +// Function: findGroups +// Class: SketchSolver_Session +// Purpose: search groups of entities interacting with given feature +// ============================================================================ +void SketchSolver_ConstraintManager::findGroups( + std::shared_ptr theFeature, + std::set& theGroupIDs) const +{ + std::shared_ptr aWP = findWorkplane(theFeature); + + SketchSolver_Group* anEmptyGroup = 0; // appropriate empty group for specified constraint + std::vector::const_iterator aGroupIter; + for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) + if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) { + if (!(*aGroupIter)->isEmpty()) + theGroupIDs.insert((*aGroupIter)->getId()); + else if (!anEmptyGroup) + anEmptyGroup = *aGroupIter; + } + + // When only empty group is found, use it + if (anEmptyGroup && theGroupIDs.empty()) + theGroupIDs.insert(anEmptyGroup->getId()); +} + +// ============================================================================ +// Function: findWorkplane +// Class: SketchSolver_Session +// Purpose: search workplane containing given feature +// ============================================================================ +std::shared_ptr SketchSolver_ConstraintManager +::findWorkplane(std::shared_ptr theFeature) const +{ + // Already verified workplanes + std::set > aVerified; + + std::vector::const_iterator aGroupIter; + for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) { + std::shared_ptr aWP = (*aGroupIter)->getWorkplane(); + if (aVerified.find(aWP) != aVerified.end()) + continue; + + DataPtr aData = aWP->data(); + if (aData->isValid()) { + std::shared_ptr aWPFeatures = std::dynamic_pointer_cast< + ModelAPI_AttributeRefList>(aData->attribute(SketchPlugin_Sketch::FEATURES_ID())); + std::list aFeaturesList = aWPFeatures->list(); + std::list::const_iterator anIter; + for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++) + if (*anIter == theFeature) + return aWP; // workplane is found + } + aVerified.insert(aWP); + } + + return std::shared_ptr(); +} + +// ============================================================================ +// Function: resolveConstraints +// Class: SketchSolver_Session +// Purpose: change entities according to available constraints +// ============================================================================ +void SketchSolver_ConstraintManager::resolveConstraints(const bool theForceUpdate) +{ + myIsComputed = true; + bool needToUpdate = false; + static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); + // to avoid redisplay of each segment on update by solver one by one in the viewer + bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent); + if (isUpdateFlushed) { + Events_Loop::loop()->setFlushed(anUpdateEvent, false); + } + + std::vector::iterator aGroupIter; + for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) + if ((*aGroupIter)->resolveConstraints()) + needToUpdate = true; + + // Features may be updated => now send events, but for all changed at once + if (isUpdateFlushed) { + Events_Loop::loop()->setFlushed(anUpdateEvent, true); + } + // Must be before flush because on "Updated" flush the results may be produced + // and the creation event is appeared with many new objects. If myIsComputed these + // events are missed in processEvents and some elements are not added. + myIsComputed = false; + if (needToUpdate || theForceUpdate) + Events_Loop::loop()->flush(anUpdateEvent); +} + diff --git a/src/SketchSolver/SketchSolver_ConstraintManager.h b/src/SketchSolver/SketchSolver_ConstraintManager.h new file mode 100644 index 000000000..a2d7ffaff --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintManager.h @@ -0,0 +1,112 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_ConstraintManager.h +// Created: 08 May 2014 +// Author: Artem ZHIDKOV + +#ifndef SketchSolver_ConstraintManager_H_ +#define SketchSolver_ConstraintManager_H_ + +#include "SketchSolver.h" +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +/** \class SketchSolver_ConstraintManager + * \ingroup Plugins + * \brief Listens the changes of SketchPlugin features and transforms the Constraint + * feature into the format understandable by SolveSpace library. + * + * Constraints created for SolveSpace library are divided into the groups. + * The division order based on connectedness of the features by the constraints. + * The groups may be fused or separated according to the new constraints. + * + * \remark This is a singleton. + */ +class SketchSolver_ConstraintManager : public Events_Listener +{ + public: + /** \brief Main method to create constraint manager + * \return pointer to the singleton + */ + static SketchSolver_ConstraintManager* 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 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); + + /** \brief Removes a constraint from the manager + * \param[in] theConstraint constraint to be removed + * \return \c true if the constraint removed successfully + */ + bool removeConstraint(std::shared_ptr theConstraint); + + /** \brief Adds or updates a workplane in the manager + * \param[in] theSketch the feature to create or update workplane + * \return \c true if the workplane changed successfully + * \remark Type of theSketch is not verified inside + */ + bool changeWorkplane(CompositeFeaturePtr theSketch); + + /** \brief Removes a workplane from the manager. + * All groups based on such workplane will be removed too. + * \param[in] theSketch the feature to be removed + * \return \c true if the workplane removed successfully + */ + bool removeWorkplane(std::shared_ptr theSketch); + + /** \brief Updates entity which is moved in GUI + * \param[in] theFeature entity to be updated + */ + void moveEntity(std::shared_ptr theFeature); + + /** \brief Goes through the list of groups and solve the constraints + * \param theForceUpdate flushes the update event in any case: something changed or not + */ + void resolveConstraints(const bool theForceUpdate); + + 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; + + /** \brief Searches in the list of groups the workplane which constains 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 + std::vector myGroups; ///< Groups of constraints + /// true if computation is performed and all "updates" are generated by this algo + /// and needs no recomputation + bool myIsComputed; +}; + +#endif diff --git a/src/SketchSolver/SketchSolver_ConstraintMirror.cpp b/src/SketchSolver/SketchSolver_ConstraintMirror.cpp index be15c46a0..9d1477545 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMirror.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMirror.cpp @@ -1,33 +1,34 @@ #include +#include #include -#include -////#include -////#include +#include +#include #include -////#include -//// -////#include -////#include -//// -////#include +#include + +#include +#include + +#include void SketchSolver_ConstraintMirror::getAttributes( - EntityWrapperPtr& theMirrorLine, - std::vector& theBaseEntities, - std::vector& theMirrorEntities) + Slvs_Entity& theMirrorLine, + std::vector& theBaseEntities, + std::vector& theMirrorEntities) { - AttributePtr aMirLineAttr = myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()); - AttributeRefAttrPtr aMirLineRefAttr = - std::dynamic_pointer_cast(aMirLineAttr); - if (!aMirLineRefAttr || !aMirLineRefAttr->isInitialized() || !aMirLineRefAttr->isObject()) { + DataPtr aData = myBaseConstraint->data(); + AttributeRefAttrPtr aMirLineAttr = std::dynamic_pointer_cast( + myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + if (!aMirLineAttr || !aMirLineAttr->isInitialized() || !aMirLineAttr->isObject()) { myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); return; } - - myType = TYPE(myBaseConstraint); - myStorage->update(aMirLineAttr, myGroupID); - theMirrorLine = myStorage->entity(aMirLineAttr); + 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); // Create SolveSpace entity for all features AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast( @@ -44,25 +45,26 @@ 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++) { - aFeature = ModelAPI_Feature::feature(*anIter); + aRC = std::dynamic_pointer_cast(*anIter); + aFeature = aRC ? aRC->document()->feature(aRC) : + std::dynamic_pointer_cast(*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)); + 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)); } } @@ -73,16 +75,16 @@ void SketchSolver_ConstraintMirror::getAttributes( void SketchSolver_ConstraintMirror::process() { cleanErrorMsg(); - if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) { - // Not enough parameters are assigned + if (!myBaseConstraint || !myStorage || myGroup == 0) { + /// TODO: Put error message here return; } -//// if (!mySlvsConstraints.empty()) // some data is changed, update constraint -//// update(myBaseConstraint); + if (!mySlvsConstraints.empty()) // some data is changed, update constraint + update(myBaseConstraint); - EntityWrapperPtr aMirrorLine; - std::vector aBaseList; - std::vector aMirrorList; + Slvs_Entity aMirrorLine; + std::vector aBaseList; + std::vector aMirrorList; getAttributes(aMirrorLine, aBaseList, aMirrorList); if (!myErrorMsg.empty()) return; @@ -92,328 +94,389 @@ void SketchSolver_ConstraintMirror::process() return; } - 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()); + 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; } - myStorage->addConstraint(myBaseConstraint, aMirConstrList); + 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); + } + } + } } -void SketchSolver_ConstraintMirror::update() +void SketchSolver_ConstraintMirror::update(ConstraintPtr theConstraint) { cleanErrorMsg(); - AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_C())); - if (aMirroredRefList->size() != myNumberOfObjects) { - remove(); - process(); - return; + if (!theConstraint || theConstraint == myBaseConstraint) { + AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast( + myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_C())); + if (aMirroredRefList->size() != myNumberOfObjects) { + remove(myBaseConstraint); + 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); -//// } -////} +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() { - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - - 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); - -//// 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; -//// } -//// -//// // 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); + 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; + } + + // 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); } diff --git a/src/SketchSolver/SketchSolver_ConstraintMirror.h b/src/SketchSolver/SketchSolver_ConstraintMirror.h index 30d72e781..f6aa365eb 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMirror.h +++ b/src/SketchSolver/SketchSolver_ConstraintMirror.h @@ -20,57 +20,60 @@ public: /// Constructor based on SketchPlugin constraint SketchSolver_ConstraintMirror(ConstraintPtr theConstraint) : SketchSolver_Constraint(theConstraint), - myNumberOfObjects(0)////, -//// myMirrorLineLength(0.0) + myNumberOfObjects(0), + myMirrorLineLength(0.0) {} + virtual int getType() const + { return SLVS_C_SYMMETRIC_LINE; } + /// \brief Update constraint - virtual void update(); + 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 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 constraints + /// \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 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 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(EntityWrapperPtr& theMirrorLine, - std::vector& theBaseEntities, - std::vector& theMirrorEntities); + void getAttributes(Slvs_Entity& 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; + /// \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) + 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 85542cb42..b97d1a754 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMovement.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMovement.cpp @@ -1,98 +1,176 @@ #include #include -#include +#include #include #include #include #include -#include - +SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(FeaturePtr theFeature) + : SketchSolver_ConstraintRigid(theFeature) +{ + process(); +} void SketchSolver_ConstraintMovement::process() { cleanErrorMsg(); - if (!myBaseFeature || !myStorage || myGroupID == GID_UNKNOWN) { - // Not enough parameters are initialized + if (!myBaseFeature || !myStorage || myGroup == 0) { + /// TODO: Put error message here return; } + if (!mySlvsConstraints.empty()) // some data is changed, update constraint + update(myBaseConstraint); - 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(); + double aValue; + std::vector anEntities; + bool isFullyMoved; + getAttributes(aValue, anEntities, isFullyMoved); + if (!myErrorMsg.empty() || (myFeatureMap.empty() && myAttributeMap.empty())) return; - } - std::vector::iterator anEntIt = myMovedEntities.begin(); - for (; anEntIt != myMovedEntities.end(); ++anEntIt) - fixFeature(*anEntIt); + if (isFullyMoved) + fixFeature(); + else { + std::vector::iterator anEntIt = anEntities.begin(); + for (; anEntIt != anEntities.end(); ++anEntIt) + fixPoint(*anEntIt); + } } -static std::list movedEntities( - EntityWrapperPtr theOld, StoragePtr theOldStorage, - EntityWrapperPtr theNew, StoragePtr theNewStorage) +void SketchSolver_ConstraintMovement::getAttributes( + double& theValue, + std::vector& theAttributes, + bool& theIsFullyMoved) { - 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()); + 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); } - if (isFullyMoved) { - aMoved.clear(); - aMoved.push_back(theOld); + 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; + } } - 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::getAttributes( - ParameterWrapperPtr& theValue, - std::vector& theAttributes) +void SketchSolver_ConstraintMovement::fixFeature() { - // 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); + Slvs_hEntity anEntID = fixedEntity(); - 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()); - } + 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(); + + 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); } - 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 ba119beaa..dbec1b020 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 to the Fixed constraint for the moved feature only + * \brief Stores data of Rigid (Fixed) constraint for the moved feature only */ -class SketchSolver_ConstraintMovement : public SketchSolver_ConstraintFixed +class SketchSolver_ConstraintMovement : public SketchSolver_ConstraintRigid { private: /// Creates constraint to manage the given constraint from plugin SketchSolver_ConstraintMovement(ConstraintPtr theConstraint) - : SketchSolver_ConstraintFixed(theConstraint) + : SketchSolver_ConstraintRigid(theConstraint) {} public: /// Creates temporary constraint based on feature - SketchSolver_ConstraintMovement(FeaturePtr theFeature) - : SketchSolver_ConstraintFixed(theFeature) - {} + SketchSolver_ConstraintMovement(FeaturePtr theFeature); protected: /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints @@ -34,11 +34,16 @@ 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 (list of moved entities or attributes) - virtual void getAttributes(ParameterWrapperPtr& theValue, std::vector& theAttributes); + /// \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(); private: - std::vector myMovedEntities; ///< list of entities that are moved + /// \brief Check the coordinates of point are differ than coordinates of correponding SolveSpace entity + bool isMoved(std::shared_ptr thePoint, const Slvs_Entity& theEntity); }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintMulti.cpp b/src/SketchSolver/SketchSolver_ConstraintMulti.cpp index 3c664be9c..5be0d2fe5 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMulti.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMulti.cpp @@ -1,360 +1,310 @@ #include +#include #include -#include -////#include -//// -////#include +#include + +#include #include #include #include -////#include -//// -////#include -////#include -//// -////#include - -void SketchSolver_ConstraintMulti::getEntitiesAndCopies( - std::list< std::list >& theEntAndCopies) +#include + +#include +#include + +#include + +void SketchSolver_ConstraintMulti::processEntities(const std::vector< std::vector >& theEntAndCopies) { - 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; + // 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]); + } - AttributeRefListPtr aRefList = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Constraint::ENTITY_B())); - if (!aRefList || aRefList->size() == 0) { - myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); - return; - } + // 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()); + } - 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 (!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); } - if (!anEntities.empty()) - theEntAndCopies.push_back(anEntities); } } - -////void SketchSolver_ConstraintMulti::processEntities(const std::vector< std::vector >& 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()); -//// } -//// -//// 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); -//// } -//// } -////} - -void SketchSolver_ConstraintMulti::update(bool isForce) +void SketchSolver_ConstraintMulti::update(ConstraintPtr theConstraint) { 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; + 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; + } } - // update derivative object updateLocal(); - if (isForce) - myAdjusted = false; - // update parent object SketchSolver_Constraint::update(); } -////bool SketchSolver_ConstraintMulti::remove() -////{ -//// 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; -////} - -////void SketchSolver_ConstraintMulti::addFeature(FeaturePtr theFeature) -////{ -//// SketchSolver_Constraint::addFeature(theFeature); -//// -//// std::map::iterator aFeatIt = myFeatureMap.find(theFeature); -//// if (aFeatIt == myFeatureMap.end()) -//// 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]); -////} +bool SketchSolver_ConstraintMulti::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); + 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; +} + +void SketchSolver_ConstraintMulti::addFeature(FeaturePtr theFeature) +{ + SketchSolver_Constraint::addFeature(theFeature); + + std::map::iterator aFeatIt = myFeatureMap.find(theFeature); + if (aFeatIt == myFeatureMap.end()) + 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]); +} void SketchSolver_ConstraintMulti::adjustConstraint() { if (myAdjusted) return; // constraint already adjusted, don't do it once again - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - - 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); - -//// 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]); -//// -//// 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(); + 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]); + + 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(); 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); -//// } -//// } -//// } -//// } -//// } -////} +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 9328b55f8..4786ee430 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMulti.h +++ b/src/SketchSolver/SketchSolver_ConstraintMulti.h @@ -27,29 +27,29 @@ public: myAdjusted(false) {} -//// virtual int getType() const -//// { return SLVS_C_UNKNOWN; } + virtual int getType() const + { return SLVS_C_UNKNOWN; } /// \brief Update constraint - virtual void update(bool isForce = false); - -//// /// \brief Tries to remove constraint -//// /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence) -//// virtual bool remove(); -//// -//// /// \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(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(); protected: /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints @@ -57,12 +57,12 @@ protected: { /* do nothing here */ } /// \brief Collect entities and their copies, like circles and arcs - void getEntitiesAndCopies(std::list< std::list >& theEntAndCopies); + void processEntities(const std::vector< std::vector >& 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 +73,24 @@ 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: + /// \brief Convert absolute coordinates to relative coordinates + virtual void getRelative(double theAbsX, double theAbsY, double& theRelX, double& theRelY) = 0; + /// \brief Convert relative coordinates to absolute coordinates + virtual void getAbsolute(double theRelX, double theRelY, double& theAbsX, double& theAbsY) = 0; + /// \brief Apply transformation for relative coordinates + virtual void transformRelative(double& theX, double& theY) = 0; protected: - int myNumberOfObjects; ///< number of previous initial objects - int 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 + 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 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 91fd4bf40..7608460c4 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp @@ -1,24 +1,25 @@ #include +#include #include -#include -////#include +#include #include -////#include -////#include -////#include -////#include -////#include -//// -////#include -////#include +#include +#include +#include +#include +#include + +#include +#include #include void SketchSolver_ConstraintMultiRotation::getAttributes( - EntityWrapperPtr& theCenter, double& theAngle, - std::list< std::list >& theEntities) + Slvs_hEntity& theCenter, double& theAngle, + std::vector< std::vector >& thePoints, + std::vector< std::vector >& theEntities) { DataPtr aData = myBaseConstraint->data(); theAngle = std::dynamic_pointer_cast( @@ -29,121 +30,106 @@ 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; + } - myType = CONSTRAINT_MULTI_ROTATION; - - myStorage->update(aCenterAttr, GID_OUTOFGROUP); - theCenter = myStorage->entity(aCenterAttr); - - getEntitiesAndCopies(theEntities); - -//// // 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); -//// } + // 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); + } } void SketchSolver_ConstraintMultiRotation::process() { cleanErrorMsg(); - if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) { + if (!myBaseConstraint || !myStorage || myGroup == 0) { /// TODO: Put error message here return; } -//// if (!mySlvsConstraints.empty()) // some data is changed, update constraint -//// update(myBaseConstraint); + if (!mySlvsConstraints.empty()) // some data is changed, update constraint + update(myBaseConstraint); - EntityWrapperPtr aRotationCenter; - std::list > anEntitiesAndCopies; - getAttributes(aRotationCenter, myAngle, anEntitiesAndCopies); + std::vector > anEntitiesAndCopies; + getAttributes(myRotationCenter, myAngle, myPointsAndCopies, 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()); + // 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); } - myStorage->addConstraint(myBaseConstraint, aRotConstraints); myAdjusted = false; -//// processEntities(anEntitiesAndCopies); + processEntities(anEntitiesAndCopies); adjustConstraint(); } @@ -155,13 +141,6 @@ 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() @@ -170,69 +149,63 @@ 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); + 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); 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; -////} +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() { diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h index 8ebda4584..86966e522 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h +++ b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h @@ -22,19 +22,21 @@ public: SketchSolver_ConstraintMulti(theConstraint) {} -//// virtual int getType() const -//// { return SLVS_C_MULTI_ROTATION; } + 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 central point of rotation + /// \param[out] theCenter ID of central point of rotation /// \param[out] theAngle rotation angle - /// \param[out] theEntities list of entities and their rotated copies - void getAttributes(EntityWrapperPtr& theCenter, double& theAngle, - std::list< std::list >& theEntities); + /// \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); /// \brief This method is used in derived objects to check consistence of constraint. virtual void adjustConstraint(); @@ -42,24 +44,24 @@ 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 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 +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 cosine of rotation angle + + 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 9b6a0840d..02b872c6e 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp @@ -1,26 +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 + +#include void SketchSolver_ConstraintMultiTranslation::getAttributes( - EntityWrapperPtr& theStartPoint, EntityWrapperPtr& theEndPoint, - std::list< std::list >& theEntities) + Slvs_hEntity& theStartPoint, Slvs_hEntity& theEndPoint, + std::vector< std::vector >& thePoints, + std::vector< std::vector >& theEntities) { DataPtr aData = myBaseConstraint->data(); AttributePtr aStartPointAttr = aData->attribute(SketchPlugin_MultiTranslation::START_POINT_ID()); @@ -31,196 +32,175 @@ void SketchSolver_ConstraintMultiTranslation::getAttributes( return; } - myType = CONSTRAINT_MULTI_TRANSLATION; - - myStorage->update(aStartPointAttr); - theStartPoint = myStorage->entity(aStartPointAttr); - myStorage->update(aEndPointAttr); - theEndPoint = myStorage->entity(aEndPointAttr); - - getEntitiesAndCopies(theEntities); - -//// 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; -//// } -//// -//// // 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(); -//// -//// 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); -//// } + 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; + } + + // 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(); + + 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); + } } void SketchSolver_ConstraintMultiTranslation::process() { cleanErrorMsg(); - if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) { + if (!myBaseConstraint || !myStorage || myGroup == 0) { /// TODO: Put error message here return; } -//// if (!mySlvsConstraints.empty()) // some data is changed, update constraint -//// update(myBaseConstraint); + if (!mySlvsConstraints.empty()) // some data is changed, update constraint + update(myBaseConstraint); - EntityWrapperPtr aStartPoint, aEndPoint; - std::list > anEntitiesAndCopies; - getAttributes(aStartPoint, aEndPoint, anEntitiesAndCopies); + Slvs_hEntity aStartPoint, aEndPoint; + std::vector > anEntitiesAndCopies; + getAttributes(aStartPoint, aEndPoint, myPointsAndCopies, 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()); + // 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); + } } - myStorage->addConstraint(myBaseConstraint, aTransConstraints); myAdjusted = false; -//// processEntities(anEntitiesAndCopies); + 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]; -////} +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() { diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h index 3b3f09018..c9f10147d 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h +++ b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h @@ -19,47 +19,49 @@ 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), + myTranslationLine(SLVS_E_UNKNOWN) {} -//// virtual int getType() const -//// { return SLVS_C_MULTI_TRANSLATION; } + 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 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); + /// \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(); + /// \brief This method is used in derived objects to check consistence of constraint. + virtual void adjustConstraint(); /// \brief Update parameters (called from base class) virtual void updateLocal() {} -////private: -//// /// \brief Convert absolute coordinates to relative coordinates -//// virtual void getRelative(double theAbsX, double theAbsY, double& theRelX, double& theRelY); -//// /// \brief Convert relative coordinates to absolute coordinates -//// virtual void getAbsolute(double theRelX, double theRelY, double& theAbsX, double& theAbsY); -//// /// \brief Apply transformation for relative coordinates -//// virtual void transformRelative(double& theX, double& theY); +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 +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 new file mode 100644 index 000000000..bd533ce8e --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintParametric.cpp @@ -0,0 +1,171 @@ +#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 new file mode 100644 index 000000000..3a25d96ff --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintParametric.h @@ -0,0 +1,59 @@ +// 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 new file mode 100644 index 000000000..ed8ae3712 --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintRigid.cpp @@ -0,0 +1,393 @@ +#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 new file mode 100644 index 000000000..adac8c6a3 --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintRigid.h @@ -0,0 +1,76 @@ +// 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 7ec41bc79..865065411 100644 --- a/src/SketchSolver/SketchSolver_ConstraintTangent.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintTangent.cpp @@ -1,161 +1,84 @@ #include +#include #include -#include -#include - -/// \brief Check whether the entities has only one shared point -static bool hasSingleCoincidence(EntityWrapperPtr theEntity1, EntityWrapperPtr theEntity2) +void SketchSolver_ConstraintTangent::process() { - 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; - } - } - return aNbCoinc == 1; -} - - -void SketchSolver_ConstraintTangent::getAttributes( - double& theValue, - std::vector& theAttributes) -{ - SketchSolver_Constraint::getAttributes(theValue, theAttributes); - if (!myErrorMsg.empty() || !theAttributes[2] || !theAttributes[3]) { - theAttributes.clear(); + 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; // Check the quantity of entities of each type and their order (arcs first) int aNbLines = 0; int aNbArcs = 0; - 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; + 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++; } } - if (aNbArcs < 1) { + if (aNbLines + aNbArcs != 2) { + myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); + return; + } else if (aNbArcs < 1) { myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE(); return; } - 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(); + + // 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(); return; } - if (!hasSingleCoincidence(theAttributes[2], theAttributes[3])) - myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); - - if (isSwap) { - EntityWrapperPtr aTemp = theAttributes[2]; - theAttributes[2] = theAttributes[3]; - theAttributes[3] = aTemp; - } + 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(); } - -////void SketchSolver_ConstraintTangent::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; -//// // 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++; -//// } -//// } -//// -//// if (aNbLines + aNbArcs != 2) { -//// myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); -//// return; -//// } else 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(); -//// 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(); -////} - diff --git a/src/SketchSolver/SketchSolver_ConstraintTangent.h b/src/SketchSolver/SketchSolver_ConstraintTangent.h index e1716bf74..a6c744e44 100644 --- a/src/SketchSolver/SketchSolver_ConstraintTangent.h +++ b/src/SketchSolver/SketchSolver_ConstraintTangent.h @@ -22,11 +22,15 @@ public: SketchSolver_Constraint(theConstraint) {} + virtual int getType() const + { return myType; } + protected: - /// \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 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) }; #endif diff --git a/src/SketchSolver/SketchSolver_FeatureStorage.cpp b/src/SketchSolver/SketchSolver_FeatureStorage.cpp new file mode 100644 index 000000000..34d07b2bf --- /dev/null +++ b/src/SketchSolver/SketchSolver_FeatureStorage.cpp @@ -0,0 +1,418 @@ +// 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 new file mode 100644 index 000000000..2cb36ba81 --- /dev/null +++ b/src/SketchSolver/SketchSolver_FeatureStorage.h @@ -0,0 +1,78 @@ +// 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 f4ba30c83..9ad17d750 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -6,30 +6,29 @@ #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 +#include #include -////#include +#include #include #include -//// -////#include + +#include #include #include #include @@ -44,16 +43,16 @@ #include #include #include -////#include +#include #include #include -////#include -//// -////#include -////#include -////#include -////#include -////#include +#include + +#include +#include +#include +#include +#include #include #include @@ -64,9 +63,9 @@ class GroupIndexer { public: /// \brief Return vacant index - static GroupID NEW_GROUP() { return ++myGroupIndex; } + static Slvs_hGroup NEW_GROUP() { return ++myGroupIndex; } /// \brief Removes the index - static void REMOVE_GROUP(const GroupID& theIndex) { + static void REMOVE_GROUP(const Slvs_hGroup& theIndex) { if (myGroupIndex == theIndex) myGroupIndex--; } @@ -74,10 +73,10 @@ public: private: GroupIndexer() {}; - static GroupID myGroupIndex; ///< index of the group + static Slvs_hGroup myGroupIndex; ///< index of the group }; -GroupID GroupIndexer::myGroupIndex = GID_OUTOFGROUP; +Slvs_hGroup GroupIndexer::myGroupIndex = SLVS_G_OUTOFGROUP; static void sendMessage(const char* theMessageName) @@ -99,8 +98,12 @@ SketchSolver_Group::SketchSolver_Group( myPrevSolved(true) { // Initialize workplane - myWorkplaneID = EID_UNKNOWN; + myWorkplaneID = SLVS_E_UNKNOWN; +#ifndef NDEBUG + assert(addWorkplane(theWorkplane)); +#else addWorkplane(theWorkplane); +#endif } SketchSolver_Group::~SketchSolver_Group() @@ -124,13 +127,85 @@ 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(FeaturePtr theFeature) const +bool SketchSolver_Group::isInteract( + std::shared_ptr theFeature) const { // Empty group interacts with everything - if (isEmpty()) - return true; - // Check interaction with the storage - return myStorage->isInteract(theFeature); + 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; } // ============================================================================ @@ -142,7 +217,7 @@ bool SketchSolver_Group::changeConstraint( std::shared_ptr theConstraint) { // There is no workplane yet, something wrong - if (myWorkplaneID == EID_UNKNOWN) + if (myWorkplaneID == SLVS_E_UNKNOWN) return false; if (!theConstraint || !theConstraint->data()) @@ -151,127 +226,130 @@ 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 = aBuilder->createConstraint(theConstraint); + SolverConstraintPtr aConstraint = + SketchSolver_Builder::getInstance()->createConstraint(theConstraint); if (!aConstraint) return false; - aConstraint->process(myStorage, getId(), getWorkplaneId()); + aConstraint->setGroup(this); + aConstraint->setStorage(myStorage); 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 (aConstraint->getType() == CONSTRAINT_PT_PT_COINCIDENT) { -//// bool hasMultiCoincidence = false; -//// std::shared_ptr aCoincidence = -//// std::dynamic_pointer_cast(aConstraint); -//// -//// ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); -//// for (; aCIter != myConstraints.end(); ++aCIter) { -//// if (aCIter->second->getType() != CONSTRAINT_PT_PT_COINCIDENT) -//// continue; -//// -//// std::shared_ptr aCurCoinc = -//// std::dynamic_pointer_cast(aCIter->second); -//// if (aCoincidence != aCurCoinc && aCurCoinc->isCoincide(aCoincidence)) { -//// aCoincidence->attach(aCurCoinc); -//////// // update other coincidences -//////// ConstraintConstraintMap::iterator anIt = aCIter; -//////// for (++anIt; anIt != myConstraints.end(); ++anIt) -//////// if (anIt->second == aCIter->second) -//////// anIt->second = aCoincidence; -//// aCIter->second = aCoincidence; -//// hasMultiCoincidence = true; -//// } -//// } -//// -//// if (hasMultiCoincidence) -//// notifyMultiConstraints(); -//// } + // 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 = aBuilder->createRigidConstraint(aFeature); -//// if (!aConstraint) -//// continue; -//// aConstraint->setGroup(this); -//// aConstraint->setStorage(myStorage); -//// setTemporary(aConstraint); -//// } -//// } - + // 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()) { - std::shared_ptr aFeature = - std::dynamic_pointer_cast( - ModelAPI_Feature::feature(aRefAttr->object())); + FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); if (aFeature) { - SolverConstraintPtr aConstraint = aBuilder->createFixedConstraint(aFeature); + SolverConstraintPtr aConstraint = + SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature); if (aConstraint) { - aConstraint->process(myStorage, getId(), getWorkplaneId()); + aConstraint->setGroup(this); + aConstraint->setStorage(myStorage); setTemporary(aConstraint); } } } } -//// // 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 = aBuilder->createParametricConstraint(aPoint); -//// if (!aConstraint) -//// continue; -//// aConstraint->setGroup(this); -//// aConstraint->setStorage(myStorage); -//// myParametricConstraints[aPoint] = aConstraint; -//// } else -//// aFound->second->update(); -//// } + 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; } @@ -300,63 +378,105 @@ void SketchSolver_Group::updateConstraints() myChangedConstraints.clear(); } -bool SketchSolver_Group::updateFeature(FeaturePtr theFeature) +bool SketchSolver_Group::updateFeature(std::shared_ptr theFeature) { if (!checkFeatureValidity(theFeature)) return false; - bool isUpdated = myStorage->update(theFeature); - -//// // 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 isUpdated; -} + 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); -void SketchSolver_Group::moveFeature(FeaturePtr 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); + 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; +} - // Then, create temporary rigid constraint - SolverConstraintPtr aConstraint = aBuilder->createMovementConstraint(theFeature); +void SketchSolver_Group::moveFeature(std::shared_ptr theFeature) +{ + // Firstly, create temporary rigid constraint + SolverConstraintPtr aConstraint = + SketchSolver_Builder::getInstance()->createMovementConstraint(theFeature); if (!aConstraint) return; - aConstraint->process(myStorage, getId(), getWorkplaneId()); + aConstraint->setGroup(this); + aConstraint->setStorage(myStorage); 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); + } } // ============================================================================ @@ -366,14 +486,11 @@ void SketchSolver_Group::moveFeature(FeaturePtr theFeature) // ============================================================================ bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch) { - if (myWorkplaneID != EID_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID()) + if (myWorkplaneID != SLVS_E_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID()) return false; // the workplane already exists or the function parameter is not Sketch mySketch = theSketch; - if (!updateWorkplane()) { - mySketch = CompositeFeaturePtr(); - return false; - } + updateWorkplane(); return true; } @@ -384,17 +501,55 @@ bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch) // ============================================================================ bool SketchSolver_Group::updateWorkplane() { - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); if (!myStorage) // Create storage if not exists - myStorage = aBuilder->createStorage(getId()); + myStorage = StoragePtr(new SketchSolver_Storage); + SketchSolver_Builder* aBuilder = SketchSolver_Builder::getInstance(); - // 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(); + 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); + } } - return isUpdated; + return myWorkplaneID > 0; } // ============================================================================ @@ -410,36 +565,33 @@ bool SketchSolver_Group::resolveConstraints() bool aResolved = false; bool isGroupEmpty = isEmpty(); if (myStorage->isNeedToResolve() && !isGroupEmpty) { - if (!mySketchSolver) - mySketchSolver = SketchSolver_Manager::instance()->builder()->createSolver(); - - mySketchSolver->setGroup(myID); - mySketchSolver->calculateFailedConstraints(false); - myStorage->initializeSolver(mySketchSolver); + myConstrSolver.setGroupID(myID); + myConstrSolver.calculateFailedConstraints(false); + myStorage->initializeSolver(myConstrSolver); - SketchSolver_SolveStatus aResult = STATUS_OK; + int aResult = SLVS_RESULT_OKAY; try { if (myStorage->hasDuplicatedConstraint()) - aResult = STATUS_INCONSISTENT; + aResult = SLVS_RESULT_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; - size_t aNbTemp = myStorage->nbTemporary(); + int aNbTemp = myStorage->numberTemporary(); while (true) { - aResult = mySketchSolver->solve(); - if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET || isLastChance) + aResult = myConstrSolver.solve(); + if (aResult == SLVS_RESULT_OKAY || 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->removeTemporary(); - mySketchSolver->calculateFailedConstraints(true); // something failed => need to find it - myStorage->initializeSolver(mySketchSolver); + aNbTemp = myStorage->deleteTemporaryConstraint(); + myConstrSolver.calculateFailedConstraints(true); // something failed => need to find it + myStorage->initializeSolver(myConstrSolver); } } } catch (...) { @@ -452,18 +604,17 @@ bool SketchSolver_Group::resolveConstraints() } return false; } - if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET) { // solution succeeded, store results into correspondent attributes - myStorage->refresh(); -//// 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 == 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 (!myPrevSolved) { getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(""); // the error message should be changed before sending the message @@ -482,18 +633,15 @@ bool SketchSolver_Group::resolveConstraints() aResolved = true; } else if (!isGroupEmpty) { -//// myFeatureStorage->blockEvents(true); + 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(); + aCIt->second->refresh(); aResolved = true; - break; } -//// myFeatureStorage->blockEvents(false); - if (aCIt != myConstraints.end()) - myStorage->refresh(); + myFeatureStorage->blockEvents(false); } removeTemporaryConstraints(); myStorage->setNeedToResolve(false); @@ -510,6 +658,8 @@ 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(); @@ -531,27 +681,27 @@ void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup) // Class: SketchSolver_Group // Purpose: divide the group into several subgroups // ============================================================================ -void SketchSolver_Group::splitGroup(std::list& theCuts) +void SketchSolver_Group::splitGroup(std::vector& 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 - std::list anUnusedConstraints; + FeatureStoragePtr aNewFeatStorage(new SketchSolver_FeatureStorage); + std::vector anUnusedConstraints; ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); for ( ; aCIter != myConstraints.end(); aCIter++) { - if (aNewStorage->isInteract(FeaturePtr(aCIter->first))) - aNewStorage->addConstraint(aCIter->first, aDummyVec); - else - anUnusedConstraints.push_back(aCIter->first); + 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); } // Check the unused constraints once again, because they may become interacted with new storage since adding constraints - std::list::iterator aUnuseIt = anUnusedConstraints.begin(); + std::vector::iterator aUnuseIt = anUnusedConstraints.begin(); while (aUnuseIt != anUnusedConstraints.end()) { - if (aNewStorage->isInteract(FeaturePtr(*aUnuseIt))) { - aNewStorage->addConstraint(*aUnuseIt, aDummyVec); + if (aNewFeatStorage->isInteract(*aUnuseIt)) { + aNewFeatStorage->changeConstraint(*aUnuseIt); anUnusedConstraints.erase(aUnuseIt); aUnuseIt = anUnusedConstraints.begin(); continue; @@ -559,13 +709,13 @@ void SketchSolver_Group::splitGroup(std::list& theCuts) aUnuseIt++; } - std::list::iterator aCutsIter; + std::vector::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; @@ -575,17 +725,11 @@ void SketchSolver_Group::splitGroup(std::list& 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; } // ============================================================================ @@ -595,24 +739,12 @@ void SketchSolver_Group::splitGroup(std::list& theCuts) // ============================================================================ bool SketchSolver_Group::isConsistent() { - if (isEmpty()) // no one constraint is initialized yet + if (!myFeatureStorage) // no one constraint is initialized yet return true; - // 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; - } - } + bool aResult = myFeatureStorage->isConsistent(); if (!aResult) { - // remove invalid constraints + // remove invalid entities std::set anInvalidConstraints; ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); for (; aCIter != myConstraints.end(); ++aCIter) { @@ -622,8 +754,6 @@ 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; } @@ -639,20 +769,16 @@ void SketchSolver_Group::removeTemporaryConstraints() std::set::iterator aTmpIt = myTempConstraints.begin(); for (; aTmpIt != myTempConstraints.end(); ++aTmpIt) (*aTmpIt)->remove(); + myTempConstraints.clear(); - size_t aNbTemp = myStorage->nbTemporary(); - if (aNbTemp > 0) - myStorage->removeTemporary(aNbTemp); -//// // Clean lists of removed entities in the storage -//// std::set aRemPar; -//// std::set aRemEnt; -//// std::set aRemCon; -//// myStorage->getRemoved(aRemPar, aRemEnt, aRemCon); - - if (!myTempConstraints.empty()) - myStorage->verifyFixed(); + 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); myStorage->setNeedToResolve(false); - myTempConstraints.clear(); } // ============================================================================ @@ -663,18 +789,19 @@ 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->first == theConstraint) { - if (!aCIter->second->remove()) // the constraint is not fully removed + if (aCIter->second->hasConstraint(theConstraint)) { + if (!aCIter->second->remove(theConstraint)) // the constraint is not fully removed isFullyRemoved = false; break; } if (aCIter == myConstraints.end()) return; -//// // Remove entities not used by constraints -//// myStorage->removeUnusedEntities(); + // Remove entities not used by constraints + myStorage->removeUnusedEntities(); if (isFullyRemoved) myConstraints.erase(aCIter); @@ -690,7 +817,7 @@ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint) } if (aCIter->first != theConstraint) aMultiCoinc.push_back(aCIter->first); - aCIter->second->remove(); + aCIter->second->remove(aCIter->first); ConstraintConstraintMap::iterator aRemoveIt = aCIter++; myConstraints.erase(aRemoveIt); } @@ -718,7 +845,7 @@ bool SketchSolver_Group::isComplexConstraint(FeaturePtr theConstraint) // ============================================================================ // Function: setTemporary // Class: SketchSolver_Group -// Purpose: append given constraint to the group of temporary constraints +// Purpose: append given constraint to th group of temporary constraints // ============================================================================ void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint) { @@ -749,15 +876,15 @@ bool SketchSolver_Group::checkFeatureValidity(FeaturePtr theFeature) // ============================================================================ 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(); -//// } -//// } + 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 a8c09c2ac..507386d03 100644 --- a/src/SketchSolver/SketchSolver_Group.h +++ b/src/SketchSolver/SketchSolver_Group.h @@ -10,16 +10,18 @@ #include "SketchSolver.h" #include #include -#include +#include +#include #include -////#include +#include #include -////#include +#include #include #include #include +#include #include typedef std::map ConstraintConstraintMap; @@ -40,17 +42,22 @@ class SketchSolver_Group ~SketchSolver_Group(); /// \brief Returns group's unique identifier - inline const GroupID& getId() const + inline const Slvs_hGroup& getId() const { return myID; } /// \brief Returns identifier of the workplane - inline const EntityID& getWorkplaneId() const + inline const Slvs_hEntity& 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 { @@ -75,19 +82,19 @@ class SketchSolver_Group /** \brief Updates the data corresponding the specified feature * \param[in] theFeature the feature to be updated */ - bool updateFeature(FeaturePtr theFeature); + bool updateFeature(std::shared_ptr theFeature); /** \brief Updates the data corresponding the specified feature moved in GUI. * Additional Fixed constraints are created. * \param[in] theFeature the feature to be updated */ - void moveFeature(FeaturePtr theFeature); + void moveFeature(std::shared_ptr 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(FeaturePtr theFeature) const; + bool isInteract(std::shared_ptr 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 @@ -119,7 +126,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::list& theCuts); + void splitGroup(std::vector& theCuts); /** \brief Start solution procedure if necessary and update attributes of features * \return \c false when no need to solve constraints @@ -148,7 +155,10 @@ private: */ bool addWorkplane(CompositeFeaturePtr theSketch); - /// \brief Append given constraint to the group of temporary constraints + /// \brief Apply temporary rigid constraints for the list of features + void fixFeaturesList(AttributeRefListPtr theList); + + /// \brief Append given constraint to th group of temporary constraints void setTemporary(SolverConstraintPtr theConstraint); /// \brief Verifies is the feature valid @@ -161,8 +171,8 @@ private: void notifyMultiConstraints(); private: - GroupID myID; ///< Index of the group - EntityID myWorkplaneID; ///< Index of workplane, the group is based on + Slvs_hGroup myID; ///< Index of the group + Slvs_hEntity 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 @@ -170,8 +180,9 @@ 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 - SolverPtr mySketchSolver; ///< Solver for set of equations obtained by constraints + SketchSolver_Solver myConstrSolver; ///< 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 deleted file mode 100644 index 3e43cae10..000000000 --- a/src/SketchSolver/SketchSolver_IConstraintWrapper.h +++ /dev/null @@ -1,103 +0,0 @@ -// 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 const 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 deleted file mode 100644 index a5ecae3d8..000000000 --- a/src/SketchSolver/SketchSolver_IEntityWrapper.h +++ /dev/null @@ -1,100 +0,0 @@ -// 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 const 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 deleted file mode 100644 index fbd88192d..000000000 --- a/src/SketchSolver/SketchSolver_IParameterWrapper.h +++ /dev/null @@ -1,55 +0,0 @@ -// 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 const 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 deleted file mode 100644 index 75ddbfdf4..000000000 --- a/src/SketchSolver/SketchSolver_ISolver.h +++ /dev/null @@ -1,50 +0,0 @@ -// 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_Manager.cpp b/src/SketchSolver/SketchSolver_Manager.cpp deleted file mode 100644 index 442cf15c2..000000000 --- a/src/SketchSolver/SketchSolver_Manager.cpp +++ /dev/null @@ -1,366 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: SketchSolver_Manager.cpp -// Created: 08 May 2014 -// Author: Artem ZHIDKOV - -#include "SketchSolver_Manager.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -// Initialization of constraint manager self pointer -SketchSolver_Manager* SketchSolver_Manager::mySelf = 0; - -/// Global constraint manager object -SketchSolver_Manager* myManager = SketchSolver_Manager::instance(); - - -// ======================================================== -// ========= SketchSolver_Manager =============== -// ======================================================== -SketchSolver_Manager* SketchSolver_Manager::instance() -{ - if (!mySelf) - mySelf = new SketchSolver_Manager(); - return mySelf; -} - -SketchSolver_Manager::SketchSolver_Manager() -{ - myGroups.clear(); - myIsComputed = false; - - // Register in event loop - Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED)); - Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); - Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED)); - Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED)); -} - -SketchSolver_Manager::~SketchSolver_Manager() -{ - myGroups.clear(); -} - -void SketchSolver_Manager::setBuilder(BuilderPtr theBuilder) -{ - myBuilder = theBuilder; -} - -BuilderPtr SketchSolver_Manager::builder() -{ - return myBuilder; -} - -// ============================================================================ -// Function: processEvent -// Purpose: listen the event loop and process the message -// ============================================================================ -void SketchSolver_Manager::processEvent( - const std::shared_ptr& theMessage) -{ - if (myIsComputed) - return; - if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED) - || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED) - || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) { - std::shared_ptr anUpdateMsg = - std::dynamic_pointer_cast(theMessage); - std::set aFeatures = anUpdateMsg->objects(); - - // Shows the message has at least one feature applicable for solver - bool hasProperFeature = false; - - bool isMovedEvt = theMessage->eventID() - == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED); - if (isMovedEvt) { - std::set::iterator aFeatIter; - for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) { - std::shared_ptr aSFeature = - std::dynamic_pointer_cast(*aFeatIter); - if (aSFeature) { - moveEntity(aSFeature); - hasProperFeature = true; - } - } - } else { - std::list aSketchFeatures = SketchSolver_Group::selectApplicableFeatures(aFeatures); - std::list::iterator aFeatIter = aSketchFeatures.begin(); - for (; aFeatIter != aSketchFeatures.end(); ++aFeatIter) { - if ((*aFeatIter)->getKind() == SketchPlugin_Sketch::ID()) { - std::shared_ptr aSketch = - std::dynamic_pointer_cast(*aFeatIter); - hasProperFeature = changeWorkplane(aSketch) || hasProperFeature; - continue; - } - std::shared_ptr aFeature = - std::dynamic_pointer_cast(*aFeatIter); - if (!aFeature) - continue; - hasProperFeature = changeFeature(aFeature) || hasProperFeature; - } - } - - // Solve the set of constraints - if (hasProperFeature) - resolveConstraints(isMovedEvt); // send update for movement in any case - } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) { - std::shared_ptr aDeleteMsg = - std::dynamic_pointer_cast(theMessage); - const std::set& aFeatureGroups = aDeleteMsg->groups(); - - // Find SketchPlugin_Sketch::ID() in groups. The constraint groups should be updated when an object removed from Sketch - std::set::const_iterator aFGrIter; - for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++) - if (aFGrIter->compare(ModelAPI_ResultConstruction::group()) == 0 || - aFGrIter->compare(ModelAPI_Feature::group()) == 0) - break; - - if (aFGrIter != aFeatureGroups.end()) { - std::vector::iterator aGroupIter = myGroups.begin(); - std::list aSeparatedGroups; - while (aGroupIter != myGroups.end()) { - if (!(*aGroupIter)->isWorkplaneValid()) { // the group should be removed - delete *aGroupIter; - int aShift = aGroupIter - myGroups.begin(); - myGroups.erase(aGroupIter); - aGroupIter = myGroups.begin() + aShift; - continue; - } - if (!(*aGroupIter)->isConsistent()) { // some constraints were removed, try to split the group - (*aGroupIter)->splitGroup(aSeparatedGroups); - } - aGroupIter++; - } - if (aSeparatedGroups.size() > 0) - myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end()); - } - } -} - -// ============================================================================ -// Function: changeWorkplane -// Purpose: update workplane by given parameters of the sketch -// ============================================================================ -bool SketchSolver_Manager::changeWorkplane(CompositeFeaturePtr theSketch) -{ - bool aResult = true; // changed when a workplane wrongly updated - bool isUpdated = false; - // Try to update specified workplane in all groups - std::vector::iterator aGroupIter; - for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) - if ((*aGroupIter)->isBaseWorkplane(theSketch)) { - isUpdated = true; - aResult = false; - } - // If the workplane is not updated, so this is a new workplane - if (!isUpdated) { - SketchSolver_Group* aNewGroup = new SketchSolver_Group(theSketch); - // Verify that the group is created successfully - if (!aNewGroup->isBaseWorkplane(theSketch) || !aNewGroup->isWorkplaneValid()) { - delete aNewGroup; - return false; - } - myGroups.push_back(aNewGroup); - } - return aResult; -} - -// ============================================================================ -// Function: changeConstraintOrEntity -// Purpose: create/update the constraint or the feature and place it into appropriate group -// ============================================================================ -bool SketchSolver_Manager::changeFeature(std::shared_ptr theFeature) -{ - // Search the groups which this feature touches - std::set aGroups; - findGroups(theFeature, aGroups); - - std::shared_ptr aConstraint = - std::dynamic_pointer_cast(theFeature); - - // Process the groups list - if (aGroups.size() == 0) { - // There are no groups applicable for this constraint => create new one - // The group will be created only for constraints, not for features - if (!aConstraint) return false; - std::shared_ptr aWP = findWorkplane(aConstraint); - if (!aWP) - return false; - SketchSolver_Group* aGroup = new SketchSolver_Group(aWP); - if (!aGroup->changeConstraint(aConstraint)) { - delete aGroup; - return false; - } - myGroups.push_back(aGroup); - return true; - } else if (aGroups.size() == 1) { // Only one group => add feature into it - GroupID aGroupId = *(aGroups.begin()); - std::vector::iterator aGroupIter; - for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) - if ((*aGroupIter)->getId() == aGroupId) { - // If the group is empty, the feature is not added (the constraint only) - if (!aConstraint && !(*aGroupIter)->isEmpty()) - return (*aGroupIter)->updateFeature(theFeature); - 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(); - - // Search first group - std::vector::iterator aFirstGroupIter; - for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++) - if ((*aFirstGroupIter)->getId() == *aGroupsIter) - break; - if (aFirstGroupIter == myGroups.end()) - return false; - - // Append other groups to the first one - std::vector::iterator anOtherGroupIter = aFirstGroupIter + 1; - for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) { - for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++) - if ((*anOtherGroupIter)->getId() == *aGroupsIter) - break; - if (anOtherGroupIter == myGroups.end()) { // Group disappears - anOtherGroupIter = aFirstGroupIter + 1; - continue; - } - - (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter); - int aShiftFirst = aFirstGroupIter - myGroups.begin(); - int aShiftOther = anOtherGroupIter - myGroups.begin(); - delete *anOtherGroupIter; - myGroups.erase(anOtherGroupIter); - aFirstGroupIter = myGroups.begin() + aShiftFirst; - anOtherGroupIter = myGroups.begin() + aShiftOther; - } - - if (aConstraint) - return (*aFirstGroupIter)->changeConstraint(aConstraint); - return (*aFirstGroupIter)->updateFeature(theFeature); - } - - // Something goes wrong - return false; -} - -// ============================================================================ -// Function: moveEntity -// Purpose: update element moved on the sketch, which is used by constraints -// ============================================================================ -void SketchSolver_Manager::moveEntity(std::shared_ptr theFeature) -{ - std::vector::iterator aGroupIt = myGroups.begin(); - for (; aGroupIt != myGroups.end(); aGroupIt++) - if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature)) - (*aGroupIt)->moveFeature(theFeature); -} - -// ============================================================================ -// Function: findGroups -// Purpose: search groups of entities interacting with given feature -// ============================================================================ -void SketchSolver_Manager::findGroups( - std::shared_ptr theFeature, - std::set& theGroupIDs) const -{ - std::shared_ptr aWP = findWorkplane(theFeature); - - SketchSolver_Group* anEmptyGroup = 0; // appropriate empty group for specified constraint - std::vector::const_iterator aGroupIter; - for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) - if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) { - if (!(*aGroupIter)->isEmpty()) - theGroupIDs.insert((*aGroupIter)->getId()); - else if (!anEmptyGroup) - anEmptyGroup = *aGroupIter; - } - - // When only empty group is found, use it - if (anEmptyGroup && theGroupIDs.empty()) - theGroupIDs.insert(anEmptyGroup->getId()); -} - -// ============================================================================ -// Function: findWorkplane -// Purpose: search workplane containing given feature -// ============================================================================ -std::shared_ptr SketchSolver_Manager -::findWorkplane(std::shared_ptr theFeature) const -{ - // Already verified workplanes - std::set > aVerified; - - std::vector::const_iterator aGroupIter; - for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) { - std::shared_ptr aWP = (*aGroupIter)->getWorkplane(); - if (aVerified.find(aWP) != aVerified.end()) - continue; - - DataPtr aData = aWP->data(); - if (aData->isValid()) { - std::shared_ptr aWPFeatures = std::dynamic_pointer_cast< - ModelAPI_AttributeRefList>(aData->attribute(SketchPlugin_Sketch::FEATURES_ID())); - std::list aFeaturesList = aWPFeatures->list(); - std::list::const_iterator anIter; - for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++) - if (*anIter == theFeature) - return aWP; // workplane is found - } - aVerified.insert(aWP); - } - - return std::shared_ptr(); -} - -// ============================================================================ -// Function: resolveConstraints -// Purpose: change entities according to available constraints -// ============================================================================ -void SketchSolver_Manager::resolveConstraints(const bool theForceUpdate) -{ - myIsComputed = true; - bool needToUpdate = false; - static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); - // to avoid redisplay of each segment on update by solver one by one in the viewer - bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent); - if (isUpdateFlushed) { - Events_Loop::loop()->setFlushed(anUpdateEvent, false); - } - - std::vector::iterator aGroupIter; - for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) - if ((*aGroupIter)->resolveConstraints()) - needToUpdate = true; - - // Features may be updated => now send events, but for all changed at once - if (isUpdateFlushed) { - Events_Loop::loop()->setFlushed(anUpdateEvent, true); - } - // Must be before flush because on "Updated" flush the results may be produced - // and the creation event is appeared with many new objects. If myIsComputed these - // events are missed in processEvents and some elements are not added. - myIsComputed = false; - if (needToUpdate || theForceUpdate) - Events_Loop::loop()->flush(anUpdateEvent); -} diff --git a/src/SketchSolver/SketchSolver_Manager.h b/src/SketchSolver/SketchSolver_Manager.h deleted file mode 100644 index 8ceddc79a..000000000 --- a/src/SketchSolver/SketchSolver_Manager.h +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: SketchSolver_Manager.h -// Created: 08 May 2014 -// Author: Artem ZHIDKOV - -#ifndef SketchSolver_Manager_H_ -#define SketchSolver_Manager_H_ - -#include "SketchSolver.h" -#include -#include - -#include -#include - -#include -#include - -/** \class SketchSolver_Manager - * \ingroup Plugins - * \brief Listens the changes of SketchPlugin features and transforms the Constraint - * feature into the format understandable by SolveSpace library. - * - * Constraints created for SolveSpace library are divided into the groups. - * The division order based on connectedness of the features by the constraints. - * The groups may be fused or separated according to the new constraints. - * - * \remark This is a singleton. - */ -class SketchSolver_Manager : public Events_Listener -{ -public: - /** \brief Main method to create constraint manager - * \return pointer to the singleton - */ - 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); - - /// \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 changeFeature(std::shared_ptr theFeature); - - /** \brief Removes a constraint from the manager - * \param[in] theConstraint constraint to be removed - * \return \c true if the constraint removed successfully - */ - bool removeConstraint(std::shared_ptr theConstraint); - - /** \brief Adds or updates a workplane in the manager - * \param[in] theSketch the feature to create or update workplane - * \return \c true if the workplane changed successfully - * \remark Type of theSketch is not verified inside - */ - bool changeWorkplane(CompositeFeaturePtr theSketch); - - /** \brief Removes a workplane from the manager. - * All groups based on such workplane will be removed too. - * \param[in] theSketch the feature to be removed - * \return \c true if the workplane removed successfully - */ - bool removeWorkplane(std::shared_ptr theSketch); - - /** \brief Updates entity which is moved in GUI - * \param[in] theFeature entity to be updated - */ - void moveEntity(std::shared_ptr theFeature); - - /** \brief Goes through the list of groups and solve the constraints - * \param theForceUpdate flushes the update event in any case: something changed or not - */ - void resolveConstraints(const bool theForceUpdate); - -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; - - /** \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_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; -}; - -#endif diff --git a/src/SketchSolver/SketchSolver_Solver.cpp b/src/SketchSolver/SketchSolver_Solver.cpp new file mode 100644 index 000000000..36979d747 --- /dev/null +++ b/src/SketchSolver/SketchSolver_Solver.cpp @@ -0,0 +1,112 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_Solver.cpp +// Created: 07 May 2014 +// Author: Artem ZHIDKOV + +#include "SketchSolver_Solver.h" +#include + +SketchSolver_Solver::SketchSolver_Solver() +{ + myGroupID = 0; + // Nullify all elements of the set of equations + myEquationsSystem.param = 0; + myEquationsSystem.params = 0; + myEquationsSystem.entity = 0; + myEquationsSystem.entities = 0; + myEquationsSystem.constraint = 0; + myEquationsSystem.constraints = 0; + myEquationsSystem.failed = 0; + myEquationsSystem.faileds = 0; + + myEquationsSystem.dragged[0] = 0; + myEquationsSystem.dragged[1] = 0; + myEquationsSystem.dragged[2] = 0; + myEquationsSystem.dragged[3] = 0; + + // If the set of constraints is inconsistent, + // the failed field will contain wrong constraints + myEquationsSystem.calculateFaileds = 0; +} + +SketchSolver_Solver::~SketchSolver_Solver() +{ + if (myEquationsSystem.constraint) + delete[] myEquationsSystem.constraint; + myEquationsSystem.constraint = 0; + if (myEquationsSystem.failed) + delete[] myEquationsSystem.failed; + myEquationsSystem.failed = 0; +} + +void SketchSolver_Solver::setParameters(Slvs_Param* theParameters, int theSize) +{ + myEquationsSystem.param = theParameters; + myEquationsSystem.params = theSize; +} + + +void SketchSolver_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) +{ + myEquationsSystem.entity = theEntities; + myEquationsSystem.entities = theSize; +} + +void SketchSolver_Solver::setConstraints(Slvs_Constraint* theConstraints, int theSize) +{ + if (!myEquationsSystem.constraint) { + myEquationsSystem.constraint = new Slvs_Constraint[theSize]; + myEquationsSystem.constraints = theSize; + myEquationsSystem.failed = new Slvs_hConstraint[theSize]; + } + else if (myEquationsSystem.constraints != theSize) { + if (theSize > myEquationsSystem.constraints) { + delete[] myEquationsSystem.constraint; + myEquationsSystem.constraint = new Slvs_Constraint[theSize]; + if (myEquationsSystem.failed) + delete[] myEquationsSystem.failed; + myEquationsSystem.failed = new Slvs_hConstraint[theSize]; + } + myEquationsSystem.constraints = theSize; + } + memcpy(myEquationsSystem.constraint, theConstraints, theSize * sizeof(Slvs_Constraint)); + memset(myEquationsSystem.failed, SLVS_C_UNKNOWN, theSize * sizeof(Slvs_hConstraint)); +} + + +int SketchSolver_Solver::solve() +{ + if (myEquationsSystem.constraints <= 0) + return SLVS_RESULT_EMPTY_SET; + + Events_LongOp::start(this); + Slvs_Solve(&myEquationsSystem, myGroupID); + 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; + } + + return true; +} diff --git a/src/SketchSolver/SketchSolver_Solver.h b/src/SketchSolver/SketchSolver_Solver.h new file mode 100644 index 000000000..52ac18f98 --- /dev/null +++ b/src/SketchSolver/SketchSolver_Solver.h @@ -0,0 +1,101 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_Solver.h +// Created: 07 May 2014 +// Author: Artem ZHIDKOV + +#ifndef SketchSolver_Solver_H_ +#define SketchSolver_Solver_H_ + +#include "SketchSolver.h" + +// Need to be defined before including SolveSpace to avoid additional dependances on Windows platform +#if defined(WIN32) && !defined(HAVE_C99_INTEGER_TYPES) +typedef unsigned int UINT32; +#else +#include +#endif +#include +#include + +#include + +#define SLVS_RESULT_EMPTY_SET -1 + +// Unknown constraint (for error reporting) +#define SLVS_C_UNKNOWN 0 +// Fillet constraint identifier +#define SLVS_C_FILLET 100100 +// Multi-rotation constraint identifier +#define SLVS_C_MULTI_ROTATION 100101 +// Multi-translation constraint identifier +#define SLVS_C_MULTI_TRANSLATION 100102 +// Unknown entity +#define SLVS_E_UNKNOWN 0 +// Unknown group +#define SLVS_G_UNKNOWN 0 +// 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 SketchSolver_Solver +{ + public: + SketchSolver_Solver(); + ~SketchSolver_Solver(); + + /** \brief Initialize the ID of the group + */ + inline void setGroupID(Slvs_hGroup theGroupID) + { + myGroupID = theGroupID; + } + + /** \brief Change array of parameters + * \param[in] theParameters pointer to the array of parameters + * \param[in] theSize size of this array + */ + void setParameters(Slvs_Param* theParameters, int theSize); + + /** \brief Change array of entities + * \param[in] theEntities pointer to the array of entities + * \param[in] theSize size of this array + */ + void setEntities(Slvs_Entity* theEntities, int theSize); + + /** \brief Change array of constraints + * \param[in] theConstraints pointer to the array of constraints + * \param[in] theSize size of this array + */ + void setConstraints(Slvs_Constraint* theConstraints, int theSize); + + /** \brief Store the parameters of the point which was moved by user. + * The solver will watch this items to be constant + * \param[in] theDragged list of parameters (not more than 4) which should not be changed during solving + */ + 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); + + private: + Slvs_hGroup myGroupID; ///< identifier of the group to be solved + Slvs_System myEquationsSystem; ///< set of equations for solving in SolveSpace +}; + +#endif diff --git a/src/SketchSolver/SketchSolver_Storage.cpp b/src/SketchSolver/SketchSolver_Storage.cpp index 9e38f9270..58cd67418 100644 --- a/src/SketchSolver/SketchSolver_Storage.cpp +++ b/src/SketchSolver/SketchSolver_Storage.cpp @@ -1,352 +1,1222 @@ // Copyright (C) 2014-20xx CEA/DEN, EDF R&D // File: SketchSolver_Storage.cpp -// Created: 30 Nov 2015 +// Created: 18 Mar 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 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); +/// \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); -void SketchSolver_Storage::addConstraint(ConstraintPtr theConstraint, - ConstraintWrapperPtr theSolverConstraint) +SketchSolver_Storage::SketchSolver_Storage() + : myParamMaxID(SLVS_E_UNKNOWN), + myEntityMaxID(SLVS_E_UNKNOWN), + myConstrMaxID(SLVS_C_UNKNOWN), + myFixed(SLVS_E_UNKNOWN), + myNeedToResolve(false), + myDuplicatedConstraint(false) { - std::list aConstrList(1, theSolverConstraint); - addConstraint(theConstraint, aConstrList); } -void SketchSolver_Storage::addConstraint( - ConstraintPtr theConstraint, - std::list theSolverConstraints) +Slvs_hParam SketchSolver_Storage::addParameter(const Slvs_Param& theParam) { - std::map >::const_iterator - aFound = myConstraintMap.find(theConstraint); - if (!isEqual(aFound->second, theSolverConstraints)) - setNeedToResolve(true); + 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 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; + } + } + + // Parameter is not found, add new one + Slvs_Param aParam = theParam; + aParam.h = 0; + return addParameter(aParam); +} - // 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); +bool SketchSolver_Storage::removeParameter(const Slvs_hParam& theParamID) +{ + 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; } - myConstraintMap[theConstraint] = theSolverConstraints; + return false; } -void SketchSolver_Storage::addEntity(FeaturePtr theFeature, - EntityWrapperPtr theSolverEntity) +const Slvs_Param& SketchSolver_Storage::getParameter(const Slvs_hParam& theParamID) const { - std::map::const_iterator aFound = myFeatureMap.find(theFeature); - if (aFound == myFeatureMap.end() || !aFound->second->isEqual(theSolverEntity)) - setNeedToResolve(true); // the entity is new or modified + int aPos = Search(theParamID, myParameters); + if (aPos >= 0 && aPos < (int)myParameters.size()) + return myParameters[aPos]; - myFeatureMap[theFeature] = theSolverEntity; + // Parameter is not found, return empty object + static Slvs_Param aDummy; + aDummy.h = 0; + return aDummy; } -void SketchSolver_Storage::addEntity(AttributePtr theAttribute, - EntityWrapperPtr theSolverEntity) + +Slvs_hEntity SketchSolver_Storage::addEntity(const Slvs_Entity& 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 + if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) { + // Entity is already used, rewrite it + return updateEntity(theEntity); + } - myAttributeMap[theAttribute] = theSolverEntity; + 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 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::update(FeaturePtr theFeature, const GroupID& theGroup) +bool SketchSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID) { - 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)); + 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; } - // 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::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() +{ + 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; } - // 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); + 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); + } + } } - // Secondly, convert feature - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - aRelated = aBuilder->createFeature(theFeature, aSubs, theGroup); - if (!aRelated) - return false; - addEntity(theFeature, aRelated); - } else if (theGroup != GID_UNKNOWN) - changeGroup(aRelated, theGroup); - return update(aRelated) || isUpdated; + } + + 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]); + 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::update(AttributePtr theAttribute, const GroupID& theGroup) + +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 { - 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(); + 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++; } - 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) + 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; - addEntity(anAttribute, aRelated); - } else if (theGroup != GID_UNKNOWN) - changeGroup(aRelated, theGroup); - return update(aRelated); + // 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; +} -const std::list& SketchSolver_Storage::constraint( - const ConstraintPtr& theConstraint) const +Slvs_hConstraint SketchSolver_Storage::updateConstraint(const Slvs_Constraint& theConstraint) { - static std::list aDummy; + 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; + } + } - std::map>::const_iterator - aFound = myConstraintMap.find(theConstraint); - if (aFound != myConstraintMap.end()) - return aFound->second; - return aDummy; + // Constraint is not found, add new one + Slvs_Constraint aConstraint = theConstraint; + aConstraint.h = 0; + return addConstraint(aConstraint); +} + +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 EntityWrapperPtr& SketchSolver_Storage::entity(const FeaturePtr& theFeature) const +const Slvs_Constraint& SketchSolver_Storage::getConstraint(const Slvs_hConstraint& theConstraintID) const { - static EntityWrapperPtr aDummy; + int aPos = Search(theConstraintID, myConstraints); + if (aPos >= 0 && aPos < (int)myConstraints.size()) + return myConstraints[aPos]; - std::map::const_iterator aFound = myFeatureMap.find(theFeature); - if (aFound != myFeatureMap.end()) - return aFound->second; + // Constraint is not found, return empty object + static Slvs_Constraint aDummy; + aDummy.h = 0; return aDummy; } -const EntityWrapperPtr& SketchSolver_Storage::entity(const AttributePtr& theAttribute) const +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) { - static EntityWrapperPtr aDummy; + myTemporaryConstraints.insert(theConstraintID); +} - std::map::const_iterator - aFound = myAttributeMap.find(theAttribute); - if (aFound != myAttributeMap.end()) - return aFound->second; +void SketchSolver_Storage::removeTemporaryConstraints() +{ + myTemporaryConstraints.clear(); +} - 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()); +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; } - return aDummy; + 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(); } -////const ParameterWrapperPtr& SketchSolver_Storage::parameter(const AttributeDoublePtr& theAttribute) const -////{ -//// static ParameterWrapperPtr aDummy; -//// -//// std::map::const_iterator -//// aFound = myParametersMap.find(theAttribute); -//// if (aFound != myParametersMap.end()) -//// return aFound->second; -//// return aDummy; -////} +bool SketchSolver_Storage::isTemporary(const Slvs_hConstraint& theConstraintID) const +{ + return myTemporaryConstraints.find(theConstraintID) != myTemporaryConstraints.end(); +} -bool SketchSolver_Storage::isInteract(const FeaturePtr& theFeature) const +void SketchSolver_Storage::getRemoved( + std::set& theParameters, + std::set& theEntities, + std::set& theConstraints) { - if (!theFeature) - return false; - if (myConstraintMap.empty()) - return true; // empty storage interacts with each feature + theParameters = myRemovedParameters; + theEntities = myRemovedEntities; + theConstraints = myRemovedConstraints; + + myRemovedParameters.clear(); + myRemovedEntities.clear(); + myRemovedConstraints.clear(); +} + +void SketchSolver_Storage::initializeSolver(SketchSolver_Solver& theSolver) +{ + theSolver.setParameters(myParameters.data(), (int)myParameters.size()); + theSolver.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); + theSolver.setDraggedParameters(myEntities[aPos].param); + } + theSolver.setConstraints(aConstraints.data(), (int)aConstraints.size()); +} + +void SketchSolver_Storage::addCoincidentPoints( + const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) +{ + std::vector< std::set >::iterator aCIter = myCoincidentPoints.begin(); + std::vector< std::set >::iterator aFoundIter = myCoincidentPoints.end(); // already found coincidence + bool isFound = false; + for (; aCIter != myCoincidentPoints.end(); aCIter++) { + bool isFirstFound = aCIter->find(thePoint1) != aCIter->end(); + bool isSecondFound = aCIter->find(thePoint2) != aCIter->end(); + isFound = isFound || isFirstFound || isSecondFound; + if (isFirstFound && isSecondFound) + break; // already coincident + else if (isFirstFound || isSecondFound) { + if (aFoundIter != myCoincidentPoints.end()) { + // merge two sets + aFoundIter->insert(aCIter->begin(), aCIter->end()); + myCoincidentPoints.erase(aCIter); + break; + } 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); + } +} + +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; + } +} - ConstraintPtr aConstraint = std::dynamic_pointer_cast(theFeature); - if (aConstraint) { - if (myConstraintMap.find(aConstraint) != myConstraintMap.end()) +void SketchSolver_Storage::removeCoincidence(const Slvs_Constraint& theCoincidence) +{ + // 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); +} + +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()) return true; - } else if (myFeatureMap.find(theFeature) != myFeatureMap.end()) + return false; +} + +bool SketchSolver_Storage::isEqual( + const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const +{ + if (isCoincident(thePoint1, thePoint2)) return true; - std::list anAttrList = theFeature->data()->attributes(std::string()); - std::list::const_iterator anIt = anAttrList.begin(); - for (; anIt != anAttrList.end(); ++anIt) - if (isInteract(*anIt)) + // 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; } -bool SketchSolver_Storage::isInteract(const AttributePtr& theAttribute) const + +std::vector SketchSolver_Storage::fixEntity(const Slvs_hEntity& theEntity) { - if (!theAttribute) - return false; + std::vector aNewConstraints; - 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(); + 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; + } + } - FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); - return isInteract(aFeature); + return aNewConstraints; } -bool SketchSolver_Storage::isConsistent() const +void SketchSolver_Storage::fixPoint(const Slvs_Entity& thePoint, + std::vector& theCreated) { - // 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; + 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 SketchSolver_Storage::setSketch(const EntityWrapperPtr& theSketch) +void SketchSolver_Storage::fixLine(const Slvs_Entity& theLine, + std::vector& theCreated) { - if (sketch()) + 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; - addEntity(FeaturePtr(), theSketch); + } + 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 SketchSolver_Storage::blockEvents(bool isBlocked) const +void SketchSolver_Storage::fixCircle(const Slvs_Entity& theCircle, + std::vector& theCreated) { - 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); + 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); - 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; - 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); + // 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 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; +} -// ============== Auxiliary functions ==================================== -bool isEqual(const std::list& theCVec1, - const std::list& theCVec2) +bool SketchSolver_Storage::isUsedInEqual( + const Slvs_hEntity& theEntity, Slvs_Constraint& theEqual) const { - if (theCVec1.size() != theCVec2.size()) + // 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() +{ + if (myConstraints.empty()) return false; - 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; + 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; + } + } } - return true; + + 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; } diff --git a/src/SketchSolver/SketchSolver_Storage.h b/src/SketchSolver/SketchSolver_Storage.h index a286f8a28..bb270d77d 100644 --- a/src/SketchSolver/SketchSolver_Storage.h +++ b/src/SketchSolver/SketchSolver_Storage.h @@ -1,216 +1,218 @@ // Copyright (C) 2014-20xx CEA/DEN, EDF R&D // File: SketchSolver_Storage.h -// Created: 30 Nov 2015 +// Created: 18 Mar 2015 // Author: Artem ZHIDKOV #ifndef SketchSolver_Storage_H_ #define SketchSolver_Storage_H_ -#include -#include -#include -#include -#include +#include "SketchSolver.h" +#include -#include -#include -#include -#include +#include +#include +#include +#include /** \class SketchSolver_Storage * \ingroup Plugins - * \brief Interface to map SketchPlugin features to the entities of corresponding solver. + * \brief Contains all necessary data in SolveSpace format to solve a single group of constraints */ class SketchSolver_Storage { -private: +public: SketchSolver_Storage(); - SketchSolver_Storage(const SketchSolver_Storage&); - SketchSolver_Storage& operator=(const SketchSolver_Storage&); -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 Returns parameter related to corresponding scalar attribute -//// SKETCHSOLVER_EXPORT -//// const ParameterWrapperPtr& parameter(const AttributeDoublePtr& 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 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(); } /// \brief Shows the sketch should be resolved - virtual bool isNeedToResolve() - { return myNeedToResolve; } + bool isNeedToResolve(); + + /// \brief Shows the storage has the same constraint twice + bool hasDuplicatedConstraint() const + { return myDuplicatedConstraint; } + /// \brief Changes the flag of group to be resolved void setNeedToResolve(bool theFlag) { myNeedToResolve = theFlag; } - /// \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 Change mapping scalar attribute and the parameter applicable for corresponding solver. -//// /// \param theValue [in] original attribute -//// /// \param theSolverParam [in] solver's parameter, created outside -//// SKETCHSOLVER_EXPORT -//// void addParameter(AttributeDoublePtr theValue, -//// ParameterWrapperPtr theSolverParam); - - /// \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; + /// \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); private: - /// \brief Find the normal of the sketch - EntityWrapperPtr getNormal() const; + /// \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); -protected: - GroupID myGroupID; ///< identifier of the group, this storage belongs to +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) - /// 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; -//// /// map scalar attribute to solver's parameter -//// std::map myParametersMap; + std::vector< std::set > myCoincidentPoints; ///< lists of coincident points + Slvs_hConstraint myFixed; ///< identifier of one of temporary constraints to fix separate point bool myNeedToResolve; ///< parameters are changed and group needs to be resolved + 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 deleted file mode 100644 index cda6e3bc1..000000000 --- a/src/SketchSolver/SolveSpaceSolver/CMakeLists.txt +++ /dev/null @@ -1,42 +0,0 @@ -## 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 deleted file mode 100644 index b74a8db1a..000000000 --- a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.cpp +++ /dev/null @@ -1,879 +0,0 @@ -// 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 -{ -//// std::shared_ptr anEntity1 = -//// std::dynamic_pointer_cast(theEntity1); -//// std::shared_ptr anEntity2 = -//// std::dynamic_pointer_cast(theEntity2); -//// -//// // Make aMirrorEnt parameters to be symmetric with aBaseEnt -//// makeMirrorEntity(theEntity1, theEntity2, theMirrorLine); - - 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(); - -//// EntityWrapperPtr aBothArcs[2] = {theEntity1, theEntity2}; -//// EntityWrapperPtr aBothMiddlePoints[2]; -//// for (int i = 0; i < 2; i++) { -//// aBothMiddlePoints[i] = calculateMiddlePoint(aBothArcs[i], 0.5, theGroupID, theSketchID); -//// // additional constraint point-on-curve -//// aMrrList = createConstraint(theConstraint, theGroupID, theSketchID, CONSTRAINT_PT_ON_CIRCLE, -//// 0.0, aBothMiddlePoints[i], EntityWrapperPtr(), aBothArcs[i]); -//// aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end()); -//////// 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.push_back(aBothMiddlePoints[0]); -//// aMirrorArcPoints.push_back(aBothMiddlePoints[1]); - 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 deleted file mode 100644 index f55330ad2..000000000 --- a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Builder.h +++ /dev/null @@ -1,140 +0,0 @@ -// 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 deleted file mode 100644 index a38939bd4..000000000 --- a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintType.h +++ /dev/null @@ -1,75 +0,0 @@ -// 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 deleted file mode 100644 index 8419b9a2e..000000000 --- a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintWrapper.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// 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 deleted file mode 100644 index dd1bb1c69..000000000 --- a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ConstraintWrapper.h +++ /dev/null @@ -1,61 +0,0 @@ -// 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 const 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 deleted file mode 100644 index 1cb81157d..000000000 --- a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_EntityWrapper.cpp +++ /dev/null @@ -1,127 +0,0 @@ -// 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 deleted file mode 100644 index 4f7482361..000000000 --- a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_EntityWrapper.h +++ /dev/null @@ -1,57 +0,0 @@ -// 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 const 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 deleted file mode 100644 index 1f2c7d451..000000000 --- a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ParameterWrapper.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// 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 deleted file mode 100644 index 35609f543..000000000 --- a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_ParameterWrapper.h +++ /dev/null @@ -1,55 +0,0 @@ -// 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 const 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/SolveSpaceSolver/SolveSpaceSolver_Solver.cpp b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Solver.cpp deleted file mode 100644 index de1cc3edd..000000000 --- a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Solver.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: SolveSpaceSolver_Solver.cpp -// Created: 07 May 2014 -// Author: Artem ZHIDKOV - -#include "SolveSpaceSolver_Solver.h" -#include - -SolveSpaceSolver_Solver::SolveSpaceSolver_Solver() -{ - // Nullify all elements of the set of equations - myEquationsSystem.param = 0; - myEquationsSystem.params = 0; - myEquationsSystem.entity = 0; - myEquationsSystem.entities = 0; - myEquationsSystem.constraint = 0; - myEquationsSystem.constraints = 0; - myEquationsSystem.failed = 0; - myEquationsSystem.faileds = 0; - - myEquationsSystem.dragged[0] = 0; - myEquationsSystem.dragged[1] = 0; - myEquationsSystem.dragged[2] = 0; - myEquationsSystem.dragged[3] = 0; - - // If the set of constraints is inconsistent, - // the failed field will contain wrong constraints - myEquationsSystem.calculateFaileds = 0; -} - -SolveSpaceSolver_Solver::~SolveSpaceSolver_Solver() -{ - if (myEquationsSystem.constraint) - delete[] myEquationsSystem.constraint; - myEquationsSystem.constraint = 0; - if (myEquationsSystem.failed) - delete[] myEquationsSystem.failed; - myEquationsSystem.failed = 0; -} - -void SolveSpaceSolver_Solver::setParameters(Slvs_Param* theParameters, int theSize) -{ - myEquationsSystem.param = theParameters; - myEquationsSystem.params = theSize; -} - - -void SolveSpaceSolver_Solver::setDraggedParameters(const Slvs_hParam* theDragged) -{ - for (unsigned int i = 0; i < 4; i++) - myEquationsSystem.dragged[i] = theDragged[i]; -} - -void SolveSpaceSolver_Solver::setEntities(Slvs_Entity* theEntities, int theSize) -{ - myEquationsSystem.entity = theEntities; - myEquationsSystem.entities = theSize; -} - -void SolveSpaceSolver_Solver::setConstraints(Slvs_Constraint* theConstraints, int theSize) -{ - if (!myEquationsSystem.constraint) { - myEquationsSystem.constraint = new Slvs_Constraint[theSize]; - myEquationsSystem.constraints = theSize; - myEquationsSystem.failed = new Slvs_hConstraint[theSize]; - } - else if (myEquationsSystem.constraints != theSize) { - if (theSize > myEquationsSystem.constraints) { - delete[] myEquationsSystem.constraint; - myEquationsSystem.constraint = new Slvs_Constraint[theSize]; - if (myEquationsSystem.failed) - delete[] myEquationsSystem.failed; - myEquationsSystem.failed = new Slvs_hConstraint[theSize]; - } - myEquationsSystem.constraints = theSize; - } - memcpy(myEquationsSystem.constraint, theConstraints, theSize * sizeof(Slvs_Constraint)); - memset(myEquationsSystem.failed, SLVS_C_UNKNOWN, theSize * sizeof(Slvs_hConstraint)); -} - - -SketchSolver_SolveStatus SolveSpaceSolver_Solver::solve() -{ - if (myEquationsSystem.constraints <= 0) - return STATUS_EMPTYSET; - - myEquationsSystem.calculateFaileds = myFindFaileds ? 1 : 0; - - Events_LongOp::start(this); - Slvs_Solve(&myEquationsSystem, myGroup); - Events_LongOp::end(this); - - 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 aStatus; -} diff --git a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Solver.h b/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Solver.h deleted file mode 100644 index c853970a3..000000000 --- a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Solver.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: SolveSpaceSolver_Solver.h -// Created: 07 May 2014 -// Author: Artem ZHIDKOV - -#ifndef SolveSpaceSolver_Solver_H_ -#define SolveSpaceSolver_Solver_H_ - -#include - -// 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 -#include -#endif -#include -#include - -#include - -// Unknown constraint (for error reporting) -#define SLVS_C_UNKNOWN 0 -// Fillet constraint identifier -#define SLVS_C_FILLET 100100 -// Multi-rotation constraint identifier -#define SLVS_C_MULTI_ROTATION 100101 -// Multi-translation constraint identifier -#define SLVS_C_MULTI_TRANSLATION 100102 -// Unknown entity -#define SLVS_E_UNKNOWN 0 -// Unknown group -#define SLVS_G_UNKNOWN 0 -// Group ID to store external objects -#define SLVS_G_OUTOFGROUP 1 - -/** \class SolveSpaceSolver_Solver - * \ingroup Plugins - * \brief Performs high-level operations to solve sketch in SolveSpace. - */ -class SolveSpaceSolver_Solver : public SketchSolver_ISolver -{ - public: - SolveSpaceSolver_Solver(); - virtual ~SolveSpaceSolver_Solver(); - - /** \brief Change array of parameters - * \param[in] theParameters pointer to the array of parameters - * \param[in] theSize size of this array - */ - void setParameters(Slvs_Param* theParameters, int theSize); - - /** \brief Change array of entities - * \param[in] theEntities pointer to the array of entities - * \param[in] theSize size of this array - */ - void setEntities(Slvs_Entity* theEntities, int theSize); - - /** \brief Change array of constraints - * \param[in] theConstraints pointer to the array of constraints - * \param[in] theSize size of this array - */ - void setConstraints(Slvs_Constraint* theConstraints, int theSize); - - /** \brief Store the parameters of the point which was moved by user. - * The solver will watch this items to be constant - * \param[in] theDragged list of parameters (not more than 4) which should not be changed during solving - */ - void setDraggedParameters(const Slvs_hParam* theDragged); - - /** \brief Solve the set of equations - * \return identifier whether solution succeeded - */ - virtual SketchSolver_SolveStatus solve(); - - private: - 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 deleted file mode 100644 index 7843cd88c..000000000 --- a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Storage.cpp +++ /dev/null @@ -1,2044 +0,0 @@ -// 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; -//// else if (aParameter->isParametric() && aParamToUpd.group != (Slvs_hGroup)GID_OUTOFGROUP) -//// aParameter->setGroup(GID_OUTOFGROUP); - 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); - 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; -//// myRemovedParameters.insert(theParamID); - return true; - } -//// else if (myRemovedParameters.find(theParamID) != myRemovedParameters.end()) -//// return 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; -//// myRemovedEntities.insert(theEntityID); -//// if (anEntity.type == SLVS_E_POINT_IN_2D || anEntity.type == SLVS_E_POINT_IN_3D) -//// removeCoincidentPoint(theEntityID); - } -//// else if (myRemovedEntities.find(theEntityID) != myRemovedEntities.end()) -//// return 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]); -//// 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 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); -//// 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 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); -//// 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) - 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; -//// if (aConstraint.type == SLVS_C_POINTS_COINCIDENT) -//// addCoincidentPoints(aConstraint.ptA, aConstraint.ptB); - 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; -//// if (theConstraint.type == SLVS_C_POINTS_COINCIDENT) -//// addCoincidentPoints(theConstraint.ptA, theConstraint.ptB); - 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; -//// 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; - } - } - } -//// else if (myRemovedConstraints.find(theConstraintID) != myRemovedConstraints.end()) -//// return 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::getRemoved( -//// std::set& theParameters, -//// std::set& theEntities, -//// std::set& theConstraints) -////{ -//// theParameters = myRemovedParameters; -//// theEntities = myRemovedEntities; -//// theConstraints = myRemovedConstraints; -//// -//// myRemovedParameters.clear(); -//// myRemovedEntities.clear(); -//// myRemovedConstraints.clear(); -////} - -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()); -} - -////void SolveSpaceSolver_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); -//// } -////} -//// -////void SolveSpaceSolver_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 SolveSpaceSolver_Storage::removeCoincidence(const Slvs_Constraint& theCoincidence) -////{ -//// // 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); -////} -//// -////bool SolveSpaceSolver_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()) -//// return true; -//// return false; -////} - -bool SolveSpaceSolver_Storage::isEqual( - const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const -{ -//// if (isCoincident(thePoint1, thePoint2)) -//// 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) - 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; -} - -////bool SolveSpaceSolver_Storage::isNeedToResolve() -////{ -//// if (myConstraints.empty()) -//// 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; -//// } -//// } -//// } -//// -//// myUpdatedParameters.clear(); -//// return myNeedToResolve; -////} - -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]); - } - 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 deleted file mode 100644 index 015ada986..000000000 --- a/src/SketchSolver/SolveSpaceSolver/SolveSpaceSolver_Storage.h +++ /dev/null @@ -1,302 +0,0 @@ -// 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 Returns lists of removed elements -//// void getRemoved(std::set& theParameters, -//// std::set& theEntities, -//// std::set& theConstraints); - -//// /// \brief Shows the sketch should be resolved -//// virtual bool isNeedToResolve(); - - /// \brief Initialize constraint solver by the entities collected by current storage - virtual void initializeSolver(SolverPtr 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); - -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 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) - - SameConstraintMap myEqualConstraints; ///< list of groups of equal constraints -}; - -#endif