X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_Constraint.cpp;h=4db4c4636bfcfa54936257b11bda9c9c28841d63;hb=953119363a54cbf70176287608a2099d74d98a51;hp=6d4fdee3330506efff1dc38bb4618042a4428e81;hpb=758a57d77b6fa3a0485fa3378a1280c7e87a74aa;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_Constraint.cpp b/src/SketchSolver/SketchSolver_Constraint.cpp index 6d4fdee33..4db4c4636 100644 --- a/src/SketchSolver/SketchSolver_Constraint.cpp +++ b/src/SketchSolver/SketchSolver_Constraint.cpp @@ -1,239 +1,745 @@ -// 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 + +SketchSolver_Constraint::SketchSolver_Constraint( + ConstraintPtr theConstraint) + : myBaseConstraint(theConstraint), + myGroup(0) +{ +} -/// Possible types of attributes (used to determine constraint type) -enum AttrType +SketchSolver_Constraint::~SketchSolver_Constraint() { - UNKNOWN, // Something wrong during type determination - POINT2D, - POINT3D, - LINE, - CIRCLE, - ARC -}; + 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); + } -/// Calculate type of the attribute -static AttrType typeOfAttribute(boost::shared_ptr theAttribute); + std::vector::const_iterator anIt4 = mySlvsConstraints.begin(); + for (; anIt4 != mySlvsConstraints.end(); anIt4++) + myStorage->removeConstraint(*anIt4); + mySlvsConstraints.clear(); +} -SketchSolver_Constraint::SketchSolver_Constraint() - : myConstraint(boost::shared_ptr()), - myType(SLVS_C_UNKNOWN), - myAttributesList() +void SketchSolver_Constraint::setStorage(StoragePtr theStorage) { + myStorage = theStorage; + process(); } -SketchSolver_Constraint::SketchSolver_Constraint( - boost::shared_ptr theConstraint) - : myConstraint(theConstraint), - myAttributesList() -{ - myType = getType(myConstraint); -} - -const int& SketchSolver_Constraint::getType( - boost::shared_ptr theConstraint) -{ - 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++) { - boost::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); +void SketchSolver_Constraint::setGroup(SketchSolver_Group* theGroup) +{ + 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; + + Slvs_hGroup aGroupID = myGroup->getId(); + Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId(); + Slvs_Constraint aConstraint; + if (mySlvsConstraints.empty()) + aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, aGroupID, aConstrType, aWorkplaneID, + aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]); + else { + aConstraint = myStorage->getConstraint(mySlvsConstraints[0]); + aConstraint.valA = aValue; + static const int aNbAttrs = 6; + Slvs_hEntity* aConstrAttrs[aNbAttrs] = { + &aConstraint.ptA, &aConstraint.ptB, + &aConstraint.entityA, &aConstraint.entityB, + &aConstraint.entityC, &aConstraint.entityD}; + std::vector::const_iterator anIter = anAttributes.begin(); + for (int i = 0; i < aNbAttrs && anIter != anAttributes.end(); i++, anIter++) + *(aConstrAttrs[i]) = *anIter; + } + + Slvs_hConstraint anID = myStorage->addConstraint(aConstraint); + if (mySlvsConstraints.empty()) + mySlvsConstraints.push_back(anID); + else + mySlvsConstraints[0] = anID; + adjustConstraint(); +} + +void SketchSolver_Constraint::update(ConstraintPtr theConstraint) +{ + cleanErrorMsg(); + bool needToRebuild = (theConstraint && theConstraint != myBaseConstraint); + if (!needToRebuild) { + // 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()); + if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end()) { + needToRebuild = true; + break; + } + } else if (aRefAttr->attr() && + myAttributeMap.find(aRefAttr->attr()) == myAttributeMap.end()) { + needToRebuild = true; 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(); - } - - // 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++) { - boost::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; + 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()) { + needToRebuild = true; + break; + } + } + if (needToRebuild) 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(); - } - - // 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++) { - boost::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(); - } - - // 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++) { - boost::shared_ptr anAttr = - aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)); - if (typeOfAttribute(anAttr) == LINE) - myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); - } - if (aNbEntities == 4) - myType = isParallel ? SLVS_C_PARALLEL : SLVS_C_PERPENDICULAR; - return getType(); - } - - // 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++) { - boost::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 (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++) { - boost::shared_ptr anAttr = - aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)); - AttrType aType = typeOfAttribute(anAttr); - if (aType != UNKNOWN) - myAttributesList[aNbAttrs++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr); - } - if (aNbAttrs == 1) - myType = SLVS_C_WHERE_DRAGGED; - return getType(); - } - - /// \todo Implement other kind of constraints - - return getType(); -} - -// ================= Auxiliary functions ============================== -AttrType typeOfAttribute(boost::shared_ptr theAttribute) -{ - boost::shared_ptr anAttrRef = boost::dynamic_pointer_cast< - ModelAPI_AttributeRefAttr>(theAttribute); - if (!anAttrRef) - return UNKNOWN; - - if (anAttrRef->isObject()) { - ResultConstructionPtr aRC = boost::dynamic_pointer_cast( - anAttrRef->object()); - if (!aRC || !aRC->shape()) - return UNKNOWN; - - if (aRC->shape()->isVertex()) - return POINT3D; - else if (aRC->shape()->isEdge()) { - boost::shared_ptr anEdge = boost::dynamic_pointer_cast( - aRC->shape()); - if (anEdge->isLine()) - return LINE; - else if (anEdge->isCircle()) - return CIRCLE; - else if (anEdge->isArc()) - return ARC; + } + if (needToRebuild) { + if (theConstraint && theConstraint->getKind() != myBaseConstraint->getKind()) + return; + remove(myBaseConstraint); + if (theConstraint) + myBaseConstraint = theConstraint; + process(); + return; + } + + // Update all attributes + int aType; + std::map aRelocationMap; + std::map::iterator aFeatIter = myFeatureMap.begin(); + for (; aFeatIter != myFeatureMap.end(); aFeatIter++) { + Slvs_hEntity aPrevID = aFeatIter->second; + aFeatIter->second = changeEntity(aFeatIter->first, aType); + if (aFeatIter->second != aPrevID) + aRelocationMap[aPrevID] = aFeatIter->second; + } + std::map::iterator anAttrIter = myAttributeMap.begin(); + for (; anAttrIter != myAttributeMap.end(); anAttrIter++) { + Slvs_hEntity aPrevID = anAttrIter->second; + anAttrIter->second = changeEntity(anAttrIter->first, aType); + if (anAttrIter->second != aPrevID) + aRelocationMap[aPrevID] = anAttrIter->second; + } + + // Value if exists + DataPtr aData = myBaseConstraint->data(); + if (!aData) return; + 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; + } + *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; +} + +void SketchSolver_Constraint::cleanRemovedEntities() +{ + std::set aRemovedParams; + std::set aRemovedEntities; + std::set aRemovedConstraints; + myStorage->getRemoved(aRemovedParams, aRemovedEntities, aRemovedConstraints); + std::map::iterator aFeatIt = myFeatureMap.begin(); + while (aFeatIt != myFeatureMap.end()) { + if (aRemovedEntities.find(aFeatIt->second) == aRemovedEntities.end()) { + aFeatIt++; + continue; + } + std::map::iterator aTmpIter = aFeatIt++; + myFeatureMap.erase(aTmpIter); + } + std::map::iterator anAttrIt = myAttributeMap.begin(); + while (anAttrIt != myAttributeMap.end()) { + if (aRemovedEntities.find(anAttrIt->second) == aRemovedEntities.end()) { + anAttrIt++; + continue; + } + std::map::iterator aTmpIter = anAttrIt++; + myAttributeMap.erase(aTmpIter); + } + std::map::iterator aValIt = myValueMap.begin(); + while (aValIt != myValueMap.end()) { + if (aRemovedParams.find(aValIt->second) == aRemovedParams.end()) { + aValIt++; + continue; + } + std::map::iterator aTmpIter = aValIt++; + myValueMap.erase(aTmpIter); + } +} + +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; + } + + 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++; + } + } +} + +Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributeRefAttrPtr theAttribute, int& theType) +{ + // Convert the object of the attribute to the feature + FeaturePtr aFeature; + if (theAttribute->isObject() && theAttribute->object()) { + ResultConstructionPtr aRC = std::dynamic_pointer_cast( + theAttribute->object()); + if (!aRC) { + myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); + return SLVS_E_UNKNOWN; } + std::shared_ptr aDoc = aRC->document(); + aFeature = aDoc->feature(aRC); + + return changeEntity(aFeature, theType); + } + + return changeEntity(theAttribute->attr(), theType); +} + +Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributePtr theEntity, int& theType) +{ + Slvs_hEntity aResult = SLVS_E_UNKNOWN; + if (!theEntity || !isInitialized(theEntity)) + return SLVS_E_UNKNOWN; + + // If the entity is already in the group, try to find it + std::map, Slvs_hEntity>::const_iterator anEntIter = + myAttributeMap.find(theEntity); + Slvs_Entity aCurrentEntity; + aCurrentEntity.h = SLVS_E_UNKNOWN; + if (anEntIter != myAttributeMap.end()) + aCurrentEntity = myStorage->getEntity(anEntIter->second); + else { + aResult = myGroup->getAttributeId(theEntity); + if (aResult != SLVS_E_UNKNOWN) { + Slvs_Entity anEnt = myStorage->getEntity(aResult); + theType = anEnt.type; + myAttributeMap[theEntity] = aResult; + return aResult; + } + } + + Slvs_hGroup aGroupID = myGroup->getId(); + // 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 { - const std::string aType = anAttrRef->attr()->attributeType(); - if (aType == GeomDataAPI_Point2D::type()) - return POINT2D; - if (aType == GeomDataAPI_Point2D::type()) - return POINT2D; + // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error + Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId(); + if (aWorkplaneID == SLVS_E_UNKNOWN) + return SLVS_E_UNKNOWN; + + // Point in 2D + std::shared_ptr aPoint2D = + std::dynamic_pointer_cast(theEntity); + if (aPoint2D) { + double aXY[2] = {aPoint2D->x(), aPoint2D->y()}; + Slvs_hParam aParams[2]; + for (int i = 0; i < 2; i++) { + Slvs_Param aPar = aCurrentEntity.h != SLVS_E_UNKNOWN ? + myStorage->getParameter(aCurrentEntity.param[i]) : + Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0); + aPar.val = aXY[i]; + aParams[i] = myStorage->addParameter(aPar); + } + + if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity + aCurrentEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aParams[0], aParams[1]); + else { // update entity data + for (int i = 0; i < 2; i++) + aCurrentEntity.param[i] = aParams[i]; + } + aResult = myStorage->addEntity(aCurrentEntity); + } else { + // Scalar value (used for the distance entities) + AttributeDoublePtr aScalar = std::dynamic_pointer_cast(theEntity); + if (aScalar) { + Slvs_Param aParam = aCurrentEntity.h != SLVS_E_UNKNOWN ? + myStorage->getParameter(aCurrentEntity.param[0]) : + Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0); + aParam.val = aScalar->value(); + Slvs_hParam aValue = myStorage->addParameter(aParam); + + if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity + aCurrentEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aValue); + else + aCurrentEntity.param[0] = aValue; + aResult = myStorage->addEntity(aCurrentEntity); + } + } + } + + myAttributeMap[theEntity] = aResult; + theType = aCurrentEntity.type; + return aResult; +} + +Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& theType) +{ + Slvs_hEntity aResult = SLVS_E_UNKNOWN; + if (!theEntity || !theEntity->data() || !theEntity->data()->isValid()) + return SLVS_E_UNKNOWN; + // If the entity is already in the group, try to find it + std::map::const_iterator anEntIter = myFeatureMap.find(theEntity); + Slvs_Entity aCurrentEntity; + aCurrentEntity.h = SLVS_E_UNKNOWN; + if (anEntIter != myFeatureMap.end()) + aCurrentEntity = myStorage->getEntity(anEntIter->second); + else { + aResult = myGroup->getFeatureId(theEntity); + if (aResult != SLVS_E_UNKNOWN) { + Slvs_Entity anEnt = myStorage->getEntity(aResult); + theType = anEnt.type; + myFeatureMap[theEntity] = aResult; + return aResult; + } } - return UNKNOWN; + 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; + } + aResult = myStorage->addEntity(aCurrentEntity); + } + // Arc + else if (aFeatureKind == SketchPlugin_Arc::ID()) { + anAttribute = aData->attribute(SketchPlugin_Arc::CENTER_ID()); + if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; + Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType); + + anAttribute = aData->attribute(SketchPlugin_Arc::START_ID()); + if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; + Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType); + + anAttribute = aData->attribute(SketchPlugin_Arc::END_ID()); + if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; + Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType); + + if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity + Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID); + aCurrentEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, + aWorkplane.normal, aCenter, aStart, aEnd); + } else { + aCurrentEntity.point[0] = aCenter; + aCurrentEntity.point[1] = aStart; + aCurrentEntity.point[2] = aEnd; + } + aResult = myStorage->addEntity(aCurrentEntity); + } + // Point (it has low probability to be an attribute of constraint, so it is checked at the end) + else if (aFeatureKind == SketchPlugin_Point::ID()) { + anAttribute = aData->attribute(SketchPlugin_Point::COORD_ID()); + if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN; + // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier + aResult = changeEntity(anAttribute, anAttrType); + aCurrentEntity.type = SLVS_E_POINT_IN_3D; + } + + if (aResult != SLVS_E_UNKNOWN) { + myFeatureMap[theEntity] = aResult; + theType = aCurrentEntity.type; + } + return aResult; +} + +std::list SketchSolver_Constraint::constraints() const +{ + std::list aConstraints; + aConstraints.push_back(myBaseConstraint); + return aConstraints; +} + +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; + } + 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) { + Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second); + 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_Entity anEntity = myStorage->getEntity(anAttrIter->second); + Slvs_Param aPar = myStorage->getParameter(anEntity.param[0]); + if (fabs(aScalar->value() - aPar.val) > tolerance) + aScalar->setValue(aPar.val); + } + } + } + } + + std::map::iterator aValIter = myValueMap.begin(); + for (; aValIter != myValueMap.end(); aValIter++) { + AttributeDoublePtr aScalar = + std::dynamic_pointer_cast(anAttrIter->first); + if (aScalar) { + Slvs_Param aPar = myStorage->getParameter(anAttrIter->second); + aScalar->setValue(aPar.val); + } + } +} + +Slvs_hEntity SketchSolver_Constraint::getId(FeaturePtr theFeature) const +{ + std::map::const_iterator aFIter = myFeatureMap.find(theFeature); + if (aFIter == myFeatureMap.end()) + return SLVS_E_UNKNOWN; + // check the Feature is really in the storage + Slvs_Entity anEntity = myStorage->getEntity(aFIter->second); + if (anEntity.h == SLVS_E_UNKNOWN) { + // rebuild feature + int aType; + anEntity.h = const_cast(this)->changeEntity(aFIter->first, aType); + const_cast(this)->myFeatureMap[theFeature] = anEntity.h; + } + return anEntity.h; +} + +Slvs_hEntity SketchSolver_Constraint::getId(AttributePtr theAttribute) const +{ + std::map::const_iterator anAttrIter = myAttributeMap.find(theAttribute); + if (anAttrIter == myAttributeMap.end()) + return SLVS_E_UNKNOWN; + return anAttrIter->second; +} + +bool SketchSolver_Constraint::isInitialized(AttributePtr theAttribute) +{ + if (theAttribute->isInitialized()) + return true; + myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); + return false; +} + + +void SketchSolver_Constraint::calculateMiddlePoint( + const Slvs_Entity& theEntity, double theCoeff, double& theX, double& theY) const +{ + if (theEntity.type == SLVS_E_LINE_SEGMENT) { + double aStartEndXY[2][2]; + Slvs_Entity aPoint; + for (int i = 0; i < 2; i++) { + aPoint = myStorage->getEntity(theEntity.point[i]); + for (int j = 0; j < 2; j++) + aStartEndXY[i][j] = myStorage->getParameter(aPoint.param[j]).val; + } + theX = (1.0 - theCoeff) * aStartEndXY[0][0] + theCoeff * aStartEndXY[1][0]; + theY = (1.0 - theCoeff) * aStartEndXY[0][1] + theCoeff * aStartEndXY[1][1]; + } else if (theEntity.type == SLVS_E_ARC_OF_CIRCLE) { + double anArcPoint[3][2]; + Slvs_Entity aPoint; + for (int i = 0; i < 3; i++) { + aPoint = myStorage->getEntity(theEntity.point[i]); + for (int j = 0; j < 2; j++) + anArcPoint[i][j] = myStorage->getParameter(aPoint.param[j]).val; + } + // project last point of arc on the arc + double x = anArcPoint[1][0] - anArcPoint[0][0]; + double y = anArcPoint[1][1] - anArcPoint[0][1]; + double aRad = sqrt(x*x + y*y); + x = anArcPoint[2][0] - anArcPoint[0][0]; + y = anArcPoint[2][1] - anArcPoint[0][1]; + double aNorm = sqrt(x*x + y*y); + if (aNorm >= tolerance) { + anArcPoint[2][0] = x * aRad / aNorm; + anArcPoint[2][1] = y * aRad / aNorm; + } + anArcPoint[1][0] -= anArcPoint[0][0]; + anArcPoint[1][1] -= anArcPoint[0][1]; + if (theCoeff < tolerance) { + theX = anArcPoint[0][0] + anArcPoint[1][0]; + theY = anArcPoint[0][1] + anArcPoint[1][1]; + return; + } else if (1 - theCoeff < tolerance) { + theX = anArcPoint[0][0] + anArcPoint[2][0]; + theY = anArcPoint[0][1] + anArcPoint[2][1]; + return; + } + + double xStart = anArcPoint[1][0] / aRad, xEnd = anArcPoint[2][0] / aRad; + double yStart = anArcPoint[1][1] / aRad, yEnd = anArcPoint[2][1] / aRad; + double aTanStart = abs(xStart) < tolerance ? yStart : yStart / xStart; + double aTanEnd = abs(xEnd) < tolerance ? yEnd : yEnd / xEnd; + double aCotStart = abs(yStart) < tolerance ? xStart : xStart / yStart; + double aCotEnd = abs(yEnd) < tolerance ? xEnd : xEnd / yEnd; + if (anArcPoint[1][0] * anArcPoint[2][0] < 0.0) { + if (anArcPoint[1][0] > 0.0) + yEnd = 2.0 - yEnd; + else + yStart = -2.0 - yStart; + } else { + if (aTanStart > aTanEnd) { + if (yStart > yEnd) { + yStart = 2.0 - yStart; + yEnd = -2.0 - yEnd; + } else { + yStart = -2.0 - yStart; + yEnd = 2.0 - yEnd; + } + } + } + if (anArcPoint[1][1] * anArcPoint[2][1] < 0.0) { + if (anArcPoint[1][1] > 0.0) + xEnd = 2.0 - xEnd; + else + xStart = -2.0 - xStart; + } else { + if (aCotStart < aCotEnd) { + if (xStart > xEnd) { + xStart = 2.0 - xStart; + xEnd = -2.0 - xEnd; + } else { + xStart = -2.0 - xStart; + xEnd = 2.0 - xEnd; + } + } + } + x = (1.0 - theCoeff) * xStart + theCoeff * xEnd; + y = (1.0 - theCoeff) * yStart + theCoeff * yEnd; + if (x > 1.0) x = 2.0 - x; + if (x < -1.0) x = -2.0 - x; + if (y > 1.0) y = 2.0 - y; + if (y < -1.0) y = -2.0 - y; + + aNorm = sqrt(x*x + y*y); + if (aNorm >= tolerance) { + x *= aRad / aNorm; + y *= aRad / aNorm; + } else { + 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; + } +} + +void SketchSolver_Constraint::makeTemporary() const +{ + std::vector::const_iterator anIt = mySlvsConstraints.begin(); + for (; anIt != mySlvsConstraints.end(); anIt++) + myStorage->addTemporaryConstraint(*anIt); }