#include <GeomAPI_Dir2d.h>
#include <GeomAPI_XY.h>
+#include <cmath>
void SketchSolver_ConstraintMirror::getAttributes(
Slvs_Entity& theMirrorLine,
continue;
anEntity = changeEntity(aFeature, aType);
- aList->push_back(myStorage->getEntity(anEntity));
+ // Sort entities by their type
+ std::vector<Slvs_Entity>::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));
}
}
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];
}
}
}
-
- // 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);
- }
}
if (aMirroredRefList->size() != myNumberOfObjects) {
remove(myBaseConstraint);
process();
+ return;
}
}
SketchSolver_Constraint::update();
isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
mySlvsConstraints.clear();
+ std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.begin();
+ for (; aFeatIt != myFeatureMap.end(); aFeatIt++)
+ myStorage->removeEntity(aFeatIt->second);
+
if (isFullyRemoved) {
myFeatureMap.clear();
myAttributeMap.clear();
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<ModelAPI_AttributeRefAttr>(
+ 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<FeaturePtr, Slvs_hEntity>::iterator aMirrorIter = myFeatureMap.find(aMirrorLine);
+ if (aMirrorIter == myFeatureMap.end())
+ return true;
+
+ // Check the entity is not used as mirror line
+ std::vector<Slvs_hConstraint>::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,
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;
// orthogonal direction
aDir = std::shared_ptr<GeomAPI_Dir2d>(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;
}
}
-void SketchSolver_ConstraintMirror::adjustConstraint()
+void SketchSolver_ConstraintMirror::adjustArcPoints(const Slvs_Entity& theArc) const
{
- // Search mirror between middle points on the arcs and recompute their coordinates
- std::list<Slvs_Constraint> aPonCirc = myStorage->getConstraintsByType(SLVS_C_PT_ON_CIRCLE);
- if (aPonCirc.empty())
- return;
+ 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()) {
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]);
aStartEnd[2*i+j] = myStorage->getParameter(aPoint.param[j]).val;
}
- Slvs_Constraint aMirror;
+ // 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;
}
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
- Slvs_Entity aBaseArc = myStorage->getEntity(aPonCircA.entityA);
- Slvs_Entity aBasePoint = myStorage->getEntity(aPonCircA.ptA);
+ 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);
- Slvs_Entity aMirrorPoint = myStorage->getEntity(aPonCircB.ptA);
- makeMirrorEntity(aBasePoint, aMirrorPoint, aStartEnd);
+ 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);
}