From: azv Date: Wed, 18 Mar 2015 05:26:37 +0000 (+0300) Subject: SketchSolver library refactoring X-Git-Tag: V_1.1.0~57^2~19 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=bc06873747d5ea9bc0e8d6bd56641eebe33ac08d;p=modules%2Fshaper.git SketchSolver library refactoring 1. Implemented data storages and base constraint 2. Implemented coincidence and fixed constraints --- diff --git a/src/SketchPlugin/SketchPlugin_Constraint.h b/src/SketchPlugin/SketchPlugin_Constraint.h index 62abd9eef..49f98b0cf 100644 --- a/src/SketchPlugin/SketchPlugin_Constraint.h +++ b/src/SketchPlugin/SketchPlugin_Constraint.h @@ -84,4 +84,6 @@ class SketchPlugin_Constraint : public SketchPlugin_Feature } }; +typedef std::shared_ptr ConstraintPtr; + #endif diff --git a/src/SketchSolver/CMakeLists.txt b/src/SketchSolver/CMakeLists.txt index 572c8b0c7..fed46c0ec 100644 --- a/src/SketchSolver/CMakeLists.txt +++ b/src/SketchSolver/CMakeLists.txt @@ -5,17 +5,28 @@ INCLUDE(FindSolveSpace) SET(PROJECT_HEADERS SketchSolver.h + SketchSolver_Error.h SketchSolver_Solver.h SketchSolver_Constraint.h - SketchSolver_ConstraintGroup.h + SketchSolver_ConstraintCoincidence.h + SketchSolver_ConstraintRigid.h + SketchSolver_Builder.h + SketchSolver_Group.h SketchSolver_ConstraintManager.h + SketchSolver_Storage.h + SketchSolver_FeatureStorage.h ) SET(PROJECT_SOURCES SketchSolver_Solver.cpp SketchSolver_Constraint.cpp - SketchSolver_ConstraintGroup.cpp + SketchSolver_ConstraintCoincidence.cpp + SketchSolver_ConstraintRigid.cpp + SketchSolver_Builder.cpp + SketchSolver_Group.cpp SketchSolver_ConstraintManager.cpp + SketchSolver_Storage.cpp + SketchSolver_FeatureStorage.cpp ) SET(PROJECT_LIBRARIES diff --git a/src/SketchSolver/SketchSolver.h b/src/SketchSolver/SketchSolver.h index f31b7e49f..77bb4029a 100644 --- a/src/SketchSolver/SketchSolver.h +++ b/src/SketchSolver/SketchSolver.h @@ -17,4 +17,7 @@ #endif #endif +/// Tolerance for value of parameters +const double tolerance = 1.e-10; + #endif diff --git a/src/SketchSolver/SketchSolver_Builder.cpp b/src/SketchSolver/SketchSolver_Builder.cpp new file mode 100644 index 000000000..67fbdc1f2 --- /dev/null +++ b/src/SketchSolver/SketchSolver_Builder.cpp @@ -0,0 +1,270 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_Builder.cpp +// Created: 25 Mar 2015 +// Author: Artem ZHIDKOV + +#include "SketchSolver_Builder.h" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// Initialization of constraint builder self pointer +SketchSolver_Builder* SketchSolver_Builder::mySelf = 0; + +SketchSolver_Builder* SketchSolver_Builder::getInstance() +{ + if (!mySelf) + mySelf = new SketchSolver_Builder(); + return mySelf; +} + +SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theConstraint) +{ + SolverConstraintPtr aResult; + DataPtr aData = theConstraint->data(); + if (!aData || !aData->isValid()) + return aResult; + + if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { + return SolverConstraintPtr(new SketchSolver_ConstraintCoincidence(theConstraint)); + } else if (theConstraint->getKind() == SketchPlugin_ConstraintDistance::ID()) { + return SolverConstraintPtr(new SketchSolver_ConstraintDistance(theConstraint)); + } else if (theConstraint->getKind() == SketchPlugin_ConstraintEqual::ID()) { +//// return SolverConstraintPtr(new SketchSolver_ConstraintEqual(theConstraint)); + } else if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) { +//// return SolverConstraintPtr(new SketchSolver_ConstraintFillet(theConstraint)); + } else if (theConstraint->getKind() == SketchPlugin_ConstraintHorizontal::ID()) { + return SolverConstraintPtr(new SketchSolver_ConstraintHorizontal(theConstraint)); + } else if (theConstraint->getKind() == SketchPlugin_ConstraintLength::ID()) { +//// return SolverConstraintPtr(new SketchSolver_ConstraintLength(theConstraint)); + } else if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) { +//// return SolverConstraintPtr(new SketchSolver_ConstraintMirror(theConstraint)); + } else if (theConstraint->getKind() == SketchPlugin_ConstraintParallel::ID()) { + return SolverConstraintPtr(new SketchSolver_ConstraintParallel(theConstraint)); + } else if (theConstraint->getKind() == SketchPlugin_ConstraintPerpendicular::ID()) { + return SolverConstraintPtr(new SketchSolver_ConstraintPerpendicular(theConstraint)); + } else if (theConstraint->getKind() == SketchPlugin_ConstraintRadius::ID()) { +//// return SolverConstraintPtr(new SketchSolver_ConstraintRadius(theConstraint)); + } else if (theConstraint->getKind() == SketchPlugin_ConstraintTangent::ID()) { +//// return SolverConstraintPtr(new SketchSolver_ConstraintTangent(theConstraint)); + } else if (theConstraint->getKind() == SketchPlugin_ConstraintVertical::ID()) { + return SolverConstraintPtr(new SketchSolver_ConstraintVertical(theConstraint)); + } else if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID()) { + return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theConstraint)); + } + return aResult; +} + +SolverConstraintPtr SketchSolver_Builder::createRigidConstraint(FeaturePtr theFixedFeature) +{ + DataPtr aData = theFixedFeature->data(); + if (!aData || !aData->isValid()) + return SolverConstraintPtr(); + return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theFixedFeature)); +} + + + +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; + + // 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) +{ + Slvs_hEntity anEntID = theEntities.empty() ? 0 : theEntities.back().h; + Slvs_hParam aParamID = theParameters.empty() ? 0 : theParameters.back().h; + + // Point in 3D + std::shared_ptr aPoint = + std::dynamic_pointer_cast(theAttribute); + if (aPoint) { + theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->x())); + theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->y())); + theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->z())); + theEntities.push_back(Slvs_MakePoint3d(++anEntID, SLVS_G_UNKNOWN, + aParamID-2, aParamID-1, aParamID)); + return true; + } + // Point in 2D + std::shared_ptr aPoint2D = + std::dynamic_pointer_cast(theAttribute); + if (aPoint2D) { + theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint2D->x())); + theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint2D->y())); + theEntities.push_back(Slvs_MakePoint2d(++anEntID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN, + aParamID-1, aParamID)); + return true; + } + // Scalar value (used for the distance entities) + AttributeDoublePtr aScalar = std::dynamic_pointer_cast(theAttribute); + if (aScalar) { + theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aScalar->value())); + theEntities.push_back(Slvs_MakeDistance(++anEntID, SLVS_G_UNKNOWN, + SLVS_E_UNKNOWN, aParamID)); + return true; + } + // unknown attribute type + return false; +} + +bool SketchSolver_Builder::createEntity( + FeaturePtr theFeature, + std::vector& theEntities, + std::vector& theParameters) +{ + if (!theFeature->data()->isValid()) + return false; + + // SketchPlugin features + std::shared_ptr aFeature = std::dynamic_pointer_cast< + SketchPlugin_Feature>(theFeature); + if (!aFeature) + return false; + + // Verify the feature by its kind + const std::string& aFeatureKind = aFeature->getKind(); + DataPtr aData = aFeature->data(); + // Line + if (aFeatureKind == SketchPlugin_Line::ID()) { + AttributePtr aStart = aData->attribute(SketchPlugin_Line::START_ID()); + AttributePtr aEnd = aData->attribute(SketchPlugin_Line::END_ID()); + if (!aStart->isInitialized() || !aEnd->isInitialized()) + return false; + if (!createEntity(aStart, theEntities, theParameters) || + !createEntity(aEnd, theEntities, theParameters)) + return false; + Slvs_hEntity aLineID = theEntities.back().h + 1; + theEntities.push_back(Slvs_MakeLineSegment(aLineID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN, + aLineID-2, aLineID-1)); + } + // Circle + else if (aFeatureKind == SketchPlugin_Circle::ID()) { + AttributePtr aCenter = aData->attribute(SketchPlugin_Circle::CENTER_ID()); + AttributePtr aRadius = aData->attribute(SketchPlugin_Circle::RADIUS_ID()); + if (!aCenter->isInitialized() || !aRadius->isInitialized()) + return false; + if (!createEntity(aCenter, theEntities, theParameters) || + !createEntity(aRadius, theEntities, theParameters)) + return false; + Slvs_hEntity aCircID = theEntities.back().h; + theEntities.push_back(Slvs_MakeCircle(aCircID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN, aCircID-2, + SLVS_E_UNKNOWN, aCircID-1)); + } + // Arc + else if (aFeatureKind == SketchPlugin_Arc::ID()) { + AttributePtr aCenter = aData->attribute(SketchPlugin_Arc::CENTER_ID()); + AttributePtr aStart = aData->attribute(SketchPlugin_Arc::START_ID()); + AttributePtr aEnd = aData->attribute(SketchPlugin_Arc::END_ID()); + if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized()) + return false; + if (!createEntity(aCenter, theEntities, theParameters) || + !createEntity(aStart, theEntities, theParameters) || + !createEntity(aEnd, theEntities, theParameters)) + return false; + Slvs_hEntity anArcID = theEntities.back().h; + theEntities.push_back(Slvs_MakeArcOfCircle(anArcID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN, + SLVS_E_UNKNOWN, anArcID-3, anArcID-2, anArcID-1)); + } + // Point (it has low probability to be an attribute of constraint, so it is checked at the end) + else if (aFeatureKind == SketchPlugin_Point::ID()) { + AttributePtr aPoint = aData->attribute(SketchPlugin_Point::COORD_ID()); + if (!aPoint->isInitialized() || + !createEntity(aPoint, theEntities, theParameters)) + return false; + // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier. + // No need to add another entity. + } + return true; +} + +bool SketchSolver_Builder::createNormal( + AttributePtr theNormal, + AttributePtr theDirX, + std::vector& theEntities, + std::vector& theParameters) +{ + std::shared_ptr aNorm = std::dynamic_pointer_cast(theNormal); + std::shared_ptr aDirX = std::dynamic_pointer_cast(theDirX); + if (!aDirX || (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance)) + 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 new file mode 100644 index 000000000..e9aa10d9e --- /dev/null +++ b/src/SketchSolver/SketchSolver_Builder.h @@ -0,0 +1,74 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_Builder.h +// Created: 25 Mar 2015 +// Author: Artem ZHIDKOV + +#ifndef SketchSolver_Builder_H_ +#define SketchSolver_Builder_H_ + +#include "SketchSolver.h" +#include + +#include + +#include + +/** \class SketchSolver_Builder + * \ingroup Plugins + * \brief Create bridges between SketchPlugin constraints and SolveSpace constraints + */ +class SketchSolver_Builder +{ +private: + /// Default constructor + SketchSolver_Builder() {} + +public: + /// \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); + + /// \brief Creates temporary constraint to fix the placement of the feature + SolverConstraintPtr createRigidConstraint(FeaturePtr theFixedFeature); + + /// \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; +}; + +#endif diff --git a/src/SketchSolver/SketchSolver_Constraint.cpp b/src/SketchSolver/SketchSolver_Constraint.cpp index 4686f6f3c..d8d3df086 100644 --- a/src/SketchSolver/SketchSolver_Constraint.cpp +++ b/src/SketchSolver/SketchSolver_Constraint.cpp @@ -1,353 +1,516 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: SketchSolver_Constraint.cpp -// Created: 27 May 2014 -// Author: Artem ZHIDKOV - -#include "SketchSolver_Constraint.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 + -/// Possible types of attributes (used to determine constraint type) -enum AttrType +SketchSolver_Constraint::SketchSolver_Constraint( + ConstraintPtr theConstraint) + : myBaseConstraint(theConstraint), + myGroup(0) { - UNKNOWN, // Something wrong during type determination - POINT2D, - POINT3D, - LINE, - CIRCLE, - ARC -}; - -/// Calculate type of the attribute -static AttrType typeOfAttribute(std::shared_ptr theAttribute); - -SketchSolver_Constraint::SketchSolver_Constraint() - : myConstraint(std::shared_ptr()), - myType(SLVS_C_UNKNOWN), - myAttributesList() +} + +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::const_iterator anIt3 = myFeatureMap.begin(); + for (; anIt3 != myFeatureMap.end(); anIt3++) + myStorage->removeEntity(anIt3->second); + myFeatureMap.clear(); + + std::vector::const_iterator anIt4 = mySlvsConstraints.begin(); + for (; anIt4 != mySlvsConstraints.end(); anIt4++) + myStorage->removeConstraint(*anIt4); + mySlvsConstraints.clear(); } -SketchSolver_Constraint::SketchSolver_Constraint( - std::shared_ptr theConstraint) - : myConstraint(theConstraint), - myAttributesList() +void SketchSolver_Constraint::setStorage(StoragePtr theStorage) { - myType = getType(myConstraint); + myStorage = theStorage; + process(); } -const int& SketchSolver_Constraint::getType( - std::shared_ptr theConstraint) +void SketchSolver_Constraint::setGroup(SketchSolver_Group* theGroup) { - myType = SLVS_C_UNKNOWN; - if (!theConstraint) - return getType(); - - DataPtr aConstrData = theConstraint->data(); - if (!aConstrData || !aConstrData->isValid()) - return getType(); - - // Assign empty names of attributes - myAttributesList.clear(); - for (int i = 0; i < CONSTRAINT_ATTR_SIZE; i++) - myAttributesList.push_back(std::string()); - - const std::string& aConstraintKind = theConstraint->getKind(); - // Constraint for coincidence of two points - if (aConstraintKind.compare(SketchPlugin_ConstraintCoincidence::ID()) == 0) { - int anAttrPos = 0; - // Verify the constraint has only two attributes and they are points - int aPt2d = 0; // bit-mapped field, each bit indicates whether the attribute is 2D point - int aPt3d = 0; // bit-mapped field, the same information for 3D points - for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) { - std::shared_ptr anAttr = - aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)); - if (!anAttr) - continue; - switch (typeOfAttribute(anAttr)) { - case POINT2D: // the attribute is a 2D point - aPt2d |= (1 << indAttr); - myAttributesList[anAttrPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); - break; - case POINT3D: // the attribute is a 3D point - aPt3d |= (1 << indAttr); - myAttributesList[anAttrPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); - break; - default: - // Attribute neither 2D nor 3D point is not supported by this type of constraint - return getType(); - } - } - // The constrained points should be in first and second positions, - // so the expected value of aPt2d or aPt3d is 3 - if (aPt2d + aPt3d == 3) - myType = SLVS_C_POINTS_COINCIDENT; - // Constraint parameters are wrong - return getType(); + myGroup = theGroup; + process(); +} + + +void SketchSolver_Constraint::process() +{ + cleanErrorMsg(); + if (!myBaseConstraint || !myStorage || myGroup == 0) { + /// TODO: Put error message here + return; } + if (!mySlvsConstraints.empty()) // some data is changed, update constraint + update(myBaseConstraint); - // Constraint for distance between point and another entity - if (aConstraintKind.compare(SketchPlugin_ConstraintDistance::ID()) == 0) { - int aNbPoints = 0; - int aNbEntities = 0; - for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) { - std::shared_ptr anAttr = - aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)); - switch (typeOfAttribute(anAttr)) { - case POINT2D: - case POINT3D: - myAttributesList[aNbPoints++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); - break; - case LINE: - // entities are placed starting from SketchPlugin_Constraint::ENTITY_C() attribute - myAttributesList[2 + aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); - myType = SLVS_C_PT_LINE_DISTANCE; - break; - } - } - // Verify the correctness of constraint arguments - if (aNbPoints == 2 && aNbEntities == 0) - myType = SLVS_C_PT_PT_DISTANCE; - else if (aNbPoints != 1 || aNbEntities != 1) - myType = SLVS_C_UNKNOWN; - return getType(); + int aConstrType = getType(); + double aValue = 0.0; + std::vector anAttributes; + getAttributes(aValue, anAttributes); + if (!myErrorMsg.empty()) + return; + + 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; } - // Constraint for the given length of a line - if (aConstraintKind.compare(SketchPlugin_ConstraintLength::ID()) == 0) { - int aNbLines = 0; - for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) { - std::shared_ptr anAttr = - aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)); - if (typeOfAttribute(anAttr) == LINE) - myAttributesList[aNbLines++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); - } - if (aNbLines == 1) - myType = SLVS_C_PT_PT_DISTANCE; - return getType(); + Slvs_hConstraint anID = myStorage->addConstraint(aConstraint); + if (mySlvsConstraints.empty()) + mySlvsConstraints.push_back(anID); + else + mySlvsConstraints[0] = anID; +} + +void SketchSolver_Constraint::update(ConstraintPtr theConstraint) +{ + cleanErrorMsg(); + if (theConstraint && theConstraint != myBaseConstraint) { + if (theConstraint->getKind() != myBaseConstraint->getKind()) + return; + remove(myBaseConstraint); + myBaseConstraint = theConstraint; + process(); } - // Constraint for two parallel/perpendicular lines - bool isParallel = (aConstraintKind.compare(SketchPlugin_ConstraintParallel::ID()) == 0); - bool isPerpendicular = (aConstraintKind.compare(SketchPlugin_ConstraintPerpendicular::ID()) == 0); - if (isParallel || isPerpendicular) { - int aNbEntities = 2; // lines in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute - for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) { - std::shared_ptr anAttr = - aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)); - if (typeOfAttribute(anAttr) == LINE) - myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); + int aType; + std::map::iterator aFeatIter = myFeatureMap.begin(); + for (; aFeatIter != myFeatureMap.end(); aFeatIter++) + aFeatIter->second = changeEntity(aFeatIter->first, aType); + std::map::iterator anAttrIter = myAttributeMap.begin(); + for (; anAttrIter != myAttributeMap.end(); anAttrIter++) + anAttrIter->second = changeEntity(anAttrIter->first, aType); +} + +bool SketchSolver_Constraint::remove(ConstraintPtr theConstraint) +{ + cleanErrorMsg(); + if (theConstraint && theConstraint != myBaseConstraint) + return false; + bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints.front()); + if (isFullyRemoved) { + myFeatureMap.clear(); + myAttributeMap.clear(); + myValueMap.clear(); + } else + cleanRemovedEntities(); + 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; } - if (aNbEntities == 4) - myType = isParallel ? SLVS_C_PARALLEL : SLVS_C_PERPENDICULAR; - return getType(); + 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); + } +} + +void SketchSolver_Constraint::getAttributes( + double& theValue, + std::vector& theAttributes) +{ + static const int anInitNbOfAttr = 4; + theAttributes.assign(anInitNbOfAttr, SLVS_E_UNKNOWN); + + DataPtr aData = myBaseConstraint->data(); - // Constraint for radius of a circle or an arc of circle - if (aConstraintKind.compare(SketchPlugin_ConstraintRadius::ID()) == 0) { - int aNbEntities = 2; // lines in SolveSpace constraints should started from SketchPlugin_Constraint::ENTITY_C() attribute - for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) { - std::shared_ptr anAttr = - aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)); - AttrType aType = typeOfAttribute(anAttr); - if (aType == CIRCLE || aType == ARC) - myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); + AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_Constraint::VALUE())); + theValue = aValueAttr ? aValueAttr->value() : 0.0; + + int aPtInd = 0; // index of first point in the list of attributes + int aEntInd = 2; // index of first antity in the list of attributes + std::list aConstrAttrs = aData->attributes(ModelAPI_AttributeRefAttr::typeId()); + std::list::iterator anIter = aConstrAttrs.begin(); + for (; anIter != aConstrAttrs.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); + else { + Slvs_Entity anEnt = myStorage->getEntity(anEntity); + aType = anEnt.type; + } + + if (aType == SLVS_E_UNKNOWN) + continue; + 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) + theAttributes[aEntInd] = anEntity; + else + theAttributes.push_back(anEntity); + aEntInd++; } - if (aNbEntities == 3) - myType = SLVS_C_DIAMETER; - return getType(); } +} - // Constraint for fixed entity - if (aConstraintKind.compare(SketchPlugin_ConstraintRigid::ID()) == 0) { - // Verify that only one entity is filled - int aNbAttrs = 0; - for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) { - std::shared_ptr anAttr = - aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)); - AttrType aType = typeOfAttribute(anAttr); - if (aType != UNKNOWN) - myAttributesList[aNbAttrs++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); +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; } - if (aNbAttrs == 1) - myType = SLVS_C_WHERE_DRAGGED; - return getType(); + std::shared_ptr aDoc = aRC->document(); + aFeature = aDoc->feature(aRC); + + return changeEntity(aFeature, theType); } - // Constraint for horizontal/vertical line - bool isHorizontal = (aConstraintKind.compare(SketchPlugin_ConstraintHorizontal::ID()) == 0); - bool isVertical = (aConstraintKind.compare(SketchPlugin_ConstraintVertical::ID()) == 0); - if (isHorizontal || isVertical) { - int aNbEntities = 2; // lines in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute - for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) { - std::shared_ptr anAttr = - aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)); - if (typeOfAttribute(anAttr) == LINE) - myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); + return changeEntity(theAttribute->attr(), theType); +} + +Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributePtr theEntity, int& theType) +{ + Slvs_hEntity aResult = SLVS_E_UNKNOWN; + if (!theEntity->isInitialized()) + 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; + return aResult; } - if (aNbEntities == 3) - myType = isHorizontal ? SLVS_C_HORIZONTAL : SLVS_C_VERTICAL; - return getType(); } - if (aConstraintKind.compare(SketchPlugin_ConstraintEqual::ID()) == 0) { - static const int aConstrType[3] = { - SLVS_C_EQUAL_RADIUS, - SLVS_C_EQUAL_LINE_ARC_LEN, - SLVS_C_EQUAL_LENGTH_LINES - }; - int aNbLines = 0; - int aNbEntities = 2; // lines and circles in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute - for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) { - std::shared_ptr anAttr = - aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)); - AttrType aType = typeOfAttribute(anAttr); - if (aType == LINE) { - myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); - aNbLines++; + Slvs_hGroup aGroupID = myGroup->getId(); + // 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); } - else if (aType == CIRCLE || aType == ARC) - myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); } - if (aNbEntities == 4) - myType = aConstrType[aNbLines]; - return getType(); } - if (aConstraintKind.compare(SketchPlugin_ConstraintTangent::ID()) == 0) { - static const int anArcPosDefault = 2; - static const int aLinePosDefault = 3; - int anArcPos = anArcPosDefault; // arc in tangency constraint should be placed before line - int aLinePos = aLinePosDefault; - for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) { - std::shared_ptr anAttr = - aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)); - AttrType aType = typeOfAttribute(anAttr); - if (aType == LINE && aLinePos < CONSTRAINT_ATTR_SIZE) - myAttributesList[aLinePos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); - else if (aType == ARC) - myAttributesList[anArcPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); + 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->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; + return aResult; } - if (anArcPos - anArcPosDefault + aLinePos - aLinePosDefault == 2) - myType = aLinePos > 3 ? SLVS_C_ARC_LINE_TANGENT : SLVS_C_CURVE_CURVE_TANGENT; - return getType(); } - if (aConstraintKind.compare(SketchPlugin_ConstraintMirror::ID()) == 0) { - int aNbAttrs = 0; - bool hasMirrorLine = false; - for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) { - AttributeRefListPtr anAttrRefList = std::dynamic_pointer_cast( - aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr))); - if (anAttrRefList) { - aNbAttrs++; - myAttributesList[aNbAttrs] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); - } + Slvs_hGroup aGroupID = myGroup->getId(); + Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId(); + // SketchPlugin features + std::shared_ptr aFeature = std::dynamic_pointer_cast< + SketchPlugin_Feature>(theEntity); + if (aFeature) { // Verify the feature by its kind + const std::string& aFeatureKind = aFeature->getKind(); + AttributePtr anAttribute; + int anAttrType; + + // Line + if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) { + anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID()); + if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; + Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType); + + anAttribute = aFeature->data()->attribute(SketchPlugin_Line::END_ID()); + if (!anAttribute->isInitialized()) 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 { - std::shared_ptr anAttr = - aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)); - if (typeOfAttribute(anAttr) == LINE) { - hasMirrorLine = !hasMirrorLine; - myAttributesList[0] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); - } + aCurrentEntity.point[0] = aStart; + aCurrentEntity.point[1] = aEnd; } + aResult = myStorage->addEntity(aCurrentEntity); } - if (aNbAttrs == 2 && hasMirrorLine) - myType = SLVS_C_SYMMETRIC_LINE; - return getType(); - } + // Circle + else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) { + anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID()); + if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; + Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType); - if (aConstraintKind.compare(SketchPlugin_ConstraintFillet::ID()) == 0) { - int aNbAttrs = 0; - for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) { - AttributeRefListPtr anAttrRefList = std::dynamic_pointer_cast( - aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr))); - if (anAttrRefList) - myAttributesList[aNbAttrs++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); - else { - std::shared_ptr anAttr = - aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)); - AttrType aType = typeOfAttribute(anAttr); - if (aType == LINE || aType == ARC) - myAttributesList[aNbAttrs++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); + anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()); + if (!anAttribute->isInitialized()) 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); } - if (aNbAttrs == 3) - myType = SLVS_C_FILLET; - return getType(); - } + // Arc + else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) { + anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID()); + if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; + Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType); - /// \todo Implement other kind of constraints + anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::START_ID()); + if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; + Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType); + + anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::END_ID()); + if (!anAttribute->isInitialized()) 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.compare(SketchPlugin_Point::ID()) == 0) { + anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID()); + if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; + // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier + aResult = changeEntity(anAttribute, anAttrType); + aCurrentEntity.type = SLVS_E_POINT_IN_3D; + } + } - return getType(); + myFeatureMap[theEntity] = aResult; + theType = aCurrentEntity.type; + return aResult; } -// ================= Auxiliary functions ============================== -AttrType typeOfAttribute(std::shared_ptr theAttribute) +std::list SketchSolver_Constraint::constraints() const { - std::shared_ptr anAttrRef = std::dynamic_pointer_cast< - ModelAPI_AttributeRefAttr>(theAttribute); - if (!anAttrRef) - return UNKNOWN; + std::list aConstraints; + aConstraints.push_back(myBaseConstraint); + return aConstraints; +} - if (anAttrRef->isObject()) { - ResultConstructionPtr aRC = std::dynamic_pointer_cast( - anAttrRef->object()); - if (!aRC || !aRC->shape()) - return UNKNOWN; - - if (aRC->shape()->isVertex()) - return POINT3D; - else if (aRC->shape()->isEdge()) { - std::shared_ptr anEdge = std::dynamic_pointer_cast( - aRC->shape()); - if (anEdge->isLine()) - return LINE; - else if (anEdge->isCircle()) - return CIRCLE; - else if (anEdge->isArc()) - return ARC; +void SketchSolver_Constraint::refresh() +{ + cleanErrorMsg(); + std::map::iterator anAttrIter = myAttributeMap.begin(); + for (; anAttrIter != myAttributeMap.end(); anAttrIter++) { + std::shared_ptr aPoint = + std::dynamic_pointer_cast(anAttrIter->first); + if (aPoint) { + Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second); + double aXYZ[3]; + for (int i = 0; i < 3; i++) { + Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]); + aXYZ[i] = aPar.val; + } + aPoint->setValue(aXYZ[0], aXYZ[1], aXYZ[2]); + } else { + // Point in 2D + std::shared_ptr aPoint2D = + std::dynamic_pointer_cast(anAttrIter->first); + if (aPoint2D) { + Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second); + double aXYZ[2]; + for (int i = 0; i < 2; i++) { + Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]); + aXYZ[i] = aPar.val; + } + aPoint2D->setValue(aXYZ[0], aXYZ[1]); + } else { + // Scalar value (used for the distance entities) + AttributeDoublePtr aScalar = + std::dynamic_pointer_cast(anAttrIter->first); + if (aScalar) { + Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second); + Slvs_Param aPar = myStorage->getParameter(anEntity.param[0]); + aScalar->setValue(aPar.val); + } + } } - } else { - if (anAttrRef->attr().get() != NULL) { - const std::string aType = anAttrRef->attr()->attributeType(); - if (aType == GeomDataAPI_Point2D::typeId()) - return POINT2D; - if (aType == GeomDataAPI_Point2D::typeId()) - return POINT2D; + } + + 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; + return aFIter->second; +} - return UNKNOWN; +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; } diff --git a/src/SketchSolver/SketchSolver_Constraint.h b/src/SketchSolver/SketchSolver_Constraint.h index 5a98e31be..b7925d66c 100644 --- a/src/SketchSolver/SketchSolver_Constraint.h +++ b/src/SketchSolver/SketchSolver_Constraint.h @@ -8,46 +8,184 @@ #define SketchSolver_Constraint_H_ #include "SketchSolver.h" +#include #include +#include + #include #include +class SketchSolver_Group; + /** \class SketchSolver_Constraint * \ingroup Plugins - * \brief Obtain information about SketchPlugin's constraint + * \brief Stores mapping between SketchPlugin and SolveSpace constraints data */ class SketchSolver_Constraint { -public: +protected: /// Default constructor - SketchSolver_Constraint(); - /// Creates constraint to manage the given constraint from plugin - SketchSolver_Constraint(std::shared_ptr theConstraint); - - /** \brief Compute constraint type according to SolveSpace identifiers - * and verify that constraint parameters are correct - * \param[in] theConstraint constraint which type should be determined - * \return identifier of constraint type or SLVS_C_UNKNOWN if the type is wrong - */ - const int& getType(std::shared_ptr theConstraint); - /// \brief Returns the type of myConstraint member - inline const int& getType() const - { - return myType; - } - - /// \brief Returns list of attributes names in the correct order required by SolveSpace - inline const std::vector& getAttributes() const - { - return myAttributesList; - } - - private: - std::shared_ptr myConstraint; - int myType; - std::vector myAttributesList; + SketchSolver_Constraint() {} + SketchSolver_Constraint(ConstraintPtr theConstraint); + +public: + virtual ~SketchSolver_Constraint(); + + /// \brief Initializes the storage of SolveSpace constraints + void setStorage(StoragePtr theStorage); + /// \brief Initializes group ID for this constraint + void setGroup(SketchSolver_Group* theGroup); + + /// \brief 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 Update SketchPlugin attributes using the data obtained from SolveSpace entities + void refresh(); + + /// \brief Returns the type of constraint + virtual int getType() const = 0; + + /// \brief Checks the constraint is used by current object + virtual bool hasConstraint(ConstraintPtr theConstraint) const + { return theConstraint == myBaseConstraint; } + + /// \brief Return list of SketchPlugin constraints attached to this object + virtual std::list constraints() const; + + /// \brief Return identifier of SolveSpace entity relating to the feature + Slvs_hEntity getId(FeaturePtr theFeature) const; + /// \brief Return identifier of SolveSpace entity relating to the attribute + Slvs_hEntity getId(AttributePtr theAttribute) const; + + /// \brief Shows error message + const std::string& error() const + { return myErrorMsg; } + +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 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 Removes the links to unused entities + void cleanRemovedEntities(); + + /// \brief Removes last error + void cleanErrorMsg() + { myErrorMsg.clear(); } + +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_ConstraintDistance + * \ingroup Plugins + * \brief Convert distance constraint to SolveSpace structure + */ +class SketchSolver_ConstraintDistance : public SketchSolver_Constraint +{ +public: + SketchSolver_ConstraintDistance(ConstraintPtr theConstraint) : + SketchSolver_Constraint(theConstraint) + {} + + virtual int getType() const + { return SLVS_C_PT_PT_DISTANCE; } +}; + + +/** \class SketchSolver_ConstraintParallel + * \ingroup Plugins + * \brief Convert Parallel constraint to SolveSpace structure + */ +class SketchSolver_ConstraintParallel : public SketchSolver_Constraint +{ +public: + 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: + 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: + 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: + SketchSolver_ConstraintVertical(ConstraintPtr theConstraint) : + SketchSolver_Constraint(theConstraint) + {} + + virtual int getType() const + { return SLVS_C_VERTICAL; } }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp b/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp new file mode 100644 index 000000000..a5b6001e7 --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp @@ -0,0 +1,140 @@ +#include +#include +#include + +#include + +bool SketchSolver_ConstraintCoincidence::hasConstraint(ConstraintPtr theConstraint) const +{ + if (myBaseConstraint == theConstraint) + return true; + std::map::const_iterator anIt = myExtraCoincidence.begin(); + for (; anIt != myExtraCoincidence.end(); anIt++) + if (anIt->first == theConstraint) + return true; + return false; +} + +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::map::const_iterator aFeatIter = myFeatureMap.begin(); + for (; aFeatIter != myFeatureMap.end(); aFeatIter++) + if (theConstraint->myFeatureMap.find(aFeatIter->first) != theConstraint->myFeatureMap.end()) + return true; + std::map::const_iterator anAttrIter = myAttributeMap.begin(); + for (; anAttrIter != myAttributeMap.end(); anAttrIter++) + if (theConstraint->myAttributeMap.find(anAttrIter->first) != theConstraint->myAttributeMap.end()) + return true; + return false; +} + +void SketchSolver_ConstraintCoincidence::attach( + std::shared_ptr theConstraint) +{ + cleanErrorMsg(); + Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front()); + // 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); + } + + // 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) +{ + 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); + mySlvsConstraints.push_back(aNewID); + return aNewID; +} + +void SketchSolver_ConstraintCoincidence::addConstraint(ConstraintPtr theConstraint) +{ + std::list anAttrList = + theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId()); + std::list::iterator anIter = anAttrList.begin(); + std::vector anEntities; + for (; anIter != anAttrList.end(); anIter++) { + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*anIter); + if (!aRefAttr || aRefAttr->isObject() || + myAttributeMap.find(aRefAttr->attr()) != myAttributeMap.end()) + continue; + int aType; + Slvs_hEntity anEntityID = myGroup->getAttributeId(aRefAttr->attr()); + if (anEntityID == SLVS_E_UNKNOWN) + anEntityID = changeEntity(aRefAttr->attr(), aType); + anEntities.push_back(anEntityID); + } + + Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front()); + Slvs_hConstraint aNewConstr = SLVS_E_UNKNOWN; + std::vector::iterator anEntIter = anEntities.begin(); + for (; anEntIter != anEntities.end(); anEntIter++) + aNewConstr = addConstraint(aBaseCoincidence.ptA, *anEntIter); + myExtraCoincidence[theConstraint] = aNewConstr; +} + +bool SketchSolver_ConstraintCoincidence::remove(ConstraintPtr theConstraint) +{ + cleanErrorMsg(); + ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint; + int aPos = -1; // position of constraint in the list (-1 for base constraint) + if (aConstraint != myBaseConstraint) { + std::map::const_iterator anIt = myExtraCoincidence.begin(); + for (aPos = 0; anIt != myExtraCoincidence.end(); anIt++, aPos++) + if (anIt->first == aConstraint) + break; + if (aPos >= (int)myExtraCoincidence.size()) + return false; // there is no constraint, which is specified to remove + } + + bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints[aPos+1]); + mySlvsConstraints.erase(mySlvsConstraints.begin() + (1+aPos)); + cleanRemovedEntities(); + if (aPos < 0 && !myExtraCoincidence.empty()) { + // Need to specify another base coincidence constraint + myBaseConstraint = myExtraCoincidence.begin()->first; + myExtraCoincidence.erase(myExtraCoincidence.begin()); + 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); + } + } + return true; +} + diff --git a/src/SketchSolver/SketchSolver_ConstraintCoincidence.h b/src/SketchSolver/SketchSolver_ConstraintCoincidence.h new file mode 100644 index 000000000..97c1c1250 --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintCoincidence.h @@ -0,0 +1,55 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_ConstraintCoincidence.h +// Created: 29 Mar 2015 +// Author: Artem ZHIDKOV + +#ifndef SketchSolver_ConstraintCoincidence_H_ +#define SketchSolver_ConstraintCoincidence_H_ + +#include "SketchSolver.h" +#include +#include + +/** \class SketchSolver_ConstraintCoincidence + * \ingroup Plugins + * \brief Convert coincidence constraint to SolveSpace structure + */ +class SketchSolver_ConstraintCoincidence : public SketchSolver_Constraint +{ +public: + SketchSolver_ConstraintCoincidence(ConstraintPtr theConstraint) : + SketchSolver_Constraint(theConstraint) + {} + + virtual int getType() const + { return SLVS_C_POINTS_COINCIDENT; } + + /// \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); + +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); + +private: + std::map myExtraCoincidence; ///< multiple coincidence of points +}; + +#endif diff --git a/src/SketchSolver/SketchSolver_ConstraintGroup.cpp b/src/SketchSolver/SketchSolver_ConstraintGroup.cpp deleted file mode 100644 index fcdcf3617..000000000 --- a/src/SketchSolver/SketchSolver_ConstraintGroup.cpp +++ /dev/null @@ -1,2347 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: SketchSolver_ConstraintGroup.cpp -// Created: 27 May 2014 -// Author: Artem ZHIDKOV - -#include "SketchSolver_ConstraintGroup.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 - -/// Tolerance for value of parameters -const double tolerance = 1.e-10; - -/** - * Collects all sketch solver error' codes - * as inline static functions - */ - // TODO: Move this class into a separate file -class SketchSolver_Error -{ - public: - /// The value parameter for the constraint - inline static const std::string& CONSTRAINTS() - { - static const std::string MY_ERROR_VALUE("Conflicting constraints"); - return MY_ERROR_VALUE; - } - /// The entities need to have shared point, but they have not - inline static const std::string& NO_COINCIDENT_POINTS() - { - static const std::string MY_ERROR_VALUE("Objects should have coincident point"); - return MY_ERROR_VALUE; - } -}; - -/// This value is used to give unique index to the groups -static Slvs_hGroup myGroupIndexer = 0; - -/** \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); - -// ======================================================== -// ========= SketchSolver_ConstraintGroup =============== -// ======================================================== - -SketchSolver_ConstraintGroup::SketchSolver_ConstraintGroup( - std::shared_ptr theWorkplane) - : myID(++myGroupIndexer), - myParamMaxID(0), - myEntityMaxID(0), - myConstrMaxID(0), - myConstraintMap(), - myNeedToSolve(false), - myConstrSolver() -{ - myParams.clear(); - myEntities.clear(); - myEntOfConstr.clear(); - myConstraints.clear(); - - myTempConstraints.clear(); - myTempPointWhereDragged.clear(); - myTempPointWDrgdID = 0; - - // Initialize workplane - myWorkplane.h = SLVS_E_UNKNOWN; -#ifndef NDEBUG - assert(addWorkplane(theWorkplane)); -#else - addWorkplane(theWorkplane); -#endif -} - -SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup() -{ - myParams.clear(); - myEntities.clear(); - myEntOfConstr.clear(); - myConstraints.clear(); - myConstraintMap.clear(); - myTempConstraints.clear(); - myTempPointWhereDragged.clear(); - - // If the group with maximal identifier is deleted, decrease the indexer - if (myID == myGroupIndexer) - myGroupIndexer--; -} - -// ============================================================================ -// Function: isBaseWorkplane -// Class: SketchSolver_ConstraintGroup -// Purpose: verify the group is based on the given workplane -// ============================================================================ -bool SketchSolver_ConstraintGroup::isBaseWorkplane( - std::shared_ptr theWorkplane) const -{ - return theWorkplane == mySketch; -} - -// ============================================================================ -// Function: isInteract -// Class: SketchSolver_ConstraintGroup -// Purpose: verify are there any entities in the group used by given constraint -// ============================================================================ -bool SketchSolver_ConstraintGroup::isInteract( - std::shared_ptr theFeature) const -{ - // Check the group is empty - if (isEmpty()) - return true; - - // Check if the feature is already in the group - if (myEntityFeatMap.find(theFeature) != myEntityFeatMap.end()) - return true; - std::shared_ptr aConstr = - std::dynamic_pointer_cast(theFeature); - if (aConstr && myConstraintMap.find(aConstr) != myConstraintMap.end()) - return true; - - // Go through the attributes and verify if some of them already in the group - std::list> - anAttrList = theFeature->data()->attributes(std::string()); - std::list>::const_iterator - anAttrIter = anAttrList.begin(); - for ( ; anAttrIter != anAttrList.end(); anAttrIter++) { - AttributeRefListPtr aCAttrRefList = - std::dynamic_pointer_cast(*anAttrIter); - if (aCAttrRefList) { - std::list anObjList = aCAttrRefList->list(); - std::list::iterator anIt = anObjList.begin(); - for ( ; anIt != anObjList.end(); anIt++) { - FeaturePtr aFeature = std::dynamic_pointer_cast(*anIt); - if (aFeature && myEntityFeatMap.find(aFeature) != myEntityFeatMap.end()) - return true; - } - continue; - } - AttributeRefAttrPtr aCAttrRef = - std::dynamic_pointer_cast(*anAttrIter); - if (!aCAttrRef || !aCAttrRef->isObject()) { - std::shared_ptr anAttr = - aCAttrRef ? aCAttrRef->attr() : *anAttrIter; - if (myEntityAttrMap.find(anAttr) != myEntityAttrMap.end()) - return true; - } else { - ResultConstructionPtr aRC = std::dynamic_pointer_cast( - aCAttrRef->object()); - if (!aRC) - continue; - std::shared_ptr aDoc = aRC->document(); - FeaturePtr aFeature = aDoc->feature(aRC); - if (myEntityFeatMap.find(aFeature) != myEntityFeatMap.end()) - return true; - // search attributes of a feature to be parameters of constraint - std::list > aFeatAttrList = - aFeature->data()->attributes(std::string()); - std::list >::const_iterator aFAIter = aFeatAttrList - .begin(); - for (; aFAIter != aFeatAttrList.end(); aFAIter++) - if (myEntityAttrMap.find(*aFAIter) != myEntityAttrMap.end()) - return true; - } - } - - // Entities did not found - return false; -} - -// ============================================================================ -// Function: checkConstraintConsistence -// Class: SketchSolver_ConstraintGroup -// Purpose: verifies and changes parameters of the constraint -// ============================================================================ -void SketchSolver_ConstraintGroup::checkConstraintConsistence(Slvs_Constraint& theConstraint) -{ - if (theConstraint.type == SLVS_C_PT_LINE_DISTANCE) { - // Get constraint parameters and check the sign of constraint value - - // point coordinates - int aPtPos = Search(theConstraint.ptA, myEntities); - int aPtParamPos = Search(myEntities[aPtPos].param[0], myParams); - std::shared_ptr aPoint( - new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val)); - - // line coordinates - int aLnPos = Search(theConstraint.entityA, myEntities); - aPtPos = Search(myEntities[aLnPos].point[0], myEntities); - aPtParamPos = Search(myEntities[aPtPos].param[0], myParams); - std::shared_ptr aStart( - new GeomAPI_XY(-myParams[aPtParamPos].val, -myParams[aPtParamPos + 1].val)); - aPtPos = Search(myEntities[aLnPos].point[1], myEntities); - aPtParamPos = Search(myEntities[aPtPos].param[0], myParams); - std::shared_ptr aEnd( - new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val)); - - aEnd = aEnd->added(aStart); - aPoint = aPoint->added(aStart); - if (aPoint->cross(aEnd) * theConstraint.valA < 0.0) - theConstraint.valA *= -1.0; - } -} - -// ============================================================================ -// Function: changeConstraint -// Class: SketchSolver_ConstraintGroup -// Purpose: create/update the constraint in the group -// ============================================================================ -bool SketchSolver_ConstraintGroup::changeConstraint( - std::shared_ptr theConstraint) -{ - // There is no workplane yet, something wrong - if (myWorkplane.h == SLVS_E_UNKNOWN) - return false; - - if (theConstraint) { - if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID()) - return changeRigidConstraint(theConstraint); - if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) - return changeMirrorConstraint(theConstraint); - if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) - return changeFilletConstraint(theConstraint); - } - - // Search this constraint in the current group to update it - ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint); - std::vector::iterator aConstrIter; - if (aConstrMapIter != myConstraintMap.end()) { - int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints); - aConstrIter = myConstraints.begin() + aConstrPos; - } - - // Get constraint type and verify the constraint parameters are correct - SketchSolver_Constraint aConstraint(theConstraint); - int aConstrType = aConstraint.getType(); - if (aConstrType == SLVS_C_UNKNOWN - || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType)) - return false; - const std::vector& aConstraintAttributes = aConstraint.getAttributes(); - - // Create constraint parameters - double aDistance = 0.0; // scalar value of the constraint - AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast( - theConstraint->data()->attribute(SketchPlugin_Constraint::VALUE())); - if (aDistAttr) { - aDistance = aDistAttr->value(); - // Issue #196: checking the positivity of the distance constraint - if (aDistance < tolerance && - (aConstrType == SLVS_C_PT_PT_DISTANCE || aConstrType == SLVS_C_PT_LINE_DISTANCE)) - return false; - // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter - if (aConstrType == SLVS_C_DIAMETER) - aDistance *= 2.0; - if (aConstrMapIter != myConstraintMap.end() - && fabs(aConstrIter->valA - aDistance) > tolerance) { - myNeedToSolve = true; - aConstrIter->valA = aDistance; - } - } - - size_t aNbTmpConstraints = myTempConstraints.size(); - Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint - for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) { - aConstrEnt[indAttr] = SLVS_E_UNKNOWN; - std::shared_ptr aConstrAttr = std::dynamic_pointer_cast< - ModelAPI_AttributeRefAttr>( - theConstraint->data()->attribute(aConstraintAttributes[indAttr])); - if (!aConstrAttr) - continue; - - // Convert the object of the attribute to the feature - FeaturePtr aFeature; - if (aConstrAttr->isObject() && aConstrAttr->object()) { - ResultConstructionPtr aRC = std::dynamic_pointer_cast( - aConstrAttr->object()); - if (!aRC) - continue; - std::shared_ptr aDoc = aRC->document(); - aFeature = aDoc->feature(aRC); - } - - // For the length constraint the start and end points of the line should be added to the entities list instead of line - if (aConstrType == SLVS_C_PT_PT_DISTANCE - && theConstraint->getKind().compare(SketchPlugin_ConstraintLength::ID()) == 0) { - Slvs_hEntity aLineEnt = changeEntityFeature(aFeature); - int aEntPos = Search(aLineEnt, myEntities); - aConstrEnt[indAttr++] = myEntities[aEntPos].point[0]; - aConstrEnt[indAttr++] = myEntities[aEntPos].point[1]; - while (indAttr < CONSTRAINT_ATTR_SIZE) - aConstrEnt[indAttr++] = 0; - break; // there should be no other entities - } else if (aConstrAttr->isObject()) - aConstrEnt[indAttr] = changeEntityFeature(aFeature); - else - aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr()); - } - - if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint - // Several points may be coincident, it is not necessary to store all constraints between them. - // Try to find sequence of coincident points which connects the points of new constraint - if (aConstrType == SLVS_C_POINTS_COINCIDENT) { - if (aConstrEnt[0] == aConstrEnt[1]) // no need to add self coincidence - return false; - if (!addCoincidentPoints(aConstrEnt[0], aConstrEnt[1])) { - myExtraCoincidence.insert(theConstraint); // the constraint is stored for further purposes - return false; - } - if (aNbTmpConstraints < myTempConstraints.size()) { - // There was added temporary constraint. Check that there is no coincident points which already rigid. - - // Get list of already fixed points - std::set anAlreadyFixed; - std::vector::const_iterator aCIter = myConstraints.begin(); - for (; aCIter != myConstraints.end(); aCIter++) - if (aCIter->type == SLVS_C_WHERE_DRAGGED) { - std::list::const_iterator aTmpIt = myTempConstraints.begin(); - for (; aTmpIt != myTempConstraints.end(); aTmpIt++) - if (*aTmpIt == aCIter->h) - break; - if (aTmpIt == myTempConstraints.end()) - anAlreadyFixed.insert(aCIter->ptA); - } - - std::set aTmpConstrToDelete; - std::list::reverse_iterator aTmpIter = myTempConstraints.rbegin(); - size_t aCurSize = myTempConstraints.size(); - for (; aCurSize > aNbTmpConstraints && aTmpIter != myTempConstraints.rend(); - aTmpIter++, aCurSize--) { - int aConstrPos = Search(*aTmpIter, myConstraints); - std::vector >::const_iterator - aCoincIter = myCoincidentPoints.begin(); - for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++) - if (aCoincIter->find(myConstraints[aConstrPos].ptA) != aCoincIter->end()) { - std::set::const_iterator anIt; - for (anIt = aCoincIter->begin(); anIt != aCoincIter->end(); anIt++) - if (anAlreadyFixed.find(*anIt) != anAlreadyFixed.end()) { - aTmpConstrToDelete.insert(*aTmpIter); - break; - } - break; - } - } - if (!aTmpConstrToDelete.empty()) - removeTemporaryConstraints(aTmpConstrToDelete); - } - } - // For the tangency constraints it is necessary to identify which points of entities are coincident - int aSlvsOtherFlag = 0; - int aSlvsOther2Flag = 0; - if (aConstrType == SLVS_C_ARC_LINE_TANGENT || aConstrType == SLVS_C_CURVE_CURVE_TANGENT) { - // Search entities used by constraint - int anEnt1Pos = Search(aConstrEnt[2], myEntities); - int anEnt2Pos = Search(aConstrEnt[3], myEntities); - // Obtain start and end points of entities - Slvs_hEntity aPointsToFind[4]; - aPointsToFind[0] = myEntities[anEnt1Pos].point[1]; - aPointsToFind[1]= myEntities[anEnt1Pos].point[2]; - bool hasLine = (myEntities[anEnt2Pos].type == SLVS_E_LINE_SEGMENT); - aPointsToFind[2]= myEntities[anEnt2Pos].point[hasLine ? 0 : 1]; - aPointsToFind[3]= myEntities[anEnt2Pos].point[hasLine ? 1 : 2]; - // Search coincident points - bool isPointFound[4]; - std::vector >::const_iterator aCPIter = myCoincidentPoints.begin(); - for ( ; aCPIter != myCoincidentPoints.end(); aCPIter++) { - for (int i = 0; i < 4; i++) - isPointFound[i] = (aCPIter->find(aPointsToFind[i]) != aCPIter->end()); - if ((isPointFound[0] || isPointFound[1]) && (isPointFound[2] || isPointFound[3])) { - // the arc is tangent by end point - if (isPointFound[1]) aSlvsOtherFlag = 1; - // the second item is an arc and it is tangent by end point too - if (!hasLine && isPointFound[3]) aSlvsOther2Flag = 1; - break; - } - } - if (aCPIter == myCoincidentPoints.end()) { - // There is no coincident points between tangential objects. Generate error message - Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this); - return false; - } - } - - // Create SolveSpace constraint structure - Slvs_Constraint aSlvsConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, - myWorkplane.h, aDistance, aConstrEnt[0], - aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]); - if (aSlvsOtherFlag != 0) aSlvsConstr.other = aSlvsOtherFlag; - if (aSlvsOther2Flag != 0) aSlvsConstr.other2 = aSlvsOther2Flag; - myConstraints.push_back(aSlvsConstr); - myConstraintMap[theConstraint] = std::vector(1, aSlvsConstr.h); - int aConstrPos = Search(aSlvsConstr.h, myConstraints); - aConstrIter = myConstraints.begin() + aConstrPos; - myNeedToSolve = true; - } else { // Attributes of constraint may be changed => update constraint - Slvs_hEntity* aCurrentAttr[] = {&aConstrIter->ptA, &aConstrIter->ptB, - &aConstrIter->entityA, &aConstrIter->entityB, - &aConstrIter->entityC, &aConstrIter->entityD}; - for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) { - if (*(aCurrentAttr[indAttr]) != aConstrEnt[indAttr]) - { - *(aCurrentAttr[indAttr]) = aConstrEnt[indAttr]; - myNeedToSolve = true; - } - } - } - - // Update flags of entities to be used by constraints - for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) - if (aConstrEnt[indAttr] != 0) { - int aPos = Search(aConstrEnt[indAttr], myEntities); - myEntOfConstr[aPos] = true; - // Sub-entities should be used implcitly - Slvs_hEntity* aEntPtr = myEntities[aPos].point; - while (*aEntPtr != 0) { - aPos = Search(*aEntPtr, myEntities); - myEntOfConstr[aPos] = true; - aEntPtr++; - } - } - - checkConstraintConsistence(*aConstrIter); - return true; -} - -// ============================================================================ -// Function: changeRigidConstraint -// Class: SketchSolver_ConstraintGroup -// Purpose: create/update the "Rigid" constraint in the group -// ============================================================================ -bool SketchSolver_ConstraintGroup::changeRigidConstraint( - std::shared_ptr theConstraint) -{ - // Search this constraint in the current group to update it - ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint); - std::vector::iterator aConstrIter; - if (aConstrMapIter != myConstraintMap.end()) { - int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints); - aConstrIter = myConstraints.begin() + aConstrPos; - } - - // Get constraint type and verify the constraint parameters are correct - SketchSolver_Constraint aConstraint(theConstraint); - int aConstrType = aConstraint.getType(); - if (aConstrType == SLVS_C_UNKNOWN - || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType)) - return false; - const std::vector& aConstraintAttributes = aConstraint.getAttributes(); - - Slvs_hEntity aConstrEnt = SLVS_E_UNKNOWN; - std::shared_ptr aConstrAttr = std::dynamic_pointer_cast< - ModelAPI_AttributeRefAttr>( - theConstraint->data()->attribute(aConstraintAttributes[0])); - if (!aConstrAttr) - return false; - - // Convert the object of the attribute to the feature - FeaturePtr aFeature; - if (aConstrAttr->isObject() && aConstrAttr->object()) { - ResultConstructionPtr aRC = std::dynamic_pointer_cast( - aConstrAttr->object()); - if (!aRC) - return false; - std::shared_ptr aDoc = aRC->document(); - aFeature = aDoc->feature(aRC); - } - - aConstrEnt = aConstrAttr->isObject() ? changeEntityFeature(aFeature) : changeEntity(aConstrAttr->attr()); - - if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint - // Check the fixed entity is not a point. - std::shared_ptr aConstrAttr = std::dynamic_pointer_cast< - ModelAPI_AttributeRefAttr>(theConstraint->data()->attribute(aConstraintAttributes[0])); - std::shared_ptr aPoint = - std::dynamic_pointer_cast(aConstrAttr->attr()); - std::shared_ptr aPoint2D = - std::dynamic_pointer_cast(aConstrAttr->attr()); - if (aPoint || aPoint2D || aFeature->getKind() == SketchPlugin_Point::ID()) { - // Create SolveSpace constraint structure - Slvs_Constraint aConstraint = Slvs_MakeConstraint( - ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0, - aConstrEnt, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - myConstraints.push_back(aConstraint); - myConstraintMap[theConstraint] = std::vector(1, aConstraint.h); - int aConstrPos = Search(aConstraint.h, myConstraints); - aConstrIter = myConstraints.begin() + aConstrPos; - myNeedToSolve = true; - } else { - myConstraintMap[theConstraint] = std::vector(); - - // To avoid SolveSpace problems: - // * if the circle is rigid, we will fix its center and radius; - // * if the arc is rigid, we will fix its start and end points and radius. - double aRadius = 0.0; - bool isArc = false; - bool isCircle = false; - if (aFeature) { - if (aFeature->getKind() == SketchPlugin_Arc::ID()) { - std::shared_ptr aCenter = - std::dynamic_pointer_cast( - aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID())); - std::shared_ptr aStart = - std::dynamic_pointer_cast( - aFeature->data()->attribute(SketchPlugin_Arc::START_ID())); - aRadius = aStart->pnt()->distance(aCenter->pnt()); - isArc = true; - } else if (aFeature->getKind() == SketchPlugin_Circle::ID()) { - aRadius = std::dynamic_pointer_cast( - aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()))->value(); - isCircle = true; - } - } - - // Get list of already fixed points - std::set anAlreadyFixed; - std::vector::const_iterator aCIter = myConstraints.begin(); - for (; aCIter != myConstraints.end(); aCIter++) - if (aCIter->type == SLVS_C_WHERE_DRAGGED) - anAlreadyFixed.insert(aCIter->ptA); - - // Create constraints to fix the parameters of the entity - int aEntPos = Search(aConstrEnt, myEntities); - Slvs_hEntity* aPointsPtr = myEntities[aEntPos].point; - if (isArc) aPointsPtr++; // avoid to fix center of arc - while (*aPointsPtr != 0) { - // Avoid to create additional "Rigid" constraints for coincident points - bool isCoincAlreadyFixed = false; - if (!anAlreadyFixed.empty()) { - if (anAlreadyFixed.find(*aPointsPtr) != anAlreadyFixed.end()) - isCoincAlreadyFixed = true; - - std::vector >::const_iterator aCoincIter = - myCoincidentPoints.begin(); - for (; !isCoincAlreadyFixed && aCoincIter != myCoincidentPoints.end(); aCoincIter++) { - if (aCoincIter->find(*aPointsPtr) == aCoincIter->end()) - continue; - std::set::const_iterator anIter = anAlreadyFixed.begin(); - for (; !isCoincAlreadyFixed && anIter != anAlreadyFixed.end(); anIter++) - if (aCoincIter->find(*anIter) != aCoincIter->end()) - isCoincAlreadyFixed = true; - } - } - - if (!isCoincAlreadyFixed) { - Slvs_Constraint aConstraint = Slvs_MakeConstraint( - ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0, - *aPointsPtr, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - myConstraints.push_back(aConstraint); - myConstraintMap[theConstraint].push_back(aConstraint.h); - } - aPointsPtr++; - } - - if (isArc || isCircle) { // add radius constraint - Slvs_Constraint aConstraint = Slvs_MakeConstraint( - ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, 2.0 * aRadius, - SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aConstrEnt, SLVS_E_UNKNOWN); - myConstraints.push_back(aConstraint); - myConstraintMap[theConstraint].push_back(aConstraint.h); - } - - // The object is already rigid, so there is no constraints added - if (myConstraintMap[theConstraint].empty()) { - myConstraintMap.erase(theConstraint); - myNeedToSolve = false; - } - else - myNeedToSolve = true; - } - } - return true; -} - -// ============================================================================ -// Function: changeMirrorConstraint -// Class: SketchSolver_ConstraintGroup -// Purpose: create/update the "Mirror" constraint in the group -// ============================================================================ -bool SketchSolver_ConstraintGroup::changeMirrorConstraint( - std::shared_ptr theConstraint) -{ - DataPtr aConstrData = theConstraint->data(); - - // Search this constraint in the current group to update it - ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint); - std::vector::iterator aConstrIter; - bool isExists = false; - if (aConstrMapIter != myConstraintMap.end()) { - int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints); - aConstrIter = myConstraints.begin() + aConstrPos; - isExists = true; - } - - // Get constraint type and verify the constraint parameters are correct - SketchSolver_Constraint aConstraint(theConstraint); - int aConstrType = aConstraint.getType(); - if (aConstrType == SLVS_C_UNKNOWN - || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType)) - return false; - const std::vector& aConstraintAttributes = aConstraint.getAttributes(); - - Slvs_hEntity aMirrorLineEnt = SLVS_E_UNKNOWN; - AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast( - aConstrData->attribute(aConstraintAttributes[0])); - if (!aConstrAttr) - return false; - - // Convert the object of the attribute to the feature - FeaturePtr aMirrorLineFeat; - if (aConstrAttr->isObject() && aConstrAttr->object()) { - ResultConstructionPtr aRC = std::dynamic_pointer_cast( - aConstrAttr->object()); - if (!aRC) - return false; - std::shared_ptr aDoc = aRC->document(); - aMirrorLineFeat = aDoc->feature(aRC); - } - aMirrorLineEnt = aConstrAttr->isObject() ? - changeEntityFeature(aMirrorLineFeat) : changeEntity(aConstrAttr->attr()); - - // Append symmetric constraint for each point of mirroring features - AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast( - aConstrData->attribute(aConstraintAttributes[1])); - AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast( - aConstrData->attribute(aConstraintAttributes[2])); - if (!aBaseRefList || !aMirroredRefList) - return false; - - std::list aBaseList = aBaseRefList->list(); - std::list aMirroredList = aMirroredRefList->list(); - // remove all empty items - std::list::iterator anIt = aBaseList.begin(); - std::list::iterator aTmpIt; - while (anIt != aBaseList.end()) { - aTmpIt = anIt; - anIt++; - if (!(*aTmpIt)) - aBaseList.erase(aTmpIt); - } - anIt = aMirroredList.begin(); - while (anIt != aMirroredList.end()) { - aTmpIt = anIt; - anIt++; - if (!(*aTmpIt)) - aMirroredList.erase(aTmpIt); - } - if (aBaseList.empty() || aBaseList.size() != aMirroredList.size()) - return false; - - std::vector aNewConstraints; - // Fill the list of already mirrored points - std::vector anOldConstraints; - std::map aMirroredPoints; - if (isExists) { - std::vector::const_iterator aCIter = aConstrMapIter->second.begin(); - for (; aCIter != aConstrMapIter->second.end(); aCIter++) { - int anInd = Search(*aCIter, myConstraints); - if (myConstraints[anInd].type != aConstrType) - continue; - aMirroredPoints[myConstraints[anInd].ptA] = myConstraints[anInd].ptB; - anOldConstraints.push_back(myConstraints[anInd]); - } - } - - FeaturePtr aBaseFeature, aMirrorFeature; - ResultConstructionPtr aRC; - std::list::iterator aBaseIter = aBaseList.begin(); - std::list::iterator aMirIter = aMirroredList.begin(); - for ( ; aBaseIter != aBaseList.end(); aBaseIter++, aMirIter++) { - aRC = std::dynamic_pointer_cast(*aBaseIter); - aBaseFeature = aRC ? aRC->document()->feature(aRC) : - std::dynamic_pointer_cast(*aBaseIter); - aRC = std::dynamic_pointer_cast(*aMirIter); - aMirrorFeature = aRC ? aRC->document()->feature(aRC) : - std::dynamic_pointer_cast(*aMirIter); - - if (!aBaseFeature || !aMirrorFeature || - aBaseFeature->getKind() != aMirrorFeature->getKind()) - return false; - Slvs_hEntity aBaseEnt = changeEntityFeature(aBaseFeature); - Slvs_hEntity aMirrorEnt = changeEntityFeature(aMirrorFeature); - // Make aMirrorEnt parameters to be symmetric with aBaseEnt - makeMirrorEntity(aBaseEnt, aMirrorEnt, aMirrorLineEnt); - - if (aBaseFeature->getKind() == SketchPlugin_Point::ID()) { - Slvs_hConstraint anID = changeMirrorPoints(aBaseEnt, aMirrorEnt, - aMirrorLineEnt, anOldConstraints, aMirroredPoints); - aNewConstraints.push_back(anID); - } else { - int aBasePos = Search(aBaseEnt, myEntities); - int aMirrorPos = Search(aMirrorEnt, myEntities); - if (aBaseFeature->getKind() == SketchPlugin_Line::ID()) { - for (int ind = 0; ind < 2; ind++) { - Slvs_hConstraint anID = changeMirrorPoints(myEntities[aBasePos].point[ind], - myEntities[aMirrorPos].point[ind], aMirrorLineEnt, anOldConstraints, aMirroredPoints); - aNewConstraints.push_back(anID); - } - } else if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) { - Slvs_hConstraint anID = changeMirrorPoints(myEntities[aBasePos].point[0], - myEntities[aMirrorPos].point[0], aMirrorLineEnt, anOldConstraints, aMirroredPoints); - aNewConstraints.push_back(anID); - // Additional constraint for equal radii - Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint( - ++myConstrMaxID, myID, SLVS_C_EQUAL_RADIUS, myWorkplane.h, 0.0, - SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseEnt, aMirrorEnt); - myConstraints.push_back(anEqRadConstr); - myConstraintMap[theConstraint].push_back(anEqRadConstr.h); - } else if (aBaseFeature->getKind() == SketchPlugin_Arc::ID()) { - // 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] = { - myEntities[aBasePos].point[1], - myEntities[aBasePos].point[2], - SLVS_E_UNKNOWN}; - Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point - myEntities[aMirrorPos].point[2], - myEntities[aMirrorPos].point[1], - SLVS_E_UNKNOWN}; - Slvs_hEntity aBothArcs[2] = {aBaseEnt, aMirrorEnt}; - Slvs_hEntity aBothMiddlePoints[2]; - for (int i = 0; i < 2; i++) { - double x, y; - calculateMiddlePoint(aBothArcs[i], x, y); - std::vector::iterator aParamIter = myParams.end(); - Slvs_hParam u = changeParameter(x, aParamIter); - Slvs_hParam v = changeParameter(y, aParamIter); - Slvs_Entity aPoint = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, u, v); - myEntities.push_back(aPoint); - myEntOfConstr.push_back(true); - aBothMiddlePoints[i] = aPoint.h; - // additional constraint point-on-curve - Slvs_Constraint aPonCircConstr = Slvs_MakeConstraint( - ++myConstrMaxID, myID, SLVS_C_PT_ON_CIRCLE, myWorkplane.h, 0.0, - aPoint.h, SLVS_E_UNKNOWN, aBothArcs[i], SLVS_E_UNKNOWN); - myConstraints.push_back(aPonCircConstr); - myConstraintMap[theConstraint].push_back(aPonCircConstr.h); - aNewConstraints.push_back(aPonCircConstr.h); - } - - aBaseArcPoints[2] = aBothMiddlePoints[0]; - aMirrorArcPoints[2] = aBothMiddlePoints[1]; - for (int ind = 0; ind < 3; ind++) { - Slvs_hConstraint anID = changeMirrorPoints(aBaseArcPoints[ind], aMirrorArcPoints[ind], - aMirrorLineEnt, anOldConstraints, aMirroredPoints); - aNewConstraints.push_back(anID); - } - } - } - } - - // Remove unused constraints - std::vector::const_iterator anOldCIter = anOldConstraints.begin(); - for (; anOldCIter != anOldConstraints.end(); anOldCIter++) { - int anInd = Search(anOldCIter->h, myConstraints); - myConstraints.erase(myConstraints.begin() + anInd); - } - myConstraintMap[theConstraint] = aNewConstraints; - - if (!isExists) { - // Set the mirror line unchanged during constraint recalculation - int aMirrorLinePos = Search(aMirrorLineEnt, myEntities); - // firstly check the line is not fixed yet - bool isFixed[2] = {false, false}; - std::vector::const_iterator aConstrIter = myConstraints.begin(); - for (; aConstrIter != myConstraints.end() && !(isFixed[0] && isFixed[1]); aConstrIter++) - if (aConstrIter->type == SLVS_C_WHERE_DRAGGED) { - if (aConstrIter->ptA == myEntities[aMirrorLinePos].point[0]) - isFixed[0] = true; - else if (aConstrIter->ptA == myEntities[aMirrorLinePos].point[1]) - isFixed[1] = true; - } - // add new rigid constraints - if (!isFixed[0]) { - Slvs_Constraint aRigidStart = Slvs_MakeConstraint( - ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0, - myEntities[aMirrorLinePos].point[0], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - myConstraints.push_back(aRigidStart); - myConstraintMap[theConstraint].push_back(aRigidStart.h); - } - if (!isFixed[1]) { - Slvs_Constraint aRigidEnd = Slvs_MakeConstraint( - ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0, - myEntities[aMirrorLinePos].point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - myConstraints.push_back(aRigidEnd); - myConstraintMap[theConstraint].push_back(aRigidEnd.h); - } - - // Add temporary constraints for initial objects to be unchanged - for (aBaseIter = aBaseList.begin(); aBaseIter != aBaseList.end(); aBaseIter++) { - aRC = std::dynamic_pointer_cast(*aBaseIter); - aBaseFeature = aRC ? aRC->document()->feature(aRC) : - std::dynamic_pointer_cast(*aBaseIter); - if (!aBaseFeature) continue; - std::list aPoints = aBaseFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); - if (aBaseFeature->getKind() != SketchPlugin_Arc::ID()) { - std::list::iterator anIt = aPoints.begin(); - for ( ; anIt != aPoints.end(); anIt++) { - addTemporaryConstraintWhereDragged(*anIt); - } - } else { - // Arcs are fixed by center and start points only (to avoid solving errors in SolveSpace) - AttributePtr aCenterAttr = aBaseFeature->attribute(SketchPlugin_Arc::CENTER_ID()); - std::map::iterator aFound = myEntityAttrMap.find(aCenterAttr); - Slvs_hEntity anArcPoints[3] = {aFound->second, 0, 0}; - AttributePtr aStartAttr = aBaseFeature->attribute(SketchPlugin_Arc::START_ID()); - aFound = myEntityAttrMap.find(aStartAttr); - anArcPoints[1] = aFound->second; - AttributePtr aEndAttr = aBaseFeature->attribute(SketchPlugin_Arc::END_ID()); - aFound = myEntityAttrMap.find(aEndAttr); - anArcPoints[2] = aFound->second; - - bool isFixed[3] = {false, false, false}; - int aNbFixed = 0; // number of already fixed points on the arc - for (int i = 0; i < 3; i++) { - std::vector >::iterator aCoPtIter = myCoincidentPoints.begin(); - for (; aCoPtIter != myCoincidentPoints.end() && !isFixed[i]; aCoPtIter++) { - if (aCoPtIter->find(anArcPoints[i]) == aCoPtIter->end()) - continue; // the entity was not found in current set - - // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points - std::vector::iterator aConstrIter = myConstraints.begin(); - for (; aConstrIter != myConstraints.end(); aConstrIter++) - if (aConstrIter->type == SLVS_C_WHERE_DRAGGED && - aCoPtIter->find(aConstrIter->ptA) != aCoPtIter->end()) { - isFixed[i] = true; - aNbFixed++; - break; // the SLVS_C_WHERE_DRAGGED constraint already exists - } - } - } - if (aNbFixed < 2) { // append constraints - if (!isFixed[0]) - addTemporaryConstraintWhereDragged(aCenterAttr); - if (!isFixed[1] && (isFixed[0] || aNbFixed == 0)) - addTemporaryConstraintWhereDragged(aStartAttr); - } - } - } - } - return true; -} - -// ============================================================================ -// Function: changeFilletConstraint -// Class: SketchSolver_ConstraintGroup -// Purpose: create/update the "Fillet" constraint in the group -// ============================================================================ -bool SketchSolver_ConstraintGroup::changeFilletConstraint( - std::shared_ptr theConstraint) -{ - DataPtr aConstrData = theConstraint->data(); - - // Search this constraint in the current group to update it - ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint); - std::vector::iterator aConstrIter; - if (aConstrMapIter != myConstraintMap.end()) { - int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints); - aConstrIter = myConstraints.begin() + aConstrPos; - } - - // Get constraint type and verify the constraint parameters are correct - SketchSolver_Constraint aConstraint(theConstraint); - int aConstrType = aConstraint.getType(); - if (aConstrType == SLVS_C_UNKNOWN) - return false; - const std::vector& aConstraintAttributes = aConstraint.getAttributes(); - - // Obtain hEntity for basic objects of fillet - Slvs_hEntity aBaseObject[2]; - FeaturePtr aBaseFeature[2]; - for (unsigned int indAttr = 0; indAttr < 2; indAttr++) { - AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast( - aConstrData->attribute(aConstraintAttributes[indAttr])); - if (!aConstrAttr) - return false; - if (aConstrAttr->isObject() && aConstrAttr->object()) { - ResultConstructionPtr aRC = std::dynamic_pointer_cast( - aConstrAttr->object()); - if (!aRC) - return false; - std::shared_ptr aDoc = aRC->document(); - aBaseFeature[indAttr] = aDoc->feature(aRC); - } - aBaseObject[indAttr] = aConstrAttr->isObject() ? - changeEntityFeature(aBaseFeature[indAttr]) : changeEntity(aConstrAttr->attr()); - } - // Check the base entities have a coincident point - int aBaseObjInd[2] = { - Search(aBaseObject[0], myEntities), - Search(aBaseObject[1], myEntities) - }; - int aShift[2] = { // shift for calculating correct start and end points for different types of objects - myEntities[aBaseObjInd[0]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0, - myEntities[aBaseObjInd[1]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0, - }; - Slvs_hEntity aFirstObjPoints[2] = { // indices of start and end point of first object - myEntities[aBaseObjInd[0]].point[aShift[0]], - myEntities[aBaseObjInd[0]].point[1+aShift[0]] - }; - Slvs_hEntity aSecondObjPoints[2] = { // indices of start and end point of second object - myEntities[aBaseObjInd[1]].point[aShift[1]], - myEntities[aBaseObjInd[1]].point[1+aShift[1]] - }; - bool isCoincidentFound = false; - int aBaseCoincInd[2] = {0, 0}; // indices in aFirstObjPoint and aSecondObjPoint identifying coincident points - std::vector >::iterator aCPIter = myCoincidentPoints.begin(); - for ( ; aCPIter != myCoincidentPoints.end() && !isCoincidentFound; aCPIter++) - for (int ind1 = 0; ind1 < 2 && !isCoincidentFound; ind1++) - for (int ind2 = 0; ind2 < 2 && !isCoincidentFound; ind2++) - if (aCPIter->find(aFirstObjPoints[ind1]) != aCPIter->end() && - aCPIter->find(aSecondObjPoints[ind2]) != aCPIter->end()) { - aBaseCoincInd[0] = ind1; - aBaseCoincInd[1] = ind2; - isCoincidentFound = true; - } - if (!isCoincidentFound) { - // There is no coincident points between objects. Generate error message - Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this); - return false; - } - - // Create fillet entities - // - first object is placed on the first base - // - second object is on the second base - // - third object is a filleting arc - static const int aNbFilletEnt = 3; - Slvs_hEntity aFilletEnt[aNbFilletEnt]; - int aFilletObjInd[aNbFilletEnt]; - AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast( - aConstrData->attribute(aConstraintAttributes[2])); - if (!aFilletRefList) - return false; - std::list aFilletList = aFilletRefList->list(); - if (aFilletList.size() < aNbFilletEnt) - return false; - FeaturePtr aFilletFeature; - ResultConstructionPtr aRC; - 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) - return false; - aFilletEnt[indEnt] = changeEntityFeature(aFilletFeature); - if (aFilletEnt[indEnt] == SLVS_E_UNKNOWN) - return false; // not all attributes are initialized yet - aFilletObjInd[indEnt] = Search(aFilletEnt[indEnt], myEntities); - } - // At first time, for correct result, move floating points of fillet on the middle points of base objects - if (myConstraintMap.find(theConstraint) == myConstraintMap.end()) { - double anArcPoints[6]; - for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) { - int anIndShift = myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0; - int aPointsPos[2] = { - Search(myEntities[aFilletObjInd[indEnt]].point[anIndShift], myEntities), - Search(myEntities[aFilletObjInd[indEnt]].point[1+anIndShift], myEntities) - }; - int aParamPos[2] = { - Search(myEntities[aPointsPos[0]].param[0], myParams), - Search(myEntities[aPointsPos[1]].param[0], myParams) - }; - int anIndex = aParamPos[aBaseCoincInd[indEnt]]; - if (anIndShift == 0) { - myParams[anIndex].val = - 0.5 * (myParams[aParamPos[0]].val + myParams[aParamPos[1]].val); - myParams[1 + anIndex].val = - 0.5 * (myParams[1 + aParamPos[0]].val + myParams[1 + aParamPos[1]].val); - } else { // place the changed point on the arc - double x = 0, y = 0; - calculateMiddlePoint(aFilletEnt[indEnt], x, y); - myParams[anIndex].val = x; - myParams[1 + anIndex].val = y; - } - anArcPoints[indEnt*2+2] = myParams[anIndex].val; - anArcPoints[indEnt*2+3] = myParams[1 + anIndex].val; - } - anArcPoints[0] = 0.5 * (anArcPoints[2] + anArcPoints[4]); - anArcPoints[1] = 0.5 * (anArcPoints[3] + anArcPoints[5]); - for (int indArcPt = 0; indArcPt < 3; indArcPt++) { - int aPtPos = Search(myEntities[aFilletObjInd[2]].point[indArcPt], myEntities); - int aParamPos = Search(myEntities[aPtPos].param[0], myParams); - myParams[aParamPos].val = anArcPoints[indArcPt * 2]; - myParams[aParamPos + 1].val = anArcPoints[indArcPt * 2 + 1]; - } - } - - // Create list of constraints to generate fillet - int aPtInd; - std::vector aConstrList; - bool isExists = myConstraintMap.find(theConstraint) != myConstraintMap.end(); // constraint already exists - std::vector::iterator aCMapIter = - isExists ? myConstraintMap[theConstraint].begin() : aConstrList.begin(); - std::vector::iterator aCMapEnd = - isExists ? myConstraintMap[theConstraint].end() : aConstrList.end(); - int aCurConstrPos = isExists ? Search(*aCMapIter, myConstraints) : 0; - for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) { - // one point of fillet object should be coincident with the point on base, non-coincident with another base object - aPtInd = 1-aBaseCoincInd[indEnt]+aShift[indEnt]; // (1-aBaseCoincInd[indEnt]) = index of non-coincident point, aShift is used to process all types of shapes - Slvs_hEntity aPtBase = myEntities[aBaseObjInd[indEnt]].point[aPtInd]; - Slvs_hEntity aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd]; - if (isExists) { - myConstraints[aCurConstrPos].ptA = aPtBase; - myConstraints[aCurConstrPos].ptB = aPtFillet; - aCMapIter++; - aCurConstrPos = Search(*aCMapIter, myConstraints); - } else if (addCoincidentPoints(aPtBase, aPtFillet)) { // the points are not connected by coincidence yet - Slvs_Constraint aCoincConstr = Slvs_MakeConstraint( - ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h, - 0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - myConstraints.push_back(aCoincConstr); - aConstrList.push_back(aCoincConstr.h); - } - - // another point of fillet object should be placed on the base object - Slvs_Constraint aPonCurveConstr; - int aTangentType; - if (myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE) { - // centers of arcs should be coincident - aPtBase = myEntities[aBaseObjInd[indEnt]].point[0]; - aPtFillet = myEntities[aFilletObjInd[indEnt]].point[0]; - if (isExists) { - myConstraints[aCurConstrPos].ptA = aPtBase; - myConstraints[aCurConstrPos].ptB = aPtFillet; - aCMapIter++; - if (aCMapIter != aCMapEnd) - aCurConstrPos = Search(*aCMapIter, myConstraints); - } else if (addCoincidentPoints(aPtBase, aPtFillet)) { // the points are not connected by coincidence yet - aPonCurveConstr = Slvs_MakeConstraint( - ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h, - 0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - } - aPtFillet = myEntities[aFilletObjInd[indEnt]].point[1+aBaseCoincInd[indEnt]]; // !!! will be used below - aTangentType = SLVS_C_CURVE_CURVE_TANGENT; - } else { - aPtInd = aBaseCoincInd[indEnt]; - aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd]; - if (isExists) { - myConstraints[aCurConstrPos].ptA = aPtFillet; - aCMapIter++; - if (aCMapIter != aCMapEnd) - aCurConstrPos = Search(*aCMapIter, myConstraints); - } else { - aPonCurveConstr = Slvs_MakeConstraint( - ++myConstrMaxID, myID, SLVS_C_PT_ON_LINE, myWorkplane.h, - 0, aPtFillet, SLVS_E_UNKNOWN, aBaseObject[indEnt], SLVS_E_UNKNOWN); - } - aTangentType = SLVS_C_ARC_LINE_TANGENT; - } - if (!isExists) { - myConstraints.push_back(aPonCurveConstr); - aConstrList.push_back(aPonCurveConstr.h); - } - } - - if (!isExists) - myConstraintMap[theConstraint] = aConstrList; - - // Additional temporary constraints for base objects to be fixed - int aNbArcs = 0; - for (unsigned int indAttr = 0; indAttr < 2; indAttr++) { - if (!aBaseFeature[indAttr]) { - AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast( - aConstrData->attribute(aConstraintAttributes[indAttr])); - addTemporaryConstraintWhereDragged(aConstrAttr->attr()); - continue; - } - if (aBaseFeature[indAttr]->getKind() == SketchPlugin_Line::ID()) { - addTemporaryConstraintWhereDragged( - aBaseFeature[indAttr]->attribute(SketchPlugin_Line::START_ID())); - addTemporaryConstraintWhereDragged( - aBaseFeature[indAttr]->attribute(SketchPlugin_Line::END_ID())); - } else if (aBaseFeature[indAttr]->getKind() == SketchPlugin_Arc::ID()) { - // Arc should be fixed by its center only (to avoid "conflicting constraints" message) - // If the fillet is made on two arc, the shared point should be fixed too - aNbArcs++; - addTemporaryConstraintWhereDragged( - aBaseFeature[indAttr]->attribute(SketchPlugin_Arc::CENTER_ID())); - } - } - if (aNbArcs == 2) { - addTemporaryConstraintWhereDragged(aBaseCoincInd[0] == 0 ? - aBaseFeature[0]->attribute(SketchPlugin_Arc::START_ID()) : - aBaseFeature[0]->attribute(SketchPlugin_Arc::END_ID())); - } - return true; -} - -// ============================================================================ -// Function: changeEntity -// Class: SketchSolver_ConstraintGroup -// Purpose: create/update the element affected by any constraint -// ============================================================================ -Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity( - std::shared_ptr theEntity) -{ - // If the entity is already in the group, try to find it - std::map, Slvs_hEntity>::const_iterator aEntIter = - myEntityAttrMap.find(theEntity); - int aEntPos; - std::vector::iterator aParamIter; // looks at first parameter of already existent entity or at the end of vector otherwise - if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created - aParamIter = myParams.end(); - else { // the entity already exists - aEntPos = Search(aEntIter->second, myEntities); - int aParamPos = Search(myEntities[aEntPos].param[0], myParams); - aParamIter = myParams.begin() + aParamPos; - } - const bool isEntExists = (aEntIter != myEntityAttrMap.end()); // defines that the entity already exists - const bool isNeedToSolve = myNeedToSolve; - myNeedToSolve = false; - - if (isEntExists) { - // Verify that the entity is not used by "Rigid" constraint. - // If it is used, the object should not move. - std::vector >::iterator aCoincIter = myCoincidentPoints.begin(); - for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++) - if (aCoincIter->find(aEntIter->second) != aCoincIter->end()) - break; - std::set aCoincident; - if (aCoincIter != myCoincidentPoints.end()) { - aCoincident = *aCoincIter; - aCoincident.erase(aEntIter->second); - - 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()) { - myNeedToSolve = true; - return aEntIter->second; - } - } - } - - // Look over supported types of entities - Slvs_Entity aNewEntity; - aNewEntity.h = SLVS_E_UNKNOWN; - - // Point in 3D - std::shared_ptr aPoint = std::dynamic_pointer_cast( - theEntity); - if (aPoint) { - Slvs_hParam aX = changeParameter(aPoint->x(), aParamIter); - Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter); - Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter); - if (!isEntExists) // New entity - aNewEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ); - } else { - // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error - if (myWorkplane.h == SLVS_E_UNKNOWN) - return SLVS_E_UNKNOWN; - - // Point in 2D - std::shared_ptr aPoint2D = - std::dynamic_pointer_cast(theEntity); - if (aPoint2D) { - Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter); - Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter); - if (!isEntExists) // New entity - aNewEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV); - } else { - // Scalar value (used for the distance entities) - AttributeDoublePtr aScalar = std::dynamic_pointer_cast(theEntity); - if (aScalar) { - Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter); - if (!isEntExists) // New entity - aNewEntity = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue); - } - } - } - /// \todo Other types of entities - - Slvs_hEntity aResult = SLVS_E_UNKNOWN; // Unsupported or wrong entity type - - if (isEntExists) { - myNeedToSolve = myNeedToSolve || isNeedToSolve; - aResult = aEntIter->second; - } else if (aNewEntity.h != SLVS_E_UNKNOWN) { - myEntities.push_back(aNewEntity); - myEntOfConstr.push_back(false); - myEntityAttrMap[theEntity] = aNewEntity.h; - aResult = aNewEntity.h; - } - - // If the attribute was changed by the user, we need to fix it before solving - if (myNeedToSolve && theEntity->isImmutable()) - addTemporaryConstraintWhereDragged(theEntity, false); - - return aResult; -} - -// ============================================================================ -// Function: changeEntity -// Class: SketchSolver_ConstraintGroup -// Purpose: create/update the element defined by the feature affected by any constraint -// ============================================================================ -Slvs_hEntity SketchSolver_ConstraintGroup::changeEntityFeature(FeaturePtr theEntity) -{ - if (!theEntity->data()->isValid()) - return SLVS_E_UNKNOWN; - // If the entity is already in the group, try to find it - std::map::const_iterator aEntIter = myEntityFeatMap.find(theEntity); - // defines that the entity already exists - const bool isEntExists = (myEntityFeatMap.find(theEntity) != myEntityFeatMap.end()); - - Slvs_Entity aNewEntity; - aNewEntity.h = SLVS_E_UNKNOWN; - - // SketchPlugin features - std::shared_ptr aFeature = std::dynamic_pointer_cast< - SketchPlugin_Feature>(theEntity); - if (aFeature) { // Verify the feature by its kind - const std::string& aFeatureKind = aFeature->getKind(); - AttributePtr anAttribute; - - // Line - if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) { - anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID()); - if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; - Slvs_hEntity aStart = changeEntity(anAttribute); - - anAttribute = aFeature->data()->attribute(SketchPlugin_Line::END_ID()); - if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; - Slvs_hEntity aEnd = changeEntity(anAttribute); - - if (!isEntExists) // New entity - aNewEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd); - } - // Circle - else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) { - anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID()); - if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; - Slvs_hEntity aCenter = changeEntity(anAttribute); - - anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()); - if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; - Slvs_hEntity aRadius = changeEntity(anAttribute); - - if (!isEntExists) // New entity - aNewEntity = Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter, - myWorkplane.normal, aRadius); - } - // Arc - else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) { - anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID()); - if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; - Slvs_hEntity aCenter = changeEntity(anAttribute); - - anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::START_ID()); - if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; - Slvs_hEntity aStart = changeEntity(anAttribute); - - anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::END_ID()); - if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; - Slvs_hEntity aEnd = changeEntity(anAttribute); - - if (!isEntExists) - aNewEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID, myWorkplane.h, - myWorkplane.normal, aCenter, aStart, aEnd); - } - // Point (it has low probability to be an attribute of constraint, so it is checked at the end) - else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) { - anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID()); - if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; - Slvs_hEntity aPoint = changeEntity(anAttribute); - - if (isEntExists) - return aEntIter->second; - - // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier - myEntityFeatMap[theEntity] = aPoint; - myNeedToSolve = true; - return aPoint; - } - } - /// \todo Other types of features - - if (isEntExists) - return aEntIter->second; - - if (aNewEntity.h != SLVS_E_UNKNOWN) { - myEntities.push_back(aNewEntity); - myEntOfConstr.push_back(false); - myEntityFeatMap[theEntity] = aNewEntity.h; - myNeedToSolve = true; - return aNewEntity.h; - } - - // Unsupported or wrong entity type - return SLVS_E_UNKNOWN; -} - -// ============================================================================ -// Function: changeNormal -// Class: SketchSolver_ConstraintGroup -// Purpose: create/update the normal of workplane -// ============================================================================ -Slvs_hEntity SketchSolver_ConstraintGroup::changeNormal( - std::shared_ptr theDirX, - std::shared_ptr theNorm) -{ - std::shared_ptr aNorm = std::dynamic_pointer_cast(theNorm); - std::shared_ptr aDirX = std::dynamic_pointer_cast(theDirX); - if (!aDirX || (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance)) - return SLVS_E_UNKNOWN; - // 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 }; - - // Try to find existent normal - std::map, Slvs_hEntity>::const_iterator aEntIter = - myEntityAttrMap.find(theNorm); - std::vector::iterator aParamIter; // looks to the first parameter of already existent entity or to the end of vector otherwise - if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created - aParamIter = myParams.end(); - else { // the entity already exists, update it - int aEntPos = Search(aEntIter->second, myEntities); - int aParamPos = Search(myEntities[aEntPos].param[0], myParams); - aParamIter = myParams.begin() + aParamPos; - } - - // Change parameters of the normal - Slvs_hParam aNormParams[4]; - for (int i = 0; i < 4; i++) - aNormParams[i] = changeParameter(aNormCoord[i], aParamIter); - - if (aEntIter != myEntityAttrMap.end()) // the entity already exists - return aEntIter->second; - - // Create a normal - Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID, aNormParams[0], aNormParams[1], - aNormParams[2], aNormParams[3]); - myEntities.push_back(aNormal); - myEntOfConstr.push_back(false); - myEntityAttrMap[theNorm] = aNormal.h; - return aNormal.h; -} - -// ============================================================================ -// Function: addWorkplane -// Class: SketchSolver_ConstraintGroup -// Purpose: create workplane for the group -// ============================================================================ -bool SketchSolver_ConstraintGroup::addWorkplane(std::shared_ptr theSketch) -{ - if (myWorkplane.h || theSketch->getKind().compare(SketchPlugin_Sketch::ID()) != 0) - return false; // the workplane already exists or the function parameter is not Sketch - - mySketch = theSketch; - updateWorkplane(); - return true; -} - -// ============================================================================ -// Function: updateWorkplane -// Class: SketchSolver_ConstraintGroup -// Purpose: update parameters of workplane -// ============================================================================ -bool SketchSolver_ConstraintGroup::updateWorkplane() -{ - if (!mySketch->data()) - return false; // case sketch is deleted - // Get parameters of workplane - std::shared_ptr aDirX = mySketch->data()->attribute( - SketchPlugin_Sketch::DIRX_ID()); - std::shared_ptr aNorm = mySketch->data()->attribute( - SketchPlugin_Sketch::NORM_ID()); - std::shared_ptr anOrigin = mySketch->data()->attribute( - SketchPlugin_Sketch::ORIGIN_ID()); - // Transform them into SolveSpace format - Slvs_hEntity aNormalWP = changeNormal(aDirX, aNorm); - if (!aNormalWP) - return false; - Slvs_hEntity anOriginWP = changeEntity(anOrigin); - if (!anOriginWP) - return false; - - if (!myWorkplane.h) { - // Create workplane - myWorkplane = Slvs_MakeWorkplane(++myEntityMaxID, myID, anOriginWP, aNormalWP); - // Workplane should be added to the list of entities - myEntities.push_back(myWorkplane); - myEntOfConstr.push_back(false); - } - return true; -} - -// ============================================================================ -// Function: changeParameter -// Class: SketchSolver_ConstraintGroup -// Purpose: create/update value of parameter -// ============================================================================ -Slvs_hParam SketchSolver_ConstraintGroup::changeParameter( - double theParam, std::vector::iterator& thePrmIter) -{ - if (thePrmIter != myParams.end()) { // Parameter should be updated - int aParamPos = thePrmIter - myParams.begin(); - if (fabs(thePrmIter->val - theParam) > tolerance) { - myNeedToSolve = true; // parameter is changed, need to resolve constraints - myParams[aParamPos].val = theParam; - } - thePrmIter++; - return myParams[aParamPos].h; - } - - // Newly created parameter - Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam); - myParams.push_back(aParam); - myNeedToSolve = true; - // The list of parameters is changed, move iterator to the end of the list to avoid problems - thePrmIter = myParams.end(); - return aParam.h; -} - -// ============================================================================ -// Function: resolveConstraints -// Class: SketchSolver_ConstraintGroup -// Purpose: solve the set of constraints for the current group -// ============================================================================ -bool SketchSolver_ConstraintGroup::resolveConstraints() -{ - if (!myNeedToSolve) - return false; - - myConstrSolver.setGroupID(myID); - myConstrSolver.setParameters(myParams); - myConstrSolver.setEntities(myEntities); - myConstrSolver.setConstraints(myConstraints); - myConstrSolver.setDraggedParameters(myTempPointWhereDragged); - - int aResult = myConstrSolver.solve(); - if (aResult == SLVS_RESULT_OKAY) { // solution succeeded, store results into correspondent attributes - // Obtain result into the same list of parameters - if (!myConstrSolver.getResult(myParams)) - return true; - - // We should go through the attributes map, because only attributes have valued parameters - std::map, Slvs_hEntity>::iterator anEntIter = - myEntityAttrMap.begin(); - for (; anEntIter != myEntityAttrMap.end(); anEntIter++) { - if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get()) - anEntIter->first->owner()->data()->blockSendAttributeUpdated(true); - if (updateAttribute(anEntIter->first, anEntIter->second)) - updateRelatedConstraints(anEntIter->first); - } - updateFilletConstraints(); - // unblock all features then - for (anEntIter = myEntityAttrMap.begin(); anEntIter != myEntityAttrMap.end(); anEntIter++) { - if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get()) - anEntIter->first->owner()->data()->blockSendAttributeUpdated(false); - } - } else if (!myConstraints.empty()) - Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this); - - removeTemporaryConstraints(); - myNeedToSolve = false; - return true; -} - -// ============================================================================ -// Function: mergeGroups -// Class: SketchSolver_ConstraintGroup -// Purpose: append specified group to the current group -// ============================================================================ -void SketchSolver_ConstraintGroup::mergeGroups(const SketchSolver_ConstraintGroup& theGroup) -{ - // If specified group is empty, no need to merge - if (theGroup.myConstraintMap.empty()) - return; - - // Map between old and new indexes of SolveSpace constraints - std::map aConstrMap; - - // Add all constraints from theGroup to the current group - ConstraintMap::const_iterator aConstrIter = theGroup.myConstraintMap.begin(); - for (; aConstrIter != theGroup.myConstraintMap.end(); aConstrIter++) - if (changeConstraint(aConstrIter->first)) - aConstrMap[aConstrIter->second.back()] = myConstrMaxID; // the constraint was added => store its ID - - // Add temporary constraints from theGroup - std::list::const_iterator aTempConstrIter = theGroup.myTempConstraints.begin(); - for (; aTempConstrIter != theGroup.myTempConstraints.end(); aTempConstrIter++) { - std::map::iterator aFind = aConstrMap.find( - *aTempConstrIter); - if (aFind != aConstrMap.end()) - myTempConstraints.push_back(aFind->second); - } - - if (myTempPointWhereDragged.empty()) - myTempPointWhereDragged = theGroup.myTempPointWhereDragged; - else if (!theGroup.myTempPointWhereDragged.empty()) { // Need to create additional transient constraint - std::map, Slvs_hEntity>::const_iterator aFeatureIter = - theGroup.myEntityAttrMap.begin(); - for (; aFeatureIter != theGroup.myEntityAttrMap.end(); aFeatureIter++) - if (aFeatureIter->second == myTempPointWDrgdID) { - addTemporaryConstraintWhereDragged(aFeatureIter->first); - break; - } - } - - myNeedToSolve = myNeedToSolve || theGroup.myNeedToSolve; -} - -// ============================================================================ -// Function: splitGroup -// Class: SketchSolver_ConstraintGroup -// Purpose: divide the group into several subgroups -// ============================================================================ -void SketchSolver_ConstraintGroup::splitGroup(std::vector& theCuts) -{ - // Divide constraints and entities into several groups - std::vector > aGroupsEntities; - std::vector > aGroupsConstr; - int aMaxNbEntities = 0; // index of the group with maximal nuber of elements (this group will be left in the current) - std::vector::const_iterator aConstrIter = myConstraints.begin(); - for (; aConstrIter != myConstraints.end(); aConstrIter++) { - Slvs_hEntity aConstrEnt[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA, - aConstrIter->entityB }; - std::vector anIndexes; - // Go through the groupped entities and find even one of entities of current constraint - std::vector >::iterator aGrEntIter; - for (aGrEntIter = aGroupsEntities.begin(); aGrEntIter != aGroupsEntities.end(); aGrEntIter++) { - bool isFound = false; - for (int i = 0; i < 4 && !isFound; i++) - if (aConstrEnt[i] != 0) { - isFound = (aGrEntIter->find(aConstrEnt[i]) != aGrEntIter->end()); - // Also we need to check sub-entities - int aEntPos = Search(aConstrEnt[i], myEntities); - if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close - Slvs_hEntity* aSub = myEntities[aEntPos].point; - for (int j = 0; *aSub != 0 && j < 4 && !isFound; aSub++, j++) - isFound = (aGrEntIter->find(*aSub) != aGrEntIter->end()); - } - } - if (isFound) - anIndexes.push_back(aGrEntIter - aGroupsEntities.begin()); - } - // Add new group if no one is found - if (anIndexes.empty()) { - std::set aNewGrEnt; - for (int i = 0; i < 4; i++) - if (aConstrEnt[i] != 0) { - aNewGrEnt.insert(aConstrEnt[i]); - int aEntPos = Search(aConstrEnt[i], myEntities); - if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close - Slvs_hEntity* aSub = myEntities[aEntPos].point; - for (int j = 0; *aSub != 0 && j < 4; aSub++, j++) - aNewGrEnt.insert(*aSub); - } - } - std::set aNewGrConstr; - aNewGrConstr.insert(aConstrIter->h); - - aGroupsEntities.push_back(aNewGrEnt); - aGroupsConstr.push_back(aNewGrConstr); - if (aNewGrEnt.size() > aGroupsEntities[aMaxNbEntities].size()) - aMaxNbEntities = aGroupsEntities.size() - 1; - } else { // Add entities indexes into the found group - aGrEntIter = aGroupsEntities.begin() + anIndexes.front(); - for (int i = 0; i < 4; i++) - if (aConstrEnt[i] != 0) { - aGrEntIter->insert(aConstrEnt[i]); - int aEntPos = Search(aConstrEnt[i], myEntities); - if (aEntPos != myEntities.size()) { // MPV: to fix the crash on close - Slvs_hEntity* aSub = myEntities[aEntPos].point; - for (int j = 0; *aSub != 0 && j < 4; aSub++, j++) - aGrEntIter->insert(*aSub); - } - } - aGroupsConstr[anIndexes.front()].insert(aConstrIter->h); - if (aGrEntIter->size() > aGroupsEntities[aMaxNbEntities].size()) - aMaxNbEntities = aGrEntIter - aGroupsEntities.begin(); - if (anIndexes.size() > 1) { // There are found several connected groups, merge them - std::vector >::iterator aFirstGroup = aGroupsEntities.begin() - + anIndexes.front(); - std::vector >::iterator aFirstConstr = aGroupsConstr.begin() - + anIndexes.front(); - std::vector::iterator anInd = anIndexes.begin(); - for (++anInd; anInd != anIndexes.end(); anInd++) { - aFirstGroup->insert(aGroupsEntities[*anInd].begin(), aGroupsEntities[*anInd].end()); - aFirstConstr->insert(aGroupsConstr[*anInd].begin(), aGroupsConstr[*anInd].end()); - } - if (aFirstGroup->size() > aGroupsEntities[aMaxNbEntities].size()) - aMaxNbEntities = anIndexes.front(); - // Remove merged groups - for (anInd = anIndexes.end() - 1; anInd != anIndexes.begin(); anInd--) { - aGroupsEntities.erase(aGroupsEntities.begin() + (*anInd)); - aGroupsConstr.erase(aGroupsConstr.begin() + (*anInd)); - } - } - } - } - - if (aGroupsEntities.size() <= 1) - return; - - // Remove the group with maximum elements as it will be left in the current group - aGroupsEntities.erase(aGroupsEntities.begin() + aMaxNbEntities); - aGroupsConstr.erase(aGroupsConstr.begin() + aMaxNbEntities); - - // Add new groups of constraints and divide current group - std::vector aNewGroups; - for (int i = aGroupsEntities.size(); i > 0; i--) { - SketchSolver_ConstraintGroup* aG = new SketchSolver_ConstraintGroup(mySketch); - aNewGroups.push_back(aG); - } - ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.begin(); - int aConstrMapPos = 0; // position of iterator in the map (used to restore iterator after removing constraint) - while (aConstrMapIter != myConstraintMap.end()) { - std::vector >::const_iterator aGIter = aGroupsConstr.begin(); - std::vector::iterator aGroup = aNewGroups.begin(); - for (; aGIter != aGroupsConstr.end(); aGIter++, aGroup++) - if (aGIter->find(aConstrMapIter->second.front()) != aGIter->end()) { - (*aGroup)->changeConstraint(aConstrMapIter->first); - removeConstraint(aConstrMapIter->first); - // restore iterator - aConstrMapIter = myConstraintMap.begin(); - for (int i = 0; i < aConstrMapPos; i++) - aConstrMapIter++; - break; - } - if (aGIter == aGroupsConstr.end()) { - aConstrMapIter++; - aConstrMapPos++; - } - } - - theCuts.insert(theCuts.end(), aNewGroups.begin(), aNewGroups.end()); -} - -// ============================================================================ -// Function: updateGroup -// Class: SketchSolver_ConstraintGroup -// Purpose: search removed entities and constraints -// ============================================================================ -bool SketchSolver_ConstraintGroup::updateGroup() -{ - ConstraintMap::reverse_iterator aConstrIter = myConstraintMap.rbegin(); - bool isAllValid = true; - bool isCCRemoved = false; // indicates that at least one of coincidence constraints was removed - int aConstrIndex = 0; - while (/*isAllValid && */aConstrIter != myConstraintMap.rend()) { - if (!aConstrIter->first->data() || !aConstrIter->first->data()->isValid()) { - if (aConstrIter->first->getKind().compare(SketchPlugin_ConstraintCoincidence::ID()) == 0) - isCCRemoved = true; - removeConstraint(aConstrIter->first); - isAllValid = false; - // Get back the correct position of iterator after the "remove" operation - aConstrIter = myConstraintMap.rbegin(); - for (int i = 0; i < aConstrIndex && aConstrIter != myConstraintMap.rend(); i++) - aConstrIter++; - } else { - aConstrIter++; - aConstrIndex++; - } - } - - // Check if some entities are invalid too - std::set anEntToRemove; - std::map, Slvs_hEntity>::iterator - anAttrIter = myEntityAttrMap.begin(); - while (anAttrIter != myEntityAttrMap.end()) { - if (!anAttrIter->first->owner() || !anAttrIter->first->owner()->data() || - !anAttrIter->first->owner()->data()->isValid()) { - anEntToRemove.insert(anAttrIter->second); - std::map, Slvs_hEntity>::iterator - aRemovedIter = anAttrIter; - anAttrIter++; - myEntityAttrMap.erase(aRemovedIter); - } else - anAttrIter++; - } - std::map::iterator aFeatIter = myEntityFeatMap.begin(); - while (aFeatIter != myEntityFeatMap.end()) { - if (!aFeatIter->first || !aFeatIter->first->data() || - !aFeatIter->first->data()->isValid()) { - anEntToRemove.insert(aFeatIter->second); - std::map::iterator aRemovedIter = aFeatIter; - aFeatIter++; - myEntityFeatMap.erase(aRemovedIter); - } else - aFeatIter++; - } - removeEntitiesById(anEntToRemove); - - // Probably, need to update coincidence constraints - if (isCCRemoved && !myExtraCoincidence.empty()) { - // Make a copy, because the new list of unused constrtaints will be generated - std::set > anExtraCopy = myExtraCoincidence; - myExtraCoincidence.clear(); - - std::set >::iterator aCIter = anExtraCopy.begin(); - for (; aCIter != anExtraCopy.end(); aCIter++) - if ((*aCIter)->data() && (*aCIter)->data()->isValid()) - changeConstraint(*aCIter); - } - - return !isAllValid; -} - -// ============================================================================ -// Function: updateAttribute -// Class: SketchSolver_ConstraintGroup -// Purpose: update features of sketch after resolving constraints -// ============================================================================ -bool SketchSolver_ConstraintGroup::updateAttribute( - std::shared_ptr theAttribute, const Slvs_hEntity& theEntityID) -{ - // Search the position of the first parameter of the entity - int anEntPos = Search(theEntityID, myEntities); - int aFirstParamPos = Search(myEntities[anEntPos].param[0], myParams); - - // Look over supported types of entities - - // Point in 3D - std::shared_ptr aPoint = std::dynamic_pointer_cast( - theAttribute); - if (aPoint) { - if (fabs(aPoint->x() - myParams[aFirstParamPos].val) > tolerance - || fabs(aPoint->y() - myParams[aFirstParamPos + 1].val) > tolerance - || fabs(aPoint->z() - myParams[aFirstParamPos + 2].val) > tolerance) { - aPoint->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val, - myParams[aFirstParamPos + 2].val); - return true; - } - return false; - } - - // Point in 2D - std::shared_ptr aPoint2D = - std::dynamic_pointer_cast(theAttribute); - if (aPoint2D) { - if (fabs(aPoint2D->x() - myParams[aFirstParamPos].val) > tolerance - || fabs(aPoint2D->y() - myParams[aFirstParamPos + 1].val) > tolerance) { - aPoint2D->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val); - return true; - } - return false; - } - - // Scalar value - AttributeDoublePtr aScalar = std::dynamic_pointer_cast(theAttribute); - if (aScalar) { - if (fabs(aScalar->value() - myParams[aFirstParamPos].val) > tolerance) { - aScalar->setValue(myParams[aFirstParamPos].val); - return true; - } - return false; - } - - /// \todo Support other types of entities - return false; -} - -// ============================================================================ -// Function: updateEntityIfPossible -// Class: SketchSolver_ConstraintGroup -// Purpose: search the entity in this group and update it -// ============================================================================ -void SketchSolver_ConstraintGroup::updateEntityIfPossible( - std::shared_ptr theEntity) -{ - if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end()) { - // If the attribute is a point and it is changed (the group needs to rebuild), - // probably user has dragged this point into this position, - // so it is necessary to add constraint which will guarantee the point will not change - - // Store myNeedToSolve flag to verify the entity is really changed - bool aNeedToSolveCopy = myNeedToSolve; - myNeedToSolve = false; - - changeEntity(theEntity); - - if (myNeedToSolve) // the entity is changed - { - // Verify the entity is a point and add temporary constraint of permanency - std::shared_ptr aPoint = std::dynamic_pointer_cast( - theEntity); - std::shared_ptr aPoint2D = std::dynamic_pointer_cast< - GeomDataAPI_Point2D>(theEntity); - if (aPoint || aPoint2D) - addTemporaryConstraintWhereDragged(theEntity); - } - - // Restore flag of changes - myNeedToSolve = myNeedToSolve || aNeedToSolveCopy; - - if (myNeedToSolve) - updateRelatedConstraints(theEntity); - } -} - -// ============================================================================ -// Function: addTemporaryConstraintWhereDragged -// Class: SketchSolver_ConstraintGroup -// Purpose: add transient constraint SLVS_C_WHERE_DRAGGED for the entity, -// which was moved by user -// ============================================================================ -void SketchSolver_ConstraintGroup::addTemporaryConstraintWhereDragged( - std::shared_ptr theEntity, - bool theAllowToFit) -{ - // Find identifier of the entity - std::map, Slvs_hEntity>::const_iterator anEntIter = - myEntityAttrMap.find(theEntity); - if (anEntIter == myEntityAttrMap.end()) - return; - - // Get identifiers of all dragged points - std::set aDraggedPntID; - aDraggedPntID.insert(myTempPointWDrgdID); - std::list::const_iterator aTmpCoIter = myTempConstraints.begin(); - for (; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++) { - unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints); - if (aConstrPos < myConstraints.size()) - aDraggedPntID.insert(myConstraints[aConstrPos].ptA); - } - std::vector::const_iterator aConstrIter = myConstraints.begin(); - for (; aConstrIter != myConstraints.end(); aConstrIter++) - if (aConstrIter->type == SLVS_C_WHERE_DRAGGED) - aDraggedPntID.insert(aConstrIter->ptA); - // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED - std::vector >::iterator aCoPtIter = myCoincidentPoints.begin(); - for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) { - if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end()) - continue; // the entity was not found in current set - - // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points - std::set::const_iterator aDrgIter = aDraggedPntID.begin(); - for (; aDrgIter != aDraggedPntID.end(); aDrgIter++) - if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end()) - return; // the SLVS_C_WHERE_DRAGGED constraint already exists - } - if (aDraggedPntID.find(anEntIter->second) != aDraggedPntID.end()) - return; - - // If this is a first dragged point, its parameters should be placed - // into Slvs_System::dragged field to avoid system inconsistense - if (myTempPointWhereDragged.empty() && theAllowToFit) { - int anEntPos = Search(anEntIter->second, myEntities); - Slvs_hParam* aDraggedParam = myEntities[anEntPos].param; - for (int i = 0; i < 4; i++, aDraggedParam++) - if (*aDraggedParam != 0) - myTempPointWhereDragged.push_back(*aDraggedParam); - myTempPointWDrgdID = myEntities[anEntPos].h; - return; - } - - // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty - Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, - myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0); - myConstraints.push_back(aWDConstr); - myTempConstraints.push_back(aWDConstr.h); -} - -// ============================================================================ -// Function: removeTemporaryConstraints -// Class: SketchSolver_ConstraintGroup -// Purpose: remove all transient SLVS_C_WHERE_DRAGGED constraints after -// resolving the set of constraints -// ============================================================================ -void SketchSolver_ConstraintGroup::removeTemporaryConstraints( - const std::set& theRemoved) -{ - std::list::reverse_iterator aTmpConstrIter; - for (aTmpConstrIter = myTempConstraints.rbegin(); aTmpConstrIter != myTempConstraints.rend(); - aTmpConstrIter++) { - if (!theRemoved.empty() && theRemoved.find(*aTmpConstrIter) == theRemoved.end()) - continue; - unsigned int aConstrPos = Search(*aTmpConstrIter, myConstraints); - if (aConstrPos >= myConstraints.size()) - continue; - myConstraints.erase(myConstraints.begin() + aConstrPos); - - // If the removing constraint has higher index, decrease the indexer - if (*aTmpConstrIter == myConstrMaxID) - myConstrMaxID--; - } - myTempConstraints.clear(); - - // Clear basic dragged point - myTempPointWhereDragged.clear(); - myTempPointWDrgdID = SLVS_E_UNKNOWN; -} - -// ============================================================================ -// Function: removeConstraint -// Class: SketchSolver_ConstraintGroup -// Purpose: remove constraint and all unused entities -// ============================================================================ -void SketchSolver_ConstraintGroup::removeConstraint( - std::shared_ptr theConstraint) -{ - ConstraintMap::iterator anIterToRemove = myConstraintMap.find(theConstraint); - if (anIterToRemove == myConstraintMap.end()) - return; - - std::vector aCnstrToRemove = anIterToRemove->second; - // Remove constraint from the map - myConstraintMap.erase(anIterToRemove); - - std::set anEntToRemove; - - // Find unused entities - std::vector::iterator aCnstrToRemoveIter = aCnstrToRemove.begin(); - for (; aCnstrToRemoveIter != aCnstrToRemove.end(); aCnstrToRemoveIter++) { - int aConstrPos = Search(*aCnstrToRemoveIter, myConstraints); - Slvs_hEntity aCnstEnt[] = { myConstraints[aConstrPos].ptA, myConstraints[aConstrPos].ptB, - myConstraints[aConstrPos].entityA, myConstraints[aConstrPos].entityB }; - for (int i = 0; i < 4; i++) - if (aCnstEnt[i] != 0) - anEntToRemove.insert(aCnstEnt[i]); - myConstraints.erase(myConstraints.begin() + aConstrPos); - if (*aCnstrToRemoveIter == myConstrMaxID) - myConstrMaxID--; - } - - // Find all entities which are based on these unused - std::vector::const_iterator anEntIter = myEntities.begin(); - for ( ; anEntIter != myEntities.end(); anEntIter++) - if (anEntIter->type == SLVS_E_LINE_SEGMENT || anEntIter->type == SLVS_E_CIRCLE || - anEntIter->type == SLVS_E_ARC_OF_CIRCLE) { - for (int i = 0; i < 4; i++) - if (anEntToRemove.find(anEntIter->point[i]) != anEntToRemove.end()) { - anEntToRemove.insert(anEntIter->h); - for (int j = 0; j < 4; j++) - if (anEntIter->point[j] != 0) - anEntToRemove.insert(anEntIter->point[j]); - break; - } - } - - // Find entities used by remaining constraints and remove them from the list to delete - std::vector::const_iterator aConstrIter = myConstraints.begin(); - for (; aConstrIter != myConstraints.end(); aConstrIter++) { - Slvs_hEntity aEnts[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA, aConstrIter - ->entityB }; - for (int i = 0; i < 4; i++) - if (aEnts[i] != 0 && anEntToRemove.find(aEnts[i]) != anEntToRemove.end()) { - anEntToRemove.erase(aEnts[i]); - // remove from the list all points of current entity - int aEntPos = Search(aEnts[i], myEntities); - for (int j = 0; j < 4; j++) - if (myEntities[aEntPos].point[j] != 0) - anEntToRemove.erase(myEntities[aEntPos].point[j]); - } - } - - if (anEntToRemove.empty()) - return; - - // Remove unused entities - std::map, Slvs_hEntity>::iterator anEntAttrIter = - myEntityAttrMap.begin(); - while (anEntAttrIter != myEntityAttrMap.end()) { - if (anEntToRemove.find(anEntAttrIter->second) != anEntToRemove.end()) { - std::map, Slvs_hEntity>::iterator aRemovedIter = - anEntAttrIter; - anEntAttrIter++; - myEntityAttrMap.erase(aRemovedIter); - } else - anEntAttrIter++; - } - std::map::iterator anEntFeatIter = myEntityFeatMap.begin(); - while (anEntFeatIter != myEntityFeatMap.end()) { - if (anEntToRemove.find(anEntFeatIter->second) != anEntToRemove.end()) { - std::map::iterator aRemovedIter = anEntFeatIter; - anEntFeatIter++; - myEntityFeatMap.erase(aRemovedIter); - } else - anEntFeatIter++; - } - - removeEntitiesById(anEntToRemove); - - if (myCoincidentPoints.size() == 1 && myCoincidentPoints.front().empty()) - myCoincidentPoints.clear(); -} - -// ============================================================================ -// Function: removeEntitiesById -// Class: SketchSolver_ConstraintGroup -// Purpose: Removes specified entities and their parameters -// ============================================================================ -void SketchSolver_ConstraintGroup::removeEntitiesById(const std::set& theEntities) -{ - std::set::const_reverse_iterator aRemIter = theEntities.rbegin(); - for (; aRemIter != theEntities.rend(); aRemIter++) { - unsigned int anEntPos = Search(*aRemIter, myEntities); - if (anEntPos >= myEntities.size()) - continue; - if (myEntities[anEntPos].param[0] != 0) { - unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams); - if (aParamPos >= myParams.size()) - continue; - int aNbParams = 0; - while (myEntities[anEntPos].param[aNbParams] != 0) - aNbParams++; - if (myEntities[anEntPos].param[aNbParams - 1] == myParamMaxID) - myParamMaxID -= aNbParams; - myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams); - if (*aRemIter == myEntityMaxID) - myEntityMaxID--; - } - myEntities.erase(myEntities.begin() + anEntPos); - myEntOfConstr.erase(myEntOfConstr.begin() + anEntPos); - - // Remove entity's ID from the lists of conincident points - std::vector >::iterator aCoPtIter = myCoincidentPoints.begin(); - for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) - aCoPtIter->erase(*aRemIter); - } -} - -// ============================================================================ -// Function: addCoincidentPoints -// Class: SketchSolver_ConstraintGroup -// Purpose: add coincident point the appropriate list of such points -// ============================================================================ -bool SketchSolver_ConstraintGroup::addCoincidentPoints(const Slvs_hEntity& thePoint1, - const Slvs_hEntity& thePoint2) -{ - std::vector >::iterator aCoPtIter = myCoincidentPoints.begin(); - std::vector >::iterator aFirstFound = myCoincidentPoints.end(); - while (aCoPtIter != myCoincidentPoints.end()) { - bool isFound[2] = { // indicate which point ID was already in coincidence constraint - aCoPtIter->find(thePoint1) != aCoPtIter->end(), aCoPtIter->find(thePoint2) - != aCoPtIter->end(), }; - if (isFound[0] && isFound[1]) // points are already connected by coincidence constraints => no need additional one - return false; - if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1])) { - if (aFirstFound != myCoincidentPoints.end()) { // there are two groups of coincident points connected by created constraint => merge them - int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin(); - int aCurrentShift = aCoPtIter - myCoincidentPoints.begin(); - aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end()); - myCoincidentPoints.erase(aCoPtIter); - aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift; - aCoPtIter = myCoincidentPoints.begin() + aCurrentShift; - continue; - } else { - aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1); - aFirstFound = aCoPtIter; - } - } - aCoPtIter++; - } - // No points were found, need to create new set - if (aFirstFound == myCoincidentPoints.end()) { - std::set aNewSet; - aNewSet.insert(thePoint1); - aNewSet.insert(thePoint2); - myCoincidentPoints.push_back(aNewSet); - } - - return true; -} - -// ============================================================================ -// Function: updateRelatedConstraints -// Class: SketchSolver_ConstraintGroup -// Purpose: emit the signal to update constraints -// ============================================================================ -void SketchSolver_ConstraintGroup::updateRelatedConstraints( - std::shared_ptr theEntity) const -{ - ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin(); - for (; aConstrIter != myConstraintMap.end(); aConstrIter++) { - std::list > anAttributes = aConstrIter->first->data() - ->attributes(std::string()); - - std::list >::iterator anAttrIter = anAttributes.begin(); - for (; anAttrIter != anAttributes.end(); anAttrIter++) { - bool isUpd = (*anAttrIter == theEntity); - std::shared_ptr aRefAttr = std::dynamic_pointer_cast< - ModelAPI_AttributeRefAttr>(*anAttrIter); - if (aRefAttr && !aRefAttr->isObject() && aRefAttr->attr() == theEntity) - isUpd = true; - - if (isUpd) { - static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); - ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent); - break; - } - } - } -} - -void SketchSolver_ConstraintGroup::updateRelatedConstraintsFeature( - std::shared_ptr theFeature) const -{ - ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin(); - for (; aConstrIter != myConstraintMap.end(); aConstrIter++) { - std::list > anAttributes = aConstrIter->first->data() - ->attributes(std::string()); - - std::list >::iterator anAttrIter = anAttributes.begin(); - for (; anAttrIter != anAttributes.end(); anAttrIter++) { - std::shared_ptr aRefAttr = std::dynamic_pointer_cast< - ModelAPI_AttributeRefAttr>(*anAttrIter); - if (aRefAttr && aRefAttr->isObject() && aRefAttr->object() == theFeature) { - static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); - ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent); - break; - } - } - } -} - -// ============================================================================ -// Function: updateFilletConstraints -// Class: SketchSolver_ConstraintGroup -// Purpose: change fillet arc to be less than 180 degree -// ============================================================================ -void SketchSolver_ConstraintGroup::updateFilletConstraints() -{ - ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin(); - for (; aConstrIter != myConstraintMap.end(); aConstrIter++) - if (aConstrIter->first->getKind() == SketchPlugin_ConstraintFillet::ID()) { - AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast( - aConstrIter->first->data()->attribute(SketchPlugin_ConstraintFillet::ENTITY_C())); - if (!aFilletRefList) - return; - ObjectPtr anArcObj = aFilletRefList->object(2); - std::shared_ptr aCenter = std::dynamic_pointer_cast( - anArcObj->data()->attribute(SketchPlugin_Arc::CENTER_ID())); - std::shared_ptr aStart = std::dynamic_pointer_cast( - anArcObj->data()->attribute(SketchPlugin_Arc::START_ID())); - std::shared_ptr aEnd = std::dynamic_pointer_cast( - anArcObj->data()->attribute(SketchPlugin_Arc::END_ID())); - double aCosA = aStart->x() - aCenter->x(); - double aSinA = aStart->y() - aCenter->y(); - double aCosB = aEnd->x() - aCenter->x(); - double aSinB = aEnd->y() - aCenter->y(); - if (aCosA * aSinB - aSinA * aCosB <= 0.0) { - anArcObj->data()->blockSendAttributeUpdated(true); - double x = aStart->x(); - double y = aStart->y(); - aStart->setValue(aEnd->x(), aEnd->y()); - aEnd->setValue(x, y); - // Update constraint data - changeFilletConstraint(aConstrIter->first); - anArcObj->data()->blockSendAttributeUpdated(false); - } - } -} - -// ============================================================================ -// Function: makeMirrorEntity -// Class: SketchSolver_ConstraintGroup -// Purpose: change entities parameters to make them symmetric relating to the mirror line -// ============================================================================ -void SketchSolver_ConstraintGroup::makeMirrorEntity(const Slvs_hEntity& theBase, - const Slvs_hEntity& theMirror, - const Slvs_hEntity& theMirrorLine) -{ - Slvs_Entity aBase = myEntities[Search(theBase, myEntities)]; - Slvs_Entity aMirror = myEntities[Search(theMirror, myEntities)]; - int i = 0; - if (aBase.type != SLVS_E_ARC_OF_CIRCLE) { - while (aBase.point[i] != 0 && aMirror.point[i] != 0) { - makeMirrorEntity(aBase.point[i], aMirror.point[i], theMirrorLine); - i++; - } - } else { - // swap mirroring first and last points of an arc - makeMirrorEntity(aBase.point[0], aMirror.point[0], theMirrorLine); - makeMirrorEntity(aBase.point[1], aMirror.point[2], theMirrorLine); - makeMirrorEntity(aBase.point[2], aMirror.point[1], theMirrorLine); - } - if (aBase.param[0] != 0 && aMirror.param[0] != 0) { // this is a point, copy it - Slvs_Entity aMirrorLine = myEntities[Search(theMirrorLine, myEntities)]; - std::shared_ptr aLinePoints[2]; - for (i = 0; i < 2; i++) { - Slvs_Entity aPoint = myEntities[Search(aMirrorLine.point[i], myEntities)]; - int aParamPos = Search(aPoint.param[0], myParams); - aLinePoints[i] = std::shared_ptr( - new GeomAPI_XY(myParams[aParamPos].val, myParams[1+aParamPos].val)); - } - int aBaseParamPos = Search(aBase.param[0], myParams); - int aMirrorParamPos = Search(aMirror.param[0], myParams); - std::shared_ptr aPoint = std::shared_ptr( - new GeomAPI_XY(myParams[aBaseParamPos].val, myParams[1+aBaseParamPos].val)); - - // 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())); - - 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()); - std::shared_ptr aMirrorPoint = aPoint->added(aDir->xy()->multiplied(-2.0 * aDist)); - - myParams[aMirrorParamPos].val = aMirrorPoint->x(); - myParams[1+aMirrorParamPos].val = aMirrorPoint->y(); - } -} - -// ============================================================================ -// Function: changeMirrorPoints -// Class: SketchSolver_ConstraintGroup -// Purpose: creates/updates mirror constraint for two points -// ============================================================================ -Slvs_hConstraint SketchSolver_ConstraintGroup::changeMirrorPoints( - const Slvs_hEntity& theBasePoint, - const Slvs_hEntity& theMirrorPoint, - const Slvs_hEntity& theMirrorLine, - std::vector& thePrevConstr, - std::map& thePrevMirror) -{ - std::map::iterator aMapIter = thePrevMirror.find(theBasePoint); - if (aMapIter != thePrevMirror.end()) { - thePrevMirror.erase(aMapIter); - std::vector::iterator anIter = thePrevConstr.begin(); - for (; anIter != thePrevConstr.end(); anIter++) - if (anIter->ptA == theBasePoint) { - if (anIter->ptB != theMirrorPoint) { - int aConstrInd = Search(anIter->h, myConstraints); - myConstraints[aConstrInd].ptB = theMirrorPoint; - myConstraints[aConstrInd].entityA = theMirrorLine; - } - Slvs_hConstraint aResult = anIter->h; - thePrevConstr.erase(anIter); - return aResult; - } - } - - // Newly created constraint - Slvs_Constraint aConstraint = Slvs_MakeConstraint( - ++myConstrMaxID, myID, SLVS_C_SYMMETRIC_LINE, myWorkplane.h, 0.0, - theBasePoint, theMirrorPoint, theMirrorLine, SLVS_E_UNKNOWN); - myConstraints.push_back(aConstraint); - return aConstraint.h; -} - - -// ============================================================================ -// Function: calculateMiddlePoint -// Class: SketchSolver_ConstraintGroup -// Purpose: calculates middle point on line or arc -// ============================================================================ -void SketchSolver_ConstraintGroup::calculateMiddlePoint( - const Slvs_hEntity& theEntity, - double& theX, - double& theY) const -{ - int anInd = Search(theEntity, myEntities); - if (myEntities[anInd].type == SLVS_E_LINE_SEGMENT) { - int aLineParams[2]; - for (int i = 0; i < 2; i++) { - int aPtPos = Search(myEntities[anInd].point[i], myEntities); - aLineParams[i] = Search(myEntities[aPtPos].param[0], myParams); - } - theX = 0.5 * (myParams[aLineParams[0]].val + myParams[aLineParams[1]].val); - theY = 0.5 * (myParams[1 + aLineParams[0]].val + myParams[1 + aLineParams[1]].val); - } else if (myEntities[anInd].type == SLVS_E_ARC_OF_CIRCLE) { - double anArcPoint[3][2]; - for (int i = 0; i < 3; i++) { - int aPtPos = Search(myEntities[anInd].point[i], myEntities); - int anArcParam = Search(myEntities[aPtPos].param[0], myParams); - anArcPoint[i][0] = myParams[anArcParam].val; - anArcPoint[i][1] = myParams[1 + anArcParam].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] = anArcPoint[0][0] + x * aRad / aNorm; - anArcPoint[2][1] = anArcPoint[0][1] + y * aRad / aNorm; - } - - x = anArcPoint[1][0] + anArcPoint[2][0] - 2.0 * anArcPoint[0][0]; - y = anArcPoint[1][1] + anArcPoint[2][1] - 2.0 * anArcPoint[0][1]; - aNorm = sqrt(x*x + y*y); - if (aNorm >= tolerance) { - x *= aRad / aNorm; - y *= aRad / aNorm; - } else { // obtain orthogonal direction - x = 0.5 * (anArcPoint[2][1] - anArcPoint[1][1]); - y = -0.5 * (anArcPoint[2][0] - anArcPoint[1][0]); - } - theX = anArcPoint[0][0] + x; - theY = anArcPoint[0][1] + y; - } -} - - -// ======================================================== -// ========= 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(); - while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID) - aResIndex--; - while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID) - aResIndex++; - if (aResIndex == -1) - aResIndex = aVecSize; - return aResIndex; -} diff --git a/src/SketchSolver/SketchSolver_ConstraintGroup.h b/src/SketchSolver/SketchSolver_ConstraintGroup.h deleted file mode 100644 index 8ec26852f..000000000 --- a/src/SketchSolver/SketchSolver_ConstraintGroup.h +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: SketchSolver_ConstraintGroup.h -// Created: 27 May 2014 -// Author: Artem ZHIDKOV - -#ifndef SketchSolver_ConstraintGroup_H_ -#define SketchSolver_ConstraintGroup_H_ - -#include "SketchSolver.h" -#include - -#include -#include -#include - - -#include -#include -#include -#include -#include - -typedef std::map< std::shared_ptr, std::vector > - ConstraintMap; - -/** \class SketchSolver_ConstraintGroup - * \ingroup Plugins - * \brief Keeps the group of constraints which based on the same entities - */ -class SketchSolver_ConstraintGroup -{ - public: - /** \brief New group based on specified workplane. - * Throws an exception if theWorkplane is not an object of SketchPlugin_Sketch type - * \remark Type of theSketch is not verified inside - */ - SketchSolver_ConstraintGroup(std::shared_ptr theWorkplane); - - ~SketchSolver_ConstraintGroup(); - - /// \brief Returns group's unique identifier - inline const Slvs_hGroup& getId() const - { - return myID; - } - - /// \brief Returns true if the group has no constraints yet - inline bool isEmpty() const - { - return myConstraints.empty(); - } - - /// \brief Check for valid sketch data - inline bool isWorkplaneValid() const - { - return mySketch->data() && mySketch->data()->isValid(); - } - - /** \brief Adds or updates a constraint in the group - * \param[in] theConstraint constraint to be changed - * \return \c true if the constraint added or updated successfully - */ - bool changeConstraint(std::shared_ptr theConstraint); - /** \brief Adds or updates a rigid constraint in the group - * \param[in] theConstraint constraint to be changed - * \return \c true if the constraint added or updated successfully - */ - bool changeRigidConstraint(std::shared_ptr theConstraint); - /** \brief Adds or updates a mirror constraint in the group - * \param[in] theConstraint constraint to be changed - * \return \c true if the constraint added or updated successfully - */ - bool changeMirrorConstraint(std::shared_ptr theConstraint); - /** \brief Adds or updates a fillet constraint in the group - * \param[in] theConstraint constraint to be changed - * \return \c true if the constraint added or updated successfully - */ - bool changeFilletConstraint(std::shared_ptr theConstraint); - - /** \brief Verifies the feature attributes are used in this group - * \param[in] theFeature constraint or any other object for verification of interaction - * \return \c true if some of attributes are used in current group - */ - bool isInteract(std::shared_ptr theFeature) const; - - /** \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 - * \return \c true if workplanes are the same - */ - bool isBaseWorkplane(std::shared_ptr theWorkplane) const; - - /// Returns the current workplane - std::shared_ptr getWorkplane() const - { - return mySketch; - } - - /** \brief Update parameters of workplane. Should be called when Update event is coming. - * \return \c true if workplane updated successfully, \c false if workplane parameters are not consistent - */ - bool updateWorkplane(); - - /** \brief If the entity is in this group it will updated - * \param[in] theEntity attribute, which values should update SolveSpace entity - */ - void updateEntityIfPossible(std::shared_ptr theEntity); - - /** \brief Searches invalid features and constraints in the group and avoids them - * \return \c true if the group several constraints were removed - */ - bool updateGroup(); - - /** \brief Add specified group to this one - * \param[in] theGroup group of constraint to be added - */ - void mergeGroups(const SketchSolver_ConstraintGroup& theGroup); - - /** \brief Cut from the group several subgroups, which are not connected to the current one by any constraint - * \param[out] theCuts enlarge this list by newly created groups - */ - void splitGroup(std::vector& theCuts); - - /** \brief Start solution procedure if necessary and update attributes of features - * \return \c false when no need to solve constraints - */ - bool resolveConstraints(); - - /** \brief Searches the constraints built on the entity and emit the signal to update them - * \param[in] theEntity attribute of the constraint - */ - void updateRelatedConstraints(std::shared_ptr theEntity) const; - /** \brief Searches the constraints built on the entity and emit the signal to update them - * \param[in] theFeature feature of the constraint - */ - void updateRelatedConstraintsFeature(std::shared_ptr theFeature) const; - - /** \brief Adds or updates an entity in the group - * - * The parameters of entity will be parsed and added to the list of SolveSpace parameters. - * Parameters of certain entity will be placed sequentially in the list. - * - * \param[in] theEntity the object of constraint - * \return identifier of changed entity or 0 if entity could not be changed - */ - Slvs_hEntity changeEntity(std::shared_ptr theEntity); - Slvs_hEntity changeEntityFeature(std::shared_ptr theEntity); - -protected: - /** \brief Adds or updates a normal in the group - * - * Normal is a special entity in SolveSpace, which defines a direction in 3D and - * a rotation about this direction. So, SolveSpace represents normals as unit quaternions. - * - * To define a normal there should be specified two coordinate axis - * on the plane transversed to created normal. - * - * \param[in] theDirX first coordinate axis of the plane - * \param[in] theNorm attribute for the normal (used to identify newly created entity) - * \return identifier of created or updated normal - */ - Slvs_hEntity changeNormal(std::shared_ptr theDirX, - std::shared_ptr theNorm); - - /** \brief Adds or updates a parameter in the group - * \param[in] theParam the value of parameter - * \param[in] thePrmIter the cell in the list of parameters which should be changed - * (the iterator will be increased if it does not reach the end of the list) - * \return identifier of changed parameter; when the parameter cannot be created, returned ID is 0 - */ - Slvs_hParam changeParameter(double theParam, - std::vector::iterator& thePrmIter); - - /** \brief Removes specified entities and their parameters - * \param[in] theEntities list of IDs of the entities to be removed - */ - void removeEntitiesById(const std::set& theEntities); - - /** \brief Removes constraints from the group - * \param[in] theConstraint constraint to be removed - */ - void removeConstraint(std::shared_ptr theConstraint); - - /** \brief Change values of attribute by parameters received from SolveSpace solver - * \param[in,out] theAttribute pointer to the attribute to be changed - * \param[in] theEntityID identifier of SolveSpace entity, which contains updated data - * \return \c true if the attribute's value has changed - */ - bool updateAttribute(std::shared_ptr theAttribute, - const Slvs_hEntity& theEntityID); - - /// \brief Update arc of fillet to be less than 180 degree - void updateFilletConstraints(); - - /** \brief Adds a constraint for a point which should not be changed during computations - * \param[in] theEntity the base for the constraint - * \param[in] theAllowToFit this flag shows that the entity may be placed into - * the 'dragged' field of SolveSpace solver, so this entity - * may be changed a little during solution - */ - void addTemporaryConstraintWhereDragged(std::shared_ptr theEntity, - bool theAllowToFit = true); - - /** \brief Remove all temporary constraint after computation finished - * \param[in] theRemoved indexes of constraints to be removed. If empty, all temporary constraints should be deleted - */ - void removeTemporaryConstraints(const std::set& theRemoved = - std::set()); - - private: - /** \brief Creates a workplane from the sketch parameters - * \param[in] theSketch parameters of workplane are the attributes of this sketch - * \return \c true if success, \c false if workplane parameters are not consistent - */ - bool addWorkplane(std::shared_ptr theSketch); - - /** \brief Add the entities of constraint for points coincidence into the appropriate list - * \param[in] thePoint1 identifier of the first point - * \param[in] thePoint2 identifier of the second point - * \return \c true if the points are added successfully, and - * \c false if the constraint is the extra one (should not be created in SolveSpace) - */ - bool addCoincidentPoints(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2); - - /** \brief Verifies and changes parameters of constriant, - * e.g. sign of the distance between line and point - * \param[in,out] theConstraint SolveSpace constraint to be verified - */ - void checkConstraintConsistence(Slvs_Constraint& theConstraint); - - /** \brief Change entities parameters to make them symmetric relating to the mirror line - * \param[in] theBase entity to be mirrored - * \param[in] theMirror a mirrored object - * \param[in] theMirrorLine a mirror line - */ - void makeMirrorEntity(const Slvs_hEntity& theBase, - const Slvs_hEntity& theMirror, - const Slvs_hEntity& theMirrorLine); - - /** \brief Creates/updates mirror constraint for two points - * \param[in] theBasePoint ID of initial point - * \param[in] theMirrorPoint ID of the mirroring point - * \param[in] theMirrorLine ID of the mirror line - * \param[in] thePrevConstr list of previous constraints (the items will be deleted from the list if they are updated) - * \param[in,out] thePrevMirror list of previously mirrored points (the items will be deleted from the list if they are updated) - * \return ID of created/updated constraint - */ - Slvs_hConstraint changeMirrorPoints(const Slvs_hEntity& theBasePoint, - const Slvs_hEntity& theMirrorPoint, - const Slvs_hEntity& theMirrorLine, - std::vector& thePrevConstr, - std::map& thePrevMirror); - - /** \brief Calculates middle point on line or arc - * \param[in] theEntity identifier of line or arc - * \param[out] theX X value of middle point - * \param[out] theY Y value of middle point - */ - void calculateMiddlePoint(const Slvs_hEntity& theEntity, - double& theX, double& theY) const; - - private: - // SolveSpace entities - Slvs_hGroup myID; ///< the index of the group - Slvs_Entity myWorkplane; ///< Workplane for the current group - std::vector myParams; ///< List of parameters of the constraints - Slvs_hParam myParamMaxID; ///< Actual maximal ID of parameters (not equal to myParams size) - std::vector myEntities; ///< List of entities of the constaints - std::vector myEntOfConstr; ///< Flags show that certain entity used in constraints - Slvs_hEntity myEntityMaxID; ///< Actual maximal ID of entities (not equal to myEntities size) - std::vector myConstraints; ///< List of constraints in SolveSpace format - Slvs_hConstraint myConstrMaxID; ///< Actual maximal ID of constraints (not equal to myConstraints size) - bool myNeedToSolve; ///< Indicator that something changed in the group and constraint system need to be rebuilt - - SketchSolver_Solver myConstrSolver; ///< Solver for set of equations obtained by constraints - - std::vector myTempPointWhereDragged; ///< Parameters of one of the points which is moved by user - Slvs_hEntity myTempPointWDrgdID; ///< Identifier of such point - std::list myTempConstraints; ///< The list of identifiers of temporary constraints (SLVS_C_WHERE_DRAGGED) applied for all other points moved by user - - // SketchPlugin entities - std::shared_ptr mySketch; ///< Equivalent to workplane - ConstraintMap myConstraintMap; ///< The map between SketchPlugin and SolveSpace constraints - std::map, Slvs_hEntity> myEntityAttrMap; ///< The map between "attribute" parameters of constraints and their equivalent SolveSpace entities - std::map myEntityFeatMap; ///< The map between "feature" parameters of constraints and their equivalent SolveSpace entities - - // Conincident items - std::vector > myCoincidentPoints; ///< Stores the lists of identifiers of coincident points (to avoid unnecessary coincidence constraints) - std::set > myExtraCoincidence; ///< Additional coincidence constraints which are not necessary (coincidence between points already done - ///< by other constraints) but created by GUI tools. Useful when some coincidence constraints were removed -}; - -#endif diff --git a/src/SketchSolver/SketchSolver_ConstraintManager.cpp b/src/SketchSolver/SketchSolver_ConstraintManager.cpp index bd346fb35..1e80079c9 100644 --- a/src/SketchSolver/SketchSolver_ConstraintManager.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintManager.cpp @@ -5,7 +5,6 @@ // Author: Artem ZHIDKOV #include "SketchSolver_ConstraintManager.h" -#include #include #include @@ -88,7 +87,7 @@ void SketchSolver_ConstraintManager::processEvent( std::shared_ptr aSFeature = std::dynamic_pointer_cast(*aFeatIter); if (aSFeature) - updateEntity(aSFeature); + moveEntity(aSFeature); } } else { std::set::iterator aFeatIter; @@ -138,8 +137,8 @@ void SketchSolver_ConstraintManager::processEvent( break; if (aFGrIter != aFeatureGroups.end()) { - std::vector::iterator aGroupIter = myGroups.begin(); - std::vector aSeparatedGroups; + std::vector::iterator aGroupIter = myGroups.begin(); + std::vector aSeparatedGroups; while (aGroupIter != myGroups.end()) { if (!(*aGroupIter)->isWorkplaneValid()) { // the group should be removed delete *aGroupIter; @@ -148,7 +147,7 @@ void SketchSolver_ConstraintManager::processEvent( aGroupIter = myGroups.begin() + aShift; continue; } - if ((*aGroupIter)->updateGroup()) { // some constraints were removed, try to split the group + if (!(*aGroupIter)->isConsistent()) { // some constraints were removed, try to split the group (*aGroupIter)->splitGroup(aSeparatedGroups); } aGroupIter++; @@ -164,13 +163,12 @@ void SketchSolver_ConstraintManager::processEvent( // Class: SketchSolver_Session // Purpose: update workplane by given parameters of the sketch // ============================================================================ -bool SketchSolver_ConstraintManager::changeWorkplane( - std::shared_ptr theSketch) +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; + std::vector::iterator aGroupIter; for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) if ((*aGroupIter)->isBaseWorkplane(theSketch)) { isUpdated = true; @@ -179,7 +177,7 @@ bool SketchSolver_ConstraintManager::changeWorkplane( } // If the workplane is not updated, so this is a new workplane if (!isUpdated) { - SketchSolver_ConstraintGroup* aNewGroup = new SketchSolver_ConstraintGroup(theSketch); + SketchSolver_Group* aNewGroup = new SketchSolver_Group(theSketch); // Verify that the group is created successfully if (!aNewGroup->isBaseWorkplane(theSketch) || !aNewGroup->isWorkplaneValid()) { delete aNewGroup; @@ -213,7 +211,7 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity( std::shared_ptr aWP = findWorkplane(aConstraint); if (!aWP) return false; - SketchSolver_ConstraintGroup* aGroup = new SketchSolver_ConstraintGroup(aWP); + SketchSolver_Group* aGroup = new SketchSolver_Group(aWP); if (!aGroup->changeConstraint(aConstraint)) { delete aGroup; return false; @@ -222,19 +220,19 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity( return true; } else if (aGroups.size() == 1) { // Only one group => add feature into it Slvs_hGroup aGroupId = *(aGroups.begin()); - std::vector::iterator aGroupIter; + 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)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN; +//// if (!aConstraint && !(*aGroupIter)->isEmpty()) +//// return (*aGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN; 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; + std::vector::iterator aFirstGroupIter; for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++) if ((*aFirstGroupIter)->getId() == *aGroupsIter) break; @@ -242,7 +240,7 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity( return false; // Append other groups to the first one - std::vector::iterator anOtherGroupIter = aFirstGroupIter + 1; + std::vector::iterator anOtherGroupIter = aFirstGroupIter + 1; for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) { for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++) if ((*anOtherGroupIter)->getId() == *aGroupsIter) @@ -263,7 +261,7 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity( if (aConstraint) return (*aFirstGroupIter)->changeConstraint(aConstraint); - return (*aFirstGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN; +//// return (*aFirstGroupIter)->changeEntityFeature(theFeature) != SLVS_E_UNKNOWN; } // Something goes wrong @@ -271,54 +269,59 @@ bool SketchSolver_ConstraintManager::changeConstraintOrEntity( } // ============================================================================ -// Function: updateEntity +// Function: moveEntity // Class: SketchSolver_Session -// Purpose: update any element on the sketch, which is used by constraints +// Purpose: update element moved on the sketch, which is used by constraints // ============================================================================ -void SketchSolver_ConstraintManager::updateEntity( +void SketchSolver_ConstraintManager::moveEntity( std::shared_ptr theFeature) { - // Create list of attributes depending on type of the feature - std::vector anAttrList; - const std::string& aFeatureKind = theFeature->getKind(); - // Point - if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) - anAttrList.push_back(SketchPlugin_Point::COORD_ID()); - // Line - else if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) { - anAttrList.push_back(SketchPlugin_Line::START_ID()); - anAttrList.push_back(SketchPlugin_Line::END_ID()); - } - // Circle - else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) { - anAttrList.push_back(SketchPlugin_Circle::CENTER_ID()); - anAttrList.push_back(SketchPlugin_Circle::RADIUS_ID()); - } - // Arc - else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) { - anAttrList.push_back(SketchPlugin_Arc::CENTER_ID()); - anAttrList.push_back(SketchPlugin_Arc::START_ID()); - anAttrList.push_back(SketchPlugin_Arc::END_ID()); - } - /// \todo Other types of features should be implemented - - // Check changing of feature's attributes (go through the groups and search usage of the attributes) - std::vector::const_iterator anAttrIter; - for (anAttrIter = anAttrList.begin(); anAttrIter != anAttrList.end(); anAttrIter++) { - std::vector::iterator aGroupIter; - for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) { - if ((*aGroupIter)->isEmpty()) - continue; - std::shared_ptr anAttribute = std::dynamic_pointer_cast< - ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter)); - (*aGroupIter)->updateEntityIfPossible(anAttribute); - } - } - - std::vector::iterator aGroupIter; - for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) - if (!(*aGroupIter)->isEmpty()) - (*aGroupIter)->updateRelatedConstraintsFeature(theFeature); + std::vector::iterator aGroupIt = myGroups.begin(); + for (; aGroupIt != myGroups.end(); aGroupIt++) + if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature)) + (*aGroupIt)->moveFeature(theFeature); + +//// // Create list of attributes depending on type of the feature +//// std::vector anAttrList; +//// const std::string& aFeatureKind = theFeature->getKind(); +//// // Point +//// if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) +//// anAttrList.push_back(SketchPlugin_Point::COORD_ID()); +//// // Line +//// else if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) { +//// anAttrList.push_back(SketchPlugin_Line::START_ID()); +//// anAttrList.push_back(SketchPlugin_Line::END_ID()); +//// } +//// // Circle +//// else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) { +//// anAttrList.push_back(SketchPlugin_Circle::CENTER_ID()); +//// anAttrList.push_back(SketchPlugin_Circle::RADIUS_ID()); +//// } +//// // Arc +//// else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) { +//// anAttrList.push_back(SketchPlugin_Arc::CENTER_ID()); +//// anAttrList.push_back(SketchPlugin_Arc::START_ID()); +//// anAttrList.push_back(SketchPlugin_Arc::END_ID()); +//// } +//// /// \todo Other types of features should be implemented +//// +//// // Check changing of feature's attributes (go through the groups and search usage of the attributes) +//// std::vector::const_iterator anAttrIter; +//// for (anAttrIter = anAttrList.begin(); anAttrIter != anAttrList.end(); anAttrIter++) { +//// std::vector::iterator aGroupIter; +//// for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) { +//// if ((*aGroupIter)->isEmpty()) +//// continue; +//// std::shared_ptr anAttribute = std::dynamic_pointer_cast< +//// ModelAPI_Attribute>(theFeature->data()->attribute(*anAttrIter)); +//// (*aGroupIter)->updateEntityIfPossible(anAttribute); +//// } +//// } +//// +//// std::vector::iterator aGroupIter; +//// for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) +//// if (!(*aGroupIter)->isEmpty()) +//// (*aGroupIter)->updateRelatedConstraintsFeature(theFeature); } // ============================================================================ @@ -332,8 +335,8 @@ void SketchSolver_ConstraintManager::findGroups( { std::shared_ptr aWP = findWorkplane(theFeature); - SketchSolver_ConstraintGroup* anEmptyGroup = 0; // appropriate empty group for specified constraint - std::vector::const_iterator aGroupIter; + 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()) @@ -358,7 +361,7 @@ std::shared_ptr SketchSolver_ConstraintManager // Already verified workplanes std::set > aVerified; - std::vector::const_iterator aGroupIter; + 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()) @@ -396,7 +399,7 @@ void SketchSolver_ConstraintManager::resolveConstraints(const bool theForceUpdat Events_Loop::loop()->setFlushed(anUpdateEvent, false); } - std::vector::iterator aGroupIter; + std::vector::iterator aGroupIter; for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) if ((*aGroupIter)->resolveConstraints()) needToUpdate = true; diff --git a/src/SketchSolver/SketchSolver_ConstraintManager.h b/src/SketchSolver/SketchSolver_ConstraintManager.h index f5e148362..a2d7ffaff 100644 --- a/src/SketchSolver/SketchSolver_ConstraintManager.h +++ b/src/SketchSolver/SketchSolver_ConstraintManager.h @@ -9,7 +9,7 @@ #include "SketchSolver.h" #include -#include +#include #include #include @@ -67,7 +67,7 @@ class SketchSolver_ConstraintManager : public Events_Listener * \return \c true if the workplane changed successfully * \remark Type of theSketch is not verified inside */ - bool changeWorkplane(std::shared_ptr theSketch); + bool changeWorkplane(CompositeFeaturePtr theSketch); /** \brief Removes a workplane from the manager. * All groups based on such workplane will be removed too. @@ -76,10 +76,10 @@ class SketchSolver_ConstraintManager : public Events_Listener */ bool removeWorkplane(std::shared_ptr theSketch); - /** \brief Updates entity which is neither workplane nor constraint + /** \brief Updates entity which is moved in GUI * \param[in] theFeature entity to be updated */ - void updateEntity(std::shared_ptr theFeature); + 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 @@ -103,7 +103,7 @@ class SketchSolver_ConstraintManager : public Events_Listener private: static SketchSolver_ConstraintManager* _self; ///< Self pointer to implement singleton functionality - std::vector myGroups; ///< Groups of constraints + 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; diff --git a/src/SketchSolver/SketchSolver_ConstraintRigid.cpp b/src/SketchSolver/SketchSolver_ConstraintRigid.cpp new file mode 100644 index 000000000..02ba819a8 --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintRigid.cpp @@ -0,0 +1,102 @@ +#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); + + Slvs_Constraint aConstraint; + std::vector::iterator aConstrIter = mySlvsConstraints.begin(); + bool isEmpty = aConstrIter == mySlvsConstraints.end(); + std::vector::const_iterator anEntIter = anEntities.begin(); + for (; anEntIter != anEntities.end(); anEntIter++) { + if (isEmpty) { // create new constraint + aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), + aValue, *anEntIter, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); + aConstraint.h = myStorage->addConstraint(aConstraint); + mySlvsConstraints.push_back(aConstraint.h); + if (!myBaseConstraint) + myStorage->addTemporaryConstraint(aConstraint.h); + } else { // update already existent constraint + aConstraint = myStorage->getConstraint(*aConstrIter); + aConstraint.ptA = *anEntIter; + myStorage->addConstraint(aConstraint); + aConstrIter++; + isEmpty = aConstrIter == mySlvsConstraints.end(); + } + } +} + + +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) { + 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); + } + + // 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; + + if (isFullyRemoved) { + myFeatureMap.clear(); + myAttributeMap.clear(); + myValueMap.clear(); + } else + cleanRemovedEntities(); + return true; +} + diff --git a/src/SketchSolver/SketchSolver_ConstraintRigid.h b/src/SketchSolver/SketchSolver_ConstraintRigid.h new file mode 100644 index 000000000..66f581638 --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintRigid.h @@ -0,0 +1,51 @@ +// 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 + */ +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 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); + +protected: + FeaturePtr myBaseFeature; ///< fixed feature (when it is set, myBaseConstraint should be NULL) +}; + +#endif diff --git a/src/SketchSolver/SketchSolver_Error.h b/src/SketchSolver/SketchSolver_Error.h new file mode 100644 index 000000000..0ef01476e --- /dev/null +++ b/src/SketchSolver/SketchSolver_Error.h @@ -0,0 +1,40 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_Error.h +// Created: 29 Mar 2015 +// Author: Artem ZHIDKOV + +#ifndef SketchSolver_Error_H_ +#define SketchSolver_Error_H_ + +#include + +/** \class SketchSolver_Error + * \ingroup Plugins + * \brief Collects all sketch solver error' codes + * as inline static functions + */ +class SketchSolver_Error +{ + public: + /// The value parameter for the constraint + inline static const std::string& CONSTRAINTS() + { + static const std::string MY_ERROR_VALUE("Conflicting constraints"); + return MY_ERROR_VALUE; + } + /// The entities need to have shared point, but they have not + inline static const std::string& NO_COINCIDENT_POINTS() + { + static const std::string MY_ERROR_VALUE("Objects should have coincident point"); + return MY_ERROR_VALUE; + } + /// Attribute of a feature is not initialized + inline static const std::string& NOT_INITIALIZED() + { + static const std::string MY_ERROR_VALUE("Attribute is not initialized"); + return MY_ERROR_VALUE; + } +}; + +#endif diff --git a/src/SketchSolver/SketchSolver_FeatureStorage.cpp b/src/SketchSolver/SketchSolver_FeatureStorage.cpp new file mode 100644 index 000000000..9b8f133f4 --- /dev/null +++ b/src/SketchSolver/SketchSolver_FeatureStorage.cpp @@ -0,0 +1,372 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_FeatureStorage.cpp +// Created: 23 Mar 2015 +// Author: Artem ZHIDKOV + +#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()) { + aFeatIter->second.erase(aCIter); + if (aFeatIter->second.empty()) { + MapFeatureConstraint::iterator aTmpIter = aFeatIter; // stores iterator for the next element, while the current is deleting + aTmpIter++; + myFeatures.erase(aFeatIter); + aFeatIter = aTmpIter; + 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 + + 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); + } + + 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; + + 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()) + 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; + // Check the attributes are valid + MapAttributeFeature::const_iterator aTIter = myAttributes.begin(); + for (; aTIter != myAttributes.end(); aTIter++) + if (!aTIter->first->isInitialized()) + 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; +} + diff --git a/src/SketchSolver/SketchSolver_FeatureStorage.h b/src/SketchSolver/SketchSolver_FeatureStorage.h new file mode 100644 index 000000000..287be5a57 --- /dev/null +++ b/src/SketchSolver/SketchSolver_FeatureStorage.h @@ -0,0 +1,75 @@ +// 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; + +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 new file mode 100644 index 000000000..f5b0ee387 --- /dev/null +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -0,0 +1,2028 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_Group.cpp +// Created: 27 May 2014 +// Author: Artem ZHIDKOV + +#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 + + +/// \brief This class is used to give unique index to the groups +class GroupIndexer +{ +public: + /// \brief Return vacant index + static Slvs_hGroup NEW_GROUP() { return ++myGroupIndex; } + /// \brief Removes the index + static void REMOVE_GROUP(const Slvs_hGroup& theIndex) { + if (myGroupIndex == theIndex) + myGroupIndex--; + } + +private: + GroupIndexer() {}; + + static Slvs_hGroup myGroupIndex; ///< index of the group +}; + +Slvs_hGroup GroupIndexer::myGroupIndex = 0; + + +/** \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); + +// ======================================================== +// ========= SketchSolver_Group =============== +// ======================================================== + +SketchSolver_Group::SketchSolver_Group( + std::shared_ptr theWorkplane) + : myID(GroupIndexer::NEW_GROUP()) +{ + // Initialize workplane + myWorkplaneID = SLVS_E_UNKNOWN; +#ifndef NDEBUG + assert(addWorkplane(theWorkplane)); +#else + addWorkplane(theWorkplane); +#endif +} + +SketchSolver_Group::~SketchSolver_Group() +{ + myConstraints.clear(); + GroupIndexer::REMOVE_GROUP(myID); +} + +// ============================================================================ +// Function: isBaseWorkplane +// Class: SketchSolver_Group +// Purpose: verify the group is based on the given workplane +// ============================================================================ +bool SketchSolver_Group::isBaseWorkplane(CompositeFeaturePtr theWorkplane) const +{ + return theWorkplane == mySketch; +} + +// ============================================================================ +// Function: isInteract +// Class: SketchSolver_Group +// Purpose: verify are there any entities in the group used by given constraint +// ============================================================================ +bool SketchSolver_Group::isInteract( + std::shared_ptr theFeature) const +{ + // Empty group interacts with everything + if (isEmpty()) return true; + ConstraintPtr aConstraint = std::dynamic_pointer_cast(theFeature); + if (aConstraint) + return myFeatureStorage->isInteract(aConstraint); + return myFeatureStorage->isInteract(theFeature); +} + +// ============================================================================ +// 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 +{ + if (!myFeatureStorage) + return SLVS_E_UNKNOWN; + std::set aConstraints = myFeatureStorage->getConstraints(theFeature); + if (aConstraints.empty()) + return SLVS_E_UNKNOWN; + ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstraints.begin()); + if (aCIter == myConstraints.end()) + return SLVS_E_UNKNOWN; + return aCIter->second->getId(theFeature); +} + +// ============================================================================ +// 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 +{ + if (!myFeatureStorage) + return SLVS_E_UNKNOWN; + std::set aConstraints = myFeatureStorage->getConstraints(theAttribute); + if (aConstraints.empty()) + return SLVS_E_UNKNOWN; + ConstraintConstraintMap::const_iterator aCIter = myConstraints.find(*aConstraints.begin()); + if (aCIter == myConstraints.end()) + return SLVS_E_UNKNOWN; + return aCIter->second->getId(theAttribute); +} + + +////// ============================================================================ +////// Function: checkConstraintConsistence +////// Class: SketchSolver_Group +////// Purpose: verifies and changes parameters of the constraint +////// ============================================================================ +////void SketchSolver_Group::checkConstraintConsistence(Slvs_Constraint& theConstraint) +////{ +//// if (theConstraint.type == SLVS_C_PT_LINE_DISTANCE) { +//// // Get constraint parameters and check the sign of constraint value +//// +//// // point coordinates +//// int aPtPos = Search(theConstraint.ptA, myEntities); +//// int aPtParamPos = Search(myEntities[aPtPos].param[0], myParams); +//// std::shared_ptr aPoint( +//// new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val)); +//// +//// // line coordinates +//// int aLnPos = Search(theConstraint.entityA, myEntities); +//// aPtPos = Search(myEntities[aLnPos].point[0], myEntities); +//// aPtParamPos = Search(myEntities[aPtPos].param[0], myParams); +//// std::shared_ptr aStart( +//// new GeomAPI_XY(-myParams[aPtParamPos].val, -myParams[aPtParamPos + 1].val)); +//// aPtPos = Search(myEntities[aLnPos].point[1], myEntities); +//// aPtParamPos = Search(myEntities[aPtPos].param[0], myParams); +//// std::shared_ptr aEnd( +//// new GeomAPI_XY(myParams[aPtParamPos].val, myParams[aPtParamPos + 1].val)); +//// +//// aEnd = aEnd->added(aStart); +//// aPoint = aPoint->added(aStart); +//// if (aPoint->cross(aEnd) * theConstraint.valA < 0.0) +//// theConstraint.valA *= -1.0; +//// } +////} + +// ============================================================================ +// Function: changeConstraint +// Class: SketchSolver_Group +// Purpose: create/update the constraint in the group +// ============================================================================ +bool SketchSolver_Group::changeConstraint( + std::shared_ptr theConstraint) +{ + // There is no workplane yet, something wrong + if (myWorkplaneID == SLVS_E_UNKNOWN) + return false; + + if (!theConstraint) + return false; + + if (myConstraints.find(theConstraint) == myConstraints.end()) { + // Add constraint to the current group + SolverConstraintPtr aConstraint = + SketchSolver_Builder::getInstance()->createConstraint(theConstraint); + if (!aConstraint) + return false; + 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 (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { + 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)) { + aCoincidence->attach(aCoinc2); + aConstraint = aCoincidence; + } + } + } + myConstraints[theConstraint] = aConstraint; + } + else + myConstraints[theConstraint]->update(); + + if (!myFeatureStorage) + myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage); + myFeatureStorage->changeConstraint(theConstraint); + +//// if (theConstraint) { +//// if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID()) +//// return changeRigidConstraint(theConstraint); +//// if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) +//// return changeMirrorConstraint(theConstraint); +//// if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) +//// return changeFilletConstraint(theConstraint); +//// } +//// +//// // Search this constraint in the current group to update it +//// ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint); +//// std::vector::iterator aConstrIter; +//// if (aConstrMapIter != myConstraintMap.end()) { +//// int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints); +//// aConstrIter = myConstraints.begin() + aConstrPos; +//// } +//// +//// // Get constraint type and verify the constraint parameters are correct +//// SketchSolver_Constraint aConstraint(theConstraint); +//// int aConstrType = aConstraint.getType(); +//// if (aConstrType == SLVS_C_UNKNOWN +//// || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType)) +//// return false; +//// const std::vector& aConstraintAttributes = aConstraint.getAttributes(); +//// +//// // Create constraint parameters +//// double aDistance = 0.0; // scalar value of the constraint +//// AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast( +//// theConstraint->data()->attribute(SketchPlugin_Constraint::VALUE())); +//// if (aDistAttr) { +//// aDistance = aDistAttr->value(); +//// // Issue #196: checking the positivity of the distance constraint +//// if (aDistance < tolerance && +//// (aConstrType == SLVS_C_PT_PT_DISTANCE || aConstrType == SLVS_C_PT_LINE_DISTANCE)) +//// return false; +//// // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter +//// if (aConstrType == SLVS_C_DIAMETER) +//// aDistance *= 2.0; +//// if (aConstrMapIter != myConstraintMap.end() +//// && fabs(aConstrIter->valA - aDistance) > tolerance) { +//// myNeedToSolve = true; +//// aConstrIter->valA = aDistance; +//// } +//// } +//// +//// size_t aNbTmpConstraints = myTempConstraints.size(); +//// Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint +//// for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) { +//// aConstrEnt[indAttr] = SLVS_E_UNKNOWN; +//// std::shared_ptr aConstrAttr = std::dynamic_pointer_cast< +//// ModelAPI_AttributeRefAttr>( +//// theConstraint->data()->attribute(aConstraintAttributes[indAttr])); +//// if (!aConstrAttr) +//// continue; +//// +//// // Convert the object of the attribute to the feature +//// FeaturePtr aFeature; +//// if (aConstrAttr->isObject() && aConstrAttr->object()) { +//// ResultConstructionPtr aRC = std::dynamic_pointer_cast( +//// aConstrAttr->object()); +//// if (!aRC) +//// continue; +//// std::shared_ptr aDoc = aRC->document(); +//// aFeature = aDoc->feature(aRC); +//// } +//// +//// // For the length constraint the start and end points of the line should be added to the entities list instead of line +//// if (aConstrType == SLVS_C_PT_PT_DISTANCE +//// && theConstraint->getKind().compare(SketchPlugin_ConstraintLength::ID()) == 0) { +//// Slvs_hEntity aLineEnt = changeEntityFeature(aFeature); +//// int aEntPos = Search(aLineEnt, myEntities); +//// aConstrEnt[indAttr++] = myEntities[aEntPos].point[0]; +//// aConstrEnt[indAttr++] = myEntities[aEntPos].point[1]; +//// while (indAttr < CONSTRAINT_ATTR_SIZE) +//// aConstrEnt[indAttr++] = 0; +//// break; // there should be no other entities +//// } else if (aConstrAttr->isObject()) +//// aConstrEnt[indAttr] = changeEntityFeature(aFeature); +//// else +//// aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr()); +//// } +//// +//// if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint +//// // Several points may be coincident, it is not necessary to store all constraints between them. +//// // Try to find sequence of coincident points which connects the points of new constraint +//// if (aConstrType == SLVS_C_POINTS_COINCIDENT) { +//// if (aConstrEnt[0] == aConstrEnt[1]) // no need to add self coincidence +//// return false; +//// if (!addCoincidentPoints(aConstrEnt[0], aConstrEnt[1])) { +//// myExtraCoincidence.insert(theConstraint); // the constraint is stored for further purposes +//// return false; +//// } +//// if (aNbTmpConstraints < myTempConstraints.size()) { +//// // There was added temporary constraint. Check that there is no coincident points which already rigid. +//// +//// // Get list of already fixed points +//// std::set anAlreadyFixed; +//// std::vector::const_iterator aCIter = myConstraints.begin(); +//// for (; aCIter != myConstraints.end(); aCIter++) +//// if (aCIter->type == SLVS_C_WHERE_DRAGGED) { +//// std::list::const_iterator aTmpIt = myTempConstraints.begin(); +//// for (; aTmpIt != myTempConstraints.end(); aTmpIt++) +//// if (*aTmpIt == aCIter->h) +//// break; +//// if (aTmpIt == myTempConstraints.end()) +//// anAlreadyFixed.insert(aCIter->ptA); +//// } +//// +//// std::set aTmpConstrToDelete; +//// std::list::reverse_iterator aTmpIter = myTempConstraints.rbegin(); +//// size_t aCurSize = myTempConstraints.size(); +//// for (; aCurSize > aNbTmpConstraints && aTmpIter != myTempConstraints.rend(); +//// aTmpIter++, aCurSize--) { +//// int aConstrPos = Search(*aTmpIter, myConstraints); +//// std::vector >::const_iterator +//// aCoincIter = myCoincidentPoints.begin(); +//// for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++) +//// if (aCoincIter->find(myConstraints[aConstrPos].ptA) != aCoincIter->end()) { +//// std::set::const_iterator anIt; +//// for (anIt = aCoincIter->begin(); anIt != aCoincIter->end(); anIt++) +//// if (anAlreadyFixed.find(*anIt) != anAlreadyFixed.end()) { +//// aTmpConstrToDelete.insert(*aTmpIter); +//// break; +//// } +//// break; +//// } +//// } +//// if (!aTmpConstrToDelete.empty()) +//// removeTemporaryConstraints(aTmpConstrToDelete); +//// } +//// } +//// // For the tangency constraints it is necessary to identify which points of entities are coincident +//// int aSlvsOtherFlag = 0; +//// int aSlvsOther2Flag = 0; +//// if (aConstrType == SLVS_C_ARC_LINE_TANGENT || aConstrType == SLVS_C_CURVE_CURVE_TANGENT) { +//// // Search entities used by constraint +//// int anEnt1Pos = Search(aConstrEnt[2], myEntities); +//// int anEnt2Pos = Search(aConstrEnt[3], myEntities); +//// // Obtain start and end points of entities +//// Slvs_hEntity aPointsToFind[4]; +//// aPointsToFind[0] = myEntities[anEnt1Pos].point[1]; +//// aPointsToFind[1]= myEntities[anEnt1Pos].point[2]; +//// bool hasLine = (myEntities[anEnt2Pos].type == SLVS_E_LINE_SEGMENT); +//// aPointsToFind[2]= myEntities[anEnt2Pos].point[hasLine ? 0 : 1]; +//// aPointsToFind[3]= myEntities[anEnt2Pos].point[hasLine ? 1 : 2]; +//// // Search coincident points +//// bool isPointFound[4]; +//// std::vector >::const_iterator aCPIter = myCoincidentPoints.begin(); +//// for ( ; aCPIter != myCoincidentPoints.end(); aCPIter++) { +//// for (int i = 0; i < 4; i++) +//// isPointFound[i] = (aCPIter->find(aPointsToFind[i]) != aCPIter->end()); +//// if ((isPointFound[0] || isPointFound[1]) && (isPointFound[2] || isPointFound[3])) { +//// // the arc is tangent by end point +//// if (isPointFound[1]) aSlvsOtherFlag = 1; +//// // the second item is an arc and it is tangent by end point too +//// if (!hasLine && isPointFound[3]) aSlvsOther2Flag = 1; +//// break; +//// } +//// } +//// if (aCPIter == myCoincidentPoints.end()) { +//// // There is no coincident points between tangential objects. Generate error message +//// Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this); +//// return false; +//// } +//// } +//// +//// // Create SolveSpace constraint structure +//// Slvs_Constraint aSlvsConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, +//// myWorkplane.h, aDistance, aConstrEnt[0], +//// aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]); +//// if (aSlvsOtherFlag != 0) aSlvsConstr.other = aSlvsOtherFlag; +//// if (aSlvsOther2Flag != 0) aSlvsConstr.other2 = aSlvsOther2Flag; +//// myConstraints.push_back(aSlvsConstr); +//// myConstraintMap[theConstraint] = std::vector(1, aSlvsConstr.h); +//// int aConstrPos = Search(aSlvsConstr.h, myConstraints); +//// aConstrIter = myConstraints.begin() + aConstrPos; +//// myNeedToSolve = true; +//// } else { // Attributes of constraint may be changed => update constraint +//// Slvs_hEntity* aCurrentAttr[] = {&aConstrIter->ptA, &aConstrIter->ptB, +//// &aConstrIter->entityA, &aConstrIter->entityB, +//// &aConstrIter->entityC, &aConstrIter->entityD}; +//// for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) { +//// if (*(aCurrentAttr[indAttr]) != aConstrEnt[indAttr]) +//// { +//// *(aCurrentAttr[indAttr]) = aConstrEnt[indAttr]; +//// myNeedToSolve = true; +//// } +//// } +//// } +//// +//// // Update flags of entities to be used by constraints +//// for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) +//// if (aConstrEnt[indAttr] != 0) { +//// int aPos = Search(aConstrEnt[indAttr], myEntities); +//// myEntOfConstr[aPos] = true; +//// // Sub-entities should be used implcitly +//// Slvs_hEntity* aEntPtr = myEntities[aPos].point; +//// while (*aEntPtr != 0) { +//// aPos = Search(*aEntPtr, myEntities); +//// myEntOfConstr[aPos] = true; +//// aEntPtr++; +//// } +//// } +//// +//// checkConstraintConsistence(*aConstrIter); + return true; +} + +void SketchSolver_Group::moveFeature(std::shared_ptr theFeature) +{ + std::set aConstraints = myFeatureStorage->getConstraints(theFeature); + std::set::iterator aCIter = aConstraints.begin(); + for (; aCIter != aConstraints.end(); aCIter++) { + ConstraintConstraintMap::iterator aSolConIter = myConstraints.find(*aCIter); + aSolConIter->second->update(); + } + + // Temporary rigid constraint + SolverConstraintPtr aConstraint = + SketchSolver_Builder::getInstance()->createRigidConstraint(theFeature); + if (!aConstraint) + return; + aConstraint->setGroup(this); + aConstraint->setStorage(myStorage); + myTempConstraints.insert(aConstraint); +} + +////// ============================================================================ +////// Function: changeRigidConstraint +////// Class: SketchSolver_Group +////// Purpose: create/update the "Rigid" constraint in the group +////// ============================================================================ +////bool SketchSolver_Group::changeRigidConstraint( +//// std::shared_ptr theConstraint) +////{ +//// // Search this constraint in the current group to update it +//// ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint); +//// std::vector::iterator aConstrIter; +//// if (aConstrMapIter != myConstraintMap.end()) { +//// int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints); +//// aConstrIter = myConstraints.begin() + aConstrPos; +//// } +//// +//// // Get constraint type and verify the constraint parameters are correct +//// SketchSolver_Constraint aConstraint(theConstraint); +//// int aConstrType = aConstraint.getType(); +//// if (aConstrType == SLVS_C_UNKNOWN +//// || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType)) +//// return false; +//// const std::vector& aConstraintAttributes = aConstraint.getAttributes(); +//// +//// Slvs_hEntity aConstrEnt = SLVS_E_UNKNOWN; +//// std::shared_ptr aConstrAttr = std::dynamic_pointer_cast< +//// ModelAPI_AttributeRefAttr>( +//// theConstraint->data()->attribute(aConstraintAttributes[0])); +//// if (!aConstrAttr) +//// return false; +//// +//// // Convert the object of the attribute to the feature +//// FeaturePtr aFeature; +//// if (aConstrAttr->isObject() && aConstrAttr->object()) { +//// ResultConstructionPtr aRC = std::dynamic_pointer_cast( +//// aConstrAttr->object()); +//// if (!aRC) +//// return false; +//// std::shared_ptr aDoc = aRC->document(); +//// aFeature = aDoc->feature(aRC); +//// } +//// +//// aConstrEnt = aConstrAttr->isObject() ? changeEntityFeature(aFeature) : changeEntity(aConstrAttr->attr()); +//// +//// if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint +//// // Check the fixed entity is not a point. +//// std::shared_ptr aConstrAttr = std::dynamic_pointer_cast< +//// ModelAPI_AttributeRefAttr>(theConstraint->data()->attribute(aConstraintAttributes[0])); +//// std::shared_ptr aPoint = +//// std::dynamic_pointer_cast(aConstrAttr->attr()); +//// std::shared_ptr aPoint2D = +//// std::dynamic_pointer_cast(aConstrAttr->attr()); +//// if (aPoint || aPoint2D) { +//// // Create SolveSpace constraint structure +//// Slvs_Constraint aConstraint = Slvs_MakeConstraint( +//// ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0, +//// aConstrEnt, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); +//// myConstraints.push_back(aConstraint); +//// myConstraintMap[theConstraint] = std::vector(1, aConstraint.h); +//// int aConstrPos = Search(aConstraint.h, myConstraints); +//// aConstrIter = myConstraints.begin() + aConstrPos; +//// myNeedToSolve = true; +//// } else { +//// myConstraintMap[theConstraint] = std::vector(); +//// +//// // To avoid SolveSpace problems: +//// // * if the circle is rigid, we will fix its center and radius; +//// // * if the arc is rigid, we will fix its start and end points and radius. +//// double aRadius = 0.0; +//// bool isArc = false; +//// bool isCircle = false; +//// if (aFeature) { +//// if (aFeature->getKind() == SketchPlugin_Arc::ID()) { +//// std::shared_ptr aCenter = +//// std::dynamic_pointer_cast( +//// aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID())); +//// std::shared_ptr aStart = +//// std::dynamic_pointer_cast( +//// aFeature->data()->attribute(SketchPlugin_Arc::START_ID())); +//// aRadius = aStart->pnt()->distance(aCenter->pnt()); +//// isArc = true; +//// } else if (aFeature->getKind() == SketchPlugin_Circle::ID()) { +//// aRadius = std::dynamic_pointer_cast( +//// aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()))->value(); +//// isCircle = true; +//// } +//// } +//// +//// // Get list of already fixed points +//// std::set anAlreadyFixed; +//// std::vector::const_iterator aCIter = myConstraints.begin(); +//// for (; aCIter != myConstraints.end(); aCIter++) +//// if (aCIter->type == SLVS_C_WHERE_DRAGGED) +//// anAlreadyFixed.insert(aCIter->ptA); +//// +//// // Create constraints to fix the parameters of the entity +//// int aEntPos = Search(aConstrEnt, myEntities); +//// Slvs_hEntity* aPointsPtr = myEntities[aEntPos].point; +//// if (isArc) aPointsPtr++; // avoid to fix center of arc +//// while (*aPointsPtr != 0) { +//// // Avoid to create additional "Rigid" constraints for coincident points +//// bool isCoincAlreadyFixed = false; +//// if (!anAlreadyFixed.empty()) { +//// if (anAlreadyFixed.find(*aPointsPtr) != anAlreadyFixed.end()) +//// isCoincAlreadyFixed = true; +//// +//// std::vector >::const_iterator aCoincIter = +//// myCoincidentPoints.begin(); +//// for (; !isCoincAlreadyFixed && aCoincIter != myCoincidentPoints.end(); aCoincIter++) { +//// if (aCoincIter->find(*aPointsPtr) == aCoincIter->end()) +//// continue; +//// std::set::const_iterator anIter = anAlreadyFixed.begin(); +//// for (; !isCoincAlreadyFixed && anIter != anAlreadyFixed.end(); anIter++) +//// if (aCoincIter->find(*anIter) != aCoincIter->end()) +//// isCoincAlreadyFixed = true; +//// } +//// } +//// +//// if (!isCoincAlreadyFixed) { +//// Slvs_Constraint aConstraint = Slvs_MakeConstraint( +//// ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0, +//// *aPointsPtr, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); +//// myConstraints.push_back(aConstraint); +//// myConstraintMap[theConstraint].push_back(aConstraint.h); +//// } +//// aPointsPtr++; +//// } +//// +//// if (isArc || isCircle) { // add radius constraint +//// Slvs_Constraint aConstraint = Slvs_MakeConstraint( +//// ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, 2.0 * aRadius, +//// SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aConstrEnt, SLVS_E_UNKNOWN); +//// myConstraints.push_back(aConstraint); +//// myConstraintMap[theConstraint].push_back(aConstraint.h); +//// } +//// +//// // The object is already rigid, so there is no constraints added +//// if (myConstraintMap[theConstraint].empty()) { +//// myConstraintMap.erase(theConstraint); +//// myNeedToSolve = false; +//// } +//// else +//// myNeedToSolve = true; +//// } +//// } +//// return true; +////} +//// +////// ============================================================================ +////// Function: changeMirrorConstraint +////// Class: SketchSolver_Group +////// Purpose: create/update the "Mirror" constraint in the group +////// ============================================================================ +////bool SketchSolver_Group::changeMirrorConstraint( +//// std::shared_ptr theConstraint) +////{ +//// DataPtr aConstrData = theConstraint->data(); +//// +//// // Search this constraint in the current group to update it +//// ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint); +//// std::vector::iterator aConstrIter; +//// if (aConstrMapIter != myConstraintMap.end()) { +//// int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints); +//// aConstrIter = myConstraints.begin() + aConstrPos; +//// } +//// +//// // Get constraint type and verify the constraint parameters are correct +//// SketchSolver_Constraint aConstraint(theConstraint); +//// int aConstrType = aConstraint.getType(); +//// if (aConstrType == SLVS_C_UNKNOWN +//// || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType)) +//// return false; +//// const std::vector& aConstraintAttributes = aConstraint.getAttributes(); +//// +//// Slvs_hEntity aMirrorLineEnt = SLVS_E_UNKNOWN; +//// AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast( +//// aConstrData->attribute(aConstraintAttributes[0])); +//// if (!aConstrAttr) +//// return false; +//// +//// // Convert the object of the attribute to the feature +//// FeaturePtr aMirrorLineFeat; +//// if (aConstrAttr->isObject() && aConstrAttr->object()) { +//// ResultConstructionPtr aRC = std::dynamic_pointer_cast( +//// aConstrAttr->object()); +//// if (!aRC) +//// return false; +//// std::shared_ptr aDoc = aRC->document(); +//// aMirrorLineFeat = aDoc->feature(aRC); +//// } +//// aMirrorLineEnt = aConstrAttr->isObject() ? +//// changeEntityFeature(aMirrorLineFeat) : changeEntity(aConstrAttr->attr()); +//// +//// if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint +//// // Append symmetric constraint for each point of mirroring features +//// AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast( +//// aConstrData->attribute(aConstraintAttributes[1])); +//// AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast( +//// aConstrData->attribute(aConstraintAttributes[2])); +//// if (!aBaseRefList || !aMirroredRefList) +//// return false; +//// +//// std::list aBaseList = aBaseRefList->list(); +//// std::list aMirroredList = aMirroredRefList->list(); +//// if (aBaseList.size() != aMirroredList.size()) +//// return false; +//// +//// myConstraintMap[theConstraint] = std::vector(); +//// +//// FeaturePtr aBaseFeature, aMirrorFeature; +//// ResultConstructionPtr aRC; +//// std::list::iterator aBaseIter = aBaseList.begin(); +//// std::list::iterator aMirIter = aMirroredList.begin(); +//// for ( ; aBaseIter != aBaseList.end(); aBaseIter++, aMirIter++) { +//// aRC = std::dynamic_pointer_cast(*aBaseIter); +//// aBaseFeature = aRC ? aRC->document()->feature(aRC) : +//// std::dynamic_pointer_cast(*aBaseIter); +//// aRC = std::dynamic_pointer_cast(*aMirIter); +//// aMirrorFeature = aRC ? aRC->document()->feature(aRC) : +//// std::dynamic_pointer_cast(*aMirIter); +//// +//// if (!aBaseFeature || !aMirrorFeature || +//// aBaseFeature->getKind() != aMirrorFeature->getKind()) +//// return false; +//// Slvs_hEntity aBaseEnt = changeEntityFeature(aBaseFeature); +//// Slvs_hEntity aMirrorEnt = changeEntityFeature(aMirrorFeature); +//// // Make aMirrorEnt parameters to be symmetric with aBaseEnt +//// makeMirrorEntity(aBaseEnt, aMirrorEnt, aMirrorLineEnt); +//// +//// if (aBaseFeature->getKind() == SketchPlugin_Point::ID()) { +//// Slvs_Constraint aConstraint = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, +//// myWorkplane.h, 0.0, aBaseEnt, aMirrorEnt, aMirrorLineEnt, SLVS_E_UNKNOWN); +//// myConstraints.push_back(aConstraint); +//// myConstraintMap[theConstraint].push_back(aConstraint.h); +//// } else { +//// int aBasePos = Search(aBaseEnt, myEntities); +//// int aMirrorPos = Search(aMirrorEnt, myEntities); +//// if (aBaseFeature->getKind() == SketchPlugin_Line::ID()) { +//// for (int ind = 0; ind < 2; ind++) { +//// Slvs_Constraint aConstraint = Slvs_MakeConstraint( +//// ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0, +//// myEntities[aBasePos].point[ind], myEntities[aMirrorPos].point[ind], +//// aMirrorLineEnt, SLVS_E_UNKNOWN); +//// myConstraints.push_back(aConstraint); +//// myConstraintMap[theConstraint].push_back(aConstraint.h); +//// } +//// } else if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) { +//// Slvs_Constraint aConstraint = Slvs_MakeConstraint( +//// ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0, +//// myEntities[aBasePos].point[0], myEntities[aMirrorPos].point[0], +//// aMirrorLineEnt, SLVS_E_UNKNOWN); +//// myConstraints.push_back(aConstraint); +//// myConstraintMap[theConstraint].push_back(aConstraint.h); +//// // Additional constraint for equal radii +//// Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint( +//// ++myConstrMaxID, myID, SLVS_C_EQUAL_RADIUS, myWorkplane.h, 0.0, +//// SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseEnt, aMirrorEnt); +//// myConstraints.push_back(anEqRadConstr); +//// myConstraintMap[theConstraint].push_back(anEqRadConstr.h); +//// } else if (aBaseFeature->getKind() == SketchPlugin_Arc::ID()) { +//// // 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] = { +//// myEntities[aBasePos].point[1], +//// myEntities[aBasePos].point[2], +//// SLVS_E_UNKNOWN}; +//// Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point +//// myEntities[aMirrorPos].point[2], +//// myEntities[aMirrorPos].point[1], +//// SLVS_E_UNKNOWN}; +//// Slvs_hEntity aBothArcs[2] = {aBaseEnt, aMirrorEnt}; +//// Slvs_hEntity aBothMiddlePoints[2]; +//// for (int i = 0; i < 2; i++) { +//// double x, y; +//// calculateMiddlePoint(aBothArcs[i], x, y); +//// std::vector::iterator aParamIter = myParams.end(); +//// Slvs_hParam u = changeParameter(x, aParamIter); +//// Slvs_hParam v = changeParameter(y, aParamIter); +//// Slvs_Entity aPoint = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, u, v); +//// myEntities.push_back(aPoint); +//// aBothMiddlePoints[i] = aPoint.h; +//// // additional constraint point-on-curve +//// Slvs_Constraint aPonCircConstr = Slvs_MakeConstraint( +//// ++myConstrMaxID, myID, SLVS_C_PT_ON_CIRCLE, myWorkplane.h, 0.0, +//// aPoint.h, SLVS_E_UNKNOWN, aBothArcs[i], SLVS_E_UNKNOWN); +//// myConstraints.push_back(aPonCircConstr); +//// myConstraintMap[theConstraint].push_back(aPonCircConstr.h); +//// } +//// +//// aBaseArcPoints[2] = aBothMiddlePoints[0]; +//// aMirrorArcPoints[2] = aBothMiddlePoints[1]; +//// for (int ind = 0; ind < 3; ind++) { +//// Slvs_Constraint aConstraint = Slvs_MakeConstraint( +//// ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0, +//// aBaseArcPoints[ind], aMirrorArcPoints[ind], aMirrorLineEnt, SLVS_E_UNKNOWN); +//// myConstraints.push_back(aConstraint); +//// myConstraintMap[theConstraint].push_back(aConstraint.h); +//// } +//// } +//// } +//// } +//// +//// // Set the mirror line unchanged during constraint recalculation +//// int aMirrorLinePos = Search(aMirrorLineEnt, myEntities); +//// Slvs_Constraint aRigidStart = Slvs_MakeConstraint( +//// ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0, +//// myEntities[aMirrorLinePos].point[0], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); +//// myConstraints.push_back(aRigidStart); +//// myConstraintMap[theConstraint].push_back(aRigidStart.h); +//// Slvs_Constraint aRigidEnd = Slvs_MakeConstraint( +//// ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0, +//// myEntities[aMirrorLinePos].point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); +//// myConstraints.push_back(aRigidEnd); +//// myConstraintMap[theConstraint].push_back(aRigidEnd.h); +//// +//// // Add temporary constraints for initial objects to be unchanged +//// for (aBaseIter = aBaseList.begin(); aBaseIter != aBaseList.end(); aBaseIter++) { +//// aRC = std::dynamic_pointer_cast(*aBaseIter); +//// aBaseFeature = aRC ? aRC->document()->feature(aRC) : +//// std::dynamic_pointer_cast(*aBaseIter); +//// if (!aBaseFeature) continue; +//// std::list aPoints = aBaseFeature->data()->attributes(GeomDataAPI_Point2D::type()); +//// std::list::iterator anIt = aPoints.begin(); +//// for ( ; anIt != aPoints.end(); anIt++) { +//// // Arcs are fixed by center and start points only (to avoid solving errors in SolveSpace) +//// if (aBaseFeature->getKind() == SketchPlugin_Arc::ID() && +//// (*anIt)->id() == SketchPlugin_Arc::END_ID()) +//// continue; +//// addTemporaryConstraintWhereDragged(*anIt); +//// } +//// } +//// } +//// return true; +////} +//// +////// ============================================================================ +////// Function: changeFilletConstraint +////// Class: SketchSolver_Group +////// Purpose: create/update the "Fillet" constraint in the group +////// ============================================================================ +////bool SketchSolver_Group::changeFilletConstraint( +//// std::shared_ptr theConstraint) +////{ +//// DataPtr aConstrData = theConstraint->data(); +//// +//// // Search this constraint in the current group to update it +//// ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint); +//// std::vector::iterator aConstrIter; +//// if (aConstrMapIter != myConstraintMap.end()) { +//// int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints); +//// aConstrIter = myConstraints.begin() + aConstrPos; +//// } +//// +//// // Get constraint type and verify the constraint parameters are correct +//// SketchSolver_Constraint aConstraint(theConstraint); +//// int aConstrType = aConstraint.getType(); +//// if (aConstrType == SLVS_C_UNKNOWN) +//// return false; +//// const std::vector& aConstraintAttributes = aConstraint.getAttributes(); +//// +//// // Obtain hEntity for basic objects of fillet +//// Slvs_hEntity aBaseObject[2]; +//// FeaturePtr aBaseFeature[2]; +//// for (unsigned int indAttr = 0; indAttr < 2; indAttr++) { +//// AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast( +//// aConstrData->attribute(aConstraintAttributes[indAttr])); +//// if (!aConstrAttr) +//// return false; +//// if (aConstrAttr->isObject() && aConstrAttr->object()) { +//// ResultConstructionPtr aRC = std::dynamic_pointer_cast( +//// aConstrAttr->object()); +//// if (!aRC) +//// return false; +//// std::shared_ptr aDoc = aRC->document(); +//// aBaseFeature[indAttr] = aDoc->feature(aRC); +//// } +//// aBaseObject[indAttr] = aConstrAttr->isObject() ? +//// changeEntityFeature(aBaseFeature[indAttr]) : changeEntity(aConstrAttr->attr()); +//// } +//// // Check the base entities have a coincident point +//// int aBaseObjInd[2] = { +//// Search(aBaseObject[0], myEntities), +//// Search(aBaseObject[1], myEntities) +//// }; +//// int aShift[2] = { // shift for calculating correct start and end points for different types of objects +//// myEntities[aBaseObjInd[0]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0, +//// myEntities[aBaseObjInd[1]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0, +//// }; +//// Slvs_hEntity aFirstObjPoints[2] = { // indices of start and end point of first object +//// myEntities[aBaseObjInd[0]].point[aShift[0]], +//// myEntities[aBaseObjInd[0]].point[1+aShift[0]] +//// }; +//// Slvs_hEntity aSecondObjPoints[2] = { // indices of start and end point of second object +//// myEntities[aBaseObjInd[1]].point[aShift[1]], +//// myEntities[aBaseObjInd[1]].point[1+aShift[1]] +//// }; +//// bool isCoincidentFound = false; +//// int aBaseCoincInd[2] = {0, 0}; // indices in aFirstObjPoint and aSecondObjPoint identifying coincident points +//// std::vector >::iterator aCPIter = myCoincidentPoints.begin(); +//// for ( ; aCPIter != myCoincidentPoints.end() && !isCoincidentFound; aCPIter++) +//// for (int ind1 = 0; ind1 < 2 && !isCoincidentFound; ind1++) +//// for (int ind2 = 0; ind2 < 2 && !isCoincidentFound; ind2++) +//// if (aCPIter->find(aFirstObjPoints[ind1]) != aCPIter->end() && +//// aCPIter->find(aSecondObjPoints[ind2]) != aCPIter->end()) { +//// aBaseCoincInd[0] = ind1; +//// aBaseCoincInd[1] = ind2; +//// isCoincidentFound = true; +//// } +//// if (!isCoincidentFound) { +//// // There is no coincident points between objects. Generate error message +//// Events_Error::send(SketchSolver_Error::NO_COINCIDENT_POINTS(), this); +//// return false; +//// } +//// +//// // Create fillet entities +//// // - first object is placed on the first base +//// // - second object is on the second base +//// // - third object is a filleting arc +//// static const int aNbFilletEnt = 3; +//// Slvs_hEntity aFilletEnt[aNbFilletEnt]; +//// int aFilletObjInd[aNbFilletEnt]; +//// AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast( +//// aConstrData->attribute(aConstraintAttributes[2])); +//// if (!aFilletRefList) +//// return false; +//// std::list aFilletList = aFilletRefList->list(); +//// if (aFilletList.size() < aNbFilletEnt) +//// return false; +//// FeaturePtr aFilletFeature; +//// ResultConstructionPtr aRC; +//// 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) +//// return false; +//// aFilletEnt[indEnt] = changeEntityFeature(aFilletFeature); +//// aFilletObjInd[indEnt] = Search(aFilletEnt[indEnt], myEntities); +//// } +//// // At first time, for correct result, move floating points of fillet on the middle points of base objects +//// if (myConstraintMap.find(theConstraint) == myConstraintMap.end()) { +//// double anArcPoints[6]; +//// for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) { +//// int anIndShift = myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0; +//// int aPointsPos[2] = { +//// Search(myEntities[aFilletObjInd[indEnt]].point[anIndShift], myEntities), +//// Search(myEntities[aFilletObjInd[indEnt]].point[1+anIndShift], myEntities) +//// }; +//// int aParamPos[2] = { +//// Search(myEntities[aPointsPos[0]].param[0], myParams), +//// Search(myEntities[aPointsPos[1]].param[0], myParams) +//// }; +//// int anIndex = aParamPos[aBaseCoincInd[indEnt]]; +//// if (anIndShift == 0) { +//// myParams[anIndex].val = +//// 0.5 * (myParams[aParamPos[0]].val + myParams[aParamPos[1]].val); +//// myParams[1 + anIndex].val = +//// 0.5 * (myParams[1 + aParamPos[0]].val + myParams[1 + aParamPos[1]].val); +//// } else { // place the changed point on the arc +//// double x = 0, y = 0; +//// calculateMiddlePoint(aFilletEnt[indEnt], x, y); +//// myParams[anIndex].val = x; +//// myParams[1 + anIndex].val = y; +//// } +//// anArcPoints[indEnt*2+2] = myParams[anIndex].val; +//// anArcPoints[indEnt*2+3] = myParams[1 + anIndex].val; +//// } +//// anArcPoints[0] = 0.5 * (anArcPoints[2] + anArcPoints[4]); +//// anArcPoints[1] = 0.5 * (anArcPoints[3] + anArcPoints[5]); +//// for (int indArcPt = 0; indArcPt < 3; indArcPt++) { +//// int aPtPos = Search(myEntities[aFilletObjInd[2]].point[indArcPt], myEntities); +//// int aParamPos = Search(myEntities[aPtPos].param[0], myParams); +//// myParams[aParamPos].val = anArcPoints[indArcPt * 2]; +//// myParams[aParamPos + 1].val = anArcPoints[indArcPt * 2 + 1]; +//// } +//// } +//// +//// // Check the fillet arc which point to be connected to +//// bool isArcInversed = false; // indicates that start and end points of arc should be connected to second and first object respectively +//// Slvs_hEntity hEnt = myEntities[aFilletObjInd[2]].point[1]; +//// int aPos = Search(hEnt, myEntities); +//// Slvs_hParam anArcStartPoint = myEntities[aPos].param[0]; +//// aPos = Search(anArcStartPoint, myParams); +//// double anArcPtCoord[2] = {myParams[aPos].val, myParams[aPos+1].val}; +//// double aSqDistances[2]; +//// int aPtInd; +//// for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) { +//// aPtInd = aBaseCoincInd[indEnt]+aShift[indEnt]; +//// hEnt = myEntities[aFilletObjInd[indEnt]].point[aPtInd]; +//// aPos = Search(hEnt, myEntities); +//// Slvs_hParam anObjectPoint = myEntities[aPos].param[0]; +//// aPos = Search(anObjectPoint, myParams); +//// double aPtCoord[2] = {myParams[aPos].val, myParams[aPos+1].val}; +//// aSqDistances[indEnt] = +//// (anArcPtCoord[0] - aPtCoord[0]) * (anArcPtCoord[0] - aPtCoord[0]) + +//// (anArcPtCoord[1] - aPtCoord[1]) * (anArcPtCoord[1] - aPtCoord[1]); +//// } +//// if (aSqDistances[1] < aSqDistances[0]) +//// isArcInversed = true; +//// +//// // Create list of constraints to generate fillet +//// std::vector aConstrList; +//// bool isExists = myConstraintMap.find(theConstraint) != myConstraintMap.end(); // constraint already exists +//// std::vector::iterator aCMapIter = +//// isExists ? myConstraintMap[theConstraint].begin() : aConstrList.begin(); +//// int aCurConstrPos = isExists ? Search(*aCMapIter, myConstraints) : 0; +//// for (int indEnt = 0; indEnt < aNbFilletEnt - 1; indEnt++) { +//// // one point of fillet object should be coincident with the point on base, non-coincident with another base object +//// aPtInd = 1-aBaseCoincInd[indEnt]+aShift[indEnt]; // (1-aBaseCoincInd[indEnt]) = index of non-coincident point, aShift is used to process all types of shapes +//// Slvs_hEntity aPtBase = myEntities[aBaseObjInd[indEnt]].point[aPtInd]; +//// Slvs_hEntity aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd]; +//// if (isExists) { +//// myConstraints[aCurConstrPos].ptA = aPtBase; +//// myConstraints[aCurConstrPos].ptB = aPtFillet; +//// aCMapIter++; +//// aCurConstrPos = Search(*aCMapIter, myConstraints); +//// } else { +//// Slvs_Constraint aCoincConstr = Slvs_MakeConstraint( +//// ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h, +//// 0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); +//// myConstraints.push_back(aCoincConstr); +//// aConstrList.push_back(aCoincConstr.h); +//// } +//// +//// // another point of fillet object should be placed on the base object +//// Slvs_Constraint aPonCurveConstr; +//// int aTangentType; +//// if (myEntities[aFilletObjInd[indEnt]].type == SLVS_E_ARC_OF_CIRCLE) { +//// // centers of arcs should be coincident +//// aPtBase = myEntities[aBaseObjInd[indEnt]].point[0]; +//// aPtFillet = myEntities[aFilletObjInd[indEnt]].point[0]; +//// if (isExists) { +//// myConstraints[aCurConstrPos].ptA = aPtBase; +//// myConstraints[aCurConstrPos].ptB = aPtFillet; +//// aCMapIter++; +//// aCurConstrPos = Search(*aCMapIter, myConstraints); +//// } else { +//// aPonCurveConstr = Slvs_MakeConstraint( +//// ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h, +//// 0, aPtBase, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); +//// } +//// aPtFillet = myEntities[aFilletObjInd[indEnt]].point[1+aBaseCoincInd[indEnt]]; // !!! will be used below +//// aTangentType = SLVS_C_CURVE_CURVE_TANGENT; +//// } else { +//// aPtInd = aBaseCoincInd[indEnt]; +//// aPtFillet = myEntities[aFilletObjInd[indEnt]].point[aPtInd]; +//// if (isExists) { +//// myConstraints[aCurConstrPos].ptA = aPtFillet; +//// aCMapIter++; +//// aCurConstrPos = Search(*aCMapIter, myConstraints); +//// } else { +//// aPonCurveConstr = Slvs_MakeConstraint( +//// ++myConstrMaxID, myID, SLVS_C_PT_ON_LINE, myWorkplane.h, +//// 0, aPtFillet, SLVS_E_UNKNOWN, aBaseObject[indEnt], SLVS_E_UNKNOWN); +//// } +//// aTangentType = SLVS_C_ARC_LINE_TANGENT; +//// } +//// if (!isExists) { +//// myConstraints.push_back(aPonCurveConstr); +//// aConstrList.push_back(aPonCurveConstr.h); +//// } +//// +//// // Bound point of fillet arc should be tangently coincident with a bound point of fillet object +//// aPtInd = 1 + (isArcInversed ? 1-indEnt : indEnt); +//// Slvs_hEntity aPtArc = myEntities[aFilletObjInd[2]].point[aPtInd]; +//// if (isExists) { +//// myConstraints[aCurConstrPos].ptA = aPtArc; +//// myConstraints[aCurConstrPos].ptB = aPtFillet; +//// aCMapIter++; +//// aCurConstrPos = Search(*aCMapIter, myConstraints); +//// myConstraints[aCurConstrPos].entityA = aFilletEnt[2]; +//// myConstraints[aCurConstrPos].entityB = aFilletEnt[indEnt]; +//// myConstraints[aCurConstrPos].other = (isArcInversed ? 1-indEnt : indEnt); +//// aCMapIter++; +//// aCurConstrPos = Search(*aCMapIter, myConstraints); +//// } else { +//// Slvs_Constraint aCoincConstr = Slvs_MakeConstraint( +//// ++myConstrMaxID, myID, SLVS_C_POINTS_COINCIDENT, myWorkplane.h, +//// 0, aPtArc, aPtFillet, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); +//// myConstraints.push_back(aCoincConstr); +//// aConstrList.push_back(aCoincConstr.h); +//// Slvs_Constraint aTangency = Slvs_MakeConstraint( +//// ++myConstrMaxID, myID, aTangentType, myWorkplane.h, +//// 0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aFilletEnt[2], aFilletEnt[indEnt]); +//// aTangency.other = (isArcInversed ? 1-indEnt : indEnt); +//// aTangency.other2 = aTangentType == SLVS_C_CURVE_CURVE_TANGENT ? aBaseCoincInd[indEnt] : 0; +//// myConstraints.push_back(aTangency); +//// aConstrList.push_back(aTangency.h); +//// } +//// } +//// +//// // Additional constraint for fillet diameter +//// double aRadius = 0.0; // scalar value of the constraint +//// AttributeDoublePtr aDistAttr = std::dynamic_pointer_cast( +//// aConstrData->attribute(SketchPlugin_Constraint::VALUE())); +//// aRadius = aDistAttr->value(); +//// if (isExists) { +//// myConstraints[aCurConstrPos].entityA = aFilletEnt[2]; +//// myConstraints[aCurConstrPos].valA = aRadius * 2.0; +//// aCMapIter++; +//// } else { +//// Slvs_Constraint aDiamConstr = Slvs_MakeConstraint( +//// ++myConstrMaxID, myID, SLVS_C_DIAMETER, myWorkplane.h, aRadius * 2.0, +//// SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aFilletEnt[2], SLVS_E_UNKNOWN); +//// myConstraints.push_back(aDiamConstr); +//// aConstrList.push_back(aDiamConstr.h); +//// +//// myConstraintMap[theConstraint] = aConstrList; +//// } +//// +//// // Additional temporary constraints for base objects to be fixed +//// for (unsigned int indAttr = 0; indAttr < 2; indAttr++) { +//// if (!aBaseFeature[indAttr]) { +//// AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast( +//// aConstrData->attribute(aConstraintAttributes[indAttr])); +//// addTemporaryConstraintWhereDragged(aConstrAttr->attr()); +//// continue; +//// } +//// std::list anAttributes = +//// aBaseFeature[indAttr]->data()->attributes(GeomDataAPI_Point2D::type()); +//// std::list::iterator anIt = anAttributes.begin(); +//// for ( ; anIt != anAttributes.end(); anIt++) { +//// // Arc should be fixed by center and start points only (to avoid "conflicting constraints" message) +//// if (aBaseFeature[indAttr]->getKind() == SketchPlugin_Arc::ID() && +//// (*anIt)->id() == SketchPlugin_Arc::END_ID()) +//// continue; +//// addTemporaryConstraintWhereDragged(*anIt); +//// } +//// } +//// return true; +////} +//// +////// ============================================================================ +////// Function: changeEntity +////// Class: SketchSolver_Group +////// Purpose: create/update the element affected by any constraint +////// ============================================================================ +////Slvs_hEntity SketchSolver_Group::changeEntity( +//// std::shared_ptr theEntity) +////{ +//// // If the entity is already in the group, try to find it +//// std::map, Slvs_hEntity>::const_iterator aEntIter = +//// myEntityAttrMap.find(theEntity); +//// int aEntPos; +//// std::vector::const_iterator aParamIter; // looks at first parameter of already existent entity or at the end of vector otherwise +//// if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created +//// aParamIter = myParams.end(); +//// else { // the entity already exists +//// aEntPos = Search(aEntIter->second, myEntities); +//// int aParamPos = Search(myEntities[aEntPos].param[0], myParams); +//// aParamIter = myParams.begin() + aParamPos; +//// } +//// const bool isEntExists = (aEntIter != myEntityAttrMap.end()); // defines that the entity already exists +//// const bool isNeedToSolve = myNeedToSolve; +//// myNeedToSolve = false; +//// +//// if (isEntExists) { +//// // Verify that the entity is not used by "Rigid" constraint. +//// // If it is used, the object should not move. +//// std::vector >::iterator aCoincIter = myCoincidentPoints.begin(); +//// for (; aCoincIter != myCoincidentPoints.end(); aCoincIter++) +//// if (aCoincIter->find(aEntIter->second) != aCoincIter->end()) +//// break; +//// std::set aCoincident; +//// if (aCoincIter != myCoincidentPoints.end()) { +//// aCoincident = *aCoincIter; +//// aCoincident.erase(aEntIter->second); +//// +//// 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()) { +//// myNeedToSolve = true; +//// return aEntIter->second; +//// } +//// } +//// } +//// +//// // Look over supported types of entities +//// Slvs_Entity aNewEntity; +//// aNewEntity.h = SLVS_E_UNKNOWN; +//// +//// // Point in 3D +//// std::shared_ptr aPoint = std::dynamic_pointer_cast( +//// theEntity); +//// if (aPoint) { +//// Slvs_hParam aX = changeParameter(aPoint->x(), aParamIter); +//// Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter); +//// Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter); +//// if (!isEntExists) // New entity +//// aNewEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ); +//// } else { +//// // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error +//// if (myWorkplane.h == SLVS_E_UNKNOWN) +//// return SLVS_E_UNKNOWN; +//// +//// // Point in 2D +//// std::shared_ptr aPoint2D = +//// std::dynamic_pointer_cast(theEntity); +//// if (aPoint2D) { +//// Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter); +//// Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter); +//// if (!isEntExists) // New entity +//// aNewEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV); +//// } else { +//// // Scalar value (used for the distance entities) +//// AttributeDoublePtr aScalar = std::dynamic_pointer_cast(theEntity); +//// if (aScalar) { +//// Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter); +//// if (!isEntExists) // New entity +//// aNewEntity = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue); +//// } +//// } +//// } +//// /// \todo Other types of entities +//// +//// Slvs_hEntity aResult = SLVS_E_UNKNOWN; // Unsupported or wrong entity type +//// +//// if (isEntExists) { +//// myNeedToSolve = myNeedToSolve || isNeedToSolve; +//// aResult = aEntIter->second; +//// } else if (aNewEntity.h != SLVS_E_UNKNOWN) { +//// myEntities.push_back(aNewEntity); +//// myEntOfConstr.push_back(false); +//// myEntityAttrMap[theEntity] = aNewEntity.h; +//// aResult = aNewEntity.h; +//// } +//// +//// // If the attribute was changed by the user, we need to fix it before solving +//// if (myNeedToSolve && theEntity->isImmutable()) +//// addTemporaryConstraintWhereDragged(theEntity, false); +//// +//// return aResult; +////} +//// +////// ============================================================================ +////// Function: changeEntity +////// Class: SketchSolver_Group +////// Purpose: create/update the element defined by the feature affected by any constraint +////// ============================================================================ +////Slvs_hEntity SketchSolver_Group::changeEntityFeature(FeaturePtr theEntity) +////{ +//// if (!theEntity->data()->isValid()) +//// return SLVS_E_UNKNOWN; +//// // If the entity is already in the group, try to find it +//// std::map::const_iterator aEntIter = myEntityFeatMap.find(theEntity); +//// // defines that the entity already exists +//// const bool isEntExists = (myEntityFeatMap.find(theEntity) != myEntityFeatMap.end()); +//// +//// Slvs_Entity aNewEntity; +//// aNewEntity.h = SLVS_E_UNKNOWN; +//// +//// // SketchPlugin features +//// std::shared_ptr aFeature = std::dynamic_pointer_cast< +//// SketchPlugin_Feature>(theEntity); +//// if (aFeature) { // Verify the feature by its kind +//// const std::string& aFeatureKind = aFeature->getKind(); +//// AttributePtr anAttribute; +//// +//// // Line +//// if (aFeatureKind.compare(SketchPlugin_Line::ID()) == 0) { +//// anAttribute = aFeature->data()->attribute(SketchPlugin_Line::START_ID()); +//// if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; +//// Slvs_hEntity aStart = changeEntity(anAttribute); +//// +//// anAttribute = aFeature->data()->attribute(SketchPlugin_Line::END_ID()); +//// if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; +//// Slvs_hEntity aEnd = changeEntity(anAttribute); +//// +//// if (!isEntExists) // New entity +//// aNewEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd); +//// } +//// // Circle +//// else if (aFeatureKind.compare(SketchPlugin_Circle::ID()) == 0) { +//// anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::CENTER_ID()); +//// if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; +//// Slvs_hEntity aCenter = changeEntity(anAttribute); +//// +//// anAttribute = aFeature->data()->attribute(SketchPlugin_Circle::RADIUS_ID()); +//// if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; +//// Slvs_hEntity aRadius = changeEntity(anAttribute); +//// +//// if (!isEntExists) // New entity +//// aNewEntity = Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter, +//// myWorkplane.normal, aRadius); +//// } +//// // Arc +//// else if (aFeatureKind.compare(SketchPlugin_Arc::ID()) == 0) { +//// anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::CENTER_ID()); +//// if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; +//// Slvs_hEntity aCenter = changeEntity(anAttribute); +//// +//// anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::START_ID()); +//// if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; +//// Slvs_hEntity aStart = changeEntity(anAttribute); +//// +//// anAttribute = aFeature->data()->attribute(SketchPlugin_Arc::END_ID()); +//// if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; +//// Slvs_hEntity aEnd = changeEntity(anAttribute); +//// +//// if (!isEntExists) +//// aNewEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID, myWorkplane.h, +//// myWorkplane.normal, aCenter, aStart, aEnd); +//// } +//// // Point (it has low probability to be an attribute of constraint, so it is checked at the end) +//// else if (aFeatureKind.compare(SketchPlugin_Point::ID()) == 0) { +//// anAttribute = aFeature->data()->attribute(SketchPlugin_Point::COORD_ID()); +//// if (!anAttribute->isInitialized()) return SLVS_E_UNKNOWN; +//// Slvs_hEntity aPoint = changeEntity(anAttribute); +//// +//// if (isEntExists) +//// return aEntIter->second; +//// +//// // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier +//// myEntityFeatMap[theEntity] = aPoint; +//// myNeedToSolve = true; +//// return aPoint; +//// } +//// } +//// /// \todo Other types of features +//// +//// if (isEntExists) +//// return aEntIter->second; +//// +//// if (aNewEntity.h != SLVS_E_UNKNOWN) { +//// myEntities.push_back(aNewEntity); +//// myEntOfConstr.push_back(false); +//// myEntityFeatMap[theEntity] = aNewEntity.h; +//// myNeedToSolve = true; +//// return aNewEntity.h; +//// } +//// +//// // Unsupported or wrong entity type +//// return SLVS_E_UNKNOWN; +////} + +// ============================================================================ +// Function: addWorkplane +// Class: SketchSolver_Group +// Purpose: create workplane for the group +// ============================================================================ +bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch) +{ + 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; + updateWorkplane(); + return true; +} + +// ============================================================================ +// Function: updateWorkplane +// Class: SketchSolver_Group +// Purpose: update parameters of workplane +// ============================================================================ +bool SketchSolver_Group::updateWorkplane() +{ + if (!myStorage) // Create storage if not exists + myStorage = StoragePtr(new SketchSolver_Storage); + SketchSolver_Builder* aBuilder = SketchSolver_Builder::getInstance(); + + 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 = myID; + 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 = myID; + 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 myWorkplaneID > 0; +} + +////// ============================================================================ +////// Function: changeParameter +////// Class: SketchSolver_Group +////// Purpose: create/update value of parameter +////// ============================================================================ +////Slvs_hParam SketchSolver_Group::changeParameter( +//// const double& theParam, std::vector::const_iterator& thePrmIter) +////{ +//// if (thePrmIter != myParams.end()) { // Parameter should be updated +//// int aParamPos = thePrmIter - myParams.begin(); +//// if (fabs(thePrmIter->val - theParam) > tolerance) { +//// myNeedToSolve = true; // parameter is changed, need to resolve constraints +//// myParams[aParamPos].val = theParam; +//// } +//// thePrmIter++; +//// return myParams[aParamPos].h; +//// } +//// +//// // Newly created parameter +//// Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam); +//// myParams.push_back(aParam); +//// myNeedToSolve = true; +//// // The list of parameters is changed, move iterator to the end of the list to avoid problems +//// thePrmIter = myParams.end(); +//// return aParam.h; +////} + +// ============================================================================ +// Function: resolveConstraints +// Class: SketchSolver_Group +// Purpose: solve the set of constraints for the current group +// ============================================================================ +bool SketchSolver_Group::resolveConstraints() +{ + if (!myStorage->isNeedToResolve() || isEmpty()) + return false; + + myConstrSolver.setGroupID(myID); + myStorage->initializeSolver(myConstrSolver); + +//// theSolver.setDraggedParameters(myTempPointWhereDragged); +//// + int aResult = myConstrSolver.solve(); + if (aResult == SLVS_RESULT_OKAY) { // solution succeeded, store results into correspondent attributes + ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin(); + for (; aConstrIter != myConstraints.end(); aConstrIter++) + aConstrIter->second->refresh(); + +//// // Obtain result into the same list of parameters +//// if (!myConstrSolver.getResult(myParams)) +//// return true; +//// +//// // We should go through the attributes map, because only attributes have valued parameters +//// std::map, Slvs_hEntity>::iterator anEntIter = +//// myEntityAttrMap.begin(); +//// for (; anEntIter != myEntityAttrMap.end(); anEntIter++) { +//// if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get()) +//// anEntIter->first->owner()->data()->blockSendAttributeUpdated(true); +//// if (updateAttribute(anEntIter->first, anEntIter->second)) +//// updateRelatedConstraints(anEntIter->first); +//// } +//// updateFilletConstraints(); +//// // unblock all features then +//// for (anEntIter = myEntityAttrMap.begin(); anEntIter != myEntityAttrMap.end(); anEntIter++) { +//// if (anEntIter->first->owner().get() && anEntIter->first->owner()->data().get()) +//// anEntIter->first->owner()->data()->blockSendAttributeUpdated(false); +//// } + } else if (!myConstraints.empty()) + Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this); + + removeTemporaryConstraints(); +//// myNeedToSolve = false; + myStorage->setNeedToResolve(false); + return true; +} + +// ============================================================================ +// Function: mergeGroups +// Class: SketchSolver_Group +// Purpose: append specified group to the current group +// ============================================================================ +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); + + ConstraintConstraintMap::const_iterator aConstrIter = theGroup.myConstraints.begin(); + for (; aConstrIter != theGroup.myConstraints.end(); aConstrIter++) + changeConstraint(aConstrIter->first); +} + +// ============================================================================ +// Function: splitGroup +// Class: SketchSolver_Group +// Purpose: divide the group into several subgroups +// ============================================================================ +void SketchSolver_Group::splitGroup(std::vector& theCuts) +{ + // Obtain constraints, which should be separated + FeatureStoragePtr aNewFeatStorage(new SketchSolver_FeatureStorage); + std::vector anUnusedConstraints; + ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); + for ( ; aCIter != myConstraints.end(); aCIter++) { + std::list aBaseConstraints = aCIter->second->constraints(); + std::list::iterator anIter = aBaseConstraints.begin(); + for (; anIter != aBaseConstraints.end(); anIter++) + if (aNewFeatStorage->isInteract(*anIter)) { + aNewFeatStorage->changeConstraint(*anIter); + } else + anUnusedConstraints.push_back(*anIter); + } + + std::vector::iterator aCutsIter; + std::vector::iterator aUnuseIt = anUnusedConstraints.begin(); + 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++) + if ((*aCutsIter)->isInteract(*aUnuseIt)) { + (*aCutsIter)->changeConstraint(*aUnuseIt); + break; + } + if (aCutsIter == theCuts.end()) { + // Add new group + SketchSolver_Group* aGroup = new SketchSolver_Group(mySketch); + aGroup->changeConstraint(*aUnuseIt); + theCuts.push_back(aGroup); + } + } +} + +// ============================================================================ +// Function: isConsistent +// Class: SketchSolver_Group +// Purpose: search removed entities and constraints +// ============================================================================ +bool SketchSolver_Group::isConsistent() +{ + if (!myFeatureStorage) // no one constraint is initialized yet + return true; + + bool aResult = myFeatureStorage->isConsistent(); + if (!aResult) { + // remove invalid entities + ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); + while (aCIter != myConstraints.end()) { + std::list aConstraints = aCIter->second->constraints(); + std::list::iterator anIt = aConstraints.begin(); + for (; anIt != aConstraints.end(); anIt++) + if (!(*anIt)->data() || !(*anIt)->data()->isValid()) + if (aCIter->second->remove(*anIt)) { + // the constraint is fully removed, detach it from the list + ConstraintConstraintMap::iterator aTmpIt = aCIter++; + myFeatureStorage->removeConstraint(aTmpIt->first); + myConstraints.erase(aTmpIt); + break; + } + if (anIt == aConstraints.end()) + aCIter++; + } + } + return aResult; +} + +////// ============================================================================ +////// Function: updateAttribute +////// Class: SketchSolver_Group +////// Purpose: update features of sketch after resolving constraints +////// ============================================================================ +////bool SketchSolver_Group::updateAttribute( +//// std::shared_ptr theAttribute, const Slvs_hEntity& theEntityID) +////{ +//// // Search the position of the first parameter of the entity +//// int anEntPos = Search(theEntityID, myEntities); +//// int aFirstParamPos = Search(myEntities[anEntPos].param[0], myParams); +//// +//// // Look over supported types of entities +//// +//// // Point in 3D +//// std::shared_ptr aPoint = std::dynamic_pointer_cast( +//// theAttribute); +//// if (aPoint) { +//// if (fabs(aPoint->x() - myParams[aFirstParamPos].val) > tolerance +//// || fabs(aPoint->y() - myParams[aFirstParamPos + 1].val) > tolerance +//// || fabs(aPoint->z() - myParams[aFirstParamPos + 2].val) > tolerance) { +//// aPoint->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val, +//// myParams[aFirstParamPos + 2].val); +//// return true; +//// } +//// return false; +//// } +//// +//// // Point in 2D +//// std::shared_ptr aPoint2D = +//// std::dynamic_pointer_cast(theAttribute); +//// if (aPoint2D) { +//// if (fabs(aPoint2D->x() - myParams[aFirstParamPos].val) > tolerance +//// || fabs(aPoint2D->y() - myParams[aFirstParamPos + 1].val) > tolerance) { +//// aPoint2D->setValue(myParams[aFirstParamPos].val, myParams[aFirstParamPos + 1].val); +//// return true; +//// } +//// return false; +//// } +//// +//// // Scalar value +//// AttributeDoublePtr aScalar = std::dynamic_pointer_cast(theAttribute); +//// if (aScalar) { +//// if (fabs(aScalar->value() - myParams[aFirstParamPos].val) > tolerance) { +//// aScalar->setValue(myParams[aFirstParamPos].val); +//// return true; +//// } +//// return false; +//// } +//// +//// /// \todo Support other types of entities +//// return false; +////} +//// +////// ============================================================================ +////// Function: updateEntityIfPossible +////// Class: SketchSolver_Group +////// Purpose: search the entity in this group and update it +////// ============================================================================ +////void SketchSolver_Group::updateEntityIfPossible( +//// std::shared_ptr theEntity) +////{ +//// if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end()) { +//// // If the attribute is a point and it is changed (the group needs to rebuild), +//// // probably user has dragged this point into this position, +//// // so it is necessary to add constraint which will guarantee the point will not change +//// +//// // Store myNeedToSolve flag to verify the entity is really changed +//// bool aNeedToSolveCopy = myNeedToSolve; +//// myNeedToSolve = false; +//// +//// changeEntity(theEntity); +//// +//// if (myNeedToSolve) // the entity is changed +//// { +//// // Verify the entity is a point and add temporary constraint of permanency +//// std::shared_ptr aPoint = std::dynamic_pointer_cast( +//// theEntity); +//// std::shared_ptr aPoint2D = std::dynamic_pointer_cast< +//// GeomDataAPI_Point2D>(theEntity); +//// if (aPoint || aPoint2D) +//// addTemporaryConstraintWhereDragged(theEntity); +//// } +//// +//// // Restore flag of changes +//// myNeedToSolve = myNeedToSolve || aNeedToSolveCopy; +//// +//// if (myNeedToSolve) +//// updateRelatedConstraints(theEntity); +//// } +////} +//// +////// ============================================================================ +////// Function: addTemporaryConstraintWhereDragged +////// Class: SketchSolver_Group +////// Purpose: add transient constraint SLVS_C_WHERE_DRAGGED for the entity, +////// which was moved by user +////// ============================================================================ +////void SketchSolver_Group::addTemporaryConstraintWhereDragged( +//// std::shared_ptr theEntity, +//// bool theAllowToFit) +////{ +//// // Find identifier of the entity +//// std::map, Slvs_hEntity>::const_iterator anEntIter = +//// myEntityAttrMap.find(theEntity); +//// if (anEntIter == myEntityAttrMap.end()) +//// return; +//// +//// // Get identifiers of all dragged points +//// std::set aDraggedPntID; +//// aDraggedPntID.insert(myTempPointWDrgdID); +//// std::list::const_iterator aTmpCoIter = myTempConstraints.begin(); +//// for (; aTmpCoIter != myTempConstraints.end(); aTmpCoIter++) { +//// unsigned int aConstrPos = Search(*aTmpCoIter, myConstraints); +//// if (aConstrPos < myConstraints.size()) +//// aDraggedPntID.insert(myConstraints[aConstrPos].ptA); +//// } +//// std::vector::const_iterator aConstrIter = myConstraints.begin(); +//// for (; aConstrIter != myConstraints.end(); aConstrIter++) +//// if (aConstrIter->type == SLVS_C_WHERE_DRAGGED) +//// aDraggedPntID.insert(aConstrIter->ptA); +//// // Find whether there is a point coincident with theEntity, which already has SLVS_C_WHERE_DRAGGED +//// std::vector >::iterator aCoPtIter = myCoincidentPoints.begin(); +//// for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) { +//// if (aCoPtIter->find(anEntIter->second) == aCoPtIter->end()) +//// continue; // the entity was not found in current set +//// +//// // Find one of already created SLVS_C_WHERE_DRAGGED constraints in current set of coincident points +//// std::set::const_iterator aDrgIter = aDraggedPntID.begin(); +//// for (; aDrgIter != aDraggedPntID.end(); aDrgIter++) +//// if (aCoPtIter->find(*aDrgIter) != aCoPtIter->end()) +//// return; // the SLVS_C_WHERE_DRAGGED constraint already exists +//// } +//// if (aDraggedPntID.find(anEntIter->second) != aDraggedPntID.end()) +//// return; +//// +//// // If this is a first dragged point, its parameters should be placed +//// // into Slvs_System::dragged field to avoid system inconsistense +//// if (myTempPointWhereDragged.empty() && theAllowToFit) { +//// int anEntPos = Search(anEntIter->second, myEntities); +//// Slvs_hParam* aDraggedParam = myEntities[anEntPos].param; +//// for (int i = 0; i < 4; i++, aDraggedParam++) +//// if (*aDraggedParam != 0) +//// myTempPointWhereDragged.push_back(*aDraggedParam); +//// myTempPointWDrgdID = myEntities[anEntPos].h; +//// return; +//// } +//// +//// // Create additional SLVS_C_WHERE_DRAGGED constraint if myTempPointWhereDragged field is not empty +//// Slvs_Constraint aWDConstr = Slvs_MakeConstraint(++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, +//// myWorkplane.h, 0.0, anEntIter->second, 0, 0, 0); +//// myConstraints.push_back(aWDConstr); +//// myTempConstraints.push_back(aWDConstr.h); +////} + +// ============================================================================ +// Function: removeTemporaryConstraints +// Class: SketchSolver_Group +// Purpose: remove all transient SLVS_C_WHERE_DRAGGED constraints after +// resolving the set of constraints +// ============================================================================ +void SketchSolver_Group::removeTemporaryConstraints() +{ + myTempConstraints.clear(); + // Clean lists of removed entities in the storage + std::set aRemPar; + std::set aRemEnt; + std::set aRemCon; + myStorage->getRemoved(aRemPar, aRemEnt, aRemCon); +} + +// ============================================================================ +// Function: removeConstraint +// Class: SketchSolver_Group +// Purpose: remove constraint and all unused entities +// ============================================================================ +void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint) +{ + myFeatureStorage->removeConstraint(theConstraint); + ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); + for (; aCIter != myConstraints.end(); aCIter++) + if (aCIter->second->hasConstraint(theConstraint)) { + if (!aCIter->second->remove(theConstraint)) // the constraint is not fully removed + aCIter = myConstraints.end(); + break; + } + if (aCIter != myConstraints.end()) + myConstraints.erase(aCIter); +} + +////// ============================================================================ +////// Function: removeEntitiesById +////// Class: SketchSolver_Group +////// Purpose: Removes specified entities and their parameters +////// ============================================================================ +////void SketchSolver_Group::removeEntitiesById(const std::set& theEntities) +////{ +//// std::set::const_reverse_iterator aRemIter = theEntities.rbegin(); +//// for (; aRemIter != theEntities.rend(); aRemIter++) { +//// unsigned int anEntPos = Search(*aRemIter, myEntities); +//// if (anEntPos >= myEntities.size()) +//// continue; +//// if (myEntities[anEntPos].param[0] != 0) { +//// unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams); +//// if (aParamPos >= myParams.size()) +//// continue; +//// int aNbParams = 0; +//// while (myEntities[anEntPos].param[aNbParams] != 0) +//// aNbParams++; +//// if (myEntities[anEntPos].param[aNbParams - 1] == myParamMaxID) +//// myParamMaxID -= aNbParams; +//// myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams); +//// if (*aRemIter == myEntityMaxID) +//// myEntityMaxID--; +//// } +//// myEntities.erase(myEntities.begin() + anEntPos); +//// myEntOfConstr.erase(myEntOfConstr.begin() + anEntPos); +//// +//// // Remove entity's ID from the lists of conincident points +//// std::vector >::iterator aCoPtIter = myCoincidentPoints.begin(); +//// for (; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) +//// aCoPtIter->erase(*aRemIter); +//// } +////} +//// +////// ============================================================================ +////// Function: addCoincidentPoints +////// Class: SketchSolver_Group +////// Purpose: add coincident point the appropriate list of such points +////// ============================================================================ +////bool SketchSolver_Group::addCoincidentPoints(const Slvs_hEntity& thePoint1, +//// const Slvs_hEntity& thePoint2) +////{ +//// std::vector >::iterator aCoPtIter = myCoincidentPoints.begin(); +//// std::vector >::iterator aFirstFound = myCoincidentPoints.end(); +//// while (aCoPtIter != myCoincidentPoints.end()) { +//// bool isFound[2] = { // indicate which point ID was already in coincidence constraint +//// aCoPtIter->find(thePoint1) != aCoPtIter->end(), aCoPtIter->find(thePoint2) +//// != aCoPtIter->end(), }; +//// if (isFound[0] && isFound[1]) // points are already connected by coincidence constraints => no need additional one +//// return false; +//// if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1])) { +//// if (aFirstFound != myCoincidentPoints.end()) { // there are two groups of coincident points connected by created constraint => merge them +//// int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin(); +//// int aCurrentShift = aCoPtIter - myCoincidentPoints.begin(); +//// aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end()); +//// myCoincidentPoints.erase(aCoPtIter); +//// aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift; +//// aCoPtIter = myCoincidentPoints.begin() + aCurrentShift; +//// continue; +//// } else { +//// aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1); +//// aFirstFound = aCoPtIter; +//// } +//// } +//// aCoPtIter++; +//// } +//// // No points were found, need to create new set +//// if (aFirstFound == myCoincidentPoints.end()) { +//// std::set aNewSet; +//// aNewSet.insert(thePoint1); +//// aNewSet.insert(thePoint2); +//// myCoincidentPoints.push_back(aNewSet); +//// } +//// +//// return true; +////} +//// +////// ============================================================================ +////// Function: updateRelatedConstraints +////// Class: SketchSolver_Group +////// Purpose: emit the signal to update constraints +////// ============================================================================ +////void SketchSolver_Group::updateRelatedConstraints( +//// std::shared_ptr theEntity) const +////{ +//// ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin(); +//// for (; aConstrIter != myConstraintMap.end(); aConstrIter++) { +//// std::list > anAttributes = aConstrIter->first->data() +//// ->attributes(std::string()); +//// +//// std::list >::iterator anAttrIter = anAttributes.begin(); +//// for (; anAttrIter != anAttributes.end(); anAttrIter++) { +//// bool isUpd = (*anAttrIter == theEntity); +//// std::shared_ptr aRefAttr = std::dynamic_pointer_cast< +//// ModelAPI_AttributeRefAttr>(*anAttrIter); +//// if (aRefAttr && !aRefAttr->isObject() && aRefAttr->attr() == theEntity) +//// isUpd = true; +//// +//// if (isUpd) { +//// static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); +//// ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent); +//// break; +//// } +//// } +//// } +////} +//// +////void SketchSolver_Group::updateRelatedConstraintsFeature( +//// std::shared_ptr theFeature) const +////{ +//// ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin(); +//// for (; aConstrIter != myConstraintMap.end(); aConstrIter++) { +//// std::list > anAttributes = aConstrIter->first->data() +//// ->attributes(std::string()); +//// +//// std::list >::iterator anAttrIter = anAttributes.begin(); +//// for (; anAttrIter != anAttributes.end(); anAttrIter++) { +//// std::shared_ptr aRefAttr = std::dynamic_pointer_cast< +//// ModelAPI_AttributeRefAttr>(*anAttrIter); +//// if (aRefAttr && aRefAttr->isObject() && aRefAttr->object() == theFeature) { +//// static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); +//// ModelAPI_EventCreator::get()->sendUpdated(aConstrIter->first, anEvent); +//// break; +//// } +//// } +//// } +////} +//// +////// ============================================================================ +////// Function: updateFilletConstraints +////// Class: SketchSolver_Group +////// Purpose: change fillet arc to be less than 180 degree +////// ============================================================================ +////void SketchSolver_Group::updateFilletConstraints() +////{ +//// ConstraintMap::const_iterator aConstrIter = myConstraintMap.begin(); +//// for (; aConstrIter != myConstraintMap.end(); aConstrIter++) +//// if (aConstrIter->first->getKind() == SketchPlugin_ConstraintFillet::ID()) { +//// AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast( +//// aConstrIter->first->data()->attribute(SketchPlugin_ConstraintFillet::ENTITY_C())); +//// if (!aFilletRefList) +//// return; +//// ObjectPtr anArcObj = aFilletRefList->object(2); +//// std::shared_ptr aCenter = std::dynamic_pointer_cast( +//// anArcObj->data()->attribute(SketchPlugin_Arc::CENTER_ID())); +//// std::shared_ptr aStart = std::dynamic_pointer_cast( +//// anArcObj->data()->attribute(SketchPlugin_Arc::START_ID())); +//// std::shared_ptr aEnd = std::dynamic_pointer_cast( +//// anArcObj->data()->attribute(SketchPlugin_Arc::END_ID())); +//// double aCosA = aStart->x() - aCenter->x(); +//// double aSinA = aStart->y() - aCenter->y(); +//// double aCosB = aEnd->x() - aCenter->x(); +//// double aSinB = aEnd->y() - aCenter->y(); +//// if (aCosA * aSinB - aSinA * aCosB <= 0.0) { +//// anArcObj->data()->blockSendAttributeUpdated(true); +//// double x = aStart->x(); +//// double y = aStart->y(); +//// aStart->setValue(aEnd->x(), aEnd->y()); +//// aEnd->setValue(x, y); +//// // Update constraint data +//// changeFilletConstraint(aConstrIter->first); +//// anArcObj->data()->blockSendAttributeUpdated(false); +//// } +//// } +////} +//// +////// ============================================================================ +////// Function: makeMirrorEntity +////// Class: SketchSolver_Group +////// Purpose: change entities parameters to make them symmetric relating to the mirror line +////// ============================================================================ +////void SketchSolver_Group::makeMirrorEntity(const Slvs_hEntity& theBase, +//// const Slvs_hEntity& theMirror, +//// const Slvs_hEntity& theMirrorLine) +////{ +//// Slvs_Entity aBase = myEntities[Search(theBase, myEntities)]; +//// Slvs_Entity aMirror = myEntities[Search(theMirror, myEntities)]; +//// int i = 0; +//// while (aBase.point[i] != 0 && aMirror.point[i] != 0) { +//// makeMirrorEntity(aBase.point[i], aMirror.point[i], theMirrorLine); +//// i++; +//// } +//// if (aBase.param[0] != 0 && aMirror.param[0] != 0) { // this is a point, copy it +//// Slvs_Entity aMirrorLine = myEntities[Search(theMirrorLine, myEntities)]; +//// std::shared_ptr aLinePoints[2]; +//// for (i = 0; i < 2; i++) { +//// Slvs_Entity aPoint = myEntities[Search(aMirrorLine.point[i], myEntities)]; +//// int aParamPos = Search(aPoint.param[0], myParams); +//// aLinePoints[i] = std::shared_ptr( +//// new GeomAPI_XY(myParams[aParamPos].val, myParams[1+aParamPos].val)); +//// } +//// int aBaseParamPos = Search(aBase.param[0], myParams); +//// int aMirrorParamPos = Search(aMirror.param[0], myParams); +//// std::shared_ptr aPoint = std::shared_ptr( +//// new GeomAPI_XY(myParams[aBaseParamPos].val, myParams[1+aBaseParamPos].val)); +//// +//// // 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())); +//// +//// 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()); +//// std::shared_ptr aMirrorPoint = aPoint->added(aDir->xy()->multiplied(-2.0 * aDist)); +//// +//// myParams[aMirrorParamPos].val = aMirrorPoint->x(); +//// myParams[1+aMirrorParamPos].val = aMirrorPoint->y(); +//// } +////} +//// +////// ============================================================================ +////// Function: calculateMiddlePoint +////// Class: SketchSolver_Group +////// Purpose: calculates middle point on line or arc +////// ============================================================================ +////void SketchSolver_Group::calculateMiddlePoint( +//// const Slvs_hEntity& theEntity, +//// double& theX, +//// double& theY) const +////{ +//// int anInd = Search(theEntity, myEntities); +//// if (myEntities[anInd].type == SLVS_E_LINE_SEGMENT) { +//// int aLineParams[2]; +//// for (int i = 0; i < 2; i++) { +//// int aPtPos = Search(myEntities[anInd].point[i], myEntities); +//// aLineParams[i] = Search(myEntities[aPtPos].param[0], myParams); +//// } +//// theX = 0.5 * (myParams[aLineParams[0]].val + myParams[aLineParams[1]].val); +//// theY = 0.5 * (myParams[1 + aLineParams[0]].val + myParams[1 + aLineParams[1]].val); +//// } else if (myEntities[anInd].type == SLVS_E_ARC_OF_CIRCLE) { +//// double anArcPoint[3][2]; +//// for (int i = 0; i < 3; i++) { +//// int aPtPos = Search(myEntities[anInd].point[i], myEntities); +//// int anArcParam = Search(myEntities[aPtPos].param[0], myParams); +//// anArcPoint[i][0] = myParams[anArcParam].val; +//// anArcPoint[i][1] = myParams[1 + anArcParam].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] = anArcPoint[0][0] + x * aRad / aNorm; +//// anArcPoint[2][1] = anArcPoint[0][1] + y * aRad / aNorm; +//// } +//// +//// x = anArcPoint[1][0] + anArcPoint[2][0] - 2.0 * anArcPoint[0][0]; +//// y = anArcPoint[1][1] + anArcPoint[2][1] - 2.0 * anArcPoint[0][1]; +//// aNorm = sqrt(x*x + y*y); +//// if (aNorm >= tolerance) { +//// x *= aRad / aNorm; +//// y *= aRad / aNorm; +//// } else { // obtain orthogonal direction +//// x = 0.5 * (anArcPoint[2][1] - anArcPoint[1][1]); +//// y = -0.5 * (anArcPoint[2][0] - anArcPoint[1][0]); +//// } +//// theX = anArcPoint[0][0] + x; +//// theY = anArcPoint[0][1] + y; +//// } +////} + + +// ======================================================== +// ========= 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(); + while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID) + aResIndex--; + while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID) + aResIndex++; + if (aResIndex == -1) + aResIndex = aVecSize; + return aResIndex; +} diff --git a/src/SketchSolver/SketchSolver_Group.h b/src/SketchSolver/SketchSolver_Group.h new file mode 100644 index 000000000..68317fd0a --- /dev/null +++ b/src/SketchSolver/SketchSolver_Group.h @@ -0,0 +1,309 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_Group.h +// Created: 27 May 2014 +// Author: Artem ZHIDKOV + +#ifndef SketchSolver_Group_H_ +#define SketchSolver_Group_H_ + +#include "SketchSolver.h" +#include +#include +#include +#include + +#include +#include +#include + + +#include +#include +#include +#include +#include + +typedef std::map ConstraintConstraintMap; + +/** \class SketchSolver_Group + * \ingroup Plugins + * \brief Keeps the group of constraints which based on the same entities + */ +class SketchSolver_Group +{ + public: + /** \brief New group based on specified workplane. + * Throws an exception if theWorkplane is not an object of SketchPlugin_Sketch type + * \remark Type of theSketch is not verified inside + */ + SketchSolver_Group(std::shared_ptr theWorkplane); + + ~SketchSolver_Group(); + + /// \brief Returns group's unique identifier + inline const Slvs_hGroup& getId() const + { + return myID; + } + + /// \brief Returns identifier of the workplane + 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 + { + return myConstraints.empty(); + } + + /// \brief Check for valid sketch data + inline bool isWorkplaneValid() const + { + return mySketch->data() && mySketch->data()->isValid(); + } + + /** \brief Adds or updates a constraint in the group + * \param[in] theConstraint constraint to be changed + * \return \c true if the constraint added or updated successfully + */ + bool changeConstraint(std::shared_ptr theConstraint); +//// /** \brief Adds or updates a rigid constraint in the group +//// * \param[in] theConstraint constraint to be changed +//// * \return \c true if the constraint added or updated successfully +//// */ +//// bool changeRigidConstraint(std::shared_ptr theConstraint); +//// /** \brief Adds or updates a mirror constraint in the group +//// * \param[in] theConstraint constraint to be changed +//// * \return \c true if the constraint added or updated successfully +//// */ +//// bool changeMirrorConstraint(std::shared_ptr theConstraint); +//// /** \brief Adds or updates a fillet constraint in the group +//// * \param[in] theConstraint constraint to be changed +//// * \return \c true if the constraint added or updated successfully +//// */ +//// bool changeFilletConstraint(std::shared_ptr theConstraint); + + /** \brief Updates the data corresponding the specified feature moved in GUI. + * Additional Fixed constraints are created. + * \param[in] theFeature the feature to be updated + */ + void moveFeature(std::shared_ptr theFeature); + + /** \brief Verifies the feature attributes are used in this group + * \param[in] theFeature constraint or any other object for verification of interaction + * \return \c true if some of attributes are used in current group + */ + bool isInteract(std::shared_ptr theFeature) const; + + /** \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 + * \return \c true if workplanes are the same + */ + bool isBaseWorkplane(CompositeFeaturePtr theWorkplane) const; + + /// Returns the current workplane + std::shared_ptr getWorkplane() const + { + return mySketch; + } + + /** \brief Update parameters of workplane. Should be called when Update event is coming. + * \return \c true if workplane updated successfully, \c false if workplane parameters are not consistent + */ + bool updateWorkplane(); +//// +//// /** \brief If the entity is in this group it will updated +//// * \param[in] theEntity attribute, which values should update SolveSpace entity +//// */ +//// void updateEntityIfPossible(std::shared_ptr theEntity); + + /** \brief Searches invalid features and constraints in the group and removes them + * \return \c false if the group several constraints were removed + */ + bool isConsistent(); + + /** \brief Add specified group to this one + * \param[in] theGroup group of constraint to be added + */ + void mergeGroups(const SketchSolver_Group& theGroup); + + /** \brief Cut from the group several subgroups, which are not connected to the current one by any constraint + * \param[out] theCuts enlarge this list by newly created groups + */ + void splitGroup(std::vector& theCuts); + + /** \brief Start solution procedure if necessary and update attributes of features + * \return \c false when no need to solve constraints + */ + bool resolveConstraints(); +//// +//// /** \brief Searches the constraints built on the entity and emit the signal to update them +//// * \param[in] theEntity attribute of the constraint +//// */ +//// void updateRelatedConstraints(std::shared_ptr theEntity) const; +//// /** \brief Searches the constraints built on the entity and emit the signal to update them +//// * \param[in] theFeature feature of the constraint +//// */ +//// void updateRelatedConstraintsFeature(std::shared_ptr theFeature) const; +//// +//// /** \brief Adds or updates an entity in the group +//// * +//// * The parameters of entity will be parsed and added to the list of SolveSpace parameters. +//// * Parameters of certain entity will be placed sequentially in the list. +//// * +//// * \param[in] theEntity the object of constraint +//// * \return identifier of changed entity or 0 if entity could not be changed +//// */ +//// Slvs_hEntity changeEntity(std::shared_ptr theEntity); +//// Slvs_hEntity changeEntityFeature(std::shared_ptr theEntity); + +protected: +//// /** \brief Adds or updates a normal in the group +//// * +//// * Normal is a special entity in SolveSpace, which defines a direction in 3D and +//// * a rotation about this direction. So, SolveSpace represents normals as unit quaternions. +//// * +//// * To define a normal there should be specified two coordinate axis +//// * on the plane transversed to created normal. +//// * +//// * \param[in] theDirX first coordinate axis of the plane +//// * \param[in] theNorm attribute for the normal (used to identify newly created entity) +//// * \return identifier of created or updated normal +//// */ +//// Slvs_hEntity changeNormal(std::shared_ptr theDirX, +//// std::shared_ptr theNorm); +//// +//// /** \brief Adds or updates a parameter in the group +//// * \param[in] theParam the value of parameter +//// * \param[in] thePrmIter the cell in the list of parameters which should be changed +//// * (the iterator will be increased if it does not reach the end of the list) +//// * \return identifier of changed parameter; when the parameter cannot be created, returned ID is 0 +//// */ +//// Slvs_hParam changeParameter(const double& theParam, +//// std::vector::const_iterator& thePrmIter); +//// +//// /** \brief Removes specified entities and their parameters +//// * \param[in] theEntities list of IDs of the entities to be removed +//// */ +//// void removeEntitiesById(const std::set& theEntities); + + /** \brief Removes constraints from the group + * \param[in] theConstraint constraint to be removed + */ + void removeConstraint(ConstraintPtr theConstraint); +//// +//// /** \brief Change values of attribute by parameters received from SolveSpace solver +//// * \param[in,out] theAttribute pointer to the attribute to be changed +//// * \param[in] theEntityID identifier of SolveSpace entity, which contains updated data +//// * \return \c true if the attribute's value has changed +//// */ +//// bool updateAttribute(std::shared_ptr theAttribute, +//// const Slvs_hEntity& theEntityID); +//// +//// /// \brief Update arc of fillet to be less than 180 degree +//// void updateFilletConstraints(); +//// +//// /** \brief Adds a constraint for a point which should not be changed during computations +//// * \param[in] theEntity the base for the constraint +//// * \param[in] theAllowToFit this flag shows that the entity may be placed into +//// * the 'dragged' field of SolveSpace solver, so this entity +//// * may be changed a little during solution +//// */ +//// void addTemporaryConstraintWhereDragged(std::shared_ptr theEntity, +//// bool theAllowToFit = true); + + /** \brief Remove all temporary constraint after computation finished + * \param[in] theRemoved indexes of constraints to be removed. If empty, all temporary constraints should be deleted + */ + void removeTemporaryConstraints(); + +private: + /** \brief Creates a workplane from the sketch parameters + * \param[in] theSketch parameters of workplane are the attributes of this sketch + * \return \c true if success, \c false if workplane parameters are not consistent + */ + bool addWorkplane(CompositeFeaturePtr theSketch); +//// +//// /** \brief Add the entities of constraint for points coincidence into the appropriate list +//// * \param[in] thePoint1 identifier of the first point +//// * \param[in] thePoint2 identifier of the second point +//// * \return \c true if the points are added successfully, and +//// * \c false if the constraint is the extra one (should not be created in SolveSpace) +//// */ +//// bool addCoincidentPoints(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2); +//// +//// /** \brief Verifies and changes parameters of constriant, +//// * e.g. sign of the distance between line and point +//// * \param[in,out] theConstraint SolveSpace constraint to be verified +//// */ +//// void checkConstraintConsistence(Slvs_Constraint& theConstraint); +//// +//// /** \brief Change entities parameters to make them symmetric relating to the mirror line +//// * \param[in] theBase entity to be mirrored +//// * \param[in] theMirror a mirrored object +//// * \param[in] theMirrorLine a mirror line +//// */ +//// void makeMirrorEntity(const Slvs_hEntity& theBase, +//// const Slvs_hEntity& theMirror, +//// const Slvs_hEntity& theMirrorLine); +//// +//// /** \brief Calculates middle point on line or arc +//// * \param[in] theEntity identifier of line or arc +//// * \param[out] theX X value of middle point +//// * \param[out] theY Y value of middle point +//// */ +//// void calculateMiddlePoint(const Slvs_hEntity& theEntity, +//// double& theX, double& theY) const; +//// +//// private: +//// // SolveSpace entities +//// Slvs_hGroup myID; ///< the index of the group +//// Slvs_Entity myWorkplane; ///< Workplane for the current group +//// std::vector myParams; ///< List of parameters of the constraints +//// Slvs_hParam myParamMaxID; ///< Actual maximal ID of parameters (not equal to myParams size) +//// std::vector myEntities; ///< List of entities of the constaints +//// std::vector myEntOfConstr; ///< Flags show that certain entity used in constraints +//// Slvs_hEntity myEntityMaxID; ///< Actual maximal ID of entities (not equal to myEntities size) +//// std::vector myConstraints; ///< List of constraints in SolveSpace format +//// Slvs_hConstraint myConstrMaxID; ///< Actual maximal ID of constraints (not equal to myConstraints size) +//// bool myNeedToSolve; ///< Indicator that something changed in the group and constraint system need to be rebuilt +//// +//// SketchSolver_Solver myConstrSolver; ///< Solver for set of equations obtained by constraints +//// +//// std::vector myTempPointWhereDragged; ///< Parameters of one of the points which is moved by user +//// Slvs_hEntity myTempPointWDrgdID; ///< Identifier of such point +//// std::list myTempConstraints; ///< The list of identifiers of temporary constraints (SLVS_C_WHERE_DRAGGED) applied for all other points moved by user +//// +//// // SketchPlugin entities +//// std::shared_ptr mySketch; ///< Equivalent to workplane +//// ConstraintMap myConstraintMap; ///< The map between SketchPlugin and SolveSpace constraints +//// std::map, Slvs_hEntity> myEntityAttrMap; ///< The map between "attribute" parameters of constraints and their equivalent SolveSpace entities +//// std::map myEntityFeatMap; ///< The map between "feature" parameters of constraints and their equivalent SolveSpace entities +//// +//// // Conincident items +//// std::vector > myCoincidentPoints; ///< Stores the lists of identifiers of coincident points (to avoid unnecessary coincidence constraints) +//// std::set > myExtraCoincidence; ///< Additional coincidence constraints which are not necessary (coincidence between points already done +//// ///< by other constraints) but created by GUI tools. Useful when some coincidence constraints were removed + +private: + 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 + + StoragePtr myStorage; ///< Container for the set of SolveSpace constraints and their entities + FeatureStoragePtr myFeatureStorage; ///< Container for the set of SketchPlugin features and their dependencies + + SketchSolver_Solver myConstrSolver; ///< Solver for set of equations obtained by constraints +}; + +#endif diff --git a/src/SketchSolver/SketchSolver_Solver.cpp b/src/SketchSolver/SketchSolver_Solver.cpp index 7e3a33de2..650e11c2d 100644 --- a/src/SketchSolver/SketchSolver_Solver.cpp +++ b/src/SketchSolver/SketchSolver_Solver.cpp @@ -31,83 +31,36 @@ SketchSolver_Solver::SketchSolver_Solver() SketchSolver_Solver::~SketchSolver_Solver() { - if (myEquationsSystem.param) - delete[] myEquationsSystem.param; - if (myEquationsSystem.entity) - delete[] myEquationsSystem.entity; - if (myEquationsSystem.constraint) - delete[] myEquationsSystem.constraint; if (myEquationsSystem.failed) delete[] myEquationsSystem.failed; } -void SketchSolver_Solver::setParameters(const std::vector& theParameters) +void SketchSolver_Solver::setParameters(Slvs_Param* theParameters, int theSize) { - if (theParameters.size() != myEquationsSystem.params) // number of parameters was changed => reallocate the memory - { - if (myEquationsSystem.param) - delete[] myEquationsSystem.param; - myEquationsSystem.params = theParameters.size(); - myEquationsSystem.param = new Slvs_Param[theParameters.size()]; - } - - // Copy data - std::vector::const_iterator aParamIter = theParameters.begin(); - for (int i = 0; i < myEquationsSystem.params; i++, aParamIter++) - myEquationsSystem.param[i] = *aParamIter; + myEquationsSystem.param = theParameters; + myEquationsSystem.params = theSize; } -void SketchSolver_Solver::setDraggedParameters(const std::vector& theDragged) + +void SketchSolver_Solver::setDraggedParameters(const Slvs_hParam* theDragged) { - if (theDragged.size() == 0) { - myEquationsSystem.dragged[0] = 0; - myEquationsSystem.dragged[1] = 0; - myEquationsSystem.dragged[2] = 0; - myEquationsSystem.dragged[3] = 0; - return; - } - for (unsigned int i = 0; i < theDragged.size(); i++) + for (unsigned int i = 0; i < 4; i++) myEquationsSystem.dragged[i] = theDragged[i]; } -void SketchSolver_Solver::setEntities(const std::vector& theEntities) +void SketchSolver_Solver::setEntities(Slvs_Entity* theEntities, int theSize) { - if (theEntities.size() != myEquationsSystem.entities) // number of entities was changed => reallocate the memory - { - if (myEquationsSystem.entity) - delete[] myEquationsSystem.entity; - myEquationsSystem.entities = theEntities.size(); - myEquationsSystem.entity = new Slvs_Entity[theEntities.size()]; - } - - // Copy data - std::vector::const_iterator aEntIter = theEntities.begin(); - for (int i = 0; i < myEquationsSystem.entities; i++, aEntIter++) - myEquationsSystem.entity[i] = *aEntIter; + myEquationsSystem.entity = theEntities; + myEquationsSystem.entities = theSize; } -void SketchSolver_Solver::setConstraints(const std::vector& theConstraints) +void SketchSolver_Solver::setConstraints(Slvs_Constraint* theConstraints, int theSize) { - if (theConstraints.size() != myEquationsSystem.constraints) // number of constraints was changed => reallocate the memory - { - if (myEquationsSystem.constraint) - delete[] myEquationsSystem.constraint; - myEquationsSystem.constraints = theConstraints.size(); - myEquationsSystem.constraint = new Slvs_Constraint[theConstraints.size()]; - - // Assign the memory for the failed constraints - if (myEquationsSystem.failed) - delete[] myEquationsSystem.failed; - myEquationsSystem.failed = new Slvs_hConstraint[theConstraints.size()]; - myEquationsSystem.faileds = theConstraints.size(); - } - - // Copy data - std::vector::const_iterator aConstrIter = theConstraints.begin(); - for (int i = 0; i < myEquationsSystem.constraints; i++, aConstrIter++) - myEquationsSystem.constraint[i] = *aConstrIter; + myEquationsSystem.constraint = theConstraints; + myEquationsSystem.constraints = theSize; } + int SketchSolver_Solver::solve() { if (myEquationsSystem.constraints <= 0) diff --git a/src/SketchSolver/SketchSolver_Solver.h b/src/SketchSolver/SketchSolver_Solver.h index 4a45b5253..bdc23ce28 100644 --- a/src/SketchSolver/SketchSolver_Solver.h +++ b/src/SketchSolver/SketchSolver_Solver.h @@ -28,6 +28,8 @@ typedef unsigned int UINT32; #define SLVS_C_FILLET 100100 // Unknown entity #define SLVS_E_UNKNOWN 0 +// Unknown group +#define SLVS_G_UNKNOWN 0 /** * The main class that performs the high-level operations for connection to the SolveSpace. @@ -46,25 +48,28 @@ class SketchSolver_Solver } /** \brief Change array of parameters - * \param[in] theParameters vector of parameters + * \param[in] theParameters pointer to the array of parameters + * \param[in] theSize size of this array */ - void setParameters(const std::vector& theParameters); + void setParameters(Slvs_Param* theParameters, int theSize); /** \brief Change array of entities - * \param[in] theEntities vector of entities + * \param[in] theEntities pointer to the array of entities + * \param[in] theSize size of this array */ - void setEntities(const std::vector& theEntities); + void setEntities(Slvs_Entity* theEntities, int theSize); /** \brief Change array of constraints - * \param[in] theConstraints vector of constraints + * \param[in] theConstraints pointer to the array of constraints + * \param[in] theSize size of this array */ - void setConstraints(const std::vector& theConstraints); + 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 std::vector& theDragged); + void setDraggedParameters(const Slvs_hParam* theDragged); /** \brief Solve the set of equations * \return identifier whether solution succeeded diff --git a/src/SketchSolver/SketchSolver_Storage.cpp b/src/SketchSolver/SketchSolver_Storage.cpp new file mode 100644 index 000000000..d56d98d85 --- /dev/null +++ b/src/SketchSolver/SketchSolver_Storage.cpp @@ -0,0 +1,343 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_Storage.cpp +// Created: 18 Mar 2015 +// Author: Artem ZHIDKOV + +#include + +/** \brief Search the entity/parameter with specified ID in the list of elements + * \param[in] theEntityID unique ID of the element + * \param[in] theEntities list of elements + * \return position of the found element or -1 if the element is not found + */ +template +static int Search(const uint32_t& theEntityID, const std::vector& theEntities); + +/// \brief Compare two parameters to be different +static bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2); +/// \brief Compare two entities to be different +static bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2); +/// \brief Compare two constriants to be different +static bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2); + + +SketchSolver_Storage::SketchSolver_Storage() + : myParamMaxID(SLVS_E_UNKNOWN), + myEntityMaxID(SLVS_E_UNKNOWN), + myConstrMaxID(SLVS_C_UNKNOWN), + myNeedToResolve(false) +{ +} + +Slvs_hParam SketchSolver_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 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()) { + myNeedToResolve = myNeedToResolve || IsNotEqual(myParameters[aPos], theParam); + myParameters[aPos] = theParam; + return theParam.h; + } + } + + // Parameter is not found, add new one + Slvs_Param aParam = theParam; + aParam.h = 0; + return addParameter(aParam); +} + +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); + myNeedToResolve = true; + myRemovedParameters.insert(theParamID); + return true; + } + return false; +} + +const Slvs_Param& SketchSolver_Storage::getParameter(const Slvs_hParam& theParamID) const +{ + int aPos = Search(theParamID, myParameters); + if (aPos >= 0 && aPos < (int)myParameters.size()) + return myParameters[aPos]; + + // Parameter is not found, return empty object + static Slvs_Param aDummy; + aDummy.h = 0; + return aDummy; +} + + +Slvs_hEntity SketchSolver_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 SketchSolver_Storage::updateEntity(const Slvs_Entity& theEntity) +{ + if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) { + // Entity already used, rewrite it + int aPos = Search(theEntity.h, myEntities); + if (aPos >= 0 && aPos < (int)myEntities.size()) { + myNeedToResolve = myNeedToResolve || IsNotEqual(myEntities[aPos], theEntity); + myEntities[aPos] = theEntity; + return theEntity.h; + } + } + + // Entity is not found, add new one + Slvs_Entity aEntity = theEntity; + aEntity.h = 0; + return addEntity(aEntity); +} + +bool SketchSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID) +{ + bool aResult = true; + int aPos = Search(theEntityID, myEntities); + if (aPos >= 0 && aPos < (int)myEntities.size()) { + // Firstly, check the entity 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->point[i] == theEntityID) + return false; + if (anEntIter->distance == theEntityID) + 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 (anEntIDs[i] == theEntityID) + return false; + } + // The entity is not used, remove it and its parameters + Slvs_Entity anEntity = myEntities[aPos]; + myEntities.erase(myEntities.begin() + aPos); + 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); + } + return aResult; +} + +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 = 0; + return aDummy; +} + + +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; + if (aConstraint.h > myConstrMaxID) + myConstrMaxID = aConstraint.h; + else + aConstraint.h = ++myConstrMaxID; + myConstraints.push_back(aConstraint); + myNeedToResolve = true; + return aConstraint.h; +} + +Slvs_hConstraint SketchSolver_Storage::updateConstraint(const Slvs_Constraint& theConstraint) +{ + if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) { + // Constraint already used, rewrite it + int aPos = Search(theConstraint.h, myConstraints); + if (aPos >= 0 && aPos < (int)myConstraints.size()) { + myNeedToResolve = myNeedToResolve || IsNotEqual(myConstraints[aPos], theConstraint); + myConstraints[aPos] = theConstraint; + return theConstraint.h; + } + } + + // Constraint is not found, add new one + Slvs_Constraint aConstraint = theConstraint; + aConstraint.h = 0; + return addConstraint(aConstraint); +} + +bool 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); + myNeedToResolve = true; + myRemovedConstraints.insert(theConstraintID); + // 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 points, if exists + std::vector::iterator aFPIt = myFixedPoints.begin(); + for (; aFPIt != myFixedPoints.end(); aFPIt++) + if (*aFPIt == anEntities[i]) { + myFixedPoints.erase(aFPIt); + break; + } + } + } + return aResult; +} + +const Slvs_Constraint& SketchSolver_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; +} + +void SketchSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID) +{ + int aPos = Search(theConstraintID, myConstraints); + myFixedPoints.push_back(myConstraints[aPos].ptA); +} + +void SketchSolver_Storage::getRemoved( + std::set& theParameters, + std::set& theEntities, + std::set& theConstraints) +{ + theParameters = myRemovedParameters; + theEntities = myRemovedEntities; + theConstraints = myRemovedConstraints; + + myRemovedParameters.clear(); + myRemovedEntities.clear(); + myRemovedConstraints.clear(); +} + +void SketchSolver_Storage::initializeSolver(SketchSolver_Solver& theSolver) +{ + theSolver.setParameters(myParameters.data(), (int)myParameters.size()); + theSolver.setEntities(myEntities.data(), (int)myEntities.size()); + theSolver.setConstraints(myConstraints.data(), (int)myConstraints.size()); + + // initialize fixed points + if (!myFixedPoints.empty()) { + int aPos = Search(myFixedPoints.front(), myEntities); + theSolver.setDraggedParameters(myEntities[aPos].param); + } +} + + +// ======================================================== +// ========= 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(); + while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID) + aResIndex--; + while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID) + aResIndex++; + if (aResIndex == -1) + 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 new file mode 100644 index 000000000..0317f930f --- /dev/null +++ b/src/SketchSolver/SketchSolver_Storage.h @@ -0,0 +1,121 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_Storage.h +// Created: 18 Mar 2015 +// Author: Artem ZHIDKOV + +#ifndef SketchSolver_Storage_H_ +#define SketchSolver_Storage_H_ + +#include "SketchSolver.h" +#include + +#include +#include +#include + +/** \class SketchSolver_Storage + * \ingroup Plugins + * \brief Contains all necessary data in SolveSpace format to solve a single group of constraints + */ +class SketchSolver_Storage +{ +public: + SketchSolver_Storage(); + + /** \brief Add new parameter to the current group + * \param[in] theParam SolveSpace parameter + * \return the ID of added parameter + */ + Slvs_hParam addParameter(const Slvs_Param& theParam); + /** \brief Updates parameter in the current group. If the ID of parameter is zero, the new item will be added + * \param[in] theParam SolveSpace parameter + * \return the ID of updated/added parameter + */ + Slvs_hParam updateParameter(const Slvs_Param& theParam); + /** \brief Removes the parameter by its ID + * \param[in] theParamID index of parameter to be removed + * \return \c true if the parameter was successfully removed + */ + bool removeParameter(const Slvs_hParam& theParamID); + /// \brief Returns the parameter by its ID + const Slvs_Param& getParameter(const Slvs_hParam& theParamID) const; + + /** \brief Add new entity to the current group + * \param[in] theEntity SolveSpace entity + * \return the ID of added entity + */ + Slvs_hEntity addEntity(const Slvs_Entity& theEntity); + /** \brief Updates entity in the current group. If the ID of entity is zero, the new item will be added + * \param[in] theEntity SolveSpace entity + * \return the ID of updated/added entity + */ + Slvs_hEntity updateEntity(const Slvs_Entity& theEntity); + /** \brief Removes the entity by its ID. All parameters used in this entity, + * and not used in other constraints, will be removed too. + * \param[in] theEntityID index of entity to be removed + * \return \c true if the entity was successfully removed + */ + bool removeEntity(const Slvs_hEntity& theEntityID); + /// \brief Returns the entity by its ID + const Slvs_Entity& getEntity(const Slvs_hEntity& theEntityID) const; + + /** \brief Add new constraint to the current group + * \param[in] theConstraint SolveSpace 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 Attach temporary constraint to this storage. It need to make precise calculations + void addTemporaryConstraint(const Slvs_hConstraint& theConstraintID); + + /// \brief Shows the sketch should be resolved + bool isNeedToResolve() const + { return myNeedToResolve; } + + /// \brief Changes the flag of group to be resolved + void setNeedToResolve(bool theFlag) + { myNeedToResolve = theFlag; } + + /// \brief Returns lists of removed elements + void getRemoved(std::set& theParameters, + std::set& theEntities, + std::set& theConstraints); + + /// \brief Initialize constraint solver by the entities collected by current storage + void initializeSolver(SketchSolver_Solver& theSolver); + +private: + 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 + 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 + Slvs_hConstraint myConstrMaxID; ///< current constraint index (may differs with the number of constraints) + std::vector myConstraints; ///< list of constraints used in the current group + + std::vector myFixedPoints; ///< identifiers of entities which relate to temporary constraints + + bool myNeedToResolve; ///< parameters are changed and group needs to be resolved + + 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) +}; + +typedef std::shared_ptr StoragePtr; + +#endif