X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_Constraint.cpp;h=c1d0558f4ec08054ba0ccacc19ee227503173e64;hb=07ff3c02f47a2efa7b51a661716262291fd5ccfd;hp=aed82cec5b1f2c16143eae40c737440f37c9322c;hpb=cd087e8e165c06c13e68aa8b1ecb162bfe630f34;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_Constraint.cpp b/src/SketchSolver/SketchSolver_Constraint.cpp index aed82cec5..c1d0558f4 100644 --- a/src/SketchSolver/SketchSolver_Constraint.cpp +++ b/src/SketchSolver/SketchSolver_Constraint.cpp @@ -1,332 +1,738 @@ -// 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 + +#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::iterator anIt3 = myFeatureMap.begin(); + while (!myFeatureMap.empty()) { + std::shared_ptr aFeature = + std::dynamic_pointer_cast(anIt3->first); + Slvs_hEntity anEnt = anIt3->second; + std::map::iterator aRemIt = anIt3++; + myFeatureMap.erase(aRemIt); + if (!myGroup->isInteract(aFeature)) + myStorage->removeEntity(anEnt); + } + + std::vector::const_iterator anIt4 = mySlvsConstraints.begin(); + for (; anIt4 != mySlvsConstraints.end(); anIt4++) + myStorage->removeConstraint(*anIt4); + mySlvsConstraints.clear(); } -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 == 3 && aPt3d == 0) || (aPt2d == 0 && aPt3d == 3)) - myType = SLVS_C_POINTS_COINCIDENT; - // Constraint parameters are wrong - return getType(); + myGroup = theGroup; + process(); +} + +void SketchSolver_Constraint::addFeature(FeaturePtr theFeature) +{ + int aType; + changeEntity(theFeature, aType); +} + + +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); + + int aConstrType = getType(); + double aValue = 0.0; + std::vector anAttributes; + getAttributes(aValue, anAttributes); + if (!myErrorMsg.empty()) + return; + if (aConstrType == SLVS_C_UNKNOWN) + aConstrType = getType(); + + Slvs_hGroup aGroupID = myGroup->getId(); + Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId(); + Slvs_Constraint aConstraint; + if (mySlvsConstraints.empty()) + aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, aGroupID, aConstrType, aWorkplaneID, + aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]); + else { + aConstraint = myStorage->getConstraint(mySlvsConstraints[0]); + aConstraint.valA = aValue; + static const int aNbAttrs = 6; + Slvs_hEntity* aConstrAttrs[aNbAttrs] = { + &aConstraint.ptA, &aConstraint.ptB, + &aConstraint.entityA, &aConstraint.entityB, + &aConstraint.entityC, &aConstraint.entityD}; + std::vector::const_iterator anIter = anAttributes.begin(); + for (int i = 0; i < aNbAttrs && anIter != anAttributes.end(); i++, anIter++) + *(aConstrAttrs[i]) = *anIter; } - // 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; + Slvs_hConstraint anID = myStorage->addConstraint(aConstraint); + if (mySlvsConstraints.empty()) + mySlvsConstraints.push_back(anID); + else + mySlvsConstraints[0] = anID; + adjustConstraint(); +} + +bool SketchSolver_Constraint::checkAttributesChanged(ConstraintPtr theConstraint) +{ + std::set aCurAttrs; // list of currently used attributes + std::vector::const_iterator aConstrIter = mySlvsConstraints.begin(); + for (; aConstrIter != mySlvsConstraints.end(); aConstrIter++) { + Slvs_Constraint aConstr = myStorage->getConstraint(*aConstrIter); + if (aConstr.ptA != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.ptA); + if (aConstr.ptB != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.ptB); + if (aConstr.entityA != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityA); + if (aConstr.entityB != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityB); + if (aConstr.entityC != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityC); + if (aConstr.entityD != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityD); + } + // Check the attrbutes of constraint are changed + ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint; + std::list anAttrList = aConstraint->data()->attributes(std::string()); + std::list::iterator anAttrIter = anAttrList.begin(); + for (; anAttrIter != anAttrList.end(); anAttrIter++) { + AttributeRefAttrPtr aRefAttr = + std::dynamic_pointer_cast(*anAttrIter); + if (aRefAttr) { + if (aRefAttr->isObject()) { + FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); + std::map::iterator aFIt = myFeatureMap.find(aFeature); + if (aFeature) { + if (aFIt == myFeatureMap.end()) + return true; + // Additional check the points of entity + if (aCurAttrs.find(aFIt->second) == aCurAttrs.end()) { + Slvs_Entity anEntity = myStorage->getEntity(aFIt->second); + bool isFound = false; + for (int i = 0; i < 4 && !isFound; i++) + if (anEntity.point[i] != SLVS_E_UNKNOWN && + aCurAttrs.find(anEntity.point[i]) != aCurAttrs.end()) + isFound = true; + if (!isFound) + return true; + } + } + } else if (aRefAttr->attr()) { + std::map::iterator anAIt = myAttributeMap.find(aRefAttr->attr()); + if (anAIt == myAttributeMap.end() || aCurAttrs.find(anAIt->second) == aCurAttrs.end()) + return true; + } + } + AttributeRefListPtr aRefList = + std::dynamic_pointer_cast(*anAttrIter); + if (aRefList) { + std::list anItems = aRefList->list(); + std::list::iterator anIt = anItems.begin(); + for (; anIt != anItems.end(); anIt++) { + FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt); + if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end()) + return true; } } - // 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(); + } + return false; +} + +void SketchSolver_Constraint::update(ConstraintPtr theConstraint) +{ + cleanErrorMsg(); + bool needToRebuild = (theConstraint && theConstraint != myBaseConstraint); + if (!needToRebuild) + needToRebuild = checkAttributesChanged(theConstraint); + if (needToRebuild) { + if (theConstraint && theConstraint->getKind() != myBaseConstraint->getKind()) + return; + remove(myBaseConstraint); + if (theConstraint) + myBaseConstraint = theConstraint; + process(); + return; } - // 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); + // Update all attributes + int aType; + std::map aRelocationMap; + std::map::iterator aFeatIter = myFeatureMap.begin(); + for (; aFeatIter != myFeatureMap.end(); aFeatIter++) { + Slvs_hEntity aPrevID = aFeatIter->second; + aFeatIter->second = changeEntity(aFeatIter->first, aType); + if (aFeatIter->second != aPrevID) + aRelocationMap[aPrevID] = aFeatIter->second; + } + std::map::iterator anAttrIter = myAttributeMap.begin(); + for (; anAttrIter != myAttributeMap.end(); anAttrIter++) { + Slvs_hEntity aPrevID = anAttrIter->second; + anAttrIter->second = changeEntity(anAttrIter->first, aType); + if (anAttrIter->second != aPrevID) + aRelocationMap[aPrevID] = anAttrIter->second; + } + + // Value if exists + DataPtr aData = myBaseConstraint->data(); + if (!aData) return; + AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast( + myBaseConstraint->attribute(SketchPlugin_Constraint::VALUE())); + double aValue = aValueAttr ? aValueAttr->value() : 0.0; + + // Update constraint + std::vector::iterator aCIter = mySlvsConstraints.begin(); + for (; aCIter != mySlvsConstraints.end(); aCIter++) { + Slvs_Constraint aConstraint = myStorage->getConstraint(*aCIter); + if (aValueAttr) + aConstraint.valA = aValue; + Slvs_hEntity* aCoeffs[6] = { + &aConstraint.ptA, &aConstraint.ptB, + &aConstraint.entityA, &aConstraint.entityB, + &aConstraint.entityC, &aConstraint.entityD}; + for (int i = 0; i < 6; i++) { + if (*(aCoeffs[i]) == SLVS_E_UNKNOWN) + continue; + std::map::iterator aFound = aRelocationMap.find(*(aCoeffs[i])); + if (aFound != aRelocationMap.end()) + *(aCoeffs[i]) = aFound->second; } - if (aNbLines == 1) - myType = SLVS_C_PT_PT_DISTANCE; - return getType(); + *aCIter = myStorage->addConstraint(aConstraint); } + adjustConstraint(); +} + +bool SketchSolver_Constraint::remove(ConstraintPtr theConstraint) +{ + cleanErrorMsg(); + if (theConstraint && theConstraint != myBaseConstraint) + return false; + if (mySlvsConstraints.empty()) + return true; + bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints.front()); + if (isFullyRemoved) { + myFeatureMap.clear(); + myAttributeMap.clear(); + myValueMap.clear(); + } else + cleanRemovedEntities(); + mySlvsConstraints.clear(); + return true; +} - // 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); +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); + } + for (size_t i = 0; i < mySlvsConstraints.size(); i++) + if (aRemovedConstraints.find(mySlvsConstraints[i]) != aRemovedConstraints.end()) { + mySlvsConstraints.erase(mySlvsConstraints.begin() + i); + i--; + } +} + +void SketchSolver_Constraint::getAttributes( + double& theValue, + std::vector& theAttributes) +{ + static const int anInitNbOfAttr = 4; + theAttributes.assign(anInitNbOfAttr, SLVS_E_UNKNOWN); + + DataPtr aData = myBaseConstraint->data(); + + 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; + } - // 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); + 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); + } + + return changeEntity(theAttribute->attr(), theType); +} + +Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributePtr theEntity, int& theType) +{ + Slvs_hEntity aResult = SLVS_E_UNKNOWN; + if (!theEntity || !isInitialized(theEntity)) { + myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); + return SLVS_E_UNKNOWN; } - // 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); + // If the entity is already in the group, try to find it + std::map, Slvs_hEntity>::const_iterator anEntIter = + myAttributeMap.find(theEntity); + Slvs_Entity aCurrentEntity; + aCurrentEntity.h = SLVS_E_UNKNOWN; + if (anEntIter != myAttributeMap.end()) + aCurrentEntity = myStorage->getEntity(anEntIter->second); + else { + aResult = myGroup->getAttributeId(theEntity); + if (aResult != SLVS_E_UNKNOWN) { + Slvs_Entity anEnt = myStorage->getEntity(aResult); + theType = anEnt.type; + myAttributeMap[theEntity] = aResult; + return aResult; } - 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]; } - else if (aType == CIRCLE || aType == ARC) - myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); + aResult = myStorage->addEntity(aCurrentEntity); + } else { + // Scalar value (used for the distance entities) + AttributeDoublePtr aScalar = std::dynamic_pointer_cast(theEntity); + if (aScalar) { + Slvs_Param aParam = aCurrentEntity.h != SLVS_E_UNKNOWN ? + myStorage->getParameter(aCurrentEntity.param[0]) : + Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0); + aParam.val = aScalar->value(); + Slvs_hParam aValue = myStorage->addParameter(aParam); + + if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity + aCurrentEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aValue); + else + aCurrentEntity.param[0] = aValue; + aResult = myStorage->addEntity(aCurrentEntity); + } + } + } + + myAttributeMap[theEntity] = aResult; + theType = aCurrentEntity.type; + return aResult; +} + +Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& theType) +{ + Slvs_hEntity aResult = SLVS_E_UNKNOWN; + if (!theEntity || !theEntity->data() || !theEntity->data()->isValid()) + return SLVS_E_UNKNOWN; + // If the entity is already in the group, try to find it + std::map::const_iterator anEntIter = myFeatureMap.find(theEntity); + Slvs_Entity aCurrentEntity; + aCurrentEntity.h = SLVS_E_UNKNOWN; + if (anEntIter != myFeatureMap.end()) + aCurrentEntity = myStorage->getEntity(anEntIter->second); + else { + aResult = myGroup->getFeatureId(theEntity); + if (aResult != SLVS_E_UNKNOWN) { + Slvs_Entity anEnt = myStorage->getEntity(aResult); + theType = anEnt.type; + myFeatureMap[theEntity] = aResult; + return aResult; + } + } + + Slvs_hGroup aGroupID = myGroup->getId(); + Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId(); + DataPtr aData = theEntity->data(); + + // SketchPlugin features + const std::string& aFeatureKind = theEntity->getKind(); + AttributePtr anAttribute; + int anAttrType; + // Line + if (aFeatureKind == SketchPlugin_Line::ID()) { + anAttribute = aData->attribute(SketchPlugin_Line::START_ID()); + if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; + Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType); + + anAttribute = aData->attribute(SketchPlugin_Line::END_ID()); + if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; + Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType); + + if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity + aCurrentEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aStart, aEnd); + else { + aCurrentEntity.point[0] = aStart; + aCurrentEntity.point[1] = aEnd; + } + aResult = myStorage->addEntity(aCurrentEntity); + } + // Circle + else if (aFeatureKind == SketchPlugin_Circle::ID()) { + anAttribute = aData->attribute(SketchPlugin_Circle::CENTER_ID()); + if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; + Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType); + + anAttribute = aData->attribute(SketchPlugin_Circle::RADIUS_ID()); + if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; + Slvs_hEntity aRadius = changeEntity(anAttribute, anAttrType); + + if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity + Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID); + aCurrentEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, + aCenter, aWorkplane.normal, aRadius); + } else { + aCurrentEntity.point[0] = aCenter; + aCurrentEntity.distance = aRadius; } - if (aNbEntities == 4) - myType = aConstrType[aNbLines]; - return getType(); + aResult = myStorage->addEntity(aCurrentEntity); } + // Arc + else if (aFeatureKind == SketchPlugin_Arc::ID()) { + anAttribute = aData->attribute(SketchPlugin_Arc::CENTER_ID()); + if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; + Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType); + + anAttribute = aData->attribute(SketchPlugin_Arc::START_ID()); + if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; + Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType); + + anAttribute = aData->attribute(SketchPlugin_Arc::END_ID()); + if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; + Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType); - if (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); + 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; } - if (anArcPos - anArcPosDefault + aLinePos - aLinePosDefault == 2) - myType = aLinePos > 3 ? SLVS_C_ARC_LINE_TANGENT : SLVS_C_CURVE_CURVE_TANGENT; - return getType(); + aResult = myStorage->addEntity(aCurrentEntity); } + // Point (it has low probability to be an attribute of constraint, so it is checked at the end) + else if (aFeatureKind == SketchPlugin_Point::ID()) { + anAttribute = aData->attribute(SketchPlugin_Point::COORD_ID()); + if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; + // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier + aResult = changeEntity(anAttribute, anAttrType); + aCurrentEntity.type = SLVS_E_POINT_IN_3D; + } + + if (aResult != SLVS_E_UNKNOWN) { + myFeatureMap[theEntity] = aResult; + theType = aCurrentEntity.type; + } + return aResult; +} - 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); +std::list SketchSolver_Constraint::constraints() const +{ + std::list aConstraints; + aConstraints.push_back(myBaseConstraint); + return aConstraints; +} + +void SketchSolver_Constraint::refresh() +{ + cleanErrorMsg(); + std::map::iterator anAttrIter = myAttributeMap.begin(); + while (anAttrIter != myAttributeMap.end()) { + std::shared_ptr aPoint = + std::dynamic_pointer_cast(anAttrIter->first); + Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second); + if (anEntity.h == SLVS_E_UNKNOWN) { + std::map::iterator aTmpIter = anAttrIter++; + myAttributeMap.erase(aTmpIter); + continue; + } + if (aPoint) { + double aXYZ[3]; + for (int i = 0; i < 3; i++) { + Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]); + aXYZ[i] = aPar.val; } - else { - std::shared_ptr anAttr = - aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)); - if (typeOfAttribute(anAttr) == LINE) { - hasMirrorLine = !hasMirrorLine; - myAttributesList[0] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); + if (fabs(aPoint->x() - aXYZ[0]) > tolerance || + fabs(aPoint->y() - aXYZ[1]) > tolerance || + fabs(aPoint->z() - aXYZ[2]) > tolerance) + aPoint->setValue(aXYZ[0], aXYZ[1], aXYZ[2]); + } else { + // Point in 2D + std::shared_ptr aPoint2D = + std::dynamic_pointer_cast(anAttrIter->first); + if (aPoint2D) { + double aXY[2]; + for (int i = 0; i < 2; i++) { + Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]); + aXY[i] = aPar.val; + } + if (fabs(aPoint2D->x() - aXY[0]) > tolerance || + fabs(aPoint2D->y() - aXY[1]) > tolerance) + aPoint2D->setValue(aXY[0], aXY[1]); + } else { + // Scalar value (used for the distance entities) + AttributeDoublePtr aScalar = + std::dynamic_pointer_cast(anAttrIter->first); + if (aScalar) { + Slvs_Param aPar = myStorage->getParameter(anEntity.param[0]); + if (fabs(aScalar->value() - aPar.val) > tolerance) + aScalar->setValue(aPar.val); } } } - if (aNbAttrs == 2 && hasMirrorLine) - myType = SLVS_C_SYMMETRIC_LINE; - return getType(); + anAttrIter++; + } + + std::map::iterator aValIter = myValueMap.begin(); + for (; aValIter != myValueMap.end(); aValIter++) { + AttributeDoublePtr aScalar = + std::dynamic_pointer_cast(anAttrIter->first); + if (aScalar) { + Slvs_Param aPar = myStorage->getParameter(anAttrIter->second); + aScalar->setValue(aPar.val); + } } +} - /// \todo Implement other kind of constraints +Slvs_hEntity SketchSolver_Constraint::getId(FeaturePtr theFeature) const +{ + std::map::const_iterator aFIter = myFeatureMap.find(theFeature); + if (aFIter == myFeatureMap.end()) + return SLVS_E_UNKNOWN; + // check the Feature is really in the storage + Slvs_Entity anEntity = myStorage->getEntity(aFIter->second); + if (anEntity.h == SLVS_E_UNKNOWN) { + // rebuild feature + int aType; + anEntity.h = const_cast(this)->changeEntity(aFIter->first, aType); + const_cast(this)->myFeatureMap[theFeature] = anEntity.h; + } + return anEntity.h; +} - return getType(); +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; } -// ================= Auxiliary functions ============================== -AttrType typeOfAttribute(std::shared_ptr theAttribute) +bool SketchSolver_Constraint::isInitialized(AttributePtr theAttribute) { - std::shared_ptr anAttrRef = std::dynamic_pointer_cast< - ModelAPI_AttributeRefAttr>(theAttribute); - if (!anAttrRef) - return UNKNOWN; + if (theAttribute->isInitialized()) + return true; + myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); + return false; +} - 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::calculateMiddlePoint( + const Slvs_Entity& theEntity, double theCoeff, double& theX, double& theY) const +{ + if (theEntity.type == SLVS_E_LINE_SEGMENT) { + double aStartEndXY[2][2]; + Slvs_Entity aPoint; + for (int i = 0; i < 2; i++) { + aPoint = myStorage->getEntity(theEntity.point[i]); + for (int j = 0; j < 2; j++) + aStartEndXY[i][j] = myStorage->getParameter(aPoint.param[j]).val; } - } else { - if (anAttrRef->attr().get() != NULL) { - const std::string aType = anAttrRef->attr()->attributeType(); - if (aType == GeomDataAPI_Point2D::type()) - return POINT2D; - if (aType == GeomDataAPI_Point2D::type()) - return POINT2D; + theX = (1.0 - theCoeff) * aStartEndXY[0][0] + theCoeff * aStartEndXY[1][0]; + theY = (1.0 - theCoeff) * aStartEndXY[0][1] + theCoeff * aStartEndXY[1][1]; + } else if (theEntity.type == SLVS_E_ARC_OF_CIRCLE) { + double anArcPoint[3][2]; + Slvs_Entity aPoint; + for (int i = 0; i < 3; i++) { + aPoint = myStorage->getEntity(theEntity.point[i]); + for (int j = 0; j < 2; j++) + anArcPoint[i][j] = myStorage->getParameter(aPoint.param[j]).val; + } + // project last point of arc on the arc + double x = anArcPoint[1][0] - anArcPoint[0][0]; + double y = anArcPoint[1][1] - anArcPoint[0][1]; + double aRad = sqrt(x*x + y*y); + x = anArcPoint[2][0] - anArcPoint[0][0]; + y = anArcPoint[2][1] - anArcPoint[0][1]; + double aNorm = sqrt(x*x + y*y); + if (aNorm >= tolerance) { + anArcPoint[2][0] = x * aRad / aNorm; + anArcPoint[2][1] = y * aRad / aNorm; } + anArcPoint[1][0] -= anArcPoint[0][0]; + anArcPoint[1][1] -= anArcPoint[0][1]; + if (theCoeff < tolerance) { + theX = anArcPoint[0][0] + anArcPoint[1][0]; + theY = anArcPoint[0][1] + anArcPoint[1][1]; + return; + } else if (1 - theCoeff < tolerance) { + theX = anArcPoint[0][0] + anArcPoint[2][0]; + theY = anArcPoint[0][1] + anArcPoint[2][1]; + return; + } + + std::shared_ptr aStartDir(new GeomAPI_Dir2d(anArcPoint[1][0], anArcPoint[1][1])); + std::shared_ptr aEndDir(new GeomAPI_Dir2d(anArcPoint[2][0], anArcPoint[2][1])); + double anAngle = aStartDir->angle(aEndDir); + if (anAngle < 0) + anAngle += 2.0 * PI; + anAngle *= theCoeff; + double aCos = cos(anAngle); + double aSin = sin(anAngle); + theX = anArcPoint[0][0] + anArcPoint[1][0] * aCos - anArcPoint[1][1] * aSin; + theY = anArcPoint[0][1] + anArcPoint[1][0] * aSin + anArcPoint[1][1] * aCos; } +} - return UNKNOWN; +void SketchSolver_Constraint::makeTemporary() const +{ + std::vector::const_iterator anIt = mySlvsConstraints.begin(); + for (; anIt != mySlvsConstraints.end(); anIt++) + myStorage->addTemporaryConstraint(*anIt); }