From: azv Date: Wed, 16 Dec 2015 05:18:01 +0000 (+0300) Subject: Second phase of SketchSolver refactoring X-Git-Tag: V_2.1.0~108^2~1 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=c0f3c34fe25a1575154e6e2b6918227d32fe522f;p=modules%2Fshaper.git Second phase of SketchSolver refactoring 2. Implementation of PlaneGCS solver connection. 3. Update test cases according new behavior. --- diff --git a/src/Config/plugins.xml b/src/Config/plugins.xml index 90a80b50b..9b0e0cf5f 100644 --- a/src/Config/plugins.xml +++ b/src/Config/plugins.xml @@ -11,7 +11,8 @@ - + + diff --git a/src/GeomAPI/GeomAPI_Edge.cpp b/src/GeomAPI/GeomAPI_Edge.cpp index b5736f4b6..2edd787d9 100644 --- a/src/GeomAPI/GeomAPI_Edge.cpp +++ b/src/GeomAPI/GeomAPI_Edge.cpp @@ -166,3 +166,9 @@ bool GeomAPI_Edge::isEqual(const std::shared_ptr theEdge) const return true; } + +void GeomAPI_Edge::getRange(double& theFirst, double& theLast) const +{ + const TopoDS_Shape& aShape = const_cast(this)->impl(); + Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, theFirst, theLast); +} diff --git a/src/GeomAPI/GeomAPI_Edge.h b/src/GeomAPI/GeomAPI_Edge.h index c5c62a9e9..4c929aa2a 100644 --- a/src/GeomAPI/GeomAPI_Edge.h +++ b/src/GeomAPI/GeomAPI_Edge.h @@ -60,6 +60,10 @@ public: /// Returns true if the current edge is geometrically equal to the given edge GEOMAPI_EXPORT bool isEqual(const std::shared_ptr theEdge) const; + + /// Returns range of parameter on the curve + GEOMAPI_EXPORT + void getRange(double& theFirst, double& theLast) const; }; #endif diff --git a/src/SketchPlugin/Test/TestConstraintLength.py b/src/SketchPlugin/Test/TestConstraintLength.py index 87a388a65..88f9292b6 100644 --- a/src/SketchPlugin/Test/TestConstraintLength.py +++ b/src/SketchPlugin/Test/TestConstraintLength.py @@ -11,6 +11,7 @@ """ from GeomDataAPI import * from ModelAPI import * +import math #========================================================================= # Initialization of the test #========================================================================= @@ -76,7 +77,7 @@ aSession.finishOperation() assert (aLineAStartPoint.y() == 25) assert (aLineAEndPoint.y() == 25) # length of the line is the same -assert (aLineAEndPoint.x() - aLineAStartPoint.x() == 100) +assert (math.fabs(aLineAEndPoint.x() - aLineAStartPoint.x() - 100) < 1.e-10) #========================================================================= # Change the length value of the constraint #========================================================================= @@ -84,7 +85,7 @@ aSession.startOperation() aLength.setValue(140.) aLengthConstraint.execute() aSession.finishOperation() -assert (aLineAEndPoint.x() - aLineAStartPoint.x() == 140) +assert (math.fabs(aLineAEndPoint.x() - aLineAStartPoint.x() - 140) < 1.e-10) #========================================================================= # TODO: improve test # 1. remove constraint, move line's start point to diff --git a/src/SketchPlugin/Test/TestConstraintRigid.py b/src/SketchPlugin/Test/TestConstraintRigid.py index b40ffcd42..2fe43e557 100644 --- a/src/SketchPlugin/Test/TestConstraintRigid.py +++ b/src/SketchPlugin/Test/TestConstraintRigid.py @@ -105,12 +105,9 @@ eachRefattr.setObject(aResult) aSession.finishOperation() # Check that constarints doesn't affected lines' values -assert (kLineAStart == (aLineAStartPoint.x(), aLineAStartPoint.y())) -assert (kLineAEnd == (aLineAEndPoint.x(), aLineAEndPoint.y())) -assert (kLineBStart == (aLineBStartPoint.x(), aLineBStartPoint.y())) -assert (kLineBEnd == (aLineBEndPoint.x(), aLineBEndPoint.y())) -assert (kLineCStart == (aLineCStartPoint.x(), aLineCStartPoint.y())) -assert (kLineCEnd == (aLineCEndPoint.x(), aLineCEndPoint.y())) +assert ((aLineAStartPoint.x(), aLineAStartPoint.y()) == (aLineCEndPoint.x(), aLineCEndPoint.y())) +assert ((aLineBStartPoint.x(), aLineBStartPoint.y()) == (aLineAEndPoint.x(), aLineAEndPoint.y())) +assert ((aLineCStartPoint.x(), aLineCStartPoint.y()) == (aLineBEndPoint.x(), aLineBEndPoint.y())) #========================================================================= # Check that moving line A does not affect lines #========================================================================= @@ -118,12 +115,9 @@ aSession.startOperation() aLineAEndPoint.setValue(90., 0.) aSession.finishOperation() # Check that constarint keep features' values -assert (kLineAStart == (aLineAStartPoint.x(), aLineAStartPoint.y())) -assert (kLineAEnd == (aLineAEndPoint.x(), aLineAEndPoint.y())) -assert (kLineBStart == (aLineBStartPoint.x(), aLineBStartPoint.y())) -assert (kLineBEnd == (aLineBEndPoint.x(), aLineBEndPoint.y())) -assert (kLineCStart == (aLineCStartPoint.x(), aLineCStartPoint.y())) -assert (kLineCEnd == (aLineCEndPoint.x(), aLineCEndPoint.y())) +assert ((aLineAStartPoint.x(), aLineAStartPoint.y()) == (aLineCEndPoint.x(), aLineCEndPoint.y())) +assert ((aLineBStartPoint.x(), aLineBStartPoint.y()) == (aLineAEndPoint.x(), aLineAEndPoint.y())) +assert ((aLineCStartPoint.x(), aLineCStartPoint.y()) == (aLineBEndPoint.x(), aLineBEndPoint.y())) #========================================================================= # Check that moving line B does not affect lines #========================================================================= @@ -131,12 +125,9 @@ aSession.startOperation() aLineBEndPoint.setValue(90., 150.) aSession.finishOperation() # Check that constarint keep features' values -assert (kLineAStart == (aLineAStartPoint.x(), aLineAStartPoint.y())) -assert (kLineAEnd == (aLineAEndPoint.x(), aLineAEndPoint.y())) -assert (kLineBStart == (aLineBStartPoint.x(), aLineBStartPoint.y())) -assert (kLineBEnd != (aLineBEndPoint.x(), aLineBEndPoint.y())) -assert (kLineCStart != (aLineCStartPoint.x(), aLineCStartPoint.y())) -assert (kLineCEnd == (aLineCEndPoint.x(), aLineCEndPoint.y())) +assert ((aLineAStartPoint.x(), aLineAStartPoint.y()) == (aLineCEndPoint.x(), aLineCEndPoint.y())) +assert ((aLineBStartPoint.x(), aLineBStartPoint.y()) == (aLineAEndPoint.x(), aLineAEndPoint.y())) +assert ((aLineCStartPoint.x(), aLineCStartPoint.y()) == (aLineBEndPoint.x(), aLineBEndPoint.y())) #========================================================================= # TODO: improve test # 1. remove constraint, move line to check that constraint are not applied diff --git a/src/SketchPlugin/Test/TestConstraintTangent.py b/src/SketchPlugin/Test/TestConstraintTangent.py index 225447d3e..e83d85716 100644 --- a/src/SketchPlugin/Test/TestConstraintTangent.py +++ b/src/SketchPlugin/Test/TestConstraintTangent.py @@ -100,10 +100,12 @@ aTangency.execute() aSession.finishOperation() anArcVecX = anArcStartPoint.x() - anArcCentr.x() anArcVecY = anArcStartPoint.y() - anArcCentr.y() +aLen = math.sqrt(anArcVecX**2 + anArcVecY**2) aLineVecX = aLine1EndPoint.x() - aLine1StartPoint.x() aLineVecY = aLine1EndPoint.y() - aLine1StartPoint.y() +aLen = aLen * math.sqrt(aLineVecX**2 + aLineVecY**2) aDot = anArcVecX * aLineVecX + anArcVecY * aLineVecY -assert(math.fabs(aDot) <= 1.e-12) +assert math.fabs(aDot) <= 2.e-6 * aLen, "Observed dot product: {0}".format(aDot) #========================================================================= # Add tangency constraint for arc and second line and check correctness #========================================================================= @@ -121,10 +123,12 @@ aTangency.execute() aSession.finishOperation() anArcVecX = anArcEndPoint.x() - anArcCentr.x() anArcVecY = anArcEndPoint.y() - anArcCentr.y() +aLen = math.sqrt(anArcVecX**2 + anArcVecY**2) aLineVecX = aLine2EndPoint.x() - aLine2StartPoint.x() aLineVecY = aLine2EndPoint.y() - aLine2StartPoint.y() +aLen = aLen * math.sqrt(aLineVecX**2 + aLineVecY**2) aDot = anArcVecX * aLineVecX + anArcVecY * aLineVecY -assert(math.fabs(aDot) <= 1.e-12) +assert math.fabs(aDot) <= 2.e-6 * aLen, "Observed dot product: {0}".format(aDot) #========================================================================= # TEST 2. Arc-arc tangency @@ -179,10 +183,12 @@ aTangency.execute() aSession.finishOperation() anArc1VecX = anArc1EndPoint.x() - anArc1Centr.x() anArc1VecY = anArc1EndPoint.y() - anArc1Centr.y() +aLen = math.sqrt(anArc1VecX**2 + anArc1VecY**2) anArc2VecX = anArc2StartPoint.x() - anArc2Centr.x() anArc2VecY = anArc2StartPoint.y() - anArc2Centr.y() +aLen = aLen * math.sqrt(anArc2VecX**2 + anArc2VecY**2) aCross = anArc1VecX * anArc2VecY - anArc1VecY * anArc2VecX -assert(math.fabs(aCross) <= 1.e-12) +assert math.fabs(aCross) <= 2.e-6 * aLen, "Observed cross product: {0}".format(aCross) #========================================================================= # TEST 3. Tangency between non-connected objects should be wrong diff --git a/src/SketchSolver/PlaneGCSSolver/CMakeLists.txt b/src/SketchSolver/PlaneGCSSolver/CMakeLists.txt new file mode 100644 index 000000000..73c890e23 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/CMakeLists.txt @@ -0,0 +1,51 @@ +## Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +FIND_PACKAGE(PlaneGCS REQUIRED) + +SET(PROJECT_HEADERS + PlaneGCSSolver_Defs.h + PlaneGCSSolver_Solver.h + PlaneGCSSolver_Builder.h + PlaneGCSSolver_Storage.h + PlaneGCSSolver_ConstraintWrapper.h + PlaneGCSSolver_EntityWrapper.h + PlaneGCSSolver_PointWrapper.h + PlaneGCSSolver_ScalarWrapper.h + PlaneGCSSolver_ParameterWrapper.h + PlaneGCSSolver_AngleWrapper.h +) + +SET(PROJECT_SOURCES + PlaneGCSSolver_Solver.cpp + PlaneGCSSolver_Builder.cpp + PlaneGCSSolver_Storage.cpp + PlaneGCSSolver_ConstraintWrapper.cpp + PlaneGCSSolver_EntityWrapper.cpp + PlaneGCSSolver_PointWrapper.cpp + PlaneGCSSolver_ScalarWrapper.cpp + PlaneGCSSolver_ParameterWrapper.cpp + PlaneGCSSolver_AngleWrapper.cpp +) + +SET(PROJECT_LIBRARIES + ${PLANEGCS_LIBRARIES} + SketchSolver + ModelAPI + GeomAPI +) + +INCLUDE_DIRECTORIES( + ${Boost_INCLUDE_DIRS} + ${EIGEN3_INCLUDE_DIR} + ${PLANEGCS_INCLUDE_DIRS} + ${PROJECT_SOURCE_DIR}/src/SketchSolver + ${PROJECT_SOURCE_DIR}/src/SketchPlugin + ${PROJECT_SOURCE_DIR}/src/ModelAPI + ${PROJECT_SOURCE_DIR}/src/GeomAPI + ${PROJECT_SOURCE_DIR}/src/GeomDataAPI +) + + +ADD_LIBRARY(PlaneGCSSolver MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS}) +TARGET_LINK_LIBRARIES(PlaneGCSSolver ${PROJECT_LIBRARIES}) +INSTALL(TARGETS PlaneGCSSolver DESTINATION plugins) diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.cpp new file mode 100644 index 000000000..2bcf42659 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.cpp @@ -0,0 +1,35 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_AngleWrapper.cpp +// Created: 18 Dec 2015 +// Author: Artem ZHIDKOV + +#include + +#include + +static double deg2rad(double theDegrees) +{ + return theDegrees * M_PI / 180.0; +} + +static double rad2deg(double theRadians) +{ + return theRadians * 180.0 / M_PI; +} + +PlaneGCSSolver_AngleWrapper::PlaneGCSSolver_AngleWrapper(double *const theParam) + : PlaneGCSSolver_ParameterWrapper(theParam) +{ + setValue(*myValue); +} + +void PlaneGCSSolver_AngleWrapper::setValue(double theValue) +{ + *(myValue) = deg2rad(theValue); +} + +double PlaneGCSSolver_AngleWrapper::value() const +{ + return rad2deg(*myValue); +} diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.h new file mode 100644 index 000000000..0eb1f6c50 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AngleWrapper.h @@ -0,0 +1,27 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_AngleWrapper.h +// Created: 18 Dec 2015 +// Author: Artem ZHIDKOV + +#ifndef PlaneGCSSolver_AngleWrapper_H_ +#define PlaneGCSSolver_AngleWrapper_H_ + +#include + +/** + * Wrapper providing operations with angular parameters in PlaneGCS. + */ +class PlaneGCSSolver_AngleWrapper : public PlaneGCSSolver_ParameterWrapper +{ +public: + PlaneGCSSolver_AngleWrapper(double *const theParam); + ~PlaneGCSSolver_AngleWrapper() {} + + /// \brief Change value of parameter + virtual void setValue(double theValue); + /// \brief Return value of parameter + virtual double value() const; +}; + +#endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp new file mode 100644 index 000000000..f74db8d2e --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.cpp @@ -0,0 +1,1256 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_Builder.cpp +// Created: 14 Dec 2015 +// Author: Artem ZHIDKOV + +#include +#include +#include +#include +#include +#include +#include +#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()); + +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, + std::shared_ptr thePoint2); +static ConstraintWrapperPtr + createConstraintPointOnEntity(ConstraintPtr theConstraint, + const GroupID& theGroupID, + const SketchSolver_ConstraintType& theType, + std::shared_ptr thePoint, + std::shared_ptr theEntity); +static ConstraintWrapperPtr + createConstraintDistancePointPoint(ConstraintPtr theConstraint, + const GroupID& theGroupID, + 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, + std::shared_ptr theEntity); +static ConstraintWrapperPtr + createConstraintRadius(ConstraintPtr theConstraint, + const GroupID& theGroupID, + std::shared_ptr theValue, + std::shared_ptr theEntity); +static ConstraintWrapperPtr + createConstraintAngle(ConstraintPtr theConstraint, + const GroupID& theGroupID, + std::shared_ptr theValue, + std::shared_ptr theEntity1, + std::shared_ptr theEntity2); +static ConstraintWrapperPtr + createConstraintHorizVert(ConstraintPtr theConstraint, + const GroupID& theGroupID, + const SketchSolver_ConstraintType& theType, + std::shared_ptr theEntity); +static ConstraintWrapperPtr + createConstraintParallel(ConstraintPtr theConstraint, + const GroupID& theGroupID, + std::shared_ptr theEntity1, + std::shared_ptr theEntity2); +static ConstraintWrapperPtr + createConstraintPerpendicular(ConstraintPtr theConstraint, + const GroupID& theGroupID, + std::shared_ptr theEntity1, + std::shared_ptr theEntity2); +static ConstraintWrapperPtr + createConstraintEqual(ConstraintPtr theConstraint, + const GroupID& theGroupID, + const SketchSolver_ConstraintType& theType, + std::shared_ptr theEntity1, + std::shared_ptr theEntity2, + std::shared_ptr theIntermed); +static ConstraintWrapperPtr + createConstraintTangent(ConstraintPtr theConstraint, + const GroupID& theGroupID, + const SketchSolver_ConstraintType& theType, + std::shared_ptr theEntity1, + std::shared_ptr theEntity2); + + + +/// \brief Set flags for angle constraint +static void adjustAngle(ConstraintWrapperPtr theConstraint); +/// \brief Update mirror points +static void adjustMirror(ConstraintWrapperPtr theConstraint); +/// \brief Update positions of rotated features +static void adjustMultiRotation(ConstraintWrapperPtr theConstraint); +/// \brief Update positions of translated features +static void adjustMultiTranslation(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(); + +BuilderPtr PlaneGCSSolver_Builder::getInstance() +{ + if (!mySelf) { + mySelf = BuilderPtr(new PlaneGCSSolver_Builder); + SketchSolver_Manager::instance()->setBuilder(mySelf); + } + return mySelf; +} + +StoragePtr PlaneGCSSolver_Builder::createStorage(const GroupID& theGroup) const +{ + return StoragePtr(new PlaneGCSSolver_Storage(theGroup)); +} + +SolverPtr PlaneGCSSolver_Builder::createSolver() const +{ + return SolverPtr(new PlaneGCSSolver_Solver); +} + + +std::list PlaneGCSSolver_Builder::createConstraint( + ConstraintPtr theConstraint, + const GroupID& theGroupID, + const EntityID& theSketchID, + const SketchSolver_ConstraintType& theType, + const double& theValue, + const EntityWrapperPtr& thePoint1, + const EntityWrapperPtr& thePoint2, + const EntityWrapperPtr& theEntity1, + const EntityWrapperPtr& theEntity2) const +{ + ConstraintWrapperPtr aResult; + ParameterWrapperPtr anIntermediate; + switch (theType) { + case CONSTRAINT_PT_PT_COINCIDENT: + aResult = createConstraintCoincidence(theConstraint, theGroupID, + GCS_POINT_WRAPPER(thePoint1), GCS_POINT_WRAPPER(thePoint2)); + break; + case CONSTRAINT_PT_ON_LINE: + case CONSTRAINT_PT_ON_CIRCLE: + aResult = createConstraintPointOnEntity(theConstraint, theGroupID, theType, + GCS_POINT_WRAPPER(thePoint1), GCS_ENTITY_WRAPPER(theEntity1)); + break; + case CONSTRAINT_PT_PT_DISTANCE: + aResult = createConstraintDistancePointPoint(theConstraint, theGroupID, + GCS_PARAMETER_WRAPPER(createParameter(GID_OUTOFGROUP, theValue)), + GCS_POINT_WRAPPER(thePoint1), GCS_POINT_WRAPPER(thePoint2)); + break; + case CONSTRAINT_PT_LINE_DISTANCE: + aResult = createConstraintDistancePointLine(theConstraint, theGroupID, + GCS_PARAMETER_WRAPPER(createParameter(GID_OUTOFGROUP, theValue)), + GCS_POINT_WRAPPER(thePoint1), GCS_ENTITY_WRAPPER(theEntity1)); + break; + case CONSTRAINT_RADIUS: + aResult = createConstraintRadius(theConstraint, theGroupID, + GCS_PARAMETER_WRAPPER(createParameter(GID_OUTOFGROUP, theValue)), + GCS_ENTITY_WRAPPER(theEntity1)); + break; + case CONSTRAINT_ANGLE: + aResult = createConstraintAngle(theConstraint, theGroupID, + GCS_PARAMETER_WRAPPER(createParamAngle(GID_OUTOFGROUP, 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)); + break; + case CONSTRAINT_PARALLEL: + aResult = createConstraintParallel(theConstraint, theGroupID, + GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2)); + break; + case CONSTRAINT_PERPENDICULAR: + aResult = createConstraintPerpendicular(theConstraint, theGroupID, + GCS_ENTITY_WRAPPER(theEntity1), GCS_ENTITY_WRAPPER(theEntity2)); + break; + case CONSTRAINT_EQUAL_LINES: + anIntermediate = createParameter(theGroupID); + 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)); + break; + case CONSTRAINT_TANGENT_ARC_LINE: + case CONSTRAINT_TANGENT_ARC_ARC: + aResult = createConstraintTangent(theConstraint, theGroupID, theType, + 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); +} + +std::list PlaneGCSSolver_Builder::createConstraint( + ConstraintPtr theConstraint, + const GroupID& theGroupID, + const EntityID& theSketchID, + const SketchSolver_ConstraintType& theType, + const double& theValue, + 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(); + + std::list aConstrAttrList = theTrsfEnt; + if (thePoint2) + aConstrAttrList.push_front(thePoint2); + aConstrAttrList.push_front(thePoint1); + + std::shared_ptr aResult( + new PlaneGCSSolver_ConstraintWrapper(theConstraint, std::list(), theType)); + aResult->setGroup(theGroupID); + aResult->setEntities(aConstrAttrList); + if (anAngleParam) + aResult->setValueParameter(anAngleParam); + 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 = + std::dynamic_pointer_cast(theEntity1); + std::shared_ptr aPoint2 = + std::dynamic_pointer_cast(theEntity2); + + 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::ConstraintPerpendicular( + *(aPoint1->point()), *(aPoint2->point()), aLine->p1, aLine->p2))); + aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintMidpointOnLine( + *(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(); + 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(false); + } + return aResult; +} + +void PlaneGCSSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstraint) const +{ + SketchSolver_ConstraintType aType = theConstraint->type(); + // Update flags and parameters in constraints + if (aType == CONSTRAINT_ANGLE) + adjustAngle(theConstraint); +//// else if (aType == CONSTRAINT_SYMMETRIC) +//// adjustMirror(theConstraint); + else if (aType == CONSTRAINT_MULTI_ROTATION) + adjustMultiRotation(theConstraint); + else if (aType == CONSTRAINT_MULTI_TRANSLATION) + adjustMultiTranslation(theConstraint); +} + +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()) { + AttributePtr aPoint = theFeature->attribute(SketchPlugin_Point::COORD_ID()); + if (!aPoint->isInitialized()) + return aDummy; + EntityWrapperPtr 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; +} + +EntityWrapperPtr PlaneGCSSolver_Builder::createAttribute( + AttributePtr theAttribute, + const GroupID& theGroupID, + const EntityID& theSketchID) 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(); + } + + aResult->setGroup(theGroupID); + aResult->setParameters(aParameters); + return aResult; +} + +ParameterWrapperPtr PlaneGCSSolver_Builder::createParameter( + const GroupID& theGroupID, double theValue) const +{ + return ::createParameter(theGroupID, theValue); +} + + +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; +} + + + +////EntityWrapperPtr PlaneGCSSolver_Builder::createNormal( +//// AttributePtr theNormal, +//// AttributePtr theDirX, +//// const GroupID& theGroupID) const +////{ +//// std::shared_ptr aNorm = std::dynamic_pointer_cast(theNormal); +//// std::shared_ptr aDirX = std::dynamic_pointer_cast(theDirX); +//// if (!aDirX || !aNorm || +//// (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) || +//// !aNorm->isInitialized()) +//// return EntityWrapperPtr(); +//// // calculate Y direction +//// std::shared_ptr aDirY(new GeomAPI_Dir(aNorm->dir()->cross(aDirX->dir()))); +//// +//// // quaternion parameters of normal vector +//// double qw, qx, qy, qz; +//// Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), aDirY->x(), aDirY->y(), aDirY->z(), &qw, +//// &qx, &qy, &qz); +//// double aNormCoord[4] = { qw, qx, qy, qz }; +//// +//// // Create parameters of the normal +//// std::list aParameters; +//// for (int i = 0; i < 4; i++) +//// aParameters.push_back(createParameter(theGroupID, aNormCoord[i])); +//// +//// // Create a normal with empty parameters +//// Slvs_Entity aNormalEnt = Slvs_MakeNormal3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, +//// SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN); +//// EntityWrapperPtr aNormal(new SolveSpaceSolver_EntityWrapper(theNormal, aNormalEnt)); +//// aNormal->setParameters(aParameters); +//// return aNormal; +////} + + + + + +// ================ 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)); + aNewEntity->setGroup(theGroupID); // sub-entities should not change their groups, therefore they are added later + 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)); + aNewEntity->setGroup(theGroupID); // sub-entities should not change their groups, therefore they are added later + 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)); + aNewEntity->setGroup(theGroupID); // sub-entities should not change their groups, therefore they are added later + aNewEntity->setSubEntities(aSubs); + return aNewEntity; +} + + + +ConstraintWrapperPtr createConstraintCoincidence( + ConstraintPtr theConstraint, + const GroupID& theGroupID, + std::shared_ptr thePoint1, + std::shared_ptr thePoint2) +{ + // 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()))); + } + + 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; +} + +ConstraintWrapperPtr createConstraintPointOnEntity( + ConstraintPtr theConstraint, + const GroupID& theGroupID, + const SketchSolver_ConstraintType& theType, + std::shared_ptr thePoint, + std::shared_ptr theEntity) +{ + GCSConstraintPtr aNewConstr; + + switch (theEntity->type()) { + case ENTITY_LINE: { + std::shared_ptr aLine = std::dynamic_pointer_cast(theEntity->entity()); + aNewConstr = GCSConstraintPtr(new GCS::ConstraintPointOnLine(*(thePoint->point()), *aLine)); + break; + } + case ENTITY_ARC: + case ENTITY_CIRCLE: { + std::shared_ptr aCirc = std::dynamic_pointer_cast(theEntity->entity()); + aNewConstr = GCSConstraintPtr( + new GCS::ConstraintP2PDistance(*(thePoint->point()), aCirc->center, aCirc->rad)); + break; + } + default: + 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; +} + +ConstraintWrapperPtr createConstraintDistancePointPoint( + ConstraintPtr theConstraint, + const GroupID& theGroupID, + std::shared_ptr theValue, + std::shared_ptr thePoint1, + std::shared_ptr thePoint2) +{ + GCSConstraintPtr aNewConstr(new GCS::ConstraintP2PDistance( + *(thePoint1->point()), *(thePoint2->point()), theValue->parameter())); + + 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); + aResult->setValueParameter(theValue); + return aResult; +} + +ConstraintWrapperPtr createConstraintDistancePointLine( + ConstraintPtr theConstraint, + const GroupID& theGroupID, + 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())); + + 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); + aResult->setValueParameter(theValue); + return aResult; +} + +ConstraintWrapperPtr createConstraintRadius( + ConstraintPtr theConstraint, + const GroupID& theGroupID, + 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())); + + std::shared_ptr aResult( + new PlaneGCSSolver_ConstraintWrapper(theConstraint, aNewConstr, CONSTRAINT_RADIUS)); + aResult->setGroup(theGroupID); + std::list aSubs(1, theEntity); + aResult->setEntities(aSubs); + aResult->setValueParameter(theValue); + return aResult; +} + +ConstraintWrapperPtr createConstraintAngle( + ConstraintPtr theConstraint, + const GroupID& theGroupID, + std::shared_ptr theValue, + std::shared_ptr theEntity1, + std::shared_ptr theEntity2) +{ + std::shared_ptr aLine1 = std::dynamic_pointer_cast(theEntity1->entity()); + std::shared_ptr aLine2 = std::dynamic_pointer_cast(theEntity2->entity()); + GCSConstraintPtr aNewConstr(new GCS::ConstraintL2LAngle( + *(aLine1), *(aLine2), theValue->parameter())); + + 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); + aResult->setValueParameter(theValue); + return aResult; +} + +ConstraintWrapperPtr createConstraintHorizVert( + ConstraintPtr theConstraint, + const GroupID& theGroupID, + const SketchSolver_ConstraintType& theType, + std::shared_ptr theEntity) +{ + std::shared_ptr aLine = std::dynamic_pointer_cast(theEntity->entity()); + GCSConstraintPtr aNewConstr; + if (theType == CONSTRAINT_HORIZONTAL) + aNewConstr = GCSConstraintPtr(new GCS::ConstraintEqual(aLine->p1.y, aLine->p2.y)); + 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; +} + +ConstraintWrapperPtr createConstraintParallel( + ConstraintPtr theConstraint, + const GroupID& theGroupID, + std::shared_ptr theEntity1, + std::shared_ptr theEntity2) +{ + std::shared_ptr aLine1 = std::dynamic_pointer_cast(theEntity1->entity()); + 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; +} + +ConstraintWrapperPtr createConstraintPerpendicular( + ConstraintPtr theConstraint, + const GroupID& theGroupID, + std::shared_ptr theEntity1, + std::shared_ptr theEntity2) +{ + std::shared_ptr aLine1 = std::dynamic_pointer_cast(theEntity1->entity()); + 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; +} + +ConstraintWrapperPtr createConstraintEqual( + ConstraintPtr theConstraint, + const GroupID& theGroupID, + const SketchSolver_ConstraintType& theType, + std::shared_ptr theEntity1, + std::shared_ptr theEntity2, + std::shared_ptr theIntermed) +{ + if (theType == CONSTRAINT_EQUAL_LINE_ARC) + return ConstraintWrapperPtr(); // line-arc equivalence is not supported yet + + std::list aConstrList; + if (theType == CONSTRAINT_EQUAL_LINES) { + std::shared_ptr aLine1 = std::dynamic_pointer_cast(theEntity1->entity()); + std::shared_ptr aLine2 = std::dynamic_pointer_cast(theEntity2->entity()); + + aConstrList.push_back(GCSConstraintPtr( + new GCS::ConstraintP2PDistance(aLine1->p1, aLine1->p2, theIntermed->parameter()))); + aConstrList.push_back(GCSConstraintPtr( + new GCS::ConstraintP2PDistance(aLine2->p1, aLine2->p2, theIntermed->parameter()))); + } else { + std::shared_ptr aCirc1 = + std::dynamic_pointer_cast(theEntity1->entity()); + std::shared_ptr aCirc2 = + std::dynamic_pointer_cast(theEntity2->entity()); + + aConstrList.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(aCirc1->rad, aCirc2->rad))); + } + + 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); + 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) +{ + GCSConstraintPtr aNewConstr; + if (theType == CONSTRAINT_TANGENT_ARC_LINE) { + std::shared_ptr aCirc = std::dynamic_pointer_cast(theEntity1->entity()); + std::shared_ptr aLine = std::dynamic_pointer_cast(theEntity2->entity()); + + aNewConstr = GCSConstraintPtr(new GCS::ConstraintP2LDistance(aCirc->center, *aLine, aCirc->rad)); + } else { + std::shared_ptr aCirc1 = std::dynamic_pointer_cast(theEntity1->entity()); + std::shared_ptr aCirc2 = std::dynamic_pointer_cast(theEntity2->entity()); + + double aDX = *(aCirc1->center.x) - *(aCirc2->center.x); + double aDY = *(aCirc1->center.y) - *(aCirc2->center.y); + double aDist = sqrt(aDX * aDX + aDY * aDY); + aNewConstr = GCSConstraintPtr(new GCS::ConstraintTangentCircumf(aCirc1->center, aCirc2->center, + 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 adjustAngle(ConstraintWrapperPtr theConstraint) +{ + BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance(); + + std::shared_ptr aConstraint = + std::dynamic_pointer_cast(theConstraint); + + std::shared_ptr aPoints[2][2]; // start and end points of lines + const std::list& aConstrLines = aConstraint->entities(); + std::list::const_iterator aCLIt = aConstrLines.begin(); + for (int i = 0; aCLIt != aConstrLines.end(); ++i, ++aCLIt) { + const std::list& aLinePoints = (*aCLIt)->subEntities(); + std::list::const_iterator aLPIt = aLinePoints.begin(); + for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt) + aPoints[i][j] = aBuilder->point(*aLPIt); + } + + std::shared_ptr aLine[2] = { + std::shared_ptr(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])), + std::shared_ptr(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1])) + }; + std::shared_ptr anIntersection = aLine[0]->intersect(aLine[1]); + if (!anIntersection) + return; + double aDist[2][2]; + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + aDist[i][j] = anIntersection->distance(aPoints[i][j]); + if (fabs(aDist[i][j]) <= tolerance) + aDist[i][j] = 0.0; + } + if (aDist[i][0] > tolerance && aDist[i][1] > tolerance && + aDist[i][0] + aDist[i][1] < aPoints[i][0]->distance(aPoints[i][1]) + 2.0 * tolerance) { + // the intersection point is an inner point of the line, + // we change the sign of distance till start point to calculate correct coordinates + // after rotation + aDist[i][0] *= -1.0; + } + } + std::shared_ptr aDir[2]; + for (int i = 0; i < 2; i++) { + if (aDist[i][1] > fabs(aDist[i][0])) + aDir[i] = std::shared_ptr(new GeomAPI_Dir2d( + aPoints[i][1]->xy()->decreased(anIntersection->xy()))); + else { + aDir[i] = std::shared_ptr(new GeomAPI_Dir2d( + aPoints[i][0]->xy()->decreased(anIntersection->xy()))); + // main direction is opposite => change signs + if (aDist[i][0] < 0.0) { + aDist[i][0] *= -1.0; + aDist[i][1] *= -1.0; + } + } + } + + bool isChange = false; + for (int i = 0; i < 2; i++) + if (aLine[i]->direction()->dot(aDir[i]) < 0.0) + isChange = !isChange; + if (isChange) + aConstraint->setValue(180.0 - aConstraint->value()); +} + +////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; +//// } +//// +//// makeMirrorPoints(aPoints[0], aPoints[1], aMirrorLine); +////} + +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]); + } +} + +static void rotate(EntityWrapperPtr theSource, EntityWrapperPtr theDest, + std::shared_ptr theCenter, + double theSin, double theCos) +{ + if (theSource->type() == ENTITY_POINT) { + // Rotate single point + std::shared_ptr aSrcAttr = + std::dynamic_pointer_cast(theSource->baseAttribute()); + std::shared_ptr aDstAttr = + std::dynamic_pointer_cast(theDest->baseAttribute()); + if (aSrcAttr && aDstAttr) { + std::shared_ptr aVec = aSrcAttr->pnt()->xy()->decreased(theCenter->xy()); + double aNewX = aVec->x() * theCos - aVec->y() * theSin; + double aNewY = aVec->x() * theSin + aVec->y() * theCos; + aDstAttr->setValue(theCenter->x() + aNewX, theCenter->y() + aNewY); + } + return; + } + + FeaturePtr aDestFeature = theDest->baseFeature(); + if (aDestFeature) + aDestFeature->data()->blockSendAttributeUpdated(true); + + // Rotate points of the feature + const std::list& aSrcSubs = theSource->subEntities(); + const std::list& aDstSubs = theDest->subEntities(); + std::list::const_iterator aSrcIt, aDstIt; + for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin(); + aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt) + rotate(*aSrcIt, *aDstIt, theCenter, theSin, theCos); + + if (aDestFeature) + aDestFeature->data()->blockSendAttributeUpdated(false); +} + +static void translate(EntityWrapperPtr theSource, EntityWrapperPtr theDest, + std::shared_ptr theDelta) +{ + if (theSource->type() == ENTITY_POINT) { + // Translate single point + std::shared_ptr aSrcAttr = + std::dynamic_pointer_cast(theSource->baseAttribute()); + std::shared_ptr aDstAttr = + std::dynamic_pointer_cast(theDest->baseAttribute()); + if (aSrcAttr && aDstAttr) + aDstAttr->setValue(aSrcAttr->x() + theDelta->x(), aSrcAttr->y() + theDelta->y()); + return; + } + + FeaturePtr aDestFeature = theDest->baseFeature(); + if (aDestFeature) + aDestFeature->data()->blockSendAttributeUpdated(true); + + // Translate points of the feature + const std::list& aSrcSubs = theSource->subEntities(); + const std::list& aDstSubs = theDest->subEntities(); + std::list::const_iterator aSrcIt, aDstIt; + for (aSrcIt = aSrcSubs.begin(), aDstIt = aDstSubs.begin(); + aSrcIt != aSrcSubs.end() && aDstIt != aDstSubs.end(); ++aSrcIt, ++aDstIt) + translate(*aSrcIt, *aDstIt, theDelta); + + if (aDestFeature) + aDestFeature->data()->blockSendAttributeUpdated(false); +} + +void adjustMultiRotation(ConstraintWrapperPtr theConstraint) +{ + BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance(); + + double anAngleRad = theConstraint->value() * PI / 180.0; + double aSin = sin(anAngleRad); + double aCos = cos(anAngleRad); + + const std::list& aSubs = theConstraint->entities(); + std::list::const_iterator aSIt = aSubs.begin(); + + std::shared_ptr aCenter = aBuilder->point(*aSIt++); + std::list::const_iterator aPrevIt = aSIt++; + for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt) + rotate(*aPrevIt, *aSIt, aCenter, aSin, aCos); +} + +void adjustMultiTranslation(ConstraintWrapperPtr theConstraint) +{ + BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance(); + + const std::list& aSubs = theConstraint->entities(); + std::list::const_iterator aSIt = aSubs.begin(); + + std::shared_ptr aStartPnt = aBuilder->point(*aSIt++); + std::shared_ptr aEndPnt = aBuilder->point(*aSIt++); + std::shared_ptr aDelta = aEndPnt->xy()->decreased(aStartPnt->xy()); + + std::list::const_iterator aPrevIt = aSIt++; + for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt) + translate(*aPrevIt, *aSIt, aDelta); +} diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.h new file mode 100644 index 000000000..ef511e3ea --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Builder.h @@ -0,0 +1,139 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_Builder.h +// Created: 14 Dec 2015 +// Author: Artem ZHIDKOV + +#ifndef PlaneGCSSolver_Builder_H_ +#define PlaneGCSSolver_Builder_H_ + +#include + +#include +#include + +#include + +#include + +/** \class PlaneGCSSolver_Builder + * \ingroup Plugins + * \brief Create bridges between SketchPlugin constraints and PlaneGCS constraints + */ +class PlaneGCSSolver_Builder : public SketchSolver_Builder +{ +private: + /// Default constructor + PlaneGCSSolver_Builder() {} + +public: + /// \brief Returns single instance of builder + static BuilderPtr getInstance(); + + /// \brief Creates a storage specific for used solver + virtual StoragePtr createStorage(const GroupID& theGroup) const; + /// \brief Creates specific solver + virtual SolverPtr createSolver() const; + + /// \brief Creates new constraint(s) 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 + /// \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 + createConstraint(ConstraintPtr theConstraint, + const GroupID& theGroupID, + const EntityID& theSketchID, + const SketchSolver_ConstraintType& theType, + const double& theValue, + const EntityWrapperPtr& theEntity1, + const EntityWrapperPtr& theEntity2 = EntityWrapperPtr(), + const EntityWrapperPtr& theEntity3 = EntityWrapperPtr(), + const EntityWrapperPtr& theEntity4 = EntityWrapperPtr()) const; + + /// \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 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 + createConstraint(ConstraintPtr theConstraint, + const GroupID& theGroupID, + const EntityID& theSketchID, + const SketchSolver_ConstraintType& theType, + const double& theValue, + const EntityWrapperPtr& thePoint1, + const EntityWrapperPtr& thePoint2, + const std::list& theTrsfEnt) const; + + /// \brief Update flags for several kinds of constraints + virtual void adjustConstraint(ConstraintWrapperPtr theConstraint) const; + + /// \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; + +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; + +//// /// \brief Converts two axes of sketch's trihedron to the normal entity +//// /// \param theNormal [in] direction of the normal of the sketch +//// /// \param theDirX [in] direction of the X axis of the sketch +//// /// \param theGroupID [in] group, the normal belongs to +//// /// \return Created entity or empty pointer, if there are incorrect attributes +//// EntityWrapperPtr createNormal(AttributePtr theNormal, +//// AttributePtr theDirX, +//// const GroupID& theGroupID) const; + +private: + static BuilderPtr mySelf; +}; + +#endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.cpp new file mode 100644 index 000000000..db932e8b0 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.cpp @@ -0,0 +1,128 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_ConstraintWrapper.cpp +// Created: 14 Dec 2015 +// Author: Artem ZHIDKOV + +#include + +#include + +PlaneGCSSolver_ConstraintWrapper::PlaneGCSSolver_ConstraintWrapper( + const ConstraintPtr& theOriginal, + const GCSConstraintPtr& theConstraint, + const SketchSolver_ConstraintType& theType) + : myGCSConstraints(1, theConstraint), + myType(theType), + myID(CID_UNKNOWN) +{ + myBaseConstraint = theOriginal; + myValue = 0.0; +} + +PlaneGCSSolver_ConstraintWrapper::PlaneGCSSolver_ConstraintWrapper( + const ConstraintPtr& theOriginal, + const std::list& theConstraints, + const SketchSolver_ConstraintType& theType) + : myGCSConstraints(theConstraints), + myType(theType), + myID(CID_UNKNOWN) +{ + myBaseConstraint = theOriginal; + myValue = 0.0; +} + +void PlaneGCSSolver_ConstraintWrapper::setValueParameter(const ParameterWrapperPtr& 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) +{ + if (type() != theOther->type()) + return false; +//// const Slvs_Constraint anOtherConstraint = +//// std::dynamic_pointer_cast(theOther)->constraint(); +//// if (mySlvsConstraint.type != anOtherConstraint.type) +//// return false; +//// +//// // Verify SolveSpace entities. If they are equal, no need additional checking of parameters. +//// if (mySlvsConstraint.group == anOtherConstraint.group && +//// mySlvsConstraint.ptA == anOtherConstraint.ptA && +//// mySlvsConstraint.ptB == anOtherConstraint.ptB && +//// mySlvsConstraint.entityA == anOtherConstraint.entityA && +//// mySlvsConstraint.entityB == anOtherConstraint.entityB && +//// mySlvsConstraint.entityC == anOtherConstraint.entityC && +//// mySlvsConstraint.entityD == anOtherConstraint.entityD && +//// fabs(mySlvsConstraint.valA - anOtherConstraint.valA) < tolerance) { +//// return true; +//// } + + // 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; +} diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.h new file mode 100644 index 000000000..74341b589 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ConstraintWrapper.h @@ -0,0 +1,78 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_ConstraintWrapper.h +// Created: 14 Dec 2015 +// Author: Artem ZHIDKOV + +#ifndef PlaneGCSSolver_ConstraintWrapper_H_ +#define PlaneGCSSolver_ConstraintWrapper_H_ + +#include +#include +#include + + +/** + * Wrapper providing operations with SovleSpace constraints. + */ +class PlaneGCSSolver_ConstraintWrapper : public SketchSolver_IConstraintWrapper +{ +public: + PlaneGCSSolver_ConstraintWrapper(const ConstraintPtr& theOriginal, + const GCSConstraintPtr& theConstraint, + const SketchSolver_ConstraintType& theType); + PlaneGCSSolver_ConstraintWrapper(const ConstraintPtr& theOriginal, + const std::list& theConstraints, + const SketchSolver_ConstraintType& theType); + + /// \brief Return list of constraints + const std::list& constraints() const + { return myGCSConstraints; } +//// /// \brief Return SolveSpace constraint to change +//// GCSConstraintPtr& changeConstraint() +//// { return myGCSConstraint; } + + /// \brief Return ID of current entity + virtual ConstraintID id() const + { return myID; } + + /// \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; } + + /// \brief Return type of current entity + virtual SketchSolver_ConstraintType type() const + { return myType; } + + /// \brief Assign numeric parameter of constraint + virtual void setValue(const double& theValue); + + /// \brief Change parameter representing the value of constraint + void setValueParameter(const ParameterWrapperPtr& theValue); + /// \brief Return parametric representation of constraint value + const ParameterWrapperPtr& 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; + std::list myGCSConstraints; +}; + +#endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Defs.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Defs.h new file mode 100644 index 000000000..5a22cde9e --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Defs.h @@ -0,0 +1,20 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_Defs.h +// Created: 14 Dec 2015 +// Author: Artem ZHIDKOV + +#ifndef PlaneGCSSolver_Defs_H_ +#define PlaneGCSSolver_Defs_H_ + +#include + +#include +#include +#include + +typedef std::shared_ptr GCSPointPtr; +typedef std::shared_ptr GCSCurvePtr; +typedef std::shared_ptr GCSConstraintPtr; + +#endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.cpp new file mode 100644 index 000000000..45bee0ed5 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.cpp @@ -0,0 +1,118 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_EntityWrapper.cpp +// Created: 14 Dec 2015 +// Author: Artem ZHIDKOV + +#include +#include +#include + +PlaneGCSSolver_EntityWrapper::PlaneGCSSolver_EntityWrapper( + const FeaturePtr theFeature, const GCSCurvePtr theEntity) + : myEntity(theEntity), + myID(EID_UNKNOWN) +{ + myBaseFeature = theFeature; + + std::shared_ptr aLine = std::dynamic_pointer_cast(myEntity); + if (aLine) myType = ENTITY_LINE; + else { + std::shared_ptr anArc = std::dynamic_pointer_cast(myEntity); + if (anArc) myType = ENTITY_ARC; + else { + std::shared_ptr aCircle = std::dynamic_pointer_cast(myEntity); + if (aCircle) myType = ENTITY_CIRCLE; + } + } + + // empty entity, probably this is a SketchPlugin_Point or SketchPlugin_Sketch + if (theFeature->getKind() == SketchPlugin_Point::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 new file mode 100644 index 000000000..cb107b7d7 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EntityWrapper.h @@ -0,0 +1,64 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_EntityWrapper.h +// Created: 14 Dec 2015 +// Author: Artem ZHIDKOV + +#ifndef PlaneGCSSolver_EntityWrapper_H_ +#define PlaneGCSSolver_EntityWrapper_H_ + +#include +#include + +/** + * Wrapper providing operations with PlaneGCS entities. + */ +class PlaneGCSSolver_EntityWrapper : public SketchSolver_IEntityWrapper +{ +public: + PlaneGCSSolver_EntityWrapper(const FeaturePtr theFeature, const GCSCurvePtr theEntity = GCSCurvePtr()); + + /// \brief Return PlaneGCS geometric entity + const GCSCurvePtr& entity() const + { return myEntity; } + /// \brief Return PlaneGCS geometric entity to change + 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; +}; + +#endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ParameterWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ParameterWrapper.cpp new file mode 100644 index 000000000..0a271ffab --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ParameterWrapper.cpp @@ -0,0 +1,44 @@ +// 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() +{ + 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 new file mode 100644 index 000000000..757728e3d --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ParameterWrapper.h @@ -0,0 +1,63 @@ +// 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 new file mode 100644 index 000000000..a1e66e587 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointWrapper.cpp @@ -0,0 +1,61 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_PointWrapper.cpp +// Created: 14 Dec 2015 +// Author: Artem ZHIDKOV + +#include + +PlaneGCSSolver_PointWrapper::PlaneGCSSolver_PointWrapper( + const AttributePtr theAttribute, const GCSPointPtr thePoint) + : myPoint(thePoint), + myID(EID_UNKNOWN) +{ + 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 new file mode 100644 index 000000000..dc276d4b2 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointWrapper.h @@ -0,0 +1,64 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_PointWrapper.h +// Created: 16 Dec 2015 +// Author: Artem ZHIDKOV + +#ifndef PlaneGCSSolver_PointWrapper_H_ +#define PlaneGCSSolver_PointWrapper_H_ + +#include +#include + +/** + * Wrapper providing operations with PlaneGCS points. + */ +class PlaneGCSSolver_PointWrapper : public SketchSolver_IEntityWrapper +{ +public: + PlaneGCSSolver_PointWrapper(const AttributePtr theAttribute, const GCSPointPtr thePoint); + + /// \brief Return PlaneGCS point + const GCSPointPtr& point() const + { return myPoint; } + /// \brief Return PlaneGCS point to change + 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; +}; + +#endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.cpp new file mode 100644 index 000000000..281198846 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.cpp @@ -0,0 +1,66 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_ScalarWrapper.cpp +// Created: 14 Dec 2015 +// Author: Artem ZHIDKOV + +#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) +{ + myGroup = theGroup; + myParameters.front()->setGroup(theGroup); +} + +double* PlaneGCSSolver_ScalarWrapper::scalar() const +{ + 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; +} + +bool PlaneGCSSolver_ScalarWrapper::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_ScalarWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.h new file mode 100644 index 000000000..89e389da2 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.h @@ -0,0 +1,59 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_ScalarWrapper.h +// Created: 16 Dec 2015 +// Author: Artem ZHIDKOV + +#ifndef PlaneGCSSolver_ScalarWrapper_H_ +#define PlaneGCSSolver_ScalarWrapper_H_ + +#include +#include + +/** + * Wrapper providing operations with PlaneGCS scalars. + */ +class PlaneGCSSolver_ScalarWrapper : public SketchSolver_IEntityWrapper +{ +public: + PlaneGCSSolver_ScalarWrapper(const AttributePtr theAttribute, const ParameterWrapperPtr theParam); + + /// \brief Return PlaneGCS parameter + double* scalar() const; + + /// \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_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; +}; + +#endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp new file mode 100644 index 000000000..71f6d87b3 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.cpp @@ -0,0 +1,67 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_Solver.cpp +// Created: 14 Dec 2014 +// Author: Artem ZHIDKOV + +#include "PlaneGCSSolver_Solver.h" +#include + + +PlaneGCSSolver_Solver::~PlaneGCSSolver_Solver() +{ + clear(); +} + +void PlaneGCSSolver_Solver::clear() +{ + std::set::const_iterator anIt = myConstraints.begin(); + for (; anIt != myConstraints.end(); ++anIt) + myEquationSystem.removeConstraint(*anIt); + myConstraints.clear(); + myParameters.clear(); +} + +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.insert(aConstraint); +} + +void PlaneGCSSolver_Solver::removeConstraint(GCSConstraintPtr theConstraint) +{ + GCS::Constraint* aConstraint = theConstraint.get(); + if (myConstraints.find(aConstraint) == myConstraints.end()) + return; // no constraint, no need to remove it + + myEquationSystem.removeConstraint(aConstraint); + myConstraints.erase(aConstraint); +} + +SketchSolver_SolveStatus PlaneGCSSolver_Solver::solve() +{ + if (myConstraints.empty()) + return STATUS_EMPTYSET; + if (myParameters.empty()) + return STATUS_INCONSISTENT; + +//// myEquationSystem.calculateFaileds = myFindFaileds ? 1 : 0; + + Events_LongOp::start(this); + GCS::SolveStatus aResult = (GCS::SolveStatus)myEquationSystem.solve(myParameters); + Events_LongOp::end(this); + + SketchSolver_SolveStatus aStatus; + if (aResult == GCS::Success) { + myEquationSystem.applySolution(); + aStatus = STATUS_OK; + } else { + myEquationSystem.undoSolution(); + aStatus = STATUS_FAILED; + } + return aStatus; +} diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h new file mode 100644 index 000000000..605a97794 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Solver.h @@ -0,0 +1,57 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_Solver.h +// Created: 14 Dec 2014 +// Author: Artem ZHIDKOV + +#ifndef PlaneGCSSolver_Solver_H_ +#define PlaneGCSSolver_Solver_H_ + +#include +#include + +////// Need to be defined before including SolveSpace to avoid additional dependences on Windows platform +////#if defined(WIN32) && !defined(HAVE_C99_INTEGER_TYPES) +////typedef unsigned int UINT32; +////#else +////#include +////#endif +////#include +#include + +////#include + +/** + * The main class that performs the high-level operations for connection to the PlaneGCS. + */ +class PlaneGCSSolver_Solver : public SketchSolver_ISolver +{ +public: + PlaneGCSSolver_Solver() {} + ~PlaneGCSSolver_Solver(); + + /// \brief Clear system of equations + void clear(); + + /// \brief Add constraint to the system of equations + void addConstraint(GCSConstraintPtr theConstraint); + + /// \brief Remove constraint from the system of equations + void removeConstraint(GCSConstraintPtr theConstraint); + + /// \brief Initialize list of unknowns + void setParameters(const GCS::VEC_pD& theParams) + { myParameters = theParams; } + + /** \brief Solve the set of equations + * \return identifier whether solution succeeded + */ + virtual SketchSolver_SolveStatus solve(); + +private: + GCS::VEC_pD myParameters; ///< list of unknowns + std::set myConstraints; ///< list of constraints already processed by the system + GCS::System myEquationSystem; ///< set of equations for solving in FreeGCS +}; + +#endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp new file mode 100644 index 000000000..475fd7e27 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp @@ -0,0 +1,1256 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_Storage.cpp +// Created: 14 Dec 2015 +// Author: Artem ZHIDKOV + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +////#include +////#include +////#include + +#include +////#include +////#include +////#include +//// +////#ifndef OBSOLETE +////#include +////#endif + +#include + +////#ifdef OBSOLETE +/////** \brief Search the entity/parameter with specified ID in the list of elements +//// * \param[in] theEntityID unique ID of the element +//// * \param[in] theEntities list of elements +//// * \return position of the found element or -1 if the element is not found +//// */ +////template +////static int Search(const uint32_t& theEntityID, const std::vector& theEntities); +//// +/////// \brief Compare two parameters to be different +////static bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2); +/////// \brief Compare two entities to be different +////static bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2); +/////// \brief Compare two constriants to be different +////static bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2); +////#endif + + +PlaneGCSSolver_Storage::PlaneGCSSolver_Storage(const GroupID& theGroup) + : SketchSolver_Storage(theGroup), + myEntityLastID(EID_SKETCH) +{ +} + +void PlaneGCSSolver_Storage::addConstraint( + ConstraintPtr theConstraint, + std::list theSolverConstraints) +{ + 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); + } +} + + +bool PlaneGCSSolver_Storage::update(ConstraintWrapperPtr& theConstraint) +{ + 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; + + return isUpdated; +} + +/// \brief Update coordinates of the point or scalar using its base attribute +static bool updateValues(EntityWrapperPtr& theEntity) +{ + 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); + if (aPoint2D) { + aCoord[0] = aPoint2D->x(); + aCoord[1] = aPoint2D->y(); + } 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]) > tolerance) { + (*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); + } + + // 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); + aPoint->setId(++myEntityLastID); + } else if (theEntity->type() == ENTITY_SCALAR) { + std::shared_ptr aScalar = + std::dynamic_pointer_cast(theEntity); + aScalar->setId(++myEntityLastID); + } else { + std::shared_ptr aGCSEnt = + std::dynamic_pointer_cast(theEntity); + aGCSEnt->setId(++myEntityLastID); + } + } + 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; + 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()->data() || !aConstraint->baseConstraint()->data()->isValid())) + isFullyRemoved = true; + if (isFullyRemoved) { + setNeedToResolve(true); + myRemovedConstraints.insert(myRemovedConstraints.end(), + aConstraint->constraints().begin(), aConstraint->constraints().end()); + } + return isFullyRemoved; +} + +bool PlaneGCSSolver_Storage::remove(EntityWrapperPtr theEntity) +{ + if ((theEntity->baseAttribute() && isUsed(theEntity->baseAttribute())) || + (theEntity->baseFeature() && isUsed(theEntity->baseFeature()))) + return false; + + bool isFullyRemoved = SketchSolver_Storage::remove(theEntity); + if (isFullyRemoved && theEntity->id() == myEntityLastID) + --myEntityLastID; + return isFullyRemoved; +} + +bool PlaneGCSSolver_Storage::remove(ParameterWrapperPtr theParameter) +{ + 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); + } + 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); + return true; +} + + +void PlaneGCSSolver_Storage::addCoincidentPoints( + EntityWrapperPtr theMaster, EntityWrapperPtr theSlave) +{ + if (theMaster->type() != ENTITY_POINT || theSlave->type() != ENTITY_POINT) + return; + + // Search available coincidence + CoincidentPointsMap::iterator aMasterFound = myCoincidentPoints.find(theMaster); + CoincidentPointsMap::iterator aSlaveFound = myCoincidentPoints.find(theSlave); + 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(theMaster) != anIt->second.end()) + aMasterFound = anIt; + else if (anIt->second.find(theSlave) != anIt->second.end()) + aSlaveFound = anIt; + + if (aMasterFound != myCoincidentPoints.end() && aSlaveFound != myCoincidentPoints.end()) + break; + } + } + + if (aMasterFound == myCoincidentPoints.end()) { + // create new group + myCoincidentPoints[theMaster] = std::set(); + aMasterFound = myCoincidentPoints.find(theMaster); + } 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(theMaster, *aSlIt); + } else { +//// std::list aSlaveParams = theSlave->parameters(); +//// theSlave->setParameters(theMaster->parameters()); +//// +//// // Remove slave's parameters +//// std::list::iterator aParIt = aSlaveParams.begin(); +//// for (; aParIt != aSlaveParams.end(); ++aParIt) +//// remove(*aParIt); + + aMasterFound->second.insert(theSlave); + } +} + + +void PlaneGCSSolver_Storage::changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup) +{ + theEntity->setGroup(theGroup); + if (theGroup == myGroupID) + makeVariable(theEntity); + else + makeConstant(theEntity); +} + +void PlaneGCSSolver_Storage::changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup) +{ +//// // TODO +} + +void PlaneGCSSolver_Storage::verifyFixed() +{ +//// // TODO +} + + +#ifndef OBSOLETE +//// +////void PlaneGCSSolver_Storage::changeConstraint( +//// const ConstraintPtr& theConstraint, +//// const std::vector& theGCSConstraints) +////{ +//// myConstraintsMap[theConstraint] = theGCSConstraints; +////} + +////void PlaneGCSSolver_Storage::addConstraint(GCSConstraintPtr theConstraint) +////{ +//// std::map >::iterator +//// aFound = myConstraintsMap.find(ConstraintPtr()); +//// if (aFound != myConstraintsMap.end()) +//// aFound->second.push_back(theConstraint); +//// else { +//// std::vector aConstrVec(1, theConstraint); +//// myConstraintsMap[ConstraintPtr()] = aConstrVec; +//// } +////} + +////EntityID PlaneGCSSolver_Storage::changeEntity(const FeaturePtr& theEntity) +////{ +//// if (!theEntity || !theEntity->data() || !theEntity->data()->isValid()) +//// return ENTITY_UNKNOWN; +//// +//// // Firstly, try to find entity +//// std::map::const_iterator aFound = myFeatureEntityMap.find(theEntity); +//// +//// EntityID aNewEntID; +//// if (aFound != myFeatureEntityMap.end()) +//// aNewEntID = aFound->second; +//// +//// const std::string& aFeatureKind = theEntity->getKind(); +//// // SketchPlugin features +//// if (aFeatureKind == SketchPlugin_Line::ID()) +//// updateLine(theEntity, aNewEntID); +//// // Circle +//// else if (aFeatureKind == SketchPlugin_Circle::ID()) +//// updateCircle(theEntity, aNewEntID); +//// // Arc +//// else if (aFeatureKind == SketchPlugin_Arc::ID()) +//// updateArc(theEntity, aNewEntID); +//// // Point (it has low probability to be an attribute of constraint, so it is checked at the end) +//// else if (aFeatureKind == SketchPlugin_Point::ID()) { +//// AttributePtr anAttribute = theEntity->attribute(SketchPlugin_Point::COORD_ID()); +//// if (!anAttribute->isInitialized()) +//// return ENTITY_UNKNOWN; +//// // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier +//// aNewEntID = changeEntity(anAttribute); +//// } +//// else // NOTE: Other types of entities are unsupported +//// aNewEntID = ENTITY_UNKNOWN; +//// +//// if (aNewEntID != ENTITY_UNKNOWN) +//// myFeatureEntityMap[theEntity] = aNewEntID; +//// return aNewEntID; +////} +//// +////EntityID PlaneGCSSolver_Storage::changeEntity(const AttributePtr& theEntity) +////{ +//// if (!theEntity) +//// return ENTITY_UNKNOWN; +//// +//// AttributeRefAttrPtr aRefAttr = +//// std::dynamic_pointer_cast(theEntity); +//// if (aRefAttr) { +//// if (aRefAttr->isObject()) { +//// ResultConstructionPtr aRC = +//// std::dynamic_pointer_cast(aRefAttr->object()); +//// if (!aRC) +//// return ENTITY_UNKNOWN; +//// return changeEntity(ModelAPI_Feature::feature(aRC)); +//// } +//// else +//// return changeEntity(aRefAttr->attr()); +//// } +//// +//// EntityID aNewEntID = ENTITY_UNKNOWN; +//// +//// // Firstly, try to find entity +//// std::map::const_iterator aFound = myAttributeEntityMap.find(theEntity); +//// // Check type of attribute and create corresponding entity +//// std::shared_ptr aPoint2D = +//// std::dynamic_pointer_cast(theEntity); +//// if (aPoint2D) { +//// if (aFound != myAttributeEntityMap.end()) +//// aNewEntID = aFound->second; +//// updatePoint(aPoint2D, aNewEntID); +//// } else { +//// AttributeDoublePtr aScalar = std::dynamic_pointer_cast(theEntity); +//// if (aScalar) { +//// // Check the scalar represents an angular value +//// bool isAngular = false; +//// FeaturePtr anOwner = ModelAPI_Feature::feature(aScalar->owner()); +//// if (anOwner && anOwner->getKind() == SketchPlugin_ConstraintAngle::ID()) +//// isAngular = true; +//// +//// if (aFound != myAttributeEntityMap.end()) +//// aNewEntID = aFound->second; +//// if (isAngular) +//// updateAngle(aScalar, aNewEntID); +//// else +//// updateScalar(aScalar, aNewEntID); +//// } +//// } +//// // NOTE: Other types of attributes are not supported +//// +//// // Map attribute and new entity ID +//// if (aFound == myAttributeEntityMap.end() && aNewEntID != ENTITY_UNKNOWN) +//// myAttributeEntityMap[theEntity] = aNewEntID; +//// return aNewEntID; +////} + + +////bool PlaneGCSSolver_Storage::removeConstraint(const ConstraintPtr& theConstraint) +////{ +//// std::map >::iterator +//// aFound = myConstraintsMap.find(theConstraint); +//// if (aFound == myConstraintsMap.end()) +//// return true; // no constraint - nothing to remove +//// +//// std::vector aConstrList = aFound->second; +//// myConstraintsMap.erase(aFound); +//// bool isFullyRemoved = removeEntity(theConstraint->attribute(SketchPlugin_Constraint::VALUE())); +//// for (int ind = 0; ind < CONSTRAINT_ATTR_SIZE; ++ind) +//// isFullyRemoved = removeEntity(theConstraint->attribute(SketchPlugin_Constraint::ATTRIBUTE(ind))) +//// && isFullyRemoved; +//// +//// myRemovedConstraints.insert(myRemovedConstraints.end(), aConstrList.begin(), aConstrList.end()); +//// +//// return isFullyRemoved; +////} + +////bool PlaneGCSSolver_Storage::removeConstraint(GCSConstraintPtr theConstraint) +////{ +//// std::map >::iterator +//// aFound = myConstraintsMap.find(ConstraintPtr()); +//// if (aFound != myConstraintsMap.end()) { +//// std::vector::iterator anIt = aFound->second.begin(); +//// for (; anIt != aFound->second.end(); ++anIt) +//// if (*anIt == theConstraint) { +//// aFound->second.erase(anIt); +//// break; +//// } +//// } +//// +//// myRemovedConstraints.push_back(theConstraint); +//// return true; +////} +//// +////bool PlaneGCSSolver_Storage::removeEntity(const FeaturePtr& theFeature) +////{ +//// if (!theFeature) +//// return true; +//// if (isUsed(theFeature)) +//// return false; +//// +//// // remove feature and corresponding entity +//// std::map::iterator aFound = myFeatureEntityMap.find(theFeature); +//// if (aFound != myFeatureEntityMap.end()) { +//// if (aFound->second.type == ARC) { +//// // remove additional arc constraints +//// std::map >::iterator aFoundArc = +//// myArcConstraintMap.find(aFound->second); +//// if (aFoundArc != myArcConstraintMap.end()) { +//// myRemovedConstraints.insert(myRemovedConstraints.end(), +//// aFoundArc->second.begin(), aFoundArc->second.end()); +//// myArcConstraintMap.erase(aFoundArc); +//// } +//// } +//// myGCSEntities.erase(aFound->second); +//// myFeatureEntityMap.erase(aFound); +//// } +//// +//// // remove feature's attributes +//// bool isFullyRemoved = true; +//// std::list anAttributes = theFeature->data()->attributes(std::string()); +//// std::list::iterator anAttrIt = anAttributes.begin(); +//// for (; anAttrIt != anAttributes.end(); ++anAttrIt) +//// isFullyRemoved = removeEntity(*anAttrIt) && isFullyRemoved; +//// return isFullyRemoved; +////} +//// +////bool PlaneGCSSolver_Storage::removeEntity(const AttributePtr& theAttribute) +////{ +//// if (!theAttribute) +//// return true; +//// if (isUsed(theAttribute)) +//// return false; +//// +//// AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(theAttribute); +//// if (aRefAttr) { +//// if (aRefAttr->isObject()) { +//// FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); +//// return removeEntity(aFeature); +//// } else +//// return removeEntity(aRefAttr->attr()); +//// } +//// +//// // remove attribute and corresponding entity +//// std::map::iterator aFound = myAttributeEntityMap.find(theAttribute); +//// if (aFound == myAttributeEntityMap.end()) +//// return true; // no attribute, nothing to remove +//// +//// if (aFound->second.type == SCALAR || aFound->second.type == ANGLE) { +//// std::map::iterator aFoundScalar = myGCSScalars.find(aFound->second); +//// if (aFoundScalar != myGCSScalars.end()) { +//// removeParameters(aFoundScalar->second); +//// myGCSScalars.erase(aFoundScalar); +//// } +//// } +//// else if (aFound->second.type == POINT) { +//// std::map::iterator aFoundPoint = myGCSPoints.find(aFound->second); +//// if (aFoundPoint != myGCSPoints.end()) { +//// removeParameters(aFoundPoint->second->x, aFoundPoint->second->y); +//// myGCSPoints.erase(aFoundPoint); +//// } +//// } +//// +//// myAttributeEntityMap.erase(aFound); +//// return true; +////} + +////void PlaneGCSSolver_Storage::removeParameters(double* theParam1, double* theParam2) +////{ +//// int aNbRemoved = 2; +//// for (int ind = 0; ind < 2 && aNbRemoved > 0; ++ind) { +//// GCS::VEC_pD& aList = ind ==0 ? myParameters : myConst; +//// +//// GCS::VEC_pD::iterator aParIt = aList.begin(); +//// while (aNbRemoved > 0 && aParIt != aList.end()) { +//// if (*aParIt != theParam1 && *aParIt != theParam2) { +//// ++aParIt; +//// continue; +//// } +//// +//// myRemovedParameters.push_back(*aParIt); +//// int aShift = aParIt - aList.begin(); +//// aList.erase(aParIt); +//// aParIt = aList.begin() + aShift; +//// --aNbRemoved; +//// } +//// } +////} + + +////double* PlaneGCSSolver_Storage::createScalar(const AttributeDoublePtr& theScalar) +////{ +//// double* aResult = new double; +//// if (theScalar) +//// *aResult = theScalar->value(); +//// myParameters.push_back(aResult); +//// myNeedToResolve = true; +//// return aResult; +////} +//// +////void PlaneGCSSolver_Storage::updateScalar(const AttributeDoublePtr& theScalar, EntityID& theID) +////{ +//// std::map::const_iterator aFound = myGCSScalars.find(theID); +//// if (aFound == myGCSScalars.end()) { +//// // new scalar +//// theID = ++myEntityLastID; +//// theID.type = SCALAR; +//// myGCSScalars[theID] = createScalar(theScalar); +//// } +//// else if (fabs(*(myGCSScalars[theID]) - theScalar->value()) > tolerance) { +//// *(myGCSScalars[theID]) = theScalar->value(); +//// myNeedToResolve = true; +//// } +////} +//// +////void PlaneGCSSolver_Storage::updateAngle(const AttributeDoublePtr& theAngle, EntityID& theID) +////{ +//// std::map::const_iterator aFound = myGCSScalars.find(theID); +//// if (aFound == myGCSScalars.end()) { +//// // new scalar +//// theID = ++myEntityLastID; +//// theID.type = ANGLE; +//// myGCSScalars[theID] = createScalar(theAngle); +//// } +//// else if (fabs(*(myGCSScalars[theID]) - theAngle->value()) > tolerance) { +//// *(myGCSScalars[theID]) = theAngle->value(); +//// myNeedToResolve = true; +//// } +//// // Convert degrees to radians +//// *(myGCSScalars[theID]) *= M_PI / 180.0; +////} +//// +////GCS::Point PlaneGCSSolver_Storage::createPoint(const std::shared_ptr& thePoint) +////{ +//// GCS::Point aResult; +//// aResult.x = new double(thePoint->x()); +//// aResult.y = new double(thePoint->y()); +//// +//// myParameters.push_back(aResult.x); +//// myParameters.push_back(aResult.y); +//// +//// myNeedToResolve = true; +//// return aResult; +////} +//// +////void PlaneGCSSolver_Storage::updatePoint(const std::shared_ptr& thePoint, +//// EntityID& theID) +////{ +//// std::map::iterator aFound = myGCSPoints.find(theID); +//// if (aFound == myGCSPoints.end()) { +//// // new point +//// theID = ++myEntityLastID; +//// theID.type = POINT; +//// myGCSPoints[theID] = GCSPointPtr(new GCS::Point(createPoint(thePoint))); +//// } +//// else if (fabs(*(aFound->second->x) - thePoint->x()) > tolerance || +//// fabs(*(aFound->second->y) - thePoint->y()) > tolerance) { +//// // update point +//// *(aFound->second->x) = thePoint->x(); +//// *(aFound->second->y) = thePoint->y(); +//// myNeedToResolve = true; +//// } +////} +//// +////void PlaneGCSSolver_Storage::updateLine(const FeaturePtr& theLine, EntityID& theID) +////{ +//// std::shared_ptr aStartAttr = +//// std::dynamic_pointer_cast( +//// theLine->attribute(SketchPlugin_Line::START_ID())); +//// std::shared_ptr aEndAttr = +//// std::dynamic_pointer_cast( +//// theLine->attribute(SketchPlugin_Line::END_ID())); +//// if (!aStartAttr->isInitialized() || !aEndAttr->isInitialized()) { +//// theID = ENTITY_UNKNOWN; +//// return; +//// } +//// +//// std::map::iterator aFound = myGCSEntities.find(theID); +//// if (aFound == myGCSEntities.end()) { +//////// // new line +//////// theID = ++myEntityLastID; +//////// theID.type = LINE; +//////// +//////// EntityID aStartID = changeEntity(aStartAttr); +//////// EntityID aEndID = changeEntity(aEndAttr); +//////// GCS::Point* aStart = getPoint(aStartID); +//////// GCS::Point* aEnd = getPoint(aEndID); +//////// +//////// std::shared_ptr aLine(new GCS::Line); +//////// aLine->p1 = *aStart; +//////// aLine->p2 = *aEnd; +//////// myGCSEntities[theID] = aLine; +//// } +//// else { +//// // update line parameters +//// std::map::iterator aFoundAttr = myAttributeEntityMap.find(aStartAttr); +//// if (aFoundAttr != myAttributeEntityMap.end()) +//// updatePoint(aStartAttr, aFoundAttr->second); +//// aFoundAttr = myAttributeEntityMap.find(aEndAttr); +//// if (aFoundAttr != myAttributeEntityMap.end()) +//// updatePoint(aEndAttr, aFoundAttr->second); +//// } +////} +//// +////void PlaneGCSSolver_Storage::updateCircle(const FeaturePtr& theCircle, EntityID& theID) +////{ +//// std::shared_ptr aCenterAttr = +//// std::dynamic_pointer_cast( +//// theCircle->attribute(SketchPlugin_Circle::CENTER_ID())); +//// AttributeDoublePtr aRadiusAttr = std::dynamic_pointer_cast( +//// theCircle->attribute(SketchPlugin_Circle::RADIUS_ID())); +//// if (!aCenterAttr->isInitialized() || !aRadiusAttr->isInitialized()) { +//// theID = ENTITY_UNKNOWN; +//// return; +//// } +//// +//// std::map::iterator aFound = myGCSEntities.find(theID); +//// if (aFound == myGCSEntities.end()) { +//////// // new circle +//////// theID = ++myEntityLastID; +//////// theID.type = CIRCLE; +//////// +//////// EntityID aCenterID = changeEntity(aCenterAttr); +//////// EntityID aRadiusID = changeEntity(aRadiusAttr); +//////// GCS::Point* aCenter = getPoint(aCenterID); +//////// double* aRadius = getScalar(aRadiusID); +//////// +//////// std::shared_ptr aCircle(new GCS::Circle); +//////// aCircle->center = *aCenter; +//////// aCircle->rad = aRadius; +//////// myGCSEntities[theID] = aCircle; +//// } +//// else { +//// // update circle parameters +//// std::map::iterator aFoundAttr = myAttributeEntityMap.find(aCenterAttr); +//// if (aFoundAttr != myAttributeEntityMap.end()) +//// updatePoint(aCenterAttr, aFoundAttr->second); +//// aFoundAttr = myAttributeEntityMap.find(aRadiusAttr); +//// if (aFoundAttr != myAttributeEntityMap.end()) +//// updateScalar(aRadiusAttr, aFoundAttr->second); +//// } +////} +//// +////void PlaneGCSSolver_Storage::updateArc(const FeaturePtr& theArc, EntityID& theID) +////{ +//// std::shared_ptr aCenterAttr = +//// std::dynamic_pointer_cast( +//// theArc->attribute(SketchPlugin_Arc::CENTER_ID())); +//// std::shared_ptr aStartAttr = +//// std::dynamic_pointer_cast( +//// theArc->attribute(SketchPlugin_Arc::START_ID())); +//// std::shared_ptr aEndAttr = +//// std::dynamic_pointer_cast( +//// theArc->attribute(SketchPlugin_Arc::END_ID())); +//// if (!aCenterAttr->isInitialized() || +//// !aStartAttr->isInitialized() || +//// !aEndAttr->isInitialized()) { +//// theID = ENTITY_UNKNOWN; +//// return; +//// } +//// +//// std::shared_ptr anArc; +//// std::map::iterator aFound = myGCSEntities.find(theID); +//// if (aFound == myGCSEntities.end()) { +//// // new arc +//// theID = ++myEntityLastID; +//// theID.type = ARC; +//// +//// EntityID aCenterID = changeEntity(aCenterAttr); +//// EntityID aStartID = changeEntity(aStartAttr); +//// EntityID aEndID = changeEntity(aEndAttr); +//// GCS::Point* aCenter = getPoint(aCenterID); +//// GCS::Point* aStart = getPoint(aStartID); +//// GCS::Point* aEnd = getPoint(aEndID); +//// +//// anArc = std::shared_ptr(new GCS::Arc); +//// anArc->center = *aCenter; +//// anArc->start = *aStart; +//// anArc->end = *aEnd; +//// anArc->startAngle = createScalar(); +//// anArc->endAngle = createScalar(); +//// anArc->rad = createScalar(); +//// myGCSEntities[theID] = anArc; +//// +//// // Additional constraints for new arc +//// processArc(theID); +//// } +//// else { +//// // update arc parameters +//// anArc = std::dynamic_pointer_cast(aFound->second); +//// std::map::iterator aFoundAttr = myAttributeEntityMap.find(aCenterAttr); +//// if (aFoundAttr != myAttributeEntityMap.end()) +//// updatePoint(aCenterAttr, aFoundAttr->second); +//// aFoundAttr = myAttributeEntityMap.find(aStartAttr); +//// if (aFoundAttr != myAttributeEntityMap.end()) +//// updatePoint(aStartAttr, aFoundAttr->second); +//// aFoundAttr = myAttributeEntityMap.find(aEndAttr); +//// if (aFoundAttr != myAttributeEntityMap.end()) +//// updatePoint(aEndAttr, aFoundAttr->second); +//// } +//// +//// // Calculate additional parameters necessary for FreeGCS +//// std::shared_ptr aCenterPnt = aCenterAttr->pnt(); +//// std::shared_ptr aStartPnt = aStartAttr->pnt(); +//// std::shared_ptr aEndPnt = aEndAttr->pnt(); +//// +//// *(anArc->rad) = aCenterPnt->distance(aStartPnt); +//// std::shared_ptr anArcEdge = +//// std::dynamic_pointer_cast(theArc->lastResult()->shape()); +//// if (!anArcEdge) { +//// theID = ENTITY_UNKNOWN; +//// return; +//// } +//// anArcEdge->getRange(*(anArc->startAngle), *(anArc->endAngle)); +////} + + +////double* PlaneGCSSolver_Storage::getScalar(const EntityID& theID) const +////{ +//// std::map::const_iterator aFound = myGCSScalars.find(theID); +//// if (aFound == myGCSScalars.end()) +//// return 0; +//// return aFound->second; +////} +//// +////GCS::Point* PlaneGCSSolver_Storage::getPoint(const EntityID& theID) const +////{ +//// std::map::const_iterator aFound = myGCSPoints.find(theID); +//// if (aFound == myGCSPoints.end()) +//// return 0; +//// return aFound->second.get(); +////} +//// +////GCS::Line* PlaneGCSSolver_Storage::getLine(const EntityID& theID) const +////{ +//// std::map::const_iterator aFound = myGCSEntities.find(theID); +//// if (aFound == myGCSEntities.end()) +//// return 0; +//// std::shared_ptr aLine = std::dynamic_pointer_cast(aFound->second); +//// if (!aLine) +//// return 0; +//// return aLine.get(); +////} +//// +////GCS::Circle* PlaneGCSSolver_Storage::getCircle(const EntityID& theID) const +////{ +//// std::map::const_iterator aFound = myGCSEntities.find(theID); +//// if (aFound == myGCSEntities.end()) +//// return 0; +//// std::shared_ptr aCircle = std::dynamic_pointer_cast(aFound->second); +//// if (!aCircle) +//// return 0; +//// return aCircle.get(); +////} +//// +////GCS::Arc* PlaneGCSSolver_Storage::getArc(const EntityID& theID) const +////{ +//// std::map::const_iterator aFound = myGCSEntities.find(theID); +//// if (aFound == myGCSEntities.end()) +//// return 0; +//// std::shared_ptr anArc = std::dynamic_pointer_cast(aFound->second); +//// if (!anArc) +//// return 0; +//// return anArc.get(); +////} + +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(); + while ((*aSubIt)->type() == ENTITY_POINT) // search scalar entities + ++aSubIt; + double* aStartAngle = std::dynamic_pointer_cast(*aSubIt++)->scalar(); + double* aEndAngle = std::dynamic_pointer_cast(*aSubIt++)->scalar(); + double* aRadius = std::dynamic_pointer_cast(*aSubIt)->scalar(); + + FeaturePtr anArcFeature = 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())); + std::shared_ptr aCenterPnt = aCenterAttr->pnt(); + std::shared_ptr aStartPnt = aStartAttr->pnt(); + std::shared_ptr aEndPnt = aEndAttr->pnt(); + + *aRadius = aCenterPnt->distance(aStartPnt); + if (!anArcFeature->lastResult()) + return; + std::shared_ptr anArcEdge = + std::dynamic_pointer_cast(anArcFeature->lastResult()->shape()); + if (!anArcEdge) + return; + anArcEdge->getRange(*aStartAngle, *aEndAngle); + + // 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 + anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance( + anArc->center, anArc->start, anArc->rad))); + anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance( + anArc->center, anArc->end, anArc->rad))); + // Angles of start and end points should be equal to given angles + anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle( + anArc->center, anArc->start, anArc->startAngle))); + anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle( + anArc->center, anArc->end, anArc->endAngle))); + + myArcConstraintMap[theArc] = anArcConstraints; +} + +////const std::vector& PlaneGCSSolver_Storage::getConstraint( +//// const ConstraintPtr& theConstraint) const +////{ +//// static const std::vector aDummy; +//// +//// std::map >::const_iterator +//// aFound = myConstraintsMap.find(theConstraint); +//// if (aFound == myConstraintsMap.end()) +//// return aDummy; +//// return aFound->second; +////} + + +void PlaneGCSSolver_Storage::makeConstant(const EntityWrapperPtr& theEntity) +{ + toggleEntity(theEntity, myParameters, myConst); +} + +void PlaneGCSSolver_Storage::makeVariable(const EntityWrapperPtr& theEntity) +{ + toggleEntity(theEntity, myConst, myParameters); +} + +static void getParametersToMove(const EntityWrapperPtr& theEntity, std::set& theParamList) +{ + 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(); + for (; aSIt != aSubs.end(); ++aSIt) + getParametersToMove(*aSIt, theParamList); +} + +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 = anIt - theFrom.begin(); + theFrom.erase(anIt); + anIt = theFrom.begin() + aShift; + } +} + + +void PlaneGCSSolver_Storage::initializeSolver(SolverPtr theSolver) +{ + std::shared_ptr aSolver = + std::dynamic_pointer_cast(theSolver); + + // initialize constraints + std::map >::const_iterator + aCIt = myConstraintMap.begin(); + 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) + aSolver->addConstraint(*anIt); + } + } + // 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); + } + // removed waste constraints + std::list::const_iterator aRemIt = myRemovedConstraints.begin(); + for (; aRemIt != myRemovedConstraints.end(); ++aRemIt) + aSolver->removeConstraint(*aRemIt); + myRemovedConstraints.clear(); +//// // remove waste parameters +//// std::list::const_iterator aRemParIt = myRemovedParameters.begin(); +//// for (; aRemParIt != myRemovedParameters.end(); ++aRemParIt) +//// delete *aRemParIt; +//// myRemovedParameters.clear(); + // initialize unknowns + aSolver->setParameters(myParameters); +} + +void PlaneGCSSolver_Storage::refresh(bool theFixedOnly) const +{ + //blockEvents(true); + + 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 + if (anIt->first.get()) { + std::shared_ptr aSketchFeature = + std::dynamic_pointer_cast(anIt->first->owner()); + if (aSketchFeature.get() && aSketchFeature->isExternal()) + continue; + } + + // 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 || (*aParIt)->group() == GID_OUTOFGROUP || (*aParIt)->isParametric()) { + aCoords[i] = (*aParIt)->value(); + isUpd[i] = true; + } + } + if (!isUpd[0] && !isUpd[1] && !isUpd[2]) + continue; // nothing is updated + + std::shared_ptr aPoint2D = + std::dynamic_pointer_cast(anIt->first); + if (aPoint2D) { + if ((isUpd[0] && fabs(aPoint2D->x() - aCoords[0]) > tolerance) || + (isUpd[1] && fabs(aPoint2D->y() - aCoords[1]) > tolerance)) { + if (!isUpd[0]) aCoords[0] = aPoint2D->x(); + if (!isUpd[1]) aCoords[1] = aPoint2D->y(); + aPoint2D->setValue(aCoords[0], aCoords[1]); + // Find points coincident with this one (probably not in GID_OUTOFGROUP) + std::map::const_iterator aLocIt = + theFixedOnly ? myAttributeMap.begin() : anIt; + for (++aLocIt; aLocIt != myAttributeMap.end(); ++aLocIt) + if (anIt->second->id() == aLocIt->second->id()) { + aPoint2D = std::dynamic_pointer_cast(aLocIt->first); + if (aPoint2D) + aPoint2D->setValue(aCoords[0], aCoords[1]); + } + } + continue; + } + AttributeDoublePtr aScalar = std::dynamic_pointer_cast(anIt->first); + if (aScalar) { + if (isUpd[0] && fabs(aScalar->value() - aCoords[0]) > tolerance) + aScalar->setValue(aCoords[0]); + 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; +} + +////bool PlaneGCSSolver_Storage::isInteract(AttributePtr theAttribute) const +////{ +//// std::map::const_iterator aFound = myAttributeEntityMap.find(theAttribute); +//// if (aFound != myAttributeEntityMap.end()) +//// return true; +//// +//// AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(theAttribute); +//// if (!aRefAttr) +//// return false; +//// if (aRefAttr->isObject()) { +//// FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object()); +//// if (!aFeature) +//// return false; +//// return isInteract(aFeature); +//// } +//// +//// return isInteract(aRefAttr->attr()); +////} +//// +////bool PlaneGCSSolver_Storage::isInteract(FeaturePtr theFeature) const +////{ +//// if (myFeatureEntityMap.find(theFeature) != myFeatureEntityMap.end()) +//// return true; +//// std::list anAttributes = theFeature->data()->attributes(std::string()); +//// std::list::iterator anIt = anAttributes.begin(); +//// for (; anIt != anAttributes.end(); ++anIt) +//// if (isInteract(*anIt)) +//// return true; +//// return false; +////} + + +////bool PlaneGCSSolver_Storage::isUsed(const FeaturePtr& theFeature) const +////{ +//// // There is checked only the feature itself, not its attributes. +//// // The attributes should be checked separately. +//// +//// std::map >::const_iterator +//// aCIt = myConstraintsMap.begin(); +//// for (; aCIt != myConstraintsMap.end(); ++aCIt) { +//// if (!aCIt->first) +//// continue; +//// for (int ind = 0; ind < CONSTRAINT_ATTR_SIZE; ++ind) { +//// AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( +//// aCIt->first->attribute(SketchPlugin_Constraint::ATTRIBUTE(ind))); +//// if (aRefAttr && aRefAttr->isObject()) { +//// FeaturePtr aFeat = ModelAPI_Feature::feature(aRefAttr->object()); +//// if (aFeat == theFeature) +//// return true; +//// } +//// } +//// } +//// return false; +////} +//// +////bool PlaneGCSSolver_Storage::isUsed(const AttributePtr& theAttribute) const +////{ +//// // Check whether the attribute is used by constraints +//// std::map >::const_iterator +//// aCIt = myConstraintsMap.begin(); +//// for (; aCIt != myConstraintsMap.end(); ++aCIt) { +//// if (!aCIt->first) +//// continue; +//// if (aCIt->first->attribute(SketchPlugin_Constraint::VALUE()) == theAttribute) +//// return true; +//// for (int ind = 0; ind < CONSTRAINT_ATTR_SIZE; ++ind) { +//// AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast( +//// aCIt->first->attribute(SketchPlugin_Constraint::ATTRIBUTE(ind))); +//// if (!aRefAttr) +//// continue; +//// if (aRefAttr == theAttribute || +//// (!aRefAttr->isObject() && aRefAttr->attr() == theAttribute)) +//// return true; +//// } +//// } +//// +//// // Check whether the attribute is used by features +//// std::map::const_iterator aFIt = myFeatureEntityMap.begin(); +//// for (; aFIt != myFeatureEntityMap.end(); ++aFIt) { +//// std::list anAttrs = +//// aFIt->first->data()->attributes(GeomDataAPI_Point2D::typeId()); +//// std::list::const_iterator anIt = anAttrs.begin(); +//// for (; anIt != anAttrs.end(); ++anIt) +//// if (*anIt == theAttribute) +//// return true; +//// } +//// +//// return false; +////} + + +////void PlaneGCSSolver_Storage::blockEvents(bool isBlocked) +////{ +//// std::map::iterator aFIt = myFeatureEntityMap.begin(); +//// for (; aFIt != myFeatureEntityMap.end(); ++aFIt) +//// if (aFIt->first->data() && aFIt->first->data()->isValid()) +//// aFIt->first->data()->blockSendAttributeUpdated(isBlocked); +//// +//// std::map::iterator anAIt = myAttributeEntityMap.begin(); +//// for (; anAIt != myAttributeEntityMap.end(); ++anAIt) +//// if (anAIt->first->owner() && anAIt->first->owner()->data() && +//// anAIt->first->owner()->data()->isValid()) +//// anAIt->first->owner()->data()->blockSendAttributeUpdated(isBlocked); +////} + + +#else + +#endif diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h new file mode 100644 index 000000000..1ddc40100 --- /dev/null +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.h @@ -0,0 +1,460 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: PlaneGCSSolver_Storage.h +// Created: 14 Dec 2015 +// Author: Artem ZHIDKOV + +#ifndef PlaneGCSSolver_Storage_H_ +#define PlaneGCSSolver_Storage_H_ + +#include + +#include +#include +#include + +////#include +////#include +////#include +////#include +////#include +//// +////#include +////#include +//// +////#include +////#include +////#include +////#include + +////#ifndef OBSOLETE +////#include +//// +////typedef std::shared_ptr GCSPointPtr; +////typedef std::shared_ptr GCSCurvePtr; +////typedef GCS::Constraint* GCSConstraintPtr; +////#endif + +/** \class PlaneGCSSolver_Storage + * \ingroup Plugins + * \brief Contains all necessary data in PlaneGCS format to solve a single group of constraints + */ +class PlaneGCSSolver_Storage : public SketchSolver_Storage +{ +public: + PlaneGCSSolver_Storage(const GroupID& theGroup); + +// ============= 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; + + /// \brief Check if some parameters or entities are returned + /// to the current group after removing temporary constraints + virtual void verifyFixed(); + + /// \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 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 Initialize solver by constraints, entities and parameters + virtual void initializeSolver(SolverPtr theSolver); + +protected: + /// \brief Remove constraint + /// \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); + + /// \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); + + +// ============= Own methods ============= + + + +#ifndef OBSOLETE + +//// /** \brief Add or change constraint and corresponding GCS constraints to the storage +//// * \param theConstraint [in] base SketchPlugin constraint +//// * \param theGCSConstraints [in] list of GCS constraints created by SketchSolver constraint +//// */ +//// void changeConstraint(const ConstraintPtr& theConstraint, +//// const std::vector& theGCSConstraints); + +//// /** \brief Add GCS constraint not related to any SketchPlugin constraint. +//// * For example, it may be related to the moved feature. +//// * \param theConstraint [in] GCS constraint +//// */ +//// void addConstraint(GCSConstraintPtr theConstraint); + +//// /** \brief Convert SketchPlugin_Feature to the corresponding entity in FreeGCS +//// * \param theEntity [in] feature to convert +//// * \return ID of created or updated entity +//// */ +//// EntityID changeEntity(const FeaturePtr& theEntity); +//// /** \brief Convert ModelAPI_Attribute to the corresponding entity in FreeGCS +//// * \param theEntity [in] attribute to convert +//// * \return ID of created or updated entity +//// */ +//// EntityID changeEntity(const AttributePtr& theEntity); + +//// /** \brief Remove constraint and corresponding GCS constraints +//// * \param theConstraint [in] constraint to remove +//// * \return \c true, if the constraint is fully removed, +//// * \c false, if there are available entities used by other constraints +//// */ +//// bool removeConstraint(const ConstraintPtr& theConstraint); +//// /** \brief Remove GCS constraint +//// * \param theConstraint [in] constraint to remove +//// * \return \c true, if the constraint is fully removed +//// */ +//// bool removeConstraint(GCSConstraintPtr theConstraint); +//// /** \brief Remove feature and corresponding GCS entities +//// * \param theFeature [in] feature to remove +//// * \return \c true, if the feature is fully removed, +//// * \c false, if there are available entities used by other constraints or features +//// */ +//// bool removeEntity(const FeaturePtr& theFeature); +//// /** \brief Remove attribute and corresponding GCS entities +//// * \param theAttribute [in] attribute to remove +//// * \return \c true, if the attribute is removed, +//// * \c false, if it is used by existent features or constraints +//// */ +//// bool removeEntity(const AttributePtr& theAttribute); + + /// \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 Return scalar by its ID or null pointer +//// double* getScalar(const EntityID& theID) const; +//// /// \brief Return point by its ID or null pointer +//// GCS::Point* getPoint(const EntityID& theID) const; +//// /// \brief Return line by its ID or null pointer +//// GCS::Line* getLine(const EntityID& theID) const; +//// /// \brief Return circle by its ID or null pointer +//// GCS::Circle* getCircle(const EntityID& theID) const; +//// /// \brief Return arc by its ID or null pointer +//// GCS::Arc* getArc(const EntityID& theID) const; +//// +//// /// \brief Return list of GCS constraints corresponding to the given +//// const std::vector& getConstraint(const ConstraintPtr& theConstraint) const; + +//// /// \brief Verifies, the attribute is available in current storage +//// bool isInteract(AttributePtr theAttribute) const; +//// /// \brief Verifies, the feature is available in current storage +//// bool isInteract(FeaturePtr theFeature) const; + +private: +//// /** \brief Creates scalar parameter in the list of parameters +//// * \param theScalar [in] value to be converted +//// * \return pointer to new scalar +//// */ +//// double* createScalar(const AttributeDoublePtr& theScalar = AttributeDoublePtr()); +//// /** \brief Creates two parameters in the list of parameters to store point coordinates +//// * \param thePoint [in] point to be converted +//// * \return FreeGCS point +//// */ +//// GCS::Point createPoint(const std::shared_ptr& thePoint); +//// /** \brief Creates or updates a scalar value +//// * \param theScalar [in] attribute to update scalar value +//// * \param theID [in] ID of scalar to be updated +//// */ +//// void updateScalar(const AttributeDoublePtr& theScalar, EntityID& theID); +//// /** \brief Creates or updates an angular value +//// * \param theAngle [in] attribute to update scalar value +//// * \param theID [in] ID of scalar to be updated +//// */ +//// void updateAngle(const AttributeDoublePtr& theAngle, EntityID& theID); +//// /** \brief Creates or updates parameters of the point +//// * \param thePoint [in] point used to update parameters +//// * \param theID [in] ID of FreeGCS entity to be updated +//// */ +//// void updatePoint(const std::shared_ptr& thePoint, +//// EntityID& theID); +//// /** \brief Creates or updates parameters of the line +//// * \param theLine [in] line used to update parameters +//// * \param theID [in/out] ID of FreeGCS entity to be updated (cleared if problems) +//// */ +//// void updateLine(const FeaturePtr& theLine, EntityID& theID); +//// /** \brief Creates or updates parameters of the circle +//// * \param theLine [in] circle used to update parameters +//// * \param theID [in/out] ID of FreeGCS entity to be updated (cleared if problems) +//// */ +//// void updateCircle(const FeaturePtr& theCircle, EntityID& theID); +//// /** \brief Creates or updates parameters of the arc +//// * \param theLine [in] arc used to update parameters +//// * \param theID [in/out] ID of FreeGCS entity to be updated (cleared if problems) +//// */ +//// void updateArc(const FeaturePtr& theArc, EntityID& theID); + +//// /// \brief Check the feature is used by constraints +//// bool isUsed(const FeaturePtr& theFeature) const; +//// /// \brief Check the attribute is used by constraints or features +//// bool isUsed(const AttributePtr& theAttribute) const; + +//// /// \brief Remove given parameter from the lists of parameters and constants +//// void removeParameters(double* theParam1, double* theParam2 = 0); + + /// \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); + +private: + GCS::VEC_pD myParameters; ///< list of parameters + GCS::VEC_pD myConst; ///< list of constants + EntityID myEntityLastID; ///< identifier of last added entity + +//// std::map > +//// myConstraintsMap; ///< map SketchPlugin constraints to corresponding GCS constraints +//// +//// std::map myAttributeEntityMap; ///< map attributes to corresponding entities +//// std::map myFeatureEntityMap; ///< map features to corresponding entities +//// +//// std::map myGCSScalars; ///< list of scalar values and their IDs +//// std::map myGCSPoints; ///< list of points and their IDs +//// std::map myGCSEntities; ///< list of lines, circles and arcs and their IDs + + std::map > + myArcConstraintMap; ///< additional constraints for correct processing of the arcs + +//// std::list myRemovedParameters; ///< list of removed parameters + std::list myRemovedConstraints; ///< list of removed constraints to notify solver + +#else + +// ================================================================================================ +// =================== OBSOLETE =========================================================== +public: + PlaneGCSSolver_Storage(); + + /** \brief Add new parameter to the current group + * \param[in] theParam SolveSpace parameter + * \return the ID of added parameter + */ + Slvs_hParam addParameter(const Slvs_Param& theParam); + /** \brief Updates parameter in the current group. If the ID of parameter is zero, the new item will be added + * \param[in] theParam SolveSpace parameter + * \return the ID of updated/added parameter + */ + Slvs_hParam updateParameter(const Slvs_Param& theParam); + /** \brief Removes the parameter by its ID + * \param[in] theParamID index of parameter to be removed + * \return \c true if the parameter was successfully removed + */ + bool removeParameter(const Slvs_hParam& theParamID); + /// \brief Returns the parameter by its ID + const Slvs_Param& getParameter(const Slvs_hParam& theParamID) const; + + /** \brief Add new entity to the current group + * \param[in] theEntity SolveSpace entity + * \return the ID of added entity + */ + Slvs_hEntity addEntity(const Slvs_Entity& theEntity); + /** \brief Updates entity in the current group. If the ID of entity is zero, the new item will be added + * \param[in] theEntity SolveSpace entity + * \return the ID of updated/added entity + */ + Slvs_hEntity updateEntity(const Slvs_Entity& theEntity); + /** \brief Removes the entity by its ID. All parameters used in this entity, + * and not used in other constraints, will be removed too. + * \param[in] theEntityID index of entity to be removed + * \return \c true if the entity was successfully removed + */ + bool removeEntity(const Slvs_hEntity& theEntityID); + /** \brief Remove all entities, which are not used in constraints + */ + void removeUnusedEntities(); + /// \brief Returns the entity by its ID + const Slvs_Entity& getEntity(const Slvs_hEntity& theEntityID) const; + /// \brief Makes a full copy of the given entity + Slvs_hEntity copyEntity(const Slvs_hEntity& theCopied); + /// \brief Copy one entity to another + void copyEntity(const Slvs_hEntity& theFrom, const Slvs_hEntity& theTo); + /// \brief Check the entity is used in constraints + bool isUsedByConstraints(const Slvs_hEntity& theEntityID) const; + + /// \brief Verifies the current point or another coincident one is fixed + /// \param[in] thePointID entity to be checked fixed + /// \param[out] theFixed ID of constraint + /// \param[in] theAccurate if \c true, the calculation will be made for all type of constraints, + /// if \c false, only the point is verified + /// \return \c true if the point is fixed + bool isPointFixed(const Slvs_hEntity& thePointID, Slvs_hConstraint& theFixed, bool theAccurate = false) const; + /// \brief Verifies the current entity is fully fixed (may not be changed by constraints) + /// \param[in] theEntityID entity to be checked fixed + /// \param[in] theAccurate if \c true, the calculation will be made for all type of constraints, + /// if \c false, only points are verified + /// \return \c true if the entity is fixed + bool isEntityFixed(const Slvs_hEntity& theEntityID, bool theAccurate = false) const; + + /** \brief Add new constraint to the current group + * \param[in] theConstraint SolveSpace's constraint + * \return the ID of added constraint + */ + Slvs_hConstraint addConstraint(const Slvs_Constraint& theConstraint); + /** \brief Updates constraint in the current group. + * If the ID of constraint is zero, the new item will be added + * \param[in] theConstraint SolveSpace constraint + * \return the ID of updated/added constraint + */ + Slvs_hConstraint updateConstraint(const Slvs_Constraint& theConstraint); + /** \brief Removes the constraint by its ID. All entities and parameters depending on this + * constraint, which are not used in other constraints, will be removed too. + * \param[in] theConstraintID index of constraint to be removed + * \return \c true if the constraint was successfully removed + */ + bool removeConstraint(const Slvs_hConstraint& theConstraintID); + /// \brief Returns the constraint by its ID + const Slvs_Constraint& getConstraint(const Slvs_hConstraint& theConstraintID) const; + /// \brief Returns list of constraints of specified type + std::list getConstraintsByType(int theConstraintType) const; + + /// \brief Attach constraint SLVS_C_WHERE_DRAGGED to this storage. It need to make precise calculations + void addConstraintWhereDragged(const Slvs_hConstraint& theConstraintID); + + /// \brief Add transient constraint + void addTemporaryConstraint(const Slvs_hConstraint& theConstraintID); + /// \brief Remove all transient constraints + void removeTemporaryConstraints(); + /// \brief Remove one temporary constraint. Preferable to remove the points under Point-on-Line constraint + /// \return Number of remaining temporary constraints + int deleteTemporaryConstraint(); + /// \brief Checks the constraint is temporary + bool isTemporary(const Slvs_hConstraint& theConstraintID) const; + /// \brief Number of temporary constraints + int numberTemporary() const + { return (int)myTemporaryConstraints.size(); } + + /// \brief Shows the sketch should be resolved + bool isNeedToResolve(); + + /// \brief Shows the storage has the same constraint twice + bool hasDuplicatedConstraint() const + { return myDuplicatedConstraint; } + + /// \brief Changes the flag of group to be resolved + void setNeedToResolve(bool theFlag) + { myNeedToResolve = theFlag; } + + /// \brief Returns lists of removed elements + void getRemoved(std::set& theParameters, + std::set& theEntities, + std::set& theConstraints); + + /// \brief Initialize constraint solver by the entities collected by current storage + void initializeSolver(SketchSolver_Solver& theSolver); + +private: + /// \brief Store coincident points + void addCoincidentPoints(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2); + /// \brief Remove point from lists of coincidence + void removeCoincidentPoint(const Slvs_hEntity& thePoint); + /// \brief Remove point-point coincidence + void removeCoincidence(const Slvs_Constraint& theCoincidence); + +public: + /// \brief Check two points are coincident + bool isCoincident(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const; + + /// \brief Check two points are coincident or have same coordinates + bool isEqual(const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const; + + /// \brief Check the entity is horizontal of vertical + bool isAxisParallel(const Slvs_hEntity& theEntity) const; + + /// \brief Verifies the entity is used in any equal constraint + /// \param[in] theEntity entity to be found + /// \param[out] theEqual constraint, which uses the entity + /// \return \c true, if the Equal constrait is found + bool isUsedInEqual(const Slvs_hEntity& theEntity, Slvs_Constraint& theEqual) const; + + /// \brief Fixes specified entity + /// \param theEntity ID of the entity to be fixed + /// \return List of created constraints + std::vector fixEntity(const Slvs_hEntity& theEntity); + +private: + /// \brief Fixes specified point + /// \param [in] thePoint point to be fixed + /// \param [out] theCreated list of the Fixed constraints created + void fixPoint(const Slvs_Entity& thePoint, std::vector& theCreated); + /// \brief Fixes specified line + /// \param [in] theLine line to be fixed + /// \param [out] theCreated list of the Fixed constraints created + void fixLine(const Slvs_Entity& theLine, std::vector& theCreated); + /// \brief Fixes specified circle + /// \param [in] theCircle circle to be fixed + /// \param [out] theCreated list of the Fixed constraints created + void fixCircle(const Slvs_Entity& theCircle, std::vector& theCreated); + /// \brief Fixes specified arc + /// \param [in] theArc arc to be fixed + /// \param [out] theCreated list of the Fixed constraints created + void fixArc(const Slvs_Entity& theArc, std::vector& theCreated); + +private: + Slvs_hParam myParamMaxID; ///< current parameter index (may differs with the number of parameters) + std::vector myParameters; ///< list of parameters used in the current group of constraints (sorted by the identifier) + Slvs_hEntity myEntityMaxID; ///< current entity index (may differs with the number of entities) + std::vector myEntities; ///< list of entities used in the current group of constraints (sorted by the identifier) + Slvs_hConstraint myConstrMaxID; ///< current constraint index (may differs with the number of constraints) + std::vector myConstraints; ///< list of constraints used in the current group (sorted by the identifier) + + std::vector< std::set > myCoincidentPoints; ///< lists of coincident points + Slvs_hConstraint myFixed; ///< identifier of one of temporary constraints to fix separate point + + bool myNeedToResolve; ///< parameters are changed and group needs to be resolved + bool myDuplicatedConstraint; ///< shows the storage has same constraint twice + + std::set myTemporaryConstraints; ///< list of transient constraints + std::set myRemovedParameters; ///< list of just removed parameters (cleared when returning to applicant) + std::set myRemovedEntities; ///< list of just removed entities (cleared when returning to applicant) + std::set myRemovedConstraints; ///< list of just removed constraints (cleared when returning to applicant) + std::set myUpdatedParameters; ///< list of just updated parameters (cleared when isNeedToResolve() called) +#endif +}; + +#endif diff --git a/src/SketchSolver/SketchSolver.h b/src/SketchSolver/SketchSolver.h index 56fa1dba2..8beb83a98 100644 --- a/src/SketchSolver/SketchSolver.h +++ b/src/SketchSolver/SketchSolver.h @@ -36,6 +36,7 @@ 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; #endif diff --git a/src/SketchSolver/SketchSolver_IEntityWrapper.h b/src/SketchSolver/SketchSolver_IEntityWrapper.h index 49f4d796e..15735e733 100644 --- a/src/SketchSolver/SketchSolver_IEntityWrapper.h +++ b/src/SketchSolver/SketchSolver_IEntityWrapper.h @@ -20,6 +20,7 @@ enum SketchSolver_EntityType { ENTITY_UNKNOWN = 0, ENTITY_SCALAR, + ENTITY_ANGLE, ENTITY_POINT, ENTITY_NORMAL, ENTITY_LINE, diff --git a/src/SketchSolver/SketchSolver_Storage.h b/src/SketchSolver/SketchSolver_Storage.h index 772846c82..c5346906e 100644 --- a/src/SketchSolver/SketchSolver_Storage.h +++ b/src/SketchSolver/SketchSolver_Storage.h @@ -50,7 +50,7 @@ public: /// the list of constraints applicable for corresponding solver. /// \param theConstraint [in] original SketchPlugin constraint /// \param theSolverConstraints [in] list of solver's constraints - SKETCHSOLVER_EXPORT + SKETCHSOLVER_EXPORT virtual void addConstraint(ConstraintPtr theConstraint, std::list theSolverConstraints); @@ -192,15 +192,15 @@ protected: /// \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; + private: /// \brief Find the normal of the sketch EntityWrapperPtr getNormal() const; - /// \brief Verify the feature or any its attribute is used by constraint - bool isUsed(FeaturePtr theFeature) const; - /// \brief Verify the attribute is used by constraint - bool isUsed(AttributePtr theAttirubute) const; - protected: GroupID myGroupID; ///< identifier of the group, this storage belongs to bool myNeedToResolve; ///< parameters are changed and group needs to be resolved