From: azv Date: Tue, 7 Feb 2017 06:39:01 +0000 (+0300) Subject: SketchSolver Refactoring: Eliminate SolveSpace as a sketch solver. X-Git-Tag: V_2.7.0~267 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=e066abaa17e20d15934c0c83cdd8de07ffd93122;p=modules%2Fshaper.git SketchSolver Refactoring: Eliminate SolveSpace as a sketch solver. * Improve SketchSolver_Manager to add features placed in a single sketch into a single group * Remove unnecessary IDs for entities and parameters. Do not set GroupID for such kind of elements. * Remove unnecessary IDs for groups * Check feature validity on at the very beginning of processing. * Fix problems when deleting temporary constraint built for correct restart of an operation. * Remove data structure to store lists of coincident points. * Integrate SketchSolver sources into PlaneGCSSolver plugin * Take out ParameterWrapper * Move converting and removing entities to specific classes * Remove notifications on changing point-point coincidences. * Update processing Fixed constraint (make it more natural to PlaneGCS). Remove Movement constraint as unneeded. * Repair Point-point coincidence and the Fixed constraints * Fix incorrect processing of the Update event. * Repair Point-on-Line and Point-on-Circle constraints. * Repair processing of external features * Processing of point-point multi-coincidence has been updated. Unit test has been improved. * Repair constraints: Horizontal, Vertical, Parallel, Perpendicular, Radius, Distance, Length, Equal and Tangent * Fix issue that arc cannot be created on the sketch with constraints * Repair Angle and Middle point constraints. * Repair Multi-Rotation and Multi-Translation constraints. * Introduce Updaters to send changed features to interested object only. * Remove the Fixed constraint applying on the external features. * Update Multi-* constraints to use Updaters. * Mirror constraint redesign * Remove obsolete std::dynamic_pointer_cast * Optimize blocking events while solving constraints * Update Coincidence and Middle Point constraints processing (move checking multi coincidence to the constraint layer) --- diff --git a/src/PartSet/PartSet_Tools.cpp b/src/PartSet/PartSet_Tools.cpp index de6b4bdea..9affd9803 100755 --- a/src/PartSet/PartSet_Tools.cpp +++ b/src/PartSet/PartSet_Tools.cpp @@ -542,12 +542,12 @@ ResultPtr PartSet_Tools::createFixedObjectByExternal(const TopoDS_Shape& theShap //if (!theTemporary) { aMyFeature->execute(); - // fix this edge - FeaturePtr aFix = theSketch->addFeature(SketchPlugin_ConstraintRigid::ID()); - aFix->data()->refattr(SketchPlugin_Constraint::ENTITY_A())-> - setObject(aMyFeature->lastResult()); - // we need to flush created signal in order to fixed constraint is processed by solver - Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED)); + // // fix this edge + // FeaturePtr aFix = theSketch->addFeature(SketchPlugin_ConstraintRigid::ID()); + // aFix->data()->refattr(SketchPlugin_Constraint::ENTITY_A())-> + // setObject(aMyFeature->lastResult()); + // // we need to flush created signal in order to fixed constraint is processed by solver + // Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED)); //} return aMyFeature->lastResult(); } @@ -604,12 +604,12 @@ ResultPtr PartSet_Tools::createFixedObjectByExternal(const TopoDS_Shape& theShap //if (theTemporary) { aMyFeature->execute(); - // fix this edge - FeaturePtr aFix = theSketch->addFeature(SketchPlugin_ConstraintRigid::ID()); - aFix->data()->refattr(SketchPlugin_Constraint::ENTITY_A())-> - setObject(aMyFeature->lastResult()); - // we need to flush created signal in order to fixed constraint is processed by solver - Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED)); + // // fix this edge + // FeaturePtr aFix = theSketch->addFeature(SketchPlugin_ConstraintRigid::ID()); + // aFix->data()->refattr(SketchPlugin_Constraint::ENTITY_A())-> + // setObject(aMyFeature->lastResult()); + // // we need to flush created signal in order to fixed constraint is processed by solver + // Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED)); //} return aMyFeature->lastResult(); } diff --git a/src/PythonAPI/Test/TestSketcherSetEqual.py b/src/PythonAPI/Test/TestSketcherSetEqual.py index b803cb74f..2e6b98695 100644 --- a/src/PythonAPI/Test/TestSketcherSetEqual.py +++ b/src/PythonAPI/Test/TestSketcherSetEqual.py @@ -27,13 +27,13 @@ class SketcherSetEqual(SketcherTestCase): # Set the constraint circle_1 = self.sketch.addCircle(0, 0, 10.0) circle_2 = self.sketch.addCircle(1, 2, 25.0) - self.sketch.setEqual(circle_1.result(), circle_2.result()) + self.sketch.setEqual(circle_1.defaultResult(), circle_2.defaultResult()) # Commit the transaction model.do() # Check the result self.assertAlmostEqual( - circle_1.radiusData().value(), - circle_2.radiusData().value(), + circle_1.radius().value(), + circle_2.radius().value(), delta=TestSketcher.DELTA ) diff --git a/src/PythonAPI/examples/MakeBrick1.py b/src/PythonAPI/examples/MakeBrick1.py index 3af36f897..bfb8c57c9 100644 --- a/src/PythonAPI/examples/MakeBrick1.py +++ b/src/PythonAPI/examples/MakeBrick1.py @@ -50,7 +50,7 @@ model.do() # Creating a cylinder on a face of the box thisface = "Extrusion_1_1/Generated_Face_2" -thisxmax = "Extrusion_1_1/Generated_Face_3&Extrusion_1_1/Generated_Face_2" +thisxmax = "Extrusion_1_1/Generated_Face_2&Extrusion_1_1/Generated_Face_1" thiszmax = "Extrusion_1_1/Generated_Face_2&Extrusion_1_1/To_Face_1_1" mystand = model.addSketch(mypart, thisface) diff --git a/src/PythonAPI/examples/MakeBrick2.py b/src/PythonAPI/examples/MakeBrick2.py index 267cc692d..ecbcb43cd 100644 --- a/src/PythonAPI/examples/MakeBrick2.py +++ b/src/PythonAPI/examples/MakeBrick2.py @@ -48,7 +48,7 @@ model.do() # Creating a cylinder on a face of the box thisface = "Extrusion_1_1/Generated_Face_2" -thisxmin = "Extrusion_1_1/Generated_Face_3&Extrusion_1_1/Generated_Face_2" +thisxmin = "Extrusion_1_1/Generated_Face_2&Extrusion_1_1/Generated_Face_1" thiszmax = "Extrusion_1_1/Generated_Face_2&Extrusion_1_1/To_Face_1_1" mystand = model.addSketch(mypart, thisface) diff --git a/src/SketchPlugin/CMakeLists.txt b/src/SketchPlugin/CMakeLists.txt index a92dcbd51..90d57ff70 100644 --- a/src/SketchPlugin/CMakeLists.txt +++ b/src/SketchPlugin/CMakeLists.txt @@ -144,4 +144,5 @@ ADD_UNIT_TESTS(TestSketchPointLine.py TestHighload.py TestSnowflake.py TestArcBehavior.py + Test1061.py Test1924.py ) diff --git a/src/SketchPlugin/SketchPlugin_ConstraintRigid.cpp b/src/SketchPlugin/SketchPlugin_ConstraintRigid.cpp index ec34ff9e1..fe5453aa4 100644 --- a/src/SketchPlugin/SketchPlugin_ConstraintRigid.cpp +++ b/src/SketchPlugin/SketchPlugin_ConstraintRigid.cpp @@ -33,25 +33,5 @@ AISObjectPtr SketchPlugin_ConstraintRigid::getAISObject(AISObjectPtr thePrevious { if (!sketch()) return thePrevious; - - AISObjectPtr anAIS = thePrevious; - - bool isValidRigid = false; - std::shared_ptr aData = data(); - AttributeRefAttrPtr anAttr = aData->refattr(SketchPlugin_Constraint::ENTITY_A()); - ObjectPtr aObj = anAttr->object(); - if (aObj.get() != NULL) { - FeaturePtr aFeature = ModelAPI_Feature::feature(aObj); - std::shared_ptr aSkFea = - std::dynamic_pointer_cast(aFeature); - if (!aSkFea->isExternal()) - isValidRigid = true; - } - - if (isValidRigid) - anAIS = SketcherPrs_Factory::rigidConstraint(this, sketch()->coordinatePlane(), thePrevious); - else - anAIS = AISObjectPtr(); - - return anAIS; + return SketcherPrs_Factory::rigidConstraint(this, sketch()->coordinatePlane(), thePrevious); } \ No newline at end of file diff --git a/src/SketchPlugin/SketchPlugin_Projection.cpp b/src/SketchPlugin/SketchPlugin_Projection.cpp index a39d90d7c..8b3f61127 100644 --- a/src/SketchPlugin/SketchPlugin_Projection.cpp +++ b/src/SketchPlugin/SketchPlugin_Projection.cpp @@ -200,12 +200,6 @@ void SketchPlugin_Projection::computeProjection(const std::string& theID) aProjection->execute(); aRefAttr->setObject(aProjection); - if (!hasPrevProj) { - FeaturePtr aFixed = sketch()->addFeature(SketchPlugin_ConstraintRigid::ID()); - aFixed->refattr(SketchPlugin_Constraint::ENTITY_A())->setObject(aProjection->lastResult()); - aFixed->execute(); - } - if (theID == EXTERNAL_FEATURE_ID()) { selection(EXTERNAL_ID())->setValue(aExtFeature->context(), aExtFeature->value()); diff --git a/src/SketchPlugin/Test/Test1061.py b/src/SketchPlugin/Test/Test1061.py new file mode 100644 index 000000000..b961f58a3 --- /dev/null +++ b/src/SketchPlugin/Test/Test1061.py @@ -0,0 +1,28 @@ +""" + Test1061.py + Test case for issue #1061 "Distance constraint using for points with equal coordinates" +""" + +import math +from salome.shaper import model + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() + +Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY")) +SketchLine_1 = Sketch_1.addLine(70, 120, 50, 25) +SketchLine_2 = Sketch_1.addLine(50, 25, 170, 50) + +DISTANCE = 100 +SketchConstraintDistance_1 = Sketch_1.setDistance(SketchLine_1.endPoint(), SketchLine_2.startPoint(), DISTANCE) +model.do() + +# check distance between points +aDist2 = (SketchLine_1.endPoint().x() - SketchLine_2.startPoint().x())**2 + (SketchLine_1.endPoint().y() - SketchLine_2.startPoint().y())**2 +assert(math.fabs(aDist2 - DISTANCE**2) > 1e-12) + +model.end() + +assert(model.checkPythonDump()) diff --git a/src/SketchPlugin/Test/TestConstraintCoincidence.py b/src/SketchPlugin/Test/TestConstraintCoincidence.py index 9bc2f2808..f416f5d26 100644 --- a/src/SketchPlugin/Test/TestConstraintCoincidence.py +++ b/src/SketchPlugin/Test/TestConstraintCoincidence.py @@ -85,8 +85,7 @@ aSession.finishOperation() aSession.startOperation() aSketchArc = aSketchFeature.addFeature("SketchArc") anArcCentr = geomDataAPI_Point2D(aSketchArc.attribute("ArcCenter")) -anArcStartPoint = geomDataAPI_Point2D( - aSketchArc.attribute("ArcStartPoint")) +anArcStartPoint = geomDataAPI_Point2D(aSketchArc.attribute("ArcStartPoint")) anArcEndPoint = geomDataAPI_Point2D(aSketchArc.attribute("ArcEndPoint")) anArcCentr.setValue(10., 10.) anArcStartPoint.setValue(0., 50.) @@ -112,10 +111,8 @@ aSession.finishOperation() #========================================================================= # Check values and move one constrainted object #========================================================================= -assert (anArcEndPoint.x() == 50) -assert (anArcEndPoint.y() == 0) -assert (aLineStartPoint.x() == 50) -assert (aLineStartPoint.y() == 0) +assert (anArcEndPoint.x() == aLineStartPoint.x()) +assert (anArcEndPoint.y() == aLineStartPoint.y()) deltaX = deltaY = 40. # move line aSession.startOperation() @@ -202,10 +199,97 @@ reflistB.setObject(aSketchArc.lastResult()) aConstraint.execute() aSession.finishOperation() checkPointOnArc(aCircleCenter, aSketchArc) +# check center of circle is still in origin +assert (aCircleCenter.x() == 0. and aCircleCenter.y() == 0.) + #========================================================================= -# Check center of circle is still in origin +# Create two more lines and set multi-coincidence between their extremities #========================================================================= -assert (aCircleCenter.x() == 0. and aCircleCenter.y() == 0.) +aSession.startOperation() +# line 2 +aLine2 = aSketchFeature.addFeature("SketchLine") +aLine2StartPoint = geomDataAPI_Point2D(aLine2.attribute("StartPoint")) +aLine2EndPoint = geomDataAPI_Point2D(aLine2.attribute("EndPoint")) +aLine2StartPoint.setValue(50., 0.) +aLine2EndPoint.setValue(100., 0.) +# line 3 +aLine3 = aSketchFeature.addFeature("SketchLine") +aLine3StartPoint = geomDataAPI_Point2D(aLine3.attribute("StartPoint")) +aLine3EndPoint = geomDataAPI_Point2D(aLine3.attribute("EndPoint")) +aLine3StartPoint.setValue(50., 0.) +aLine3EndPoint.setValue(0., 100.) +aSession.finishOperation() +# coincidences between extremities of lines +aSession.startOperation() +aConstraint12 = aSketchFeature.addFeature("SketchConstraintCoincidence") +refAttrA = aConstraint12.refattr("ConstraintEntityA") +refAttrB = aConstraint12.refattr("ConstraintEntityB") +refAttrA.setAttr(aLineStartPoint) +refAttrB.setAttr(aLine2StartPoint) +aConstraint23 = aSketchFeature.addFeature("SketchConstraintCoincidence") +refAttrA = aConstraint23.refattr("ConstraintEntityA") +refAttrB = aConstraint23.refattr("ConstraintEntityB") +refAttrA.setAttr(aLine2StartPoint) +refAttrB.setAttr(aLine3StartPoint) +aConstraint31 = aSketchFeature.addFeature("SketchConstraintCoincidence") +refAttrA = aConstraint31.refattr("ConstraintEntityA") +refAttrB = aConstraint31.refattr("ConstraintEntityB") +refAttrA.setAttr(aLine3StartPoint) +refAttrB.setAttr(aLineStartPoint) +aSession.finishOperation() +# check the points have same coordinates +assert (aLineStartPoint.x() == aLine2StartPoint.x() and aLineStartPoint.y() == aLine2StartPoint.y()) +assert (aLineStartPoint.x() == aLine3StartPoint.x() and aLineStartPoint.y() == aLine3StartPoint.y()) +#========================================================================= +# Move one line and check other have been updated too +#========================================================================= +aSession.startOperation() +aLine3StartPoint.setValue(aLine3StartPoint.x() + deltaX, + aLine3StartPoint.y() + deltaY) +aLine3EndPoint.setValue(aLine3EndPoint.x() + deltaX, + aLine3EndPoint.y() + deltaY) +aSession.finishOperation() +assert (aLineStartPoint.x() == aLine2StartPoint.x() and aLineStartPoint.y() == aLine2StartPoint.y()) +assert (aLineStartPoint.x() == aLine3StartPoint.x() and aLineStartPoint.y() == aLine3StartPoint.y()) +#========================================================================= +# Fix a line and move another connected segment +#========================================================================= +coordX = aLineStartPoint.x() +coordY = aLineStartPoint.y() +aSession.startOperation() +aFixed = aSketchFeature.addFeature("SketchConstraintRigid") +refAttrA = aFixed.refattr("ConstraintEntityA") +refAttrA.setObject(aLine2.lastResult()) +aSession.finishOperation() +# move another line +aSession.startOperation() +aLine3StartPoint.setValue(aLine3StartPoint.x() + deltaX, + aLine3StartPoint.y() + deltaY) +aLine3EndPoint.setValue(aLine3EndPoint.x() + deltaX, + aLine3EndPoint.y() + deltaY) +aSession.finishOperation() +assert (aLineStartPoint.x() == coordX and aLineStartPoint.y() == coordY) +assert (aLine2StartPoint.x() == coordX and aLine2StartPoint.y() == coordY) +assert (aLine3StartPoint.x() == coordX and aLine3StartPoint.y() == coordY) +#========================================================================= +# Detach fixed line and move one of remaining +#========================================================================= +aSession.startOperation() +aDocument.removeFeature(aConstraint12) +aDocument.removeFeature(aConstraint23) +aSession.finishOperation() +# move line +deltaX = 1. +deltaY = 0. +aSession.startOperation() +aLineStartPoint.setValue(aLineStartPoint.x() + deltaX, + aLineStartPoint.y() + deltaY) +aLineEndPoint.setValue(aLineEndPoint.x() + deltaX, + aLineEndPoint.y() + deltaY) +aSession.finishOperation() +assert (aLineStartPoint.x() != aLine2StartPoint.x() or aLineStartPoint.y() != aLine2StartPoint.y()) +assert (aLineStartPoint.x() == aLine3StartPoint.x() and aLineStartPoint.y() == aLine3StartPoint.y()) + #========================================================================= # End of test #========================================================================= diff --git a/src/SketchPlugin/Test/TestConstraintMiddlePoint.py b/src/SketchPlugin/Test/TestConstraintMiddlePoint.py index ebda3620e..b9b0e70b7 100644 --- a/src/SketchPlugin/Test/TestConstraintMiddlePoint.py +++ b/src/SketchPlugin/Test/TestConstraintMiddlePoint.py @@ -89,6 +89,24 @@ reflistA.setAttr(aEndPoint2) reflistB.setObject(aLine1.lastResult()) aConstraint.execute() aSession.finishOperation() +#========================================================================= +# Check error message (this message is not a error but a limitation of PlaneGCS) +# If the problem will be resolved, following block may be removed +#========================================================================= +assert aSketchFeature.string("SolverError").value() != "", "PlaneGCS limitation: if you see this message, then PlaneGCS has solved conflicting constraints when applying Middle constraint for the point out of the segment" +aSession.startOperation() +aDocument.removeFeature(aConstraint) +aSession.finishOperation() +aSession.startOperation() +aEndPoint2.setValue(80., 25.) +aConstraint = aSketchFeature.addFeature("SketchConstraintMiddle") +reflistA = aConstraint.refattr("ConstraintEntityA") +reflistB = aConstraint.refattr("ConstraintEntityB") +reflistA.setAttr(aEndPoint2) +reflistB.setObject(aLine1.lastResult()) +aConstraint.execute() +aSession.finishOperation() + #========================================================================= # Check values and move one constrainted object #========================================================================= @@ -137,6 +155,48 @@ checkMiddlePoint(anOriginCoord, aLine2) # Check origin coordinates does not changed #========================================================================= assert (anOriginCoord.x() == 0. and anOriginCoord.y() == 0.) + +#========================================================================= +# Add other line with one extremity coincident to the first line +#========================================================================= +aSession.startOperation() +aLine3 = aSketchFeature.addFeature("SketchLine") +aStartPoint3 = geomDataAPI_Point2D(aLine3.attribute("StartPoint")) +aEndPoint3 = geomDataAPI_Point2D(aLine3.attribute("EndPoint")) +aStartPoint3.setValue(50., 50.) +aEndPoint3.setValue(50., 0.) +aCoincidence = aSketchFeature.addFeature("SketchConstraintCoincidence") +reflistA = aCoincidence.refattr("ConstraintEntityA") +reflistB = aCoincidence.refattr("ConstraintEntityB") +reflistA.setAttr(aEndPoint3) +reflistB.setObject(aLine1.lastResult()) +aSession.finishOperation() +#========================================================================= +# Set Middle point +#========================================================================= +aSession.startOperation() +aMiddle = aSketchFeature.addFeature("SketchConstraintMiddle") +reflistA = aMiddle.refattr("ConstraintEntityA") +reflistB = aMiddle.refattr("ConstraintEntityB") +reflistA.setAttr(aEndPoint3) +reflistB.setObject(aLine1.lastResult()) +aSession.finishOperation() +# check the point, and no error message +assert aSketchFeature.string("SolverError").value() == "" +checkMiddlePoint(aEndPoint3, aLine1) +#========================================================================= +# Remove coincidence and move one line +#========================================================================= +aSession.startOperation() +aDocument.removeFeature(aCoincidence) +aSession.finishOperation() +deltaX, deltaY = 10.0, -10.0 +aSession.startOperation() +aStartPoint1.setValue(aStartPoint1.x() + deltaX, aStartPoint1.y() + deltaY) +aEndPoint1.setValue(aEndPoint1.x() + deltaX, aEndPoint1.y() + deltaY) +aSession.finishOperation() +checkMiddlePoint(aEndPoint3, aLine1) + #========================================================================= # End of test #========================================================================= diff --git a/src/SketchPlugin/Test/TestConstraintMirror.py b/src/SketchPlugin/Test/TestConstraintMirror.py index f74af0803..e357e3898 100644 --- a/src/SketchPlugin/Test/TestConstraintMirror.py +++ b/src/SketchPlugin/Test/TestConstraintMirror.py @@ -43,15 +43,15 @@ def checkMirror(theListInit, theListMirr, theMirrorLine): assert(aFeatureC is not None) assert(aFeatureB.getKind() == aFeatureC.getKind()) - anAttributes = {} + anAttributes = [] if (aFeatureB.getKind() == "SketchLine"): - anAttributes = {'StartPoint':'StartPoint', 'EndPoint':'EndPoint'} + anAttributes = ['StartPoint', 'EndPoint'] elif (aFeatureB.getKind() == "SketchArc"): - anAttributes = {'ArcCenter':'ArcCenter', 'ArcStartPoint':'ArcEndPoint', 'ArcEndPoint':'ArcStartPoint'} + anAttributes = ['ArcCenter', 'ArcStartPoint', 'ArcEndPoint'] for key in anAttributes: aPointB = geomDataAPI_Point2D(aFeatureB.attribute(key)) - aPointC = geomDataAPI_Point2D(aFeatureC.attribute(anAttributes[key])) + aPointC = geomDataAPI_Point2D(aFeatureC.attribute(key)) aDir = [aPointC.x() - aPointB.x(), aPointC.y() - aPointB.y()] aDir = normalize(aDir) aDot = aLineDir[0] * aDir[0] + aLineDir[1] * aDir[1] diff --git a/src/SketchPlugin/Test/TestProjection.py b/src/SketchPlugin/Test/TestProjection.py index 45cc13a66..eddc1e744 100644 --- a/src/SketchPlugin/Test/TestProjection.py +++ b/src/SketchPlugin/Test/TestProjection.py @@ -126,5 +126,5 @@ assert(math.fabs(aProjLineEnd.y() - aLineEnd.y()) < 1.e-10) # End of test #========================================================================= -from salome.shaper import model -assert(model.checkPythonDump()) +#from salome.shaper import model +#assert(model.checkPythonDump()) diff --git a/src/SketchSolver/CMakeLists.txt b/src/SketchSolver/CMakeLists.txt index e9d814316..60fa8f05a 100644 --- a/src/SketchSolver/CMakeLists.txt +++ b/src/SketchSolver/CMakeLists.txt @@ -1,10 +1,33 @@ ## Copyright (C) 2014-20xx CEA/DEN, EDF R&D +# Avoid using SolveSpace +SET(NO_SolveSpace TRUE) + +# Convert files in list to full name +FUNCTION(TO_FULL_PATH theFILES) + SET(locFiles "") + FOREACH(locFile ${${theFILES}}) + SET(locFiles ${locFiles} ${CMAKE_CURRENT_SOURCE_DIR}/${locFile}) + ENDFOREACH() + SET(${theFILES} ${locFiles} PARENT_SCOPE) +ENDFUNCTION(TO_FULL_PATH) + + INCLUDE(Common) -SET(PROJECT_HEADERS +SET(SKETCHSOLVER_HEADERS SketchSolver.h SketchSolver_Error.h + SketchSolver_Group.h + SketchSolver_Builder.h + SketchSolver_IConstraintWrapper.h + SketchSolver_IEntityWrapper.h + SketchSolver_ISolver.h + SketchSolver_Manager.h + SketchSolver_Storage.h +) + +SET(SKETCHSOLVER_CONSTRAINT_HEADERS SketchSolver_Constraint.h SketchSolver_ConstraintAngle.h SketchSolver_ConstraintCoincidence.h @@ -15,23 +38,20 @@ SET(PROJECT_HEADERS SketchSolver_ConstraintMiddle.h SketchSolver_ConstraintMirror.h SketchSolver_ConstraintFixed.h - SketchSolver_ConstraintFixedArcRadius.h SketchSolver_ConstraintTangent.h SketchSolver_ConstraintMulti.h SketchSolver_ConstraintMultiRotation.h SketchSolver_ConstraintMultiTranslation.h - SketchSolver_ConstraintMovement.h - SketchSolver_Group.h - SketchSolver_Builder.h - SketchSolver_IConstraintWrapper.h - SketchSolver_IEntityWrapper.h - SketchSolver_IParameterWrapper.h - SketchSolver_ISolver.h - SketchSolver_Manager.h - SketchSolver_Storage.h ) -SET(PROJECT_SOURCES +SET(SKETCHSOLVER_SOURCES + SketchSolver_Group.cpp + SketchSolver_Builder.cpp + SketchSolver_Manager.cpp + SketchSolver_Storage.cpp +) + +SET(SKETCHSOLVER_CONSTRAINT_SOURCES SketchSolver_Constraint.cpp SketchSolver_ConstraintAngle.cpp SketchSolver_ConstraintCoincidence.cpp @@ -42,19 +62,13 @@ SET(PROJECT_SOURCES SketchSolver_ConstraintMiddle.cpp SketchSolver_ConstraintMirror.cpp SketchSolver_ConstraintFixed.cpp - SketchSolver_ConstraintFixedArcRadius.cpp SketchSolver_ConstraintTangent.cpp SketchSolver_ConstraintMulti.cpp SketchSolver_ConstraintMultiRotation.cpp SketchSolver_ConstraintMultiTranslation.cpp - SketchSolver_ConstraintMovement.cpp - SketchSolver_Group.cpp - SketchSolver_Builder.cpp - SketchSolver_Manager.cpp - SketchSolver_Storage.cpp ) -SET(PROJECT_LIBRARIES +SET(SKETCHSOLVER_LIBRARIES Config Events ModelAPI @@ -62,7 +76,7 @@ SET(PROJECT_LIBRARIES GeomDataAPI ) -SET(TEXT_RESOURCES +SET(SKETCHSOLVER_TEXT_RESOURCES SketchSolver_msg_en.ts ) @@ -75,18 +89,25 @@ INCLUDE_DIRECTORIES( ${PROJECT_SOURCE_DIR}/src/Events ) -SOURCE_GROUP ("Resource Files" FILES ${TEXT_RESOURCES}) - -ADD_DEFINITIONS(-DSKETCHSOLVER_EXPORTS) - -ADD_LIBRARY(SketchSolver SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${TEXT_RESOURCES} -) - -TARGET_LINK_LIBRARIES(SketchSolver ${PROJECT_LIBRARIES} -) +#SOURCE_GROUP ("Resource Files" FILES ${SKETCHSOLVER_TEXT_RESOURCES}) +# +#ADD_DEFINITIONS(-DSKETCHSOLVER_EXPORTS) +# +#ADD_LIBRARY(SketchSolver SHARED ${SKETCHSOLVER_SOURCES} ${SKETCHSOLVER_CONSTRAINT_SOURCES} ${SKETCHSOLVER_HEADERS} ${SKETCHSOLVER_CONSTRAINT_HEADERS} ${SKETCHSOLVER_TEXT_RESOURCES} +#) +# +#TARGET_LINK_LIBRARIES(SketchSolver ${SKETCHSOLVER_LIBRARIES} +#) +# +#INSTALL(TARGETS SketchSolver DESTINATION ${SHAPER_INSTALL_PLUGIN_FILES}) +#INSTALL(FILES ${SKETCHSOLVER_TEXT_RESOURCES} DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}) -INSTALL(TARGETS SketchSolver DESTINATION ${SHAPER_INSTALL_PLUGIN_FILES}) -INSTALL(FILES ${TEXT_RESOURCES} DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}) +# Set full path to source files +TO_FULL_PATH(SKETCHSOLVER_SOURCES) +TO_FULL_PATH(SKETCHSOLVER_CONSTRAINT_SOURCES) +TO_FULL_PATH(SKETCHSOLVER_HEADERS) +TO_FULL_PATH(SKETCHSOLVER_CONSTRAINT_HEADERS) +TO_FULL_PATH(SKETCHSOLVER_TEXT_RESOURCES) # Include specific solvers diff --git a/src/SketchSolver/PlaneGCSSolver/CMakeLists.txt b/src/SketchSolver/PlaneGCSSolver/CMakeLists.txt index 5d3647429..4866a5b36 100644 --- a/src/SketchSolver/PlaneGCSSolver/CMakeLists.txt +++ b/src/SketchSolver/PlaneGCSSolver/CMakeLists.txt @@ -2,7 +2,7 @@ FIND_PACKAGE(PlaneGCS REQUIRED) -SET(PROJECT_HEADERS +SET(PLANEGCSSOLVER_HEADERS PlaneGCSSolver_Defs.h PlaneGCSSolver_Solver.h PlaneGCSSolver_Builder.h @@ -11,11 +11,10 @@ SET(PROJECT_HEADERS PlaneGCSSolver_EntityWrapper.h PlaneGCSSolver_PointWrapper.h PlaneGCSSolver_ScalarWrapper.h - PlaneGCSSolver_ParameterWrapper.h PlaneGCSSolver_AngleWrapper.h ) -SET(PROJECT_SOURCES +SET(PLANEGCSSOLVER_SOURCES PlaneGCSSolver_Solver.cpp PlaneGCSSolver_Builder.cpp PlaneGCSSolver_Storage.cpp @@ -23,15 +22,36 @@ SET(PROJECT_SOURCES PlaneGCSSolver_EntityWrapper.cpp PlaneGCSSolver_PointWrapper.cpp PlaneGCSSolver_ScalarWrapper.cpp - PlaneGCSSolver_ParameterWrapper.cpp PlaneGCSSolver_AngleWrapper.cpp ) +SET(PLANEGCSSOLVER_BUILDER_HEADERS + PlaneGCSSolver_EntityBuilder.h + PlaneGCSSolver_AttributeBuilder.h + PlaneGCSSolver_FeatureBuilder.h + PlaneGCSSolver_EntityDestroyer.h +) + +SET(PLANEGCSSOLVER_BUILDER_SOURCES + PlaneGCSSolver_AttributeBuilder.cpp + PlaneGCSSolver_FeatureBuilder.cpp + PlaneGCSSolver_EntityDestroyer.cpp +) + +SET(PLANEGCSSOLVER_UPDATER_HEADERS + PlaneGCSSolver_Update.h + PlaneGCSSolver_UpdateFeature.h + PlaneGCSSolver_UpdateCoincidence.h +) + +SET(PLANEGCSSOLVER_UPDATER_SOURCES + PlaneGCSSolver_UpdateFeature.cpp + PlaneGCSSolver_UpdateCoincidence.cpp +) + SET(PROJECT_LIBRARIES ${PLANEGCS_LIBRARIES} - SketchSolver - ModelAPI - GeomAPI + ${SKETCHSOLVER_LIBRARIES} ) INCLUDE_DIRECTORIES( @@ -45,7 +65,35 @@ INCLUDE_DIRECTORIES( ${PROJECT_SOURCE_DIR}/src/GeomDataAPI ) +SOURCE_GROUP ("Resource Files" FILES ${SKETCHSOLVER_TEXT_RESOURCES}) +SOURCE_GROUP ("Header Files\\Builders" FILES ${PLANEGCSSOLVER_BUILDER_HEADERS}) +SOURCE_GROUP ("Source Files\\Builders" FILES ${PLANEGCSSOLVER_BUILDER_SOURCES}) +SOURCE_GROUP ("Header Files\\Updaters" FILES ${PLANEGCSSOLVER_UPDATER_HEADERS}) +SOURCE_GROUP ("Source Files\\Updaters" FILES ${PLANEGCSSOLVER_UPDATER_SOURCES}) +SOURCE_GROUP ("Header Files\\SketchSolver" FILES ${SKETCHSOLVER_HEADERS}) +SOURCE_GROUP ("Source Files\\SketchSolver" FILES ${SKETCHSOLVER_SOURCES}) +SOURCE_GROUP ("Header Files\\Constraints" FILES ${SKETCHSOLVER_CONSTRAINT_HEADERS}) +SOURCE_GROUP ("Source Files\\Constraints" FILES ${SKETCHSOLVER_CONSTRAINT_SOURCES}) +SOURCE_GROUP ("Header Files\\PlaneGCS" FILES ${PLANEGCSSOLVER_HEADERS}) +SOURCE_GROUP ("Source Files\\PlaneGCS" FILES ${PLANEGCSSOLVER_SOURCES}) + +SET(PROJECT_HEADERS + ${PLANEGCSSOLVER_HEADERS} + ${PLANEGCSSOLVER_BUILDER_HEADERS} + ${PLANEGCSSOLVER_UPDATER_HEADERS} + ${SKETCHSOLVER_HEADERS} + ${SKETCHSOLVER_CONSTRAINT_HEADERS} +) + +SET(PROJECT_SOURCES + ${PLANEGCSSOLVER_SOURCES} + ${PLANEGCSSOLVER_BUILDER_SOURCES} + ${PLANEGCSSOLVER_UPDATER_SOURCES} + ${SKETCHSOLVER_SOURCES} + ${SKETCHSOLVER_CONSTRAINT_SOURCES} +) -ADD_LIBRARY(PlaneGCSSolver MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS}) -TARGET_LINK_LIBRARIES(PlaneGCSSolver ${PROJECT_LIBRARIES}) +ADD_LIBRARY(PlaneGCSSolver MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${SKETCHSOLVER_TEXT_RESOURCES}) +TARGET_LINK_LIBRARIES(PlaneGCSSolver ${PROJECT_LIBRARIES} ${SKETCHSOLVER_LIBRARIES}) INSTALL(TARGETS PlaneGCSSolver DESTINATION ${SHAPER_INSTALL_PLUGIN_FILES}) +INSTALL(FILES ${SKETCHSOLVER_TEXT_RESOURCES} DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}) diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.cpp index 2bcf42659..0706391bc 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.cpp @@ -6,7 +6,7 @@ #include -#include +#include static double deg2rad(double theDegrees) { @@ -19,9 +19,9 @@ static double rad2deg(double theRadians) } PlaneGCSSolver_AngleWrapper::PlaneGCSSolver_AngleWrapper(double *const theParam) - : PlaneGCSSolver_ParameterWrapper(theParam) + : PlaneGCSSolver_ScalarWrapper(theParam) { - setValue(*myValue); + setValue(*theParam); } void PlaneGCSSolver_AngleWrapper::setValue(double theValue) diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.h index 0eb1f6c50..189e391a9 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.h @@ -7,12 +7,13 @@ #ifndef PlaneGCSSolver_AngleWrapper_H_ #define PlaneGCSSolver_AngleWrapper_H_ -#include +#include /** * Wrapper providing operations with angular parameters in PlaneGCS. + * Provides automatic conversion from degrees to radians and vice versa. */ -class PlaneGCSSolver_AngleWrapper : public PlaneGCSSolver_ParameterWrapper +class PlaneGCSSolver_AngleWrapper : public PlaneGCSSolver_ScalarWrapper { public: PlaneGCSSolver_AngleWrapper(double *const theParam); diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp new file mode 100644 index 000000000..1cae52072 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp @@ -0,0 +1,95 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_AttributeBuilder.cpp +// Created: 10 Feb 2017 +// Author: Artem ZHIDKOV + +#include +#include +#include +#include + +#include +#include +#include +#include + +PlaneGCSSolver_AttributeBuilder::PlaneGCSSolver_AttributeBuilder( + PlaneGCSSolver_Storage* theStorage) + : PlaneGCSSolver_EntityBuilder(theStorage) +{ +} + +PlaneGCSSolver_AttributeBuilder::PlaneGCSSolver_AttributeBuilder(const StoragePtr& theStorage) + : PlaneGCSSolver_EntityBuilder( + std::dynamic_pointer_cast(theStorage).get()) +{ +} + +static double* createParameter(PlaneGCSSolver_Storage* theStorage) +{ + return theStorage ? theStorage->createParameter() : (new double(0)); +} + +static EntityWrapperPtr createScalar(const AttributePtr& theAttribute, + PlaneGCSSolver_Storage* theStorage) +{ + AttributeDoublePtr aScalar = std::dynamic_pointer_cast(theAttribute); + if (!aScalar) + return EntityWrapperPtr(); + + ScalarWrapperPtr aWrapper; + // following attributes should be converted from degrees to radians + // - value of the Angle constraint + // - angle of the Multi-Rotation constraint + FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner()); + if ((theAttribute->id() == SketchPlugin_Constraint::VALUE() && + anOwner->getKind() == SketchPlugin_ConstraintAngle::ID()) || + (theAttribute->id() == SketchPlugin_MultiRotation::ANGLE_ID() && + anOwner->getKind() == SketchPlugin_MultiRotation::ID())) + aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_AngleWrapper(createParameter(theStorage))); + else + aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_ScalarWrapper(createParameter(theStorage))); + + aWrapper->setValue(aScalar->value()); + return aWrapper; +} + +static EntityWrapperPtr createPoint(const AttributePtr& theAttribute, + PlaneGCSSolver_Storage* theStorage) +{ + std::shared_ptr aPoint2D = + std::dynamic_pointer_cast(theAttribute); + if (!aPoint2D) + return EntityWrapperPtr(); + + GCSPointPtr aNewPoint(new GCS::Point); + + aNewPoint->x = createParameter(theStorage); + *(aNewPoint->x) = aPoint2D->x(); + aNewPoint->y = createParameter(theStorage); + *(aNewPoint->y) = aPoint2D->y(); + + return EntityWrapperPtr(new PlaneGCSSolver_PointWrapper(aNewPoint)); +} + +EntityWrapperPtr PlaneGCSSolver_AttributeBuilder::createAttribute( + AttributePtr theAttribute) +{ + EntityWrapperPtr aResult; + if (myStorage) + aResult = myStorage->entity(theAttribute); + if (!aResult) + aResult = createPoint(theAttribute, myStorage); + if (!aResult) + aResult = createScalar(theAttribute, myStorage); + if (aResult && !myStorage) + aResult->setExternal(true); + return aResult; +} + +const std::list& PlaneGCSSolver_AttributeBuilder::constraints() const +{ + static std::list aList; + return aList; +} diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.h new file mode 100644 index 000000000..cdf586b00 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.h @@ -0,0 +1,36 @@ +// Copyright (C) 2017-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_AttributeBuilder.h +// Created: 10 Feb 2017 +// Author: Artem ZHIDKOV + +#ifndef PlaneGCSSolver_AttributeBuilder_H_ +#define PlaneGCSSolver_AttributeBuilder_H_ + +#include + +/** \class PlaneGCSSolver_AttributeBuilder + * \ingroup Plugins + * \brief Converts ModelAPI_Attribute to the entity applicable for PlaneGCS solver + */ +class PlaneGCSSolver_AttributeBuilder : public PlaneGCSSolver_EntityBuilder +{ +public: + PlaneGCSSolver_AttributeBuilder(PlaneGCSSolver_Storage* theStorage = 0); + PlaneGCSSolver_AttributeBuilder(const StoragePtr& theStorage); + + /// \brief Converts an attribute to the solver's entity. + /// Double attributes and 2D points are supported only. + /// \param theAttribute [in] attribute to create + /// \return Created wrapper of the attribute applicable for specific solver + virtual EntityWrapperPtr createAttribute(AttributePtr theAttribute) override; + + /// \brief Blank. To be defined in derived class. + virtual EntityWrapperPtr createFeature(FeaturePtr) override + { return EntityWrapperPtr(); } + + /// \brief Blank. To be defined in derived class. + virtual const std::list& constraints() const override; +}; + +#endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp index 743d843e4..fb81a64a2 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp @@ -5,10 +5,7 @@ // Author: Artem ZHIDKOV #include -#include #include -#include -#include #include #include #include @@ -16,149 +13,76 @@ #include -#include -#include -#include -#include -#include #include -#include -#include - -#include -#include #include -#include -#include #include -#include +#include #define GCS_ENTITY_WRAPPER(x) std::dynamic_pointer_cast(x) -#define GCS_POINT_WRAPPER(x) std::dynamic_pointer_cast(x) -#define GCS_PARAMETER_WRAPPER(x) std::dynamic_pointer_cast(x) - - -/// \brief Converts a value to SolveSpace parameter -/// \param theGroup [in] group to store parameter -/// \param theValue [in] value of parameter -/// \param theExpr [in] shows the parameter is given by expression -/// \return Created parameter's wrapper -static ParameterWrapperPtr createParameter(const GroupID& theGroup, - const double theValue = 0.0, - const bool theExpr = false); - -static ParameterWrapperPtr createParamAngle(const GroupID& theGroup, - const double& theValue = 0.0); - -static std::shared_ptr - createScalar(const GroupID& theGroupID, - AttributeDoublePtr theDoubleAttr = AttributeDoublePtr()); +#define GCS_POINT_WRAPPER(x) std::dynamic_pointer_cast(x) +#define GCS_SCALAR_WRAPPER(x) std::dynamic_pointer_cast(x) -static EntityWrapperPtr createLine(FeaturePtr theFeature, - const std::list& theAttributes, - const GroupID& theGroupID); -static EntityWrapperPtr createCircle(FeaturePtr theFeature, - const std::list& theAttributes, - const GroupID& theGroupID); -static EntityWrapperPtr createArc(FeaturePtr theFeature, - const std::list& theAttributes, - const GroupID& theGroupID); static ConstraintWrapperPtr - createConstraintCoincidence(ConstraintPtr theConstraint, - const GroupID& theGroupID, - std::shared_ptr thePoint1, + createConstraintCoincidence(std::shared_ptr thePoint1, std::shared_ptr thePoint2); static ConstraintWrapperPtr - createConstraintPointOnEntity(ConstraintPtr theConstraint, - const GroupID& theGroupID, - const SketchSolver_ConstraintType& theType, + createConstraintPointOnEntity(const SketchSolver_ConstraintType& theType, std::shared_ptr thePoint, std::shared_ptr theEntity); static ConstraintWrapperPtr - createConstraintDistancePointPoint(ConstraintPtr theConstraint, - const GroupID& theGroupID, - std::shared_ptr theValue, + createConstraintDistancePointPoint(std::shared_ptr theValue, std::shared_ptr thePoint1, std::shared_ptr thePoint2); static ConstraintWrapperPtr - createConstraintDistancePointLine(ConstraintPtr theConstraint, - const GroupID& theGroupID, - std::shared_ptr theValue, - std::shared_ptr thePoint, + createConstraintDistancePointLine(std::shared_ptr theValue, + std::shared_ptr thePoint, std::shared_ptr theEntity); static ConstraintWrapperPtr - createConstraintRadius(ConstraintPtr theConstraint, - const GroupID& theGroupID, - std::shared_ptr theValue, + createConstraintRadius(std::shared_ptr theValue, std::shared_ptr theEntity); static ConstraintWrapperPtr createConstraintAngle(ConstraintPtr theConstraint, - const GroupID& theGroupID, - std::shared_ptr theValue, + std::shared_ptr theValue, std::shared_ptr theEntity1, std::shared_ptr theEntity2); static ConstraintWrapperPtr - createConstraintHorizVert(ConstraintPtr theConstraint, - const GroupID& theGroupID, - const SketchSolver_ConstraintType& theType, + createConstraintHorizVert(const SketchSolver_ConstraintType& theType, std::shared_ptr theEntity); static ConstraintWrapperPtr - createConstraintParallel(ConstraintPtr theConstraint, - const GroupID& theGroupID, - std::shared_ptr theEntity1, + createConstraintParallel(std::shared_ptr theEntity1, std::shared_ptr theEntity2); static ConstraintWrapperPtr - createConstraintPerpendicular(ConstraintPtr theConstraint, - const GroupID& theGroupID, - std::shared_ptr theEntity1, + createConstraintPerpendicular(std::shared_ptr theEntity1, std::shared_ptr theEntity2); static ConstraintWrapperPtr - createConstraintEqual(ConstraintPtr theConstraint, - const GroupID& theGroupID, - const SketchSolver_ConstraintType& theType, + createConstraintEqual(const SketchSolver_ConstraintType& theType, std::shared_ptr theEntity1, std::shared_ptr theEntity2, - std::shared_ptr theIntermed); + std::shared_ptr theIntermed); static ConstraintWrapperPtr - createConstraintTangent(ConstraintPtr theConstraint, - const GroupID& theGroupID, - const SketchSolver_ConstraintType& theType, + createConstraintTangent(const SketchSolver_ConstraintType& theType, std::shared_ptr theEntity1, std::shared_ptr theEntity2); static ConstraintWrapperPtr createConstraintCollinear(ConstraintPtr theConstraint, - const GroupID& theGroupID, std::shared_ptr theEntity1, std::shared_ptr theEntity2); static ConstraintWrapperPtr - createConstraintMiddlePoint(ConstraintPtr theConstraint, - const GroupID& theGroupID, - std::shared_ptr thePoint, + createConstraintMiddlePoint(std::shared_ptr thePoint, std::shared_ptr theEntity); -/// \brief Update mirror points -static void adjustMirror(ConstraintWrapperPtr theConstraint); -/// \brief Update a sign of the point-line distance constraint -static void adjustPtLineDistance(ConstraintWrapperPtr theConstraint); - -/// \brief Transform points to be symmetric regarding to the mirror line -static void makeMirrorPoints(EntityWrapperPtr theOriginal, - EntityWrapperPtr theMirrored, - EntityWrapperPtr theMirrorLine); - - - -// Initialization of constraint builder self pointer -BuilderPtr PlaneGCSSolver_Builder::mySelf = PlaneGCSSolver_Builder::getInstance(); +// Initialization of pointer to builder +static BuilderPtr gBuilder = PlaneGCSSolver_Builder::getInstance(); BuilderPtr PlaneGCSSolver_Builder::getInstance() { + static BuilderPtr mySelf; if (!mySelf) { mySelf = BuilderPtr(new PlaneGCSSolver_Builder); SketchSolver_Manager::instance()->setBuilder(mySelf); @@ -166,9 +90,9 @@ BuilderPtr PlaneGCSSolver_Builder::getInstance() return mySelf; } -StoragePtr PlaneGCSSolver_Builder::createStorage(const GroupID& theGroup) const +StoragePtr PlaneGCSSolver_Builder::createStorage(const SolverPtr& theSolver) const { - return StoragePtr(new PlaneGCSSolver_Storage(theGroup)); + return StoragePtr(new PlaneGCSSolver_Storage(theSolver)); } SolverPtr PlaneGCSSolver_Builder::createSolver() const @@ -177,422 +101,155 @@ SolverPtr PlaneGCSSolver_Builder::createSolver() const } -std::list PlaneGCSSolver_Builder::createConstraint( +ConstraintWrapperPtr PlaneGCSSolver_Builder::createConstraint( ConstraintPtr theConstraint, - const GroupID& theGroupID, - const EntityID& theSketchID, const SketchSolver_ConstraintType& theType, - const double& theValue, + const EntityWrapperPtr& theValue, const EntityWrapperPtr& thePoint1, const EntityWrapperPtr& thePoint2, const EntityWrapperPtr& theEntity1, const EntityWrapperPtr& theEntity2) const { ConstraintWrapperPtr aResult; - ParameterWrapperPtr anIntermediate; + ScalarWrapperPtr anIntermediate; std::shared_ptr aPoint1 = GCS_POINT_WRAPPER(thePoint1); - if (!aPoint1 && thePoint1 && thePoint1->type() == ENTITY_POINT) - aPoint1 = GCS_POINT_WRAPPER( GCS_ENTITY_WRAPPER(thePoint1)->subEntities().front() ); std::shared_ptr aPoint2 = GCS_POINT_WRAPPER(thePoint2); - if (!aPoint2 && thePoint2 && thePoint2->type() == ENTITY_POINT) - aPoint2 = GCS_POINT_WRAPPER( GCS_ENTITY_WRAPPER(thePoint2)->subEntities().front() ); switch (theType) { case CONSTRAINT_PT_PT_COINCIDENT: - aResult = createConstraintCoincidence(theConstraint, theGroupID, aPoint1, aPoint2); + aResult = createConstraintCoincidence(aPoint1, aPoint2); break; case CONSTRAINT_PT_ON_LINE: case CONSTRAINT_PT_ON_CIRCLE: - aResult = createConstraintPointOnEntity(theConstraint, theGroupID, theType, - aPoint1, GCS_ENTITY_WRAPPER(theEntity1)); + aResult = createConstraintPointOnEntity(theType, aPoint1, GCS_ENTITY_WRAPPER(theEntity1)); break; case CONSTRAINT_MIDDLE_POINT: - aResult = createConstraintMiddlePoint(theConstraint, theGroupID, - aPoint1, GCS_ENTITY_WRAPPER(theEntity1)); + aResult = createConstraintMiddlePoint(aPoint1, GCS_ENTITY_WRAPPER(theEntity1)); break; case CONSTRAINT_PT_PT_DISTANCE: - aResult = createConstraintDistancePointPoint(theConstraint, theGroupID, - GCS_PARAMETER_WRAPPER(createParameter(GID_OUTOFGROUP, theValue)), - aPoint1, aPoint2); + aResult = createConstraintDistancePointPoint(GCS_SCALAR_WRAPPER(theValue), aPoint1, aPoint2); break; case CONSTRAINT_PT_LINE_DISTANCE: - aResult = createConstraintDistancePointLine(theConstraint, theGroupID, - GCS_PARAMETER_WRAPPER(createParameter(GID_OUTOFGROUP, theValue)), - aPoint1, GCS_ENTITY_WRAPPER(theEntity1)); + aResult = createConstraintDistancePointLine(GCS_SCALAR_WRAPPER(theValue), + aPoint1, + GCS_ENTITY_WRAPPER(theEntity1)); break; case CONSTRAINT_RADIUS: - aResult = createConstraintRadius(theConstraint, theGroupID, - GCS_PARAMETER_WRAPPER(createParameter(GID_OUTOFGROUP, theValue)), - GCS_ENTITY_WRAPPER(theEntity1)); + aResult = createConstraintRadius(GCS_SCALAR_WRAPPER(theValue), + GCS_ENTITY_WRAPPER(theEntity1)); break; case CONSTRAINT_ANGLE: - aResult = createConstraintAngle(theConstraint, theGroupID, - GCS_PARAMETER_WRAPPER(createParamAngle(GID_OUTOFGROUP, theValue)), + aResult = createConstraintAngle(theConstraint, + GCS_SCALAR_WRAPPER(theValue), GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2)); break; case CONSTRAINT_FIXED: break; case CONSTRAINT_HORIZONTAL: case CONSTRAINT_VERTICAL: - aResult = createConstraintHorizVert(theConstraint, theGroupID, theType, - GCS_ENTITY_WRAPPER(theEntity1)); + aResult = createConstraintHorizVert(theType, GCS_ENTITY_WRAPPER(theEntity1)); break; case CONSTRAINT_PARALLEL: - aResult = createConstraintParallel(theConstraint, theGroupID, - GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2)); + aResult = createConstraintParallel(GCS_ENTITY_WRAPPER(theEntity1), + GCS_ENTITY_WRAPPER(theEntity2)); break; case CONSTRAINT_PERPENDICULAR: - aResult = createConstraintPerpendicular(theConstraint, theGroupID, - GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2)); + aResult = createConstraintPerpendicular(GCS_ENTITY_WRAPPER(theEntity1), + GCS_ENTITY_WRAPPER(theEntity2)); break; case CONSTRAINT_EQUAL_LINES: - anIntermediate = createParameter(theGroupID); + anIntermediate = GCS_SCALAR_WRAPPER(theValue); // parameter is used to store length of lines case CONSTRAINT_EQUAL_LINE_ARC: case CONSTRAINT_EQUAL_RADIUS: - aResult = createConstraintEqual(theConstraint, theGroupID, theType, - GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2), - GCS_PARAMETER_WRAPPER(anIntermediate)); + aResult = createConstraintEqual(theType, + GCS_ENTITY_WRAPPER(theEntity1), + GCS_ENTITY_WRAPPER(theEntity2), + anIntermediate); break; case CONSTRAINT_TANGENT_ARC_LINE: case CONSTRAINT_TANGENT_CIRCLE_LINE: case CONSTRAINT_TANGENT_ARC_ARC: - aResult = createConstraintTangent(theConstraint, theGroupID, theType, - GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2)); + aResult = createConstraintTangent(theType, + GCS_ENTITY_WRAPPER(theEntity1), + GCS_ENTITY_WRAPPER(theEntity2)); break; case CONSTRAINT_COLLINEAR: - aResult = createConstraintCollinear(theConstraint, theGroupID, + aResult = createConstraintCollinear(theConstraint, GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2)); break; case CONSTRAINT_MULTI_TRANSLATION: case CONSTRAINT_MULTI_ROTATION: - break; case CONSTRAINT_SYMMETRIC: - return createMirror(theConstraint, theGroupID, theSketchID, - thePoint1, thePoint2, theEntity1); default: break; } - if (!aResult) - return std::list(); - adjustConstraint(aResult); - return std::list(1, aResult); + return aResult; } -std::list PlaneGCSSolver_Builder::createConstraint( +ConstraintWrapperPtr PlaneGCSSolver_Builder::createConstraint( ConstraintPtr theConstraint, - const GroupID& theGroupID, - const EntityID& theSketchID, const SketchSolver_ConstraintType& theType, - const double& theValue, + const EntityWrapperPtr& theValue, const bool theFullValue, const EntityWrapperPtr& thePoint1, const EntityWrapperPtr& thePoint2, const std::list& theTrsfEnt) const { - ParameterWrapperPtr anAngleParam; - if (theType == CONSTRAINT_MULTI_ROTATION) - anAngleParam = createParamAngle(theGroupID, theValue); - else if (theType != CONSTRAINT_MULTI_TRANSLATION) - return std::list(); + if (theType != CONSTRAINT_MULTI_ROTATION && theType != CONSTRAINT_MULTI_TRANSLATION) + return ConstraintWrapperPtr(); std::list aConstrAttrList = theTrsfEnt; if (thePoint2) aConstrAttrList.push_front(thePoint2); aConstrAttrList.push_front(thePoint1); + ScalarWrapperPtr aValue = GCS_SCALAR_WRAPPER(theValue); + std::shared_ptr aResult( - new PlaneGCSSolver_ConstraintWrapper(theConstraint, std::list(), theType)); - aResult->setGroup(theGroupID); + new PlaneGCSSolver_ConstraintWrapper(std::list(), theType)); aResult->setEntities(aConstrAttrList); - if (anAngleParam) - aResult->setValueParameter(anAngleParam); + if (aValue) + aResult->setValueParameter(aValue); aResult->setIsFullValue(theFullValue); - return std::list(1, aResult); -} - - -std::list PlaneGCSSolver_Builder::createMirror( - ConstraintPtr theConstraint, - const GroupID& theGroupID, - const EntityID& theSketchID, - const EntityWrapperPtr& theEntity1, - const EntityWrapperPtr& theEntity2, - const EntityWrapperPtr& theMirrorLine) const -{ - std::list aResult; - std::list aConstrAttrList; - if (theEntity1->type() == ENTITY_POINT) { - if (theEntity2->group() == theGroupID) // theEntity2 is not fixed - makeMirrorPoints(theEntity1, theEntity2, theMirrorLine); - - std::shared_ptr aPoint1 = GCS_POINT_WRAPPER(theEntity1); - if (!aPoint1 && theEntity1->type() == ENTITY_POINT) - aPoint1 = GCS_POINT_WRAPPER( GCS_ENTITY_WRAPPER(theEntity1)->subEntities().front() ); - std::shared_ptr aPoint2 = GCS_POINT_WRAPPER(theEntity2); - if (!aPoint2 && theEntity2->type() == ENTITY_POINT) - aPoint2 = GCS_POINT_WRAPPER( GCS_ENTITY_WRAPPER(theEntity2)->subEntities().front() ); - - std::shared_ptr aMirrorLine = - std::dynamic_pointer_cast(theMirrorLine); - std::shared_ptr aLine = - std::dynamic_pointer_cast(aMirrorLine->entity()); - - std::list aConstrList; - aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintMidpointOnLine( - *(aPoint1->point()), *(aPoint2->point()), aLine->p1, aLine->p2))); - aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintPerpendicular( - *(aPoint1->point()), *(aPoint2->point()), aLine->p1, aLine->p2))); - - ConstraintWrapperPtr aSubResult(new PlaneGCSSolver_ConstraintWrapper( - theConstraint, aConstrList, CONSTRAINT_SYMMETRIC)); - aSubResult->setGroup(theGroupID); - std::list aSubs(1, theEntity1); - aSubs.push_back(theEntity2); - aSubs.push_back(theMirrorLine); - aSubResult->setEntities(aSubs); - aResult.push_back(aSubResult); - } - else if (theEntity1->type() == ENTITY_LINE) { - const std::list& aPoints1 = theEntity1->subEntities(); - const std::list& aPoints2 = theEntity2->subEntities(); - std::list::const_iterator anIt1 = aPoints1.begin(); - std::list::const_iterator anIt2 = aPoints2.begin(); - for (; anIt1 != aPoints1.end() && anIt2 != aPoints2.end(); ++anIt1, ++anIt2) { - std::list aMrrList = - createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine); - aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end()); - } - } - else if (theEntity1->type() == ENTITY_CIRCLE) { - const std::list& aPoints1 = theEntity1->subEntities(); - std::list::const_iterator anIt1 = aPoints1.begin(); - for (; anIt1 != aPoints1.end(); ++anIt1) - if ((*anIt1)->type() == ENTITY_POINT) - break; - const std::list& aPoints2 = theEntity2->subEntities(); - std::list::const_iterator anIt2 = aPoints2.begin(); - for (; anIt2 != aPoints2.end(); ++anIt2) - if ((*anIt2)->type() == ENTITY_POINT) - break; - - std::list aMrrList = - createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine); - aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end()); - - // Additional constraint for equal radii - aMrrList = createConstraint(theConstraint, theGroupID, theSketchID, CONSTRAINT_EQUAL_RADIUS, - 0.0, EntityWrapperPtr(), EntityWrapperPtr(), theEntity1, theEntity2); - aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end()); - } - else if (theEntity1->type() == ENTITY_ARC) { - // Do not allow mirrored arc recalculate its position until - // coordinated of all points recalculated - FeaturePtr aMirrArc = theEntity2->baseFeature(); - bool aWasBlocked = aMirrArc->data()->blockSendAttributeUpdated(true); - - // Make mirror for center and start point of original arc - std::list aMrrList; - std::list::const_iterator anIt1 = theEntity1->subEntities().begin(); - std::list::const_iterator anIt2 = theEntity2->subEntities().begin(); - aMrrList = createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine); - aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end()); - - ++anIt1; - ++anIt2; ++anIt2; - aMrrList = createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine); - aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end()); - - // make symmetric last point of original arc and first point of - // mirrored arc without additional constraint - ++anIt1; - --anIt2; - makeMirrorPoints(*anIt1, *anIt2, theMirrorLine); - - // Additionally, make equal radii... - aMrrList = createConstraint(theConstraint, theGroupID, theSketchID, CONSTRAINT_EQUAL_RADIUS, - 0.0, EntityWrapperPtr(), EntityWrapperPtr(), theEntity1, theEntity2); - aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end()); - // ... and make parametric length of arcs the same - std::shared_ptr anArcEnt1 = - std::dynamic_pointer_cast(theEntity1); - std::shared_ptr anArcEnt2 = - std::dynamic_pointer_cast(theEntity2); - std::shared_ptr anArc1 = std::dynamic_pointer_cast(anArcEnt1->entity()); - std::shared_ptr anArc2 = std::dynamic_pointer_cast(anArcEnt2->entity()); - std::shared_ptr anIntermed = - std::dynamic_pointer_cast( - createParameter(theGroupID, *(anArc1->endAngle) - *(anArc1->startAngle))); - // By the way, recalculate start and end angles of mirrored arc - std::shared_ptr anOX(new GeomAPI_Dir2d(1.0, 0.0)); - std::shared_ptr aStartDir(new GeomAPI_Dir2d( - *(anArc2->start.x) - *(anArc2->center.x), *(anArc2->start.y) - *(anArc2->center.y))); - std::shared_ptr aEndDir(new GeomAPI_Dir2d( - *(anArc2->end.x) - *(anArc2->center.x), *(anArc2->end.y) - *(anArc2->center.y))); - *anArc2->startAngle = anOX->angle(aStartDir); - *anArc2->endAngle = anOX->angle(aEndDir); - - std::list aConstrList; - aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintDifference( - anArc1->endAngle, anArc1->startAngle, anIntermed->parameter()))); - aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintDifference( - anArc2->endAngle, anArc2->startAngle, anIntermed->parameter()))); - - std::shared_ptr aSubResult( - new PlaneGCSSolver_ConstraintWrapper(theConstraint, aConstrList, CONSTRAINT_SYMMETRIC)); - aSubResult->setGroup(theGroupID); - std::list aSubs(1, theEntity1); - aSubs.push_back(theEntity2); - aSubs.push_back(theMirrorLine); - aSubResult->setEntities(aSubs); - aSubResult->setValueParameter(anIntermed); - aResult.push_back(aSubResult); - - // Restore event sending - aMirrArc->data()->blockSendAttributeUpdated(aWasBlocked); - } return aResult; } -void PlaneGCSSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstraint) const +std::shared_ptr PlaneGCSSolver_Builder::point(EntityWrapperPtr theEntity) const { - SketchSolver_ConstraintType aType = theConstraint->type(); - // Update flags and parameters in constraints - if (aType == CONSTRAINT_PT_LINE_DISTANCE) - adjustPtLineDistance(theConstraint); - else if (aType == CONSTRAINT_SYMMETRIC) - adjustMirror(theConstraint); -} + if (theEntity->type() != ENTITY_POINT) + return std::shared_ptr(); -EntityWrapperPtr PlaneGCSSolver_Builder::createFeature( - FeaturePtr theFeature, - const std::list& theAttributes, - const GroupID& theGroupID, - const EntityID& /*theSketchID*/) const -{ - static EntityWrapperPtr aDummy; - if (!theFeature->data()->isValid()) - return aDummy; - - // Sketch - CompositeFeaturePtr aSketch = std::dynamic_pointer_cast(theFeature); - if (aSketch) - return createSketchEntity(aSketch, theGroupID); - - // SketchPlugin features - std::shared_ptr aFeature = - std::dynamic_pointer_cast(theFeature); - if (!aFeature) - return aDummy; - - // Verify the feature by its kind - const std::string& aFeatureKind = aFeature->getKind(); - // Line - if (aFeatureKind == SketchPlugin_Line::ID()) - return createLine(theFeature, theAttributes, theGroupID); - // Circle - else if (aFeatureKind == SketchPlugin_Circle::ID()) - return createCircle(theFeature, theAttributes, theGroupID); - // Arc - else if (aFeatureKind == SketchPlugin_Arc::ID()) - return createArc(theFeature, theAttributes, theGroupID); - // Point (it has low probability to be an attribute of constraint, so it is checked at the end) - else if (aFeatureKind == SketchPlugin_Point::ID() || - aFeatureKind == SketchPlugin_IntersectionPoint::ID()) { - EntityWrapperPtr aSub; - if (theAttributes.size() == 1) - aSub = theAttributes.front(); - else { - AttributePtr aPoint = theFeature->attribute(SketchPlugin_Point::COORD_ID()); - if (aPoint->isInitialized()) - aSub = createAttribute(aPoint, theGroupID); - } - if (!aSub) - return aDummy; - - GCSPointPtr aSubEnt = - std::dynamic_pointer_cast(aSub)->point(); - EntityWrapperPtr aNewEntity(new PlaneGCSSolver_EntityWrapper(theFeature)); - aNewEntity->setSubEntities(std::list(1, aSub)); - return aNewEntity; - } - - // wrong entity - return aDummy; + std::shared_ptr aPointWrapper = + std::dynamic_pointer_cast(theEntity); + const GCSPointPtr& aPoint = aPointWrapper->point(); + return std::shared_ptr(new GeomAPI_Pnt2d(*aPoint->x, *aPoint->y)); } -EntityWrapperPtr PlaneGCSSolver_Builder::createAttribute( - AttributePtr theAttribute, - const GroupID& theGroupID, - const EntityID& theSketchID) const +std::shared_ptr PlaneGCSSolver_Builder::line(EntityWrapperPtr theEntity) const { - AttributePtr anAttribute = theAttribute; - AttributeRefAttrPtr aRefAttr = - std::dynamic_pointer_cast(anAttribute); - if (aRefAttr) { - if (aRefAttr->isObject()) { - // do not create features here - return EntityWrapperPtr(); - } else - anAttribute = aRefAttr->attr(); - } - - std::list aParameters; - EntityWrapperPtr aResult; - - // Point in 2D - std::shared_ptr aPoint2D = - std::dynamic_pointer_cast(theAttribute); - if (aPoint2D) { - aParameters.push_back(::createParameter(theGroupID, aPoint2D->x(), !aPoint2D->textX().empty())); - aParameters.push_back(::createParameter(theGroupID, aPoint2D->y(), !aPoint2D->textY().empty())); - GCSPointPtr aGCSPoint(new GCS::Point); - aGCSPoint->x = std::dynamic_pointer_cast< - PlaneGCSSolver_ParameterWrapper>(aParameters.front())->parameter(); - aGCSPoint->y = std::dynamic_pointer_cast< - PlaneGCSSolver_ParameterWrapper>(aParameters.back())->parameter(); - // Create entity (parameters are not filled) - aResult = EntityWrapperPtr(new PlaneGCSSolver_PointWrapper(theAttribute, aGCSPoint)); - } else { - // Scalar value (used for the distance entities) - AttributeDoublePtr aScalar = - std::dynamic_pointer_cast(theAttribute); - if (aScalar) - return createScalar(theGroupID, aScalar); - } - - if (!aResult) { - // unknown attribute type - return EntityWrapperPtr(); - } + if (theEntity->type() != ENTITY_LINE) + return std::shared_ptr(); - aResult->setGroup(theGroupID); - aResult->setParameters(aParameters); - return aResult; + std::shared_ptr anEntity = + std::dynamic_pointer_cast(theEntity); + std::shared_ptr aLine = std::dynamic_pointer_cast(anEntity->entity()); + return std::shared_ptr( + new GeomAPI_Lin2d(*(aLine->p1.x), *(aLine->p1.y), *(aLine->p2.x), *(aLine->p2.y))); } -ParameterWrapperPtr PlaneGCSSolver_Builder::createParameter( - const GroupID& theGroupID, double theValue) const +std::shared_ptr PlaneGCSSolver_Builder::line(FeaturePtr theFeature) const { - return ::createParameter(theGroupID, theValue); -} + if (theFeature->getKind() != SketchPlugin_Line::ID()) + return std::shared_ptr(); + AttributePoint2DPtr aStart = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Line::START_ID())); + AttributePoint2DPtr aEnd = std::dynamic_pointer_cast( + theFeature->attribute(SketchPlugin_Line::END_ID())); -EntityWrapperPtr PlaneGCSSolver_Builder::createSketchEntity( - CompositeFeaturePtr theSketch, - const GroupID& theGroupID) const -{ - DataPtr aSketchData = theSketch->data(); - if (!aSketchData || !aSketchData->isValid()) - return EntityWrapperPtr(); // the sketch is incorrect - - // Create dummy wrapper representing workplane - std::shared_ptr aSketchEnt( - new PlaneGCSSolver_EntityWrapper(FeaturePtr(theSketch))); - aSketchEnt->setGroup(theGroupID); - aSketchEnt->setId(EID_SKETCH); - return aSketchEnt; + return std::shared_ptr(new GeomAPI_Lin2d(aStart->pnt(), aEnd->pnt())); } @@ -600,205 +257,25 @@ EntityWrapperPtr PlaneGCSSolver_Builder::createSketchEntity( // ================ Auxiliary functions ========================== -ParameterWrapperPtr createParameter( - const GroupID& theGroup, const double theValue, const bool theExpr) -{ - double* aParam = new double(theValue); - ParameterWrapperPtr aWrapper(new PlaneGCSSolver_ParameterWrapper(aParam)); - aWrapper->setGroup(theGroup); - aWrapper->setIsParametric(theExpr); - return aWrapper; -} - -ParameterWrapperPtr createParamAngle(const GroupID& theGroup, const double& theValue) -{ - double* aParam = new double(theValue); - ParameterWrapperPtr aWrapper(new PlaneGCSSolver_AngleWrapper(aParam)); - aWrapper->setGroup(theGroup); - return aWrapper; -} - -std::shared_ptr createScalar( - const GroupID& theGroupID, - AttributeDoublePtr theDoubleAttr) -{ - ParameterWrapperPtr aParam = - createParameter(theGroupID, theDoubleAttr ? theDoubleAttr->value() : 0.0); - return std::shared_ptr( - new PlaneGCSSolver_ScalarWrapper(theDoubleAttr, aParam)); -} - -EntityWrapperPtr createLine(FeaturePtr theFeature, - const std::list& theAttributes, - const GroupID& theGroupID) -{ - EntityWrapperPtr aNewEntity; - std::list aSubs; - - AttributePtr aStart = theFeature->attribute(SketchPlugin_Line::START_ID()); - AttributePtr aEnd = theFeature->attribute(SketchPlugin_Line::END_ID()); - if (!aStart->isInitialized() || !aEnd->isInitialized()) - return aNewEntity; - - std::shared_ptr aStartEnt, aEndEnt; - std::list::const_iterator anIt = theAttributes.begin(); - for (; anIt != theAttributes.end(); ++anIt) { - std::shared_ptr aWrapper = - std::dynamic_pointer_cast(*anIt); - if (!aWrapper) - continue; - if (aWrapper->isBase(aStart)) - aStartEnt = aWrapper; - else if (aWrapper->isBase(aEnd)) - aEndEnt = aWrapper; - } - if (!aStartEnt || !aEndEnt) - return aNewEntity; - - aSubs.push_back(aStartEnt); - aSubs.push_back(aEndEnt); - - std::shared_ptr aLine(new GCS::Line); - aLine->p1 = *(aStartEnt->point()); - aLine->p2 = *(aEndEnt->point()); - - aNewEntity = EntityWrapperPtr(new PlaneGCSSolver_EntityWrapper(theFeature, aLine)); - // sub-entities should not change their groups, therefore they are added later - aNewEntity->setGroup(theGroupID); - aNewEntity->setSubEntities(aSubs); - return aNewEntity; -} - -EntityWrapperPtr createCircle(FeaturePtr theFeature, - const std::list& theAttributes, - const GroupID& theGroupID) -{ - EntityWrapperPtr aNewEntity; - std::list aSubs; - - AttributePtr aCenter = theFeature->attribute(SketchPlugin_Circle::CENTER_ID()); - AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID()); - if (!aCenter->isInitialized() || !aRadius->isInitialized()) - return aNewEntity; - - std::shared_ptr aCenterEnt; - std::shared_ptr aRadiusEnt; - std::list::const_iterator anIt = theAttributes.begin(); - for (; anIt != theAttributes.end(); ++anIt) { - if ((*anIt)->isBase(aCenter)) - aCenterEnt = std::dynamic_pointer_cast(*anIt); - else if ((*anIt)->isBase(aRadius)) - aRadiusEnt = std::dynamic_pointer_cast(*anIt); - } - if (!aCenterEnt || !aRadiusEnt) - return aNewEntity; - - aSubs.push_back(aCenterEnt); - aSubs.push_back(aRadiusEnt); - - std::shared_ptr aCircle(new GCS::Circle); - aCircle->center = *(aCenterEnt->point()); - aCircle->rad = aRadiusEnt->scalar(); - - aNewEntity = EntityWrapperPtr(new PlaneGCSSolver_EntityWrapper(theFeature, aCircle)); - // sub-entities should not change their groups, therefore they are added later - aNewEntity->setGroup(theGroupID); - aNewEntity->setSubEntities(aSubs); - return aNewEntity; -} - -EntityWrapperPtr createArc(FeaturePtr theFeature, - const std::list& theAttributes, - const GroupID& theGroupID) -{ - EntityWrapperPtr aNewEntity; - std::list aSubs; - - AttributePtr aCenter = theFeature->attribute(SketchPlugin_Arc::CENTER_ID()); - AttributePtr aStart = theFeature->attribute(SketchPlugin_Arc::START_ID()); - AttributePtr aEnd = theFeature->attribute(SketchPlugin_Arc::END_ID()); - if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized()) - return aNewEntity; - - std::shared_ptr aCenterEnt, aStartEnt, aEndEnt; - std::list::const_iterator anIt = theAttributes.begin(); - for (; anIt != theAttributes.end(); ++anIt) { - std::shared_ptr aWrapper = - std::dynamic_pointer_cast(*anIt); - if (!aWrapper) - continue; - if (aWrapper->isBase(aCenter)) - aCenterEnt = aWrapper; - else if (aWrapper->isBase(aStart)) - aStartEnt = aWrapper; - else if (aWrapper->isBase(aEnd)) - aEndEnt = aWrapper; - } - if (!aCenterEnt || !aStartEnt || !aEndEnt) - return aNewEntity; - - std::shared_ptr aStartAng, aEndAng, aRadius; - aStartAng = createScalar(theGroupID); - aEndAng = createScalar(theGroupID); - aRadius = createScalar(theGroupID); - - aSubs.push_back(aCenterEnt); - aSubs.push_back(aStartEnt); - aSubs.push_back(aEndEnt); - aSubs.push_back(aStartAng); - aSubs.push_back(aEndAng); - aSubs.push_back(aRadius); - - std::shared_ptr anArc(new GCS::Arc); - anArc->center = *(aCenterEnt->point()); - anArc->start = *(aStartEnt->point()); - anArc->end = *(aEndEnt->point()); - anArc->startAngle = aStartAng->scalar(); - anArc->endAngle = aEndAng->scalar(); - anArc->rad = aRadius->scalar(); - - aNewEntity = EntityWrapperPtr(new PlaneGCSSolver_EntityWrapper(theFeature, anArc)); - // sub-entities should not change their groups, therefore they are added later - aNewEntity->setGroup(theGroupID); - aNewEntity->setSubEntities(aSubs); - return aNewEntity; -} - - - ConstraintWrapperPtr createConstraintCoincidence( - ConstraintPtr theConstraint, - const GroupID& theGroupID, std::shared_ptr thePoint1, std::shared_ptr thePoint2) { + GCSPointPtr aPoint1 = thePoint1->point(); + GCSPointPtr aPoint2 = thePoint2->point(); + // Create equality constraint for corresponding attributes of the points std::list aConstrList; - std::list::const_iterator anIt1 = thePoint1->parameters().begin(); - std::list::const_iterator anIt2 = thePoint2->parameters().begin(); - for (; anIt1 != thePoint1->parameters().end(); ++anIt1, ++anIt2) { - if (*anIt1 == *anIt2) - continue; // points use same parameters, no need additional constraints - std::shared_ptr aParam1 = - std::dynamic_pointer_cast(*anIt1); - std::shared_ptr aParam2 = - std::dynamic_pointer_cast(*anIt2); - aConstrList.push_back( - GCSConstraintPtr(new GCS::ConstraintEqual(aParam1->parameter(), aParam2->parameter()))); - } + aConstrList.push_back( + GCSConstraintPtr(new GCS::ConstraintEqual(aPoint1->x, aPoint2->x))); + aConstrList.push_back( + GCSConstraintPtr(new GCS::ConstraintEqual(aPoint1->y, aPoint2->y))); - ConstraintWrapperPtr aResult(new PlaneGCSSolver_ConstraintWrapper( - theConstraint, aConstrList, CONSTRAINT_PT_PT_COINCIDENT)); - aResult->setGroup(theGroupID); - std::list aSubs(1, thePoint1); - aSubs.push_back(thePoint2); - aResult->setEntities(aSubs); - return aResult; + return ConstraintWrapperPtr(new PlaneGCSSolver_ConstraintWrapper( + aConstrList, CONSTRAINT_PT_PT_COINCIDENT)); } ConstraintWrapperPtr createConstraintPointOnEntity( - ConstraintPtr theConstraint, - const GroupID& theGroupID, const SketchSolver_ConstraintType& theType, std::shared_ptr thePoint, std::shared_ptr theEntity) @@ -823,34 +300,10 @@ ConstraintWrapperPtr createConstraintPointOnEntity( return ConstraintWrapperPtr(); } - ConstraintWrapperPtr aResult(new PlaneGCSSolver_ConstraintWrapper( - theConstraint, aNewConstr, theType)); - aResult->setGroup(theGroupID); - std::list aSubs(1, thePoint); - aSubs.push_back(theEntity); - aResult->setEntities(aSubs); - return aResult; -} - -// calculate length of the line -static inline double lineLength(const GCS::Line& theLine) -{ - double aDir[2] = {*(theLine.p2.x) - *(theLine.p1.x), *(theLine.p2.y) - *(theLine.p1.y)}; - return sqrt(aDir[0] * aDir[0] + aDir[1] * aDir[1]); -} - -// check the point is on the line -static inline bool isPointOnLine(const GCS::Point& thePoint, const GCS::Line& theLine) -{ - double aDir[2] = {*(theLine.p2.x) - *(theLine.p1.x), *(theLine.p2.y) - *(theLine.p1.y)}; - double aVec[2] = {*(thePoint.x) - *(theLine.p1.x), *(thePoint.y) - *(theLine.p1.y)}; - double aCross = aVec[0] * aDir[1] - aVec[1] * aDir[0]; - return fabs(aCross) < tolerance; + return ConstraintWrapperPtr(new PlaneGCSSolver_ConstraintWrapper(aNewConstr, theType)); } ConstraintWrapperPtr createConstraintMiddlePoint( - ConstraintPtr theConstraint, - const GroupID& theGroupID, std::shared_ptr thePoint, std::shared_ptr theEntity) { @@ -860,102 +313,58 @@ ConstraintWrapperPtr createConstraintMiddlePoint( return ConstraintWrapperPtr(); std::list aConstrList; + aConstrList.push_back( + GCSConstraintPtr(new GCS::ConstraintPointOnPerpBisector(*aPoint, aLine->p1, aLine->p2))); aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintPointOnLine(*aPoint, *aLine))); - double aDist = lineLength(*aLine); - std::shared_ptr aDistance = - std::dynamic_pointer_cast( - createParameter(theGroupID, aDist * 0.5)); - aConstrList.push_back(GCSConstraintPtr( - new GCS::ConstraintP2PDistance(*aPoint, aLine->p1, aDistance->parameter()))); - aConstrList.push_back(GCSConstraintPtr( - new GCS::ConstraintP2PDistance(*aPoint, aLine->p2, aDistance->parameter()))); - - // Workaround to avoid conflicting constraints when the point is already placed on line - if (thePoint->group() != GID_UNKNOWN && isPointOnLine(*aPoint, *aLine)) { - std::shared_ptr aCoord = - std::dynamic_pointer_cast(thePoint->baseAttribute()); - if (aCoord) { - *(aPoint->x) = (*(aLine->p1.x) + *(aLine->p2.x)) * 0.5; - *(aPoint->y) = (*(aLine->p1.y) + *(aLine->p2.y)) * 0.5; - aCoord->setValue(*(aPoint->x), *(aPoint->y)); - } - } - std::shared_ptr aResult(new PlaneGCSSolver_ConstraintWrapper( - theConstraint, aConstrList, CONSTRAINT_MIDDLE_POINT)); - aResult->setGroup(theGroupID); - std::list aSubs(1, thePoint); - aSubs.push_back(theEntity); - aResult->setEntities(aSubs); - aResult->setValueParameter(aDistance); - return aResult; + return ConstraintWrapperPtr( + new PlaneGCSSolver_ConstraintWrapper(aConstrList, CONSTRAINT_MIDDLE_POINT)); } ConstraintWrapperPtr createConstraintDistancePointPoint( - ConstraintPtr theConstraint, - const GroupID& theGroupID, - std::shared_ptr theValue, - std::shared_ptr thePoint1, - std::shared_ptr thePoint2) + std::shared_ptr theValue, + std::shared_ptr thePoint1, + std::shared_ptr thePoint2) { GCSConstraintPtr aNewConstr(new GCS::ConstraintP2PDistance( - *(thePoint1->point()), *(thePoint2->point()), theValue->parameter())); - + *(thePoint1->point()), *(thePoint2->point()), theValue->scalar())); std::shared_ptr aResult( - new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_PT_PT_DISTANCE)); - aResult->setGroup(theGroupID); - std::list aSubs(1, thePoint1); - aSubs.push_back(thePoint2); - aResult->setEntities(aSubs); + new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_PT_PT_DISTANCE)); aResult->setValueParameter(theValue); return aResult; } ConstraintWrapperPtr createConstraintDistancePointLine( - ConstraintPtr theConstraint, - const GroupID& theGroupID, - std::shared_ptr theValue, - std::shared_ptr thePoint, + std::shared_ptr theValue, + std::shared_ptr thePoint, std::shared_ptr theEntity) { std::shared_ptr aLine = std::dynamic_pointer_cast(theEntity->entity()); GCSConstraintPtr aNewConstr(new GCS::ConstraintP2LDistance( - *(thePoint->point()), *(aLine), theValue->parameter())); - + *(thePoint->point()), *(aLine), theValue->scalar())); std::shared_ptr aResult( - new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_PT_LINE_DISTANCE)); - aResult->setGroup(theGroupID); - std::list aSubs(1, thePoint); - aSubs.push_back(theEntity); - aResult->setEntities(aSubs); + new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_PT_LINE_DISTANCE)); aResult->setValueParameter(theValue); return aResult; } ConstraintWrapperPtr createConstraintRadius( - ConstraintPtr theConstraint, - const GroupID& theGroupID, - std::shared_ptr theValue, + std::shared_ptr theValue, std::shared_ptr theEntity) { std::shared_ptr aCircle = std::dynamic_pointer_cast(theEntity->entity()); - GCSConstraintPtr aNewConstr(new GCS::ConstraintEqual(aCircle->rad, theValue->parameter())); - + GCSConstraintPtr aNewConstr(new GCS::ConstraintEqual(aCircle->rad, theValue->scalar())); std::shared_ptr aResult( - new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_RADIUS)); - aResult->setGroup(theGroupID); - std::list aSubs(1, theEntity); - aResult->setEntities(aSubs); + new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_RADIUS)); aResult->setValueParameter(theValue); return aResult; } ConstraintWrapperPtr createConstraintAngle( ConstraintPtr theConstraint, - const GroupID& theGroupID, - std::shared_ptr theValue, + std::shared_ptr theValue, std::shared_ptr theEntity1, std::shared_ptr theEntity2) { @@ -972,21 +381,15 @@ ConstraintWrapperPtr createConstraintAngle( GCS::Point aLine2Pt2 = isLine2Rev ? aLine2->p1 : aLine2->p2; GCSConstraintPtr aNewConstr(new GCS::ConstraintL2LAngle( - aLine1Pt1, aLine1Pt2, aLine2Pt1, aLine2Pt2, theValue->parameter())); + aLine1Pt1, aLine1Pt2, aLine2Pt1, aLine2Pt2, theValue->scalar())); std::shared_ptr aResult( - new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_ANGLE)); - aResult->setGroup(theGroupID); - std::list aSubs(1, theEntity1); - aSubs.push_back(theEntity2); - aResult->setEntities(aSubs); + new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_ANGLE)); aResult->setValueParameter(theValue); return aResult; } ConstraintWrapperPtr createConstraintHorizVert( - ConstraintPtr theConstraint, - const GroupID& theGroupID, const SketchSolver_ConstraintType& theType, std::shared_ptr theEntity) { @@ -997,17 +400,11 @@ ConstraintWrapperPtr createConstraintHorizVert( else aNewConstr = GCSConstraintPtr(new GCS::ConstraintEqual(aLine->p1.x, aLine->p2.x)); - ConstraintWrapperPtr aResult(new PlaneGCSSolver_ConstraintWrapper( - theConstraint, aNewConstr, theType)); - aResult->setGroup(theGroupID); - std::list aSubs(1, theEntity); - aResult->setEntities(aSubs); - return aResult; + return ConstraintWrapperPtr(new PlaneGCSSolver_ConstraintWrapper(aNewConstr, theType)); } ConstraintWrapperPtr createConstraintCollinear( ConstraintPtr theConstraint, - const GroupID& theGroupID, std::shared_ptr theEntity1, std::shared_ptr theEntity2) { @@ -1019,18 +416,11 @@ ConstraintWrapperPtr createConstraintCollinear( aConstrList.push_back( GCSConstraintPtr(new GCS::ConstraintPointOnLine(aLine2->p1, *aLine1)) ); aConstrList.push_back( GCSConstraintPtr(new GCS::ConstraintPointOnLine(aLine2->p2, *aLine1)) ); - ConstraintWrapperPtr aResult(new PlaneGCSSolver_ConstraintWrapper( - theConstraint, aConstrList, CONSTRAINT_COLLINEAR)); - aResult->setGroup(theGroupID); - std::list aSubs(1, theEntity1); - aSubs.push_back(theEntity2); - aResult->setEntities(aSubs); - return aResult; + return ConstraintWrapperPtr( + new PlaneGCSSolver_ConstraintWrapper(aConstrList, CONSTRAINT_COLLINEAR)); } ConstraintWrapperPtr createConstraintParallel( - ConstraintPtr theConstraint, - const GroupID& theGroupID, std::shared_ptr theEntity1, std::shared_ptr theEntity2) { @@ -1038,18 +428,11 @@ ConstraintWrapperPtr createConstraintParallel( std::shared_ptr aLine2 = std::dynamic_pointer_cast(theEntity2->entity()); GCSConstraintPtr aNewConstr(new GCS::ConstraintParallel(*(aLine1), *(aLine2))); - std::shared_ptr aResult( - new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_PARALLEL)); - aResult->setGroup(theGroupID); - std::list aSubs(1, theEntity1); - aSubs.push_back(theEntity2); - aResult->setEntities(aSubs); - return aResult; + return ConstraintWrapperPtr( + new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_PARALLEL)); } ConstraintWrapperPtr createConstraintPerpendicular( - ConstraintPtr theConstraint, - const GroupID& theGroupID, std::shared_ptr theEntity1, std::shared_ptr theEntity2) { @@ -1057,22 +440,15 @@ ConstraintWrapperPtr createConstraintPerpendicular( std::shared_ptr aLine2 = std::dynamic_pointer_cast(theEntity2->entity()); GCSConstraintPtr aNewConstr(new GCS::ConstraintPerpendicular(*(aLine1), *(aLine2))); - std::shared_ptr aResult( - new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_PERPENDICULAR)); - aResult->setGroup(theGroupID); - std::list aSubs(1, theEntity1); - aSubs.push_back(theEntity2); - aResult->setEntities(aSubs); - return aResult; + return ConstraintWrapperPtr( + new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_PERPENDICULAR)); } ConstraintWrapperPtr createConstraintEqual( - ConstraintPtr theConstraint, - const GroupID& theGroupID, const SketchSolver_ConstraintType& theType, std::shared_ptr theEntity1, std::shared_ptr theEntity2, - std::shared_ptr theIntermed) + std::shared_ptr theIntermed) { if (theType == CONSTRAINT_EQUAL_LINE_ARC) return ConstraintWrapperPtr(); // line-arc equivalence is not supported yet @@ -1083,9 +459,9 @@ ConstraintWrapperPtr createConstraintEqual( std::shared_ptr aLine2 = std::dynamic_pointer_cast(theEntity2->entity()); aConstrList.push_back(GCSConstraintPtr( - new GCS::ConstraintP2PDistance(aLine1->p1, aLine1->p2, theIntermed->parameter()))); + new GCS::ConstraintP2PDistance(aLine1->p1, aLine1->p2, theIntermed->scalar()))); aConstrList.push_back(GCSConstraintPtr( - new GCS::ConstraintP2PDistance(aLine2->p1, aLine2->p2, theIntermed->parameter()))); + new GCS::ConstraintP2PDistance(aLine2->p1, aLine2->p2, theIntermed->scalar()))); // update value of intermediate parameter double x = *aLine1->p1.x - *aLine1->p2.x; double y = *aLine1->p1.y - *aLine1->p2.y; @@ -1101,19 +477,13 @@ ConstraintWrapperPtr createConstraintEqual( } std::shared_ptr aResult( - new PlaneGCSSolver_ConstraintWrapper(theConstraint, aConstrList, theType)); - aResult->setGroup(theGroupID); - std::list aSubs(1, theEntity1); - aSubs.push_back(theEntity2); - aResult->setEntities(aSubs); + new PlaneGCSSolver_ConstraintWrapper(aConstrList, theType)); if (theIntermed) aResult->setValueParameter(theIntermed); return aResult; } ConstraintWrapperPtr createConstraintTangent( - ConstraintPtr theConstraint, - const GroupID& theGroupID, const SketchSolver_ConstraintType& theType, std::shared_ptr theEntity1, std::shared_ptr theEntity2) @@ -1140,93 +510,7 @@ ConstraintWrapperPtr createConstraintTangent( aCirc1->rad, aCirc2->rad, (aDist < *(aCirc1->rad) || aDist < *(aCirc2->rad)))); } - std::shared_ptr aResult( - new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, theType)); - aResult->setGroup(theGroupID); - std::list aSubs(1, theEntity1); - aSubs.push_back(theEntity2); - aResult->setEntities(aSubs); - return aResult; -} - - - - - -void makeMirrorPoints(EntityWrapperPtr theOriginal, - EntityWrapperPtr theMirrored, - EntityWrapperPtr theMirrorLine) -{ - BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance(); - - std::shared_ptr aMirrorLine = aBuilder->line(theMirrorLine); - std::shared_ptr aMLDir = aMirrorLine->direction(); - // orthogonal direction - aMLDir = std::shared_ptr(new GeomAPI_Dir2d(aMLDir->y(), -aMLDir->x())); - - std::shared_ptr aPoint = aBuilder->point(theOriginal); - std::shared_ptr aVec = aPoint->xy()->decreased(aMirrorLine->location()->xy()); - double aDist = aVec->dot(aMLDir->xy()); - aVec = aPoint->xy()->added(aMLDir->xy()->multiplied(-2.0 * aDist)); - double aCoord[2] = {aVec->x(), aVec->y()}; - std::list::const_iterator aMIt = theMirrored->parameters().begin(); - for (int i = 0; aMIt != theMirrored->parameters().end(); ++aMIt, ++i) - (*aMIt)->setValue(aCoord[i]); - - // update corresponding attribute - AttributePtr anAttr = - std::dynamic_pointer_cast(theMirrored)->baseAttribute(); - if (anAttr) { - std::shared_ptr aMirroredPnt = - std::dynamic_pointer_cast(anAttr); - aMirroredPnt->setValue(aCoord[0], aCoord[1]); - } -} - -void adjustPtLineDistance(ConstraintWrapperPtr theConstraint) -{ - BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance(); - - std::shared_ptr aPoint; - std::shared_ptr aLine; - std::list aSubs = theConstraint->entities(); - std::list::const_iterator aSIt = aSubs.begin(); - for (; aSIt != aSubs.end(); ++aSIt) { - if ((*aSIt)->type() == ENTITY_POINT) - aPoint = aBuilder->point(*aSIt); - else if ((*aSIt)->type() == ENTITY_LINE) - aLine = aBuilder->line(*aSIt); - } - - std::shared_ptr aLineVec = aLine->direction()->xy(); - std::shared_ptr aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy()); - if (aPtLineVec->cross(aLineVec) * theConstraint->value() < 0.0) - theConstraint->setValue(theConstraint->value() * (-1.0)); -} - -void adjustMirror(ConstraintWrapperPtr theConstraint) -{ - std::vector aPoints; - EntityWrapperPtr aMirrorLine; - - const std::list& aSubs = theConstraint->entities(); - std::list::const_iterator anIt = aSubs.begin(); - for (; anIt != aSubs.end(); ++anIt) { - if ((*anIt)->type() == ENTITY_POINT) - aPoints.push_back(*anIt); - else if ((*anIt)->type() == ENTITY_LINE) - aMirrorLine = *anIt; - } - - if (aPoints.size() == 2) - makeMirrorPoints(aPoints[0], aPoints[1], aMirrorLine); - - // update scales of constraints - std::shared_ptr aGCSConstraint = - std::dynamic_pointer_cast(theConstraint); - std::list::const_iterator aCIt = aGCSConstraint->constraints().begin(); - for (; aCIt != aGCSConstraint->constraints().end(); ++aCIt) - (*aCIt)->rescale(); + return ConstraintWrapperPtr(new PlaneGCSSolver_ConstraintWrapper(aNewConstr, theType)); } bool PlaneGCSSolver_Builder::isArcArcTangencyInternal( @@ -1246,4 +530,3 @@ bool PlaneGCSSolver_Builder::isArcArcTangencyInternal( return (aDist < *(aCirc1->rad) || aDist < *(aCirc2->rad)); } - diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.h index ea9042a6f..62b9ff327 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.h @@ -22,7 +22,6 @@ */ class PlaneGCSSolver_Builder : public SketchSolver_Builder { -private: /// Default constructor PlaneGCSSolver_Builder() {} @@ -31,14 +30,12 @@ public: static BuilderPtr getInstance(); /// \brief Creates a storage specific for used solver - virtual StoragePtr createStorage(const GroupID& theGroup) const; + virtual StoragePtr createStorage(const SolverPtr& theSolver) const override; /// \brief Creates specific solver - virtual SolverPtr createSolver() const; + virtual SolverPtr createSolver() const override; - /// \brief Creates new constraint(s) using given parameters + /// \brief Creates new constraint using given parameters /// \param theConstraint [in] original constraint - /// \param theGroupID [in] group the constraint belongs to - /// \param theSketchID [in] sketch the constraint belongs to /// \param theType [in] type of constraint /// \param theValue [in] numeric characteristic of constraint /// (e.g. distance or radius) if applicable @@ -46,24 +43,18 @@ public: /// \param theEntity2 [in] second attribute of constraint /// \param theEntity3 [in] third attribute of constraint /// \param theEntity4 [in] fourth attribute of constraint - /// \return Created list of wrappers of constraints applicable for specific solver. - /// Most of constraint types lead to single constraint, but there are some kind of - /// constraints (e.g. mirror), which may produce couple of constraints. - virtual std::list + /// \return Created wrapper of constraints applicable for specific solver. + virtual ConstraintWrapperPtr createConstraint(ConstraintPtr theConstraint, - const GroupID& theGroupID, - const EntityID& theSketchID, const SketchSolver_ConstraintType& theType, - const double& theValue, + const EntityWrapperPtr& theValue, const EntityWrapperPtr& theEntity1, const EntityWrapperPtr& theEntity2 = EntityWrapperPtr(), const EntityWrapperPtr& theEntity3 = EntityWrapperPtr(), - const EntityWrapperPtr& theEntity4 = EntityWrapperPtr()) const; + const EntityWrapperPtr& theEntity4 = EntityWrapperPtr()) const override; /// \brief Creates new multi-translation or multi-rotation constraint /// \param theConstraint [in] original constraint - /// \param theGroupID [in] group the constraint belongs to - /// \param theSketchID [in] sketch the constraint belongs to /// \param theType [in] type of constraint /// \param theValue [in] numeric characteristic of constraint (angle for multi-rotation) /// if applicable @@ -72,68 +63,30 @@ public: /// \param thePoint1 [in] center for multi-rotation or start point for multi-translation /// \param thePoint2 [in] end point for multi-translation (empty for multi-rotation) /// \param theTrsfEnt [in] list of transformed entities - virtual std::list + virtual ConstraintWrapperPtr createConstraint(ConstraintPtr theConstraint, - const GroupID& theGroupID, - const EntityID& theSketchID, const SketchSolver_ConstraintType& theType, - const double& theValue, + const EntityWrapperPtr& theValue, const bool theFullValue, const EntityWrapperPtr& thePoint1, const EntityWrapperPtr& thePoint2, - const std::list& theTrsfEnt) const; + const std::list& theTrsfEnt) const override; - /// \brief Update flags for several kinds of constraints - virtual void adjustConstraint(ConstraintWrapperPtr theConstraint) const; + /// \brief Convert entity to point + /// \return empty pointer if the entity is not a point + virtual std::shared_ptr point(EntityWrapperPtr theEntity) const override; + /// \brief Convert entity to line + /// \return empty pointer if the entity is not a line + virtual std::shared_ptr line(EntityWrapperPtr theEntity) const override; - /// \brief Creates a feature using list of already created attributes - /// \param theFeature [in] feature to create - /// \param theAttributes [in] attributes of the feature - /// \param theGroupID [in] group the feature belongs to - /// \param theSketchID [in] sketch the feature belongs to - /// \return Created wrapper of the feature applicable for specific solver - virtual EntityWrapperPtr createFeature(FeaturePtr theFeature, - const std::list& theAttributes, - const GroupID& theGroupID, - const EntityID& theSketchID = EID_UNKNOWN) const; - - /// \brief Creates an attribute - /// \param theAttribute [in] attribute to create - /// \param theGroup [in] group the attribute belongs to - /// \param theSketchID [in] sketch the attribute belongs to - /// \return Created wrapper of the attribute applicable for specific solver - virtual EntityWrapperPtr createAttribute(AttributePtr theAttribute, - const GroupID& theGroup, - const EntityID& theSketchID = EID_UNKNOWN) const; - - /// \brief Create a parameter - /// \param theGroupID [in] group the parameter belongs to - /// \param theValue [in] value of the parameter - /// \return Created wrapper for parameter - ParameterWrapperPtr createParameter(const GroupID& theGroupID, double theValue = 0.0) const; + /// \brief Convert entity to line + /// \return empty pointer if the entity is not a line + virtual std::shared_ptr line(FeaturePtr theFeature) const override; /// \brief Check if two connected arcs have centers /// in same direction relatively to connection point - virtual bool isArcArcTangencyInternal(EntityWrapperPtr theArc1, EntityWrapperPtr theArc2) const; - -private: - /// \brief Create necessary constraints to make two object symmetric relatively a given line - std::list createMirror(ConstraintPtr theConstraint, - const GroupID& theGroupID, - const EntityID& theSketchID, - const EntityWrapperPtr& theEntity1, - const EntityWrapperPtr& theEntity2, - const EntityWrapperPtr& theMirrorLine) const; - - /// \brief Converts sketch parameters to the entity applicable for the solver. - /// \param theSketch [in] the element to be converted - /// \param theGroupID [in] group where the sketch should be created - /// \return Entity respective the sketch or empty pointer, it the sketch has incorrect attributes - EntityWrapperPtr createSketchEntity(CompositeFeaturePtr theSketch, - const GroupID& theGroupID) const; - -private: - static BuilderPtr mySelf; + virtual bool isArcArcTangencyInternal(EntityWrapperPtr theArc1, + EntityWrapperPtr theArc2) const override; }; #endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.cpp index a2be38efe..a9924a773 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.cpp @@ -6,30 +6,22 @@ #include -#include - PlaneGCSSolver_ConstraintWrapper::PlaneGCSSolver_ConstraintWrapper( - const ConstraintPtr& theOriginal, const GCSConstraintPtr& theConstraint, const SketchSolver_ConstraintType& theType) : myGCSConstraints(1, theConstraint), - myType(theType), - myID(CID_UNKNOWN) + myType(theType) { - myBaseConstraint = theOriginal; - myValue = 0.0; + myID = CID_UNKNOWN; } PlaneGCSSolver_ConstraintWrapper::PlaneGCSSolver_ConstraintWrapper( - const ConstraintPtr& theOriginal, const std::list& theConstraints, const SketchSolver_ConstraintType& theType) : myGCSConstraints(theConstraints), - myType(theType), - myID(CID_UNKNOWN) + myType(theType) { - myBaseConstraint = theOriginal; - myValue = 0.0; + myID = CID_UNKNOWN; } void PlaneGCSSolver_ConstraintWrapper::setId(const ConstraintID& theID) @@ -40,81 +32,17 @@ void PlaneGCSSolver_ConstraintWrapper::setId(const ConstraintID& theID) (*anIt)->setTag((int)theID); } -void PlaneGCSSolver_ConstraintWrapper::setValueParameter(const ParameterWrapperPtr& theValue) +void PlaneGCSSolver_ConstraintWrapper::setValueParameter(const ScalarWrapperPtr& theValue) { myValueParam = theValue; - myValue = myValueParam->value(); } void PlaneGCSSolver_ConstraintWrapper::setValue(const double& theValue) { - myValue = theValue; myValueParam->setValue(theValue); } - -void PlaneGCSSolver_ConstraintWrapper::setGroup(const GroupID& theGroup) -{ - myGroup = theGroup; - std::list::iterator aSubsIt = myConstrained.begin(); - for (; aSubsIt != myConstrained.end(); ++aSubsIt) - (*aSubsIt)->setGroup(theGroup); -} - -bool PlaneGCSSolver_ConstraintWrapper::isUsed(FeaturePtr theFeature) const -{ - std::list::const_iterator anIt = myConstrained.begin(); - for (; anIt != myConstrained.end(); ++anIt) - if ((*anIt)->isUsed(theFeature)) - return true; - return false; -} - -bool PlaneGCSSolver_ConstraintWrapper::isUsed(AttributePtr theAttribute) const -{ - std::list::const_iterator anIt = myConstrained.begin(); - for (; anIt != myConstrained.end(); ++anIt) - if ((*anIt)->isUsed(theAttribute)) - return true; - return false; -} - -bool PlaneGCSSolver_ConstraintWrapper::isEqual(const ConstraintWrapperPtr& theOther) +double PlaneGCSSolver_ConstraintWrapper::value() const { - if (type() != theOther->type()) - return false; - - // Verify equality of values - if (fabs(myValue - theOther->value()) > tolerance) - return false; - - // Verify equality of entities - const std::list& anOtherSubs = theOther->entities(); - if (myConstrained.size() != anOtherSubs.size()) - return false; - std::list::const_iterator aMySubsIt = myConstrained.begin(); - std::list::const_iterator anOtherSubsIt = anOtherSubs.begin(); - for (; aMySubsIt != myConstrained.end(); ++aMySubsIt, ++anOtherSubsIt) - if (!(*aMySubsIt)->isEqual(*anOtherSubsIt)) - return false; - return true; -} - -bool PlaneGCSSolver_ConstraintWrapper::update(const ConstraintWrapperPtr& theOther) -{ - bool isUpdated = false; - - std::list aMySubs = entities(); - std::list anOtherSubs = theOther->entities(); - std::list::const_iterator aMySubsIt = aMySubs.begin(); - std::list::const_iterator anOtherSubsIt = anOtherSubs.begin(); - for (; aMySubsIt != aMySubs.end() && anOtherSubsIt != anOtherSubs.end(); - ++aMySubsIt, ++anOtherSubsIt) - isUpdated = (*aMySubsIt)->update(*anOtherSubsIt) || isUpdated; - - if (fabs(value() - theOther->value()) > tolerance) { - myValue = theOther->value(); - isUpdated = true; - } - return isUpdated; + return myValueParam->value(); } diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.h index ebf65ea65..216905155 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.h @@ -9,20 +9,19 @@ #include #include +#include #include /** - * Wrapper providing operations with SovleSpace constraints. + * Wrapper providing operations with PlaneGCS constraints. */ class PlaneGCSSolver_ConstraintWrapper : public SketchSolver_IConstraintWrapper { public: - PlaneGCSSolver_ConstraintWrapper(const ConstraintPtr& theOriginal, - const GCSConstraintPtr& theConstraint, + PlaneGCSSolver_ConstraintWrapper(const GCSConstraintPtr& theConstraint, const SketchSolver_ConstraintType& theType); - PlaneGCSSolver_ConstraintWrapper(const ConstraintPtr& theOriginal, - const std::list& theConstraints, + PlaneGCSSolver_ConstraintWrapper(const std::list& theConstraints, const SketchSolver_ConstraintType& theType); /// \brief Return list of constraints @@ -32,17 +31,8 @@ public: void setConstraints(const std::list& theConstraints) { myGCSConstraints = theConstraints; } - /// \brief Return ID of current entity - virtual ConstraintID id() const - { return myID; } /// \brief Change constraint ID - void setId( const ConstraintID& theID); - - /// \brief Change group for the constraint - virtual void setGroup(const GroupID& theGroup); - /// \brief Return identifier of the group the constraint belongs to - virtual GroupID group() const - { return myGroup; } + virtual void setId(const ConstraintID& theID); /// \brief Return type of current entity virtual SketchSolver_ConstraintType type() const @@ -50,30 +40,18 @@ public: /// \brief Assign numeric parameter of constraint virtual void setValue(const double& theValue); + /// \brief Return numeric parameter of constraint + virtual double value() const; /// \brief Change parameter representing the value of constraint - void setValueParameter(const ParameterWrapperPtr& theValue); + void setValueParameter(const ScalarWrapperPtr& theValue); /// \brief Return parametric representation of constraint value - const ParameterWrapperPtr& valueParameter() const + const ScalarWrapperPtr& valueParameter() const { return myValueParam; } - /// \brief Verify the feature is used in the constraint - virtual bool isUsed(FeaturePtr theFeature) const; - /// \brief Verify the attribute is used in the constraint - virtual bool isUsed(AttributePtr theAttribute) const; - - /// \brief Compare current constraint with other - virtual bool isEqual(const ConstraintWrapperPtr& theOther); - - /// \brief Update values of parameters of this constraint by the parameters of given one - /// \return \c true if some parameters change their values - virtual bool update(const std::shared_ptr& theOther); - private: - ConstraintID myID; - GroupID myGroup; SketchSolver_ConstraintType myType; - ParameterWrapperPtr myValueParam; + ScalarWrapperPtr myValueParam; std::list myGCSConstraints; }; diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityBuilder.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityBuilder.h new file mode 100644 index 000000000..d4eb9d9d2 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityBuilder.h @@ -0,0 +1,47 @@ +// Copyright (C) 2017-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_EntityBuilder.h +// Created: 14 Feb 2017 +// Author: Artem ZHIDKOV + +#ifndef PlaneGCSSolver_EntityBuilder_H_ +#define PlaneGCSSolver_EntityBuilder_H_ + +#include +#include + +/** \class PlaneGCSSolver_EntityBuilder + * \ingroup Plugins + * \brief API to convert data model entity to the entity applicable for PlaneGCS solver + */ +class PlaneGCSSolver_EntityBuilder +{ +public: + /// \brief Create entity in the given storage. + /// If the storage is empty, the entity should not be changed + /// while constraint solving. So, it is created out of the storage. + PlaneGCSSolver_EntityBuilder(PlaneGCSSolver_Storage* theStorage = 0) + : myStorage(theStorage) + {} + + virtual ~PlaneGCSSolver_EntityBuilder() {} + + /// \brief Converts an attribute to the solver's entity. + /// Double attributes and 2D points are supported only. + /// \param theAttribute [in] attribute to create + /// \return Created wrapper of the attribute applicable for specific solver + virtual EntityWrapperPtr createAttribute(AttributePtr theAttribute) = 0; + + /// \brief Converts SketchPlugin's feature to the solver's entity. + /// Result if based on the list of already converted attributes. + /// \param theFeature [in] feature to create + virtual EntityWrapperPtr createFeature(FeaturePtr) = 0; + + /// \brief Return list of constraints necessary to fix feature's extra DoF + virtual const std::list& constraints() const = 0; + +protected: + PlaneGCSSolver_Storage* myStorage; +}; + +#endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityDestroyer.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityDestroyer.cpp new file mode 100644 index 000000000..697d2db5c --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityDestroyer.cpp @@ -0,0 +1,87 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_EntityDestroyer.cpp +// Created: 10 Feb 2017 +// Author: Artem ZHIDKOV + +#include + +#include +#include +#include + +static void destroyScalar(const EntityWrapperPtr& theEntity, GCS::SET_pD& theParams) +{ + ScalarWrapperPtr aScalar = std::dynamic_pointer_cast(theEntity); + theParams.insert(aScalar->scalar()); +} + +static void destroyPoint(const EntityWrapperPtr& theEntity, GCS::SET_pD& theParams) +{ + std::shared_ptr aPoint = + std::dynamic_pointer_cast(theEntity); + theParams.insert(aPoint->point()->x); + theParams.insert(aPoint->point()->y); +} + +static void destroyLine(const EntityWrapperPtr& theEntity, GCS::SET_pD& theParams) +{ + std::shared_ptr anEntity = + std::dynamic_pointer_cast(theEntity); + std::shared_ptr aLine = std::dynamic_pointer_cast(anEntity->entity()); + theParams.insert(aLine->p1.x); + theParams.insert(aLine->p1.y); + theParams.insert(aLine->p2.x); + theParams.insert(aLine->p2.y); +} + +static void destroyCircle(const EntityWrapperPtr& theEntity, GCS::SET_pD& theParams) +{ + std::shared_ptr anEntity = + std::dynamic_pointer_cast(theEntity); + std::shared_ptr aCirc = std::dynamic_pointer_cast(anEntity->entity()); + theParams.insert(aCirc->center.x); + theParams.insert(aCirc->center.y); + theParams.insert(aCirc->rad); +} + +static void destroyArc(const EntityWrapperPtr& theEntity, GCS::SET_pD& theParams) +{ + std::shared_ptr anEntity = + std::dynamic_pointer_cast(theEntity); + std::shared_ptr anArc = std::dynamic_pointer_cast(anEntity->entity()); + theParams.insert(anArc->center.x); + theParams.insert(anArc->center.y); + theParams.insert(anArc->start.x); + theParams.insert(anArc->start.y); + theParams.insert(anArc->end.x); + theParams.insert(anArc->end.y); + theParams.insert(anArc->startAngle); + theParams.insert(anArc->endAngle); + theParams.insert(anArc->rad); +} + +void PlaneGCSSolver_EntityDestroyer::remove(const EntityWrapperPtr& theEntity) +{ + GCS::SET_pD& aParamSet = theEntity->isExternal() ? myParamsOutOfStorage : myParams; + + switch (theEntity->type()) { + case ENTITY_SCALAR: + case ENTITY_ANGLE: + destroyScalar(theEntity, aParamSet); + break; + case ENTITY_POINT: + destroyPoint(theEntity, aParamSet); + break; + case ENTITY_LINE: + destroyLine(theEntity, aParamSet); + break; + case ENTITY_CIRCLE: + destroyCircle(theEntity, aParamSet); + break; + case ENTITY_ARC: + destroyArc(theEntity, aParamSet); + break; + default: break; + } +} diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityDestroyer.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityDestroyer.h new file mode 100644 index 000000000..043797fd8 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityDestroyer.h @@ -0,0 +1,34 @@ +// Copyright (C) 2017-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_EntityDestroyer.h +// Created: 10 Feb 2017 +// Author: Artem ZHIDKOV + +#ifndef PlaneGCSSolver_EntityDestroyer_H_ +#define PlaneGCSSolver_EntityDestroyer_H_ + +#include +#include + +/** \class PlaneGCSSolver_EntityDestroyer + * \ingroup Plugins + * \brief Collect entities of PlaneGCS solver which should be removed + */ +class PlaneGCSSolver_EntityDestroyer +{ +public: + PlaneGCSSolver_EntityDestroyer() {} + + /// \brief Add entity to remove. Its parameters are stored for further remove from the storage. + void remove(const EntityWrapperPtr& theEntity); + + /// \brief Return parameters to remove + const GCS::SET_pD& parametersToRemove() + { return myParams; } + +private: + GCS::SET_pD myParams; ///< set of parameters to be removed + GCS::SET_pD myParamsOutOfStorage; ///< set of parameters not kept in the storage +}; + +#endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.cpp index e1dbad9be..907ca6167 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.cpp @@ -5,17 +5,10 @@ // Author: Artem ZHIDKOV #include -#include -#include -#include -PlaneGCSSolver_EntityWrapper::PlaneGCSSolver_EntityWrapper( - const FeaturePtr theFeature, const GCSCurvePtr theEntity) - : myEntity(theEntity), - myID(EID_UNKNOWN) +PlaneGCSSolver_EntityWrapper::PlaneGCSSolver_EntityWrapper(const GCSCurvePtr theEntity) + : myEntity(theEntity) { - myBaseFeature = theFeature; - std::shared_ptr aLine = std::dynamic_pointer_cast(myEntity); if (aLine) myType = ENTITY_LINE; else { @@ -26,95 +19,4 @@ PlaneGCSSolver_EntityWrapper::PlaneGCSSolver_EntityWrapper( if (aCircle) myType = ENTITY_CIRCLE; } } - - // empty entity, probably this is a SketchPlugin_Point or SketchPlugin_Sketch - if (theFeature->getKind() == SketchPlugin_Point::ID() || - theFeature->getKind() == SketchPlugin_IntersectionPoint::ID()) - myType = ENTITY_POINT; - else if (theFeature->getKind() == SketchPlugin_Sketch::ID()) - myType = ENTITY_SKETCH; -} - -void PlaneGCSSolver_EntityWrapper::setGroup(const GroupID& theGroup) -{ - myGroup = theGroup; - std::list::iterator aSubsIt = mySubEntities.begin(); - for (; aSubsIt != mySubEntities.end(); ++aSubsIt) - (*aSubsIt)->setGroup(theGroup); - std::list::iterator aPIt = myParameters.begin(); - for (; aPIt != myParameters.end(); ++aPIt) - (*aPIt)->setGroup(theGroup); -} - -bool PlaneGCSSolver_EntityWrapper::isUsed(FeaturePtr theFeature) const -{ - if (isBase(theFeature)) - return true; - - std::list::const_iterator anIt = mySubEntities.begin(); - for (; anIt != mySubEntities.end(); ++anIt) - if ((*anIt)->isUsed(theFeature)) - return true; - return false; -} - -bool PlaneGCSSolver_EntityWrapper::isUsed(AttributePtr theAttribute) const -{ - if (isBase(theAttribute)) - return true; - - std::list::const_iterator anIt = mySubEntities.begin(); - for (; anIt != mySubEntities.end(); ++anIt) - if ((*anIt)->isUsed(theAttribute)) - return true; - return false; -} - -bool PlaneGCSSolver_EntityWrapper::isEqual(const EntityWrapperPtr& theOther) -{ - if (type() != theOther->type()) - return false; - - // Verify Equality of sub-entities - const std::list& anOtherSubs = theOther->subEntities(); - if (mySubEntities.size() != anOtherSubs.size()) - return false; - std::list::const_iterator aMySubsIt = mySubEntities.begin(); - std::list::const_iterator anOtherSubsIt = anOtherSubs.begin(); - for (; aMySubsIt != mySubEntities.end(); ++aMySubsIt, ++anOtherSubsIt) - if (!(*aMySubsIt)->isEqual(*anOtherSubsIt)) - return false; - - // Verify equality of parameters - const std::list& anOtherParams = theOther->parameters(); - if (myParameters.size() != anOtherParams.size()) - return false; - std::list::const_iterator aMyIt = myParameters.begin(); - std::list::const_iterator anOtherIt = anOtherParams.begin(); - for (; aMyIt != myParameters.end(); ++aMyIt, ++anOtherIt) - if (!(*aMyIt)->isEqual(*anOtherIt)) - return false; - return true; -} - -bool PlaneGCSSolver_EntityWrapper::update(const EntityWrapperPtr& theOther) -{ - bool isUpdated = false; - - std::list aMySubs = subEntities(); - std::list anOtherSubs = theOther->subEntities(); - std::list::const_iterator aMySubsIt = aMySubs.begin(); - std::list::const_iterator anOtherSubsIt = anOtherSubs.begin(); - for (; aMySubsIt != aMySubs.end() && anOtherSubsIt != anOtherSubs.end(); - ++aMySubsIt, ++anOtherSubsIt) - isUpdated = (*aMySubsIt)->update(*anOtherSubsIt) || isUpdated; - - std::list aMyParams = parameters(); - std::list anOtherParams = theOther->parameters(); - std::list::const_iterator aMyParIt = aMyParams.begin(); - std::list::const_iterator anOtherParIt = anOtherParams.begin(); - for (; aMyParIt != aMyParams.end() && anOtherParIt != anOtherParams.end(); - ++aMyParIt, ++anOtherParIt) - isUpdated = (*aMyParIt)->update(*anOtherParIt); - return isUpdated; } diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.h index 5fb99ddb4..38c92198a 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.h @@ -11,13 +11,12 @@ #include /** - * Wrapper providing operations with PlaneGCS entities. + * Wrapper providing operations with PlaneGCS entities (lines, circles and arcs). */ class PlaneGCSSolver_EntityWrapper : public SketchSolver_IEntityWrapper { public: - PlaneGCSSolver_EntityWrapper(const FeaturePtr theFeature, - const GCSCurvePtr theEntity = GCSCurvePtr()); + PlaneGCSSolver_EntityWrapper(const GCSCurvePtr theEntity); /// \brief Return PlaneGCS geometric entity const GCSCurvePtr& entity() const @@ -26,38 +25,11 @@ public: GCSCurvePtr& changeEntity() { return myEntity; } - /// \brief Return ID of current entity - virtual EntityID id() const - { return myID; } - /// \brief Change ID of the entity - void setId(EntityID theID) - { myID = theID; } - - /// \brief Change group for the entity - virtual void setGroup(const GroupID& theGroup); - /// \brief Return identifier of the group the entity belongs to - virtual GroupID group() const - { return myGroup; } - /// \brief Return type of current entity virtual SketchSolver_EntityType type() const { return myType; } - /// \brief Verify the feature is used in the entity - virtual bool isUsed(FeaturePtr theFeature) const; - /// \brief Verify the attribute is used in the entity - virtual bool isUsed(AttributePtr theAttribute) const; - - /// \brief Compare current entity with other - virtual bool isEqual(const EntityWrapperPtr& theOther); - - /// \brief Update values of parameters of this entity by the parameters of given one - /// \return \c true if some parameters change their values - virtual bool update(const EntityWrapperPtr& theOther); - private: - EntityID myID; - GroupID myGroup; SketchSolver_EntityType myType; GCSCurvePtr myEntity; }; diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp new file mode 100644 index 000000000..fdcc98b44 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp @@ -0,0 +1,201 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_AttributeBuilder.cpp +// Created: 10 Feb 2017 +// Author: Artem ZHIDKOV + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +static EntityWrapperPtr createLine(const AttributeEntityMap& theAttributes); +static EntityWrapperPtr createCircle(const AttributeEntityMap& theAttributes); +static EntityWrapperPtr createArc(const AttributeEntityMap& theAttributes, + PlaneGCSSolver_Storage* theStorage, + std::list& theArcConstraints); + + +PlaneGCSSolver_FeatureBuilder::PlaneGCSSolver_FeatureBuilder( + PlaneGCSSolver_Storage* theStorage) + : PlaneGCSSolver_AttributeBuilder(theStorage) +{ +} + +PlaneGCSSolver_FeatureBuilder::PlaneGCSSolver_FeatureBuilder(const StoragePtr& theStorage) + : PlaneGCSSolver_AttributeBuilder(theStorage) +{ +} + +EntityWrapperPtr PlaneGCSSolver_FeatureBuilder::createAttribute( + AttributePtr theAttribute) +{ + EntityWrapperPtr anAttr = PlaneGCSSolver_AttributeBuilder::createAttribute(theAttribute); + if (anAttr) + myAttributes[theAttribute] = anAttr; + return anAttr; +} + +EntityWrapperPtr PlaneGCSSolver_FeatureBuilder::createFeature(FeaturePtr theFeature) +{ + EntityWrapperPtr aResult; + if (myStorage) + aResult = myStorage->entity(theFeature); + if (aResult) + return aResult; + + // Process SketchPlugin features only + std::shared_ptr aFeature = + std::dynamic_pointer_cast(theFeature); + if (!aFeature) + return aResult; + + // Verify the feature by its kind + const std::string& aFeatureKind = aFeature->getKind(); + // Line + if (aFeatureKind == SketchPlugin_Line::ID()) + aResult = createLine(myAttributes); + // Circle + else if (aFeatureKind == SketchPlugin_Circle::ID()) + aResult = createCircle(myAttributes); + // Arc + else if (aFeatureKind == SketchPlugin_Arc::ID()) + aResult = createArc(myAttributes, myStorage, myFeatureConstraints); + // Point (it has low probability to be an attribute of constraint, so it is checked at the end) + else if (aFeatureKind == SketchPlugin_Point::ID() || + aFeatureKind == SketchPlugin_IntersectionPoint::ID()) { + AttributeEntityMap::const_iterator anIt = myAttributes.begin(); + for (; anIt != myAttributes.end(); ++anIt) + if (anIt->first->id() == SketchPlugin_Point::COORD_ID()) { + aResult = anIt->second; + break; + } + } + + if (aResult && !myStorage) + aResult->setExternal(true); + + myAttributes.clear(); + return aResult; +} + + + + + +// ============== Auxiliary functions ===================================== +EntityWrapperPtr createLine(const AttributeEntityMap& theAttributes) +{ + std::shared_ptr aNewLine(new GCS::Line); + + AttributeEntityMap::const_iterator anIt = theAttributes.begin(); + for (; anIt != theAttributes.end(); ++anIt) { + std::shared_ptr aPoint = + std::dynamic_pointer_cast(anIt->second); + if (!aPoint) + continue; + + if (anIt->first->id() == SketchPlugin_Line::START_ID()) + aNewLine->p1 = *(aPoint->point()); + else if (anIt->first->id() == SketchPlugin_Line::END_ID()) + aNewLine->p2 = *(aPoint->point()); + } + + return EntityWrapperPtr(new PlaneGCSSolver_EntityWrapper(aNewLine)); +} + +EntityWrapperPtr createCircle(const AttributeEntityMap& theAttributes) +{ + std::shared_ptr aNewCircle(new GCS::Circle); + + AttributeEntityMap::const_iterator anIt = theAttributes.begin(); + for (; anIt != theAttributes.end(); ++anIt) { + if (anIt->first->id() == SketchPlugin_Circle::CENTER_ID()) { + std::shared_ptr aPoint = + std::dynamic_pointer_cast(anIt->second); + aNewCircle->center = *(aPoint->point()); + } + else if(anIt->first->id() == SketchPlugin_Circle::RADIUS_ID()) { + ScalarWrapperPtr aScalar = + std::dynamic_pointer_cast(anIt->second); + aNewCircle->rad = aScalar->scalar(); + } + } + + return EntityWrapperPtr(new PlaneGCSSolver_EntityWrapper(aNewCircle)); +} + +static double* createParameter(PlaneGCSSolver_Storage* theStorage) +{ + return theStorage ? theStorage->createParameter() : (new double(0)); +} + +EntityWrapperPtr createArc(const AttributeEntityMap& theAttributes, + PlaneGCSSolver_Storage* theStorage, + std::list& theArcConstraints) +{ + std::shared_ptr aNewArc(new GCS::Arc); + + // Base attributes of arc (center, start and end points) + AttributeEntityMap::const_iterator anIt = theAttributes.begin(); + for (; anIt != theAttributes.end(); ++anIt) { + std::shared_ptr aPoint = + std::dynamic_pointer_cast(anIt->second); + if (!aPoint) + continue; + + if (anIt->first->id() == SketchPlugin_Arc::CENTER_ID()) + aNewArc->center = *(aPoint->point()); + else if (anIt->first->id() == SketchPlugin_Arc::START_ID()) + aNewArc->start = *(aPoint->point()); + else if (anIt->first->id() == SketchPlugin_Arc::END_ID()) + aNewArc->end = *(aPoint->point()); + } + + // Additional atrtributes of arc necessary for PlaneGCS solver + // (start and end angles, radius) + aNewArc->startAngle = createParameter(theStorage); + aNewArc->endAngle = createParameter(theStorage); + aNewArc->rad = createParameter(theStorage); + + static std::shared_ptr OX(new GeomAPI_Dir2d(1.0, 0.0)); + std::shared_ptr aCenter( + new GeomAPI_Pnt2d(*aNewArc->center.x, *aNewArc->center.y)); + std::shared_ptr aStart( + new GeomAPI_Pnt2d(*aNewArc->start.x, *aNewArc->start.y)); + + *aNewArc->rad = aStart->distance(aCenter); + + std::shared_ptr aDir(new GeomAPI_Dir2d(aStart->xy()->decreased(aCenter->xy()))); + *aNewArc->startAngle = OX->angle(aDir); + + aDir = std::shared_ptr( + new GeomAPI_Dir2d((*aNewArc->end.x) - aCenter->x(), (*aNewArc->end.y) - aCenter->y())); + *aNewArc->endAngle = OX->angle(aDir); + + if (theStorage) { + // Additional constaints to fix arc's extra DoF (if the arc is not external): + // 1. distances from center till start and end points are equal to radius + theArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance( + aNewArc->center, aNewArc->start, aNewArc->rad))); + theArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance( + aNewArc->center, aNewArc->end, aNewArc->rad))); + // 2. angles of start and end points should be equal to the arc angles + theArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle( + aNewArc->center, aNewArc->start, aNewArc->startAngle))); + theArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle( + aNewArc->center, aNewArc->end, aNewArc->endAngle))); + } + + return EntityWrapperPtr(new PlaneGCSSolver_EntityWrapper(aNewArc)); +} diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.h new file mode 100644 index 000000000..d08d5ab26 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.h @@ -0,0 +1,48 @@ +// Copyright (C) 2017-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_FeatureBuilder.h +// Created: 10 Feb 2017 +// Author: Artem ZHIDKOV + +#ifndef PlaneGCSSolver_FeatureBuilder_H_ +#define PlaneGCSSolver_FeatureBuilder_H_ + +#include + +typedef std::map AttributeEntityMap; + +/** \class PlaneGCSSolver_FeatureBuilder + * \ingroup Plugins + * \brief Converts SketchPlugin_Feature to the entity applicable for PlaneGCS solver + */ +class PlaneGCSSolver_FeatureBuilder : public PlaneGCSSolver_AttributeBuilder +{ +public: + PlaneGCSSolver_FeatureBuilder(PlaneGCSSolver_Storage* theStorage = 0); + PlaneGCSSolver_FeatureBuilder(const StoragePtr& theStorage); + + /// \brief Converts an attribute to the solver's entity and stores it for further processing. + /// Double attributes and 2D points are supported only. + /// \param theAttribute [in] attribute to create + /// \return Created wrapper of the attribute applicable for specific solver + virtual EntityWrapperPtr createAttribute(AttributePtr theAttribute) override; + + /// \brief Converts SketchPlugin's feature to the solver's entity. + /// Result if based on the list of already converted attributes. + /// \param theFeature [in] feature to create + virtual EntityWrapperPtr createFeature(FeaturePtr theFeature) override; + + /// \brief Return list of constraints necessary to fix feature's extra DoF + virtual const std::list& constraints() const override + { return myFeatureConstraints; } + +private: + /// list of converted attributes (will be cleared when the feature is created) + AttributeEntityMap myAttributes; + + /// constraints for the feature + /// (primarily used for constrain arcs, which have 9 parameters but 5 DoF) + std::list myFeatureConstraints; +}; + +#endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ParameterWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ParameterWrapper.cpp deleted file mode 100644 index 9c0dfde11..000000000 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ParameterWrapper.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: PlaneGCSSolver_ParameterWrapper.cpp -// Created: 14 Dec 2015 -// Author: Artem ZHIDKOV - -#include - -#include - -PlaneGCSSolver_ParameterWrapper::PlaneGCSSolver_ParameterWrapper(double *const theParam) - : myValue(theParam), - myProcessing(false) -{ -} - -PlaneGCSSolver_ParameterWrapper::~PlaneGCSSolver_ParameterWrapper() -{ - if (!myProcessing) - delete myValue; -} - -void PlaneGCSSolver_ParameterWrapper::setValue(double theValue) -{ - *(myValue) = theValue; -} - -double PlaneGCSSolver_ParameterWrapper::value() const -{ - return *(myValue); -} - -bool PlaneGCSSolver_ParameterWrapper::isEqual(const ParameterWrapperPtr& theOther) -{ - return fabs(value() - theOther->value()) < tolerance; -} - -bool PlaneGCSSolver_ParameterWrapper::update(const ParameterWrapperPtr& theOther) -{ - if (fabs(value() - theOther->value()) < tolerance) - return false; - setValue(theOther->value()); - myIsParametric = theOther->isParametric(); - return true; -} diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ParameterWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ParameterWrapper.h deleted file mode 100644 index 757728e3d..000000000 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ParameterWrapper.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: PlaneGCSSolver_ParameterWrapper.h -// Created: 14 Dec 2015 -// Author: Artem ZHIDKOV - -#ifndef PlaneGCSSolver_ParameterWrapper_H_ -#define PlaneGCSSolver_ParameterWrapper_H_ - -#include -#include - -/** - * Wrapper providing operations with parameters in PlaneGCS. - */ -class PlaneGCSSolver_ParameterWrapper : public SketchSolver_IParameterWrapper -{ -public: - PlaneGCSSolver_ParameterWrapper(double *const theParam); - virtual ~PlaneGCSSolver_ParameterWrapper(); - - /// \brief Return ID of current parameter - virtual ParameterID id() const - { return myID; } - - double* parameter() const - { return myValue; } - - /// \brief Change group for the parameter - virtual void setGroup(const GroupID& theGroup) - { myGroup = theGroup; } - - /// \brief Return identifier of the group the parameter belongs to - virtual GroupID group() const - { return myGroup; } - - /// \brief Change value of parameter - virtual void setValue(double theValue); - /// \brief Return value of parameter - virtual double value() const; - - /// \brief Compare current parameter with other - virtual bool isEqual(const ParameterWrapperPtr& theOther); - - /// \brief Update value of parameter by the given one - /// \return \c true if the value of parameter is changed - virtual bool update(const ParameterWrapperPtr& theOther); - - /// \brief Shows the parameter is added to full list of parameters - bool isProcessed() const - { return myProcessing; } - /// \brief Set the flag that parameter is under processing - void setProcessed(bool isProc) - { myProcessing = isProc; } - -protected: - ParameterID myID; - GroupID myGroup; - double* myValue; - bool myProcessing; ///< identify that the parameter is already in the list of parameters -}; - -#endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointWrapper.cpp index a1e66e587..31426d017 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointWrapper.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointWrapper.cpp @@ -6,56 +6,7 @@ #include -PlaneGCSSolver_PointWrapper::PlaneGCSSolver_PointWrapper( - const AttributePtr theAttribute, const GCSPointPtr thePoint) - : myPoint(thePoint), - myID(EID_UNKNOWN) +PlaneGCSSolver_PointWrapper::PlaneGCSSolver_PointWrapper(const GCSPointPtr thePoint) + : myPoint(thePoint) { - myBaseAttribute = theAttribute; -} - -void PlaneGCSSolver_PointWrapper::setGroup(const GroupID& theGroup) -{ - myGroup = theGroup; - std::list::iterator aSubsIt = mySubEntities.begin(); - for (; aSubsIt != mySubEntities.end(); ++aSubsIt) - (*aSubsIt)->setGroup(theGroup); - std::list::iterator aPIt = myParameters.begin(); - for (; aPIt != myParameters.end(); ++aPIt) - (*aPIt)->setGroup(theGroup); -} - -bool PlaneGCSSolver_PointWrapper::isUsed(AttributePtr theAttribute) const -{ - return isBase(theAttribute); -} - -bool PlaneGCSSolver_PointWrapper::isEqual(const EntityWrapperPtr& theOther) -{ - if (type() != theOther->type()) - return false; - - // Verify equality of parameters - const std::list& anOtherParams = theOther->parameters(); - if (myParameters.size() != anOtherParams.size()) - return false; - std::list::const_iterator aMyIt = myParameters.begin(); - std::list::const_iterator anOtherIt = anOtherParams.begin(); - for (; aMyIt != myParameters.end(); ++aMyIt, ++anOtherIt) - if (!(*aMyIt)->isEqual(*anOtherIt)) - return false; - return true; -} - -bool PlaneGCSSolver_PointWrapper::update(const EntityWrapperPtr& theOther) -{ - bool isUpdated = false; - std::list aMyParams = parameters(); - std::list anOtherParams = theOther->parameters(); - std::list::const_iterator aMyParIt = aMyParams.begin(); - std::list::const_iterator anOtherParIt = anOtherParams.begin(); - for (; aMyParIt != aMyParams.end() && anOtherParIt != anOtherParams.end(); - ++aMyParIt, ++anOtherParIt) - isUpdated = (*aMyParIt)->update(*anOtherParIt); - return isUpdated; } diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointWrapper.h index dc276d4b2..6bb2ade7a 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointWrapper.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointWrapper.h @@ -16,7 +16,7 @@ class PlaneGCSSolver_PointWrapper : public SketchSolver_IEntityWrapper { public: - PlaneGCSSolver_PointWrapper(const AttributePtr theAttribute, const GCSPointPtr thePoint); + PlaneGCSSolver_PointWrapper(const GCSPointPtr thePoint); /// \brief Return PlaneGCS point const GCSPointPtr& point() const @@ -25,39 +25,11 @@ public: GCSPointPtr& changeEntity() { return myPoint; } - /// \brief Return ID of current entity - virtual EntityID id() const - { return myID; } - /// \brief Change ID of the entity - void setId(EntityID theID) - { myID = theID; } - - /// \brief Change group for the entity - virtual void setGroup(const GroupID& theGroup); - /// \brief Return identifier of the group the entity belongs to - virtual GroupID group() const - { return myGroup; } - /// \brief Return type of current entity virtual SketchSolver_EntityType type() const { return ENTITY_POINT; } - /// \brief Verify the feature is used in the entity - virtual bool isUsed(FeaturePtr theFeature) const - { return false; } - /// \brief Verify the attribute is used in the entity - virtual bool isUsed(AttributePtr theAttribute) const; - - /// \brief Compare current entity with other - virtual bool isEqual(const EntityWrapperPtr& theOther); - - /// \brief Update values of parameters of this entity by the parameters of given one - /// \return \c true if some parameters change their values - virtual bool update(const EntityWrapperPtr& theOther); - private: - EntityID myID; - GroupID myGroup; GCSPointPtr myPoint; }; diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.cpp index 281198846..92cd4c95d 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.cpp @@ -5,62 +5,20 @@ // Author: Artem ZHIDKOV #include -#include +#include - -PlaneGCSSolver_ScalarWrapper::PlaneGCSSolver_ScalarWrapper( - const AttributePtr theAttribute, - const ParameterWrapperPtr theParam) -{ - myBaseAttribute = theAttribute; - myParameters.assign(1, theParam); -} - -void PlaneGCSSolver_ScalarWrapper::setGroup(const GroupID& theGroup) +PlaneGCSSolver_ScalarWrapper::PlaneGCSSolver_ScalarWrapper(double *const theParam) + : myValue(theParam) { - myGroup = theGroup; - myParameters.front()->setGroup(theGroup); } -double* PlaneGCSSolver_ScalarWrapper::scalar() const +void PlaneGCSSolver_ScalarWrapper::setValue(double theValue) { - std::shared_ptr aParam = - std::dynamic_pointer_cast(myParameters.front()); - return aParam->parameter(); -} - -bool PlaneGCSSolver_ScalarWrapper::isUsed(AttributePtr theAttribute) const -{ - return isBase(theAttribute); -} - -bool PlaneGCSSolver_ScalarWrapper::isEqual(const EntityWrapperPtr& theOther) -{ - if (type() != theOther->type()) - return false; - - // Verify equality of parameters - const std::list& anOtherParams = theOther->parameters(); - if (myParameters.size() != anOtherParams.size()) - return false; - std::list::const_iterator aMyIt = myParameters.begin(); - std::list::const_iterator anOtherIt = anOtherParams.begin(); - for (; aMyIt != myParameters.end(); ++aMyIt, ++anOtherIt) - if (!(*aMyIt)->isEqual(*anOtherIt)) - return false; - return true; + *myValue = theValue; } -bool PlaneGCSSolver_ScalarWrapper::update(const EntityWrapperPtr& theOther) +double PlaneGCSSolver_ScalarWrapper::value() const { - bool isUpdated = false; - std::list aMyParams = parameters(); - std::list anOtherParams = theOther->parameters(); - std::list::const_iterator aMyParIt = aMyParams.begin(); - std::list::const_iterator anOtherParIt = anOtherParams.begin(); - for (; aMyParIt != aMyParams.end() && anOtherParIt != anOtherParams.end(); - ++aMyParIt, ++anOtherParIt) - isUpdated = (*aMyParIt)->update(*anOtherParIt); - return isUpdated; + return *myValue; } diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.h index 89e389da2..f0907a588 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.h @@ -16,44 +16,25 @@ class PlaneGCSSolver_ScalarWrapper : public SketchSolver_IEntityWrapper { public: - PlaneGCSSolver_ScalarWrapper(const AttributePtr theAttribute, const ParameterWrapperPtr theParam); + PlaneGCSSolver_ScalarWrapper(double *const theParam); /// \brief Return PlaneGCS parameter - double* scalar() const; + double* scalar() const + { return myValue; } - /// \brief Return ID of current entity - virtual EntityID id() const - { return myID; } - /// \brief Change ID of the entity - void setId(EntityID theID) - { myID = theID; } - - /// \brief Change group for the entity - virtual void setGroup(const GroupID& theGroup); - /// \brief Return identifier of the group the entity belongs to - virtual GroupID group() const - { return myGroup; } + /// \brief Change value of parameter + virtual void setValue(double theValue); + /// \brief Return value of parameter + virtual double value() const; /// \brief Return type of current entity virtual SketchSolver_EntityType type() const { return ENTITY_SCALAR; } - /// \brief Verify the feature is used in the entity - virtual bool isUsed(FeaturePtr theFeature) const - { return false; } - /// \brief Verify the attribute is used in the entity - virtual bool isUsed(AttributePtr theAttribute) const; - - /// \brief Compare current entity with other - virtual bool isEqual(const EntityWrapperPtr& theOther); - - /// \brief Update values of parameters of this entity by the parameters of given one - /// \return \c true if some parameters change their values - virtual bool update(const EntityWrapperPtr& theOther); - -private: - EntityID myID; - GroupID myGroup; +protected: + double* myValue; ///< pointer to value provided by the storage }; +typedef std::shared_ptr ScalarWrapperPtr; + #endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp index a16a3bbde..9181f43dd 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp @@ -7,28 +7,10 @@ #include "PlaneGCSSolver_Solver.h" #include -#include - -// remove indices of all point-point coincidences from the vector -static void removePtPtCoincidences(const ConstraintMap& theConstraints, GCS::VEC_I& theVecToClear) -{ - ConstraintMap::const_iterator aCIt = theConstraints.begin(); - for (; aCIt != theConstraints.end(); ++aCIt) { - if (aCIt->second != CONSTRAINT_PT_PT_COINCIDENT) - continue; - GCS::VEC_I::iterator aRIt = theVecToClear.begin(); - for (; aRIt != theVecToClear.end(); ++aRIt) - if (aCIt->first->getTag() == *aRIt) { - theVecToClear.erase(aRIt); - break; - } - } -} - PlaneGCSSolver_Solver::PlaneGCSSolver_Solver() : myEquationSystem(new GCS::System), - myConfCollected(false) + myConfCollected(false) { } @@ -40,34 +22,19 @@ PlaneGCSSolver_Solver::~PlaneGCSSolver_Solver() void PlaneGCSSolver_Solver::clear() { myEquationSystem->clear(); - myConstraints.clear(); myParameters.clear(); + myEqualConstraints.clear(); + myEqualParameters.clear(); } -void PlaneGCSSolver_Solver::addConstraint(GCSConstraintPtr theConstraint, - const SketchSolver_ConstraintType theType) +void PlaneGCSSolver_Solver::addConstraint(GCSConstraintPtr theConstraint) { - GCS::Constraint* aConstraint = theConstraint.get(); - if (myConstraints.find(aConstraint) != myConstraints.end()) - return; // constraint already exists, no need to add it again - - myEquationSystem->addConstraint(aConstraint); - myConstraints[aConstraint] = theType; + myEquationSystem->addConstraint(theConstraint.get()); } -void PlaneGCSSolver_Solver::removeConstraint(GCSConstraintPtr theConstraint) +void PlaneGCSSolver_Solver::removeConstraint(ConstraintID theID) { - GCS::Constraint* aConstraint = theConstraint.get(); - removeConstraint(aConstraint); -} - -void PlaneGCSSolver_Solver::removeConstraint(GCS::Constraint* theConstraint) -{ - if (myConstraints.find(theConstraint) == myConstraints.end()) - return; // no constraint, no need to remove it - - myEquationSystem->removeConstraint(theConstraint); - myConstraints.erase(theConstraint); + myEquationSystem->clearByTag(theID); } SketchSolver_SolveStatus PlaneGCSSolver_Solver::solve() @@ -78,79 +45,12 @@ SketchSolver_SolveStatus PlaneGCSSolver_Solver::solve() myConfCollected = false; } - if (myConstraints.empty()) - return STATUS_EMPTYSET; if (myParameters.empty()) return STATUS_INCONSISTENT; Events_LongOp::start(this); - GCS::SolveStatus aResult = GCS::Success; - // if there is a constraint with all attributes constant, set fail status - GCS::SET_pD aParameters; - aParameters.insert(myParameters.begin(), myParameters.end()); - ConstraintMap::const_iterator aConstrIt = myConstraints.begin(); - for (; aConstrIt != myConstraints.end(); ++aConstrIt) { - GCS::VEC_pD aParams = aConstrIt->first->params(); - GCS::VEC_pD::const_iterator aPIt = aParams.begin(); - for (; aPIt != aParams.end(); ++aPIt) - if (aParameters.find(*aPIt) != aParameters.end()) - break; - if (aPIt == aParams.end() && aConstrIt->first->getTag() > 0) { - myConflictingIDs.insert(aConstrIt->first->getTag()); - myConfCollected = true; - aResult = GCS::Failed; - } - } // solve equations - if (aResult == GCS::Success) - aResult = (GCS::SolveStatus)myEquationSystem->solve(myParameters); - - GCS::VEC_I aRedundantID; - - // Workaround: the system with tangent constraint - // may fail if the tangent entities are connected smoothly. - // Investigate this situation and move constraints to redundant list - if (aResult == GCS::Failed && !myTangent.empty()) { - GCS::VEC_I aConflictingID; - myEquationSystem->getConflicting(aConflictingID); - GCS::VEC_I::iterator aCIt = aConflictingID.begin(); - for (; aCIt != aConflictingID.end(); ++ aCIt) { - if (myTangent.find(*aCIt) == myTangent.end()) - continue; - if (isTangentTruth(*aCIt)) - aRedundantID.push_back(*aCIt); - } - - if (!aRedundantID.empty()) - aResult = GCS::Success; // check redundant constraints - } - - // Additionally check redundant constraints - if (aResult == GCS::Success || aResult == GCS::Converged) { - bool isSolveWithoutTangent = !aRedundantID.empty(); - GCS::VEC_I aRedundantLocal; - myEquationSystem->getRedundant(aRedundantLocal); - aRedundantID.insert(aRedundantID.end(), aRedundantLocal.begin(), aRedundantLocal.end()); - // Workaround: remove all point-point coincidences from list of redundant - if (!aRedundantID.empty()) - removePtPtCoincidences(myConstraints, aRedundantID); - // The system with tangent constraints may show redundant constraints - // if the entities are coupled smoothly. - // Sometimes tangent constraints are fall to both conflicting and redundant constraints. - // Need to check if there are redundant constraints without these tangencies. - if (!aRedundantID.empty() && !isSolveWithoutTangent) { - GCS::VEC_I::iterator aCIt = aRedundantID.begin(); - for (; aCIt != aRedundantID.end(); ++ aCIt) - if (myTangent.find(*aCIt) != myTangent.end()) { - isSolveWithoutTangent = true; - break; - } - } - if (isSolveWithoutTangent) - aResult = myTangent.empty() ? GCS::Failed : solveWithoutTangent(); - else - aResult = GCS::Success; - } + GCS::SolveStatus aResult = (GCS::SolveStatus)myEquationSystem->solve(myParameters); Events_LongOp::end(this); SketchSolver_SolveStatus aStatus; @@ -163,119 +63,6 @@ SketchSolver_SolveStatus PlaneGCSSolver_Solver::solve() return aStatus; } -GCS::SolveStatus PlaneGCSSolver_Solver::solveWithoutTangent() -{ - std::shared_ptr aSystemWithoutTangent(new GCS::System); - - // Remove tangency which leads to redundant or conflicting constraints - GCS::VEC_I aConflicting, aRedundant; - myEquationSystem->getRedundant(aRedundant); - size_t aNbRemove = myTangent.size(); // number of tangent constraints which can be removed - myEquationSystem->getConflicting(aConflicting); - aRedundant.insert(aRedundant.end(), aConflicting.begin(), aConflicting.end()); - - GCS::SET_I aTangentToRemove; - GCS::VEC_I::iterator aCIt = aRedundant.begin(); - for (; aCIt != aRedundant.end() && aNbRemove > 0; ++aCIt) - if (myTangent.find(*aCIt) != myTangent.end()) { - aTangentToRemove.insert(*aCIt); - --aNbRemove; - } - - std::set aRemovedTangent; - ConstraintMap::const_iterator aConstrIt = myConstraints.begin(); - while (aConstrIt != myConstraints.end()) { - GCS::Constraint* aConstraint = aConstrIt->first; - int anID = aConstraint->getTag(); - ++aConstrIt; - if (aTangentToRemove.find(anID) == aTangentToRemove.end()) - aSystemWithoutTangent->addConstraint(aConstraint); - else - aRemovedTangent.insert(aConstraint); - } - - myTangent.clear(); - GCS::SolveStatus aResult = (GCS::SolveStatus)aSystemWithoutTangent->solve(myParameters); - if (aResult == GCS::Success) { - GCS::VEC_I aRedundant; - aSystemWithoutTangent->getRedundant(aRedundant); - if (!aRedundant.empty()) { - removePtPtCoincidences(myConstraints, aRedundant); - if (!aRedundant.empty()) - aResult = GCS::Failed; - } - } - - // additional check that removed constraints are still correct - if (aResult == GCS::Success) { - aSystemWithoutTangent->applySolution(); - std::set::const_iterator aRemIt = aRemovedTangent.begin(); - for (; aRemIt != aRemovedTangent.end(); ++aRemIt) - if (!isTangentTruth(*aRemIt)) - break; - if (aRemIt != aRemovedTangent.end()) { - aResult = (GCS::SolveStatus)myEquationSystem->solve(myParameters); - if (aResult != GCS::Failed) { - aSystemWithoutTangent = myEquationSystem; - aResult = GCS::Success; - } - } - } - - if (aResult == GCS::Success) - myEquationSystem = aSystemWithoutTangent; - else { - // Add IDs of removed tangent to the list of conflicting constraints - std::set::const_iterator aRemIt = aRemovedTangent.begin(); - for (; aRemIt != aRemovedTangent.end(); ++aRemIt) - myConflictingIDs.insert((*aRemIt)->getTag()); - } - - return aResult; -} - -bool PlaneGCSSolver_Solver::isTangentTruth(GCS::Constraint* theTangent) const -{ - if (theTangent->getTypeId() == GCS::TangentCircumf) { - static const double aTol = 1e-4; - GCS::VEC_pD aParams = theTangent->params(); - double dx = *(aParams[2]) - *(aParams[0]); - double dy = *(aParams[3]) - *(aParams[1]); - double aDist2 = dx * dx + dy * dy; - double aRadSum = *(aParams[4]) + *(aParams[5]); - double aRadDiff = *(aParams[4]) - *(aParams[5]); - double aTol2 = aTol * aRadSum; - aTol2 *= aTol2; - return fabs(aDist2 - aRadSum * aRadSum) <= aTol2 || - fabs(aDist2 - aRadDiff * aRadDiff) <= aTol2; - } - if (theTangent->getTypeId() == GCS::P2LDistance) { - static const double aTol2 = 1e-10; - GCS::VEC_pD aParams = theTangent->params(); - double aDist2 = *(aParams[6]) * *(aParams[6]); - // orthogonal line direction - double aDirX = *(aParams[5]) - *(aParams[3]); - double aDirY = *(aParams[2]) - *(aParams[4]); - double aLen2 = aDirX * aDirX + aDirY * aDirY; - // vector from line's start to point - double aVecX = *(aParams[0]) - *(aParams[2]); - double aVecY = *(aParams[1]) - *(aParams[3]); - - double aDot = aVecX * aDirX + aVecY * aDirY; - return fabs(aDot * aDot - aDist2 * aLen2) <= aTol2 * aLen2; - } - return false; -} - -bool PlaneGCSSolver_Solver::isTangentTruth(int theTagID) const -{ - ConstraintMap::const_iterator anIt = myConstraints.begin(); - for (; anIt != myConstraints.end(); ++anIt) - if (anIt->first->getTag() == theTagID) - return isTangentTruth(anIt->first); - return false; -} - void PlaneGCSSolver_Solver::undo() { myEquationSystem->undoSolution(); diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h index c32d2daf6..051f73cad 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h @@ -13,11 +13,7 @@ #include -typedef std::map ConstraintMap; - -/** - * The main class that performs the high-level operations for connection to the PlaneGCS. - */ +/// \brief The main class that performs the high-level operations for connection to the PlaneGCS. class PlaneGCSSolver_Solver : public SketchSolver_ISolver { public: @@ -28,60 +24,37 @@ public: void clear(); /// \brief Add constraint to the system of equations - void addConstraint(GCSConstraintPtr theConstraint, - const SketchSolver_ConstraintType theType); + void addConstraint(GCSConstraintPtr theConstraint); /// \brief Remove constraint from the system of equations - void removeConstraint(GCSConstraintPtr theConstraint); + void removeConstraint(ConstraintID theID); /// \brief Initialize list of unknowns void setParameters(const GCS::VEC_pD& theParams) { myParameters = theParams; } - /// \brief Set list of IDs of tangent constraints - /// - /// Workaround to avoid incorrect report about redundant constraints - /// if an arc is already smoothly connected to a line. - void setTangent(const GCS::SET_I& theTangentIDs) - { myTangent = theTangentIDs; } - - /** \brief Solve the set of equations - * \return identifier whether solution succeeded - */ - virtual SketchSolver_SolveStatus solve(); + /// \brief Solve the set of equations + /// \return identifier whether solution succeeded + virtual SketchSolver_SolveStatus solve() override; /// \brief Prepare for solving. Store initial values of parameters for undo - virtual void prepare() + virtual void prepare() override { /* do nothing */ } /// \brief Revert solution to initial values - virtual void undo(); + virtual void undo() override; /// \brief Check the constraint is conflicted with others - virtual bool isConflicting(const ConstraintID& theConstraint) const; + virtual bool isConflicting(const ConstraintID& theConstraint) const override; /// \brief Degrees of freedom - virtual int dof() const; + virtual int dof() const override; private: void collectConflicting(); - /// \brief Remove constraint from the system of equations - void removeConstraint(GCS::Constraint* theConstraint); - - /// \brief Remove redundant tangent constraints and try to solve the system again - GCS::SolveStatus solveWithoutTangent(); - - /// \brief Check the entities under the tangent constraint are smoothly connected - bool isTangentTruth(int theTagID) const; - /// \brief Check the entities under the tangent constraint are smoothly connected - bool isTangentTruth(GCS::Constraint* theTangent) const; - private: GCS::VEC_pD myParameters; ///< list of unknowns - - /// list of constraints already processed by the system - ConstraintMap myConstraints; std::shared_ptr myEquationSystem; ///< set of equations for solving in FreeGCS GCS::SET_I myConflictingIDs; ///< list of IDs of conflicting constraints @@ -89,8 +62,10 @@ private: /// specifies the conflicting constraints are already collected bool myConfCollected; - /// list of tangent IDs to check incorrect redundant constraints - GCS::SET_I myTangent; + /// lists of parameters used in the Equal constraints (to avoid multiple equalities) + std::list myEqualParameters; + /// lists of the Equal constraints + std::map > myEqualConstraints; }; #endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp index 37086e22f..89c5bd29f 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp @@ -10,545 +10,344 @@ #include #include #include -#include -#include -#include +#include +#include +#include + #include #include #include #include -#include -#include +#include #include -PlaneGCSSolver_Storage::PlaneGCSSolver_Storage(const GroupID& theGroup) - : SketchSolver_Storage(theGroup), - myEntityLastID(EID_SKETCH), +static void constraintsToSolver(const ConstraintWrapperPtr& theConstraint, + const SolverPtr& theSolver) +{ + std::shared_ptr aSolver = + std::dynamic_pointer_cast(theSolver); + if (!aSolver) + return; + + const std::list& aConstraints = + std::dynamic_pointer_cast(theConstraint)->constraints(); + std::list::const_iterator anIt = aConstraints.begin(); + for (; anIt != aConstraints.end(); ++anIt) + aSolver->addConstraint(*anIt); +} + + +PlaneGCSSolver_Storage::PlaneGCSSolver_Storage(const SolverPtr& theSolver) + : SketchSolver_Storage(theSolver), myConstraintLastID(CID_UNKNOWN) { } void PlaneGCSSolver_Storage::addConstraint( - ConstraintPtr theConstraint, - std::list theSolverConstraints) + ConstraintPtr theConstraint, + ConstraintWrapperPtr theSolverConstraint) { - SketchSolver_Storage::addConstraint(theConstraint, theSolverConstraints); - - // update point-point coincidence - if (!theSolverConstraints.empty() && - theSolverConstraints.front()->type() == CONSTRAINT_PT_PT_COINCIDENT) { - std::list::iterator aCIt = theSolverConstraints.begin(); - for (; aCIt != theSolverConstraints.end(); ++aCIt) - update(*aCIt); - } + SketchSolver_Storage::addConstraint(theConstraint, theSolverConstraint); + + theSolverConstraint->setId(++myConstraintLastID); + constraintsToSolver(theSolverConstraint, mySketchSolver); +} + +void PlaneGCSSolver_Storage::addTemporaryConstraint( + const ConstraintWrapperPtr& theSolverConstraint) +{ + if (myConstraintMap.empty()) + return; // no need to process temporary constraints if there is no active constraint + + theSolverConstraint->setId(CID_MOVEMENT); + constraintsToSolver(theSolverConstraint, mySketchSolver); } -bool PlaneGCSSolver_Storage::update(ConstraintWrapperPtr theConstraint) +EntityWrapperPtr PlaneGCSSolver_Storage::createFeature( + const FeaturePtr& theFeature, + PlaneGCSSolver_EntityBuilder* theBuilder) { - bool isUpdated = false; - std::shared_ptr aConstraint = - std::dynamic_pointer_cast(theConstraint); - - // point-Line distance should be positive - if (aConstraint->type() == CONSTRAINT_PT_LINE_DISTANCE && aConstraint->value() < 0.0) - aConstraint->setValue(-aConstraint->value()); - - // make value of constraint unchangeable - ParameterWrapperPtr aValue = aConstraint->valueParameter(); - if (aValue) - isUpdated = update(aValue) || isUpdated; - - // update constrained entities - std::list anEntities = theConstraint->entities(); - std::list::iterator anIt = anEntities.begin(); - for (; anIt != anEntities.end(); ++anIt) - isUpdated = update(*anIt) || isUpdated; - - if (aConstraint->id() == CID_UNKNOWN) { - const std::list& aSubs = aConstraint->entities(); - // check middle-point constraint conflicts with point-on-line - if (aConstraint->type() == CONSTRAINT_MIDDLE_POINT) { - std::map >::const_iterator - anIt = myConstraintMap.begin(); - for (; anIt != myConstraintMap.end(); ++anIt) { - EntityWrapperPtr aPoint, aLine; - if (anIt->second.empty()) - continue; - ConstraintWrapperPtr aCurrentConstr = anIt->second.front(); - if (aCurrentConstr->type() != CONSTRAINT_PT_ON_LINE) - continue; - const std::list& aCurSubs = aCurrentConstr->entities(); - std::list::const_iterator aSIt1, aSIt2; - for (aSIt1 = aSubs.begin(); aSIt1 != aSubs.end(); ++aSIt1) { - if ((*aSIt1)->type() == ENTITY_POINT) - aPoint = *aSIt1; - else if((*aSIt1)->type() == ENTITY_LINE) - aLine = *aSIt1; - else - continue; - for (aSIt2 = aCurSubs.begin(); aSIt2 != aCurSubs.end(); ++aSIt2) - if ((*aSIt1)->id() == (*aSIt2)->id()) - break; - if (aSIt2 == aCurSubs.end()) - break; - } - // point-on-line found, change it to bisector - if (aSIt1 == aSubs.end()) { - std::list aConstrList = aConstraint->constraints(); - aConstrList.pop_front(); - aConstraint->setConstraints(aConstrList); - break; - } - } - } + std::list anAttributes = theFeature->data()->attributes(std::string()); + std::list::const_iterator anIt = anAttributes.begin(); + for (; anIt != anAttributes.end(); ++anIt) + createAttribute(*anIt, theBuilder); + + EntityWrapperPtr aResult = theBuilder->createFeature(theFeature); + if (aResult) + addEntity(theFeature, aResult); + return aResult; +} - // Change ID of constraints - aConstraint->setId(++myConstraintLastID); - } +EntityWrapperPtr PlaneGCSSolver_Storage::createAttribute( + const AttributePtr& theAttribute, + PlaneGCSSolver_EntityBuilder* theBuilder) +{ + EntityWrapperPtr aResult = theBuilder->createAttribute(theAttribute); + if (aResult) + addEntity(theAttribute, aResult); + return aResult; +} +/// \brief Update value +static bool updateValue(const double& theSource, double& theDest) +{ + static const double aTol = 1000. * tolerance; + bool isUpdated = fabs(theSource - theDest) > aTol; + if (isUpdated) + theDest = theSource; return isUpdated; } /// \brief Update coordinates of the point or scalar using its base attribute -static bool updateValues(EntityWrapperPtr& theEntity) +static bool updateValues(AttributePtr& theAttribute, EntityWrapperPtr& theEntity) { - const double aTol = 1000. * tolerance; bool isUpdated = false; - AttributePtr anAttr = theEntity->baseAttribute(); - const std::list aParams = theEntity->parameters(); - - double aCoord[2]; std::shared_ptr aPoint2D = - std::dynamic_pointer_cast(anAttr); + std::dynamic_pointer_cast(theAttribute); if (aPoint2D) { - aCoord[0] = aPoint2D->x(); - aCoord[1] = aPoint2D->y(); + const GCSPointPtr& aGCSPoint = + std::dynamic_pointer_cast(theEntity)->point(); + isUpdated = updateValue(aPoint2D->x(), *(aGCSPoint->x)) || isUpdated; + isUpdated = updateValue(aPoint2D->y(), *(aGCSPoint->y)) || isUpdated; } else { - AttributeDoublePtr aScalar = std::dynamic_pointer_cast(anAttr); - if (aScalar) - aCoord[0] = aScalar->value(); - } - - std::list::const_iterator anIt = aParams.begin(); - for (int i = 0; anIt != aParams.end(); ++anIt, ++i) - if (fabs((*anIt)->value() - aCoord[i]) > aTol) { - (*anIt)->setValue(aCoord[i]); - isUpdated = true; - } - return isUpdated; -} - -bool PlaneGCSSolver_Storage::update(EntityWrapperPtr theEntity) -{ - if (theEntity->type() == ENTITY_SKETCH) - return true; // sketch is not necessary for PlaneGCS, so it is always says true - - bool isUpdated = false; - - if (theEntity->baseAttribute()) { - isUpdated = updateValues(theEntity); - if (isUpdated) { - setNeedToResolve(true); - if (theEntity->type() == ENTITY_POINT && theEntity->group() != myGroupID) - updateCoincident(theEntity); - } - } - - // update parameters - std::list aParams = theEntity->parameters(); - std::list::iterator aPIt = aParams.begin(); - for (; aPIt != aParams.end(); ++aPIt) - isUpdated = update(*aPIt) || isUpdated; - - // update sub-entities - std::list aSubEntities = theEntity->subEntities(); - std::list::iterator aSIt = aSubEntities.begin(); - for (; aSIt != aSubEntities.end(); ++aSIt) - isUpdated = update(*aSIt) || isUpdated; - - // additional constraints for the arc processing - if (theEntity->type() == ENTITY_ARC) - processArc(theEntity); - - // Change entity's ID, if necessary - if (theEntity->id() == EID_UNKNOWN) { - if (theEntity->type() == ENTITY_POINT) { - std::shared_ptr aPoint = - std::dynamic_pointer_cast(theEntity); - if (!aPoint) { - aPoint = std::dynamic_pointer_cast( - theEntity->subEntities().front()); - } - aPoint->setId(++myEntityLastID); - } else if (theEntity->type() == ENTITY_SCALAR) { - std::shared_ptr aScalar = + AttributeDoublePtr aScalar = + std::dynamic_pointer_cast(theAttribute); + if (aScalar) { + ScalarWrapperPtr aWrapper = std::dynamic_pointer_cast(theEntity); - aScalar->setId(++myEntityLastID); - } else { - std::shared_ptr aGCSEnt = - std::dynamic_pointer_cast(theEntity); - aGCSEnt->setId(++myEntityLastID); + // There is possible angular value, which is converted between degrees and radians. + // So, we use its value instead of using direct pointer to value. + double aValue = aWrapper->value(); + isUpdated = updateValue(aScalar->value(), aValue); + if (isUpdated) + aWrapper->setValue(aValue); } } - return isUpdated; -} - -bool PlaneGCSSolver_Storage::update(ParameterWrapperPtr theParameter) -{ - std::shared_ptr aParam = - std::dynamic_pointer_cast(theParameter); - if (aParam->isProcessed()) - return false; - if (theParameter->group() != myGroupID || theParameter->isParametric()) - myConst.push_back(aParam->parameter()); - else - myParameters.push_back(aParam->parameter()); - aParam->setProcessed(true); - return true; -} - -bool PlaneGCSSolver_Storage::remove(ConstraintWrapperPtr theConstraint) -{ - std::shared_ptr aConstraint = - std::dynamic_pointer_cast(theConstraint); - - bool isFullyRemoved = true; - // remove point-point coincidence - if (aConstraint->type() == CONSTRAINT_PT_PT_COINCIDENT) - isFullyRemoved = removeCoincidence(theConstraint) && isFullyRemoved; - // remove sub-entities - const std::list& aSubs = aConstraint->entities(); - std::list::const_iterator aSIt = aSubs.begin(); - for (; aSIt != aSubs.end(); ++ aSIt) - isFullyRemoved = remove(*aSIt) && isFullyRemoved; - - if (aConstraint->valueParameter()) - isFullyRemoved = remove(aConstraint->valueParameter()) && isFullyRemoved; - if (!isFullyRemoved && aConstraint->baseConstraint() && - (!aConstraint->baseConstraint()->data() || !aConstraint->baseConstraint()->data()->isValid())) - isFullyRemoved = true; - setNeedToResolve(true); - myRemovedConstraints.insert(myRemovedConstraints.end(), - aConstraint->constraints().begin(), aConstraint->constraints().end()); - - if (isFullyRemoved && theConstraint->id() == myConstraintLastID) - --myConstraintLastID; - - return isFullyRemoved; + return isUpdated; } -bool PlaneGCSSolver_Storage::remove(EntityWrapperPtr theEntity) +static bool isCopyInMulti(std::shared_ptr theFeature) { - // do not remove entity, if it is used by constraints or other entities - if ((theEntity->baseFeature() && isUsed(theEntity->baseFeature())) || - (theEntity->baseAttribute() && isUsed(theEntity->baseAttribute()))) + if (!theFeature) return false; - bool isFullyRemoved = SketchSolver_Storage::remove(theEntity); - if (isFullyRemoved) { - if (theEntity->type() == ENTITY_ARC) { - // remove arc additional constraints - std::map >::iterator - aFound = myArcConstraintMap.find(theEntity); - if (aFound != myArcConstraintMap.end()) { - myRemovedConstraints.insert(myRemovedConstraints.end(), - aFound->second.begin(), aFound->second.end()); - myArcConstraintMap.erase(aFound); - } + bool aResult = theFeature->isCopy(); + if (aResult) { + const std::set& aRefs = theFeature->data()->refsToMe(); + for (std::set::const_iterator aRefIt = aRefs.begin(); + aRefIt != aRefs.end() && aResult; ++aRefIt) { + FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner()); + if (anOwner->getKind() == SketchPlugin_Projection::ID()) + aResult = false; } - if (theEntity->id() == myEntityLastID) - --myEntityLastID; } - return isFullyRemoved; + return aResult; } -bool PlaneGCSSolver_Storage::remove(ParameterWrapperPtr theParameter) +bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce) { - std::shared_ptr aParam = - std::dynamic_pointer_cast(theParameter); - if (aParam->isProcessed()) { - double* aValPtr = aParam->parameter(); - GCS::VEC_pD::iterator anIt = myParameters.begin(); - for (; anIt != myParameters.end(); ++anIt) - if (*anIt == aValPtr) - break; - if (anIt != myParameters.end()) { - myParameters.erase(anIt); - setNeedToResolve(true); - aParam->setProcessed(false); - } - else { - for (anIt = myConst.begin(); anIt != myConst.end(); ++anIt) - if (*anIt == aValPtr) - break; - if (anIt != myConst.end()) { - myConst.erase(anIt); - setNeedToResolve(true); - aParam->setProcessed(false); - } + bool isUpdated = false; + EntityWrapperPtr aRelated = entity(theFeature); + if (aRelated) // send signal to subscribers + notify(theFeature); + else { // Feature is not exist, create it + std::shared_ptr aSketchFeature = + std::dynamic_pointer_cast(theFeature); + bool isCopy = isCopyInMulti(aSketchFeature); + // the feature is a copy in "Multi" constraint and does not used in other constraints + if (!theForce && isCopy && myFeatureMap.find(theFeature) == myFeatureMap.end()) + return false; + + // external feature processing + bool isExternal = (aSketchFeature && (aSketchFeature->isExternal() || isCopy)); + + PlaneGCSSolver_FeatureBuilder aBuilder(isExternal ? 0 : this); + + // Reserve the feature in the map of features + // (do not want to add several copies of it while adding attributes) + aRelated = createFeature(theFeature, &aBuilder); + myFeatureMap[theFeature] = aRelated; + + const std::list& aConstraints = aBuilder.constraints(); + if (!aConstraints.empty()) { // the feature is arc + /// TODO: avoid this workaround + ConstraintWrapperPtr aWrapper( + new PlaneGCSSolver_ConstraintWrapper(aConstraints, CONSTRAINT_UNKNOWN)); + aWrapper->setId(++myConstraintLastID); + constraintsToSolver(aWrapper, mySketchSolver); + + myArcConstraintMap[myFeatureMap[theFeature]] = aWrapper; } + isUpdated = true; } - return true; -} + std::list anAttributes = theFeature->data()->attributes(std::string()); + std::list::iterator anAttrIt = anAttributes.begin(); + for (; anAttrIt != anAttributes.end(); ++anAttrIt) + if ((*anAttrIt)->attributeType() == GeomDataAPI_Point2D::typeId() || + (*anAttrIt)->attributeType() == ModelAPI_AttributeDouble::typeId()) + isUpdated = update(*anAttrIt) || isUpdated; -void PlaneGCSSolver_Storage::addCoincidentPoints( - EntityWrapperPtr theMaster, EntityWrapperPtr theSlave) -{ - if (theMaster->type() != ENTITY_POINT || theSlave->type() != ENTITY_POINT) - return; - - std::shared_ptr aMaster = - std::dynamic_pointer_cast(theMaster); - if (!aMaster) - aMaster = std::dynamic_pointer_cast( - std::dynamic_pointer_cast(theMaster)->subEntities().front()); - std::shared_ptr aSlave = - std::dynamic_pointer_cast(theSlave); - if (!aSlave) - aSlave = std::dynamic_pointer_cast( - std::dynamic_pointer_cast(theSlave)->subEntities().front()); - - // Search available coincidence - CoincidentPointsMap::iterator aMasterFound = myCoincidentPoints.find(aMaster); - CoincidentPointsMap::iterator aSlaveFound = myCoincidentPoints.find(aSlave); - if (aMasterFound == myCoincidentPoints.end() && aSlaveFound == myCoincidentPoints.end()) { - // try to find master and slave points in the lists of slaves of already existent coincidences - CoincidentPointsMap::iterator anIt = myCoincidentPoints.begin(); - for (; anIt != myCoincidentPoints.end(); ++anIt) { - if (anIt->second.find(aMaster) != anIt->second.end()) - aMasterFound = anIt; - else if (anIt->second.find(aSlave) != anIt->second.end()) - aSlaveFound = anIt; - - if (aMasterFound != myCoincidentPoints.end() && aSlaveFound != myCoincidentPoints.end()) - break; - } - } + // update arc + if (aRelated && aRelated->type() == ENTITY_ARC) { + /// TODO: this code should be shared with FeatureBuilder somehow - if (aMasterFound == myCoincidentPoints.end()) { - // create new group - myCoincidentPoints[aMaster] = std::set(); - aMasterFound = myCoincidentPoints.find(aMaster); - } else if (aMasterFound == aSlaveFound) - return; // already coincident - - if (aSlaveFound != myCoincidentPoints.end()) { - // A slave has been found, we need to attach all points coincident with it to the new master - std::set aNewSlaves = aSlaveFound->second; - aNewSlaves.insert(aSlaveFound->first); - myCoincidentPoints.erase(aSlaveFound); - - std::set::const_iterator aSlIt = aNewSlaves.begin(); - for (; aSlIt != aNewSlaves.end(); ++aSlIt) - addCoincidentPoints(aMaster, *aSlIt); - } else { - //std::list aSlaveParams = aSlave->parameters(); - //aSlave->setParameters(aMaster->parameters()); + std::shared_ptr anEntity = + std::dynamic_pointer_cast(aRelated); + std::shared_ptr anArc = std::dynamic_pointer_cast(anEntity->entity()); - //// Remove slave's parameters - //std::list::iterator aParIt = aSlaveParams.begin(); - //for (; aParIt != aSlaveParams.end(); ++aParIt) - // remove(*aParIt); + static std::shared_ptr OX(new GeomAPI_Dir2d(1.0, 0.0)); + std::shared_ptr aCenter( + new GeomAPI_Pnt2d(*anArc->center.x, *anArc->center.y)); + std::shared_ptr aStart( + new GeomAPI_Pnt2d(*anArc->start.x, *anArc->start.y)); - aMasterFound->second.insert(aSlave); - } -} + *anArc->rad = aStart->distance(aCenter); + std::shared_ptr aDir(new GeomAPI_Dir2d(aStart->xy()->decreased(aCenter->xy()))); + *anArc->startAngle = OX->angle(aDir); -void PlaneGCSSolver_Storage::changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup) -{ - theEntity->setGroup(theGroup); - if (theGroup == myGroupID) - makeVariable(theEntity); - else { - if (theEntity->type() == ENTITY_POINT) - update(theEntity); - makeConstant(theEntity); + aDir = std::shared_ptr( + new GeomAPI_Dir2d((*anArc->end.x) - aCenter->x(), (*anArc->end.y) - aCenter->y())); + *anArc->endAngle = OX->angle(aDir); } -} -void PlaneGCSSolver_Storage::changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup) -{ - // TODO + return isUpdated; } -void PlaneGCSSolver_Storage::verifyFixed() +bool PlaneGCSSolver_Storage::update(AttributePtr theAttribute, bool theForce) { - // TODO -} + if (!theAttribute->isInitialized()) + return false; -void PlaneGCSSolver_Storage::processArc(const EntityWrapperPtr& theArc) -{ - // Calculate additional parameters necessary for PlaneGCS - const std::list& aSubs = theArc->subEntities(); - std::list::const_iterator aSubIt = aSubs.begin(); - bool isFixed[3] = {false, false, false}; - for (int i = 0; (*aSubIt)->type() == ENTITY_POINT; ++i) { // search scalar entities - isFixed[i] = (*aSubIt)->group() == GID_OUTOFGROUP; - ++aSubIt; + AttributePtr anAttribute = theAttribute; + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(anAttribute); + if (aRefAttr) { + if (aRefAttr->isObject()) { + FeaturePtr aFeature; + /// TODO: Check resultToFeatureOrAttribute() precisely. + resultToFeatureOrAttribute(aRefAttr->object(), aFeature, anAttribute); + if (aFeature) + return update(aFeature, theForce); + } else + anAttribute = aRefAttr->attr(); } - double* aStartAngle = - std::dynamic_pointer_cast(*aSubIt++)->scalar(); - double* aEndAngle = - std::dynamic_pointer_cast(*aSubIt++)->scalar(); - double* aRadius = std::dynamic_pointer_cast(*aSubIt)->scalar(); - - std::shared_ptr anArcFeature = - std::dynamic_pointer_cast(theArc->baseFeature()); - std::shared_ptr aCenterAttr = std::dynamic_pointer_cast( - anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID())); - std::shared_ptr aStartAttr = std::dynamic_pointer_cast( - anArcFeature->attribute(SketchPlugin_Arc::START_ID())); - std::shared_ptr aEndAttr = std::dynamic_pointer_cast( - anArcFeature->attribute(SketchPlugin_Arc::END_ID())); - if (!aCenterAttr || !aStartAttr || !aEndAttr) - return; - std::shared_ptr aCenterPnt = aCenterAttr->pnt(); - std::shared_ptr aStartPnt = aStartAttr->pnt(); - std::shared_ptr aEndPnt = aEndAttr->pnt(); - - if (isFixed[2] && !isFixed[1]) - *aRadius = aCenterPnt->distance(aEndPnt); - else - *aRadius = aCenterPnt->distance(aStartPnt); - if (!anArcFeature->lastResult()) - return; - static std::shared_ptr OX(new GeomAPI_Dir2d(1.0, 0.0)); - std::shared_ptr aDir(new GeomAPI_Dir2d( - aStartPnt->xy()->decreased(aCenterPnt->xy()))); - *aStartAngle = OX->angle(aDir); - aDir = std::shared_ptr(new GeomAPI_Dir2d( - aEndPnt->xy()->decreased(aCenterPnt->xy()))); - *aEndAngle = OX->angle(aDir); - - // no need to constraint a fixed or a copied arc - if (theArc->group() == GID_OUTOFGROUP || anArcFeature->isCopy()) - return; - // No need to add constraints if they are already exist - std::map >::const_iterator - aFound = myArcConstraintMap.find(theArc); -// if (aFound != myArcConstraintMap.end()) -// return; - - // Prepare additional constraints to produce the arc - std::vector anArcConstraints; - std::shared_ptr anArcEnt = - std::dynamic_pointer_cast(theArc); - std::shared_ptr anArc = std::dynamic_pointer_cast(anArcEnt->entity()); - // Distances from center till start and end points are equal to radius - GCSConstraintPtr aNew = GCSConstraintPtr(new GCS::ConstraintP2PDistance( - anArc->center, anArc->start, anArc->rad)); -// aNew->setTag((int)(++myConstraintLastID)); - anArcConstraints.push_back(aNew); - aNew = GCSConstraintPtr(new GCS::ConstraintP2PDistance( - anArc->center, anArc->end, anArc->rad)); -// aNew->setTag((int)myConstraintLastID); - anArcConstraints.push_back(aNew); - // Angles of start and end points should be equal to given angles - aNew = GCSConstraintPtr(new GCS::ConstraintP2PAngle( - anArc->center, anArc->start, anArc->startAngle)); -// aNew->setTag((int)myConstraintLastID); - anArcConstraints.push_back(aNew); - aNew = GCSConstraintPtr(new GCS::ConstraintP2PAngle( - anArc->center, anArc->end, anArc->endAngle)); -// aNew->setTag((int)myConstraintLastID); - anArcConstraints.push_back(aNew); - - myArcConstraintMap[theArc] = anArcConstraints; -} + EntityWrapperPtr aRelated = entity(anAttribute); + if (!aRelated) { // Attribute does not exist, create it. + // First of all check if the parent feature exists. If not, add it. + FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner()); + if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end()) + return update(aFeature, theForce); // theAttribute has been processed while adding feature -void PlaneGCSSolver_Storage::makeConstant(const EntityWrapperPtr& theEntity) -{ - toggleEntity(theEntity, myParameters, myConst); - if (theEntity->type() == ENTITY_POINT) - updateCoincident(theEntity); + PlaneGCSSolver_AttributeBuilder aBuilder(this); + aRelated = createAttribute(anAttribute, &aBuilder); + return aRelated.get() != 0; + } + + bool isUpdated = updateValues(anAttribute, aRelated); + if (isUpdated) + setNeedToResolve(true); + return isUpdated; } -void PlaneGCSSolver_Storage::makeVariable(const EntityWrapperPtr& theEntity) + + +bool PlaneGCSSolver_Storage::removeConstraint(ConstraintPtr theConstraint) { - toggleEntity(theEntity, myConst, myParameters); + std::map::iterator + aFound = myConstraintMap.find(theConstraint); + if (aFound != myConstraintMap.end()) { + ConstraintID anID = aFound->second->id(); + // Remove solver's constraints + std::shared_ptr aSolver = + std::dynamic_pointer_cast(mySketchSolver); + aSolver->removeConstraint(anID); + // Remove constraint + myConstraintMap.erase(aFound); + + // notify subscibers + notify(theConstraint); + } + return true; } -static void getParametersToMove(const EntityWrapperPtr& theEntity, std::set& theParamList) +void PlaneGCSSolver_Storage::removeInvalidEntities() { - const std::list aParams = theEntity->parameters(); - std::list::const_iterator aPIt = aParams.begin(); - for (; aPIt != aParams.end(); ++aPIt) - theParamList.insert( - std::dynamic_pointer_cast(*aPIt)->parameter()); - - const std::list aSubs = theEntity->subEntities(); - std::list::const_iterator aSIt = aSubs.begin(); - - if (theEntity->type() == ENTITY_ARC) { - // workaround for the arc processing, because the arc is fixed by a set of constraints, - // which will conflict with all parameters fixed: - // 1. take center - getParametersToMove(*aSIt++, theParamList); - // 2. skip start and end points - ++aSIt; - // 3. take radius, start angle and end angle parameters - getParametersToMove(*(++aSIt), theParamList); - getParametersToMove(*(++aSIt), theParamList); - getParametersToMove(*(++aSIt), theParamList); - } else { - for (; aSIt != aSubs.end(); ++aSIt) - getParametersToMove(*aSIt, theParamList); + PlaneGCSSolver_EntityDestroyer aDestroyer; + + // Remove invalid constraints + std::list anInvalidConstraints; + std::map::const_iterator + aCIter = myConstraintMap.begin(); + for (; aCIter != myConstraintMap.end(); ++aCIter) + if (!aCIter->first->data() || !aCIter->first->data()->isValid()) + anInvalidConstraints.push_back(aCIter->first); + std::list::const_iterator anInvCIt = anInvalidConstraints.begin(); + for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt) + removeConstraint(*anInvCIt); + + // Remove invalid features + std::list anInvalidFeatures; + std::map::const_iterator aFIter = myFeatureMap.begin(); + for (; aFIter != myFeatureMap.end(); aFIter++) + if (!aFIter->first->data() || !aFIter->first->data()->isValid()) { + anInvalidFeatures.push_back(aFIter->first); + aDestroyer.remove(aFIter->second); + + // remove invalid arc + std::map::iterator + aFound = myArcConstraintMap.find(aFIter->second); + if (aFound != myArcConstraintMap.end()) { + std::dynamic_pointer_cast( + mySketchSolver)->removeConstraint(aFound->second->id()); + myArcConstraintMap.erase(aFound); + } + } + std::list::const_iterator anInvFIt = anInvalidFeatures.begin(); + for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt) + removeFeature(*anInvFIt); + + // Remove invalid attributes + std::list anInvalidAttributes; + std::map::const_iterator anAttrIt = myAttributeMap.begin(); + for (; anAttrIt != myAttributeMap.end(); ++anAttrIt) { + FeaturePtr anOwner = ModelAPI_Feature::feature(anAttrIt->first->owner()); + if (!anOwner || !anOwner->data() || !anOwner->data()->isValid()) { + anInvalidAttributes.push_back(anAttrIt->first); + aDestroyer.remove(anAttrIt->second); + } } + std::list::const_iterator anInvAtIt = anInvalidAttributes.begin(); + for (; anInvAtIt != anInvalidAttributes.end(); ++anInvAtIt) + removeAttribute(*anInvAtIt); + + // free memory occupied by parameters + removeParameters(aDestroyer.parametersToRemove()); + + /// TODO: Think on optimization of checking invalid features and attributes } -void PlaneGCSSolver_Storage::toggleEntity( - const EntityWrapperPtr& theEntity, GCS::VEC_pD& theFrom, GCS::VEC_pD& theTo) -{ - std::set aParamsToMove; - getParametersToMove(theEntity, aParamsToMove); - GCS::VEC_pD::iterator anIt = theFrom.begin(); - while (anIt != theFrom.end()) { - if (aParamsToMove.find(*anIt) == aParamsToMove.end()) { - ++anIt; - continue; - } - theTo.push_back(*anIt); - int aShift = int(anIt - theFrom.begin()); - theFrom.erase(anIt); - anIt = theFrom.begin() + aShift; - } +double* PlaneGCSSolver_Storage::createParameter() +{ + double* aResult = new double(0); + myParameters.push_back(aResult); + return aResult; } -void PlaneGCSSolver_Storage::updateCoincident(const EntityWrapperPtr& thePoint) +void PlaneGCSSolver_Storage::removeParameters(const GCS::SET_pD& theParams) { - CoincidentPointsMap::iterator anIt = myCoincidentPoints.begin(); - for (; anIt != myCoincidentPoints.end(); ++anIt) { - if (anIt->first == thePoint || anIt->second.find(thePoint) != anIt->second.end()) { - std::set aCoincident = anIt->second; - aCoincident.insert(anIt->first); - - const std::list& aBaseParams = thePoint->parameters(); - std::list aParams; - std::list::const_iterator aBaseIt, anUpdIt; - - std::set::const_iterator aCoincIt = aCoincident.begin(); - for (; aCoincIt != aCoincident.end(); ++aCoincIt) - if (*aCoincIt != thePoint && (*aCoincIt)->group() != GID_OUTOFGROUP) { - aParams = (*aCoincIt)->parameters(); - aBaseIt = aBaseParams.begin(); - for (anUpdIt = aParams.begin(); anUpdIt != aParams.end(); ++anUpdIt, ++aBaseIt) - (*anUpdIt)->setValue((*aBaseIt)->value()); - } - - break; - } - } + for (int i = (int)myParameters.size() - 1; i >= 0; --i) + if (theParams.find(myParameters[i]) != theParams.end()) + myParameters.erase(myParameters.begin() + i); } @@ -605,54 +404,12 @@ bool PlaneGCSSolver_Storage::isRedundant( return false; } -void PlaneGCSSolver_Storage::initializeSolver(SolverPtr theSolver) +void PlaneGCSSolver_Storage::initializeSolver() { std::shared_ptr aSolver = - std::dynamic_pointer_cast(theSolver); - if (!aSolver) - return; - aSolver->clear(); - - if (myExistArc) - processArcs(); - - // initialize constraints - 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) { - std::shared_ptr aGCS = - std::dynamic_pointer_cast(*aCWIt); - std::list::const_iterator anIt = aGCS->constraints().begin(); - for (; anIt != aGCS->constraints().end(); ++anIt) - if (!isRedundant(*anIt, aGCS, aCoincidentPoints)) - aSolver->addConstraint(*anIt, aGCS->type()); - } - // store IDs of tangent constraints to avoid incorrect report of redundant constraints - if (aCIt->first && aCIt->first->getKind() == SketchPlugin_ConstraintTangent::ID()) - for (aCWIt = aCIt->second.begin(); aCWIt != aCIt->second.end(); ++ aCWIt) - aTangentIDs.insert((int)(*aCWIt)->id()); - } - // additional constraints for arcs - std::map >::const_iterator - anArcIt = myArcConstraintMap.begin(); - for (; anArcIt != myArcConstraintMap.end(); ++anArcIt) { - std::vector::const_iterator anIt = anArcIt->second.begin(); - for (; anIt != anArcIt->second.end(); ++anIt) - aSolver->addConstraint(*anIt, CONSTRAINT_UNKNOWN); - } - // removed waste constraints - std::list::const_iterator aRemIt = myRemovedConstraints.begin(); - for (; aRemIt != myRemovedConstraints.end(); ++aRemIt) - aSolver->removeConstraint(*aRemIt); - myRemovedConstraints.clear(); - // set list of tangent constraints - aSolver->setTangent(aTangentIDs); - // initialize unknowns - aSolver->setParameters(myParameters); + std::dynamic_pointer_cast(mySketchSolver); + if (aSolver) + aSolver->setParameters(myParameters); } // indicates attribute containing in the external feature @@ -665,157 +422,35 @@ bool isExternalAttribute(const AttributePtr& theAttribute) return aSketchFeature.get() && aSketchFeature->isExternal(); } -void PlaneGCSSolver_Storage::refresh(bool theFixedOnly) const +void PlaneGCSSolver_Storage::refresh() const { - //blockEvents(true); - const double aTol = 1000. * tolerance; // tolerance to prevent frequent updates std::map::const_iterator anIt = myAttributeMap.begin(); - std::list aParams; - std::list::const_iterator aParIt; for (; anIt != myAttributeMap.end(); ++anIt) { // the external feature always should keep the up to date values, so, // refresh from the solver is never needed - bool isExternal = isExternalAttribute(anIt->first); - - // update parameter wrappers and obtain values of attributes - aParams = anIt->second->parameters(); - double aCoords[3]; - bool isUpd[3] = {false}; - int i = 0; - for (aParIt = aParams.begin(); i < 3 && aParIt != aParams.end(); ++aParIt, ++i) { - if (!theFixedOnly || isExternal || - (*aParIt)->group() == GID_OUTOFGROUP || (*aParIt)->isParametric()) { - aCoords[i] = (*aParIt)->value(); - isUpd[i] = true; - } - } - if (!isUpd[0] && !isUpd[1] && !isUpd[2]) - continue; // nothing is updated + if (isExternalAttribute(anIt->first)) + continue; std::shared_ptr aPoint2D = std::dynamic_pointer_cast(anIt->first); if (aPoint2D) { - if ((isUpd[0] && fabs(aPoint2D->x() - aCoords[0]) > aTol) || - (isUpd[1] && fabs(aPoint2D->y() - aCoords[1]) > aTol) || isExternal) { - // Find points coincident with this one (probably not in GID_OUTOFGROUP) - CoincidentPointsMap::const_iterator aCoincIt = myCoincidentPoints.begin(); - for (; aCoincIt != myCoincidentPoints.end(); ++aCoincIt) - if (aCoincIt->first == anIt->second || - aCoincIt->second.find(anIt->second) != aCoincIt->second.end()) - break; - // get coordinates of "master"-point - std::shared_ptr aMaster = aCoincIt != myCoincidentPoints.end() ? - std::dynamic_pointer_cast(aCoincIt->first->baseAttribute()) : - aPoint2D; - if (!isUpd[0] || isExternal) aCoords[0] = aMaster->x(); - if (!isUpd[1] || isExternal) aCoords[1] = aMaster->y(); - if (!isExternal) - aPoint2D->setValue(aCoords[0], aCoords[1]); - if (aCoincIt != myCoincidentPoints.end()) { - if (aMaster && !isExternalAttribute(aMaster)) - aMaster->setValue(aCoords[0], aCoords[1]); - std::set::const_iterator aSlaveIt = aCoincIt->second.begin(); - for (; aSlaveIt != aCoincIt->second.end(); ++aSlaveIt) { - aPoint2D = std::dynamic_pointer_cast((*aSlaveIt)->baseAttribute()); - if (aPoint2D && !isExternalAttribute(aPoint2D)) - aPoint2D->setValue(aCoords[0], aCoords[1]); - } - } - } + std::shared_ptr aPointWrapper = + std::dynamic_pointer_cast(anIt->second); + GCSPointPtr aGCSPoint = aPointWrapper->point(); + if (fabs(aPoint2D->x() - (*aGCSPoint->x)) > aTol || + fabs(aPoint2D->y() - (*aGCSPoint->y)) > aTol) + aPoint2D->setValue(*aGCSPoint->x, *aGCSPoint->y); continue; } AttributeDoublePtr aScalar = std::dynamic_pointer_cast(anIt->first); - if (aScalar && !isExternal) { - if (isUpd[0] && fabs(aScalar->value() - aCoords[0]) > aTol) - aScalar->setValue(aCoords[0]); + if (aScalar) { + ScalarWrapperPtr aScalarWrapper = + std::dynamic_pointer_cast(anIt->second); + if (fabs(aScalar->value() - aScalarWrapper->value()) > aTol) + aScalar->setValue(aScalarWrapper->value()); continue; } } - - //blockEvents(false); -} - -EntityWrapperPtr PlaneGCSSolver_Storage::calculateMiddlePoint( - EntityWrapperPtr theBase, double theCoeff) -{ - std::shared_ptr aBuilder = - std::dynamic_pointer_cast(PlaneGCSSolver_Builder::getInstance()); - - std::shared_ptr aMidPoint; - if (theBase->type() == ENTITY_LINE) { - std::shared_ptr aPoints[2]; - const std::list& aSubs = theBase->subEntities(); - std::list::const_iterator anIt = aSubs.begin(); - for (int i = 0; i < 2; ++i, ++anIt) - aPoints[i] = aBuilder->point(*anIt); - aMidPoint = aPoints[0]->xy()->multiplied(1.0 - theCoeff)->added( - aPoints[1]->xy()->multiplied(theCoeff)); - } - else if (theBase->type() == ENTITY_ARC) { - double theX, theY; - double anArcPoint[3][2]; - const std::list& aSubs = theBase->subEntities(); - std::list::const_iterator anIt = aSubs.begin(); - for (int i = 0; i < 3; ++i, ++anIt) { - std::shared_ptr aPoint = aBuilder->point(*anIt); - anArcPoint[i][0] = aPoint->x(); - anArcPoint[i][1] = aPoint->y(); - } - // project last point of arc on the arc - double x = anArcPoint[1][0] - anArcPoint[0][0]; - double y = anArcPoint[1][1] - anArcPoint[0][1]; - double aRad = sqrt(x*x + y*y); - x = anArcPoint[2][0] - anArcPoint[0][0]; - y = anArcPoint[2][1] - anArcPoint[0][1]; - double aNorm = sqrt(x*x + y*y); - if (aNorm >= tolerance) { - anArcPoint[2][0] = x * aRad / aNorm; - anArcPoint[2][1] = y * aRad / aNorm; - } - anArcPoint[1][0] -= anArcPoint[0][0]; - anArcPoint[1][1] -= anArcPoint[0][1]; - if (theCoeff < tolerance) { - theX = anArcPoint[0][0] + anArcPoint[1][0]; - theY = anArcPoint[0][1] + anArcPoint[1][1]; - } else if (1 - theCoeff < tolerance) { - theX = anArcPoint[0][0] + anArcPoint[2][0]; - theY = anArcPoint[0][1] + anArcPoint[2][1]; - } else { - std::shared_ptr - aStartDir(new GeomAPI_Dir2d(anArcPoint[1][0], anArcPoint[1][1])); - std::shared_ptr - aEndDir(new GeomAPI_Dir2d(anArcPoint[2][0], anArcPoint[2][1])); - double anAngle = aStartDir->angle(aEndDir); - if (anAngle < 0) - anAngle += 2.0 * PI; - anAngle *= theCoeff; - double aCos = cos(anAngle); - double aSin = sin(anAngle); - theX = anArcPoint[0][0] + anArcPoint[1][0] * aCos - anArcPoint[1][1] * aSin; - theY = anArcPoint[0][1] + anArcPoint[1][0] * aSin + anArcPoint[1][1] * aCos; - } - aMidPoint = std::shared_ptr(new GeomAPI_XY(theX, theY)); - } - - if (!aMidPoint) - return EntityWrapperPtr(); - - std::list aParameters; - aParameters.push_back(aBuilder->createParameter(myGroupID, aMidPoint->x())); - aParameters.push_back(aBuilder->createParameter(myGroupID, aMidPoint->y())); - // Create entity (parameters are not filled) - GCSPointPtr aPnt(new GCS::Point); - aPnt->x = - std::dynamic_pointer_cast(aParameters.front())->parameter(); - aPnt->y = - std::dynamic_pointer_cast(aParameters.back())->parameter(); - - EntityWrapperPtr aResult(new PlaneGCSSolver_PointWrapper(AttributePtr(), aPnt)); - aResult->setGroup(myGroupID); - aResult->setParameters(aParameters); - - update(aResult); - return aResult; } diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h index ccf318aef..4af3f4e19 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h @@ -13,6 +13,8 @@ #include #include +class PlaneGCSSolver_EntityBuilder; + /** \class PlaneGCSSolver_Storage * \ingroup Plugins * \brief Contains all necessary data in PlaneGCS format to solve a single group of constraints @@ -20,89 +22,55 @@ class PlaneGCSSolver_Storage : public SketchSolver_Storage { public: - PlaneGCSSolver_Storage(const GroupID& theGroup); + PlaneGCSSolver_Storage(const SolverPtr& theSolver); // ============= Inherited from SketchSolver_Storage ============= /// \brief Change mapping between constraint from SketchPlugin and - /// the list of constraints applicable for corresponding solver. - /// Derived here to update point-point coincidence. - /// \param theConstraint [in] original SketchPlugin constraint - /// \param theSolverConstraints [in] list of solver's constraints - virtual void addConstraint(ConstraintPtr theConstraint, - std::list theSolverConstraints); - - /// \brief Update constraint's data - /// \return \c true if any value is updated - virtual bool update(ConstraintWrapperPtr theConstraint); - /// \brief Update entity's data - /// \return \c true if any value is updated - virtual bool update(EntityWrapperPtr theEntity); - /// \brief Update parameter's data - /// \return \c true if the value of parameter is updated - virtual bool update(ParameterWrapperPtr theParameter); - - /// \brief Update SketchPlugin features after resolving constraints - /// \param theFixedOnly [in] if \c true the fixed points will be updated only - virtual void refresh(bool theFixedOnly = false) const; + /// a constraint applicable for corresponding solver. + /// \param theConstraint [in] original SketchPlugin constraint + /// \param theSolverConstraint [in] solver's constraint + virtual void addConstraint(ConstraintPtr theConstraint, + ConstraintWrapperPtr theSolverConstraint) override; - /// \brief Check if some parameters or entities are returned - /// to the current group after removing temporary constraints - virtual void verifyFixed(); + /// \brief Add list of temporary constraints which will be destroyed + /// after the next solving of the set of constraints. + /// \param theSolverConstraint [in] solver's constraint + virtual void addTemporaryConstraint(const ConstraintWrapperPtr& theSolverConstraint) override; - /// \brief Mark two points as coincident - virtual void addCoincidentPoints(EntityWrapperPtr theMaster, EntityWrapperPtr theSlave); - /// \brief Shows the storage has the same constraint twice - virtual bool hasDuplicatedConstraint() const - { return false; } + /// \brief Convert feature to the form applicable for specific solver and map it + /// \param theFeature [in] feature to convert + /// \param theForce [in] forced feature creation + /// \return \c true if the feature has been created or updated + virtual bool update(FeaturePtr theFeature, bool theForce = false) override; - /// \brief Calculate point on theBase entity. Value theCoeff is in [0.0 .. 1.0] and - /// shows the distance from the start point. - virtual EntityWrapperPtr calculateMiddlePoint(EntityWrapperPtr theBase, double theCoeff); + /// \brief Convert attribute to the form applicable for specific solver and map it + /// \param theAttribute [in] attribute to convert + /// \param theForce [in] forced feature creation + /// \return \c true if the attribute has been created or updated + virtual bool update(AttributePtr theAttribute, bool theForce = false) override; - /// \brief Initialize solver by constraints, entities and parameters - virtual void initializeSolver(SolverPtr theSolver); -protected: - /// \brief Remove constraint + /// \brief Removes constraint from the storage /// \return \c true if the constraint and all its parameters are removed successfully - virtual bool remove(ConstraintWrapperPtr theConstraint); - /// \brief Remove entity - /// \return \c true if the entity and all its parameters are removed successfully - virtual bool remove(EntityWrapperPtr theEntity); - /// \brief Remove parameter - /// \return \c true if the parameter has been removed - virtual bool remove(ParameterWrapperPtr theParameter); + virtual bool removeConstraint(ConstraintPtr theConstraint) override; - /// \brief Update the group for the given entity, its sub-entities and parameters - virtual void changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup); - /// \brief Update the group for the given parameter - virtual void changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup); + /// \brief Update SketchPlugin features after resolving constraints + virtual void refresh() const override; + /// \brief Initialize solver by constraints, entities and parameters + virtual void initializeSolver(); -// ============= Own methods ============= + /// \brief Initialize memory for new solver's parameter + double* createParameter(); + /// \brief Release memory occupied by parameters + void removeParameters(const GCS::SET_pD& theParams); - /// \brief Move parameters of the entity to the constants - void makeConstant(const EntityWrapperPtr& theEntity); - /// \brief Move parameters of the entity to the variables - void makeVariable(const EntityWrapperPtr& theEntity); + /// \brief Remove all features became invalid + virtual void removeInvalidEntities() override; private: - /// \brief Move parameters of the entity from the list of variables to the list of constants - /// and vice versa - /// \param theEntity [in] entity to be changed - /// \param theFrom [out] source list - /// \param theTo [out] destination list - void toggleEntity(const EntityWrapperPtr& theEntity, GCS::VEC_pD& theFrom, GCS::VEC_pD& theTo); - - /// \brief Create additional constraints for correct processing of arcs - /// \param theArc [in] updated arc - void processArc(const EntityWrapperPtr& theArc); - - /// \brief Adjust parameters of points coincident with the given - void updateCoincident(const EntityWrapperPtr& thePoint); - /// \brief Verifies the constraint should not be added into the solver /// /// This is a workaround method to avoid some kinds of conflicting constraints: @@ -111,18 +79,23 @@ private: ConstraintWrapperPtr theParentConstraint, std::list >& theCoincidentPoints) const; + /// \brief Convert feature using specified builder. + EntityWrapperPtr createFeature(const FeaturePtr& theFeature, + PlaneGCSSolver_EntityBuilder* theBuilder); + + /// \brief Convert attribute using specified builder. + EntityWrapperPtr createAttribute(const AttributePtr& theAttribute, + PlaneGCSSolver_EntityBuilder* theBuilder); + private: - GCS::VEC_pD myParameters; ///< list of parameters - GCS::VEC_pD myConst; ///< list of constants - EntityID myEntityLastID; ///< identifier of last added entity - ConstraintID myConstraintLastID; ///< identifier of last added constraint + GCS::VEC_pD myParameters; ///< list of parameters + ConstraintID myConstraintLastID; ///< identifier of last added constraint /// additional constraints for correct processing of the arcs - std::map > - myArcConstraintMap; + std::map myArcConstraintMap; /// list of removed constraints to notify solver - std::list myRemovedConstraints; + std::list myRemovedConstraints; }; #endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Update.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Update.h new file mode 100644 index 000000000..2f1fddb00 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Update.h @@ -0,0 +1,60 @@ +// Copyright (C) 2017-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_Update.h +// Created: 17 Feb 2017 +// Author: Artem ZHIDKOV + +#ifndef PlaneGCSSolver_Update_H_ +#define PlaneGCSSolver_Update_H_ + +#include + +#include +#include +#include + +class SketchSolver_Constraint; +class PlaneGCSSolver_Update; +typedef std::shared_ptr UpdaterPtr; + +/** \class PlaneGCSSolver_Update + * \ingroup Plugins + * \brief Send events to listeners about changing a feature + */ +class PlaneGCSSolver_Update +{ +public: + PlaneGCSSolver_Update(UpdaterPtr theNext = UpdaterPtr()) + : myNext(theNext) + {} + + virtual ~PlaneGCSSolver_Update() {} + + /// \brief Attach listener + /// \param theObserver [in] object which want to receive notifications + /// \param theType [in] receive notifications about changing objects + /// of theType and their derivatives + virtual void attach(SketchSolver_Constraint* theObserver, const std::string& theType) = 0; + + /// \brief Detach listener + void detach(SketchSolver_Constraint* theObserver) { + std::list::iterator anIt = myObservers.begin(); + for (; anIt != myObservers.end(); ++anIt) + if (*anIt == theObserver) { + myObservers.erase(anIt); + break; + } + // detach listener from all senders + if (myNext) + myNext->detach(theObserver); + } + + /// \brief Send notification about update of the feature to all interested + virtual void update(const FeaturePtr& theFeature) = 0; + +protected: + UpdaterPtr myNext; ///< next updater, access if current one unable to process request + std::list myObservers; ///< list of observers +}; + +#endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_UpdateCoincidence.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_UpdateCoincidence.cpp new file mode 100644 index 000000000..205195253 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_UpdateCoincidence.cpp @@ -0,0 +1,77 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_UpdateCoincidence.cpp +// Created: 17 Feb 2017 +// Author: Artem ZHIDKOV + +#include +#include + +#include +#include + +void PlaneGCSSolver_UpdateCoincidence::attach(SketchSolver_Constraint* theObserver, const std::string& theType) +{ + if (theType == GROUP()) { + std::list::iterator aPlaceToAdd = myObservers.end(); + // point-point coincidence is placed first + if (theObserver->getType() == CONSTRAINT_PT_PT_COINCIDENT) { + for (aPlaceToAdd = myObservers.begin(); aPlaceToAdd != myObservers.end(); ++aPlaceToAdd) + if ((*aPlaceToAdd)->getType() != CONSTRAINT_PT_PT_COINCIDENT) + break; + } + myObservers.insert(aPlaceToAdd, theObserver); + } else + myNext->attach(theObserver, theType); +} + +void PlaneGCSSolver_UpdateCoincidence::update(const FeaturePtr& theFeature) +{ + if (theFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID() || + theFeature->getKind() == SketchPlugin_ConstraintMiddle::ID()) { + myCoincident.clear(); + // notify listeners and stop procesing + std::list::iterator anIt = myObservers.begin(); + for (; anIt != myObservers.end(); ++anIt) + (*anIt)->notify(theFeature, this); + } else + myNext->update(theFeature); +} + +bool PlaneGCSSolver_UpdateCoincidence::checkCoincidence( + const EntityWrapperPtr& theEntity1, + const EntityWrapperPtr& theEntity2) +{ + bool isAccepted = true; + + std::list >::iterator anIt = myCoincident.begin(); + std::list >::iterator aFound1 = myCoincident.end(); + std::list >::iterator aFound2 = myCoincident.end(); + for (; anIt != myCoincident.end(); ++anIt) { + if (aFound1 == myCoincident.end() && anIt->find(theEntity1) != anIt->end()) + aFound1 = anIt; + if (aFound2 == myCoincident.end() && anIt->find(theEntity2) != anIt->end()) + aFound2 = anIt; + if (aFound1 != myCoincident.end() && aFound2 != myCoincident.end()) + break; + } + + if (aFound1 == myCoincident.end() && aFound2 == myCoincident.end()) { + // new group of coincidence + std::set aNewCoinc; + aNewCoinc.insert(theEntity1); + aNewCoinc.insert(theEntity2); + myCoincident.push_back(aNewCoinc); + } else if (aFound1 == aFound2) // same group => already coincident + isAccepted = false; + else if (aFound1 == myCoincident.end()) + aFound2->insert(theEntity1); + else if (aFound2 == myCoincident.end()) + aFound1->insert(theEntity2); + else { // merge two groups + aFound1->insert(aFound2->begin(), aFound2->end()); + myCoincident.erase(aFound2); + } + + return isAccepted; +} diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_UpdateCoincidence.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_UpdateCoincidence.h new file mode 100644 index 000000000..d6320f65e --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_UpdateCoincidence.h @@ -0,0 +1,50 @@ +// Copyright (C) 2017-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_UpdateCoincidence.h +// Created: 17 Feb 2017 +// Author: Artem ZHIDKOV + +#ifndef PlaneGCSSolver_UpdateCoincidence_H_ +#define PlaneGCSSolver_UpdateCoincidence_H_ + +#include +#include + +/** \class PlaneGCSSolver_UpdateCoincidence + * \ingroup Plugins + * \brief Send events to listeners about changing a constraint + */ +class PlaneGCSSolver_UpdateCoincidence : public PlaneGCSSolver_Update +{ +public: + PlaneGCSSolver_UpdateCoincidence(UpdaterPtr theNext = UpdaterPtr()) + : PlaneGCSSolver_Update(theNext) + {} + + virtual ~PlaneGCSSolver_UpdateCoincidence() {} + + /// \brief Group of entities, processed by this kind of updater + static const std::string& GROUP() + { + static const std::string TYPE("Coincidence"); + return TYPE; + } + + /// \brief Attach listener + /// \param theObserver [in] object which want to receive notifications + /// \param theType [in] receive notifications about changing objects + /// of theType and their derivatives + virtual void attach(SketchSolver_Constraint* theObserver, const std::string& theType) override; + + /// \brief Send notification about update of the feature to all interested + virtual void update(const FeaturePtr& theFeature) override; + + /// \brief Verifies the entities are not coincident yet + /// \return \c true if the entities does not coincident + bool checkCoincidence(const EntityWrapperPtr& theEntity1, const EntityWrapperPtr& theEntity2); + +private: + std::list > myCoincident; ///< list of coincidences +}; + +#endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_UpdateFeature.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_UpdateFeature.cpp new file mode 100644 index 000000000..5ff77f8f3 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_UpdateFeature.cpp @@ -0,0 +1,23 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_UpdateFeature.cpp +// Created: 17 Feb 2017 +// Author: Artem ZHIDKOV + +#include +#include + +void PlaneGCSSolver_UpdateFeature::attach(SketchSolver_Constraint* theObserver, const std::string& theType) +{ + if (theType == GROUP()) + myObservers.push_back(theObserver); + else + myNext->attach(theObserver, theType); +} + +void PlaneGCSSolver_UpdateFeature::update(const FeaturePtr& theFeature) +{ + std::list::iterator anIt = myObservers.begin(); + for (; anIt != myObservers.end(); ++anIt) + (*anIt)->notify(theFeature, this); +} diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_UpdateFeature.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_UpdateFeature.h new file mode 100644 index 000000000..9da1a6eea --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_UpdateFeature.h @@ -0,0 +1,40 @@ +// Copyright (C) 2017-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_UpdateFeature.h +// Created: 17 Feb 2017 +// Author: Artem ZHIDKOV + +#ifndef PlaneGCSSolver_UpdateFeature_H_ +#define PlaneGCSSolver_UpdateFeature_H_ + +#include + +/** \class PlaneGCSSolver_UpdateFeature + * \ingroup Plugins + * \brief Send events to listeners about changing a feature + */ +class PlaneGCSSolver_UpdateFeature : public PlaneGCSSolver_Update +{ +public: + PlaneGCSSolver_UpdateFeature(UpdaterPtr theNext = UpdaterPtr()) + : PlaneGCSSolver_Update(theNext) + {} + + /// \brief Group of entities, processed by this kind of updater + static const std::string& GROUP() + { + static const std::string TYPE("Feature"); + return TYPE; + } + + /// \brief Attach listener + /// \param theObserver [in] object which want to receive notifications + /// \param theType [in] receive notifications about changing objects + /// of theType and their derivatives + virtual void attach(SketchSolver_Constraint* theObserver, const std::string& theType) override; + + /// \brief Send notification about update of the feature to all interested + virtual void update(const FeaturePtr& theFeature) override; +}; + +#endif diff --git a/src/SketchSolver/SketchSolver.h b/src/SketchSolver/SketchSolver.h index 8beb83a98..775702389 100644 --- a/src/SketchSolver/SketchSolver.h +++ b/src/SketchSolver/SketchSolver.h @@ -5,38 +5,16 @@ #include -#if defined SKETCHSOLVER_EXPORTS -#if defined WIN32 -#define SKETCHSOLVER_EXPORT __declspec( dllexport ) -#else -#define SKETCHSOLVER_EXPORT -#endif -#else -#if defined WIN32 -#define SKETCHSOLVER_EXPORT __declspec( dllimport ) -#else -#define SKETCHSOLVER_EXPORT -#endif -#endif - /// Tolerance for value of parameters const double tolerance = 1.e-10; #define PI 3.1415926535897932 // Types for data entities enumeration -typedef size_t GroupID; -typedef size_t ParameterID; -typedef size_t EntityID; -typedef size_t ConstraintID; +typedef int ConstraintID; // Predefined values for identifiers -const GroupID GID_UNKNOWN = 0; -const GroupID GID_OUTOFGROUP = 1; - -const ParameterID PID_UNKNOWN = 0; -const EntityID EID_UNKNOWN = 0; -const EntityID EID_SKETCH = 1; -const ConstraintID CID_UNKNOWN = 0; +const ConstraintID CID_UNKNOWN = 0; +const ConstraintID CID_MOVEMENT = -1; #endif diff --git a/src/SketchSolver/SketchSolver_Builder.cpp b/src/SketchSolver/SketchSolver_Builder.cpp index 718ea18ca..d5bf71dc9 100644 --- a/src/SketchSolver/SketchSolver_Builder.cpp +++ b/src/SketchSolver/SketchSolver_Builder.cpp @@ -12,14 +12,12 @@ #include #include #include -#include #include #include #include #include #include #include -#include #ifdef _DEBUG #include @@ -41,14 +39,12 @@ #include #include -#include +#include SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theConstraint) const { SolverConstraintPtr aResult; DataPtr aData = theConstraint->data(); - if (!aData || !aData->isValid()) - return aResult; #ifdef _DEBUG // Verify attributes of constraint and generate errors @@ -110,61 +106,7 @@ SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theCons return SolverConstraintPtr(new SketchSolver_Constraint(theConstraint)); } -SolverConstraintPtr SketchSolver_Builder::createFixedConstraint(FeaturePtr theFixedFeature) const +SolverConstraintPtr SketchSolver_Builder::createMovementConstraint(FeaturePtr theMovedFeature) const { - DataPtr aData = theFixedFeature->data(); - if (!aData || !aData->isValid()) - return SolverConstraintPtr(); - return SolverConstraintPtr(new SketchSolver_ConstraintFixed(theFixedFeature)); + return SolverConstraintPtr(new SketchSolver_ConstraintFixed(theMovedFeature)); } - -SolverConstraintPtr SketchSolver_Builder::createFixedArcRadiusConstraint(FeaturePtr theArc) const -{ - DataPtr aData = theArc->data(); - if (!aData || !aData->isValid()) - return SolverConstraintPtr(); - return SolverConstraintPtr(new SketchSolver_ConstraintFixedArcRadius(theArc)); -} - -SolverConstraintPtr SketchSolver_Builder::createMovementConstraint(FeaturePtr theFixedFeature) const -{ - DataPtr aData = theFixedFeature->data(); - if (!aData || !aData->isValid()) - return SolverConstraintPtr(); - return SolverConstraintPtr(new SketchSolver_ConstraintMovement(theFixedFeature)); -} - -std::shared_ptr SketchSolver_Builder::point(EntityWrapperPtr theEntity) const -{ - if (theEntity->type() != ENTITY_POINT) - return std::shared_ptr(); - if (theEntity->subEntities().size() == 1) // SketchPlugin_Point wrapper - return point(theEntity->subEntities().front()); - - double aXY[2]; - std::list aParams = theEntity->parameters(); - std::list::const_iterator anIt = aParams.begin(); - for (int i = 0; i < 2 && anIt != aParams.end(); ++i, ++anIt) - aXY[i] = (*anIt)->value(); - if (anIt != aParams.end()) - return std::shared_ptr(); - - return std::shared_ptr(new GeomAPI_Pnt2d(aXY[0], aXY[1])); -} - -std::shared_ptr SketchSolver_Builder::line(EntityWrapperPtr theEntity) const -{ - if (theEntity->type() != ENTITY_LINE) - return std::shared_ptr(); - - std::shared_ptr aPoints[2]; - std::list aSubs = theEntity->subEntities(); - std::list::const_iterator anIt = aSubs.begin(); - for (int i = 0; i < 2 && anIt != aSubs.end(); ++i, ++anIt) - aPoints[i] = point(*anIt); - if (anIt != aSubs.end()) - return std::shared_ptr(); - - return std::shared_ptr(new GeomAPI_Lin2d(aPoints[0], aPoints[1])); -} - diff --git a/src/SketchSolver/SketchSolver_Builder.h b/src/SketchSolver/SketchSolver_Builder.h index a2d67beb8..10677a712 100644 --- a/src/SketchSolver/SketchSolver_Builder.h +++ b/src/SketchSolver/SketchSolver_Builder.h @@ -21,7 +21,7 @@ class SketchSolver_Builder { public: /// \brief Creates a storage specific for used solver - virtual StoragePtr createStorage(const GroupID& theGroup) const = 0; + virtual StoragePtr createStorage(const SolverPtr&) const = 0; /// \brief Creates specific solver virtual SolverPtr createSolver() const = 0; @@ -29,35 +29,23 @@ public: /// or returns empty pointer if not all attributes are correct SolverConstraintPtr createConstraint(ConstraintPtr theConstraint) const; - /// \brief Creates temporary constraint to fix the placement of the feature - SolverConstraintPtr createFixedConstraint(FeaturePtr theFixedFeature) const; - - /// \brief Creates temporary constraint to fix radius of the arc - SolverConstraintPtr createFixedArcRadiusConstraint(FeaturePtr theArc) const; - /// \brief Creates temporary constraint to fix the feature after movement - SolverConstraintPtr createMovementConstraint(FeaturePtr theFixedFeature) const; + SolverConstraintPtr createMovementConstraint(FeaturePtr theMovedFeature) const; - /// \brief Creates new constraint(s) using given parameters + /// \brief Creates new constraint using given parameters /// \param theConstraint [in] original constraint - /// \param theGroupID [in] group the constraint belongs to - /// \param theSketchID [in] sketch the constraint belongs to /// \param theType [in] type of constraint /// \param theValue [in] numeric characteristic of constraint - /// (e.g. distance or radius) if applicable + /// (e.g. distance or radius) if applicable /// \param theEntity1 [in] first attribute of constraint /// \param theEntity2 [in] second attribute of constraint /// \param theEntity3 [in] third attribute of constraint /// \param theEntity4 [in] fourth attribute of constraint - /// \return Created list of wrappers of constraints applicable for specific solver. - /// Most of constraint types lead to single constraint, but there are some kind of - /// constraints (e.g. mirror), which may produce couple of constraints. - virtual std::list + /// \return Created wrapper of constraints applicable for specific solver. + virtual ConstraintWrapperPtr createConstraint(ConstraintPtr theConstraint, - const GroupID& theGroup, - const EntityID& theSketchID, const SketchSolver_ConstraintType& theType, - const double& theValue, + const EntityWrapperPtr& theValue, const EntityWrapperPtr& theEntity1, const EntityWrapperPtr& theEntity2 = EntityWrapperPtr(), const EntityWrapperPtr& theEntity3 = EntityWrapperPtr(), @@ -65,62 +53,39 @@ public: /// \brief Creates new multi-translation or multi-rotation constraint /// \param theConstraint [in] original constraint - /// \param theGroupID [in] group the constraint belongs to - /// \param theSketchID [in] sketch the constraint belongs to /// \param theType [in] type of constraint /// \param theValue [in] numeric characteristic of constraint (angle for multi-rotation) /// if applicable /// \param theFullValue [in] indicates theValue shows full translation delta/rotation angle or - /// delta/angle between neighbor entities + /// delta/angle between neighbor entities /// \param thePoint1 [in] center for multi-rotation or start point for multi-translation /// \param thePoint2 [in] end point for multi-translation (empty for multi-rotation) /// \param theTrsfEnt [in] list of transformed entities - virtual std::list + virtual ConstraintWrapperPtr createConstraint(ConstraintPtr theConstraint, - const GroupID& theGroup, - const EntityID& theSketchID, const SketchSolver_ConstraintType& theType, - const double& theValue, + const EntityWrapperPtr& theValue, const bool theFullValue, const EntityWrapperPtr& thePoint1, const EntityWrapperPtr& thePoint2, const std::list& theTrsfEnt) const = 0; - /// \brief Update flags for several kinds of constraints - virtual void adjustConstraint(ConstraintWrapperPtr theConstraint) const = 0; - - /// \brief Creates a feature using list of already created attributes - /// \param theFeature [in] feature to create - /// \param theAttributes [in] attributes of the feature - /// \param theGroupID [in] group the feature belongs to - /// \param theSketchID [in] sketch the feature belongs to - /// \return Created wrapper of the feature applicable for specific solver - virtual EntityWrapperPtr createFeature(FeaturePtr theFeature, - const std::list& theAttributes, - const GroupID& theGroupID, - const EntityID& theSketchID = EID_UNKNOWN) const = 0; - - /// \brief Creates an attribute - /// \param theAttribute [in] attribute to create - /// \param theGroup [in] group the attribute belongs to - /// \param theSketchID [in] sketch the attribute belongs to - /// \return Created wrapper of the attribute applicable for specific solver - virtual EntityWrapperPtr createAttribute(AttributePtr theAttribute, - const GroupID& theGroup, - const EntityID& theSketchID = EID_UNKNOWN) const = 0; - /// \brief Convert entity to point /// \return empty pointer if the entity is not a point - SKETCHSOLVER_EXPORT std::shared_ptr point(EntityWrapperPtr theEntity) const; + virtual std::shared_ptr point(EntityWrapperPtr theEntity) const = 0; + /// \brief Convert entity to line + /// \return empty pointer if the entity is not a line + virtual std::shared_ptr line(EntityWrapperPtr theEntity) const = 0; + /// \brief Convert entity to line /// \return empty pointer if the entity is not a line - SKETCHSOLVER_EXPORT std::shared_ptr line(EntityWrapperPtr theEntity) const; + virtual std::shared_ptr line(FeaturePtr theFeature) const = 0; /// \brief Check if two connected arcs have centers /// in same direction relatively to connection point - SKETCHSOLVER_EXPORT virtual bool isArcArcTangencyInternal(EntityWrapperPtr theArc1, - EntityWrapperPtr theArc2) const { return false; } + virtual bool isArcArcTangencyInternal(EntityWrapperPtr theArc1, + EntityWrapperPtr theArc2) const = 0; }; typedef std::shared_ptr BuilderPtr; diff --git a/src/SketchSolver/SketchSolver_Constraint.cpp b/src/SketchSolver/SketchSolver_Constraint.cpp index bbf00518a..1ac6bc83b 100644 --- a/src/SketchSolver/SketchSolver_Constraint.cpp +++ b/src/SketchSolver/SketchSolver_Constraint.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include #include #include @@ -37,22 +39,23 @@ SketchSolver_Constraint::SketchSolver_Constraint( ConstraintPtr theConstraint) : myBaseConstraint(theConstraint), - myGroupID(GID_UNKNOWN), myType(CONSTRAINT_UNKNOWN) { } -void SketchSolver_Constraint::process(StoragePtr theStorage, - const GroupID& theGroupID, - const EntityID& theSketchID) +void SketchSolver_Constraint::process(StoragePtr theStorage, bool theEvensBlocked) { myStorage = theStorage; - myGroupID = theGroupID; - mySketchID = theSketchID; + blockEvents(theEvensBlocked); // Process constraint according to its type process(); } +void SketchSolver_Constraint::blockEvents(bool isBlocked) +{ + myBaseConstraint->data()->blockSendAttributeUpdated(isBlocked); +} + SketchSolver_ConstraintType SketchSolver_Constraint::TYPE(ConstraintPtr theConstraint) { @@ -93,13 +96,13 @@ SketchSolver_ConstraintType SketchSolver_Constraint::TYPE(ConstraintPtr theConst void SketchSolver_Constraint::process() { cleanErrorMsg(); - if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) { + if (!myBaseConstraint || !myStorage) { // Not enough parameters are assigned return; } SketchSolver_ConstraintType aConstrType = getType(); - double aValue; + EntityWrapperPtr aValue; std::vector anAttributes; getAttributes(aValue, anAttributes); if (!myErrorMsg.empty()) @@ -112,10 +115,10 @@ void SketchSolver_Constraint::process() aConstrType = getType(); BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - std::list aNewConstraints = aBuilder->createConstraint( - myBaseConstraint, myGroupID, mySketchID, aConstrType, + ConstraintWrapperPtr aNewConstraint = aBuilder->createConstraint( + myBaseConstraint, aConstrType, aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]); - myStorage->addConstraint(myBaseConstraint, aNewConstraints); + myStorage->addConstraint(myBaseConstraint, aNewConstraint); adjustConstraint(); } @@ -123,69 +126,42 @@ void SketchSolver_Constraint::process() void SketchSolver_Constraint::update() { cleanErrorMsg(); - std::list aWrapper = myStorage->constraint(myBaseConstraint); - std::list::iterator aWIt = aWrapper.begin(); - // Check if attributes of constraint are changed, rebuild constraint - std::set anAttributes; - std::set::iterator aFoundAttr; - std::set aFeatures; - std::set::iterator aFoundFeat; + // Get list of attributes of the constraint and compare it with previously stored. + // If the lists are different, fully rebuild constraint + std::set anAttributes; for (int anEntIndex = 0; anEntIndex < 4; ++anEntIndex) { AttributePtr anAttr = myBaseConstraint->attribute(SketchPlugin_Constraint::ATTRIBUTE(anEntIndex)); if (!anAttr) continue; - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(anAttr); - if (aRefAttr) { - if (aRefAttr->isObject()) { - FeaturePtr aFeat = ModelAPI_Feature::feature(aRefAttr->object()); - if (myBaseConstraint->getKind() != SketchPlugin_ConstraintLength::ID()) - aFeatures.insert(aFeat); - else { - // Workaround for the Length constraint: add points of line, not line itself - anAttributes.insert(aFeat->attribute(SketchPlugin_Line::START_ID())); - anAttributes.insert(aFeat->attribute(SketchPlugin_Line::END_ID())); - } - } else - anAttributes.insert(aRefAttr->attr()); - } else - anAttributes.insert(anAttr); - } - bool hasNewAttr = !(anAttributes.empty() && aFeatures.empty()); - for (; hasNewAttr && aWIt != aWrapper.end(); ++ aWIt) { - const std::list& aSubs = (*aWIt)->entities(); - std::list::const_iterator aSIt = aSubs.begin(); - for (; hasNewAttr && aSIt != aSubs.end(); ++aSIt) { - if ((*aSIt)->baseAttribute()) { - aFoundAttr = anAttributes.find((*aSIt)->baseAttribute()); - if (aFoundAttr != anAttributes.end()) - anAttributes.erase(aFoundAttr); - } else { - aFoundFeat = aFeatures.find((*aSIt)->baseFeature()); - if (aFoundFeat != aFeatures.end()) - aFeatures.erase(aFoundFeat); + if (myBaseConstraint->getKind() == SketchPlugin_ConstraintLength::ID()) { + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(anAttr); + FeaturePtr aFeat = ModelAPI_Feature::feature(aRefAttr->object()); + if (aFeat) { + // Workaround for the Length constraint: add points of line, not line itself + anAttributes.insert(myStorage->entity(aFeat->attribute(SketchPlugin_Line::START_ID()))); + anAttributes.insert(myStorage->entity(aFeat->attribute(SketchPlugin_Line::END_ID()))); } - hasNewAttr = !(anAttributes.empty() && aFeatures.empty()); - } + } else + anAttributes.insert(myStorage->entity(anAttr)); } - if (hasNewAttr) { + + std::set::iterator aFound; + std::list::const_iterator anAttrIt = myAttributes.begin(); + for (; anAttrIt != myAttributes.end() && !anAttributes.empty(); ++anAttrIt) + anAttributes.erase(*anAttrIt); + + if (!anAttributes.empty()) { remove(); process(); return; } - AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::VALUE())); - if (aValueAttr) { - for (aWIt = aWrapper.begin(); aWIt != aWrapper.end(); ++aWIt) - if (fabs((*aWIt)->value() - aValueAttr->value()) > tolerance) { - (*aWIt)->setValue(aValueAttr->value()); - myStorage->setNeedToResolve(true); - } - } - myStorage->addConstraint(myBaseConstraint, aWrapper); + AttributeDoublePtr aValueAttr = myBaseConstraint->real(SketchPlugin_Constraint::VALUE()); + if (aValueAttr) + myStorage->update(aValueAttr); adjustConstraint(); } @@ -194,11 +170,12 @@ bool SketchSolver_Constraint::remove() { cleanErrorMsg(); myType = CONSTRAINT_UNKNOWN; + myStorage->unsubscribeUpdates(this); return myStorage->removeConstraint(myBaseConstraint); } void SketchSolver_Constraint::getAttributes( - double& theValue, + EntityWrapperPtr& theValue, std::vector& theAttributes) { static const int anInitNbOfAttr = 4; @@ -210,9 +187,12 @@ void SketchSolver_Constraint::getAttributes( myType = TYPE(myBaseConstraint); - AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Constraint::VALUE())); - theValue = aValueAttr ? aValueAttr->value() : 0.0; + AttributeDoublePtr aValueAttr = aData->real(SketchPlugin_Constraint::VALUE()); + if (aValueAttr) { + PlaneGCSSolver_AttributeBuilder aValueBuilder; + theValue = aValueBuilder.createAttribute(aValueAttr); + myStorage->addEntity(aValueAttr, theValue); + } int aPtInd = 0; // index of first point in the list of attributes int aEntInd = 2; // index of first entity in the list of attributes @@ -226,13 +206,8 @@ void SketchSolver_Constraint::getAttributes( return; } - myStorage->update(*anIter/*, myGroupID*/); + myStorage->update(*anIter, true); EntityWrapperPtr anEntity = myStorage->entity(*anIter); - if (!anEntity) { - // Force creation of an entity - myStorage->update(*anIter, GID_UNKNOWN, true); - anEntity = myStorage->entity(*anIter); - } myAttributes.push_back(anEntity); SketchSolver_EntityType aType = anEntity->type(); @@ -249,41 +224,3 @@ void SketchSolver_Constraint::getAttributes( } } } - -bool SketchSolver_Constraint::isUsed(FeaturePtr theFeature) const -{ - const std::list& aCList = myStorage->constraint(myBaseConstraint); - std::list::const_iterator aCIt = aCList.begin(); - for (; aCIt != aCList.end(); ++aCIt) - if ((*aCIt)->isUsed(theFeature)) - return true; - - std::list anAttrList = - theFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); - std::list::const_iterator anAttrIt = anAttrList.begin(); - for (; anAttrIt != anAttrList.end(); ++ anAttrIt) - if (isUsed(*anAttrIt)) - return true; - - return false; -} - -bool SketchSolver_Constraint::isUsed(AttributePtr theAttribute) const -{ - AttributePtr anAttribute = theAttribute; - AttributeRefAttrPtr aRefAttr = - std::dynamic_pointer_cast(anAttribute); - if (aRefAttr) { - if (aRefAttr->isObject()) - return isUsed(ModelAPI_Feature::feature(aRefAttr->object())); - else - anAttribute = aRefAttr->attr(); - } - - const std::list& aCList = myStorage->constraint(myBaseConstraint); - std::list::const_iterator aCIt = aCList.begin(); - for (; aCIt != aCList.end(); ++aCIt) - if ((*aCIt)->isUsed(theAttribute)) - return true; - return false; -} diff --git a/src/SketchSolver/SketchSolver_Constraint.h b/src/SketchSolver/SketchSolver_Constraint.h index 69513749c..5c06e0aa5 100644 --- a/src/SketchSolver/SketchSolver_Constraint.h +++ b/src/SketchSolver/SketchSolver_Constraint.h @@ -9,6 +9,7 @@ #include "SketchSolver.h" #include +#include #include @@ -27,50 +28,41 @@ class SketchSolver_Constraint protected: /// Default constructor SketchSolver_Constraint() - : myGroupID(GID_UNKNOWN), - myType(CONSTRAINT_UNKNOWN) + : myType(CONSTRAINT_UNKNOWN) {} public: /// Constructor based on SketchPlugin constraint - SKETCHSOLVER_EXPORT SketchSolver_Constraint(ConstraintPtr theConstraint); + SketchSolver_Constraint(ConstraintPtr theConstraint); virtual ~SketchSolver_Constraint() {} /// \brief Initializes parameters and start constraint creation - /// \param theStorage [in] storage where to place new constraint - /// \param theGroupID [in] group for constraint - /// \param theSketchID [in] sketch for constraint - void process(StoragePtr theStorage, const GroupID& theGroupID, const EntityID& theSketchID); + /// \param theStorage [in] storage where to place new constraint + /// \param theEventsBlocked [in] all events from this constraint should be blocked + void process(StoragePtr theStorage, bool theEvensBlocked); + + /// \brief Notify this object about the feature is changed somewhere + virtual void notify(const FeaturePtr& theFeature, PlaneGCSSolver_Update* theUpdater) {} /// \brief Update constraint - SKETCHSOLVER_EXPORT virtual void update(); + virtual void update(); /// \brief Tries to remove constraint /// \return \c false, if current constraint contains another SketchPlugin constraints /// (like for multiple coincidence) - SKETCHSOLVER_EXPORT virtual bool remove(); + virtual bool remove(); + + /// \brief Block or unblock events from this constraint + virtual void blockEvents(bool isBlocked); /// \brief Obtain a type of SketchPlugin constraint - SKETCHSOLVER_EXPORT static SketchSolver_ConstraintType TYPE(ConstraintPtr theConstraint); + static SketchSolver_ConstraintType TYPE(ConstraintPtr theConstraint); /// \brief Returns the type of constraint virtual SketchSolver_ConstraintType getType() const { return myType; } - /// \brief Returns list of attributes of constraint - const std::list& attributes() const - { return myAttributes; } - - /// \brief Verify the feature or any its attribute is used by constraint - virtual bool isUsed(FeaturePtr theFeature) const; - /// \brief Verify the attribute is used by constraint - virtual bool isUsed(AttributePtr theAttribute) const; - - /// \brief Notify constraint, that coincidence appears or removed - virtual void notifyCoincidenceChanged(EntityWrapperPtr theCoincAttr1, - EntityWrapperPtr theCoincAttr2) { /* implement in derived class */ } - /// \brief Shows error message const std::string& error() const { return myErrorMsg; } @@ -82,7 +74,8 @@ protected: /// \brief Generate list of attributes of constraint in order useful for constraints /// \param[out] theValue numerical characteristic of constraint (e.g. distance) /// \param[out] theAttributes list of attributes to be filled - virtual void getAttributes(double& theValue, std::vector& theAttributes); + virtual void getAttributes(EntityWrapperPtr& theValue, + std::vector& theAttributes); /// \brief This method is used in derived objects to check consistency of constraint. /// E.g. the distance between line and point may be signed. @@ -94,9 +87,8 @@ protected: { myErrorMsg.clear(); } protected: - GroupID myGroupID; ///< identifier of the group, the constraint belongs to - EntityID mySketchID; ///< identifier of the sketch, the constraint belongs to ConstraintPtr myBaseConstraint; ///< base SketchPlugin constraint + ConstraintWrapperPtr mySolverConstraint; ///< wrapper for PlaneGCS constraint /// storage, which contains all information about entities and constraints StoragePtr myStorage; diff --git a/src/SketchSolver/SketchSolver_ConstraintAngle.cpp b/src/SketchSolver/SketchSolver_ConstraintAngle.cpp index f4207163b..38ba87eb4 100644 --- a/src/SketchSolver/SketchSolver_ConstraintAngle.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintAngle.cpp @@ -1,41 +1,20 @@ // Copyright (C) 2014-20xx CEA/DEN, EDF R&D #include -#include - -#include -#include -#include -#include #include - #include -#include - void SketchSolver_ConstraintAngle::getAttributes( - double& theValue, std::vector& theAttributes) + EntityWrapperPtr& theValue, std::vector& theAttributes) { SketchSolver_Constraint::getAttributes(theValue, theAttributes); - - myAngle = theValue; myType = myBaseConstraint->integer(SketchPlugin_ConstraintAngle::TYPE_ID())->value(); } void SketchSolver_ConstraintAngle::adjustConstraint() { - static const double aTol = 1000. * tolerance; - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - - ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front(); - //if (fabs(myAngle - aConstraint->value()) < aTol) - // return; - myAngle = aConstraint->value(); - aBuilder->adjustConstraint(aConstraint); - myStorage->addConstraint(myBaseConstraint, aConstraint); - int aType = myBaseConstraint->integer(SketchPlugin_ConstraintAngle::TYPE_ID())->value(); if (aType != myType) { myType = aType; diff --git a/src/SketchSolver/SketchSolver_ConstraintAngle.h b/src/SketchSolver/SketchSolver_ConstraintAngle.h index cff6937c3..1c6883c06 100644 --- a/src/SketchSolver/SketchSolver_ConstraintAngle.h +++ b/src/SketchSolver/SketchSolver_ConstraintAngle.h @@ -17,22 +17,21 @@ class SketchSolver_ConstraintAngle : public SketchSolver_Constraint { public: /// Constructor based on SketchPlugin constraint - SketchSolver_ConstraintAngle(ConstraintPtr theConstraint) : - SketchSolver_Constraint(theConstraint), - myAngle(0.0) + SketchSolver_ConstraintAngle(ConstraintPtr theConstraint) + : SketchSolver_Constraint(theConstraint) {} /// \brief This method is used in derived objects to check consistence of constraint. - virtual void adjustConstraint(); + virtual void adjustConstraint() override; protected: /// \brief Generate list of attributes of constraint in order useful for constraints /// \param[out] theValue numerical characteristic of constraint (e.g. distance) /// \param[out] theAttributes list of attributes to be filled - virtual void getAttributes(double& theValue, std::vector& theAttributes); + virtual void getAttributes(EntityWrapperPtr& theValue, + std::vector& theAttributes) override; private: - double myAngle; int myType; }; diff --git a/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp b/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp index 18594018c..8501289fd 100644 --- a/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp @@ -3,9 +3,37 @@ #include #include #include +#include + +void SketchSolver_ConstraintCoincidence::process() +{ + cleanErrorMsg(); + if (!myBaseConstraint || !myStorage) { + // Not enough parameters are assigned + return; + } + + EntityWrapperPtr aValue; + std::vector anAttributes; + getAttributes(aValue, anAttributes); + if (!myErrorMsg.empty()) + return; + if (anAttributes.empty()) { + myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); + return; + } + + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + mySolverConstraint = aBuilder->createConstraint( + myBaseConstraint, getType(), + aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]); + + myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateCoincidence::GROUP()); + myStorage->notify(myBaseConstraint); +} void SketchSolver_ConstraintCoincidence::getAttributes( - double& theValue, + EntityWrapperPtr& theValue, std::vector& theAttributes) { SketchSolver_Constraint::getAttributes(theValue, theAttributes); @@ -14,19 +42,8 @@ void SketchSolver_ConstraintCoincidence::getAttributes( return; } - if (theAttributes[1]) { + if (theAttributes[1]) myType = CONSTRAINT_PT_PT_COINCIDENT; - if (myStorage->isFixed(theAttributes[1]) && !myStorage->isFixed(theAttributes[0])) { - // fixed point should go first - EntityWrapperPtr aTemp = theAttributes[0]; - theAttributes[0] = theAttributes[1]; - theAttributes[1] = aTemp; - } - // Set the slave (second) point the same as master (first) point. - // This will allow to skip adding point-point coincidence to the set of constraints - // and give us speed-up in solving the set of equations - myStorage->addCoincidentPoints(theAttributes[0], theAttributes[1]); - } else if (theAttributes[2]) { // check the type of entity (line or circle) SketchSolver_EntityType anEntType = theAttributes[2]->type(); @@ -39,3 +56,22 @@ void SketchSolver_ConstraintCoincidence::getAttributes( } else myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); } + +void SketchSolver_ConstraintCoincidence::notify(const FeaturePtr& theFeature, + PlaneGCSSolver_Update* theUpdater) +{ + PlaneGCSSolver_UpdateCoincidence* anUpdater = + static_cast(theUpdater); + bool isAccepted = anUpdater->checkCoincidence(myAttributes.front(), myAttributes.back()); + if (isAccepted) { + if (!myInSolver) { + myInSolver = true; + myStorage->addConstraint(myBaseConstraint, mySolverConstraint); + } + } else { + if (myInSolver) { + myInSolver = false; + myStorage->removeConstraint(myBaseConstraint); + } + } +} diff --git a/src/SketchSolver/SketchSolver_ConstraintCoincidence.h b/src/SketchSolver/SketchSolver_ConstraintCoincidence.h index 58b0d98df..634618ff2 100644 --- a/src/SketchSolver/SketchSolver_ConstraintCoincidence.h +++ b/src/SketchSolver/SketchSolver_ConstraintCoincidence.h @@ -18,15 +18,27 @@ class SketchSolver_ConstraintCoincidence : public SketchSolver_Constraint { public: /// Constructor based on SketchPlugin constraint - SKETCHSOLVER_EXPORT SketchSolver_ConstraintCoincidence(ConstraintPtr theConstraint) : - SketchSolver_Constraint(theConstraint) + SketchSolver_ConstraintCoincidence(ConstraintPtr theConstraint) : + SketchSolver_Constraint(theConstraint), + myInSolver(false) {} + /// \brief Notify this object about the feature is changed somewhere + virtual void notify(const FeaturePtr& theFeature, + PlaneGCSSolver_Update* theUpdater) override; + protected: + /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints + virtual void process() override; + /// \brief Generate list of attributes of constraint in order useful for constraints /// \param[out] theValue numerical characteristic of constraint (e.g. distance) /// \param[out] theAttributes list of attributes to be filled - virtual void getAttributes(double& theValue, std::vector& theAttributes); + virtual void getAttributes(EntityWrapperPtr& theValue, + std::vector& theAttributes) override; + +protected: + bool myInSolver; ///< shows the constraint is added to the solver }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintCollinear.cpp b/src/SketchSolver/SketchSolver_ConstraintCollinear.cpp index 194d47aa0..f99ab425f 100644 --- a/src/SketchSolver/SketchSolver_ConstraintCollinear.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintCollinear.cpp @@ -10,47 +10,47 @@ SketchSolver_ConstraintCollinear::SketchSolver_ConstraintCollinear(ConstraintPtr { } -void SketchSolver_ConstraintCollinear::notifyCoincidenceChanged( - EntityWrapperPtr theCoincAttr1, - EntityWrapperPtr theCoincAttr2) -{ - bool used = true; - - // obtain IDs of all boundary points of lines - EntityID aPointIDs[4]; - for (int i = 0; i < 2; ++i) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::ATTRIBUTE(i))); - if (!aRefAttr->object()) - continue; - FeaturePtr aLine = ModelAPI_Feature::feature(aRefAttr->object()); - AttributePtr aLinePt = aLine->attribute(SketchPlugin_Line::START_ID()); - aPointIDs[2*i] = myStorage->entity(aLinePt)->id(); - aLinePt = aLine->attribute(SketchPlugin_Line::END_ID()); - aPointIDs[2*i + 1] = myStorage->entity(aLinePt)->id(); - } - - EntityWrapperPtr anAttrs[2] = {theCoincAttr1, theCoincAttr2}; - for (int i = 0; i < 2 && used; ++i) { - if (anAttrs[i]->baseAttribute()) - used = used && isUsed(anAttrs[i]->baseAttribute()); - else - used = used && isUsed(anAttrs[i]->baseFeature()); - - if (!used) { - if (anAttrs[i]->type() == ENTITY_POINT) { - EntityID anID = anAttrs[i]->id(); - for (int j = 0; j < 4; ++j) - if (anID == aPointIDs[j]) { - used = true; - break; - } - } - } - } - - if (used) { - remove(); - process(); - } -} +////void SketchSolver_ConstraintCollinear::notifyCoincidenceChanged( +//// EntityWrapperPtr theCoincAttr1, +//// EntityWrapperPtr theCoincAttr2) +////{ +//// bool used = true; +//// +//// // obtain IDs of all boundary points of lines +//// EntityID aPointIDs[4]; +//// for (int i = 0; i < 2; ++i) { +//// AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( +//// myBaseConstraint->attribute(SketchPlugin_Constraint::ATTRIBUTE(i))); +//// if (!aRefAttr->object()) +//// continue; +//// FeaturePtr aLine = ModelAPI_Feature::feature(aRefAttr->object()); +//// AttributePtr aLinePt = aLine->attribute(SketchPlugin_Line::START_ID()); +//// aPointIDs[2*i] = myStorage->entity(aLinePt)->id(); +//// aLinePt = aLine->attribute(SketchPlugin_Line::END_ID()); +//// aPointIDs[2*i + 1] = myStorage->entity(aLinePt)->id(); +//// } +//// +//// EntityWrapperPtr anAttrs[2] = {theCoincAttr1, theCoincAttr2}; +//// for (int i = 0; i < 2 && used; ++i) { +//// if (anAttrs[i]->baseAttribute()) +//// used = used && isUsed(anAttrs[i]->baseAttribute()); +//// else +//// used = used && isUsed(anAttrs[i]->baseFeature()); +//// +//// if (!used) { +//// if (anAttrs[i]->type() == ENTITY_POINT) { +//// EntityID anID = anAttrs[i]->id(); +//// for (int j = 0; j < 4; ++j) +//// if (anID == aPointIDs[j]) { +//// used = true; +//// break; +//// } +//// } +//// } +//// } +//// +//// if (used) { +//// remove(); +//// process(); +//// } +////} diff --git a/src/SketchSolver/SketchSolver_ConstraintCollinear.h b/src/SketchSolver/SketchSolver_ConstraintCollinear.h index 5d6187eb4..7ab635581 100644 --- a/src/SketchSolver/SketchSolver_ConstraintCollinear.h +++ b/src/SketchSolver/SketchSolver_ConstraintCollinear.h @@ -17,13 +17,13 @@ class SketchSolver_ConstraintCollinear : public SketchSolver_Constraint { public: /// Constructor based on SketchPlugin constraint - SKETCHSOLVER_EXPORT SketchSolver_ConstraintCollinear(ConstraintPtr theConstraint); + SketchSolver_ConstraintCollinear(ConstraintPtr theConstraint); virtual ~SketchSolver_ConstraintCollinear() {} - /// \brief Notify constraint, that coincidence appears or removed - virtual void notifyCoincidenceChanged(EntityWrapperPtr theCoincAttr1, - EntityWrapperPtr theCoincAttr2); +//// /// \brief Notify constraint, that coincidence appears or removed +//// virtual void notifyCoincidenceChanged(EntityWrapperPtr theCoincAttr1, +//// EntityWrapperPtr theCoincAttr2); }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintDistance.cpp b/src/SketchSolver/SketchSolver_ConstraintDistance.cpp index afe792932..9e01c65a8 100644 --- a/src/SketchSolver/SketchSolver_ConstraintDistance.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintDistance.cpp @@ -13,7 +13,7 @@ void SketchSolver_ConstraintDistance::getAttributes( - double& theValue, + EntityWrapperPtr& theValue, std::vector& theAttributes) { SketchSolver_Constraint::getAttributes(theValue, theAttributes); @@ -34,37 +34,58 @@ void SketchSolver_ConstraintDistance::getAttributes( void SketchSolver_ConstraintDistance::adjustConstraint() { - ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front(); + ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint); // Adjust point-point distance if the points are equal if (getType() == CONSTRAINT_PT_PT_DISTANCE) { - const std::list& aSubs = aConstraint->entities(); - if (aSubs.front()->isEqual(aSubs.back())) { - // Change X coordinate of second point to eliminate coincidence - ParameterWrapperPtr aX = aSubs.back()->parameters().front(); - aX->setValue(aX->value() + 1.0); - myStorage->update(aX); - } +//// AttributePtr aPt1 = myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()); +//// AttributePtr aPt2 = myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()); +//// +//// BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); +//// std::shared_ptr aPoint1 = aBuilder->point(myStorage->entity(aPt1)); +//// EntityWrapperPtr anEntity2 = myStorage->entity(aPt2); +//// std::shared_ptr aPoint2 = aBuilder->point(anEntity2); +//// +//////// if (aPoint1->distance(aPoint2) < tolerance) { +//////// // Change X coordinate of second point to eliminate coincidence +//////// ParameterWrapperPtr aX = aSubs.back()->parameters().front(); +//////// aX->setValue(aX->value() + 1.0); +//////// myStorage->update(aX); +//////// } return; } // Adjust point-line distance if (fabs(myPrevValue) == fabs(aConstraint->value())) { // sign of distance is not changed - aConstraint->setValue(myPrevValue); - myStorage->addConstraint(myBaseConstraint, aConstraint); +//// aConstraint->setValue(myPrevValue); +//// myStorage->addConstraint(myBaseConstraint, aConstraint); return; } - // Adjust the sign of constraint value - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - aBuilder->adjustConstraint(aConstraint); - myStorage->addConstraint(myBaseConstraint, aConstraint); +//// // Adjust the sign of constraint value +//// BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); +//// +//// std::shared_ptr aLine; +//// std::shared_ptr aPoint; +//// for (int i = 0; i < 2; ++i) { +//// AttributePtr anAttr = myBaseConstraint->attribute(SketchPlugin_Constraint::ATTRIBUTE(i)); +//// EntityWrapperPtr anEntity = myStorage->entity(anAttr); +//// if (anEntity->type() == ENTITY_POINT) +//// aPoint = aBuilder->point(anEntity); +//// else if (anEntity->type() == ENTITY_LINE) +//// aLine = aBuilder->line(anEntity); +//// } +//// +//// std::shared_ptr aLineVec = aLine->direction()->xy(); +//// std::shared_ptr aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy()); +//// if (aLineVec->cross(aPtLineVec) * aConstraint->value() < 0.0) +//// aConstraint->setValue(aConstraint->value() * (-1.0)); } void SketchSolver_ConstraintDistance::update() { - ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front(); + ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint); myPrevValue = aConstraint->value(); SketchSolver_Constraint::update(); diff --git a/src/SketchSolver/SketchSolver_ConstraintDistance.h b/src/SketchSolver/SketchSolver_ConstraintDistance.h index 80a6fb5e3..08df9670a 100644 --- a/src/SketchSolver/SketchSolver_ConstraintDistance.h +++ b/src/SketchSolver/SketchSolver_ConstraintDistance.h @@ -24,17 +24,18 @@ public: {} /// \brief Update constraint - virtual void update(); + virtual void update() override; protected: /// \brief Generate list of attributes of constraint in order useful for constraints /// \param[out] theValue numerical characteristic of constraint (e.g. distance) /// \param[out] theAttributes list of attributes to be filled - virtual void getAttributes(double& theValue, std::vector& theAttributes); + virtual void getAttributes(EntityWrapperPtr& theValue, + std::vector& theAttributes) override; /// \brief This method is used in derived objects to check consistence of constraint. /// E.g. the distance between line and point may be signed. - virtual void adjustConstraint(); + virtual void adjustConstraint() override; private: double myPrevValue; ///< previous value of distance (for correct calculation of a distance sign) diff --git a/src/SketchSolver/SketchSolver_ConstraintEqual.cpp b/src/SketchSolver/SketchSolver_ConstraintEqual.cpp index 33cb9f5dd..b2cfa0a71 100644 --- a/src/SketchSolver/SketchSolver_ConstraintEqual.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintEqual.cpp @@ -3,8 +3,11 @@ #include #include +#include +#include + void SketchSolver_ConstraintEqual::getAttributes( - double& theValue, + EntityWrapperPtr& theValue, std::vector& theAttributes) { SketchSolver_Constraint::getAttributes(theValue, theAttributes); @@ -51,6 +54,15 @@ void SketchSolver_ConstraintEqual::getAttributes( break; default: myType = CONSTRAINT_EQUAL_LINES; + + AttributeRefAttrPtr aRefLine1 = + myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_A()); + FeaturePtr aLine1 = ModelAPI_Feature::feature(aRefLine1->object()); + if (aLine1) { + // store length of first line as a value for constraint + // (will be used to make equal lengths of lines) + theValue = myStorage->entity(aLine1->attribute(SketchPlugin_Line::LENGTH_ID())); + } break; } } diff --git a/src/SketchSolver/SketchSolver_ConstraintEqual.h b/src/SketchSolver/SketchSolver_ConstraintEqual.h index 12e6a334e..88a03aa16 100644 --- a/src/SketchSolver/SketchSolver_ConstraintEqual.h +++ b/src/SketchSolver/SketchSolver_ConstraintEqual.h @@ -26,7 +26,8 @@ protected: /// \brief Generate list of attributes of constraint in order useful for constraints /// \param[out] theValue numerical characteristic of constraint (e.g. distance) /// \param[out] theAttributes list of attributes to be filled - virtual void getAttributes(double& theValue, std::vector& theAttributes); + virtual void getAttributes(EntityWrapperPtr& theValue, + std::vector& theAttributes) override; }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintFixed.cpp b/src/SketchSolver/SketchSolver_ConstraintFixed.cpp index ca14864cb..73f9808eb 100644 --- a/src/SketchSolver/SketchSolver_ConstraintFixed.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintFixed.cpp @@ -2,32 +2,22 @@ #include #include -#include -#include -#include -#include -#include -#include +#include +#include +#include -#include -#include -#include -#include - -#include SketchSolver_ConstraintFixed::SketchSolver_ConstraintFixed(ConstraintPtr theConstraint) - : SketchSolver_Constraint() + : SketchSolver_Constraint(theConstraint) { - myBaseConstraint = theConstraint; myType = CONSTRAINT_FIXED; - AttributeRefAttrPtr anAttribute = - theConstraint->refattr(SketchPlugin_ConstraintRigid::ENTITY_A()); - if (anAttribute->isObject()) - myFixedFeature = ModelAPI_Feature::feature(anAttribute->object()); - else - myFixedAttribute = anAttribute->attr(); +//// AttributeRefAttrPtr anAttribute = +//// theConstraint->refattr(SketchPlugin_ConstraintRigid::ENTITY_A()); +//// if (anAttribute->isObject()) +//// myFixedFeature = ModelAPI_Feature::feature(anAttribute->object()); +//// else +//// myFixedAttribute = anAttribute->attr(); } SketchSolver_ConstraintFixed::SketchSolver_ConstraintFixed(FeaturePtr theFeature) @@ -35,91 +25,119 @@ SketchSolver_ConstraintFixed::SketchSolver_ConstraintFixed(FeaturePtr theFeature myBaseFeature(theFeature) { myType = CONSTRAINT_FIXED; - process(); +//// process(); +} + +void SketchSolver_ConstraintFixed::blockEvents(bool isBlocked) +{ + if (myBaseFeature) + myBaseFeature->data()->blockSendAttributeUpdated(isBlocked); + if (myBaseConstraint) + SketchSolver_Constraint::blockEvents(isBlocked); } void SketchSolver_ConstraintFixed::process() { cleanErrorMsg(); - if ((!myBaseConstraint && !myBaseFeature) || !myStorage || myGroupID == GID_UNKNOWN) { + if ((!myBaseConstraint && !myBaseFeature) || !myStorage) { // Not enough parameters are assigned return; } - ParameterWrapperPtr aValue; + EntityWrapperPtr aValue; std::vector anEntities; getAttributes(aValue, anEntities); - if (!myErrorMsg.empty() || anEntities.empty()) + if (anEntities.empty()) + myErrorMsg = SketchSolver_Error::ALREADY_FIXED(); + if (!myErrorMsg.empty()) return; fixFeature(anEntities.front()); } void SketchSolver_ConstraintFixed::fixFeature(EntityWrapperPtr theFeature) { - // extract feature from the group - if (theFeature->baseAttribute()) - myStorage->update(theFeature->baseAttribute(), GID_OUTOFGROUP); - else if (theFeature->baseFeature()) - myStorage->update(theFeature->baseFeature(), GID_OUTOFGROUP); + std::shared_ptr anEntity = + std::dynamic_pointer_cast(theFeature); + + GCS::VEC_pD aParameters; // parameters of entity to be fixed + + // Collect parameters for each type of entity + switch (theFeature->type()) { + case ENTITY_POINT: { + std::shared_ptr aPoint = + std::dynamic_pointer_cast(theFeature); + aParameters.push_back(aPoint->point()->x); + aParameters.push_back(aPoint->point()->y); + break; + } + case ENTITY_LINE: { + std::shared_ptr aLine = std::dynamic_pointer_cast(anEntity->entity()); + aParameters.push_back(aLine->p1.x); + aParameters.push_back(aLine->p1.y); + aParameters.push_back(aLine->p2.x); + aParameters.push_back(aLine->p2.y); + break; + } + case ENTITY_CIRCLE: { + std::shared_ptr aCircle = + std::dynamic_pointer_cast(anEntity->entity()); + aParameters.push_back(aCircle->center.x); + aParameters.push_back(aCircle->center.y); + aParameters.push_back(aCircle->rad); + break; + } + case ENTITY_ARC: { + myFixedValues.reserve(4); + std::shared_ptr anArc = std::dynamic_pointer_cast(anEntity->entity()); + aParameters.push_back(anArc->center.x); + aParameters.push_back(anArc->center.y); + aParameters.push_back(anArc->rad); + aParameters.push_back(anArc->startAngle); + aParameters.push_back(anArc->endAngle); + break; + } + default: + break; + } + + // Fix given list of parameters + std::list aConstraints; + myFixedValues.reserve(aParameters.size()); + GCS::VEC_pD::const_iterator anIt = aParameters.begin(); + for (int i = 0; anIt != aParameters.end(); ++anIt, ++i) { + myFixedValues.push_back(**anIt); + aConstraints.push_back( + GCSConstraintPtr(new GCS::ConstraintEqual(*anIt, &myFixedValues[i]))); + } + + myConstraint = ConstraintWrapperPtr( + new PlaneGCSSolver_ConstraintWrapper(aConstraints, getType())); if (myBaseConstraint) - myStorage->addConstraint(myBaseConstraint, std::list()); + myStorage->addConstraint(myBaseConstraint, myConstraint); + else + myStorage->addTemporaryConstraint(myConstraint); } void SketchSolver_ConstraintFixed::getAttributes( - ParameterWrapperPtr& theValue, + EntityWrapperPtr& theValue, std::vector& theAttributes) { - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - - EntityWrapperPtr aSolverEntity; if (myBaseFeature) { // The feature is fixed. - myStorage->update(myBaseFeature/*, myGroupID*/); - aSolverEntity = myStorage->entity(myBaseFeature); + myStorage->update(myBaseFeature); + EntityWrapperPtr aSolverEntity = myStorage->entity(myBaseFeature); + if (aSolverEntity) + theAttributes.push_back(aSolverEntity); } else if (myBaseConstraint) { // Constraint Fixed is added by user. // Get the attribute of constraint (it should be alone in the list of constraints). - AttributePtr anAttr = myBaseConstraint->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()); - AttributeRefAttrPtr aRefAttr = - std::dynamic_pointer_cast(anAttr); - if (!aRefAttr || !aRefAttr->isInitialized()) { - myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); - return; - } - - myStorage->update(anAttr, myGroupID); - aSolverEntity = myStorage->entity(anAttr); + std::vector anAttributes; + SketchSolver_Constraint::getAttributes(theValue, anAttributes); + std::vector::const_iterator anIt = anAttributes.begin(); + for (; anIt != anAttributes.end(); ++anIt) + if (*anIt) + theAttributes.push_back(*anIt); } else myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); - - if (aSolverEntity) - theAttributes.push_back(aSolverEntity); -} - - -bool SketchSolver_ConstraintFixed::remove() -{ - cleanErrorMsg(); - // Move fixed entities back to the current group - FeaturePtr aFeature = myBaseFeature; - if (myBaseConstraint) { - if (myFixedFeature) - aFeature = myFixedFeature; - else if (myFixedAttribute) - myStorage->update(AttributePtr(myFixedAttribute), myGroupID); - } - if (aFeature) - myStorage->update(aFeature, myGroupID); - myStorage->setNeedToResolve(true); - - // Remove constraint or base feature - if (myBaseConstraint) { - bool isRemoved = false; - if (aFeature) - isRemoved = myStorage->removeEntity(aFeature); - return SketchSolver_Constraint::remove() || isRemoved; - } else if (myBaseFeature) - myStorage->removeEntity(myBaseFeature); - return true; } diff --git a/src/SketchSolver/SketchSolver_ConstraintFixed.h b/src/SketchSolver/SketchSolver_ConstraintFixed.h index fd56f87d9..bccf4402a 100644 --- a/src/SketchSolver/SketchSolver_ConstraintFixed.h +++ b/src/SketchSolver/SketchSolver_ConstraintFixed.h @@ -16,43 +16,37 @@ * * Fixed constraint may have NULL basic SketchPlugin constraint, * because the Fixed constraint may be temporary for correct moving of objects. - * - * Fixed constraint does not create a constraint, but builds the entities in separate group, - * so they will not be moved while resolving the set of constraints. */ class SketchSolver_ConstraintFixed : public SketchSolver_Constraint { public: /// Creates constraint to manage the given constraint from plugin SketchSolver_ConstraintFixed(ConstraintPtr theConstraint); - /// Creates temporary constraint based on feature + /// Creates temporary constraint based on feature (useful while the feature is being moved) SketchSolver_ConstraintFixed(FeaturePtr theFeature); - /// \brief Tries to remove constraint - /// \return \c false, if current constraint contains another - /// SketchPlugin constraints (like for multiple coincidence) - virtual bool remove(); + /// \brief Block or unblock events from this constraint + virtual void blockEvents(bool isBlocked) override; protected: /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints - virtual void process(); + virtual void process() override; /// \brief Generate list of attributes of constraint in order useful for constraints /// \param[out] theValue numerical characteristic of constraint (e.g. distance) /// \param[out] theAttributes list of attributes to be filled - virtual void getAttributes(ParameterWrapperPtr& theValue, - std::vector& theAttributes); + virtual void getAttributes(EntityWrapperPtr& theValue, + std::vector& theAttributes) override; /// \brief Fixed feature basing on its type /// \param theFeature [in] feature, converted to solver specific format virtual void fixFeature(EntityWrapperPtr theFeature); -protected: +private: FeaturePtr myBaseFeature; ///< fixed feature (when it is set, myBaseConstraint should be NULL) -private: - AttributePtr myFixedAttribute; ///< possible attribute of a fixed constraint (for correct remove) - FeaturePtr myFixedFeature; ///< possible attribute of a fixed constraint (for correct remove) + ConstraintWrapperPtr myConstraint; + std::vector myFixedValues; }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintFixedArcRadius.cpp b/src/SketchSolver/SketchSolver_ConstraintFixedArcRadius.cpp deleted file mode 100644 index af32f1943..000000000 --- a/src/SketchSolver/SketchSolver_ConstraintFixedArcRadius.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -#include -#include -#include - -#include -#include - -SketchSolver_ConstraintFixedArcRadius::SketchSolver_ConstraintFixedArcRadius(FeaturePtr theFeature) - : SketchSolver_ConstraintFixed(theFeature) -{ - myType = CONSTRAINT_RADIUS; - process(); -} - -void SketchSolver_ConstraintFixedArcRadius::process() -{ - cleanErrorMsg(); - if (!myBaseFeature || !myStorage || myGroupID == GID_UNKNOWN) { - // Not enough parameters are assigned - return; - } - - if (myBaseFeature->getKind() != SketchPlugin_Arc::ID()) { - myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); - return; - } - - ParameterWrapperPtr aValue; - std::vector anEntities; - getAttributes(aValue, anEntities); - if (!myErrorMsg.empty() || anEntities.empty()) - return; - fixFeature(anEntities.front()); -} - -void SketchSolver_ConstraintFixedArcRadius::fixFeature(EntityWrapperPtr theFeature) -{ - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - - // Calculate radius of the arc - std::list aSubs = theFeature->subEntities(); - std::list::const_iterator aSubIt = aSubs.begin(); - std::shared_ptr aCenter = aBuilder->point(*aSubIt++); - std::shared_ptr aStart = aBuilder->point(*aSubIt++); - double aRadius = aCenter->distance(aStart); - - // Create constraint - std::list aConstrList = aBuilder->createConstraint(ConstraintPtr(), - myGroupID, mySketchID, myType, aRadius, EntityWrapperPtr(), EntityWrapperPtr(), theFeature); - myRadiusConstraint = aConstrList.front(); - myStorage->addConstraint(ConstraintPtr(), myRadiusConstraint); -} - -bool SketchSolver_ConstraintFixedArcRadius::remove() -{ - bool isFullyRemoved = true; - if (myBaseFeature) - isFullyRemoved = myStorage->removeEntity(myBaseFeature) && isFullyRemoved; - if (myRadiusConstraint) - isFullyRemoved = myStorage->removeConstraint(ConstraintPtr()) && - myStorage->remove(myRadiusConstraint) && isFullyRemoved; - return isFullyRemoved; -} diff --git a/src/SketchSolver/SketchSolver_ConstraintFixedArcRadius.h b/src/SketchSolver/SketchSolver_ConstraintFixedArcRadius.h deleted file mode 100644 index 6bb3e67bf..000000000 --- a/src/SketchSolver/SketchSolver_ConstraintFixedArcRadius.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: SketchSolver_ConstraintFixedArcRadiusArcRadius.h -// Created: 22 Jan 2016 -// Author: Artem ZHIDKOV - -#ifndef SketchSolver_ConstraintFixedArcRadius_H_ -#define SketchSolver_ConstraintFixedArcRadius_H_ - -#include "SketchSolver.h" -#include - -/** \class SketchSolver_ConstraintFixedArcRadius - * \ingroup Plugins - * \brief Fix radius of the arc. Temporary constraint. Based on an arc, sharp! - */ -class SketchSolver_ConstraintFixedArcRadius : public SketchSolver_ConstraintFixed -{ -public: - /// Creates temporary constraint based on feature - SketchSolver_ConstraintFixedArcRadius(FeaturePtr theFeature); - - /// \brief Tries to remove constraint - /// \return \c false, if current constraint contains another SketchPlugin constraints - /// (like for multiple coincidence) - virtual bool remove(); - -protected: - /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints - virtual void process(); - - /// \brief Fix radius of arc - /// \param theFeature [in] feature, converted to solver specific format - virtual void fixFeature(EntityWrapperPtr theFeature); - -private: - ConstraintWrapperPtr myRadiusConstraint; -}; - -#endif diff --git a/src/SketchSolver/SketchSolver_ConstraintLength.cpp b/src/SketchSolver/SketchSolver_ConstraintLength.cpp index be89bb53d..1a4be5072 100644 --- a/src/SketchSolver/SketchSolver_ConstraintLength.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintLength.cpp @@ -3,9 +3,11 @@ #include #include +#include + void SketchSolver_ConstraintLength::getAttributes( - double& theValue, + EntityWrapperPtr& theValue, std::vector& theAttributes) { SketchSolver_Constraint::getAttributes(theValue, theAttributes); @@ -15,13 +17,11 @@ void SketchSolver_ConstraintLength::getAttributes( return; } - // Get boundary points of line segment and create point-point distance constraint - std::list aSubs = theAttributes[2]->subEntities(); - theAttributes.assign(theAttributes.size(), EntityWrapperPtr()); - std::vector::iterator anAttrIt = theAttributes.begin(); - std::list::const_iterator aSubIt = aSubs.begin(); - for (; aSubIt != aSubs.end(); ++aSubIt, ++anAttrIt) - *anAttrIt = *aSubIt; + AttributeRefAttrPtr aRefAttr = myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_A()); + FeaturePtr aLine = ModelAPI_Feature::feature(aRefAttr->object()); + + theAttributes[0] = myStorage->entity(aLine->attribute(SketchPlugin_Line::START_ID())); + theAttributes[1] = myStorage->entity(aLine->attribute(SketchPlugin_Line::END_ID())); myType = CONSTRAINT_PT_PT_DISTANCE; } diff --git a/src/SketchSolver/SketchSolver_ConstraintLength.h b/src/SketchSolver/SketchSolver_ConstraintLength.h index 0899d8b73..1626f1c48 100644 --- a/src/SketchSolver/SketchSolver_ConstraintLength.h +++ b/src/SketchSolver/SketchSolver_ConstraintLength.h @@ -26,7 +26,8 @@ protected: /// \brief Generate list of attributes of constraint in order useful for constraints /// \param[out] theValue numerical characteristic of constraint (e.g. distance) /// \param[out] theAttributes list of attributes to be filled - virtual void getAttributes(double& theValue, std::vector& theAttributes); + virtual void getAttributes(EntityWrapperPtr& theValue, + std::vector& theAttributes) override; }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintMiddle.cpp b/src/SketchSolver/SketchSolver_ConstraintMiddle.cpp index 69de3881e..6680004c8 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMiddle.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMiddle.cpp @@ -1,54 +1,64 @@ // Copyright (C) 2014-20xx CEA/DEN, EDF R&D #include +#include +#include -#include -#include - -#include - -SketchSolver_ConstraintMiddle::SketchSolver_ConstraintMiddle(ConstraintPtr theConstraint) - : SketchSolver_Constraint(theConstraint) +void SketchSolver_ConstraintMiddle::getAttributes( + EntityWrapperPtr& theValue, + std::vector& theAttributes) { + SketchSolver_Constraint::getAttributes(theValue, theAttributes); } -void SketchSolver_ConstraintMiddle::notifyCoincidenceChanged( - EntityWrapperPtr theCoincAttr1, - EntityWrapperPtr theCoincAttr2) +void SketchSolver_ConstraintMiddle::notify(const FeaturePtr& theFeature, + PlaneGCSSolver_Update* theUpdater) { - // Check the coincidence between point and line has been changed - AttributePtr aPoint; - FeaturePtr aLine; - EntityWrapperPtr anEntities[2] = {theCoincAttr1, theCoincAttr2}; - for (int i = 0; i < 2; ++i) { - if (anEntities[i]->type() == ENTITY_POINT) - aPoint = anEntities[i]->baseAttribute(); - else if (anEntities[i]->type() == ENTITY_LINE) - aLine = anEntities[i]->baseFeature(); - } - if (!aPoint || !aLine) - return; - - // Check the attributes of middle-point constraint are the same point and line - bool isSameAttr = true; - for (int i = 0; i < 2 && isSameAttr; ++i) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::ATTRIBUTE(i))); - if (!aRefAttr) - { - // It seems the Middle point constraint has been deleted, so keep it unchanged. - // It will be removed later. - return; + PlaneGCSSolver_UpdateCoincidence* anUpdater = + static_cast(theUpdater); + bool isAccepted = anUpdater->checkCoincidence(myAttributes.front(), myAttributes.back()); + if (isAccepted) { + if (!myInSolver) { + myInSolver = true; + + if (myMiddle) { + // remove previously adde constraint + myStorage->removeConstraint(myBaseConstraint); + // merge divided constraints into single object + std::list aGCSConstraints; + std::shared_ptr aConstraint = + std::dynamic_pointer_cast(myMiddle); + aGCSConstraints.push_back(aConstraint->constraints().front()); + aConstraint = + std::dynamic_pointer_cast(mySolverConstraint); + aGCSConstraints.push_back(aConstraint->constraints().front()); + + myMiddle = ConstraintWrapperPtr(); + mySolverConstraint = ConstraintWrapperPtr( + new PlaneGCSSolver_ConstraintWrapper(aGCSConstraints, CONSTRAINT_MIDDLE_POINT)); + } + + myStorage->addConstraint(myBaseConstraint, mySolverConstraint); } - if (aRefAttr->isObject()) { - FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); - isSameAttr = (aFeature == aLine); - } else - isSameAttr = (aRefAttr->attr() == aPoint); - } + } else { + if (myInSolver) { + myInSolver = false; + myStorage->removeConstraint(myBaseConstraint); + } + + if (!myMiddle) { + // divide solver constraints to the middle point and point-line coincidence + std::shared_ptr aConstraint = + std::dynamic_pointer_cast(mySolverConstraint); + std::list aGCSConstraints = aConstraint->constraints(); - if (isSameAttr) { - remove(); - process(); + myMiddle = ConstraintWrapperPtr( + new PlaneGCSSolver_ConstraintWrapper(aGCSConstraints.front(), CONSTRAINT_MIDDLE_POINT)); + mySolverConstraint = ConstraintWrapperPtr( + new PlaneGCSSolver_ConstraintWrapper(aGCSConstraints.back(), CONSTRAINT_MIDDLE_POINT)); + + // send middle constraint only + myStorage->addConstraint(myBaseConstraint, myMiddle); + } } } diff --git a/src/SketchSolver/SketchSolver_ConstraintMiddle.h b/src/SketchSolver/SketchSolver_ConstraintMiddle.h index bc0053b20..4d0805704 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMiddle.h +++ b/src/SketchSolver/SketchSolver_ConstraintMiddle.h @@ -7,23 +7,33 @@ #ifndef SketchSolver_ConstraintMiddle_H_ #define SketchSolver_ConstraintMiddle_H_ -#include +#include /** \class SketchSolver_ConstraintMiddle * \ingroup Plugins * \brief Converts middle-point constraint to the constraint applicable for solver */ -class SketchSolver_ConstraintMiddle : public SketchSolver_Constraint +class SketchSolver_ConstraintMiddle : public SketchSolver_ConstraintCoincidence { public: /// Constructor based on SketchPlugin constraint - SKETCHSOLVER_EXPORT SketchSolver_ConstraintMiddle(ConstraintPtr theConstraint); + SketchSolver_ConstraintMiddle(ConstraintPtr theConstraint) + : SketchSolver_ConstraintCoincidence(theConstraint) + {} - virtual ~SketchSolver_ConstraintMiddle() {} + /// \brief Notify this object about the feature is changed somewhere + virtual void notify(const FeaturePtr& theFeature, + PlaneGCSSolver_Update* theUpdater) override; - /// \brief Notify constraint, that coincidence appears or removed - virtual void notifyCoincidenceChanged(EntityWrapperPtr theCoincAttr1, - EntityWrapperPtr theCoincAttr2); +protected: + /// \brief Generate list of attributes of constraint in order useful for constraints + /// \param[out] theValue numerical characteristic of constraint (e.g. distance) + /// \param[out] theAttributes list of attributes to be filled + virtual void getAttributes(EntityWrapperPtr& theValue, + std::vector& theAttributes) override; + +private: + ConstraintWrapperPtr myMiddle; }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintMirror.cpp b/src/SketchSolver/SketchSolver_ConstraintMirror.cpp index c91121d76..6381b2bd3 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMirror.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMirror.cpp @@ -4,98 +4,89 @@ #include #include +#include + +#include +#include #include +#include +#include + + +static void mirrorPoints(const std::shared_ptr& theMirrorLine, + const AttributePoint2DPtr& theOriginal, + const AttributePoint2DPtr& theMirrored); + +static void mirrorEntities(const std::shared_ptr& theMirrorLine, + const FeaturePtr& theOriginal, + const FeaturePtr& theMirrored); + + void SketchSolver_ConstraintMirror::getAttributes( - EntityWrapperPtr& theMirrorLine, - std::vector& theBaseEntities, - std::vector& theMirrorEntities) + EntityWrapperPtr&, + std::vector&) { - AttributePtr aMirLineAttr = myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()); AttributeRefAttrPtr aMirLineRefAttr = - std::dynamic_pointer_cast(aMirLineAttr); + myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_A()); if (!aMirLineRefAttr || !aMirLineRefAttr->isInitialized() || !aMirLineRefAttr->isObject()) { myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); return; } + FeaturePtr aMirrorLine = ModelAPI_Feature::feature(aMirLineRefAttr->object()); + myFeatures.insert(aMirrorLine); + myType = TYPE(myBaseConstraint); - myStorage->update(aMirLineAttr/*, myGroupID*/); - theMirrorLine = myStorage->entity(aMirLineAttr); - - // Create SolveSpace entity for all features - AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); - AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_C())); + myStorage->update(aMirrorLine); + + + AttributeRefListPtr aBaseRefList = + myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_B()); + AttributeRefListPtr aMirroredRefList = + myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_C()); myNumberOfObjects = aMirroredRefList->size(); if (!aBaseRefList || !aMirroredRefList) { myErrorMsg = SketchSolver_Error::INCORRECT_MIRROR_ATTRIBUTE(); return; } - std::list aBaseList = aBaseRefList->list(); - std::list aMirroredList = aMirroredRefList->list(); - - FeaturePtr aFeature; - for (int i = 0; i < 2; i++) { - std::list::iterator anIter = i == 0 ? aBaseList.begin() : aMirroredList.begin(); - std::list::iterator aEndIter = i == 0 ? aBaseList.end() : aMirroredList.end(); - std::vector* aList = i == 0 ? &theBaseEntities : & theMirrorEntities; - for ( ; anIter != aEndIter; anIter++) { - aFeature = ModelAPI_Feature::feature(*anIter); - if (!aFeature) - continue; - - myStorage->update(aFeature, GID_UNKNOWN, true); - aList->push_back(myStorage->entity(aFeature)); + // store only original entities because mirrored ones + // will be updated separately in adjustConstraint + std::list aList = aBaseRefList->list(); + std::list::iterator anIt = aList.begin(); + for (; anIt != aList.end(); ++anIt) { + FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt); + if (aFeature) { + myStorage->update(aFeature); + myFeatures.insert(aFeature); } } - - if (theBaseEntities.size() > theMirrorEntities.size() || aMirroredList.empty()) - myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); + // add mirrored features to the list + aList = aMirroredRefList->list(); + for (anIt = aList.begin(); anIt != aList.end(); ++anIt) { + FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt); + if (aFeature) + myFeatures.insert(aFeature); + } } void SketchSolver_ConstraintMirror::process() { cleanErrorMsg(); - if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) { + if (!myBaseConstraint || !myStorage) { // Not enough parameters are assigned return; } EntityWrapperPtr aMirrorLine; std::vector aBaseList; - std::vector aMirrorList; - getAttributes(aMirrorLine, aBaseList, aMirrorList); + getAttributes(aMirrorLine, aBaseList); if (!myErrorMsg.empty()) return; - if (aBaseList.size() != aMirrorList.size()) { - myErrorMsg = SketchSolver_Error::INCORRECT_MIRROR_ATTRIBUTE(); - return; - } - - std::list aNewConstraints; - SketchSolver_ConstraintType aConstrType = getType(); - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - std::list aMirConstrList; - - // update mirrored features to be in the current group - std::vector::iterator aMIt = aMirrorList.begin(); - for (; aMIt != aMirrorList.end(); ++aMIt) - myStorage->update((*aMIt)->baseFeature(), myGroupID); - - std::vector::iterator aBIt = aBaseList.begin(); - for (aMIt = aMirrorList.begin(); aBIt != aBaseList.end(); ++aBIt, ++aMIt) { - aNewConstraints = aBuilder->createConstraint( - myBaseConstraint, myGroupID, mySketchID, aConstrType, - 0.0, *aBIt, *aMIt, aMirrorLine); - aMirConstrList.insert(aMirConstrList.end(), aNewConstraints.begin(), aNewConstraints.end()); - } - myStorage->addConstraint(myBaseConstraint, aMirConstrList); - adjustConstraint(); + myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateFeature::GROUP()); } @@ -110,9 +101,86 @@ void SketchSolver_ConstraintMirror::adjustConstraint() { BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - const std::list& aConstraints = myStorage->constraint(myBaseConstraint); - std::list::const_iterator aCIt = aConstraints.begin(); - for (; aCIt != aConstraints.end(); ++aCIt) - if ((*aCIt)->type() == CONSTRAINT_SYMMETRIC) - aBuilder->adjustConstraint(*aCIt); + AttributeRefAttrPtr aMirrLineRefAttr = + myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_A()); + std::shared_ptr aMirrorLine = + aBuilder->line(ModelAPI_Feature::feature(aMirrLineRefAttr->object())); + + AttributeRefListPtr aBaseRefList = + myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_B()); + AttributeRefListPtr aMirroredRefList = + myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_C()); + + std::list aBaseList = aBaseRefList->list(); + std::list aMirroredList = aMirroredRefList->list(); + std::list::iterator aBIt, aMIt; + for (aBIt = aBaseList.begin(), aMIt = aMirroredList.begin(); + aBIt != aBaseList.end() && aMIt != aMirroredList.end(); + ++aBIt, ++aMIt) { + FeaturePtr aBase = ModelAPI_Feature::feature(*aBIt); + FeaturePtr aMirrored = ModelAPI_Feature::feature(*aMIt); + mirrorEntities(aMirrorLine, aBase, aMirrored); + } +} + +void SketchSolver_ConstraintMirror::notify(const FeaturePtr& theFeature, + PlaneGCSSolver_Update*) +{ + if (myFeatures.find(theFeature) == myFeatures.end()) + return; // the feature is not used by constraint => nothing to update + adjustConstraint(); +} + +void SketchSolver_ConstraintMirror::blockEvents(bool isBlocked) +{ + std::set::iterator anIt = myFeatures.begin(); + for (; anIt != myFeatures.end(); ++anIt) + (*anIt)->data()->blockSendAttributeUpdated(isBlocked); + + SketchSolver_Constraint::blockEvents(isBlocked); +} + + + + +// ================= Auxiliary functions ================================== +void mirrorPoints(const std::shared_ptr& theMirrorLine, + const AttributePoint2DPtr& theOriginal, + const AttributePoint2DPtr& theMirrored) +{ + std::shared_ptr anOriginal = theOriginal->pnt(); + std::shared_ptr aPtOnLine = theMirrorLine->project(anOriginal); + std::shared_ptr aPerp = aPtOnLine->xy()->decreased(anOriginal->xy()); + theMirrored->setValue(anOriginal->x() + aPerp->x() * 2.0, anOriginal->y() + aPerp->y() * 2.0); +} + +void mirrorEntities(const std::shared_ptr& theMirrorLine, + const FeaturePtr& theOriginal, + const FeaturePtr& theMirrored) +{ + std::list aPoints0 = + theOriginal->data()->attributes(GeomDataAPI_Point2D::typeId()); + std::list aPoints1 = + theMirrored->data()->attributes(GeomDataAPI_Point2D::typeId()); + + // process specific features + if (theOriginal->getKind() == SketchPlugin_Arc::ID()) { + // orientation of arc + theMirrored->boolean(SketchPlugin_Arc::INVERSED_ID())->setValue( + !theOriginal->boolean(SketchPlugin_Arc::INVERSED_ID())->value()); + } else if (theOriginal->getKind() == SketchPlugin_Circle::ID()) { + // radius of the circle + theMirrored->real(SketchPlugin_Circle::RADIUS_ID())->setValue( + theOriginal->real(SketchPlugin_Circle::RADIUS_ID())->value()); + } + + // mirror all initialized points of features + std::list::iterator anIt0, anIt1; + for (anIt0 = aPoints0.begin(), anIt1 = aPoints1.begin(); + anIt0 != aPoints0.end() && anIt1 != aPoints1.end(); ++anIt0, ++anIt1) { + AttributePoint2DPtr aPt0 = std::dynamic_pointer_cast(*anIt0); + AttributePoint2DPtr aPt1 = std::dynamic_pointer_cast(*anIt1); + if (aPt0->isInitialized() && aPt1->isInitialized()) + mirrorPoints(theMirrorLine, aPt0, aPt1); + } } diff --git a/src/SketchSolver/SketchSolver_ConstraintMirror.h b/src/SketchSolver/SketchSolver_ConstraintMirror.h index 9986fc2a0..ead02ee24 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMirror.h +++ b/src/SketchSolver/SketchSolver_ConstraintMirror.h @@ -24,32 +24,28 @@ public: {} /// \brief Update constraint - virtual void update(); + virtual void update() override; + + /// \brief Notify this object about the feature is changed somewhere + virtual void notify(const FeaturePtr& theFeature, PlaneGCSSolver_Update*) override; + + /// \brief Block or unblock events from this constraint + virtual void blockEvents(bool isBlocked) override; protected: /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints - virtual void process(); - - /// \brief Generate list of attributes of constraint in order useful for constraints - /// \param[out] theValue numerical characteristic of constraint (e.g. distance) - /// \param[out] theAttributes list of attributes to be filled - virtual void getAttributes(double& theValue, std::vector& theAttributes) - { /* do nothing here */ } + virtual void process() override; /// \brief Generate list of entities of mirror constraint - /// \param[out] theMirrorLine entity corresponding to mirror line - /// \param[out] theBaseEntities list of entities to mirror - /// \param[out] theMirrorEntities list of mirrored entities - void getAttributes(EntityWrapperPtr& theMirrorLine, - std::vector& theBaseEntities, - std::vector& theMirrorEntities); + virtual void getAttributes(EntityWrapperPtr&, std::vector&) override; /// \brief This method is used in derived objects to check consistence of constraint. /// E.g. the distance between line and point may be signed. - virtual void adjustConstraint(); + virtual void adjustConstraint() override; private: size_t myNumberOfObjects; ///< number of previously mirrored objects + std::set myFeatures; ///< mirror line, original and mirrored features }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintMovement.cpp b/src/SketchSolver/SketchSolver_ConstraintMovement.cpp deleted file mode 100644 index 916b8d551..000000000 --- a/src/SketchSolver/SketchSolver_ConstraintMovement.cpp +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -#include -#include -#include - -#include -#include -#include -#include - -#include - - -void SketchSolver_ConstraintMovement::process() -{ - cleanErrorMsg(); - if (!myBaseFeature || !myStorage || myGroupID == GID_UNKNOWN) { - // Not enough parameters are initialized - return; - } - - ParameterWrapperPtr aValue; - getAttributes(aValue, myMovedEntities); - if (!myErrorMsg.empty() || myMovedEntities.empty()) { - // Nothing to move, clear the feature to avoid changing its group - // after removing the Movement constraint. - myBaseFeature = FeaturePtr(); - return; - } - - std::vector::iterator anEntIt = myMovedEntities.begin(); - for (; anEntIt != myMovedEntities.end(); ++anEntIt) - fixFeature(*anEntIt); -} - - -static std::list movedEntities( - EntityWrapperPtr theOld, StoragePtr theOldStorage, - EntityWrapperPtr theNew, StoragePtr theNewStorage) -{ - bool isFullyMoved = true; - std::list aMoved; - if (theOld->isEqual(theNew)) - return aMoved; - - std::list anOldSubs = theOld->subEntities(); - std::list aNewSubs = theNew->subEntities(); - std::list::const_iterator anOldIt = anOldSubs.begin(); - std::list::const_iterator aNewIt = aNewSubs.begin(); - for (; anOldIt != anOldSubs.end() && aNewIt != aNewSubs.end(); ++anOldIt, ++aNewIt) { - std::list aMovedSubs = movedEntities( - *anOldIt, theOldStorage, *aNewIt, theNewStorage); - // check only the points to be moved (because arcs in PlaneGCS have scalar subs too) - if ((*anOldIt)->type() == ENTITY_POINT && - (aMovedSubs.size() != 1 || aMovedSubs.front() != *anOldIt)) - isFullyMoved = false; - aMoved.insert(aMoved.end(), aMovedSubs.begin(), aMovedSubs.end()); - } - if (isFullyMoved) { - aMoved.clear(); - aMoved.push_back(theOld); - } - return aMoved; -} - - -void SketchSolver_ConstraintMovement::getAttributes( - ParameterWrapperPtr& theValue, - std::vector& theAttributes) -{ - // There will be build entities, according to the fixed feature, in the separate storage - // to check whether any point is moved - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - StoragePtr anOtherStorage = aBuilder->createStorage(myGroupID); - anOtherStorage->setSketch(myStorage->sketch()); - if (!anOtherStorage->update(myBaseFeature, myGroupID)) - return; - EntityWrapperPtr aNewEntity = anOtherStorage->entity(myBaseFeature); - EntityWrapperPtr anOldEntity = myStorage->entity(myBaseFeature); - - std::list aMoved; - if (aNewEntity && anOldEntity) - aMoved = movedEntities(anOldEntity, myStorage, aNewEntity, anOtherStorage); - else { - // get attributes moved - std::list anAttrList = - myBaseFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); - std::list::const_iterator anIt = anAttrList.begin(); - for (; anIt != anAttrList.end(); ++anIt) { - aNewEntity = anOtherStorage->entity(*anIt); - anOldEntity = myStorage->entity(*anIt); - if (!aNewEntity || !anOldEntity) - continue; - std::list aMovedAttr = movedEntities( - anOldEntity, myStorage, aNewEntity, anOtherStorage); - aMoved.insert(aMoved.end(), aMovedAttr.begin(), aMovedAttr.end()); - } - } - theAttributes.clear(); - theAttributes.insert(theAttributes.begin(), aMoved.begin(), aMoved.end()); -} - -bool SketchSolver_ConstraintMovement::remove() -{ - cleanErrorMsg(); - // Move fixed entities back to the current group - std::vector::iterator aMoveIt = myMovedEntities.begin(); - for (; aMoveIt != myMovedEntities.end(); ++aMoveIt) { - if ((*aMoveIt)->baseAttribute()) - myStorage->update((*aMoveIt)->baseAttribute(), myGroupID); - else if ((*aMoveIt)->baseFeature()) - myStorage->update((*aMoveIt)->baseFeature(), myGroupID); - } - - // Remove base feature - if (myBaseFeature) - myStorage->removeEntity(myBaseFeature); - return true; -} diff --git a/src/SketchSolver/SketchSolver_ConstraintMovement.h b/src/SketchSolver/SketchSolver_ConstraintMovement.h deleted file mode 100644 index 63211fa4f..000000000 --- a/src/SketchSolver/SketchSolver_ConstraintMovement.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: SketchSolver_ConstraintMovement.h -// Created: 15 Jun 2015 -// Author: Artem ZHIDKOV - -#ifndef SketchSolver_ConstraintMovement_H_ -#define SketchSolver_ConstraintMovement_H_ - -#include "SketchSolver.h" -#include - -/** \class SketchSolver_ConstraintMovement - * \ingroup Plugins - * \brief Stores data to the Fixed constraint for the moved feature only - */ -class SketchSolver_ConstraintMovement : public SketchSolver_ConstraintFixed -{ -private: - /// Creates constraint to manage the given constraint from plugin - SketchSolver_ConstraintMovement(ConstraintPtr theConstraint) - : SketchSolver_ConstraintFixed(theConstraint) - {} - -public: - /// Creates temporary constraint based on feature - SketchSolver_ConstraintMovement(FeaturePtr theFeature) - : SketchSolver_ConstraintFixed(theFeature) - {} - - /// \brief Tries to remove constraint - /// \return \c false, if current constraint contains another SketchPlugin - /// constraints (like for multiple coincidence) - virtual bool remove(); - -protected: - /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints - virtual void process(); - - /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints - /// \param[out] theValue numerical characteristic of constraint (e.g. distance) - /// \param[out] theAttributes list of attributes to be filled - /// (list of moved entities or attributes) - virtual void getAttributes(ParameterWrapperPtr& theValue, - std::vector& theAttributes); - -private: - std::vector myMovedEntities; ///< list of entities that are moved -}; - -#endif diff --git a/src/SketchSolver/SketchSolver_ConstraintMulti.cpp b/src/SketchSolver/SketchSolver_ConstraintMulti.cpp index a86ab8b5f..4ca7e088b 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMulti.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMulti.cpp @@ -17,18 +17,17 @@ void SketchSolver_ConstraintMulti::getEntities(std::list& theEntities) { myAdjusted = false; - DataPtr aData = myBaseConstraint->data(); // Lists of objects and number of copies - AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Constraint::ENTITY_A())); + AttributeRefListPtr anInitialRefList = + myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_A()); myNumberOfObjects = anInitialRefList->size(); - myNumberOfCopies = aData->integer(nameNbObjects())->value() - 1; + myNumberOfCopies = myBaseConstraint->integer(nameNbObjects())->value() - 1; if (myNumberOfCopies <= 0) return; - AttributeRefListPtr aRefList = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_Constraint::ENTITY_B())); + AttributeRefListPtr aRefList = + myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_B()); if (!aRefList || aRefList->size() == 0) { myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); return; @@ -48,7 +47,7 @@ void SketchSolver_ConstraintMulti::getEntities(std::list& theE // the entity is not created, so it is a copy in "multi" constraint, force its creation if (!myStorage->update(aFeature)) - myStorage->update(aFeature, myGroupID, true); + myStorage->update(aFeature, true); theEntities.push_back(myStorage->entity(aFeature)); myFeatures.insert(aFeature); for (int i = 0; i < myNumberOfCopies && anObjIt != anObjectList.end(); ++i, ++anObjIt) { @@ -62,20 +61,17 @@ void SketchSolver_ConstraintMulti::getEntities(std::list& theE bool SketchSolver_ConstraintMulti::remove() { + myStorage->unsubscribeUpdates(this); + myFeatures.clear(); return SketchSolver_Constraint::remove(); } void SketchSolver_ConstraintMulti::update() -{ - update(false); -} - -void SketchSolver_ConstraintMulti::update(bool isForce) { cleanErrorMsg(); - AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + AttributeRefListPtr anInitialRefList = + myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_A()); AttributeIntegerPtr aNbObjects = myBaseConstraint->integer(nameNbObjects()); if (!anInitialRefList || !aNbObjects) return; // the "Multi" constraint is in queue to remove @@ -83,8 +79,8 @@ void SketchSolver_ConstraintMulti::update(bool isForce) anInitialRefList->size() != myNumberOfObjects || aNbObjects->value()-1 != myNumberOfCopies; if (!isUpdated) { // additional check that the features and their copies are changed - AttributeRefListPtr aRefList = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + AttributeRefListPtr aRefList = + myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_B()); if (aRefList && aRefList->size() != 0) { FeaturePtr aFeature; std::list anObjectList = aRefList->list(); @@ -102,26 +98,21 @@ void SketchSolver_ConstraintMulti::update(bool isForce) if (isUpdated) { remove(); process(); - return; } - - // update derivative object - updateLocal(); - if (isForce) - myAdjusted = false; - adjustConstraint(); } void SketchSolver_ConstraintMulti::adjustConstraint() { - AttributeRefListPtr aRefList = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); + AttributeRefListPtr aRefList = + myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_B()); if (!aRefList || aRefList->size() == 0) { myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); return; } FeaturePtr anOriginal, aFeature; + std::list::iterator aXIt, aYIt; + std::list anObjectList = aRefList->list(); std::list::iterator anObjIt = anObjectList.begin(); while (anObjIt != anObjectList.end()) { @@ -131,25 +122,19 @@ void SketchSolver_ConstraintMulti::adjustConstraint() // Fill lists of coordinates of points composing a feature std::list aX, aY; - std::list::iterator aXIt, aYIt; double aXCoord, aYCoord; - EntityWrapperPtr anEntity = myStorage->entity(anOriginal); - std::list aSubs = anEntity->subEntities(); - std::list::const_iterator aSIt = aSubs.begin(); - for (; aSIt != aSubs.end(); ++aSIt) { - if ((*aSIt)->type() != ENTITY_POINT) - continue; - AttributePoint2DPtr aPoint = - std::dynamic_pointer_cast((*aSIt)->baseAttribute()); - if (aPoint) { - aXCoord = aPoint->x(); - aYCoord = aPoint->y(); - } else { - std::list aParameters = (*aSIt)->parameters(); - aXCoord = aParameters.front()->value(); - aYCoord = aParameters.back()->value(); - } - getRelative(aXCoord, aYCoord, aXCoord, aYCoord); + std::list aPoints = + anOriginal->data()->attributes(GeomDataAPI_Point2D::typeId()); + std::list::iterator aPtIt = aPoints.begin(); + for (; aPtIt != aPoints.end(); ++aPtIt) { + AttributePoint2DPtr aPoint2D = std::dynamic_pointer_cast(*aPtIt); + if (aPoint2D->isInitialized()) { + aXCoord = aPoint2D->x(); + aYCoord = aPoint2D->y(); + getRelative(aXCoord, aYCoord, aXCoord, aYCoord); + } else + aXCoord = aYCoord = 0; + aX.push_back(aXCoord); aY.push_back(aYCoord); } @@ -159,78 +144,51 @@ void SketchSolver_ConstraintMulti::adjustConstraint() aFeature = ModelAPI_Feature::feature(*anObjIt); if (!aFeature) continue; - anEntity = myStorage->entity(aFeature); - - bool aWasBlocked = false; - if (!anEntity || !myStorage->isEventsBlocked()) - aWasBlocked = aFeature->data()->blockSendAttributeUpdated(true); - - std::list aPoints; - if (aFeature->getKind() == SketchPlugin_Arc::ID()) { - aPoints.push_back(aFeature->attribute(SketchPlugin_Arc::CENTER_ID())); - aPoints.push_back(aFeature->attribute(SketchPlugin_Arc::START_ID())); - aPoints.push_back(aFeature->attribute(SketchPlugin_Arc::END_ID())); - } else if (aFeature->getKind() == SketchPlugin_Line::ID()) { - aPoints.push_back(aFeature->attribute(SketchPlugin_Line::START_ID())); - aPoints.push_back(aFeature->attribute(SketchPlugin_Line::END_ID())); - } else if (aFeature->getKind() == SketchPlugin_Circle::ID()) { - aPoints.push_back(aFeature->attribute(SketchPlugin_Circle::CENTER_ID())); - // update circle's radius + + if (myIsEventsBlocked) + aFeature->data()->blockSendAttributeUpdated(true); + + if (aFeature->getKind() == SketchPlugin_Circle::ID()) // update circle's radius aFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue( anOriginal->real(SketchPlugin_Circle::RADIUS_ID())->value()); - } else if (aFeature->getKind() == SketchPlugin_Point::ID() || - aFeature->getKind() == SketchPlugin_IntersectionPoint::ID()) - aPoints.push_back(aFeature->attribute(SketchPlugin_Point::COORD_ID())); - std::list::iterator aPtIt = aPoints.begin(); - for (aXIt = aX.begin(), aYIt = aY.begin(); aPtIt != aPoints.end(); ++aXIt, ++aYIt, ++aPtIt) { + aPoints = aFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); + for (aPtIt = aPoints.begin(), aXIt = aX.begin(), aYIt = aY.begin(); + aPtIt != aPoints.end(); ++aXIt, ++aYIt, ++aPtIt) { + if (!(*aPtIt)->isInitialized()) + continue; transformRelative(*aXIt, *aYIt); getAbsolute(*aXIt, *aYIt, aXCoord, aYCoord); - std::shared_ptr aPoint2D = + AttributePoint2DPtr aPoint2D = std::dynamic_pointer_cast(*aPtIt); aPoint2D->setValue(aXCoord, aYCoord); } - - // update feature in the storage if it is used by another constraints - if (anEntity) - myStorage->update(aFeature); - else { // update attributes, if they exist in the storage - for (aPtIt = aPoints.begin(); aPtIt != aPoints.end(); ++aPtIt) { - EntityWrapperPtr aPntEnt = myStorage->entity(*aPtIt); - if (aPntEnt) - myStorage->update(*aPtIt); - } - } - - if (!anEntity || !myStorage->isEventsBlocked()) - aFeature->data()->blockSendAttributeUpdated(aWasBlocked); } } myAdjusted = true; } -bool SketchSolver_ConstraintMulti::isUsed(FeaturePtr theFeature) const +void SketchSolver_ConstraintMulti::notify(const FeaturePtr& theFeature, + PlaneGCSSolver_Update*) { - return theFeature && (myFeatures.find(theFeature) != myFeatures.end() || - SketchSolver_Constraint::isUsed(theFeature)); + if (myFeatures.find(theFeature) == myFeatures.end()) + return; // the feature is not used by constraint => nothing to update + + // update derivative object + updateLocal(); + myAdjusted = false; + adjustConstraint(); } -bool SketchSolver_ConstraintMulti::isUsed(AttributePtr theAttribute) const +void SketchSolver_ConstraintMulti::blockEvents(bool isBlocked) { - AttributePtr anAttribute = theAttribute; - AttributeRefAttrPtr aRefAttr = - std::dynamic_pointer_cast(anAttribute); - if (aRefAttr) { - if (aRefAttr->isObject()) - return isUsed(ModelAPI_Feature::feature(aRefAttr->object())); - else - anAttribute = aRefAttr->attr(); - } - if (!anAttribute) - return false; + myIsEventsBlocked = isBlocked; + + std::set::iterator anIt = myFeatures.begin(); + for (; anIt != myFeatures.end(); ++anIt) + (*anIt)->data()->blockSendAttributeUpdated(isBlocked); - FeaturePtr anOwner = ModelAPI_Feature::feature(anAttribute->owner()); - return myFeatures.find(anOwner) != myFeatures.end(); + SketchSolver_Constraint::blockEvents(isBlocked); } diff --git a/src/SketchSolver/SketchSolver_ConstraintMulti.h b/src/SketchSolver/SketchSolver_ConstraintMulti.h index 7a9edc96e..ea311e90d 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMulti.h +++ b/src/SketchSolver/SketchSolver_ConstraintMulti.h @@ -24,41 +24,39 @@ public: SketchSolver_Constraint(theConstraint), myNumberOfObjects(0), myNumberOfCopies(0), + myIsFullValue(false), myAdjusted(false), - myIsFullValue(false) + myIsEventsBlocked(false) {} /// \brief Update constraint - virtual void update(); - /// \brief Update constraint - void update(bool isForce); + virtual void update() override; + + /// \brief Notify this object about the feature is changed somewhere + virtual void notify(const FeaturePtr& theFeature, PlaneGCSSolver_Update*) override; /// \brief Tries to remove constraint /// \return \c false, if current constraint contains another SketchPlugin /// constraints (like for multiple coincidence) - virtual bool remove(); + virtual bool remove() override; - /// \brief Check the feature is a source or a copy of Multi-constraint - virtual bool isUsed(FeaturePtr theFeature) const; - /// \brief Check the attribute is used in Multi-constraint - virtual bool isUsed(AttributePtr theAttribute) const; + /// \brief Block or unblock events from this constraint + virtual void blockEvents(bool isBlocked) override; protected: /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints - virtual void process() + virtual void process() override { /* do nothing here */ } - /// \brief Collect entities which translated or rotated (not their copies) + /// \brief Collect entities which are translated or rotated (not their copies) void getEntities(std::list& theEntities); /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints - /// \param[out] theValue numerical characteristic of constraint (e.g. distance) - /// \param[out] theAttributes list of attributes to be filled - virtual void getAttributes(double& theValue, std::vector& theAttributes) + virtual void getAttributes(EntityWrapperPtr&, std::vector&) override { /* do nothing here */ } /// \brief This method is used in derived objects to check consistence of constraint. - virtual void adjustConstraint(); + virtual void adjustConstraint() override; /// \brief Update parameters of derived classes virtual void updateLocal() = 0; @@ -83,6 +81,8 @@ protected: /// list of features and their copies to find whether some of them are disappeared std::set myFeatures; + + bool myIsEventsBlocked; }; #endif diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp index 910bdaf4f..5d857e914 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp @@ -4,21 +4,27 @@ #include #include +#include +#include +#include +#include + #include #include -#include +#include void SketchSolver_ConstraintMultiRotation::getAttributes( - EntityWrapperPtr& theCenter, double& theAngle, + EntityWrapperPtr& theCenter, EntityWrapperPtr& theAngle, bool& theFullValue, std::list& theEntities) { - DataPtr aData = myBaseConstraint->data(); - theAngle = std::dynamic_pointer_cast( - aData->attribute(SketchPlugin_MultiRotation::ANGLE_ID()))->value(); + AttributePtr anAngleAttr = myBaseConstraint->attribute(SketchPlugin_MultiRotation::ANGLE_ID()); + PlaneGCSSolver_AttributeBuilder aValueBuilder; + theAngle = aValueBuilder.createAttribute(anAngleAttr); + myStorage->addEntity(anAngleAttr, theAngle); - AttributePtr aCenterAttr = aData->attribute(SketchPlugin_MultiRotation::CENTER_ID()); + AttributePtr aCenterAttr = myBaseConstraint->attribute(SketchPlugin_MultiRotation::CENTER_ID()); if (!aCenterAttr || !aCenterAttr->isInitialized()) { myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); return; @@ -29,7 +35,8 @@ void SketchSolver_ConstraintMultiRotation::getAttributes( myStorage->update(aCenterAttr); theCenter = myStorage->entity(aCenterAttr); - AttributeStringPtr aMethodTypeAttr = aData->string(SketchPlugin_MultiRotation::ANGLE_TYPE()); + AttributeStringPtr aMethodTypeAttr = + myBaseConstraint->string(SketchPlugin_MultiRotation::ANGLE_TYPE()); theFullValue = aMethodTypeAttr->value() != "SingleAngle"; getEntities(theEntities); @@ -38,39 +45,30 @@ void SketchSolver_ConstraintMultiRotation::getAttributes( void SketchSolver_ConstraintMultiRotation::process() { cleanErrorMsg(); - if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) { - /// TODO: Put error message here + if (!myBaseConstraint || !myStorage) { + // Not enough parameters are assigned return; } + EntityWrapperPtr anAngle; EntityWrapperPtr aRotationCenter; bool isFullValue; std::list aBaseEntities; - getAttributes(aRotationCenter, myAngle, isFullValue, aBaseEntities); + getAttributes(aRotationCenter, anAngle, isFullValue, aBaseEntities); if (!myErrorMsg.empty()) return; - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - std::list aRotConstraints; - - std::list::iterator anEntIt = aBaseEntities.begin(); - for (; anEntIt != aBaseEntities.end(); ++anEntIt) { - std::list aNewConstraints = - aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID, myType, - myAngle, isFullValue, aRotationCenter, EntityWrapperPtr(), - std::list(1, *anEntIt)); - aRotConstraints.insert(aRotConstraints.end(), aNewConstraints.begin(), aNewConstraints.end()); - } - myStorage->addConstraint(myBaseConstraint, aRotConstraints); - + ScalarWrapperPtr anAngleVal = std::dynamic_pointer_cast(anAngle); + myAngle = anAngleVal->value(); myAdjusted = false; adjustConstraint(); + + myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateFeature::GROUP()); } void SketchSolver_ConstraintMultiRotation::updateLocal() { - double aValue = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_MultiRotation::ANGLE_ID()))->value(); + double aValue = myBaseConstraint->real(SketchPlugin_MultiRotation::ANGLE_ID())->value(); if (fabs(myAngle - aValue) > tolerance) myAdjusted = false; // update angle value @@ -90,38 +88,8 @@ void SketchSolver_ConstraintMultiRotation::updateLocal() if (isMethodChanged) myIsFullValue = aFullValue; - if (aCenterPointChanged || isMethodChanged) { - DataPtr aData = myBaseConstraint->data(); - std::list aConstraints = myStorage->constraint(myBaseConstraint); - std::list::const_iterator anIt = aConstraints.begin(), - aLast = aConstraints.end(); - std::list anEntities; - for (; anIt != aLast; anIt++) { - ConstraintWrapperPtr aConstraint = *anIt; - aConstraint->setIsFullValue(myIsFullValue); - if (aCenterPointChanged) { - anEntities.clear(); - const std::list& aConstraintEntities = aConstraint->entities(); - std::list::const_iterator aSIt = aConstraintEntities.begin(), - aSLast = aConstraintEntities.end(); - EntityWrapperPtr aCenterPointEntity = *aSIt++; - if (aCenterPointChanged) { - AttributePtr aCenterPointAttr = aData->attribute(SketchPlugin_MultiRotation::CENTER_ID()); - myStorage->update(aCenterPointAttr); - aCenterPointEntity = myStorage->entity(aCenterPointAttr); - } - anEntities.push_back(aCenterPointEntity); - - for (; aSIt != aSLast; ++aSIt) - anEntities.push_back(*aSIt); - - aConstraint->setEntities(anEntities); - } - } - myStorage->addConstraint(myBaseConstraint, aConstraints); - + if (aCenterPointChanged || isMethodChanged) myAdjusted = false; - } } void SketchSolver_ConstraintMultiRotation::adjustConstraint() @@ -134,17 +102,13 @@ void SketchSolver_ConstraintMultiRotation::adjustConstraint() return; } - const std::list& aConstraints = myStorage->constraint(myBaseConstraint); - std::list::const_iterator aCIt = aConstraints.begin(); - for (; aCIt != aConstraints.end(); ++aCIt) - (*aCIt)->setValue(myAngle); - // Obtain coordinates of rotation center - EntityWrapperPtr aRotCenter = myStorage->entity( - myBaseConstraint->attribute(SketchPlugin_MultiRotation::CENTER_ID())); - std::list aParams = aRotCenter->parameters(); - myCenterCoord[0] = aParams.front()->value(); - myCenterCoord[1] = aParams.back()->value(); + std::shared_ptr aRotCenter = + std::dynamic_pointer_cast(myStorage->entity( + myBaseConstraint->attribute(SketchPlugin_MultiRotation::CENTER_ID()))); + GCSPointPtr aCenterPoint = aRotCenter->point(); + myCenterCoord[0] = *(aCenterPoint->x); + myCenterCoord[1] = *(aCenterPoint->y); double anAngleValue = myAngle; if (myIsFullValue && myNumberOfCopies > 0) diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h index 10087cc67..7a8daf78d 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h +++ b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h @@ -26,32 +26,36 @@ public: protected: /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints - virtual void process(); + virtual void process() override; /// \brief Generate list of rotated entities /// \param[out] theCenter central point of rotation /// \param[out] theAngle rotation angle /// \param[out] theFullValue applying translation using the disstance as a full or single value /// \param[out] theEntities list of base entities - void getAttributes(EntityWrapperPtr& theCenter, double& theAngle, bool& theFullValue, + void getAttributes(EntityWrapperPtr& theCenter, + EntityWrapperPtr& theAngle, + bool& theFullValue, std::list& theEntities); /// \brief This method is used in derived objects to check consistence of constraint. - virtual void adjustConstraint(); + virtual void adjustConstraint() override; /// \brief Update parameters (called from base class) - virtual void updateLocal(); + virtual void updateLocal() override; private: /// \brief Convert absolute coordinates to relative coordinates - virtual void getRelative(double theAbsX, double theAbsY, double& theRelX, double& theRelY); + virtual void getRelative(double theAbsX, double theAbsY, + double& theRelX, double& theRelY) override; /// \brief Convert relative coordinates to absolute coordinates - virtual void getAbsolute(double theRelX, double theRelY, double& theAbsX, double& theAbsY); + virtual void getAbsolute(double theRelX, double theRelY, + double& theAbsX, double& theAbsY) override; /// \brief Apply transformation for relative coordinates - virtual void transformRelative(double& theX, double& theY); + virtual void transformRelative(double& theX, double& theY) override; /// \brief Returns name of NUMBER_OF_COPIES parameter for corresponding feature - virtual const std::string& nameNbObjects(); + virtual const std::string& nameNbObjects() override; private: AttributePoint2DPtr myCenterPointAttribute; ///< a center of rotation diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp index 4f1741e76..5244ec6a4 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include @@ -39,8 +41,8 @@ void SketchSolver_ConstraintMultiTranslation::getAttributes( void SketchSolver_ConstraintMultiTranslation::process() { cleanErrorMsg(); - if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) { - /// TODO: Put error message here + if (!myBaseConstraint || !myStorage) { + // Not enough parameters are assigned return; } @@ -51,25 +53,10 @@ void SketchSolver_ConstraintMultiTranslation::process() if (!myErrorMsg.empty()) return; - AttributeStringPtr aMethodTypeAttr = - myBaseConstraint->data()->string(SketchPlugin_MultiTranslation::VALUE_TYPE()); - - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - std::list aTransConstraints; - - std::list::iterator anEntIt = aBaseEntities.begin(); - for (; anEntIt != aBaseEntities.end(); ++anEntIt) { - std::list aNewConstraints = - aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID, myType, - 0.0, aFullValue, aStartPoint, aEndPoint, std::list(1, *anEntIt)); - aTransConstraints.insert(aTransConstraints.end(), - aNewConstraints.begin(), aNewConstraints.end()); - } - - myStorage->addConstraint(myBaseConstraint, aTransConstraints); - myAdjusted = false; adjustConstraint(); + + myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateFeature::GROUP()); } const std::string& SketchSolver_ConstraintMultiTranslation::nameNbObjects() @@ -98,47 +85,8 @@ void SketchSolver_ConstraintMultiTranslation::updateLocal() if (isMethodChanged) myIsFullValue = aFullValue; - if (aStartPointChanged || anEndPointChanged || isMethodChanged) { - DataPtr aData = myBaseConstraint->data(); - std::list aConstraints = myStorage->constraint(myBaseConstraint); - std::list::const_iterator anIt = aConstraints.begin(), - aLast = aConstraints.end(); - std::list anEntities; - for (; anIt != aLast; anIt++) { - ConstraintWrapperPtr aConstraint = *anIt; - aConstraint->setIsFullValue(myIsFullValue); - anEntities.clear(); - - const std::list& aConstraintEntities = aConstraint->entities(); - std::list::const_iterator aSIt = aConstraintEntities.begin(), - aSLast = aConstraintEntities.end(); - EntityWrapperPtr aStartEntity = *aSIt++; - if (aStartPointChanged) { - AttributePtr aStartPointAttr = - aData->attribute(SketchPlugin_MultiTranslation::START_POINT_ID()); - myStorage->update(aStartPointAttr); - aStartEntity = myStorage->entity(aStartPointAttr); - } - anEntities.push_back(aStartEntity); - - EntityWrapperPtr anEndEntity = *aSIt++; - if (anEndPointChanged) { - AttributePtr anEndPointAttr = - aData->attribute(SketchPlugin_MultiTranslation::END_POINT_ID()); - myStorage->update(anEndPointAttr); - anEndEntity = myStorage->entity(anEndPointAttr); - } - anEntities.push_back(anEndEntity); - - for (; aSIt != aSLast; ++aSIt) - anEntities.push_back(*aSIt); - - aConstraint->setEntities(anEntities); - } - myStorage->addConstraint(myBaseConstraint, aConstraints); - + if (aStartPointChanged || anEndPointChanged || isMethodChanged) myAdjusted = false; - } } void SketchSolver_ConstraintMultiTranslation::adjustConstraint() @@ -147,15 +95,18 @@ void SketchSolver_ConstraintMultiTranslation::adjustConstraint() return; // Obtain delta between start and end points of translation - EntityWrapperPtr aStart = myStorage->entity( - myBaseConstraint->attribute(SketchPlugin_MultiTranslation::START_POINT_ID())); - std::list aStartParams = aStart->parameters(); - EntityWrapperPtr aEnd = myStorage->entity( - myBaseConstraint->attribute(SketchPlugin_MultiTranslation::END_POINT_ID())); - std::list aEndParams = aEnd->parameters(); - - myDelta[0] = aEndParams.front()->value() - aStartParams.front()->value(); - myDelta[1] = aEndParams.back()->value() - aStartParams.back()->value(); + std::shared_ptr aStartWrapper = + std::dynamic_pointer_cast(myStorage->entity( + myBaseConstraint->attribute(SketchPlugin_MultiTranslation::START_POINT_ID()))); + std::shared_ptr aEndWrapper = + std::dynamic_pointer_cast(myStorage->entity( + myBaseConstraint->attribute(SketchPlugin_MultiTranslation::END_POINT_ID()))); + + GCSPointPtr aStart = aStartWrapper->point(); + GCSPointPtr aEnd = aEndWrapper->point(); + + myDelta[0] = *(aEnd->x) - *(aStart->x); + myDelta[1] = *(aEnd->y) - *(aStart->y); if (myIsFullValue && myNumberOfCopies > 0) { myDelta[0] /= myNumberOfCopies; diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h index 7c93d6d0e..60e70f21c 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h +++ b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h @@ -26,7 +26,7 @@ public: protected: /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints - virtual void process(); + virtual void process() override; /// \brief Generate list of translated entities /// \param[out] theStartPoint start point of translation @@ -37,21 +37,23 @@ protected: bool& theFullValue, std::list& theEntities); /// \brief This method is used in derived objects to check consistence of constraint. - virtual void adjustConstraint(); + virtual void adjustConstraint() override; /// \brief Update parameters (called from base class) - virtual void updateLocal(); + virtual void updateLocal() override; private: /// \brief Convert absolute coordinates to relative coordinates - virtual void getRelative(double theAbsX, double theAbsY, double& theRelX, double& theRelY); + virtual void getRelative(double theAbsX, double theAbsY, + double& theRelX, double& theRelY) override; /// \brief Convert relative coordinates to absolute coordinates - virtual void getAbsolute(double theRelX, double theRelY, double& theAbsX, double& theAbsY); + virtual void getAbsolute(double theRelX, double theRelY, + double& theAbsX, double& theAbsY) override; /// \brief Apply transformation for relative coordinates - virtual void transformRelative(double& theX, double& theY); + virtual void transformRelative(double& theX, double& theY) override; /// \brief Returns name of NUMBER_OF_COPIES parameter for corresponding feature - virtual const std::string& nameNbObjects(); + virtual const std::string& nameNbObjects() override; private: AttributePoint2DPtr myStartPointAttribute; diff --git a/src/SketchSolver/SketchSolver_ConstraintTangent.cpp b/src/SketchSolver/SketchSolver_ConstraintTangent.cpp index 690587ae2..2a7b52a87 100644 --- a/src/SketchSolver/SketchSolver_ConstraintTangent.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintTangent.cpp @@ -6,38 +6,32 @@ #include #include +#include #include -/// \brief Check whether the entities has only one shared point -static bool hasSingleCoincidence(EntityWrapperPtr theEntity1, EntityWrapperPtr theEntity2) +/// \brief Check whether the entities has only one shared point or less +static bool hasSingleCoincidence(FeaturePtr theFeature1, FeaturePtr theFeature2) { - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - - const std::list& aPoints1 = theEntity1->subEntities(); - const std::list& aPoints2 = theEntity2->subEntities(); - - std::list::const_iterator aStartIt1 = aPoints1.begin(); - if (theEntity1->type() == ENTITY_ARC) ++aStartIt1; // skip center of arc - std::list::const_iterator aStartIt2 = aPoints2.begin(); - if (theEntity2->type() == ENTITY_ARC) ++aStartIt2; // skip center of arc - - int aNbCoinc = 0; - std::list::const_iterator anIt1, anIt2; - for (anIt1 = aStartIt1; anIt1 != aPoints1.end(); ++anIt1) { - if ((*anIt1)->type() != ENTITY_POINT) - continue; - std::shared_ptr aPt1 = aBuilder->point(*anIt1); - for (anIt2 = aStartIt2; anIt2 != aPoints2.end(); ++anIt2) { - if ((*anIt2)->type() != ENTITY_POINT) - continue; - std::shared_ptr aPt2 = aBuilder->point(*anIt2); - if (aPt1->distance(aPt2) < tolerance) - ++aNbCoinc; - } + const std::set& aRefs1 = theFeature1->data()->refsToMe(); + const std::set& aRefs2 = theFeature2->data()->refsToMe(); + + // collect all shared coincidendes + std::set aCoincidences; + std::set::const_iterator anIt; + for (anIt = aRefs1.begin(); anIt != aRefs1.end(); ++anIt) { + FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner()); + if (aRef && aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID()) + aCoincidences.insert(aRef); } - return aNbCoinc == 1; + for (anIt = aRefs2.begin(); anIt != aRefs2.end(); ++anIt) { + FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner()); + if (aRef) + aCoincidences.erase(aRef); + } + + return aCoincidences.size() <= 1; } /// \brief Check if two connected arcs have centers @@ -50,7 +44,7 @@ static bool isInternalTangency(EntityWrapperPtr theEntity1, EntityWrapperPtr the void SketchSolver_ConstraintTangent::getAttributes( - double& theValue, + EntityWrapperPtr& theValue, std::vector& theAttributes) { SketchSolver_Constraint::getAttributes(theValue, theAttributes); @@ -97,9 +91,15 @@ void SketchSolver_ConstraintTangent::getAttributes( return; } - if (myType == CONSTRAINT_TANGENT_ARC_LINE && - !hasSingleCoincidence(theAttributes[2], theAttributes[3])) - myErrorMsg = SketchSolver_Error::TANGENCY_FAILED(); + if (myType == CONSTRAINT_TANGENT_ARC_LINE) { + AttributeRefAttrPtr aRefAttr = myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_A()); + FeaturePtr aFeature1 = ModelAPI_Feature::feature(aRefAttr->object()); + aRefAttr = myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_B()); + FeaturePtr aFeature2 = ModelAPI_Feature::feature(aRefAttr->object()); + + if (!hasSingleCoincidence(aFeature1, aFeature2)) + myErrorMsg = SketchSolver_Error::TANGENCY_FAILED(); + } if (isSwap) { EntityWrapperPtr aTemp = theAttributes[2]; @@ -110,29 +110,13 @@ void SketchSolver_ConstraintTangent::getAttributes( void SketchSolver_ConstraintTangent::adjustConstraint() { - if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE) { - ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front(); - AttributePtr aCircleCenter = aConstraint->entities().front()->baseAttribute(); - if (!aCircleCenter) - return; - FeaturePtr aCircle = ModelAPI_Feature::feature(aCircleCenter->owner()); - AttributeDoublePtr aRadius = std::dynamic_pointer_cast( - aCircle->attribute(SketchPlugin_Circle::RADIUS_ID())); - - if (fabs(aRadius->value()) == fabs(aConstraint->value())) - return; - - aConstraint->setValue(aRadius->value()); - - // Adjust the sign of constraint value - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - aBuilder->adjustConstraint(aConstraint); - myStorage->addConstraint(myBaseConstraint, aConstraint); - } - else if (myType == CONSTRAINT_TANGENT_ARC_ARC) { - ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front(); - if (isArcArcInternal != isInternalTangency( - aConstraint->entities().front(), aConstraint->entities().back())) { + if (myType == CONSTRAINT_TANGENT_ARC_ARC) { + EntityWrapperPtr anEntity1 = + myStorage->entity(myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_A())); + EntityWrapperPtr anEntity2 = + myStorage->entity(myBaseConstraint->refattr(SketchPlugin_Constraint::ENTITY_B())); + + if (isArcArcInternal != isInternalTangency(anEntity1, anEntity2)) { // fully rebuld constraint, because it is unable to access attributes of PlaneGCS constraint remove(); process(); diff --git a/src/SketchSolver/SketchSolver_ConstraintTangent.h b/src/SketchSolver/SketchSolver_ConstraintTangent.h index 589d1ab45..35e724420 100644 --- a/src/SketchSolver/SketchSolver_ConstraintTangent.h +++ b/src/SketchSolver/SketchSolver_ConstraintTangent.h @@ -27,11 +27,12 @@ protected: /// \brief Generate list of attributes of constraint in order useful for constraints /// \param[out] theValue numerical characteristic of constraint (e.g. distance) /// \param[out] theAttributes list of attributes to be filled - virtual void getAttributes(double& theValue, std::vector& theAttributes); + virtual void getAttributes(EntityWrapperPtr& theValue, + std::vector& theAttributes) override; /// \brief This method is used in derived objects to check consistency of constraint. /// E.g. the distance between line and point may be signed. - virtual void adjustConstraint(); + virtual void adjustConstraint() override; private: bool isArcArcInternal; diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index 867775e50..8db65a337 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -5,62 +5,15 @@ // Author: Artem ZHIDKOV #include "SketchSolver_Group.h" - -#include -#include -#include #include #include +#include + #include -#include #include #include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include - -#include -#include - - -/// \brief This class is used to give unique index to the groups -class GroupIndexer -{ -public: - /// \brief Return vacant index - static GroupID NEW_GROUP() { return ++myGroupIndex; } - /// \brief Removes the index - static void REMOVE_GROUP(const GroupID& theIndex) { - if (myGroupIndex == theIndex) - myGroupIndex--; - } - -private: - GroupIndexer() {}; - - static GroupID myGroupIndex; ///< index of the group -}; - -GroupID GroupIndexer::myGroupIndex = GID_OUTOFGROUP; static void sendMessage(const char* theMessageName) @@ -85,20 +38,19 @@ static void sendMessage(const char* theMessageName, const std::set& t // ========= SketchSolver_Group =============== // ======================================================== -SketchSolver_Group::SketchSolver_Group( - std::shared_ptr theWorkplane) - : myID(GroupIndexer::NEW_GROUP()), - myPrevResult(STATUS_UNKNOWN) +SketchSolver_Group::SketchSolver_Group(const CompositeFeaturePtr& theWorkplane) + : mySketch(theWorkplane), + myPrevResult(STATUS_UNKNOWN), + myIsEventsBlocked(false) { - // Initialize workplane - myWorkplaneID = EID_UNKNOWN; - addWorkplane(theWorkplane); + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + mySketchSolver = aBuilder->createSolver(); + myStorage = aBuilder->createStorage(mySketchSolver); } SketchSolver_Group::~SketchSolver_Group() { myConstraints.clear(); - GroupIndexer::REMOVE_GROUP(myID); // send the message that there is no more conflicting constraints if (!myConflictingConstraints.empty()) { sendMessage(EVENT_SOLVER_REPAIRED, myConflictingConstraints); @@ -106,49 +58,6 @@ SketchSolver_Group::~SketchSolver_Group() } } -// ============================================================================ -// Function: isBaseWorkplane -// Class: SketchSolver_Group -// Purpose: verify the group is based on the given workplane -// ============================================================================ -bool SketchSolver_Group::isBaseWorkplane(CompositeFeaturePtr theWorkplane) const -{ - return theWorkplane == mySketch; -} - -// ============================================================================ -// Function: isInteract -// Class: SketchSolver_Group -// Purpose: verify are there any entities in the group used by given constraint -// ============================================================================ -bool SketchSolver_Group::isInteract(FeaturePtr theFeature) const -{ - // Empty group interacts with everything - if (isEmpty()) - return true; - // Check interaction with the storage - bool isInteracted = myStorage->isInteract(theFeature); - ConstraintConstraintMap::const_iterator anIt = myConstraints.begin(); - for (; !isInteracted && anIt != myConstraints.end(); ++anIt) - if (anIt->first->getKind() == SketchPlugin_MultiRotation::ID() || - anIt->first->getKind() == SketchPlugin_MultiTranslation::ID()) { - isInteracted = anIt->second->isUsed(theFeature); - if (isInteracted) - break; - // if theFeature is a constraint, check its attributes - ConstraintPtr aConstraint = std::dynamic_pointer_cast(theFeature); - if (!aConstraint) - continue; - for (int i = 0; i < 4 && !isInteracted; ++i) { - AttributeRefAttrPtr aRefAttr = aConstraint->refattr(aConstraint->ATTRIBUTE(i)); - if (!aRefAttr) - continue; - isInteracted = anIt->second->isUsed((AttributePtr)aRefAttr); - } - } - return isInteracted; -} - // ============================================================================ // Function: changeConstraint // Class: SketchSolver_Group @@ -157,183 +66,48 @@ bool SketchSolver_Group::isInteract(FeaturePtr theFeature) const bool SketchSolver_Group::changeConstraint( std::shared_ptr theConstraint) { - // There is no workplane yet, something wrong - if (myWorkplaneID == EID_UNKNOWN) - return false; - - if (!theConstraint || !theConstraint->data()) - return false; - - if (!checkFeatureValidity(theConstraint)) - return false; - - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - myStorage->blockEvents(true); - bool isNewConstraint = myConstraints.find(theConstraint) == myConstraints.end(); if (isNewConstraint) { + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); // Add constraint to the current group SolverConstraintPtr aConstraint = aBuilder->createConstraint(theConstraint); if (!aConstraint) return false; - aConstraint->process(myStorage, getId(), getWorkplaneId()); + aConstraint->process(myStorage, myIsEventsBlocked); if (!aConstraint->error().empty()) { if (aConstraint->error() == SketchSolver_Error::NOT_INITIALIZED()) return false; // some attribute are not initialized yet, don't show message Events_InfoMessage("SketchSolver_Group", aConstraint->error(), this).send(); } myConstraints[theConstraint] = aConstraint; - - if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) - notifyCoincidenceChanged(myConstraints[theConstraint]); } else myConstraints[theConstraint]->update(); - - // Fix mirror line - if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - theConstraint->attribute(SketchPlugin_ConstraintMirror::ENTITY_A())); - if (aRefAttr && aRefAttr->isObject()) { - std::shared_ptr aFeature = - std::dynamic_pointer_cast( - ModelAPI_Feature::feature(aRefAttr->object())); - if (aFeature) { - SolverConstraintPtr aConstraint = aBuilder->createFixedConstraint(aFeature); - if (aConstraint) { - aConstraint->process(myStorage, getId(), getWorkplaneId()); - setTemporary(aConstraint); - } - } - } - } return true; } -// Update constraints if they contain specific feature -static void updateMultiConstraints(ConstraintConstraintMap& theConstraints, FeaturePtr theFeature) -{ - ConstraintConstraintMap::iterator aCIt = theConstraints.begin(); - for (; aCIt != theConstraints.end(); ++aCIt) { - SketchSolver_ConstraintType aType = aCIt->second->getType(); - if ((aType == CONSTRAINT_MULTI_ROTATION || - aType == CONSTRAINT_MULTI_TRANSLATION) - && aCIt->second->isUsed(theFeature)) - std::dynamic_pointer_cast(aCIt->second)->update(true); - else if ((aType == CONSTRAINT_TANGENT_CIRCLE_LINE || aType == CONSTRAINT_TANGENT_ARC_ARC || - aType == CONSTRAINT_SYMMETRIC || aType == CONSTRAINT_ANGLE) - && aCIt->second->isUsed(theFeature)) - aCIt->second->update(); - } -} - -// Recalculate slave features of the Multi constraints -static void updateMultiConstraints(ConstraintConstraintMap& theConstraints) -{ - ConstraintConstraintMap::iterator aCIt = theConstraints.begin(); - for (; aCIt != theConstraints.end(); ++aCIt) { - SketchSolver_ConstraintType aType = aCIt->second->getType(); - if ((aType == CONSTRAINT_MULTI_ROTATION || - aType == CONSTRAINT_MULTI_TRANSLATION)) - std::dynamic_pointer_cast(aCIt->second)->update(true); - } -} - bool SketchSolver_Group::updateFeature(FeaturePtr theFeature) { - if (!checkFeatureValidity(theFeature)) - return false; - - bool isBlocked = myStorage->isEventsBlocked(); - if (!isBlocked) - myStorage->blockEvents(true); - - myStorage->refresh(true); - bool isUpdated = myStorage->update(theFeature); - - updateMultiConstraints(myConstraints, theFeature); - - // events were not blocked before, the feature has not been updated, - // so it is necessary to revert blocking - if (!isUpdated && !isBlocked) - myStorage->blockEvents(false); - return isUpdated; + return myStorage->update(theFeature); } bool SketchSolver_Group::moveFeature(FeaturePtr theFeature) { BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - // Firstly, revert changes in the fixed entities - myStorage->blockEvents(true); - myStorage->refresh(true); - - // Secondly, search attributes of the feature in the list of the Multi constraints and update them - updateMultiConstraints(myConstraints, theFeature); - - // Then, create temporary Fixed constraint + // Create temporary Fixed constraint SolverConstraintPtr aConstraint = aBuilder->createMovementConstraint(theFeature); if (!aConstraint) return false; - aConstraint->process(myStorage, getId(), getWorkplaneId()); + aConstraint->process(myStorage, myIsEventsBlocked); if (aConstraint->error().empty()) setTemporary(aConstraint); + else + myStorage->notify(theFeature); - // Workaround to process arcs. - // When move unconstrained arc, add temporary constraint to fix radius. - if (theFeature->getKind() == SketchPlugin_Arc::ID()) { - bool hasDup = myStorage->hasDuplicatedConstraint(); - SolverConstraintPtr aFixedRadius = aBuilder->createFixedArcRadiusConstraint(theFeature); - if (aFixedRadius) { - aFixedRadius->process(myStorage, getId(), getWorkplaneId()); - hasDup = myStorage->hasDuplicatedConstraint() && !hasDup; - if (aFixedRadius->error().empty() && !hasDup) - setTemporary(aFixedRadius); - else - aFixedRadius->remove(); - } - } - return true; -} - -// ============================================================================ -// Function: addWorkplane -// Class: SketchSolver_Group -// Purpose: create workplane for the group -// ============================================================================ -bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch) -{ - if (myWorkplaneID != EID_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID()) - return false; // the workplane already exists or the function parameter is not Sketch - - mySketch = theSketch; - if (!updateWorkplane()) { - mySketch = CompositeFeaturePtr(); - return false; - } return true; } -// ============================================================================ -// Function: updateWorkplane -// Class: SketchSolver_Group -// Purpose: update parameters of workplane -// ============================================================================ -bool SketchSolver_Group::updateWorkplane() -{ - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - if (!myStorage) // Create storage if not exists - myStorage = aBuilder->createStorage(getId()); - - // sketch should be unchanged, set it out of current group - bool isUpdated = myStorage->update(FeaturePtr(mySketch), GID_OUTOFGROUP); - if (isUpdated) { - EntityWrapperPtr anEntity = myStorage->entity(FeaturePtr(mySketch)); - myWorkplaneID = anEntity->id(); - } - return isUpdated; -} - // ============================================================================ // Function: resolveConstraints // Class: SketchSolver_Group @@ -345,19 +119,16 @@ bool SketchSolver_Group::resolveConstraints() bool isGroupEmpty = isEmpty() && myStorage->isEmpty(); if (myStorage->isNeedToResolve() && (!isGroupEmpty || !myConflictingConstraints.empty() || myPrevResult == STATUS_FAILED)) { - if (!mySketchSolver) - mySketchSolver = SketchSolver_Manager::instance()->builder()->createSolver(); +//// if (!mySketchSolver) +//// mySketchSolver = SketchSolver_Manager::instance()->builder()->createSolver(); - mySketchSolver->setGroup(myID); - mySketchSolver->calculateFailedConstraints(false); - myStorage->initializeSolver(mySketchSolver); - mySketchSolver->prepare(); +//// mySketchSolver->calculateFailedConstraints(false); + myStorage->initializeSolver(); +//// mySketchSolver->prepare(); SketchSolver_SolveStatus aResult = STATUS_OK; try { - if (myStorage->hasDuplicatedConstraint()) - aResult = STATUS_INCONSISTENT; - else if (!isGroupEmpty) { + if (!isGroupEmpty) { // To avoid overconstraint situation, we will remove temporary constraints one-by-one // and try to find the case without overconstraint bool isLastChance = false; @@ -373,7 +144,7 @@ bool SketchSolver_Group::resolveConstraints() removeTemporaryConstraints(); mySketchSolver->calculateFailedConstraints(true); // something failed => need to find it - myStorage->initializeSolver(mySketchSolver); + myStorage->initializeSolver(); } } } catch (...) { @@ -392,10 +163,10 @@ bool SketchSolver_Group::resolveConstraints() if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET) { myStorage->setNeedToResolve(false); myStorage->refresh(); - updateMultiConstraints(myConstraints); - // multi-constraints updated some parameters, need to store them - if (myStorage->isNeedToResolve()) - resolveConstraints(); +//// updateMultiConstraints(myConstraints); +//// // multi-constraints updated some parameters, need to store them +//// if (myStorage->isNeedToResolve()) +//// resolveConstraints(); if (myPrevResult != STATUS_OK || myPrevResult == STATUS_UNKNOWN) { getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(""); @@ -448,142 +219,18 @@ bool SketchSolver_Group::resolveConstraints() myStorage->refresh(); } removeTemporaryConstraints(); - myStorage->blockEvents(false); myStorage->setNeedToResolve(false); return aResolved; } // ============================================================================ -// Function: mergeGroups -// Class: SketchSolver_Group -// Purpose: append specified group to the current group -// ============================================================================ -void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup) -{ - // If specified group is empty, no need to merge - if (theGroup.isEmpty()) - return; - - std::set aConstraints; - ConstraintConstraintMap::const_iterator aConstrIter = theGroup.myConstraints.begin(); - for (; aConstrIter != theGroup.myConstraints.end(); aConstrIter++) - aConstraints.insert(aConstrIter->first); - - std::list aSortedConstraints = selectApplicableFeatures(aConstraints); - std::list::iterator aSCIter = aSortedConstraints.begin(); - for (; aSCIter != aSortedConstraints.end(); ++aSCIter) { - ConstraintPtr aConstr = std::dynamic_pointer_cast(*aSCIter); - if (!aConstr) - continue; - changeConstraint(aConstr); - } - - // merge previous states of groups => use the worst state, - // so the group after rebuilt may discard error messages if exist - if (theGroup.myPrevResult > myPrevResult) - myPrevResult = theGroup.myPrevResult; -} - -// ============================================================================ -// Function: splitGroup -// Class: SketchSolver_Group -// Purpose: divide the group into several subgroups -// ============================================================================ -void SketchSolver_Group::splitGroup(std::list& theCuts) -{ - // New storage will be used in trimmed way to store the list of constraint interacted together. - StoragePtr aNewStorage = SketchSolver_Manager::instance()->builder()->createStorage(getId()); - // empty vector to avoid creation of solver's constraints - std::list aDummyVec; - - // Obtain constraints, which should be separated - std::list anUnusedConstraints; - ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); - for ( ; aCIter != myConstraints.end(); aCIter++) { - if (aNewStorage->isInteract(FeaturePtr(aCIter->first))) - aNewStorage->addConstraint(aCIter->first, aDummyVec); - else - anUnusedConstraints.push_back(aCIter->first); - } - - // Check the unused constraints once again, - // because they may become interacted with new storage since adding constraints - std::list::iterator aUnuseIt = anUnusedConstraints.begin(); - while (aUnuseIt != anUnusedConstraints.end()) { - if (aNewStorage->isInteract(FeaturePtr(*aUnuseIt))) { - aNewStorage->addConstraint(*aUnuseIt, aDummyVec); - anUnusedConstraints.erase(aUnuseIt); - aUnuseIt = anUnusedConstraints.begin(); - continue; - } - aUnuseIt++; - } - - std::list::iterator aCutsIter; - // Remove unused constraints - for (aUnuseIt = anUnusedConstraints.begin(); aUnuseIt != anUnusedConstraints.end(); ++aUnuseIt) - removeConstraint(*aUnuseIt); - - SketchSolver_Group* aBaseGroup; - for (aUnuseIt = anUnusedConstraints.begin(); aUnuseIt != anUnusedConstraints.end(); ++aUnuseIt) { - aBaseGroup = 0; - aCutsIter = theCuts.begin(); - // Try to append constraint to the current group - if (isInteract(*aUnuseIt)) { - changeConstraint(*aUnuseIt); - aBaseGroup = this; - } else { - // Try to append constraint to already existent group - for (; aCutsIter != theCuts.end(); ++aCutsIter) - if ((*aCutsIter)->isInteract(*aUnuseIt)) { - (*aCutsIter)->changeConstraint(*aUnuseIt); - break; - } - } - - if (aCutsIter == theCuts.end() && !aBaseGroup) { - // Add new group - SketchSolver_Group* aGroup = new SketchSolver_Group(mySketch); - aGroup->changeConstraint(*aUnuseIt); - theCuts.push_back(aGroup); - } else { - if (!aBaseGroup) - aBaseGroup = *aCutsIter++; - // Find other groups interacting with constraint - for (; aCutsIter != theCuts.end(); ++aCutsIter) - if ((*aCutsIter)->isInteract(*aUnuseIt)) { - aBaseGroup->mergeGroups(**aCutsIter); - std::list::iterator aRemoveIt = aCutsIter--; - theCuts.erase(aRemoveIt); - } - } - } -} - -// ============================================================================ -// Function: isConsistent +// Function: repairConsistency // Class: SketchSolver_Group // Purpose: search removed entities and constraints // ============================================================================ -bool SketchSolver_Group::isConsistent() +void SketchSolver_Group::repairConsistency() { - if (isEmpty()) // no one constraint is initialized yet - return true; - - // Check the features and constraint is the storage are valid - bool aResult = myStorage->isConsistent(); - if (aResult) { - // additional check of consistency of the Fixed constraint, - // because they are not added to the storage - ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); - for (; aCIter != myConstraints.end(); ++aCIter) - if (aCIter->first->getKind() == SketchPlugin_ConstraintRigid::ID() && - (!aCIter->first->data() || !aCIter->first->data()->isValid())) { - aResult = false; - break; - } - } - if (!aResult) { + if (!myStorage->isConsistent()) { // remove invalid constraints std::set anInvalidConstraints; ConstraintConstraintMap::iterator aCIter = myConstraints.begin(); @@ -594,10 +241,10 @@ bool SketchSolver_Group::isConsistent() std::set::const_iterator aRemoveIt = anInvalidConstraints.begin(); for (; aRemoveIt != anInvalidConstraints.end(); ++aRemoveIt) removeConstraint(*aRemoveIt); + // remove invalid features myStorage->removeInvalidEntities(); } - return aResult; } // ============================================================================ @@ -608,14 +255,18 @@ bool SketchSolver_Group::isConsistent() // ============================================================================ void SketchSolver_Group::removeTemporaryConstraints() { - std::set::iterator aTmpIt = myTempConstraints.begin(); - for (; aTmpIt != myTempConstraints.end(); ++aTmpIt) - (*aTmpIt)->remove(); + if (!myTempConstraints.empty()) { + std::dynamic_pointer_cast( + mySketchSolver)->removeConstraint(CID_MOVEMENT); + + std::set::iterator aTmpIt = myTempConstraints.begin(); + for (; aTmpIt != myTempConstraints.end(); ++aTmpIt) + (*aTmpIt)->remove(); + + myTempConstraints.clear(); + } - if (!myTempConstraints.empty()) - myStorage->verifyFixed(); myStorage->setNeedToResolve(false); - myTempConstraints.clear(); } // ============================================================================ @@ -629,18 +280,10 @@ void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint) for (; aCIter != myConstraints.end(); aCIter++) if (aCIter->first == theConstraint) { aCIter->second->remove(); // the constraint is not fully removed - if (aCIter->first->getKind() == SketchPlugin_ConstraintCoincidence::ID()) - notifyCoincidenceChanged(aCIter->second); break; } if (aCIter != myConstraints.end()) myConstraints.erase(aCIter); - // empty group => clear storage - if (myConstraints.empty()) { - myStorage = StoragePtr(); - mySketchSolver = SolverPtr(); - updateWorkplane(); - } } // ============================================================================ @@ -653,114 +296,23 @@ void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint) myTempConstraints.insert(theConstraint); } - // ============================================================================ -// Function: checkFeatureValidity +// Function: blockEvents // Class: SketchSolver_Group -// Purpose: verifies is the feature valid +// Purpose: block or unblock events from features in this group // ============================================================================ -bool SketchSolver_Group::checkFeatureValidity(FeaturePtr theFeature) -{ - if (!theFeature || !theFeature->data()->isValid()) - return true; - - SessionPtr aMgr = ModelAPI_Session::get(); - ModelAPI_ValidatorsFactory* aFactory = aMgr->validators(); - return aFactory->validate(theFeature); -} - - - - -// =========== Auxiliary functions ======================================== -static double featureToVal(FeaturePtr theFeature) -{ - if (theFeature->getKind() == SketchPlugin_Sketch::ID()) - return 0.0; // sketch - ConstraintPtr aConstraint = std::dynamic_pointer_cast(theFeature); - if (!aConstraint) - return 1.0; // features (arc, circle, line, point) - - const std::string& anID = aConstraint->getKind(); - if (anID == SketchPlugin_ConstraintCoincidence::ID()) { - AttributeRefAttrPtr anAttrA = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - AttributeRefAttrPtr anAttrB = std::dynamic_pointer_cast( - aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B())); - if (anAttrA && anAttrB && (anAttrA->isObject() || anAttrB->isObject())) - // point-on-line and point-on-circle should go before points coincidence constraint - return 2.0; - return 2.5; - } - if (anID == SketchPlugin_ConstraintDistance::ID() || - anID == SketchPlugin_ConstraintLength::ID() || - anID == SketchPlugin_ConstraintRadius::ID()) - return 3.0; - if (anID == SketchPlugin_ConstraintAngle::ID()) - return 3.5; - if (anID == SketchPlugin_ConstraintHorizontal::ID() || - anID == SketchPlugin_ConstraintVertical::ID() || - anID == SketchPlugin_ConstraintParallel::ID() || - anID == SketchPlugin_ConstraintPerpendicular::ID()) - return 4.0; - if (anID == SketchPlugin_ConstraintEqual::ID()) - return 5.0; - if (anID == SketchPlugin_ConstraintTangent::ID() || - anID == SketchPlugin_ConstraintMirror::ID()) - return 6.0; - if (anID == SketchPlugin_ConstraintRigid::ID()) - return 0.5; - if (anID == SketchPlugin_MultiRotation::ID() || - anID == SketchPlugin_MultiTranslation::ID()) - return 8.0; - - // all other constraints are placed between Equal and Tangent constraints - return 5.5; -} - -static bool isLess(FeaturePtr theFeature1, FeaturePtr theFeature2) +void SketchSolver_Group::blockEvents(bool isBlocked) { - return featureToVal(theFeature1) < featureToVal(theFeature2); -} - -std::list SketchSolver_Group:: - selectApplicableFeatures(const std::set& theObjects) -{ - std::list aResult; - std::list::iterator aResIt; - - std::set::const_iterator anObjIter = theObjects.begin(); - for (; anObjIter != theObjects.end(); ++anObjIter) { - // Operate sketch itself and SketchPlugin features only. - // Also, the Fillet and Split need to be skipped, - // because there are several separated constraints composing it. - FeaturePtr aFeature = std::dynamic_pointer_cast(*anObjIter); - if (!aFeature) - continue; - std::shared_ptr aSketchFeature = - std::dynamic_pointer_cast(aFeature); - if ((aFeature->getKind() != SketchPlugin_Sketch::ID() && !aSketchFeature) || - aFeature->getKind() == SketchPlugin_ConstraintFillet::ID() || - aFeature->getKind() == SketchPlugin_ConstraintSplit::ID()) - continue; - - // Find the place where to insert a feature - for (aResIt = aResult.begin(); aResIt != aResult.end(); ++aResIt) - if (isLess(aFeature, *aResIt)) - break; - aResult.insert(aResIt, aFeature); - } + if (myIsEventsBlocked == isBlocked) + return; - return aResult; -} + // block/unblock events from the features in the storage + myStorage->blockEvents(isBlocked); -void SketchSolver_Group::notifyCoincidenceChanged(SolverConstraintPtr theCoincidence) -{ - const std::list& aCoincident = theCoincidence->attributes(); - EntityWrapperPtr anAttr1 = aCoincident.front(); - EntityWrapperPtr anAttr2 = aCoincident.back(); + // block/unblock events from constraints + ConstraintConstraintMap::iterator aCIt = myConstraints.begin(); + for (; aCIt != myConstraints.end(); ++aCIt) + aCIt->second->blockEvents(isBlocked); - ConstraintConstraintMap::iterator anIt = myConstraints.begin(); - for (; anIt != myConstraints.end(); ++anIt) - anIt->second->notifyCoincidenceChanged(anAttr1, anAttr2); + myIsEventsBlocked = isBlocked; } diff --git a/src/SketchSolver/SketchSolver_Group.h b/src/SketchSolver/SketchSolver_Group.h index 193e1d541..c37524fa2 100644 --- a/src/SketchSolver/SketchSolver_Group.h +++ b/src/SketchSolver/SketchSolver_Group.h @@ -7,24 +7,20 @@ #ifndef SketchSolver_Group_H_ #define SketchSolver_Group_H_ -#include "SketchSolver.h" #include #include #include #include -#include #include -#include #include -#include typedef std::map ConstraintConstraintMap; /** \class SketchSolver_Group * \ingroup Plugins - * \brief Keeps the group of constraints which based on the same entities + * \brief Keeps the group of constraints which placed in the same sketch */ class SketchSolver_Group { @@ -33,21 +29,9 @@ class SketchSolver_Group * Throws an exception if theWorkplane is not an object of SketchPlugin_Sketch type * \remark Type of theSketch is not verified inside */ - SketchSolver_Group(std::shared_ptr theWorkplane); + SketchSolver_Group(const CompositeFeaturePtr& theWorkplane); - ~SketchSolver_Group(); - - /// \brief Returns group's unique identifier - inline const GroupID& getId() const - { - return myID; - } - - /// \brief Returns identifier of the workplane - inline const EntityID& getWorkplaneId() const - { - return myWorkplaneID; - } + virtual ~SketchSolver_Group(); /// \brief Returns true if the group has no constraints yet inline bool isEmpty() const @@ -61,12 +45,6 @@ class SketchSolver_Group return mySketch->data() && mySketch->data()->isValid(); } - /// \brief Check the group has conflicting constraints - inline bool isFailed() const - { - return !myConflictingConstraints.empty(); - } - /** \brief Adds or updates a constraint in the group * \param[in] theConstraint constraint to be changed * \return \c true if the constraint added or updated successfully @@ -85,100 +63,52 @@ class SketchSolver_Group */ bool moveFeature(FeaturePtr theFeature); - /** \brief Verifies the feature attributes are used in this group - * \param[in] theFeature constraint or any other object for verification of interaction - * \return \c true if some of attributes are used in current group - */ - bool isInteract(FeaturePtr theFeature) const; - - /** \brief Verifies the specified feature is equal to the base workplane for this group - * \param[in] theWorkplane the feature to be compared with base workplane - * \return \c true if workplanes are the same - */ - bool isBaseWorkplane(CompositeFeaturePtr theWorkplane) const; - /// Returns the current workplane - std::shared_ptr getWorkplane() const + inline const CompositeFeaturePtr& getWorkplane() const { return mySketch; } - /** \brief Update parameters of workplane. Should be called when Update event is coming. - * \return \c true if workplane updated successfully, - * \c false if workplane parameters are not consistent - */ - bool updateWorkplane(); - /** \brief Searches invalid features and constraints in the group and removes them * \return \c false if the group several constraints were removed */ - bool isConsistent(); - - /** \brief Add specified group to this one - * \param[in] theGroup group of constraint to be added - */ - void mergeGroups(const SketchSolver_Group& theGroup); - - /** \brief Cut from the group several subgroups, which are not connected to - * the current one by any constraint - * \param[out] theCuts enlarge this list by newly created groups - */ - void splitGroup(std::list& theCuts); + void repairConsistency(); /** \brief Start solution procedure if necessary and update attributes of features * \return \c false when no need to solve constraints */ bool resolveConstraints(); - /** \brief Collect all features applicable for the sketch - * \param theObjects list of features - * \return list of bolted and sorted features - */ - static std::list selectApplicableFeatures(const std::set& theObjects); + /// \brief Block or unblock events sent by features in this group + void blockEvents(bool isBlocked); -protected: +private: /** \brief Removes constraints from the group * \param[in] theConstraint constraint to be removed */ void removeConstraint(ConstraintPtr theConstraint); - /// \brief Remove all temporary constraint after computation finished + /// \brief Remove all temporary constraints after the computation finished void removeTemporaryConstraints(); -private: - /** \brief Creates a workplane from the sketch parameters - * \param[in] theSketch parameters of workplane are the attributes of this sketch - * \return \c true if success, \c false if workplane parameters are not consistent - */ - bool addWorkplane(CompositeFeaturePtr theSketch); - /// \brief Append given constraint to the group of temporary constraints void setTemporary(SolverConstraintPtr theConstraint); - /// \brief Verifies is the feature valid - bool checkFeatureValidity(FeaturePtr theFeature); - - /// \brief Notify all interested constraints that coincidence appears or removed - /// \param[in] theCoincidence coincidence constraint - void notifyCoincidenceChanged(SolverConstraintPtr theCoincidence); - private: - GroupID myID; ///< Index of the group - EntityID myWorkplaneID; ///< Index of workplane, the group is based on - CompositeFeaturePtr mySketch; ///< Sketch is equivalent to workplane + CompositeFeaturePtr mySketch; ///< Sketch for this group ConstraintConstraintMap myConstraints; ///< List of constraints std::set myTempConstraints; ///< List of temporary constraints - /// List of parametric constraints - std::map myParametricConstraints; - StoragePtr myStorage; ///< Container for the set of SolveSpace constraints and their entities - SolverPtr mySketchSolver; ///< Solver for set of equations obtained by constraints /// Result of previous solution of the set of constraints SketchSolver_SolveStatus myPrevResult; std::set myConflictingConstraints; ///< List of conflicting constraints + + bool myIsEventsBlocked; ///< shows the events are blocked for this group }; +typedef std::shared_ptr SketchGroupPtr; + #endif diff --git a/src/SketchSolver/SketchSolver_IConstraintWrapper.h b/src/SketchSolver/SketchSolver_IConstraintWrapper.h index 12bf83423..04b7e917f 100644 --- a/src/SketchSolver/SketchSolver_IConstraintWrapper.h +++ b/src/SketchSolver/SketchSolver_IConstraintWrapper.h @@ -54,17 +54,11 @@ class SketchSolver_IConstraintWrapper public: virtual ~SketchSolver_IConstraintWrapper() {} - /// \brief Return base feature - const ConstraintPtr& baseConstraint() const - { return myBaseConstraint; } - - /// \brief Return ID of current entity - virtual ConstraintID id() const = 0; - - /// \brief Change group for the constraint - virtual void setGroup(const GroupID& theGroup) = 0; - /// \brief Return identifier of the group the constraint belongs to - virtual GroupID group() const = 0; + /// \brief Return ID of current constraint + const ConstraintID& id() const + { return myID; } + /// \brief Change constraint ID + virtual void setId( const ConstraintID& theID) = 0; /// \brief Return type of current entity virtual SketchSolver_ConstraintType type() const = 0; @@ -77,11 +71,9 @@ public: { return myConstrained; } /// \brief Assign numeric parameter of constraint - virtual void setValue(const double& theValue) - { myValue = theValue; } + virtual void setValue(const double& theValue) = 0; /// \brief Return numeric parameter of constraint - const double& value() const - { return myValue; } + virtual double value() const = 0; /// \brief Store a boolean flag for full value using void setIsFullValue(const bool& theFullValue) @@ -90,22 +82,9 @@ public: const bool& isFullValue() const { return myIsFullValue; } - /// \brief Verify the feature is used in the constraint - virtual bool isUsed(FeaturePtr theFeature) const = 0; - /// \brief Verify the attribute is used in the constraint - virtual bool isUsed(AttributePtr theAttribute) const = 0; - - /// \brief Compare current constraint with other - virtual bool isEqual(const std::shared_ptr& theOther) = 0; - - /// \brief Update values of parameters of this constraint by the parameters of given one - /// \return \c true if some parameters change their values - virtual bool update(const std::shared_ptr& theOther) = 0; - protected: - ConstraintPtr myBaseConstraint; + ConstraintID myID; std::list myConstrained; - double myValue; bool myIsFullValue; }; diff --git a/src/SketchSolver/SketchSolver_IEntityWrapper.h b/src/SketchSolver/SketchSolver_IEntityWrapper.h index 15735e733..41f561aba 100644 --- a/src/SketchSolver/SketchSolver_IEntityWrapper.h +++ b/src/SketchSolver/SketchSolver_IEntityWrapper.h @@ -8,7 +8,6 @@ #define SketchSolver_IEntityWrapper_H_ #include -#include #include #include @@ -22,11 +21,9 @@ enum SketchSolver_EntityType { ENTITY_SCALAR, ENTITY_ANGLE, ENTITY_POINT, - ENTITY_NORMAL, ENTITY_LINE, ENTITY_CIRCLE, - ENTITY_ARC, - ENTITY_SKETCH + ENTITY_ARC }; /** @@ -35,65 +32,19 @@ enum SketchSolver_EntityType { class SketchSolver_IEntityWrapper { public: + SketchSolver_IEntityWrapper() : myExternal(false) {} virtual ~SketchSolver_IEntityWrapper() {} - /// \brief Return base feature - const FeaturePtr& baseFeature() const - { return myBaseFeature; } - /// \brief Return base attribute - const AttributePtr& baseAttribute() const - { return myBaseAttribute; } - - /// \brief Check the feature is basis for this wrapper - bool isBase(FeaturePtr theFeature) const - { return myBaseFeature && myBaseFeature == theFeature; } - /// \brief Check the attribute is basis for this wrapper - bool isBase(AttributePtr theAttribute) const - { return myBaseAttribute && myBaseAttribute == theAttribute; } - - /// \brief Assign list of parameters for this entity - void setParameters(const std::list& theParams) - { myParameters = theParams; } - /// \brief Return list of parameters - const std::list& parameters() const - { return myParameters; } - - /// \brief Assign list of sub-entities - void setSubEntities(const std::list >& theEntities) - { mySubEntities = theEntities; } - /// \brief Return list of sub-entities - const std::list >& subEntities() const - { return mySubEntities; } - - /// \brief Return ID of current entity - virtual EntityID id() const = 0; - - /// \brief Change group for the entity - virtual void setGroup(const GroupID& theGroup) = 0; - /// \brief Return identifier of the group the entity belongs to - virtual GroupID group() const = 0; - /// \brief Return type of current entity virtual SketchSolver_EntityType type() const = 0; - /// \brief Verify the feature is used in the entity - virtual bool isUsed(FeaturePtr theFeature) const = 0; - /// \brief Verify the attribute is used in the entity - virtual bool isUsed(AttributePtr theAttribute) const = 0; - - /// \brief Compare current entity with other - virtual bool isEqual(const std::shared_ptr& theOther) = 0; - - /// \brief Update values of parameters of this entity by the parameters of given one - /// \return \c true if some parameters change their values - virtual bool update(const std::shared_ptr& theOther) = 0; - -protected: - FeaturePtr myBaseFeature; - AttributePtr myBaseAttribute; + /// \brief Change flag indicating the entity cannot be changed in the solver + void setExternal(bool theExternal) { myExternal = theExternal; } + /// \brief Return the External flag + bool isExternal() const { return myExternal; } - std::list myParameters; - std::list > mySubEntities; +private: + bool myExternal; }; typedef std::shared_ptr EntityWrapperPtr; diff --git a/src/SketchSolver/SketchSolver_IParameterWrapper.h b/src/SketchSolver/SketchSolver_IParameterWrapper.h deleted file mode 100644 index 751e3464b..000000000 --- a/src/SketchSolver/SketchSolver_IParameterWrapper.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: SketchSolver_IParameterWrapper.h -// Created: 1 Dec 2015 -// Author: Artem ZHIDKOV - -#ifndef SketchSolver_IParameterWrapper_H_ -#define SketchSolver_IParameterWrapper_H_ - -#include - -#include - -/** - * Wrapper providing operations with parameters regardless the solver. - */ -class SketchSolver_IParameterWrapper -{ -public: - virtual ~SketchSolver_IParameterWrapper() {} - - /// \brief Return ID of current parameter - virtual ParameterID id() const = 0; - - /// \brief Change group for the parameter - virtual void setGroup(const GroupID& theGroup) = 0; - /// \brief Return identifier of the group the parameter belongs to - virtual GroupID group() const = 0; - - /// \brief Change value of parameter - virtual void setValue(double theValue) = 0; - /// \brief Return value of parameter - virtual double value() const = 0; - - /// \brief Set or unset flag the parameter is given by expression - void setIsParametric(bool isParametric) - { myIsParametric = isParametric; } - /// \brief Show the parameter is an expression - bool isParametric() const - { return myIsParametric; } - - /// \brief Compare current parameter with other - virtual bool isEqual(const std::shared_ptr& theOther) = 0; - - /// \brief Update value of parameter by the given one - /// \return \c true if the value of parameter is changed - virtual bool update(const std::shared_ptr& theOther) = 0; - -protected: - bool myIsParametric; ///< indicate the parameter is given by parametric expression -}; - -typedef std::shared_ptr ParameterWrapperPtr; - -#endif diff --git a/src/SketchSolver/SketchSolver_ISolver.h b/src/SketchSolver/SketchSolver_ISolver.h index cd5254057..c1c21bffa 100644 --- a/src/SketchSolver/SketchSolver_ISolver.h +++ b/src/SketchSolver/SketchSolver_ISolver.h @@ -29,10 +29,6 @@ class SketchSolver_ISolver public: virtual ~SketchSolver_ISolver() {} - /// \brief Changes the ID of the group to solve - void setGroup(const GroupID& theGroupID) - { myGroup = theGroupID; } - /// \brief Set or unset the flag which allows to find all failed constraints void calculateFailedConstraints(bool theSic) { myFindFaileds = theSic; } @@ -54,7 +50,6 @@ public: virtual int dof() const = 0; protected: - GroupID myGroup; ///< ID of the group to be solved bool myFindFaileds; ///< flag to find conflicting or inappropriate constraints }; diff --git a/src/SketchSolver/SketchSolver_Manager.cpp b/src/SketchSolver/SketchSolver_Manager.cpp index 80f1f98ef..0d20365a4 100644 --- a/src/SketchSolver/SketchSolver_Manager.cpp +++ b/src/SketchSolver/SketchSolver_Manager.cpp @@ -8,58 +8,26 @@ #include "SketchSolver_Error.h" #include - -#include - -#include -#include -#include #include -#include #include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include +#include +#include #include -#include -#include -#include -#include -#include -#include +/// Global constraint manager object +static SketchSolver_Manager* myManager = SketchSolver_Manager::instance(); -static const Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); +/// \brief Verifies is the feature valid +static bool isFeatureValid(FeaturePtr theFeature) +{ + if (!theFeature || !theFeature->data() || !theFeature->data()->isValid()) + return false; -// Initialization of constraint manager self pointer -SketchSolver_Manager* SketchSolver_Manager::mySelf = 0; + SessionPtr aMgr = ModelAPI_Session::get(); + ModelAPI_ValidatorsFactory* aFactory = aMgr->validators(); + return aFactory->validate(theFeature); +} -/// Global constraint manager object -SketchSolver_Manager* myManager = SketchSolver_Manager::instance(); // ======================================================== @@ -67,6 +35,7 @@ SketchSolver_Manager* myManager = SketchSolver_Manager::instance(); // ======================================================== SketchSolver_Manager* SketchSolver_Manager::instance() { + static SketchSolver_Manager* mySelf = 0; // Self pointer to implement singleton functionality if (!mySelf) mySelf = new SketchSolver_Manager(); return mySelf; @@ -79,12 +48,12 @@ SketchSolver_Manager::SketchSolver_Manager() // Register in event loop Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED)); - Events_Loop::loop()->registerListener(this, anUpdateEvent); + Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED)); Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED)); - Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_FAILED)); - Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_REPAIRED)); + ////Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_FAILED)); + ////Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SOLVER_REPAIRED)); Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_SKETCH_PREPARED)); } @@ -115,6 +84,7 @@ bool SketchSolver_Manager::groupMessages() void SketchSolver_Manager::processEvent( const std::shared_ptr& theMessage) { + static const Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); static const Events_ID aSketchPreparedEvent = Events_Loop::eventByName(EVENT_SKETCH_PREPARED); // sketch is prepared for resolve: all the needed events // are collected and must be processed by the solver @@ -123,15 +93,10 @@ void SketchSolver_Manager::processEvent( return; } - checkConflictingConstraints(theMessage); - if (myIsComputed) return; myIsComputed = true; - // Shows that the message has at least one feature applicable for solver - bool hasProperFeature = false; - if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED) || theMessage->eventID() == anUpdateEvent || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) { @@ -143,45 +108,30 @@ void SketchSolver_Manager::processEvent( bool isMovedEvt = theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED); - if (isMovedEvt) { - std::set::iterator aFeatIter; - for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) { - std::shared_ptr aSFeature = - std::dynamic_pointer_cast(*aFeatIter); - if (aSFeature && moveEntity(aSFeature)) { - // Want to avoid recalculation of DoF too frequently. - // So, set the flag when the feature is really moved. - hasProperFeature = true; - } - } - if (!hasProperFeature) - // in this iteration it will compute nothing, so, no problem with recursion - // it is important that solver flushes signal updated after processing move signal as there - // is optimization that relies on this update, might be found by key "optimization" - myIsComputed = false; - } else { - std::list aSketchFeatures = - SketchSolver_Group::selectApplicableFeatures(aFeatures); - std::list::iterator aFeatIter = aSketchFeatures.begin(); - for (; aFeatIter != aSketchFeatures.end(); ++aFeatIter) { - if ((*aFeatIter)->getKind() == SketchPlugin_Sketch::ID()) { - std::shared_ptr aSketch = - std::dynamic_pointer_cast(*aFeatIter); - hasProperFeature = changeWorkplane(aSketch) || hasProperFeature; - continue; - } - std::shared_ptr aFeature = - std::dynamic_pointer_cast(*aFeatIter); - if (!aFeature) - continue; - hasProperFeature = changeFeature(aFeature) || hasProperFeature; - } + + // Shows that the message has at least one feature applicable for solver + bool hasProperFeature = false; + + // update sketch features only + std::set::iterator aFeatIter; + for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) { + std::shared_ptr aFeature = + std::dynamic_pointer_cast(*aFeatIter); + if (!aFeature || aFeature->isMacro()) + continue; + + hasProperFeature = updateFeature(aFeature, isMovedEvt) || hasProperFeature; + } + + if (isMovedEvt && !hasProperFeature) { + // in this iteration it will compute nothing, so, no problem with recursion + // it is important that solver flushes signal updated after processing move signal as there + // is optimization that relies on this update, might be found by key "optimization" + myIsComputed = false; } - bool needToUpdate = false; // Solve the set of constraints - if (hasProperFeature) - needToUpdate = resolveConstraints(); + bool needToUpdate = resolveConstraints(); // Features may be updated => now send events, but for all changed at once if (isUpdateFlushed) @@ -203,672 +153,111 @@ void SketchSolver_Manager::processEvent( std::set::const_iterator aFGrIter; for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++) if (aFGrIter->compare(ModelAPI_ResultConstruction::group()) == 0 || - aFGrIter->compare(ModelAPI_Feature::group()) == 0) + aFGrIter->compare(ModelAPI_Feature::group()) == 0) break; if (aFGrIter != aFeatureGroups.end()) { - hasProperFeature = true; - std::list aGroupsToResolve; - std::list::iterator aGroupIter = myGroups.begin(); - std::list aSeparatedGroups; + std::list::iterator aGroupIter = myGroups.begin(); while (aGroupIter != myGroups.end()) { if (!(*aGroupIter)->isWorkplaneValid()) { // the group should be removed - delete *aGroupIter; - std::list::iterator aRemoveIt = aGroupIter++; + std::list::iterator aRemoveIt = aGroupIter++; myGroups.erase(aRemoveIt); continue; } - if (!(*aGroupIter)->isConsistent()) { - // some constraints were removed, try to split the group - (*aGroupIter)->splitGroup(aSeparatedGroups); - if (!(*aGroupIter)->getWorkplane()->string( - SketchPlugin_Sketch::SOLVER_ERROR())->value().empty() || - (*aGroupIter)->isFailed()) - aGroupsToResolve.push_back(*aGroupIter); - } - aGroupIter++; - } - if (aSeparatedGroups.size() > 0) { - myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end()); - aGroupsToResolve.insert(aGroupsToResolve.end(), - aSeparatedGroups.begin(), aSeparatedGroups.end()); - } - if (!aGroupsToResolve.empty()) - resolveConstraints(aGroupsToResolve); - } - myIsComputed = false; - } - - if (hasProperFeature) - degreesOfFreedom(); -} - -void SketchSolver_Manager:: - checkConflictingConstraints(const std::shared_ptr& theMessage) -{ - if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_SOLVER_REPAIRED)) { - std::shared_ptr aMessage = - std::dynamic_pointer_cast(theMessage); - std::set aSentObjs = aMessage->objects(); - if (!aSentObjs.empty()) { - // Obtain sketch where the constraints are placed. - // It is enough to check only one constraint. - CompositeFeaturePtr aSketch; - FeaturePtr aConstraint = ModelAPI_Feature::feature(*aSentObjs.begin()); - std::list::const_iterator aGrIt = myGroups.begin(); - for (; aGrIt != myGroups.end(); ++aGrIt) - if ((*aGrIt)->isInteract(aConstraint)) { - aSketch = (*aGrIt)->getWorkplane(); - break; - } - - // Search failed groups built on the same sketch - if (aSketch) { - for (aGrIt = myGroups.begin(); aGrIt != myGroups.end(); ++aGrIt) { - SketchSolver_Group* aGroup = *aGrIt; - if (aGroup->isBaseWorkplane(aSketch) && aGroup->isFailed() && - !aGroup->isInteract(aConstraint)) { - // reset error message on the sketch - aGroup->getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue( - SketchSolver_Error::CONSTRAINTS()); - break; - } - } + (*aGroupIter)->repairConsistency(); + ++aGroupIter; } - } - } -} -// ============================================================================ -// Function: changeWorkplane -// Purpose: update workplane by given parameters of the sketch -// ============================================================================ -bool SketchSolver_Manager::changeWorkplane(CompositeFeaturePtr theSketch) -{ - bool aResult = true; // changed when a workplane wrongly updated - bool isUpdated = false; - // Try to update specified workplane in all groups - std::list::iterator aGroupIter; - for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) - if ((*aGroupIter)->isBaseWorkplane(theSketch)) { - isUpdated = true; - aResult = false; + resolveConstraints(); } - // If the workplane is not updated, so this is a new workplane - if (!isUpdated) { - SketchSolver_Group* aNewGroup = new SketchSolver_Group(theSketch); - // Verify that the group is created successfully - if (!aNewGroup->isBaseWorkplane(theSketch) || !aNewGroup->isWorkplaneValid()) { - delete aNewGroup; - return false; - } - myGroups.push_back(aNewGroup); + myIsComputed = false; } - return aResult || isUpdated; } // ============================================================================ // Function: changeConstraintOrEntity // Purpose: create/update the constraint or the feature and place it into appropriate group // ============================================================================ -bool SketchSolver_Manager::changeFeature(std::shared_ptr theFeature) +bool SketchSolver_Manager::updateFeature(std::shared_ptr theFeature, + bool theMoved) { - // Search the groups which this feature touches - std::set aGroups; - findGroups(theFeature, aGroups); + // Check feature validity and find a group to place it. + // If the feature is not valid, the returned group will be empty. + // This will protect to deal with wrong (not fully initialized) features. + SketchGroupPtr aGroup = findGroup(theFeature); + if (!aGroup) + return false; + aGroup->blockEvents(true); std::shared_ptr aConstraint = std::dynamic_pointer_cast(theFeature); - // Process the groups list - if (aGroups.size() == 0) { - // There are no groups applicable for this constraint => create new one - // The group will be created only for constraints, not for features - if (!aConstraint) return false; - std::shared_ptr aWP = findWorkplane(aConstraint); - if (!aWP) - return false; - SketchSolver_Group* aGroup = new SketchSolver_Group(aWP); - if (!aGroup->changeConstraint(aConstraint)) { - delete aGroup; - return false; - } - myGroups.push_back(aGroup); - return true; - } else if (aGroups.size() == 1) { // Only one group => add feature into it - GroupID aGroupId = *(aGroups.begin()); - std::list::iterator aGroupIter; - for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) - if ((*aGroupIter)->getId() == aGroupId) { - // If the group is empty, the feature is not added (the constraint only) - if (!aConstraint && !(*aGroupIter)->isEmpty()) - return (*aGroupIter)->updateFeature(theFeature); - return (*aGroupIter)->changeConstraint(aConstraint); - } - } else if (aGroups.size() > 1) { - // Several groups applicable for this feature => need to merge them - std::set::const_iterator aGroupsIter = aGroups.begin(); - - // Search first group - std::list::iterator aFirstGroupIter; - for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++) - if ((*aFirstGroupIter)->getId() == *aGroupsIter) - break; - if (aFirstGroupIter == myGroups.end()) - return false; - - // Append other groups to the first one - std::list::iterator anOtherGroupIter = aFirstGroupIter; - ++anOtherGroupIter; - for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) { - for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++) - if ((*anOtherGroupIter)->getId() == *aGroupsIter) - break; - if (anOtherGroupIter == myGroups.end()) { // Group disappears - anOtherGroupIter = aFirstGroupIter; - ++anOtherGroupIter; - continue; - } - - (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter); - std::list::iterator aRemoveIt = anOtherGroupIter++; - delete *aRemoveIt; - myGroups.erase(aRemoveIt); - } - - if (aConstraint) - (*aFirstGroupIter)->changeConstraint(aConstraint); - else - (*aFirstGroupIter)->updateFeature(theFeature); - // groups are merged => need to resolve them - return true; - } - - // Something goes wrong - return false; -} - -// ============================================================================ -// Function: moveEntity -// Purpose: update element moved on the sketch, which is used by constraints -// ============================================================================ -bool SketchSolver_Manager::moveEntity(std::shared_ptr theFeature) -{ - bool isMoved = false; - std::list::iterator aGroupIt = myGroups.begin(); - for (; aGroupIt != myGroups.end(); aGroupIt++) - if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature)) - isMoved = (*aGroupIt)->moveFeature(theFeature) || isMoved; - - if (!isMoved && theFeature->getKind() == SketchPlugin_Arc::ID()) { - // Workaround to move arc. - // If the arc has not been constrained, we will push it into empty group and apply movement. - bool hasEmptyGroup = false; - for (aGroupIt = myGroups.begin(); aGroupIt != myGroups.end(); aGroupIt++) - if ((*aGroupIt)->isEmpty()) { - isMoved = (*aGroupIt)->moveFeature(theFeature) || isMoved; - hasEmptyGroup = true; - } - // There is no empty group, create it explicitly - if (!hasEmptyGroup) { - // find sketch containing the arc - CompositeFeaturePtr aWP; - const std::set& aRefs = theFeature->data()->refsToMe(); - std::set::const_iterator aRefIt = aRefs.begin(); - for (; aRefIt != aRefs.end(); ++aRefIt) { - FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner()); - if (anOwner && anOwner->getKind() == SketchPlugin_Sketch::ID()) { - aWP = std::dynamic_pointer_cast(anOwner); - break; - } - } - if (aWP) { - SketchSolver_Group* aGroup = new SketchSolver_Group(aWP); - isMoved = aGroup->moveFeature(theFeature) || isMoved; - myGroups.push_back(aGroup); - } - } - } - return isMoved; + bool isOk = false; + if (aConstraint) + isOk = aGroup->changeConstraint(aConstraint); + else if (theMoved) + isOk = aGroup->moveFeature(theFeature); + else + isOk = aGroup->updateFeature(theFeature); + return isOk; } // ============================================================================ -// Function: findGroups +// Function: findGroup // Purpose: search groups of entities interacting with given feature // ============================================================================ -void SketchSolver_Manager::findGroups( - std::shared_ptr theFeature, - std::set& theGroupIDs) const +SketchGroupPtr SketchSolver_Manager::findGroup( + std::shared_ptr theFeature) { - std::shared_ptr aWP = findWorkplane(theFeature); - - SketchSolver_Group* anEmptyGroup = 0; // appropriate empty group for specified constraint - std::list::const_iterator aGroupIter; - for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) - if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) { - if (!(*aGroupIter)->isEmpty()) - theGroupIDs.insert((*aGroupIter)->getId()); - else if (!anEmptyGroup) - anEmptyGroup = *aGroupIter; + if (!isFeatureValid(theFeature)) + return SketchGroupPtr(); // do not process wrong features + + // Obtain sketch, containing the feature + CompositeFeaturePtr aSketch; + const std::set& aRefsList = theFeature->data()->refsToMe(); + std::set::const_iterator aRefIt = aRefsList.begin(); + for (; aRefIt != aRefsList.end(); ++aRefIt) { + FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner()); + if (anOwner && anOwner->getKind() == SketchPlugin_Sketch::ID()) { + aSketch = std::dynamic_pointer_cast(anOwner); + break; } + } - // When only empty group is found, use it - if (anEmptyGroup && theGroupIDs.empty()) - theGroupIDs.insert(anEmptyGroup->getId()); -} + if (!aSketch) + return SketchGroupPtr(); // not a sketch's feature -// ============================================================================ -// Function: findWorkplane -// Purpose: search workplane containing given feature -// ============================================================================ -std::shared_ptr SketchSolver_Manager -::findWorkplane(std::shared_ptr theFeature) const -{ - // Already verified workplanes - std::set > aVerified; - - std::list::const_iterator aGroupIter; - for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) { - std::shared_ptr aWP = (*aGroupIter)->getWorkplane(); - if (aVerified.find(aWP) != aVerified.end()) - continue; - - DataPtr aData = aWP->data(); - if (aData->isValid()) { - std::shared_ptr aWPFeatures = std::dynamic_pointer_cast< - ModelAPI_AttributeRefList>(aData->attribute(SketchPlugin_Sketch::FEATURES_ID())); - std::list aFeaturesList = aWPFeatures->list(); - std::list::const_iterator anIter; - for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++) - if (*anIter == theFeature) - return aWP; // workplane is found - } - aVerified.insert(aWP); - } + std::list::const_iterator aGroupIt; + for (aGroupIt = myGroups.begin(); aGroupIt != myGroups.end(); ++aGroupIt) + if ((*aGroupIt)->getWorkplane() == aSketch) + return *aGroupIt; - return std::shared_ptr(); + // group for the sketch does not created yet + SketchGroupPtr aNewGroup = SketchGroupPtr(new SketchSolver_Group(aSketch)); + myGroups.push_back(aNewGroup); + return aNewGroup; } // ============================================================================ // Function: resolveConstraints // Purpose: change entities according to available constraints // ============================================================================ -bool SketchSolver_Manager::resolveConstraints(const std::list& theGroups) +bool SketchSolver_Manager::resolveConstraints() { bool needToUpdate = false; - const std::list& aGroupsToResolve = theGroups.empty() ? - myGroups : theGroups; - std::list::const_iterator aGroupIter = aGroupsToResolve.begin(); - for (; aGroupIter != aGroupsToResolve.end(); aGroupIter++) + std::list::const_iterator aGroupIter = myGroups.begin(); + for (; aGroupIter != myGroups.end(); ++aGroupIter) { if ((*aGroupIter)->resolveConstraints()) needToUpdate = true; - return needToUpdate; -} - - -// Obtain points and their copies for Mirror, Multi-Rotation and Multi-Translation constraints -static void collectPointsAndCopies(FeaturePtr theConstraint, - std::list >& thePoints) -{ - typedef std::list strlist; - static strlist aPointAttributes(1, SketchPlugin_Point::COORD_ID()); - static strlist aLineAttributes; - if (aLineAttributes.empty()) { - aLineAttributes.push_back(SketchPlugin_Line::START_ID()); - aLineAttributes.push_back(SketchPlugin_Line::END_ID()); - }; - static strlist aCircleAttributes(1, SketchPlugin_Circle::CENTER_ID()); - static strlist anArcAttributes; - if (anArcAttributes.empty()) { - anArcAttributes.push_back(SketchPlugin_Arc::CENTER_ID()); - anArcAttributes.push_back(SketchPlugin_Arc::START_ID()); - anArcAttributes.push_back(SketchPlugin_Arc::END_ID()); - }; - - static std::map aFeatureAttributes; - if (aFeatureAttributes.empty()) { - aFeatureAttributes[SketchPlugin_Point::ID()] = aPointAttributes; - aFeatureAttributes[SketchPlugin_Line::ID()] = aLineAttributes; - aFeatureAttributes[SketchPlugin_Circle::ID()] = aCircleAttributes; - aFeatureAttributes[SketchPlugin_Arc::ID()] = anArcAttributes; - } - - - std::set aPoints; - if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) { - AttributeRefListPtr aBaseRefList = theConstraint->reflist(SketchPlugin_Constraint::ENTITY_B()); - AttributeRefListPtr aMirrRefList = theConstraint->reflist(SketchPlugin_Constraint::ENTITY_C()); - - std::list aBaseList = aBaseRefList->list(); - std::list aMirrList = aMirrRefList->list(); - std::list::const_iterator aBIt, aMIt; - for (aBIt = aBaseList.begin(), aMIt = aMirrList.begin(); - aBIt != aBaseList.end() && aMIt != aMirrList.end(); ++aBIt, ++aMIt) { - FeaturePtr aBaseFeature = ModelAPI_Feature::feature(*aBIt); - FeaturePtr aMirrFeature = ModelAPI_Feature::feature(*aMIt); - - strlist anAttrList = aFeatureAttributes[aBaseFeature->getKind()]; - strlist::iterator anIt = anAttrList.begin(); - for (; anIt != anAttrList.end(); ++anIt) { - aPoints.clear(); - aPoints.insert(aBaseFeature->attribute(*anIt)); - aPoints.insert(aMirrFeature->attribute(*anIt)); - thePoints.push_back(aPoints); - } - } - } - else { // the "Multi" constraints - std::string aNbObjName; - if (theConstraint->getKind() == SketchPlugin_MultiRotation::ID()) - aNbObjName = SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID(); - else - aNbObjName = SketchPlugin_MultiTranslation::NUMBER_OF_OBJECTS_ID(); - int aNbCopies = theConstraint->integer(aNbObjName)->value(); - - AttributeRefListPtr aRefList = theConstraint->reflist(SketchPlugin_Constraint::ENTITY_B()); - std::list aFullList = aRefList->list(); - std::list::const_iterator anObjIt = aFullList.begin(); - std::list::const_iterator aCopyIt; - while (anObjIt != aFullList.end()) { - FeaturePtr aBaseFeature = ModelAPI_Feature::feature(*anObjIt); - strlist anAttrList = aFeatureAttributes[aBaseFeature->getKind()]; - strlist::iterator anIt = anAttrList.begin(); - for (; anIt != anAttrList.end(); ++anIt) { - aPoints.clear(); - aCopyIt = anObjIt; - for (int i = 0; i < aNbCopies && aCopyIt != aFullList.end(); ++i, ++aCopyIt) { - FeaturePtr aFeature = ModelAPI_Feature::feature(*aCopyIt); - aPoints.insert(aFeature->attribute(*anIt)); - } - thePoints.push_back(aPoints); - } - anObjIt = aCopyIt; - } - } -} - - -// returns true if the feature is external -static bool isExternal(const FeaturePtr& theFeature) -{ - AttributeSelectionPtr anAttr = theFeature->selection(SketchPlugin_SketchEntity::EXTERNAL_ID()); - return anAttr && anAttr->context() && !anAttr->isInvalid(); -} - -// ============================================================================ -// Function: degreesOfFreedom -// Purpose: calculate DoFs for each sketch -// ============================================================================ -void SketchSolver_Manager::degreesOfFreedom() -{ - static std::map aDoFDelta; // indicates how many DoF adds or decreases a feature - static bool isNeedInit = true; - if (isNeedInit) { - aDoFDelta[SketchPlugin_Point::ID()] = 2; - aDoFDelta[SketchPlugin_Line::ID()] = 4; - aDoFDelta[SketchPlugin_Circle::ID()] = 3; - aDoFDelta[SketchPlugin_Arc::ID()] = 5; - - aDoFDelta[SketchPlugin_ConstraintAngle::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintCollinear::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintDistance::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintEqual::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintHorizontal::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintLength::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintParallel::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintPerpendicular::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintRadius::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintTangent::ID()] = -1; - aDoFDelta[SketchPlugin_ConstraintVertical::ID()] = -1; - - isNeedInit = false; - } - - std::map aSketchDoF; - - std::list::const_iterator aGroupIt = myGroups.begin(); - for (; aGroupIt != myGroups.end(); ++aGroupIt) { - CompositeFeaturePtr aSketch = (*aGroupIt)->getWorkplane(); - bool isSketchValid = aSketch->data() && aSketch->data()->isValid(); - - if (isSketchValid) { - std::shared_ptr aNormal = - std::dynamic_pointer_cast( - aSketch->data()->attribute(SketchPlugin_Sketch::NORM_ID())); - isSketchValid = aNormal && aNormal->isInitialized(); - } - - if (!isSketchValid) { - myDoF.erase(aSketch); - continue; - } - - // check conflicting constraints in the group - if ((*aGroupIt)->isFailed()) - aSketchDoF[aSketch] = -1; - // check the sketch is already processed - if (aSketchDoF.find(aSketch) != aSketchDoF.end() || aSketchDoF[aSketch] < 0) - continue; - - std::set aCoincidentPoints; - std::set aFixedPoints; - std::map > aPointOnLine; - std::list > aPointsInMultiConstraints; - int aDoF = 0; - int aNbSubs = aSketch->numberOfSubs(); - for (int i = 0; i < aNbSubs; ++i) { - FeaturePtr aFeature = aSketch->subFeature(i); - // do not change DoF for external feature - if (isExternal(aFeature)) - continue; - // check DoF delta for invariant types - std::map::const_iterator aFound = aDoFDelta.find(aFeature->getKind()); - if (aFound != aDoFDelta.end()) { - aDoF += aFound->second; - continue; - } - - // DoF delta in specific cases - if (aFeature->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { - AttributePtr aCoincPoint[2] = {AttributePtr(), AttributePtr()}; - FeaturePtr aCoincLine; - for (int j = 0; j < 2; ++j) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Constraint::ATTRIBUTE(j))); - if (!aRefAttr) - continue; - if (!aRefAttr->isObject()) - aCoincPoint[j] = aRefAttr->attr(); - else { - FeaturePtr anAttr = ModelAPI_Feature::feature(aRefAttr->object()); - if (!anAttr) - continue; - if (anAttr->getKind() == SketchPlugin_Point::ID()) - aCoincPoint[j] = anAttr->attribute(SketchPlugin_Point::COORD_ID()); - else if (anAttr->getKind() == SketchPlugin_Line::ID()) - aCoincLine = anAttr; - } - } - if (aCoincPoint[0] && aCoincPoint[1]) { - bool isDoFDecreased = false; - // point-point coincidence - if (aCoincidentPoints.find(aCoincPoint[0]) == aCoincidentPoints.end() || - aCoincidentPoints.find(aCoincPoint[1]) == aCoincidentPoints.end()) { - aDoF -= 2; - isDoFDecreased = true; - } - // check the coincident point is used in "multi" constraints - std::list >::const_iterator - aPtIt = aPointsInMultiConstraints.begin(); - bool isFound[2] = {false, false}; - for (; aPtIt != aPointsInMultiConstraints.end(); ++aPtIt) { - if ((!isFound[0] && (isFound[0] = (aPtIt->find(aCoincPoint[0]) != aPtIt->end()))) - || (!isFound[1] && (isFound[1] = (aPtIt->find(aCoincPoint[1]) != aPtIt->end())))) - aCoincidentPoints.insert(aPtIt->begin(), aPtIt->end()); - if (isFound[0] && isFound[1]) - break; - } - // check both points are fixed => not need to decrease DoF - bool isFixed[2] = { aFixedPoints.find(aCoincPoint[0]) != aFixedPoints.end(), - aFixedPoints.find(aCoincPoint[1]) != aFixedPoints.end() }; - if (isFixed[0] && isFixed[1] && isDoFDecreased) - aDoF += 2; // revert decrease of DoF - else if (isFixed[0] && !isFixed[1]) - aFixedPoints.insert(aCoincPoint[1]); - else if (!isFixed[0] && isFixed[1]) - aFixedPoints.insert(aCoincPoint[0]); - } else { - aDoF -= 1; - if (aCoincPoint[0] && aCoincLine) { - // if the point is already coincident to a line - // (by middle point constraint), do not decrease DoF - std::map >::iterator - aPtFound = aPointOnLine.find(aCoincPoint[0]); - if (aPtFound != aPointOnLine.end() && - aPtFound->second.find(aCoincLine) != aPtFound->second.end()) - aDoF += 1; // restore value decreased above - else - aPointOnLine[aCoincPoint[0]].insert(aCoincLine); - } - } - for (int j = 0; j < 2; ++j) - if (aCoincPoint[j]) - aCoincidentPoints.insert(aCoincPoint[j]); - } - else if (aFeature->getKind() == SketchPlugin_ConstraintMiddle::ID()) { - AttributePtr aPoint; - FeaturePtr aLine; - for (int j = 0; j < 2; ++j) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Constraint::ATTRIBUTE(j))); - if (!aRefAttr) - continue; - if (aRefAttr->isObject()) - aLine = ModelAPI_Feature::feature(aRefAttr->object()); - else - aPoint = aRefAttr->attr(); - } - if (aPoint && aLine) { - // if the point is already on the line, decrease 1 DoF, instead decrease 2 DoF - std::map >::iterator - aPtFound = aPointOnLine.find(aPoint); - if (aPtFound != aPointOnLine.end() && - aPtFound->second.find(aLine) != aPtFound->second.end()) - aDoF -= 1; - else { - aDoF -= 2; - aPointOnLine[aPoint].insert(aLine); - } - } - } - else if (aFeature->getKind() == SketchPlugin_ConstraintRigid::ID()) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Constraint::ENTITY_A())); - assert(aRefAttr); - std::set aPoints; - if (!aRefAttr->isObject()) { - aDoF -= 2; // attribute is a point - aPoints.insert(aRefAttr->attr()); - } else { - FeaturePtr anAttr = ModelAPI_Feature::feature(aRefAttr->object()); - if (anAttr) { - if (isExternal(anAttr)) - continue; // feature is already fixed since it is external - aDoF -= aDoFDelta[anAttr->getKind()]; - std::list aPtAttrs = - anAttr->data()->attributes(GeomDataAPI_Point2D::typeId()); - aPoints.insert(aPtAttrs.begin(), aPtAttrs.end()); - } - } - - // Check whether feature's points are already coincident with fixed points. - // In this case we need to revert decrease of DoF for these points. - // If the coordinates of fixed points are different, it will be processed by solver. - for (int k = 0; k < i; ++k) { - FeaturePtr aFeature = aSketch->subFeature(k); - if (aFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID()) - continue; - AttributePtr aCoincPoint[2] = {AttributePtr(), AttributePtr()}; - for (int j = 0; j < 2; ++j) { - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( - aFeature->attribute(SketchPlugin_Constraint::ATTRIBUTE(j))); - if (!aRefAttr) - continue; - if (!aRefAttr->isObject()) - aCoincPoint[j] = aRefAttr->attr(); - else { - FeaturePtr anAttr = ModelAPI_Feature::feature(aRefAttr->object()); - if (anAttr && anAttr->getKind() == SketchPlugin_Point::ID()) - aCoincPoint[j] = anAttr->attribute(SketchPlugin_Point::COORD_ID()); - } - } - if (aCoincPoint[0] && aCoincPoint[1]) { - if ((aFixedPoints.find(aCoincPoint[0]) != aFixedPoints.end() && - aPoints.find(aCoincPoint[1]) != aPoints.end()) || - (aFixedPoints.find(aCoincPoint[1]) != aFixedPoints.end() && - aPoints.find(aCoincPoint[0]) != aPoints.end())) - aDoF += 2; // point already fixed - } - } - // store fixed points - aFixedPoints.insert(aPoints.begin(), aPoints.end()); - } - else if (aFeature->getKind() == SketchPlugin_ConstraintMirror::ID() || - aFeature->getKind() == SketchPlugin_MultiRotation::ID() || - aFeature->getKind() == SketchPlugin_MultiTranslation::ID()) { - int aNbCopies = 1; - std::string anAttrName; - if (aFeature->getKind() == SketchPlugin_ConstraintMirror::ID()) - anAttrName = SketchPlugin_Constraint::ENTITY_B(); - else { - if (aFeature->getKind() == SketchPlugin_MultiRotation::ID()) - aNbCopies = - aFeature->integer(SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID())->value() - 1; - else if (aFeature->getKind() == SketchPlugin_MultiTranslation::ID()) - aNbCopies = - aFeature->integer(SketchPlugin_MultiTranslation::NUMBER_OF_OBJECTS_ID())->value() - 1; - anAttrName = SketchPlugin_Constraint::ENTITY_A(); - } - - AttributeRefListPtr aRefListOfShapes = std::dynamic_pointer_cast( - aFeature->attribute(anAttrName)); - std::list anObjList = aRefListOfShapes->list(); - std::list::const_iterator anObjIt = anObjList.begin(); - for (; anObjIt != anObjList.end(); ++anObjIt) { - FeaturePtr aSub = ModelAPI_Feature::feature(*anObjIt); - aDoF -= aDoFDelta[aSub->getKind()] * aNbCopies; - } - // collect points and their copies for correct calculation of DoF for coincident points - collectPointsAndCopies(aFeature, aPointsInMultiConstraints); - } - } - - aSketchDoF[aSketch] = aDoF; - } - - // Check the degrees of freedom are changed - std::map::const_iterator aDoFIt = aSketchDoF.begin(); - std::map::iterator aFound; - for (; aDoFIt != aSketchDoF.end(); ++aDoFIt) { - if (aDoFIt->second < 0) - continue; // conflicting constraints on the current sketch - aFound = myDoF.find(aDoFIt->first); - if (aFound != myDoF.end() && aFound->second == aDoFIt->second) - continue; // nothing is changed - myDoF[aDoFIt->first] = aDoFIt->second; - // change attribute value - std::ostringstream aStream; - if (aDoFIt->second == 0) - aStream << "Sketch fully fixed (DOF = " << aDoFIt->second << ")"; - else - aStream << "DOF (degree of freedom) = " << aDoFIt->second; - aDoFIt->first->data()->string(SketchPlugin_Sketch::SOLVER_DOF())->setValue(aStream.str()); + (*aGroupIter)->blockEvents(false); } + return needToUpdate; } bool SketchSolver_Manager::stopSendUpdate() const { +static const Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED); // to avoid redisplay of each segment on update by solver one by one in the viewer bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent); if (isUpdateFlushed) { @@ -879,5 +268,5 @@ bool SketchSolver_Manager::stopSendUpdate() const void SketchSolver_Manager::allowSendUpdate() const { - Events_Loop::loop()->setFlushed(anUpdateEvent, true); + Events_Loop::loop()->setFlushed(Events_Loop::eventByName(EVENT_OBJECT_UPDATED), true); } diff --git a/src/SketchSolver/SketchSolver_Manager.h b/src/SketchSolver/SketchSolver_Manager.h index c1e853603..89a9b7acc 100644 --- a/src/SketchSolver/SketchSolver_Manager.h +++ b/src/SketchSolver/SketchSolver_Manager.h @@ -20,11 +20,7 @@ /** \class SketchSolver_Manager * \ingroup Plugins * \brief Listens the changes of SketchPlugin features and transforms the Constraint - * feature into the format understandable by SolveSpace library. - * - * Constraints created for SolveSpace library are divided into the groups. - * The division order based on connectedness of the features by the constraints. - * The groups may be fused or separated according to the new constraints. + * feature into the format understandable by sketch solver. * * \remark This is a singleton. */ @@ -34,7 +30,7 @@ public: /** \brief Main method to create constraint manager * \return pointer to the singleton */ - SKETCHSOLVER_EXPORT static SketchSolver_Manager* instance(); + static SketchSolver_Manager* instance(); /** \brief Implementation of Event Listener method * \param[in] theMessage the data of the event @@ -49,7 +45,7 @@ public: /// \brief Initialize builder for solver's data structure entities /// \param theBuilder [in] solver's specific builder - SKETCHSOLVER_EXPORT void setBuilder(BuilderPtr theBuilder); + void setBuilder(BuilderPtr theBuilder); /// \brief Returns the builder specific for the solver BuilderPtr builder(); @@ -59,9 +55,10 @@ protected: /** \brief Adds or updates a constraint or an entity in the suitable group * \param[in] theFeature sketch feature to be changed + * \param[in] theMoved \c true if the feature has been moved in the viewer * \return \c true if the feature changed successfully */ - bool changeFeature(std::shared_ptr theFeature); + bool updateFeature(std::shared_ptr theFeature, bool theMoved = false); /** \brief Removes a constraint from the manager * \param[in] theConstraint constraint to be removed @@ -69,48 +66,18 @@ protected: */ bool removeConstraint(std::shared_ptr theConstraint); - /** \brief Adds or updates a workplane in the manager - * \param[in] theSketch the feature to create or update workplane - * \return \c true if the workplane changed successfully - * \remark Type of theSketch is not verified inside - */ - bool changeWorkplane(CompositeFeaturePtr theSketch); - - /** \brief Removes a workplane from the manager. - * All groups based on such workplane will be removed too. - * \param[in] theSketch the feature to be removed - * \return \c true if the workplane removed successfully - */ - bool removeWorkplane(std::shared_ptr theSketch); - - /** \brief Updates entity which is moved in GUI - * \param[in] theFeature entity to be updated - * \return \c true, if the entity has been moved - */ - bool moveEntity(std::shared_ptr theFeature); - /** \brief Goes through the list of groups and solve the constraints - * \param[in] theGroups list of groups to be resolved (if empty list, all groups are resolved) * \return \c true, if groups are resolved, and features should be updated * (send the Update event) */ - bool resolveConstraints(const std::list& theGroups = - std::list()); + bool resolveConstraints(); private: - /** \brief Searches list of groups which interact with specified feature + /** \brief Searches group which interact with specified feature * \param[in] theFeature object to be found - * \param[out] theGroups list of group indexes interacted with the feature - */ - void findGroups(std::shared_ptr theFeature, - std::set& theGroupIDs) const; - - /** \brief Searches in the list of groups the workplane which contains specified feature - * \param[in] theFeature object to be found - * \return workplane containing the feature + * \return Pointer to corresponding group or NULL if the group cannot be created. */ - std::shared_ptr findWorkplane( - std::shared_ptr theFeature) const; + SketchGroupPtr findGroup(std::shared_ptr theFeature); /// \brief Stop sending the Update event until all features updated /// \return \c true, if the last flushed event is Update @@ -118,22 +85,12 @@ private: /// \brief Allow to send the Update event void allowSendUpdate() const; - /// \brief If the message shows that any group is repaired after conflicting, - /// find other groups on the same sketch, which have conflicts. - void checkConflictingConstraints(const std::shared_ptr& theMessage); - - /// \brief Calculate DoF for each sketch and send messages if changed - void degreesOfFreedom(); - private: - static SketchSolver_Manager* mySelf; ///< Self pointer to implement singleton functionality - std::list myGroups; ///< Groups of constraints - BuilderPtr myBuilder; ///< Builder for solver's entities + std::list myGroups; ///< Groups of constraints + BuilderPtr myBuilder; ///< Builder for solver's entities /// true if computation is performed and all "updates" are generated by this algo /// and needs no recomputation bool myIsComputed; - - std::map myDoF; ///< Degree of freedom for corresponding sketch }; #endif diff --git a/src/SketchSolver/SketchSolver_Storage.cpp b/src/SketchSolver/SketchSolver_Storage.cpp index d1f6c4f17..81714314f 100644 --- a/src/SketchSolver/SketchSolver_Storage.cpp +++ b/src/SketchSolver/SketchSolver_Storage.cpp @@ -5,9 +5,9 @@ // Author: Artem ZHIDKOV #include -#include +#include +#include -#include #include #include #include @@ -18,73 +18,61 @@ #include #include #include -#include -/// \brief Verify two vectors of constraints are equal. -/// Vectors differ by the order of elements are equal. -static bool isEqual(const std::list& theCVec1, - const std::list& theCVec2); - -/// \brief Convert result to feature or attribute -static void resultToFeatureOrAttribute(const ObjectPtr& theResult, - FeaturePtr& theFeature, AttributePtr& theAttribute); - - -void SketchSolver_Storage::addConstraint(ConstraintPtr theConstraint, - ConstraintWrapperPtr theSolverConstraint) +SketchSolver_Storage::SketchSolver_Storage(SolverPtr theSolver) + : mySketchSolver(theSolver), + myNeedToResolve(false), + myEventsBlocked(false) { - if (theSolverConstraint) { - std::list aConstrList(1, theSolverConstraint); - addConstraint(theConstraint, aConstrList); - } else - addConstraint(theConstraint, std::list()); + // create updaters (constraints processed at first) + UpdaterPtr aFeatureUpdater(new PlaneGCSSolver_UpdateFeature); + myUpdaters = UpdaterPtr(new PlaneGCSSolver_UpdateCoincidence(aFeatureUpdater)); } -void SketchSolver_Storage::addConstraint( - ConstraintPtr theConstraint, - std::list theSolverConstraints) +void SketchSolver_Storage::addConstraint(ConstraintPtr theConstraint, + ConstraintWrapperPtr theSolverConstraint) { - std::map >::const_iterator + std::map::const_iterator aFound = myConstraintMap.find(theConstraint); - if (aFound == myConstraintMap.end() || !isEqual(aFound->second, theSolverConstraints)) + if (aFound == myConstraintMap.end() || aFound->second != theSolverConstraint) setNeedToResolve(true); - if (theSolverConstraints.empty()) { - // constraint links to the empty list, add its attributes linked to the empty entities - std::list aRefAttrs = - theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId()); - std::list::const_iterator anAttrIt = aRefAttrs.begin(); - for (; anAttrIt != aRefAttrs.end(); ++anAttrIt) { - AttributeRefAttrPtr aRef = std::dynamic_pointer_cast(*anAttrIt); - if (aRef->isObject()) { - FeaturePtr aFeature = ModelAPI_Feature::feature(aRef->object()); - if (aFeature) addEntity(aFeature, EntityWrapperPtr()); - } else - addEntity(aRef->attr(), EntityWrapperPtr()); - } - std::list aRefLists = - theConstraint->data()->attributes(ModelAPI_AttributeRefList::typeId()); - for (anAttrIt = aRefLists.begin(); anAttrIt != aRefLists.end(); ++anAttrIt) { - AttributeRefListPtr aRef = std::dynamic_pointer_cast(*anAttrIt); - std::list anObj = aRef->list(); - std::list::iterator anIt = anObj.begin(); - for (; anIt != anObj.end(); ++anIt) { - FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt); - if (aFeature) addEntity(aFeature, EntityWrapperPtr()); - } - } - } - else if (theSolverConstraints.front()->type() != CONSTRAINT_PT_PT_COINCIDENT) { - // Do not add point-point coincidence, because it is already made by setting - // the same parameters for both points - std::list::iterator aCIt = theSolverConstraints.begin(); - for (; aCIt != theSolverConstraints.end(); ++aCIt) - update(*aCIt); - } - - if (!theSolverConstraints.empty() || aFound == myConstraintMap.end()) - myConstraintMap[theConstraint] = theSolverConstraints; +//// if (theSolverConstraints.empty()) { +//// // constraint links to the empty list, add its attributes linked to the empty entities +//// std::list aRefAttrs = +//// theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId()); +//// std::list::const_iterator anAttrIt = aRefAttrs.begin(); +//// for (; anAttrIt != aRefAttrs.end(); ++anAttrIt) { +//// AttributeRefAttrPtr aRef = std::dynamic_pointer_cast(*anAttrIt); +//// if (aRef->isObject()) { +//// FeaturePtr aFeature = ModelAPI_Feature::feature(aRef->object()); +//// if (aFeature) addEntity(aFeature, EntityWrapperPtr()); +//// } else +//// addEntity(aRef->attr(), EntityWrapperPtr()); +//// } +//// std::list aRefLists = +//// theConstraint->data()->attributes(ModelAPI_AttributeRefList::typeId()); +//// for (anAttrIt = aRefLists.begin(); anAttrIt != aRefLists.end(); ++anAttrIt) { +//// AttributeRefListPtr aRef = std::dynamic_pointer_cast(*anAttrIt); +//// std::list anObj = aRef->list(); +//// std::list::iterator anIt = anObj.begin(); +//// for (; anIt != anObj.end(); ++anIt) { +//// FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt); +//// if (aFeature) addEntity(aFeature, EntityWrapperPtr()); +//// } +//// } +//// } +//// else if (theSolverConstraints.front()->type() != CONSTRAINT_PT_PT_COINCIDENT) { +//// // Do not add point-point coincidence, because it is already made by setting +//// // the same parameters for both points +//// std::list::iterator aCIt = theSolverConstraints.begin(); +//// for (; aCIt != theSolverConstraints.end(); ++aCIt) +//// update(*aCIt); +//// } + + if (!theSolverConstraint || aFound == myConstraintMap.end()) + myConstraintMap[theConstraint] = theSolverConstraint; // block events if necessary if (myEventsBlocked && theConstraint && theConstraint->data() && theConstraint->data()->isValid()) theConstraint->data()->blockSendAttributeUpdated(myEventsBlocked); @@ -115,21 +103,17 @@ static std::list pointAttributes(FeaturePtr theFeature) void SketchSolver_Storage::addEntity(FeaturePtr theFeature, EntityWrapperPtr theSolverEntity) { - std::map::const_iterator aFound = myFeatureMap.find(theFeature); - if (aFound == myFeatureMap.end() || !aFound->second || - (theSolverEntity && !aFound->second->isEqual(theSolverEntity))) - setNeedToResolve(true); // the entity is new or modified - - if (!theSolverEntity) { + if (theSolverEntity) { + myFeatureMap[theFeature] = theSolverEntity; + setNeedToResolve(true); + } else { // feature links to the empty entity, add its attributes std::list aPntAttrs = pointAttributes(theFeature); std::list::const_iterator anAttrIt = aPntAttrs.begin(); for (; anAttrIt != aPntAttrs.end(); ++anAttrIt) addEntity(*anAttrIt, EntityWrapperPtr()); - if (aFound == myFeatureMap.end()) - myFeatureMap[theFeature] = theSolverEntity; - } else myFeatureMap[theFeature] = theSolverEntity; + } // block events if necessary if (myEventsBlocked && theFeature->data() && theFeature->data()->isValid()) @@ -139,14 +123,11 @@ void SketchSolver_Storage::addEntity(FeaturePtr theFeature, void SketchSolver_Storage::addEntity(AttributePtr theAttribute, EntityWrapperPtr theSolverEntity) { - std::map::const_iterator aFound = - myAttributeMap.find(theAttribute); - if (aFound == myAttributeMap.end() || !aFound->second || - (theSolverEntity && !aFound->second->isEqual(theSolverEntity))) - setNeedToResolve(true); // the entity is new or modified - - if (theSolverEntity || aFound == myAttributeMap.end()) + if (theSolverEntity) { myAttributeMap[theAttribute] = theSolverEntity; + setNeedToResolve(true); + } + // block events if necessary if (myEventsBlocked && theAttribute->owner() && theAttribute->owner()->data() && theAttribute->owner()->data()->isValid()) @@ -154,140 +135,13 @@ void SketchSolver_Storage::addEntity(AttributePtr theAttribute, } -static bool isCopyInMulti(std::shared_ptr theFeature, - const std::map >& theConstraints) -{ - if (!theFeature) - return false; - bool aResult = theFeature->isCopy(); - if (aResult) { - const std::set& aRefs = theFeature->data()->refsToMe(); - for (std::set::const_iterator aRefIt = aRefs.begin(); - aRefIt != aRefs.end() && aResult; ++aRefIt) { - FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner()); - if ((anOwner->getKind() == SketchPlugin_ConstraintMirror::ID() && - (*aRefIt)->id() == SketchPlugin_Constraint::ENTITY_C()) || - (anOwner->getKind() == SketchPlugin_Projection::ID())) - aResult = false; - } - } - return aResult; -} - -bool SketchSolver_Storage::update(FeaturePtr theFeature, const GroupID& theGroup, bool theForce) -{ - bool isUpdated = false; - EntityWrapperPtr aRelated = entity(theFeature); - if (!aRelated) { // Feature is not exist, create it - std::shared_ptr aSketchFeature = - std::dynamic_pointer_cast(theFeature); - bool isCopy = isCopyInMulti(aSketchFeature, myConstraintMap); - // the feature is a copy in "Multi" constraint and does not used in other constraints - if (!theForce && isCopy && myFeatureMap.find(theFeature) == myFeatureMap.end()) - return false; - - std::list aSubs; - // Reserve the feature in the map of features (do not want to add several copies of it) - myFeatureMap[theFeature] = aRelated; - // Firstly, create/update its attributes - std::list anAttrs = pointAttributes(theFeature); - std::list::const_iterator anIt = anAttrs.begin(); - for (; anIt != anAttrs.end(); ++anIt) { - if (!(*anIt)->isInitialized()) - return false; - isUpdated = update(*anIt, theGroup, theForce) || isUpdated; - aSubs.push_back(entity(*anIt)); - } - // If the feature is a circle, add its radius as a sub - if (theFeature->getKind() == SketchPlugin_Circle::ID()) { - AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID()); - isUpdated = update(aRadius, theGroup, theForce) || isUpdated; - aSubs.push_back(entity(aRadius)); - } - // If the feature if circle or arc, we need to add normal of the sketch to the list of subs - if (theFeature->getKind() == SketchPlugin_Arc::ID() || - theFeature->getKind() == SketchPlugin_Circle::ID()) { - EntityWrapperPtr aNormal = getNormal(); - if (aNormal) aSubs.push_back(aNormal); - } - // Secondly, convert feature - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - GroupID aGroup = theGroup != GID_UNKNOWN ? theGroup : myGroupID; - // Check external feature - if (aSketchFeature && (aSketchFeature->isExternal() || isCopy)) - aGroup = GID_OUTOFGROUP; - aRelated = aBuilder->createFeature(theFeature, aSubs, aGroup); - if (!aRelated) - return false; - addEntity(theFeature, aRelated); - } else if (theGroup != GID_UNKNOWN) - changeGroup(aRelated, theGroup); - return update(aRelated) || isUpdated; -} - -bool SketchSolver_Storage::update(AttributePtr theAttribute, const GroupID& theGroup, bool theForce) -{ - if (!theAttribute->isInitialized()) - return false; - - AttributePtr anAttribute = theAttribute; - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(anAttribute); - if (aRefAttr) { - if (aRefAttr->isObject()) { - FeaturePtr aFeature; - resultToFeatureOrAttribute(aRefAttr->object(), aFeature, anAttribute); - if (aFeature) - return update(aFeature, theGroup, theForce); - } else { - anAttribute = aRefAttr->attr(); - if (!anAttribute->isInitialized()) - return false; - } - } - - EntityWrapperPtr aRelated = entity(anAttribute); - if (!aRelated) { // Attribute is not exist, create it - // verify the attribute is a point of arc and add whole arc - if (anAttribute->owner()) { - FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner()); - if (aFeature->getKind() == SketchPlugin_Arc::ID() && - myFeatureMap.find(aFeature) == myFeatureMap.end()) { - // Additional checking that all attributes are initialized - if (aFeature->attribute(SketchPlugin_Arc::CENTER_ID())->isInitialized() && - aFeature->attribute(SketchPlugin_Arc::START_ID())->isInitialized() && - aFeature->attribute(SketchPlugin_Arc::END_ID())->isInitialized()) { - return SketchSolver_Storage::update(aFeature, theGroup, theForce); - } else { - myFeatureMap[aFeature] = EntityWrapperPtr(); - myExistArc = true; - } - } - } - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - GroupID aGroup = theGroup != GID_UNKNOWN ? theGroup : myGroupID; - // Check attribute of external features - std::shared_ptr aSketchFeature = - std::dynamic_pointer_cast(anAttribute->owner()); - if (aSketchFeature && (aSketchFeature->isExternal() || - isCopyInMulti(aSketchFeature, myConstraintMap))) - aGroup = GID_OUTOFGROUP; - aRelated = aBuilder->createAttribute(anAttribute, aGroup); - if (!aRelated) - return false; - addEntity(anAttribute, aRelated); - } else if (theGroup != GID_UNKNOWN) - changeGroup(aRelated, theGroup); - return update(aRelated); -} - - -const std::list& SketchSolver_Storage::constraint( +const ConstraintWrapperPtr& SketchSolver_Storage::constraint( const ConstraintPtr& theConstraint) const { - static std::list aDummy; + static ConstraintWrapperPtr aDummy; - std::map>::const_iterator + std::map::const_iterator aFound = myConstraintMap.find(theConstraint); if (aFound != myConstraintMap.end()) return aFound->second; @@ -296,18 +150,16 @@ const std::list& SketchSolver_Storage::constraint( const EntityWrapperPtr& SketchSolver_Storage::entity(const FeaturePtr& theFeature) const { - static EntityWrapperPtr aDummy; - std::map::const_iterator aFound = myFeatureMap.find(theFeature); if (aFound != myFeatureMap.end()) return aFound->second; + + static EntityWrapperPtr aDummy; return aDummy; } const EntityWrapperPtr& SketchSolver_Storage::entity(const AttributePtr& theAttribute) const { - static EntityWrapperPtr aDummy; - std::map::const_iterator aFound = myAttributeMap.find(theAttribute); if (aFound != myAttributeMap.end()) @@ -316,471 +168,40 @@ const EntityWrapperPtr& SketchSolver_Storage::entity(const AttributePtr& theAttr AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(theAttribute); if (aRefAttr) { + AttributePtr anAttribute; + if (aRefAttr->isObject()) { + /// TODO: Check resultToFeatureOrAttribute() precisely. Create additional unit-test FeaturePtr aFeature; - AttributePtr anAttribute; resultToFeatureOrAttribute(aRefAttr->object(), aFeature, anAttribute); if (aFeature) return entity(aFeature); - else - return entity(anAttribute); } else - return entity(aRefAttr->attr()); - } - return aDummy; -} - -bool SketchSolver_Storage::removeConstraint(ConstraintPtr theConstraint) -{ - std::map >::iterator - aFound = myConstraintMap.find(theConstraint); - if (aFound == myConstraintMap.end()) - return true; // no constraint, already deleted - - // Remove constraint - std::list aConstrList = aFound->second; - myConstraintMap.erase(aFound); - // Remove SolveSpace constraints - bool isFullyRemoved = true; - std::list::iterator anIt = aConstrList.begin(); - while (anIt != aConstrList.end()) { - if (remove(*anIt)) { - std::list::iterator aRemoveIt = anIt++; - aConstrList.erase(aRemoveIt); - } else { - isFullyRemoved = false; - ++anIt; - } - } - return isFullyRemoved; -} - -template -static bool isUsed(ConstraintWrapperPtr theConstraint, ENT_TYPE theEntity) -{ - if (!theConstraint || !theEntity) - return false; - std::list::const_iterator anEntIt = theConstraint->entities().begin(); - for (; anEntIt != theConstraint->entities().end(); ++anEntIt) - if ((*anEntIt)->isBase(theEntity)) - return true; - return false; -} - -static bool isUsed(EntityWrapperPtr theFeature, AttributePtr theSubEntity) -{ - if (!theFeature || !theSubEntity) - return false; - std::list::const_iterator aSubIt = theFeature->subEntities().begin(); - for (; aSubIt != theFeature->subEntities().end(); ++aSubIt) - if ((*aSubIt)->isBase(theSubEntity)) - return true; - return false; -} - -static bool isUsed(FeaturePtr theFeature, AttributePtr theAttribute) -{ - if (!theFeature || !theAttribute) - return false; - std::list anAttrList = theFeature->data()->attributes(std::string()); - std::list::const_iterator anIt = anAttrList.begin(); - for (; anIt != anAttrList.end(); ++anIt) { - if (*anIt == theAttribute) - return true; - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(*anIt); - if (aRefAttr && !aRefAttr->isObject() && aRefAttr->attr() == theAttribute) - return true; - } - return false; -} - -bool SketchSolver_Storage::isUsed(FeaturePtr theFeature) const -{ - if (myFeatureMap.find(theFeature) != myFeatureMap.end()) - return true; - // check constraints - std::map >::const_iterator - aCIt = myConstraintMap.begin(); - std::list::const_iterator aCWIt; - for (; aCIt != myConstraintMap.end(); ++aCIt) - for (aCWIt = aCIt->second.begin(); aCWIt != aCIt->second.end(); ++aCWIt) - if (::isUsed(*aCWIt, theFeature)) - return true; - // check attributes - std::list anAttrList = pointAttributes(theFeature); - std::list::const_iterator anIt = anAttrList.begin(); - for (; anIt != anAttrList.end(); ++anIt) - if (isUsed(*anIt)) - return true; - return false; -} - -bool SketchSolver_Storage::isUsed(AttributePtr theAttribute) const -{ - AttributePtr anAttribute = theAttribute; - AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(anAttribute); - if (aRefAttr) { - if (aRefAttr->isObject()) - return isUsed(ModelAPI_Feature::feature(aRefAttr->object())); - else anAttribute = aRefAttr->attr(); - } - - if (myAttributeMap.find(theAttribute) != myAttributeMap.end()) - return true; - // check in constraints - std::map >::const_iterator - aCIt = myConstraintMap.begin(); - std::list::const_iterator aCWIt; - for (; aCIt != myConstraintMap.end(); ++aCIt) { - for (aCWIt = aCIt->second.begin(); aCWIt != aCIt->second.end(); ++aCWIt) - if (::isUsed(*aCWIt, anAttribute)) - return true; - // Additional check for the Fixed constraints, which have no wrapper associated. - if (aCIt->first->getKind() == SketchPlugin_ConstraintRigid::ID() && - ::isUsed(FeaturePtr(aCIt->first), anAttribute)) - return true; - } - // check in features - std::map::const_iterator aFIt = myFeatureMap.begin(); - for (; aFIt != myFeatureMap.end(); ++aFIt) - if (::isUsed(aFIt->second, anAttribute)) - return true; - return false; -} - - -bool SketchSolver_Storage::removeEntity(FeaturePtr theFeature) -{ - std::map::iterator aFound = myFeatureMap.find(theFeature); - if (aFound == myFeatureMap.end()) - return true; // feature not found, nothing to delete - - EntityWrapperPtr anEntity = aFound->second; - myFeatureMap.erase(aFound); - - // Check if the feature is not used by constraints, remove it - if (!anEntity || (!isUsed(theFeature) && remove(anEntity))) - return true; - - // feature is not removed, revert operation - myFeatureMap[theFeature] = anEntity; - update(anEntity); - return false; -} - -bool SketchSolver_Storage::removeEntity(AttributePtr theAttribute) -{ - std::map::iterator aFound = myAttributeMap.find(theAttribute); - if (aFound == myAttributeMap.end()) - return true; // attribute not found, nothing to delete - - EntityWrapperPtr anEntity = aFound->second; - myAttributeMap.erase(aFound); - - // Check if the attribute is not used by constraints and features, remove it - if (!anEntity || (!isUsed(theAttribute) && remove(anEntity))) - return true; - - // attribute is not removed, revert operation - myAttributeMap[theAttribute] = anEntity; - update(anEntity); - return false; -} - -// Merge groups containing given entities -static void mergeGroups(std::list >& theGroups, - const EntityWrapperPtr& theEntity1, const EntityWrapperPtr& theEntity2) -{ - std::list >::iterator aFound1 = theGroups.end(); - std::list >::iterator aFound2 = theGroups.end(); - std::list >::iterator anIt = theGroups.begin(); - for (; anIt != theGroups.end() && (aFound1 == theGroups.end() || aFound2 == theGroups.end()); - ++anIt) { - if (anIt->find(theEntity1) != anIt->end()) - aFound1 = anIt; - if (anIt->find(theEntity2) != anIt->end()) - aFound2 = anIt; - } - - if (aFound1 == aFound2 || aFound1 == theGroups.end() || aFound2 == theGroups.end()) - return; // nothing to merge - - aFound1->insert(aFound2->begin(), aFound2->end()); - theGroups.erase(aFound2); -} - -bool SketchSolver_Storage::removeCoincidence(ConstraintWrapperPtr theConstraint) -{ - std::list aPoints = theConstraint->entities(); - std::list::const_iterator aPIt; - - CoincidentPointsMap::iterator aPtPtIt = myCoincidentPoints.begin(); - for (; aPtPtIt != myCoincidentPoints.end(); ++aPtPtIt) { - for (aPIt = aPoints.begin(); aPIt != aPoints.end(); ++aPIt) - if (aPtPtIt->first == *aPIt || - aPtPtIt->second.find(*aPIt) != aPtPtIt->second.end()) - break; - if (aPIt != aPoints.end()) - break; - } - - if (aPtPtIt == myCoincidentPoints.end()) - return true; // already removed - - // Removing of coincidence may split this group of coincident point to several groups. - // Find all of them and also the points which become alone. - std::list< std::set > aCoincGroups; - std::set aGroup; - aGroup.insert(aPtPtIt->first); - aCoincGroups.push_back(aGroup); - std::set::const_iterator aTempIt = aPtPtIt->second.begin(); - for (; aTempIt != aPtPtIt->second.end(); ++aTempIt) { - aGroup.clear(); - aGroup.insert(*aTempIt); - aCoincGroups.push_back(aGroup); - } - - std::map >::iterator - aConstrIt = myConstraintMap.begin(); - for (; aConstrIt != myConstraintMap.end(); ++aConstrIt) { - if (aConstrIt->first->getKind() != SketchPlugin_ConstraintCoincidence::ID()) - continue; - - AttributeRefAttrPtr aRefAttr[2] = { - aConstrIt->first->refattr(SketchPlugin_Constraint::ENTITY_A()), - aConstrIt->first->refattr(SketchPlugin_Constraint::ENTITY_B()) - }; - AttributePtr anAttr[2]; - if (aConstrIt->first->data()->isValid()) { - if (!aRefAttr[0] || !aRefAttr[1]) - continue; - - for (int i = 0; i < 2; ++i) { - if (aRefAttr[i]->isObject()) { - FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr[i]->object()); - if (!aFeature || (aFeature->getKind() != SketchPlugin_Point::ID() && - aFeature->getKind() != SketchPlugin_IntersectionPoint::ID())) - continue; - anAttr[i] = aFeature->attribute(SketchPlugin_Point::COORD_ID()); - } else - anAttr[i] = aRefAttr[i]->attr(); - } - } else { - // obtain attributes from the constraint wrapper - // if SketchPlugin_Constraint has invalid data (already removed) - ConstraintWrapperPtr aWrapper = aConstrIt->second.front(); - anAttr[0] = aWrapper->entities().front()->baseAttribute(); - anAttr[1] = aWrapper->entities().back()->baseAttribute(); - } - - EntityWrapperPtr anEntities[2]; - for (int i = 0; i < 2; ++i) { - std::map::iterator - aFound = myAttributeMap.find(anAttr[i]); - if (aFound != myAttributeMap.end()) - anEntities[i] = aFound->second; - } - mergeGroups(aCoincGroups, anEntities[0], anEntities[1]); - } - // Collect alone points and build them new instances - std::list aShutOffList; - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - std::map aNotCoinc; - std::list >::iterator aGroupIt = aCoincGroups.begin(); - while (aGroupIt != aCoincGroups.end()) { - if (aGroupIt->size() == 1) { - EntityWrapperPtr aPoint = *aGroupIt->begin(); - aShutOffList.push_back(aPoint); - aNotCoinc[aPoint] = - aBuilder->createAttribute(aPoint->baseAttribute(), myGroupID, mySketchID); - std::list >::iterator aRemoveIt = aGroupIt++; - aCoincGroups.erase(aRemoveIt); - } else // point is not alone - ++aGroupIt; + return entity(anAttribute); } - if (aNotCoinc.empty() && aCoincGroups.size() == 1) - return false; - - // Find all features and constraints uses non-coincident points - replaceEntities(aNotCoinc); - - // Remove not coincident points and points in separated groups - if (!aCoincGroups.empty()) { - aGroupIt = aCoincGroups.begin(); - for (++aGroupIt; aGroupIt != aCoincGroups.end(); ++aGroupIt) - aShutOffList.insert(aShutOffList.end(), aGroupIt->begin(), aGroupIt->end()); - } - std::list::iterator aNotCIt = aShutOffList.begin(); - for (; aNotCIt != aShutOffList.end(); ++aNotCIt) { - if (aPtPtIt->second.size() <= 1) { - myCoincidentPoints.erase(aPtPtIt); - break; - } - if (aPtPtIt->first == *aNotCIt) { - std::set aSlaves = aPtPtIt->second; - EntityWrapperPtr aNewMaster = *aSlaves.begin(); - aSlaves.erase(aSlaves.begin()); - myCoincidentPoints.erase(aPtPtIt); - myCoincidentPoints[aNewMaster] = aSlaves; - aPtPtIt = myCoincidentPoints.find(aNewMaster); - } else - aPtPtIt->second.erase(*aNotCIt); - } - - // Create additional groups of coincident points - aGroupIt = aCoincGroups.begin(); - if (!aCoincGroups.empty()) - ++aGroupIt; - for (; aGroupIt != aCoincGroups.end(); ++aGroupIt) { - aNotCoinc.clear(); - std::set::iterator anEntIt = aGroupIt->begin(); - for (; anEntIt != aGroupIt->end(); ++anEntIt) { - aNotCoinc[*anEntIt] = - aBuilder->createAttribute((*anEntIt)->baseAttribute(), myGroupID, mySketchID); - } - // replace points by newly created - replaceEntities(aNotCoinc); - // set new group of coincident points - EntityWrapperPtr aMasterEnt = aNotCoinc.begin()->second; - std::map::iterator aNCIt = aNotCoinc.begin(); - for (++aNCIt; aNCIt != aNotCoinc.end(); ++aNCIt) - addCoincidentPoints(aMasterEnt, aNCIt->second); - } - - return true; + static EntityWrapperPtr aDummy; + return aDummy; } -void SketchSolver_Storage::replaceEntities(const std::map& theChange) -{ - std::set anUpdFeatures; - std::map::const_iterator aSubIt; - std::map::iterator aFIt = myFeatureMap.begin(); - for (; aFIt != myFeatureMap.end(); ++aFIt) { - if (!aFIt->second) - continue; // avoid not completed arcs - for (aSubIt = theChange.begin(); aSubIt != theChange.end(); ++aSubIt) { - if (!aSubIt->second || !::isUsed(aFIt->first, aSubIt->first->baseAttribute())) - continue; - std::list aSubs = aFIt->second->subEntities(); - std::list::iterator aSIt = aSubs.begin(); - bool isUpd = false; - for (; aSIt != aSubs.end(); ++aSIt) - if (*aSIt == aSubIt->first) { - (*aSIt)->update(aSubIt->second); - (*aSIt)->setGroup(aFIt->second->group()); - isUpd = true; - } - if (isUpd) { - aFIt->second->setSubEntities(aSubs); - anUpdFeatures.insert(aFIt->second); - } - } - } - // update features - std::set::iterator anUpdIt = anUpdFeatures.begin(); - for (; anUpdIt != anUpdFeatures.end(); ++anUpdIt) - update(EntityWrapperPtr(*anUpdIt)); -} -bool SketchSolver_Storage::remove(ConstraintWrapperPtr theConstraint) +void SketchSolver_Storage::removeFeature(FeaturePtr theFeature) { - bool isFullyRemoved = true; - std::list::const_iterator anIt = theConstraint->entities().begin(); - for (; anIt != theConstraint->entities().end(); ++anIt) { - FeaturePtr aBaseFeature = (*anIt)->baseFeature(); - if (aBaseFeature) - isFullyRemoved = SketchSolver_Storage::removeEntity(aBaseFeature) && isFullyRemoved; - else - isFullyRemoved = - SketchSolver_Storage::removeEntity((*anIt)->baseAttribute()) && isFullyRemoved; - } - return isFullyRemoved; + myFeatureMap.erase(theFeature); } -bool SketchSolver_Storage::remove(EntityWrapperPtr theEntity) +void SketchSolver_Storage::removeAttribute(AttributePtr theAttribute) { - bool isFullyRemoved = true; - std::list::const_iterator anEntIt = theEntity->subEntities().begin(); - for (; anEntIt != theEntity->subEntities().end(); ++anEntIt) { - FeaturePtr aBaseFeature = (*anEntIt)->baseFeature(); - if (aBaseFeature) - isFullyRemoved = SketchSolver_Storage::removeEntity(aBaseFeature) && isFullyRemoved; - else { - AttributePtr aBaseAttr = (*anEntIt)->baseAttribute(); - if (aBaseAttr) - isFullyRemoved = SketchSolver_Storage::removeEntity(aBaseAttr) && isFullyRemoved; - else - remove(*anEntIt); - } - } - - std::list::const_iterator aParIt = theEntity->parameters().begin(); - for (; aParIt != theEntity->parameters().end(); ++aParIt) - isFullyRemoved = remove(*aParIt) && isFullyRemoved; - return isFullyRemoved; + myAttributeMap.erase(theAttribute); } -bool SketchSolver_Storage::isInteract(const FeaturePtr& theFeature) const -{ - if (!theFeature) - return false; - if (myConstraintMap.empty()) - return true; // empty storage interacts with each feature - - ConstraintPtr aConstraint = std::dynamic_pointer_cast(theFeature); - if (aConstraint) { - if (myConstraintMap.find(aConstraint) != myConstraintMap.end()) - return true; - } else if (myFeatureMap.find(theFeature) != myFeatureMap.end()) - return true; - - std::list anAttrList = theFeature->data()->attributes(std::string()); - std::list::const_iterator anIt = anAttrList.begin(); - for (; anIt != anAttrList.end(); ++anIt) - if (isInteract(*anIt)) - return true; - - return false; -} - -bool SketchSolver_Storage::isInteract(const AttributePtr& theAttribute) const -{ - if (!theAttribute) - return false; - - AttributeRefListPtr aRefList = - std::dynamic_pointer_cast(theAttribute); - if (aRefList) { - std::list anObjects = aRefList->list(); - std::list::iterator anObjIt = anObjects.begin(); - for (; anObjIt != anObjects.end(); ++anObjIt) { - FeaturePtr aFeature = ModelAPI_Feature::feature(*anObjIt); - if (isInteract(aFeature)) - return true; - } - return false; - } - - AttributeRefAttrPtr aRefAttr = - std::dynamic_pointer_cast(theAttribute); - if (!aRefAttr) - return myAttributeMap.find(theAttribute) != myAttributeMap.end(); - if (!aRefAttr->isObject()) - return myAttributeMap.find(aRefAttr->attr()) != myAttributeMap.end(); - - FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); - return isInteract(aFeature); -} - bool SketchSolver_Storage::isConsistent() const { // Check the constraints are valid - std::map >::const_iterator + std::map::const_iterator aCIter = myConstraintMap.begin(); for (; aCIter != myConstraintMap.end(); ++aCIter) if (!aCIter->first->data() || !aCIter->first->data()->isValid()) @@ -793,128 +214,8 @@ bool SketchSolver_Storage::isConsistent() const return true; } -bool SketchSolver_Storage::isFixed(EntityWrapperPtr theEntity) const -{ - if (theEntity->group() != myGroupID) - return true; - // no need additional checking for entities differ than point - if (theEntity->type() != ENTITY_POINT) - return false; - - CoincidentPointsMap::const_iterator anIt = myCoincidentPoints.begin(); - for (; anIt != myCoincidentPoints.end(); ++anIt) - if (anIt->first == theEntity || anIt->second.find(theEntity) != anIt->second.end()) { - if (anIt->first->group() != myGroupID) - return true; - std::set::const_iterator anEntIt = anIt->second.begin(); - for (; anEntIt != anIt->second.end(); ++anEntIt) - if ((*anEntIt)->group() != myGroupID) - return true; - } - - std::map >::const_iterator aCIt = - myConstraintMap.begin(); - std::list::const_iterator aCWIt; - for (; aCIt != myConstraintMap.end(); ++aCIt) { - if (aCIt->second.empty()) - continue; - aCWIt = aCIt->second.begin(); - if ((*aCWIt)->type() != CONSTRAINT_FIXED) - continue; - for (; aCWIt != aCIt->second.end(); ++aCIt) - if ((theEntity->baseAttribute() && (*aCWIt)->isUsed(theEntity->baseAttribute())) || - (theEntity->baseFeature() && (*aCWIt)->isUsed(theEntity->baseFeature()))) - return true; - } - - return false; -} - -void SketchSolver_Storage::removeInvalidEntities() -{ - // Remove invalid constraints - std::list anInvalidConstraints; - std::map >::const_iterator - aCIter = myConstraintMap.begin(); - for (; aCIter != myConstraintMap.end(); ++aCIter) - if (!aCIter->first->data() || !aCIter->first->data()->isValid()) - anInvalidConstraints.push_back(aCIter->first); - std::list::const_iterator anInvCIt = anInvalidConstraints.begin(); - for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt) - removeConstraint(*anInvCIt); - // Remove invalid features - std::list anInvalidFeatures; - std::map::const_iterator aFIter = myFeatureMap.begin(); - for (; aFIter != myFeatureMap.end(); aFIter++) - if (!aFIter->first->data() || !aFIter->first->data()->isValid()) - anInvalidFeatures.push_back(aFIter->first); - std::list::const_iterator anInvFIt = anInvalidFeatures.begin(); - for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt) - removeEntity(*anInvFIt); -} - -EntityWrapperPtr SketchSolver_Storage::getNormal() const -{ - EntityWrapperPtr aSketch = sketch(); - if (!aSketch) - return aSketch; - - // Find normal entity - const std::list& aSketchSubs = aSketch->subEntities(); - std::list::const_iterator aSIt = aSketchSubs.begin(); - for (; aSIt != aSketchSubs.end(); ++aSIt) - if ((*aSIt)->type() == ENTITY_NORMAL) - return *aSIt; - return EntityWrapperPtr(); -} - -const EntityWrapperPtr& SketchSolver_Storage::sketch() const -{ - static EntityWrapperPtr aDummySketch; - - std::map::const_iterator aFIt = myFeatureMap.begin(); - for (; aFIt != myFeatureMap.end(); ++aFIt) - if (aFIt->second && aFIt->second->type() == ENTITY_SKETCH) - break; - if (aFIt == myFeatureMap.end()) - return aDummySketch; - return aFIt->second; -} - -void SketchSolver_Storage::setSketch(const EntityWrapperPtr& theSketch) -{ - if (sketch()) - return; - addEntity(FeaturePtr(), theSketch); -} - -void SketchSolver_Storage::processArcs() -{ - myExistArc = false; - std::map::iterator aFIt = myFeatureMap.begin(); - for (; aFIt != myFeatureMap.end(); ++aFIt) - if (!aFIt->second && aFIt->first->getKind() == SketchPlugin_Arc::ID()) { - // Additional checking the attributes are initialized - if (aFIt->first->attribute(SketchPlugin_Arc::CENTER_ID())->isInitialized() && - aFIt->first->attribute(SketchPlugin_Arc::START_ID())->isInitialized() && - aFIt->first->attribute(SketchPlugin_Arc::END_ID())->isInitialized()) - update(aFIt->first); - else - myExistArc = true; - } -} - void SketchSolver_Storage::blockEvents(bool isBlocked) { - if (isBlocked == myEventsBlocked) - return; - - std::map >::const_iterator - aCIter = myConstraintMap.begin(); - for (; aCIter != myConstraintMap.end(); aCIter++) - if (aCIter->first->data() && aCIter->first->data()->isValid()) - aCIter->first->data()->blockSendAttributeUpdated(isBlocked); - std::map::const_iterator aFIter = myFeatureMap.begin(); for (; aFIter != myFeatureMap.end(); aFIter++) if (aFIter->first->data() && aFIter->first->data()->isValid()) @@ -925,61 +226,47 @@ void SketchSolver_Storage::blockEvents(bool isBlocked) if (anAtIter->first->owner() && anAtIter->first->owner()->data() && anAtIter->first->owner()->data()->isValid()) anAtIter->first->owner()->data()->blockSendAttributeUpdated(isBlocked); + myEventsBlocked = isBlocked; } std::set SketchSolver_Storage::getConflictingConstraints(SolverPtr theSolver) const { std::set aConflicting; - std::map >::const_iterator + std::map::const_iterator aConstrIt = myConstraintMap.begin(); for (; aConstrIt != myConstraintMap.end(); ++aConstrIt) { - std::list::const_iterator anIt = aConstrIt->second.begin(); - for (; anIt != aConstrIt->second.end(); ++anIt) - if (theSolver->isConflicting((*anIt)->id())) { - aConflicting.insert(aConstrIt->first); - break; - } + if (theSolver->isConflicting(aConstrIt->second->id())) { + aConflicting.insert(aConstrIt->first); + break; + } } return aConflicting; } +void SketchSolver_Storage::subscribeUpdates( + SketchSolver_Constraint* theSubscriber, const std::string& theGroup) const +{ + myUpdaters->attach(theSubscriber, theGroup); +} +void SketchSolver_Storage::unsubscribeUpdates(SketchSolver_Constraint* theSubscriber) const +{ + myUpdaters->detach(theSubscriber); +} - - -// ============== Auxiliary functions ==================================== -bool isEqual(const std::list& theCVec1, - const std::list& theCVec2) +void SketchSolver_Storage::notify(const FeaturePtr & theFeature) const { - if (theCVec1.size() != theCVec2.size()) - return false; - - std::list aChecked(theCVec2.size(), false); - std::list::const_iterator anIt1 = theCVec1.begin(); - for (; anIt1 != theCVec1.end(); ++anIt1) { - std::list::const_iterator anIt2 = theCVec2.begin(); - std::list::iterator aCheckIt = aChecked.begin(); - while (aCheckIt != aChecked.end() && *aCheckIt) { - ++aCheckIt; - ++anIt2; - } - for (; anIt2 != theCVec2.end(); ++anIt2, ++aCheckIt) - if (!(*aCheckIt) && (*anIt1)->isEqual(*anIt2)) { - *aCheckIt = true; - break; - } - // the same constraint is not found - if (anIt2 == theCVec2.end()) - return false; - } - return true; + myUpdaters->update(theFeature); } -void resultToFeatureOrAttribute(const ObjectPtr& theResult, +void SketchSolver_Storage::resultToFeatureOrAttribute(const ObjectPtr& theResult, FeaturePtr& theFeature, AttributePtr& theAttribute) { FeaturePtr aFeature = ModelAPI_Feature::feature(theResult); + if (!aFeature) + return; + // if the feature has several results, we choose which one is referred const std::list& aResults = aFeature->results(); if (aResults.size() > 1 && theResult != aFeature->lastResult()) { diff --git a/src/SketchSolver/SketchSolver_Storage.h b/src/SketchSolver/SketchSolver_Storage.h index c4dd63ddb..8c227cba5 100644 --- a/src/SketchSolver/SketchSolver_Storage.h +++ b/src/SketchSolver/SketchSolver_Storage.h @@ -10,9 +10,10 @@ #include #include #include -#include #include +#include + #include #include #include @@ -30,93 +31,68 @@ typedef std::map > CoincidentPoints class SketchSolver_Storage { private: - SketchSolver_Storage(); SketchSolver_Storage(const SketchSolver_Storage&); SketchSolver_Storage& operator=(const SketchSolver_Storage&); public: - SketchSolver_Storage(const GroupID& theGroup) - : myGroupID(theGroup), - mySketchID(EID_UNKNOWN), - myNeedToResolve(false), - myEventsBlocked(false), - myExistArc(false) - {} + SketchSolver_Storage(SolverPtr theSolver); /// \brief Change mapping between constraint from SketchPlugin and /// a constraint applicable for corresponding solver. /// \param theConstraint [in] original SketchPlugin constraint - /// \param theSolverConstraint [in] solver's constraints - SKETCHSOLVER_EXPORT void addConstraint(ConstraintPtr theConstraint, - ConstraintWrapperPtr theSolverConstraints); - /// \brief Change mapping between constraint from SketchPlugin and - /// the list of constraints applicable for corresponding solver. - /// \param theConstraint [in] original SketchPlugin constraint - /// \param theSolverConstraints [in] list of solver's constraints - SKETCHSOLVER_EXPORT virtual - void addConstraint(ConstraintPtr theConstraint, - std::list theSolverConstraints); + /// \param theSolverConstraint [in] solver's constraint + virtual void addConstraint(ConstraintPtr theConstraint, + ConstraintWrapperPtr theSolverConstraint); + + /// \brief Add list of temporary constraints which will be destroyed + /// after the next solving of the set of constraints. + /// \param theSolverConstraint [in] solver's constraint + virtual void addTemporaryConstraint(const ConstraintWrapperPtr& theSolverConstraint) = 0; + + /// \brief Change mapping feature from SketchPlugin and + /// the entity applicable for corresponding solver. + /// \param theFeature [in] original SketchPlugin feature + /// \param theSolverEntity [in] solver's entity, created outside + void addEntity(FeaturePtr theFeature, + EntityWrapperPtr theSolverEntity); + + /// \brief Change mapping attribute of a feature and the entity + /// applicable for corresponding solver. + /// \param theAttribute [in] original attribute + /// \param theSolverEntity [in] solver's entity, created outside + void addEntity(AttributePtr theAttribute, + EntityWrapperPtr theSolverEntity); /// \brief Convert feature to the form applicable for specific solver and map it /// \param theFeature [in] feature to convert - /// \param theGroup [in] id of the group where the feature should be placed /// \param theForce [in] forced feature creation /// \return \c true if the feature has been created or updated - SKETCHSOLVER_EXPORT bool update(FeaturePtr theFeature, - const GroupID& theGroup = GID_UNKNOWN, bool theForce = false); + virtual bool update(FeaturePtr theFeature, bool theForce = false) = 0; /// \brief Convert attribute to the form applicable for specific solver and map it /// \param theAttribute [in] attribute to convert - /// \param theGroup [in] id of the group where the feature should be placed /// \param theForce [in] forced feature creation /// \return \c true if the attribute has been created or updated - SKETCHSOLVER_EXPORT bool update(AttributePtr theAttribute, - const GroupID& theGroup = GID_UNKNOWN, bool theForce = false); + virtual bool update(AttributePtr theAttribute, bool theForce = false) = 0; /// \brief Returns constraint related to corresponding constraint - SKETCHSOLVER_EXPORT - const std::list& constraint(const ConstraintPtr& theConstraint) const; + const ConstraintWrapperPtr& constraint(const ConstraintPtr& theConstraint) const; /// \brief Returns entity related to corresponding feature - SKETCHSOLVER_EXPORT const EntityWrapperPtr& entity(const FeaturePtr& theFeature) const; + const EntityWrapperPtr& entity(const FeaturePtr& theFeature) const; /// \brief Returns entity related to corresponding attribute - SKETCHSOLVER_EXPORT const EntityWrapperPtr& entity(const AttributePtr& theAttribute) const; - - /// \brief Return parsed sketch entity - const EntityWrapperPtr& sketch() const; - /// \brief Set parsed sketch entity. - /// Be careful, this method does not update fields of the storage specific for the solver. - /// Does not update if the sketch already exists. - void setSketch(const EntityWrapperPtr& theSketch); - - /// \brief Mark two points as coincident - virtual void addCoincidentPoints(EntityWrapperPtr theMaster, EntityWrapperPtr theSlave) = 0; - - /// \brief Shows the storage has any constraint twice - virtual bool hasDuplicatedConstraint() const = 0; + const EntityWrapperPtr& entity(const AttributePtr& theAttribute) const; /// \brief Removes constraint from the storage /// \return \c true if the constraint and all its parameters are removed successfully - SKETCHSOLVER_EXPORT bool removeConstraint(ConstraintPtr theConstraint); + virtual bool removeConstraint(ConstraintPtr theConstraint) = 0; /// \brief Removes feature from the storage - /// \return \c true if the feature and its attributes are removed successfully; - /// \c false if the feature or any it attribute is used by remaining constraints. - SKETCHSOLVER_EXPORT bool removeEntity(FeaturePtr theFeature); + void removeFeature(FeaturePtr theFeature); /// \brief Removes attribute from the storage - /// \return \c true if the attribute is not used by remaining features and constraints - SKETCHSOLVER_EXPORT bool removeEntity(AttributePtr theAttribute); + void removeAttribute(AttributePtr theAttribute); /// \brief Remove all features became invalid - SKETCHSOLVER_EXPORT void removeInvalidEntities(); - - /// \brief Check whether the feature or its attributes are used by this storage - /// \param theFeature [in] feature to be checked - /// \return \c true if the feature interacts with the storage - bool isInteract(const FeaturePtr& theFeature) const; - /// \brief Check whether the attribute is used by this storage - /// \param theAttribute [in] attribute to be checked - /// \return \c true if the attribute interacts with the storage - bool isInteract(const AttributePtr& theAttribute) const; + virtual void removeInvalidEntities() = 0; /// \brief Check the features is not removed bool isConsistent() const; @@ -125,10 +101,6 @@ public: bool isEmpty() const { return myConstraintMap.empty(); } - /// \brief Check the entity is fixed. - /// If the point is under verification, all coincident points are checked too. - SKETCHSOLVER_EXPORT bool isFixed(EntityWrapperPtr theEntity) const; - /// \brief Shows the sketch should be resolved virtual bool isNeedToResolve() { return myNeedToResolve; } @@ -137,109 +109,46 @@ public: { myNeedToResolve = theFlag; } /// \brief Initialize solver by constraints, entities and parameters - virtual void initializeSolver(SolverPtr theSolver) = 0; + virtual void initializeSolver() = 0; /// \brief Return list of conflicting constraints std::set getConflictingConstraints(SolverPtr theSolver) const; /// \brief Update SketchPlugin features after resolving constraints - /// \param theFixedOnly [in] if \c true the fixed points will be updated only - virtual void refresh(bool theFixedOnly = false) const = 0; - - /// \brief Check if some parameters or entities are returned - /// to the current group after removing temporary constraints - virtual void verifyFixed() = 0; - - /// \brief Calculate point on theBase entity. Value theCoeff is in [0.0 .. 1.0] and - /// shows the distance from the start point. - virtual EntityWrapperPtr calculateMiddlePoint(EntityWrapperPtr theBase, - double theCoeff) = 0; + virtual void refresh() const = 0; /// \brief Block or unblock events when refreshing features - SKETCHSOLVER_EXPORT void blockEvents(bool isBlocked); - /// \brief Shows the events are blocked for the features in the storage - bool isEventsBlocked() const - { return myEventsBlocked; } + void blockEvents(bool isBlocked); -protected: - /// \brief Change mapping feature from SketchPlugin and - /// the entity applicable for corresponding solver. - /// \param theFeature [in] original SketchPlugin feature - /// \param theSolverEntity [in] solver's entity, created outside - SKETCHSOLVER_EXPORT - void addEntity(FeaturePtr theFeature, - EntityWrapperPtr theSolverEntity); + /// \brief Subscribe for updates of features + /// \param theSubscriber [in] object which wants to revceive notifications + /// \param theGroup [in] group of updates features to be send + void subscribeUpdates(SketchSolver_Constraint* theSubscriber, const std::string& theGroup) const; + /// \brief Unsubscribe for updates of features + /// \param theSubscriber [in] object which does not want to revceive notifications anymore + void unsubscribeUpdates(SketchSolver_Constraint* theSubscriber) const; - /// \brief Change mapping attribute of a feature and the entity - /// applicable for corresponding solver. - /// \param theAttribute [in] original attribute - /// \param theSolverEntity [in] solver's entity, created outside - SKETCHSOLVER_EXPORT - void addEntity(AttributePtr theAttribute, - EntityWrapperPtr theSolverEntity); - - /// \brief Update constraint's data - /// \return \c true if any value is updated - virtual bool update(ConstraintWrapperPtr theConstraint) = 0; - /// \brief Update entity's data - /// \return \c true if any value is updated - virtual bool update(EntityWrapperPtr theEntity) = 0; - /// \brief Update parameter's data - /// \return \c true if the value of parameter is updated - virtual bool update(ParameterWrapperPtr theParameter) = 0; - - /// \brief Remove constraint - /// \return \c true if the constraint and all its parameters are removed successfully - SKETCHSOLVER_EXPORT virtual bool remove(ConstraintWrapperPtr theConstraint); - /// \brief Remove entity - /// \return \c true if the entity and all its parameters are removed successfully - SKETCHSOLVER_EXPORT virtual bool remove(EntityWrapperPtr theEntity); - /// \brief Remove parameter - /// \return \c true if the parameter has been removed - virtual bool remove(ParameterWrapperPtr theParameter) = 0; - - /// \brief Remove point-point coincidence - SKETCHSOLVER_EXPORT bool removeCoincidence(ConstraintWrapperPtr theConstraint); - - /// \brief Update the group for the given entity, its sub-entities and parameters - virtual void changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup) = 0; - /// \brief Update the group for the given parameter - virtual void changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup) = 0; - - /// \brief Verify the feature or any its attribute is used by constraint - SKETCHSOLVER_EXPORT bool isUsed(FeaturePtr theFeature) const; - /// \brief Verify the attribute is used by constraint - SKETCHSOLVER_EXPORT bool isUsed(AttributePtr theAttirubute) const; - - /// \brief Find arcs without corresponding entity applicable for the solver and build them - SKETCHSOLVER_EXPORT void processArcs(); + /// \brief Notify all subscribers about update of the feature + void notify(const FeaturePtr& theFeature) const; - /// \brief Replace entities by others - void replaceEntities(const std::map& theChange); - -private: - /// \brief Find the normal of the sketch - EntityWrapperPtr getNormal() const; +protected: + /// \brief Convert result to feature or attribute if theResult is linked to center of circle/arc + static void resultToFeatureOrAttribute(const ObjectPtr& theResult, + FeaturePtr& theFeature, + AttributePtr& theAttribute); protected: - EntityID mySketchID; ///< identifier of the sketch - GroupID myGroupID; ///< identifier of the group, this storage belongs to + SolverPtr mySketchSolver; ///< Sketch solver, prepared in corresponding group bool myNeedToResolve; ///< parameters are changed and group needs to be resolved bool myEventsBlocked; ///< indicates that features do not send events - bool myExistArc; ///< the storage has any point of arc but not full arc, need to add it /// map SketchPlugin constraint to a list of solver's constraints - std::map > myConstraintMap; + std::map myConstraintMap; /// map SketchPlugin feature to solver's entity - std::map myFeatureMap; + std::map myFeatureMap; /// map attribute to solver's entity - std::map myAttributeMap; - - /// lists of coincident points (first is a master point, second is a set of slaves) - CoincidentPointsMap myCoincidentPoints; + std::map myAttributeMap; - // to be able to update entities from constraints - friend class SketchSolver_ConstraintDistance; - friend class SketchSolver_ConstraintFixedArcRadius; + UpdaterPtr myUpdaters; }; typedef std::shared_ptr StoragePtr;