X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_Storage.cpp;h=485b81565d8b36e2a9be596183def9c678c0c357;hb=ec6769ca1253d91c847027b5d36c800d9b5ed793;hp=2dca4423378b43407226d1eea5960a22c6d3fd4b;hpb=acb9886de0517b73ad1af225186192f8b906fe55;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_Storage.cpp b/src/SketchSolver/SketchSolver_Storage.cpp index 2dca44233..485b81565 100644 --- a/src/SketchSolver/SketchSolver_Storage.cpp +++ b/src/SketchSolver/SketchSolver_Storage.cpp @@ -6,6 +6,8 @@ #include +#include +#include #include /** \brief Search the entity/parameter with specified ID in the list of elements @@ -57,7 +59,8 @@ Slvs_hParam SketchSolver_Storage::updateParameter(const Slvs_Param& theParam) // parameter already used, rewrite it int aPos = Search(theParam.h, myParameters); if (aPos >= 0 && aPos < (int)myParameters.size()) { - myNeedToResolve = myNeedToResolve || IsNotEqual(myParameters[aPos], theParam); + if (IsNotEqual(myParameters[aPos], theParam)) + myUpdatedParameters.insert(theParam.h); myParameters[aPos] = theParam; return theParam.h; } @@ -187,6 +190,108 @@ bool SketchSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID) return aResult; } +void SketchSolver_Storage::removeUnusedEntities() +{ + std::set anUnusedEntities; + std::vector::const_iterator aEIt = myEntities.begin(); + for (; aEIt != myEntities.end(); ++aEIt) { + if (aEIt->h == aEIt->wrkpl) { + // don't remove workplane + anUnusedEntities.erase(aEIt->point[0]); + anUnusedEntities.erase(aEIt->normal); + continue; + } + anUnusedEntities.insert(aEIt->h); + } + + std::vector::const_iterator aCIt = myConstraints.begin(); + for (; aCIt != myConstraints.end(); ++aCIt) { + Slvs_hEntity aSubs[6] = { + aCIt->entityA, aCIt->entityB, + aCIt->entityC, aCIt->entityD, + aCIt->ptA, aCIt->ptB}; + for (int i = 0; i < 6; i++) { + if (aSubs[i] != SLVS_E_UNKNOWN) { + anUnusedEntities.erase(aSubs[i]); + int aPos = Search(aSubs[i], myEntities); + if (aPos >= 0 && aPos < (int)myEntities.size()) { + for (int j = 0; j < 4; j++) + if (myEntities[aPos].point[j] != SLVS_E_UNKNOWN) + anUnusedEntities.erase(myEntities[aPos].point[j]); + if (myEntities[aPos].distance != SLVS_E_UNKNOWN) + anUnusedEntities.erase(myEntities[aPos].distance); + } + } + } + } + + std::set::const_iterator anEntIt = anUnusedEntities.begin(); + while (anEntIt != anUnusedEntities.end()) { + int aPos = Search(*anEntIt, myEntities); + if (aPos < 0 && aPos >= (int)myEntities.size()) + continue; + Slvs_Entity anEntity = myEntities[aPos]; + // Remove entity if and only if all its parameters unused + bool isUsed = false; + if (anEntity.distance != SLVS_E_UNKNOWN && + anUnusedEntities.find(anEntity.distance) == anUnusedEntities.end()) + isUsed = true; + for (int i = 0; i < 4 && !isUsed; i++) + if (anEntity.point[i] != SLVS_E_UNKNOWN && + anUnusedEntities.find(anEntity.point[i]) == anUnusedEntities.end()) + isUsed = true; + if (isUsed) { + anUnusedEntities.erase(anEntity.distance); + for (int i = 0; i < 4; i++) + if (anEntity.point[i] != SLVS_E_UNKNOWN) + anUnusedEntities.erase(anEntity.point[i]); + std::set::iterator aRemoveIt = anEntIt++; + anUnusedEntities.erase(aRemoveIt); + continue; + } + ++anEntIt; + } + + for (anEntIt = anUnusedEntities.begin(); anEntIt != anUnusedEntities.end(); ++anEntIt) { + int aPos = Search(*anEntIt, myEntities); + if (aPos >= 0 && aPos < (int)myEntities.size()) { + // Remove entity and its parameters + Slvs_Entity anEntity = myEntities[aPos]; + myEntities.erase(myEntities.begin() + aPos); + myEntityMaxID = myEntities.empty() ? SLVS_E_UNKNOWN : myEntities.back().h; + if (anEntity.distance != SLVS_E_UNKNOWN) + removeParameter(anEntity.distance); + for (int i = 0; i < 4; i++) + if (anEntity.param[i] != SLVS_E_UNKNOWN) + removeParameter(anEntity.param[i]); + for (int i = 0; i < 4; i++) + if (anEntity.point[i] != SLVS_E_UNKNOWN) + removeEntity(anEntity.point[i]); + myRemovedEntities.insert(*anEntIt); + if (anEntity.type == SLVS_E_POINT_IN_2D || anEntity.type == SLVS_E_POINT_IN_3D) + removeCoincidentPoint(*anEntIt); + } + } + + if (!anUnusedEntities.empty()) + myNeedToResolve = true; +} + +bool SketchSolver_Storage::isUsedByConstraints(const Slvs_hEntity& theEntityID) const +{ + std::vector::const_iterator aCIt = myConstraints.begin(); + for (; aCIt != myConstraints.end(); ++aCIt) { + Slvs_hEntity aSubs[6] = { + aCIt->entityA, aCIt->entityB, + aCIt->entityC, aCIt->entityD, + aCIt->ptA, aCIt->ptB}; + for (int i = 0; i < 6; i++) + if (aSubs[i] != SLVS_E_UNKNOWN && aSubs[i] == theEntityID) + return true; + } + return false; +} + const Slvs_Entity& SketchSolver_Storage::getEntity(const Slvs_hEntity& theEntityID) const { int aPos = Search(theEntityID, myEntities); @@ -613,7 +718,7 @@ void SketchSolver_Storage::initializeSolver(SketchSolver_Solver& theSolver) for (; anIt != aConstraints.end(); anIt++) if (anIt->h == myFixed) { aFixedPoint = anIt->ptA; - aConstraints.erase(anIt); +// aConstraints.erase(anIt); break; } // set dragged parameters @@ -641,7 +746,8 @@ void SketchSolver_Storage::addCoincidentPoints( aFoundIter->insert(aCIter->begin(), aCIter->end()); myCoincidentPoints.erase(aCIter); break; - } + } else + aFoundIter = aCIter; aCIter->insert(thePoint1); aCIter->insert(thePoint2); } @@ -674,7 +780,16 @@ bool SketchSolver_Storage::isCoincident( for (; aCIter != myCoincidentPoints.end(); aCIter++) if (aCIter->find(thePoint1) != aCIter->end() && aCIter->find(thePoint2) != aCIter->end()) return true; - // precise checking of coincidence + return false; +} + +bool SketchSolver_Storage::isEqual( + const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const +{ + if (isCoincident(thePoint1, thePoint2)) + return true; + + // Precise checking of coincidence: verify that points have equal coordinates int aEnt1Pos = Search(thePoint1, myEntities); int aEnt2Pos = Search(thePoint2, myEntities); if (aEnt1Pos >= 0 && aEnt1Pos < (int)myEntities.size() && @@ -694,6 +809,323 @@ bool SketchSolver_Storage::isCoincident( } +std::vector SketchSolver_Storage::fixEntity(const Slvs_hEntity& theEntity) +{ + std::vector aNewConstraints; + + int aPos = Search(theEntity, myEntities); + if (aPos >= 0 && aPos < (int)myEntities.size()) { + switch (myEntities[aPos].type) { + case SLVS_E_POINT_IN_2D: + case SLVS_E_POINT_IN_3D: + fixPoint(myEntities[aPos], aNewConstraints); + break; + case SLVS_E_LINE_SEGMENT: + fixLine(myEntities[aPos], aNewConstraints); + break; + case SLVS_E_CIRCLE: + fixCircle(myEntities[aPos], aNewConstraints); + break; + case SLVS_E_ARC_OF_CIRCLE: + fixArc(myEntities[aPos], aNewConstraints); + break; + default: + break; + } + } + + return aNewConstraints; +} + +void SketchSolver_Storage::fixPoint(const Slvs_Entity& thePoint, + std::vector& theCreated) +{ + Slvs_Constraint aConstraint; + Slvs_hConstraint aConstrID = SLVS_E_UNKNOWN; + bool isFixed = isPointFixed(thePoint.h, aConstrID, true); + bool isForceUpdate = (isFixed && isTemporary(aConstrID)); + if (!isForceUpdate) { // create new constraint + if (isFixed) return; + aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, thePoint.group, SLVS_C_WHERE_DRAGGED, thePoint.wrkpl, + 0.0, thePoint.h, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); + aConstraint.h = addConstraint(aConstraint); + theCreated.push_back(aConstraint.h); + } else { // update already existent constraint + if (!isFixed || aConstrID == SLVS_E_UNKNOWN) + return; + int aPos = Search(aConstrID, myConstraints); + if (aPos >= 0 && aPos < (int)myConstraints.size()) + myConstraints[aPos].ptA = thePoint.h; + } +} + +void SketchSolver_Storage::fixLine(const Slvs_Entity& theLine, + std::vector& theCreated) +{ + Slvs_Entity aPoint[2] = { + getEntity(theLine.point[0]), + getEntity(theLine.point[1]) + }; + + Slvs_Constraint anEqual; + if (isAxisParallel(theLine.h)) { + // Fix one point and a line length + Slvs_hConstraint aFixed; + if (!isPointFixed(theLine.point[0], aFixed, true) && + !isPointFixed(theLine.point[1], aFixed, true)) + fixPoint(aPoint[0], theCreated); + if (!isUsedInEqual(theLine.h, anEqual)) { + // Check the distance is not set yet + std::vector::const_iterator aDistIt = myConstraints.begin(); + for (; aDistIt != myConstraints.end(); ++aDistIt) + if ((aDistIt->type == SLVS_C_PT_PT_DISTANCE) && + ((aDistIt->ptA == theLine.point[0] && aDistIt->ptB == theLine.point[1]) || + (aDistIt->ptA == theLine.point[1] && aDistIt->ptB == theLine.point[0]))) + return; + // Calculate distance between points on the line + double aCoords[4]; + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) { + Slvs_Param aParam = getParameter(aPoint[i].param[j]); + aCoords[2*i+j] = aParam.val; + } + + double aLength = sqrt((aCoords[2] - aCoords[0]) * (aCoords[2] - aCoords[0]) + + (aCoords[3] - aCoords[1]) * (aCoords[3] - aCoords[1])); + // fix line length + Slvs_Constraint aDistance = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theLine.group, + SLVS_C_PT_PT_DISTANCE, theLine.wrkpl, aLength, + theLine.point[0], theLine.point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); + aDistance.h = addConstraint(aDistance); + theCreated.push_back(aDistance.h); + } + return; + } + else if (isUsedInEqual(theLine.h, anEqual)) { + // Check another entity of Equal is already fixed + Slvs_hEntity anOtherEntID = anEqual.entityA == theLine.h ? anEqual.entityB : anEqual.entityA; + if (isEntityFixed(anOtherEntID, true)) { + // Fix start point of the line (if end point is not fixed yet) ... + Slvs_hConstraint anEndFixedID = SLVS_E_UNKNOWN; + bool isFixed = isPointFixed(theLine.point[1], anEndFixedID, true); + if (isFixed == SLVS_E_UNKNOWN) + fixPoint(aPoint[0], theCreated); + // ... and create fixed point lying on this line + Slvs_hEntity aPointToCopy = anEndFixedID == SLVS_E_UNKNOWN ? theLine.point[1] : theLine.point[0]; + // Firstly, search already fixed point on line + bool isPonLineFixed = false; + Slvs_hEntity aFixedPoint; + std::vector::const_iterator aPLIter = myConstraints.begin(); + for (; aPLIter != myConstraints.end() && !isPonLineFixed; ++aPLIter) + if (aPLIter->type == SLVS_C_PT_ON_LINE && aPLIter->entityA == theLine.h) { + isPonLineFixed = isPointFixed(aPLIter->ptA, anEndFixedID); + aFixedPoint = aPLIter->ptA; + } + + if (isPonLineFixed) { // update existent constraint + copyEntity(aPointToCopy, aFixedPoint); + } else { // create new constraint + Slvs_hEntity aCopied = copyEntity(aPointToCopy); + Slvs_Constraint aPonLine = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theLine.group, SLVS_C_PT_ON_LINE, + theLine.wrkpl, 0.0, aCopied, SLVS_E_UNKNOWN, theLine.h, SLVS_E_UNKNOWN); + aPonLine.h = addConstraint(aPonLine); + theCreated.push_back(aPonLine.h); + fixPoint(getEntity(aCopied), theCreated); + } + return; + } + } + + // Fix both points + for (int i = 0; i < 2; i++) + fixPoint(aPoint[i], theCreated); +} + +void SketchSolver_Storage::fixCircle(const Slvs_Entity& theCircle, + std::vector& theCreated) +{ + bool isFixRadius = true; + // Verify the arc is under Equal constraint + Slvs_Constraint anEqual; + if (isUsedInEqual(theCircle.h, anEqual)) { + // Check another entity of Equal is already fixed + Slvs_hEntity anOtherEntID = anEqual.entityA == theCircle.h ? anEqual.entityB : anEqual.entityA; + if (isEntityFixed(anOtherEntID, true)) + isFixRadius = false; + } + + fixPoint(getEntity(theCircle.point[0]), theCreated); + + if (isFixRadius) { + // Search the radius is already fixed + std::vector::const_iterator aDiamIter = myConstraints.begin(); + for (; aDiamIter != myConstraints.end(); ++aDiamIter) + if (aDiamIter->type == SLVS_C_DIAMETER && aDiamIter->entityA == theCircle.h) + return; + + // Fix radius of a circle + const Slvs_Entity& aRadEnt = getEntity(theCircle.distance); + double aRadius = getParameter(aRadEnt.param[0]).val; + Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theCircle.group, SLVS_C_DIAMETER, + theCircle.wrkpl, aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, theCircle.h, SLVS_E_UNKNOWN); + aFixedR.h = addConstraint(aFixedR); + theCreated.push_back(aFixedR.h); + } +} + +void SketchSolver_Storage::fixArc(const Slvs_Entity& theArc, + std::vector& theCreated) +{ + Slvs_Entity aPoint[3] = { + getEntity(theArc.point[0]), + getEntity(theArc.point[1]), + getEntity(theArc.point[2]) + }; + + bool isFixRadius = true; + std::list aPointsToFix; + aPointsToFix.push_back(aPoint[1]); + aPointsToFix.push_back(aPoint[2]); + + // Verify the arc is under Equal constraint + Slvs_Constraint anEqual; + if (isUsedInEqual(theArc.h, anEqual)) { + // Check another entity of Equal is already fixed + Slvs_hEntity anOtherEntID = anEqual.entityA == theArc.h ? anEqual.entityB : anEqual.entityA; + if (isEntityFixed(anOtherEntID, true)) { + isFixRadius = false; + Slvs_Entity anOtherEntity = getEntity(anOtherEntID); + if (anOtherEntity.type == SLVS_E_LINE_SEGMENT) { + aPointsToFix.pop_back(); + aPointsToFix.push_back(aPoint[0]); + } + } + } + + Slvs_hConstraint aConstrID; + int aNbPointsToFix = 2; // number of fixed points for the arc + if (isPointFixed(theArc.point[0], aConstrID, true)) + aNbPointsToFix--; + + double anArcPoints[3][2]; + for (int i = 0; i < 3; i++) { + const Slvs_Entity& aPointOnArc = getEntity(theArc.point[i]); + for (int j = 0; j < 2; j++) + anArcPoints[i][j] = getParameter(aPointOnArc.param[j]).val; + } + + // Radius of the arc + std::shared_ptr aCenter(new GeomAPI_Pnt2d(anArcPoints[0][0], anArcPoints[0][1])); + std::shared_ptr aStart(new GeomAPI_Pnt2d(anArcPoints[1][0], anArcPoints[1][1])); + double aRadius = aCenter->distance(aStart); + + // Update end point of the arc to be on a curve + std::shared_ptr anEnd(new GeomAPI_Pnt2d(anArcPoints[2][0], anArcPoints[2][1])); + double aDistance = anEnd->distance(aCenter); + std::shared_ptr aDir = anEnd->xy()->decreased(aCenter->xy()); + if (aDistance < tolerance) + aDir = aStart->xy()->decreased(aCenter->xy())->multiplied(-1.0); + else + aDir = aDir->multiplied(aRadius / aDistance); + double xy[2] = {aCenter->x() + aDir->x(), aCenter->y() + aDir->y()}; + const Slvs_Entity& aEndPoint = getEntity(theArc.point[2]); + for (int i = 0; i < 2; i++) { + Slvs_Param aParam = getParameter(aEndPoint.param[i]); + aParam.val = xy[i]; + updateParameter(aParam); + } + + std::list::iterator aPtIt = aPointsToFix.begin(); + for (; aNbPointsToFix > 0; aPtIt++, aNbPointsToFix--) + fixPoint(*aPtIt, theCreated); + + if (isFixRadius) { + // Fix radius of the arc + bool isExists = false; + std::vector::iterator anIt = myConstraints.begin(); + for (; anIt != myConstraints.end() && !isExists; ++anIt) + if (anIt->type == SLVS_C_DIAMETER && anIt->entityA == theArc.h) + isExists = true; + if (!isExists) { + Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theArc.group, SLVS_C_DIAMETER, + theArc.wrkpl, aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, theArc.h, SLVS_E_UNKNOWN); + aFixedR.h = addConstraint(aFixedR); + theCreated.push_back(aFixedR.h); + } + } +} + + +bool SketchSolver_Storage::isAxisParallel(const Slvs_hEntity& theEntity) const +{ + std::vector::const_iterator anIter = myConstraints.begin(); + for (; anIter != myConstraints.end(); anIter++) + if ((anIter->type == SLVS_C_HORIZONTAL || anIter->type == SLVS_C_VERTICAL) && + anIter->entityA == theEntity) + return true; + return false; +} + +bool SketchSolver_Storage::isUsedInEqual( + const Slvs_hEntity& theEntity, Slvs_Constraint& theEqual) const +{ + // Check the entity is used in Equal constraint + std::vector::const_iterator anEqIter = myConstraints.begin(); + for (; anEqIter != myConstraints.end(); anEqIter++) + if ((anEqIter->type == SLVS_C_EQUAL_LENGTH_LINES || + anEqIter->type == SLVS_C_EQUAL_LINE_ARC_LEN || + anEqIter->type == SLVS_C_EQUAL_RADIUS) && + (anEqIter->entityA == theEntity || anEqIter->entityB == theEntity)) { + theEqual = *anEqIter; + return true; + } + return false; +} + +bool SketchSolver_Storage::isNeedToResolve() +{ + if (myConstraints.empty()) + return false; + + if (!myNeedToResolve) { + // Verify the updated parameters are used in constraints + std::set aPoints; + std::vector::const_iterator anEntIt = myEntities.begin(); + for (; anEntIt != myEntities.end(); ++anEntIt) { + for (int i = 0; i < 4 && anEntIt->param[i] != SLVS_E_UNKNOWN; ++i) + if (myUpdatedParameters.find(anEntIt->param[i]) != myUpdatedParameters.end()) { + aPoints.insert(anEntIt->h); + break; + } + } + std::set anEntities = aPoints; + for (anEntIt = myEntities.begin(); anEntIt != myEntities.end(); ++anEntIt) { + for (int i = 0; i < 4 && anEntIt->point[i] != SLVS_E_UNKNOWN; ++i) + if (aPoints.find(anEntIt->point[i]) != aPoints.end()) { + anEntities.insert(anEntIt->h); + break; + } + } + + std::vector::const_iterator aCIt = myConstraints.begin(); + for (; aCIt != myConstraints.end() && !myNeedToResolve; ++aCIt) { + Slvs_hEntity anAttrs[6] = + {aCIt->ptA, aCIt->ptB, aCIt->entityA, aCIt->entityB, aCIt->entityC, aCIt->entityD}; + for (int i = 0; i < 6; i++) + if (anAttrs[i] != SLVS_E_UNKNOWN && anEntities.find(anAttrs[i]) != anEntities.end()) { + myNeedToResolve = true; + break; + } + } + } + + myUpdatedParameters.clear(); + return myNeedToResolve; +} + + + + // ========================================================