X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_ConstraintMirror.cpp;h=9d1477545f9d969234e7c7115d2fe04b16ab2d5f;hb=20d233731eaae06b9a75280a2ca675bc9a11cc72;hp=6ea42d13ef6ef4d5c475443f36152f2851f2c9ad;hpb=ef017929d9fd0f90a8bc7513148e25ce833971ac;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_ConstraintMirror.cpp b/src/SketchSolver/SketchSolver_ConstraintMirror.cpp index 6ea42d13e..9d1477545 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMirror.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMirror.cpp @@ -10,6 +10,7 @@ #include #include +#include void SketchSolver_ConstraintMirror::getAttributes( Slvs_Entity& theMirrorLine, @@ -57,7 +58,13 @@ void SketchSolver_ConstraintMirror::getAttributes( continue; anEntity = changeEntity(aFeature, aType); - aList->push_back(myStorage->getEntity(anEntity)); + // Sort entities by their type + std::vector::iterator anIt = aList->begin(); + for (; anIt != aList->end(); anIt++) + if (aType < anIt->type) + break; +// aList->push_back(myStorage->getEntity(anEntity)); + aList->insert(anIt, myStorage->getEntity(anEntity)); } } @@ -137,8 +144,8 @@ void SketchSolver_ConstraintMirror::process() aBaseIter->point[2], SLVS_E_UNKNOWN}; Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point - aBaseIter->point[2], - aBaseIter->point[1], + aMirrorIter->point[2], + aMirrorIter->point[1], SLVS_E_UNKNOWN}; Slvs_Entity aBothArcs[2] = {*aBaseIter, *aMirrorIter}; @@ -159,6 +166,20 @@ void SketchSolver_ConstraintMirror::process() 0.0, aBothMiddlePoints[i], SLVS_E_UNKNOWN, aBothArcs[i].h, SLVS_E_UNKNOWN); aPonCircConstr.h = myStorage->addConstraint(aPonCircConstr); mySlvsConstraints.push_back(aPonCircConstr.h); + if (i == 0) { + // additional constraint for the point to be in the middle of a base arc + Slvs_Entity aLine1 = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(), + myGroup->getWorkplaneId(), aBothArcs[i].point[1], aBothMiddlePoints[i]); + aLine1.h = myStorage->addEntity(aLine1); + Slvs_Entity aLine2 = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(), + myGroup->getWorkplaneId(), aBothArcs[i].point[2], aBothMiddlePoints[i]); + aLine2.h = myStorage->addEntity(aLine2); + Slvs_Constraint aMiddleConstr = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), + SLVS_C_EQUAL_LENGTH_LINES, myGroup->getWorkplaneId(), + 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aLine1.h, aLine2.h); + aMiddleConstr.h = myStorage->addConstraint(aMiddleConstr); + mySlvsConstraints.push_back(aMiddleConstr.h); + } } aBaseArcPoints[2] = aBothMiddlePoints[0]; @@ -172,15 +193,6 @@ void SketchSolver_ConstraintMirror::process() } } } - - // Set the mirror line unchanged during constraint recalculation - for (int i = 0; i < 2; i++) { - aConstraint = Slvs_MakeConstraint( - SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0, - aMirrorLine.point[i], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); - aConstraint.h = myStorage->addConstraint(aConstraint); - mySlvsConstraints.push_back(aConstraint.h); - } } @@ -193,6 +205,7 @@ void SketchSolver_ConstraintMirror::update(ConstraintPtr theConstraint) if (aMirroredRefList->size() != myNumberOfObjects) { remove(myBaseConstraint); process(); + return; } } SketchSolver_Constraint::update(); @@ -209,6 +222,10 @@ bool SketchSolver_ConstraintMirror::remove(ConstraintPtr theConstraint) isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved; mySlvsConstraints.clear(); + std::map::iterator aFeatIt = myFeatureMap.begin(); + for (; aFeatIt != myFeatureMap.end(); aFeatIt++) + myStorage->removeEntity(aFeatIt->second); + if (isFullyRemoved) { myFeatureMap.clear(); myAttributeMap.clear(); @@ -218,6 +235,39 @@ bool SketchSolver_ConstraintMirror::remove(ConstraintPtr theConstraint) return true; } +bool SketchSolver_ConstraintMirror::checkAttributesChanged(ConstraintPtr theConstraint) +{ + // First of all, check the mirror line is changed. + // It may be changed to one of mirrored lines, which is already in this constraint + // (this case is not marked as attribute changing) + ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint; + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( + aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + if (!aRefAttr || !aRefAttr->isObject() || !aRefAttr->object()) + return true; + FeaturePtr aMirrorLine = ModelAPI_Feature::feature(aRefAttr->object()); + if (!aMirrorLine) + return true; + + std::map::iterator aMirrorIter = myFeatureMap.find(aMirrorLine); + if (aMirrorIter == myFeatureMap.end()) + return true; + + // Check the entity is not used as mirror line + std::vector::iterator aCIter = mySlvsConstraints.begin(); + for (; aCIter != mySlvsConstraints.end(); aCIter++) { + Slvs_Constraint aMirrorConstr = myStorage->getConstraint(*aCIter); + if (aMirrorConstr.type != SLVS_C_SYMMETRIC_LINE) + continue; + if (aMirrorConstr.entityA != aMirrorIter->second) + return true; + else break; // check just one symmetric constraint + } + + // Base verification + return SketchSolver_Constraint::checkAttributesChanged(theConstraint); +} + void SketchSolver_ConstraintMirror::makeMirrorEntity( const Slvs_Entity& theBase, const Slvs_Entity& theMirror, @@ -233,6 +283,11 @@ void SketchSolver_ConstraintMirror::makeMirrorEntity( Slvs_hEntity aTmp = aMirrorPoint[2]; aMirrorPoint[2] = aMirrorPoint[1]; aMirrorPoint[1] = aTmp; + adjustArcPoints(theBase); + } + if (theBase.type == SLVS_E_POINT_IN_2D || theBase.type == SLVS_E_POINT_IN_3D) { + aBasePoint[0] = theBase.h; + aMirrorPoint[0] = theMirror.h; } // Mirror line parameters @@ -246,9 +301,14 @@ void SketchSolver_ConstraintMirror::makeMirrorEntity( // orthogonal direction aDir = std::shared_ptr(new GeomAPI_Dir2d(aDir->y(), -aDir->x())); + Slvs_hConstraint aFixed; // transient variable for (int i = 0; i < 4; i++) { if (aBasePoint[i] == SLVS_E_UNKNOWN || aMirrorPoint[i] == SLVS_E_UNKNOWN) continue; + // check the mirror point is not fixed + if (myStorage->isPointFixed(aMirrorPoint[i], aFixed, true)) + continue; + Slvs_Entity aPointEnt = myStorage->getEntity(aBasePoint[i]); double aBaseX = myStorage->getParameter(aPointEnt.param[0]).val; double aBaseY = myStorage->getParameter(aPointEnt.param[1]).val; @@ -267,3 +327,156 @@ void SketchSolver_ConstraintMirror::makeMirrorEntity( } } +void SketchSolver_ConstraintMirror::adjustArcPoints(const Slvs_Entity& theArc) const +{ + Slvs_Param aParam; + Slvs_Entity aPoint; + double anArcParams[3][2]; + for (int i = 0; i < 3; i++) { + aPoint = myStorage->getEntity(theArc.point[i]); + for (int j = 0; j < 2; j++) { + aParam = myStorage->getParameter(aPoint.param[j]); + anArcParams[i][j] = aParam.val; + if (i > 0) + anArcParams[i][j] -= anArcParams[0][j]; + } + } + double aRad2 = anArcParams[1][0] * anArcParams[1][0] + anArcParams[1][1] * anArcParams[1][1]; + double aDist2 = anArcParams[2][0] * anArcParams[2][0] + anArcParams[2][1] * anArcParams[2][1]; + if (std::fabs(aRad2 - aDist2) < tolerance) + return; // nothing to update (last point already on the arc) + if (aDist2 < tolerance) + return; // unable to update + double aCoeff = std::sqrt(aRad2 / aDist2); + anArcParams[2][0] *= aCoeff; + anArcParams[2][1] *= aCoeff; + + // Update last point + aPoint = myStorage->getEntity(theArc.point[2]); + for (int i = 0; i < 2; i++) { + aParam = Slvs_MakeParam(aPoint.param[i], myGroup->getId(), + anArcParams[0][i] + anArcParams[2][i]); + myStorage->updateParameter(aParam); + } +} + +void SketchSolver_ConstraintMirror::adjustConstraint() +{ + AttributeRefAttrPtr aMirLineAttr = std::dynamic_pointer_cast( + myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + if (!aMirLineAttr || !aMirLineAttr->isInitialized() || !aMirLineAttr->isObject()) { + myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); + return; + } + ResultConstructionPtr aRC = + std::dynamic_pointer_cast(aMirLineAttr->object()); + FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) : + std::dynamic_pointer_cast(aMirLineAttr->object()); + std::map::iterator aMirLineIter = myFeatureMap.find(aFeature); + if (aMirLineIter == myFeatureMap.end()) + return; + Slvs_Entity aMirrorLine = myStorage->getEntity(aMirLineIter->second); + + Slvs_Constraint aMirror; + double aStartEnd[4]; + for (int i = 0; i < 2; i++) { + Slvs_Entity aPoint = myStorage->getEntity(aMirrorLine.point[i]); + for (int j = 0; j < 2; j++) + aStartEnd[2*i+j] = myStorage->getParameter(aPoint.param[j]).val; + } + + // Calculate length of the mirror line and create temporary constraint + double aLength = sqrt((aStartEnd[2] - aStartEnd[0]) * (aStartEnd[2] - aStartEnd[0]) + + (aStartEnd[3] - aStartEnd[1]) * (aStartEnd[3] - aStartEnd[1])); + if (aLength < tolerance) { + if (myMirrorLineLength < 1.0) + myMirrorLineLength = 1.0; + } else + myMirrorLineLength = aLength; + std::list aDist = myStorage->getConstraintsByType(SLVS_C_PT_PT_DISTANCE); + std::list::const_iterator aDIt = aDist.begin(); + for (; aDIt != aDist.end(); ++aDIt) + if ((aDIt->ptA == aMirrorLine.point[0] && aDIt->ptB == aMirrorLine.point[1]) || + (aDIt->ptA == aMirrorLine.point[1] && aDIt->ptB == aMirrorLine.point[0])) + break; // length of mirror line is already set + if (aDIt == aDist.end()) { + // check the points of mirror line is not fixed + Slvs_hConstraint aFixed; + if (!myStorage->isPointFixed(aMirrorLine.point[0], aFixed, true) || + !myStorage->isPointFixed(aMirrorLine.point[1], aFixed, true)) { + // Add length constraint + aMirror = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_PT_DISTANCE, + myGroup->getWorkplaneId(), aLength, aMirrorLine.point[0], aMirrorLine.point[1], + SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); + aMirror.h = myStorage->addConstraint(aMirror); + myStorage->addTemporaryConstraint(aMirror.h); + } + } + + // Search mirror between middle points on the arcs and recompute their coordinates + std::map aPointsOnCircles; + std::list aMirrorPonCirc; + std::list aPonCirc = myStorage->getConstraintsByType(SLVS_C_PT_ON_CIRCLE); + std::vector::iterator aConstrIter = mySlvsConstraints.begin(); + for (; aConstrIter != mySlvsConstraints.end(); aConstrIter++) { + aMirror = myStorage->getConstraint(*aConstrIter); + if (aMirror.type != SLVS_C_SYMMETRIC_LINE) + continue; + if (aMirror.entityA != aMirrorLine.h) + continue; // don't update another Mirror constraints + Slvs_Constraint aPonCircA, aPonCircB; + aPonCircA.h = SLVS_E_UNKNOWN; + aPonCircB.h = SLVS_E_UNKNOWN; + std::list::iterator aPtIter = aPonCirc.begin(); + for (; aPtIter != aPonCirc.end(); aPtIter++) { + if (aMirror.ptA == aPtIter->ptA) + aPonCircA = *aPtIter; + if (aMirror.ptB == aPtIter->ptA) + aPonCircB = *aPtIter; + } + if (aPonCircA.h == SLVS_E_UNKNOWN || aPonCircB.h == SLVS_E_UNKNOWN) + continue; + aMirrorPonCirc.push_back(aMirror); + // Store point IDs to avoid their recalculation twice + aPointsOnCircles[aPonCircA.ptA] = aPonCircA.entityA; + aPointsOnCircles[aPonCircB.ptA] = aPonCircB.entityA; + } + + // Recalculate positions of mirroring points + std::list aMirrorList = myStorage->getConstraintsByType(SLVS_C_SYMMETRIC_LINE); + std::list::iterator aMirIter = aMirrorList.begin(); + for (; aMirIter != aMirrorList.end(); aMirIter++) { + if (aMirIter->entityA != aMirrorLine.h) + continue; // don't update another Mirror constraints + if (aPointsOnCircles.find(aMirIter->ptA) != aPointsOnCircles.end()) + continue; // Avoid mirroring points on circles + Slvs_Entity aBase = myStorage->getEntity(aMirIter->ptA); + Slvs_Entity aMirror = myStorage->getEntity(aMirIter->ptB); + makeMirrorEntity(aBase, aMirror, aStartEnd); + } + + bool aNeedToResolve = myStorage->isNeedToResolve(); + for (aMirIter = aMirrorPonCirc.begin(); aMirIter != aMirrorPonCirc.end(); aMirIter++) { + // Make centers of arcs symmetric + Slvs_Entity aBaseArc = myStorage->getEntity(aPointsOnCircles[aMirIter->ptA]); + Slvs_Entity aBasePoint = myStorage->getEntity(aBaseArc.point[0]); + Slvs_Entity aMirrorArc = myStorage->getEntity(aPointsOnCircles[aMirIter->ptB]); + Slvs_Entity aMirrorPoint = myStorage->getEntity(aMirrorArc.point[0]); + makeMirrorEntity(aBasePoint, aMirrorPoint, aStartEnd); + // Calculate middle point for base arc and mirrored point on mirror arc + aBasePoint = myStorage->getEntity(aMirIter->ptA); + Slvs_Param aParamX = myStorage->getParameter(aBasePoint.param[0]); + Slvs_Param aParamY = myStorage->getParameter(aBasePoint.param[1]); + calculateMiddlePoint(aBaseArc, 0.5, aParamX.val, aParamY.val); + myStorage->updateParameter(aParamX); + myStorage->updateParameter(aParamY); + aMirrorPoint = myStorage->getEntity(aMirIter->ptB); + aParamX = myStorage->getParameter(aMirrorPoint.param[0]); + aParamY = myStorage->getParameter(aMirrorPoint.param[1]); + calculateMiddlePoint(aMirrorArc, 0.5, aParamX.val, aParamY.val); + myStorage->updateParameter(aParamX); + myStorage->updateParameter(aParamY); + } + // Restore previous value to avoid looped recalculations of sketch + myStorage->setNeedToResolve(aNeedToResolve); +}