+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<ModelAPI_AttributeRefAttr>(
+ myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+ if (!aMirLineAttr || !aMirLineAttr->isInitialized() || !aMirLineAttr->isObject()) {
+ myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+ return;
+ }
+ ResultConstructionPtr aRC =
+ std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aMirLineAttr->object());
+ FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
+ std::dynamic_pointer_cast<ModelAPI_Feature>(aMirLineAttr->object());
+ std::map<FeaturePtr, Slvs_hEntity>::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<Slvs_Constraint> aDist = myStorage->getConstraintsByType(SLVS_C_PT_PT_DISTANCE);
+ std::list<Slvs_Constraint>::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<Slvs_hEntity, Slvs_hEntity> aPointsOnCircles;
+ std::list<Slvs_Constraint> aMirrorPonCirc;
+ std::list<Slvs_Constraint> aPonCirc = myStorage->getConstraintsByType(SLVS_C_PT_ON_CIRCLE);
+ std::vector<Slvs_hConstraint>::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<Slvs_Constraint>::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<Slvs_Constraint> aMirrorList = myStorage->getConstraintsByType(SLVS_C_SYMMETRIC_LINE);
+ std::list<Slvs_Constraint>::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);
+}