From 203a3db5900f61c3da5c3cc2ccf029d9a930397e Mon Sep 17 00:00:00 2001 From: azv Date: Wed, 8 Jun 2016 14:29:15 +0300 Subject: [PATCH] PlaneGCSSolver: Update processing coincident points. Test cases correction. --- src/PythonAPI/examples/Platine.py | 2 +- src/SketchPlugin/Test/TestConstraintMirror.py | 20 +++++---- .../Test/TestConstraintTangent.py | 2 +- src/SketchPlugin/Test/TestSketchArcCircle.py | 16 +++++++- .../PlaneGCSSolver/PlaneGCSSolver_Builder.cpp | 5 +++ .../PlaneGCSSolver/PlaneGCSSolver_Storage.cpp | 41 +++++++++++++++---- .../PlaneGCSSolver/PlaneGCSSolver_Storage.h | 4 +- 7 files changed, 71 insertions(+), 19 deletions(-) diff --git a/src/PythonAPI/examples/Platine.py b/src/PythonAPI/examples/Platine.py index bb22d2882..05f985b54 100644 --- a/src/PythonAPI/examples/Platine.py +++ b/src/PythonAPI/examples/Platine.py @@ -125,7 +125,7 @@ def body_3(): geom_points = [geom.Pnt2d(*p) for p in points] left, top_left, top_middle, top_right, right, bottom, = sketch.addPolygon(*geom_points) - points = [(l + r, H), (l, H), (l + 2 * r, H)] + points = [(l + r, H), (l + 2 * r, H), (l, H)] points = [(p[0], -p[1]) for p in points] # as we look to back of the face center, start, end = [geom.Pnt2d(*p) for p in points] arc = sketch.addArc(center, start, end) diff --git a/src/SketchPlugin/Test/TestConstraintMirror.py b/src/SketchPlugin/Test/TestConstraintMirror.py index 319a725d6..bbf74982a 100644 --- a/src/SketchPlugin/Test/TestConstraintMirror.py +++ b/src/SketchPlugin/Test/TestConstraintMirror.py @@ -21,14 +21,20 @@ __updated__ = "2015-03-17" #========================================================================= # Auxiliary functions #========================================================================= +def normalize(theDir): + aLen = math.hypot(theDir[0], theDir[1]) + if aLen < 1.e-10: + aLen = 1.0 + return [theDir[0] / aLen, theDir[1] / aLen] + def checkMirror(theListInit, theListMirr, theMirrorLine): - TOL = 1.e-8 + TOL = 5.e-5 aListSize = theListInit.size() aLineStartPoint = geomDataAPI_Point2D(theMirrorLine.attribute("StartPoint")) aLineEndPoint = geomDataAPI_Point2D(theMirrorLine.attribute("EndPoint")) - aLineDirX = aLineEndPoint.x() - aLineStartPoint.x() - aLineDirY = aLineEndPoint.y() - aLineStartPoint.y() + aLineDir = [aLineEndPoint.x() - aLineStartPoint.x(), aLineEndPoint.y() - aLineStartPoint.y()] + aLineDir = normalize(aLineDir) for ind in range(0, aListSize): aFeatureB = ModelAPI_Feature.feature(theListInit.object(ind)) @@ -46,13 +52,13 @@ def checkMirror(theListInit, theListMirr, theMirrorLine): for key in anAttributes: aPointB = geomDataAPI_Point2D(aFeatureB.attribute(key)) aPointC = geomDataAPI_Point2D(aFeatureC.attribute(anAttributes[key])) - aDirX = aPointC.x() - aPointB.x() - aDirY = aPointC.y() - aPointB.y() - aDot = aLineDirX * aDirX + aLineDirY * aDirY + aDir = [aPointC.x() - aPointB.x(), aPointC.y() - aPointB.y()] + aDir = normalize(aDir) + aDot = aLineDir[0] * aDir[0] + aLineDir[1] * aDir[1] assert math.fabs(aDot) < TOL, "aDot = {0}".format(aDot) aDirX = aLineEndPoint.x() - 0.5 * (aPointB.x() + aPointC.x()) aDirY = aLineEndPoint.y() - 0.5 * (aPointB.y() + aPointC.y()) - aCross = aLineDirX * aDirY - aLineDirY * aDirX + aCross = aLineDir[0] * aDir[0] - aLineDir[1] * aDir[1] assert math.fabs(aCross) < TOL, "aCross = {0}".format(aCross) diff --git a/src/SketchPlugin/Test/TestConstraintTangent.py b/src/SketchPlugin/Test/TestConstraintTangent.py index 48ed166d7..df3cd3115 100644 --- a/src/SketchPlugin/Test/TestConstraintTangent.py +++ b/src/SketchPlugin/Test/TestConstraintTangent.py @@ -301,7 +301,7 @@ aRefObjectB.setObject(anObjectB) aTangency.execute() aSession.finishOperation() -assert(math.fabs(distancePointLine(aCircleCenter, aLine) - aCircleRadius.value()) < 1.e-10) +assert(math.fabs(distancePointLine(aCircleCenter, aLine) - round(aCircleRadius.value(), 5)) < 1.e-10) #========================================================================= # End of test #========================================================================= diff --git a/src/SketchPlugin/Test/TestSketchArcCircle.py b/src/SketchPlugin/Test/TestSketchArcCircle.py index e15964a1b..8d8c4c820 100644 --- a/src/SketchPlugin/Test/TestSketchArcCircle.py +++ b/src/SketchPlugin/Test/TestSketchArcCircle.py @@ -53,6 +53,19 @@ def distancePointPoint(thePointA, thePointB): ydiff = math.pow((thePointA.y() - thePointB.y()), 2) return round(math.sqrt(xdiff + ydiff), 5) +def dot(thePoint11, thePoint12, thePoint21, thePoint22): + """ + subroutine to calculate dit product between lines given by their points + """ + aDirX1 = thePoint12.x() - thePoint11.x() + aDirY1 = thePoint12.y() - thePoint11.y() + aLen1 = math.hypot(aDirX1, aDirY1) + aDirX2 = thePoint22.x() - thePoint21.x() + aDirY2 = thePoint22.y() - thePoint21.y() + aLen2 = math.hypot(aDirX2, aDirY2) + aDot = aDirX1 * aDirX2 + aDirY1 * aDirY2 + return aDot / aLen1 / aLen2 + aSession = ModelAPI_Session.get() aDocument = aSession.moduleDocument() @@ -217,7 +230,8 @@ aSession.startOperation() anArcEndPoint.setValue(100., 25.) aSession.finishOperation() anArcCenter = geomDataAPI_Point2D(aSketchArcTangent.attribute("ArcCenter")) -assert(anArcCenter.x() == 50.) +aDot = dot(anArcCenter, aLineEnd, aLineStart, aLineEnd) +assert math.fabs(aDot) <= 2.e-4, "Observed dot product: {0}".format(aDot) #========================================================================= # Create an arc, tangent to the previous arc #========================================================================= diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp index 0213cceaa..5e101d240 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp @@ -1077,6 +1077,11 @@ ConstraintWrapperPtr createConstraintEqual( new GCS::ConstraintP2PDistance(aLine1->p1, aLine1->p2, theIntermed->parameter()))); aConstrList.push_back(GCSConstraintPtr( new GCS::ConstraintP2PDistance(aLine2->p1, aLine2->p2, theIntermed->parameter()))); + // update value of intermediate parameter + double x = *aLine1->p1.x - *aLine1->p2.x; + double y = *aLine1->p1.y - *aLine1->p2.y; + double aLen = sqrt(x*x + y*y); + theIntermed->setValue(aLen); } else { std::shared_ptr aCirc1 = std::dynamic_pointer_cast(theEntity1->entity()); diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp index a21c6848b..2fc9185d2 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp @@ -527,7 +527,8 @@ void PlaneGCSSolver_Storage::updateCoincident(const EntityWrapperPtr& thePoint) bool PlaneGCSSolver_Storage::isRedundant( GCSConstraintPtr theCheckedConstraint, - ConstraintWrapperPtr theParentConstraint) const + ConstraintWrapperPtr theParentConstraint, + std::list >& theCoincidentPoints) const { if (theParentConstraint->type() == CONSTRAINT_SYMMETRIC) { if (theCheckedConstraint->getTypeId() == GCS::Perpendicular) { @@ -540,13 +541,36 @@ bool PlaneGCSSolver_Storage::isRedundant( } } else if (theParentConstraint->type() == CONSTRAINT_PT_PT_COINCIDENT) { - // Mark constraint redundant if the coincident points both are slaves in the list of stored coincidences - const std::list& aPoints = theParentConstraint->entities(); - CoincidentPointsMap::const_iterator aCoincIt = myCoincidentPoints.begin(); - for (; aCoincIt != myCoincidentPoints.end(); ++aCoincIt) { - if (aCoincIt->second.find(aPoints.front()) != aCoincIt->second.end() && - aCoincIt->second.find(aPoints.back()) != aCoincIt->second.end()) + // Verify that the coincidence between points is already added + GCS::VEC_pD aParams = theCheckedConstraint->params(); + + std::list >::iterator aCoincIt, aFound1, aFound2; + aFound1 = aFound2 = theCoincidentPoints.end(); + for (aCoincIt = theCoincidentPoints.begin(); aCoincIt != theCoincidentPoints.end(); ++aCoincIt) { + if (aFound1 == theCoincidentPoints.end() && aCoincIt->find(aParams[0]) != aCoincIt->end()) + aFound1 = aCoincIt; + if (aFound2 == theCoincidentPoints.end() && aCoincIt->find(aParams[1]) != aCoincIt->end()) + aFound2 = aCoincIt; + if (aFound1 != theCoincidentPoints.end() && aFound2 != theCoincidentPoints.end()) + break; + } + if (aCoincIt != theCoincidentPoints.end()) { // both point are found + if (aFound1 == aFound2) return true; + // merge two groups of coincidence + aFound1->insert(aFound2->begin(), aFound2->end()); + theCoincidentPoints.erase(aFound2); + } else { + if (aFound1 != theCoincidentPoints.end()) + aFound1->insert(aParams[1]); + else if (aFound2 != theCoincidentPoints.end()) + aFound2->insert(aParams[0]); + else { + std::set aNewCoincidence; + aNewCoincidence.insert(aParams[0]); + aNewCoincidence.insert(aParams[1]); + theCoincidentPoints.push_back(aNewCoincidence); + } } } @@ -568,6 +592,7 @@ void PlaneGCSSolver_Storage::initializeSolver(SolverPtr theSolver) std::map >::const_iterator aCIt = myConstraintMap.begin(); GCS::SET_I aTangentIDs; + std::list > aCoincidentPoints; for (; aCIt != myConstraintMap.end(); ++aCIt) { std::list::const_iterator aCWIt = aCIt->second.begin(); for (; aCWIt != aCIt->second.end(); ++ aCWIt) { @@ -575,7 +600,7 @@ void PlaneGCSSolver_Storage::initializeSolver(SolverPtr theSolver) std::dynamic_pointer_cast(*aCWIt); std::list::const_iterator anIt = aGCS->constraints().begin(); for (; anIt != aGCS->constraints().end(); ++anIt) - if (!isRedundant(*anIt, aGCS)) + if (!isRedundant(*anIt, aGCS, aCoincidentPoints)) aSolver->addConstraint(*anIt); } // store IDs of tangent constraints to avoid incorrect report of redundant constraints diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h index dd71f9eed..643a6df6f 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h @@ -107,7 +107,9 @@ private: /// /// This is a workaround method to avoid some kinds of conflicting constraints: /// * symmetric of two points placed on the mirror line (do not add perpendicular constraint) - bool isRedundant(GCSConstraintPtr theCheckedConstraint, ConstraintWrapperPtr theParentConstraint) const; + bool isRedundant(GCSConstraintPtr theCheckedConstraint, + ConstraintWrapperPtr theParentConstraint, + std::list >& theCoincidentPoints = std::list >() ) const; private: GCS::VEC_pD myParameters; ///< list of parameters -- 2.39.2