<plugin script="addons_Features" configuration="addons_Features.xml"/>
<plugin script="ConnectorPlugin" configuration="plugin-Connector.xml" dependency="Geometry"/>
<plugin library="ParametersPlugin" configuration="plugin-Parameters.xml"/>
- <plugin library="SketchSolver"/>
+ <plugin library="SolveSpaceSolver"/>
<plugin library="GeomValidators"/>
<plugin library="DFBrowser" internal="true"/>
</plugins>
assert (kLineCStart == (aLineCStartPoint.x(), aLineCStartPoint.y()))
assert (kLineCEnd == (aLineCEndPoint.x(), aLineCEndPoint.y()))
#=========================================================================
-# Check that
+# Check that moving line A does not affect lines
+#=========================================================================
+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()))
+#=========================================================================
+# Check that moving line B does not affect lines
#=========================================================================
aSession.startOperation()
aLineBEndPoint.setValue(90., 150.)
## Copyright (C) 2014-20xx CEA/DEN, EDF R&D
INCLUDE(Common)
-FIND_PACKAGE(SolveSpace REQUIRED)
SET(PROJECT_HEADERS
SketchSolver.h
SketchSolver_Error.h
- SketchSolver_Solver.h
SketchSolver_Constraint.h
SketchSolver_ConstraintAngle.h
SketchSolver_ConstraintCoincidence.h
SketchSolver_ConstraintDistance.h
SketchSolver_ConstraintEqual.h
- SketchSolver_ConstraintFillet.h
SketchSolver_ConstraintLength.h
SketchSolver_ConstraintMirror.h
- SketchSolver_ConstraintRigid.h
+ SketchSolver_ConstraintFixed.h
SketchSolver_ConstraintTangent.h
SketchSolver_ConstraintMulti.h
SketchSolver_ConstraintMultiRotation.h
SketchSolver_ConstraintMultiTranslation.h
SketchSolver_ConstraintMovement.h
- SketchSolver_ConstraintParametric.h
- SketchSolver_Builder.h
SketchSolver_Group.h
- SketchSolver_ConstraintManager.h
+ SketchSolver_Builder.h
+ SketchSolver_IConstraintWrapper.h
+ SketchSolver_IEntityWrapper.h
+ SketchSolver_IParameterWrapper.h
+ SketchSolver_ISolver.h
+ SketchSolver_Manager.h
SketchSolver_Storage.h
- SketchSolver_FeatureStorage.h
)
SET(PROJECT_SOURCES
- SketchSolver_Solver.cpp
SketchSolver_Constraint.cpp
SketchSolver_ConstraintAngle.cpp
SketchSolver_ConstraintCoincidence.cpp
SketchSolver_ConstraintDistance.cpp
SketchSolver_ConstraintEqual.cpp
- SketchSolver_ConstraintFillet.cpp
SketchSolver_ConstraintLength.cpp
SketchSolver_ConstraintMirror.cpp
- SketchSolver_ConstraintRigid.cpp
+ SketchSolver_ConstraintFixed.cpp
SketchSolver_ConstraintTangent.cpp
SketchSolver_ConstraintMulti.cpp
SketchSolver_ConstraintMultiRotation.cpp
SketchSolver_ConstraintMultiTranslation.cpp
- SketchSolver_ConstraintParametric.cpp
SketchSolver_ConstraintMovement.cpp
- SketchSolver_Builder.cpp
SketchSolver_Group.cpp
- SketchSolver_ConstraintManager.cpp
+ SketchSolver_Builder.cpp
+ SketchSolver_Manager.cpp
SketchSolver_Storage.cpp
- SketchSolver_FeatureStorage.cpp
)
SET(PROJECT_LIBRARIES
- ${SOLVESPACE_LIBRARIES}
Config
Events
ModelAPI
)
INCLUDE_DIRECTORIES(
- ${SOLVESPACE_INCLUDE_DIRS}
${PROJECT_SOURCE_DIR}/src/Config
${PROJECT_SOURCE_DIR}/src/SketchPlugin
${PROJECT_SOURCE_DIR}/src/ModelAPI
ADD_DEFINITIONS(-DSKETCHSOLVER_EXPORTS)
-ADD_LIBRARY(SketchSolver MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS}
+ADD_LIBRARY(SketchSolver SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS}
)
TARGET_LINK_LIBRARIES(SketchSolver ${PROJECT_LIBRARIES}
)
INSTALL(TARGETS SketchSolver DESTINATION plugins)
+
+
+# Include specific solvers
+FIND_FILE(SSPath "SolveSpaceSolver/CMakeLists.txt" PATHS "${CMAKE_CURRENT_SOURCE_DIR}")
+STRING(COMPARE NOTEQUAL ${SSPath} "SSPath-NOTFOUND" SSPath_FOUND)
+FIND_FILE(GCSPath "PlainGCSSolver/CMakeLists.txt" PATHS "${CMAKE_CURRENT_SOURCE_DIR}")
+STRING(COMPARE NOTEQUAL ${GCSPath} "GCSPath-NOTFOUND" GCSPath_FOUND)
+
+IF(${SSPath_FOUND} OR ${GCSPath_FOUND})
+ IF(${SSPath_FOUND})
+ MESSAGE(STATUS "SolveSpaceSolver plugin found in ${SSPath}")
+ ADD_SUBDIRECTORY(SolveSpaceSolver)
+ ENDIF()
+ IF(${GCSPath_FOUND})
+ MESSAGE(STATUS "PlainGCSSolver plugin found in ${GCSPath}")
+ ADD_SUBDIRECTORY(PlainGCSSolver)
+ ENDIF()
+ELSE()
+ MESSAGE(WARNING "No sketch solver plugin is found")
+ENDIF()
#ifndef SKETCHSOLVER_H
#define SKETCHSOLVER_H
+#include <stdlib.h>
+
#if defined SKETCHSOLVER_EXPORTS
#if defined WIN32
#define SKETCHSOLVER_EXPORT __declspec( dllexport )
#define PI 3.1415926535897932
+// Types for data entities enumeration
+typedef size_t GroupID;
+typedef size_t ParameterID;
+typedef size_t EntityID;
+typedef size_t ConstraintID;
+
+// Predefined values for identifiers
+const GroupID GID_UNKNOWN = 0;
+const GroupID GID_OUTOFGROUP = 1;
+
+const ParameterID PID_UNKNOWN = 0;
+const EntityID EID_UNKNOWN = 0;
+const ConstraintID CID_UNKNOWN = 0;
+
#endif
// Author: Artem ZHIDKOV
#include "SketchSolver_Builder.h"
-#include <SketchPlugin_ConstraintAngle.h>
+#include <SketchSolver_Constraint.h>
#include <SketchSolver_ConstraintAngle.h>
#include <SketchSolver_ConstraintCoincidence.h>
#include <SketchSolver_ConstraintDistance.h>
#include <SketchSolver_ConstraintEqual.h>
-#include <SketchSolver_ConstraintFillet.h>
+#include <SketchSolver_ConstraintFixed.h>
#include <SketchSolver_ConstraintLength.h>
#include <SketchSolver_ConstraintMirror.h>
-#include <SketchSolver_ConstraintRigid.h>
#include <SketchSolver_ConstraintTangent.h>
#include <SketchSolver_ConstraintMultiRotation.h>
#include <SketchSolver_ConstraintMultiTranslation.h>
#include <SketchSolver_ConstraintMovement.h>
-#include <SketchSolver_ConstraintParametric.h>
-#include <SketchSolver_Error.h>
-#include <GeomAPI_Edge.h>
-#include <GeomDataAPI_Dir.h>
-#include <GeomDataAPI_Point.h>
-#include <GeomDataAPI_Point2D.h>
+#ifdef _DEBUG
#include <Events_Error.h>
-#include <ModelAPI_Attribute.h>
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeRefAttr.h>
#include <ModelAPI_AttributeRefList.h>
#include <ModelAPI_ResultConstruction.h>
+#include <SketchSolver_Error.h>
+#endif
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_Circle.h>
-#include <SketchPlugin_Line.h>
-#include <SketchPlugin_Point.h>
+#include <SketchPlugin_ConstraintAngle.h>
#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_ConstraintDistance.h>
#include <SketchPlugin_ConstraintEqual.h>
-#include <SketchPlugin_ConstraintFillet.h>
-#include <SketchPlugin_ConstraintHorizontal.h>
#include <SketchPlugin_ConstraintLength.h>
#include <SketchPlugin_ConstraintMirror.h>
-#include <SketchPlugin_ConstraintParallel.h>
-#include <SketchPlugin_ConstraintPerpendicular.h>
-#include <SketchPlugin_ConstraintRadius.h>
#include <SketchPlugin_ConstraintRigid.h>
#include <SketchPlugin_ConstraintTangent.h>
-#include <SketchPlugin_ConstraintVertical.h>
#include <SketchPlugin_MultiRotation.h>
#include <SketchPlugin_MultiTranslation.h>
#include <math.h>
-// Initialization of constraint builder self pointer
-SketchSolver_Builder* SketchSolver_Builder::mySelf = 0;
-
-SketchSolver_Builder* SketchSolver_Builder::getInstance()
-{
- if (!mySelf)
- mySelf = new SketchSolver_Builder();
- return mySelf;
-}
-
-SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theConstraint)
+SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theConstraint) const
{
SolverConstraintPtr aResult;
DataPtr aData = theConstraint->data();
return SolverConstraintPtr(new SketchSolver_ConstraintDistance(theConstraint));
} else if (theConstraint->getKind() == SketchPlugin_ConstraintEqual::ID()) {
return SolverConstraintPtr(new SketchSolver_ConstraintEqual(theConstraint));
- } else if (theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) {
- return SolverConstraintPtr(new SketchSolver_ConstraintFillet(theConstraint));
- } else if (theConstraint->getKind() == SketchPlugin_ConstraintHorizontal::ID()) {
- return SolverConstraintPtr(new SketchSolver_ConstraintHorizontal(theConstraint));
} else if (theConstraint->getKind() == SketchPlugin_ConstraintLength::ID()) {
return SolverConstraintPtr(new SketchSolver_ConstraintLength(theConstraint));
} else if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) {
return SolverConstraintPtr(new SketchSolver_ConstraintMirror(theConstraint));
- } else if (theConstraint->getKind() == SketchPlugin_ConstraintParallel::ID()) {
- return SolverConstraintPtr(new SketchSolver_ConstraintParallel(theConstraint));
- } else if (theConstraint->getKind() == SketchPlugin_ConstraintPerpendicular::ID()) {
- return SolverConstraintPtr(new SketchSolver_ConstraintPerpendicular(theConstraint));
- } else if (theConstraint->getKind() == SketchPlugin_ConstraintRadius::ID()) {
- return SolverConstraintPtr(new SketchSolver_ConstraintRadius(theConstraint));
} else if (theConstraint->getKind() == SketchPlugin_ConstraintTangent::ID()) {
return SolverConstraintPtr(new SketchSolver_ConstraintTangent(theConstraint));
- } else if (theConstraint->getKind() == SketchPlugin_ConstraintVertical::ID()) {
- return SolverConstraintPtr(new SketchSolver_ConstraintVertical(theConstraint));
} else if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID()) {
- return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theConstraint));
+ return SolverConstraintPtr(new SketchSolver_ConstraintFixed(theConstraint));
} else if (theConstraint->getKind() == SketchPlugin_MultiTranslation::ID()) {
return SolverConstraintPtr(new SketchSolver_ConstraintMultiTranslation(theConstraint));
} else if (theConstraint->getKind() == SketchPlugin_MultiRotation::ID()) {
} else if (theConstraint->getKind() == SketchPlugin_ConstraintAngle::ID()) {
return SolverConstraintPtr(new SketchSolver_ConstraintAngle(theConstraint));
}
- return aResult;
+ // All other types of constraints
+ return SolverConstraintPtr(new SketchSolver_Constraint(theConstraint));
}
-SolverConstraintPtr SketchSolver_Builder::createRigidConstraint(FeaturePtr theFixedFeature)
+SolverConstraintPtr SketchSolver_Builder::createFixedConstraint(FeaturePtr theFixedFeature) const
{
DataPtr aData = theFixedFeature->data();
if (!aData || !aData->isValid())
return SolverConstraintPtr();
- return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theFixedFeature));
+ return SolverConstraintPtr(new SketchSolver_ConstraintFixed(theFixedFeature));
}
-SolverConstraintPtr SketchSolver_Builder::createMovementConstraint(FeaturePtr theFixedFeature)
+SolverConstraintPtr SketchSolver_Builder::createMovementConstraint(FeaturePtr theFixedFeature) const
{
DataPtr aData = theFixedFeature->data();
if (!aData || !aData->isValid())
return SolverConstraintPtr(new SketchSolver_ConstraintMovement(theFixedFeature));
}
-SolverConstraintPtr SketchSolver_Builder::createParametricConstraint(AttributePtr theAttribute)
+std::shared_ptr<GeomAPI_Pnt2d> SketchSolver_Builder::point(EntityWrapperPtr theEntity) const
{
- return SolverConstraintPtr(new SketchSolver_ConstraintParametric(theAttribute));
+ if (theEntity->type() != ENTITY_POINT)
+ return std::shared_ptr<GeomAPI_Pnt2d>();
+
+ double aXY[2];
+ std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
+ std::list<ParameterWrapperPtr>::const_iterator anIt = aParams.begin();
+ for (int i = 0; i < 2 && anIt != aParams.end(); ++i, ++anIt)
+ aXY[i] = (*anIt)->value();
+ if (anIt != aParams.end())
+ return std::shared_ptr<GeomAPI_Pnt2d>();
+
+ return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aXY[0], aXY[1]));
}
-
-
-bool SketchSolver_Builder::createWorkplane(
- CompositeFeaturePtr theSketch,
- std::vector<Slvs_Entity>& theEntities,
- std::vector<Slvs_Param>& theParameters)
+std::shared_ptr<GeomAPI_Lin2d> SketchSolver_Builder::line(EntityWrapperPtr theEntity) const
{
- DataPtr aSketchData = theSketch->data();
- if (!aSketchData || !aSketchData->isValid())
- return false; // the sketch is incorrect
-
- // Get parameters of workplane
- std::shared_ptr<ModelAPI_Attribute> aDirX = aSketchData->attribute(
- SketchPlugin_Sketch::DIRX_ID());
- std::shared_ptr<ModelAPI_Attribute> aNorm = aSketchData->attribute(
- SketchPlugin_Sketch::NORM_ID());
- std::shared_ptr<ModelAPI_Attribute> anOrigin = aSketchData->attribute(
- SketchPlugin_Sketch::ORIGIN_ID());
- // Create SolveSpace entity corresponding to the sketch origin
- if (!createEntity(anOrigin, theEntities, theParameters))
- return false;
- Slvs_hEntity anOriginID = theEntities.back().h;
- // Create SolveSpace entity corresponding the the sketch normal
- if (!createNormal(aNorm, aDirX, theEntities, theParameters))
- return false;
- Slvs_hEntity aNormalID = theEntities.back().h;
-
- // Create workplane
- Slvs_hEntity aWorkplaneID = theEntities.back().h + 1;
- Slvs_Entity aWorkplane = Slvs_MakeWorkplane(aWorkplaneID, SLVS_G_UNKNOWN, anOriginID, aNormalID);
- theEntities.push_back(aWorkplane);
- return true;
+ if (theEntity->type() != ENTITY_LINE)
+ return std::shared_ptr<GeomAPI_Lin2d>();
+
+ std::shared_ptr<GeomAPI_Pnt2d> aPoints[2];
+ std::list<EntityWrapperPtr> aSubs = theEntity->subEntities();
+ std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
+ for (int i = 0; i < 2 && anIt != aSubs.end(); ++i, ++anIt)
+ aPoints[i] = point(*anIt);
+ if (anIt != aSubs.end())
+ return std::shared_ptr<GeomAPI_Lin2d>();
+
+ return std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[0], aPoints[1]));
}
-bool SketchSolver_Builder::createEntity(
- AttributePtr theAttribute,
- std::vector<Slvs_Entity>& theEntities,
- std::vector<Slvs_Param>& theParameters)
-{
- Slvs_hEntity anEntID = theEntities.empty() ? 0 : theEntities.back().h;
- Slvs_hParam aParamID = theParameters.empty() ? 0 : theParameters.back().h;
-
- // Point in 3D
- std::shared_ptr<GeomDataAPI_Point> aPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
- if (aPoint) {
- theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->x()));
- theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->y()));
- theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint->z()));
- theEntities.push_back(Slvs_MakePoint3d(++anEntID, SLVS_G_UNKNOWN,
- aParamID-2, aParamID-1, aParamID));
- return true;
- }
- // Point in 2D
- std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
- if (aPoint2D) {
- theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint2D->x()));
- theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aPoint2D->y()));
- theEntities.push_back(Slvs_MakePoint2d(++anEntID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN,
- aParamID-1, aParamID));
- return true;
- }
- // Scalar value (used for the distance entities)
- AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
- if (aScalar) {
- theParameters.push_back(Slvs_MakeParam(++aParamID, SLVS_G_UNKNOWN, aScalar->value()));
- theEntities.push_back(Slvs_MakeDistance(++anEntID, SLVS_G_UNKNOWN,
- SLVS_E_UNKNOWN, aParamID));
- return true;
- }
- // unknown attribute type
- return false;
-}
-
-bool SketchSolver_Builder::createEntity(
- FeaturePtr theFeature,
- std::vector<Slvs_Entity>& theEntities,
- std::vector<Slvs_Param>& theParameters)
-{
- if (!theFeature->data()->isValid())
- return false;
-
- // SketchPlugin features
- std::shared_ptr<SketchPlugin_Feature> aFeature = std::dynamic_pointer_cast<
- SketchPlugin_Feature>(theFeature);
- if (!aFeature)
- return false;
-
- // Verify the feature by its kind
- const std::string& aFeatureKind = aFeature->getKind();
- DataPtr aData = aFeature->data();
- // Line
- if (aFeatureKind == SketchPlugin_Line::ID()) {
- AttributePtr aStart = aData->attribute(SketchPlugin_Line::START_ID());
- AttributePtr aEnd = aData->attribute(SketchPlugin_Line::END_ID());
- if (!aStart->isInitialized() || !aEnd->isInitialized())
- return false;
- if (!createEntity(aStart, theEntities, theParameters) ||
- !createEntity(aEnd, theEntities, theParameters))
- return false;
- Slvs_hEntity aLineID = theEntities.back().h + 1;
- theEntities.push_back(Slvs_MakeLineSegment(aLineID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN,
- aLineID-2, aLineID-1));
- }
- // Circle
- else if (aFeatureKind == SketchPlugin_Circle::ID()) {
- AttributePtr aCenter = aData->attribute(SketchPlugin_Circle::CENTER_ID());
- AttributePtr aRadius = aData->attribute(SketchPlugin_Circle::RADIUS_ID());
- if (!aCenter->isInitialized() || !aRadius->isInitialized())
- return false;
- if (!createEntity(aCenter, theEntities, theParameters) ||
- !createEntity(aRadius, theEntities, theParameters))
- return false;
- Slvs_hEntity aCircID = theEntities.back().h;
- theEntities.push_back(Slvs_MakeCircle(aCircID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN, aCircID-2,
- SLVS_E_UNKNOWN, aCircID-1));
- }
- // Arc
- else if (aFeatureKind == SketchPlugin_Arc::ID()) {
- AttributePtr aCenter = aData->attribute(SketchPlugin_Arc::CENTER_ID());
- AttributePtr aStart = aData->attribute(SketchPlugin_Arc::START_ID());
- AttributePtr aEnd = aData->attribute(SketchPlugin_Arc::END_ID());
- if (!aCenter->isInitialized() || !aStart->isInitialized() || !aEnd->isInitialized())
- return false;
- if (!createEntity(aCenter, theEntities, theParameters) ||
- !createEntity(aStart, theEntities, theParameters) ||
- !createEntity(aEnd, theEntities, theParameters))
- return false;
- Slvs_hEntity anArcID = theEntities.back().h;
- theEntities.push_back(Slvs_MakeArcOfCircle(anArcID, SLVS_G_UNKNOWN, SLVS_E_UNKNOWN,
- SLVS_E_UNKNOWN, anArcID-3, anArcID-2, anArcID-1));
- }
- // 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 = aData->attribute(SketchPlugin_Point::COORD_ID());
- if (!aPoint->isInitialized() ||
- !createEntity(aPoint, theEntities, theParameters))
- return false;
- // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier.
- // No need to add another entity.
- }
- return true;
-}
-
-bool SketchSolver_Builder::createNormal(
- AttributePtr theNormal,
- AttributePtr theDirX,
- std::vector<Slvs_Entity>& theEntities,
- std::vector<Slvs_Param>& theParameters)
-{
- std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormal);
- std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
- if (!aDirX || (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) ||
- !aNorm->isInitialized())
- return false;
- // calculate Y direction
- std::shared_ptr<GeomAPI_Dir> 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
- Slvs_hParam aCurParam = theParameters.back().h;
- for (int i = 0; i < 4; i++)
- theParameters.push_back(Slvs_MakeParam(++aCurParam, SLVS_G_UNKNOWN, aNormCoord[i]));
-
- // Create a normal
- Slvs_hEntity aCurEntity = theEntities.back().h + 1;
- Slvs_Entity aNormal = Slvs_MakeNormal3d(aCurEntity, SLVS_G_UNKNOWN,
- aCurParam-3, aCurParam-2, aCurParam-1, aCurParam);
- theEntities.push_back(aNormal);
- return true;
-}
#ifndef SketchSolver_Builder_H_
#define SketchSolver_Builder_H_
-#include "SketchSolver.h"
#include <SketchSolver_Constraint.h>
-
#include <SketchPlugin_Constraint.h>
-#include <ModelAPI_CompositeFeature.h>
+#include <GeomAPI_Lin2d.h>
+#include <GeomAPI_Pnt2d.h>
/** \class SketchSolver_Builder
* \ingroup Plugins
- * \brief Create bridges between SketchPlugin constraints and SolveSpace constraints
+ * \brief Abstract class for builders of solver's entities
*/
class SketchSolver_Builder
{
-private:
- /// Default constructor
- SketchSolver_Builder() {}
-
public:
- /// \brief Returns single instance of builder
- static SketchSolver_Builder* getInstance();
+ /// \brief Creates a storage specific for used solver
+ virtual StoragePtr createStorage(const GroupID& theGroup) const = 0;
+ /// \brief Creates specific solver
+ virtual SolverPtr createSolver() const = 0;
/// \brief Creates a solver's constraint using given SketchPlugin constraint
/// or returns empty pointer if not all attributes are correct
- SolverConstraintPtr createConstraint(ConstraintPtr theConstraint);
+ SolverConstraintPtr createConstraint(ConstraintPtr theConstraint) const;
/// \brief Creates temporary constraint to fix the placement of the feature
- SolverConstraintPtr createRigidConstraint(FeaturePtr theFixedFeature);
+ SolverConstraintPtr createFixedConstraint(FeaturePtr theFixedFeature) const;
/// \brief Creates temporary constraint to fix the feature after movement
- SolverConstraintPtr createMovementConstraint(FeaturePtr theFixedFeature);
-
- /// \brief Creates constraint for parametrically given attribute
- SolverConstraintPtr createParametricConstraint(AttributePtr theAttribute);
-
- /// \brief Converts sketch parameters to the list of SolveSpace entities.
- /// Identifiers of entities and parameters are local. They should be changed while adding into storage.
- /// The sketch entity goes last.
- /// \param[in] theSketch the element to be converted
- /// \param[out] theEntities created list of entities
- /// \param[out] theParameters created list of parameters of the entities
- /// \return \c true if workplane created
- bool createWorkplane(CompositeFeaturePtr theSketch,
- std::vector<Slvs_Entity>& theEntities,
- std::vector<Slvs_Param>& theParameters);
-
- /// \brief Converts attribute to the list of entities.
- /// Identifiers are local (see createWorkplane).
- /// The main entity goes last.
- bool createEntity(AttributePtr theAttribute,
- std::vector<Slvs_Entity>& theEntities,
- std::vector<Slvs_Param>& theParameters);
- /// \brief Converts feature to the list of entities.
- /// Identifiers are local (see createWorkplane).
- /// The main entity goes last.
- bool createEntity(FeaturePtr theFeature,
- std::vector<Slvs_Entity>& theEntities,
- std::vector<Slvs_Param>& theParameters);
-
- /// \brief Converts normal and OX direction to the list of entities representing a normal in SolveSpace.
- /// Identifiers are local (see createWorkplane).
- /// The main entity goes last.
- bool createNormal(AttributePtr theNormal,
- AttributePtr theDirX,
- std::vector<Slvs_Entity>& theEntities,
- std::vector<Slvs_Param>& theParameters);
-
-private:
- static SketchSolver_Builder* mySelf;
+ SolverConstraintPtr createMovementConstraint(FeaturePtr theFixedFeature) 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<ConstraintWrapperPtr>
+ createConstraint(ConstraintPtr theConstraint,
+ const GroupID& theGroup,
+ 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 = 0;
+
+ /// \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<ConstraintWrapperPtr>
+ createConstraint(ConstraintPtr theConstraint,
+ const GroupID& theGroup,
+ const EntityID& theSketchID,
+ const SketchSolver_ConstraintType& theType,
+ const double& theValue,
+ const EntityWrapperPtr& thePoint1,
+ const EntityWrapperPtr& thePoint2,
+ const std::list<EntityWrapperPtr>& theTrsfEnt) const = 0;
+
+ /// \brief Update flags for several kinds of constraints
+ virtual void adjustConstraint(ConstraintWrapperPtr theConstraint) const = 0;
+
+ /// \brief Creates a feature using list of already created attributes
+ /// \param theFeature [in] feature to create
+ /// \param theAttributes [in] attributes of the feature
+ /// \param theGroupID [in] group the feature belongs to
+ /// \param theSketchID [in] sketch the feature belongs to
+ /// \return Created wrapper of the feature applicable for specific solver
+ virtual EntityWrapperPtr createFeature(FeaturePtr theFeature,
+ const std::list<EntityWrapperPtr>& theAttributes,
+ const GroupID& theGroupID,
+ const EntityID& theSketchID = EID_UNKNOWN) const = 0;
+
+ /// \brief Creates an attribute
+ /// \param theAttribute [in] attribute to create
+ /// \param theGroup [in] group the attribute belongs to
+ /// \param theSketchID [in] sketch the attribute belongs to
+ /// \return Created wrapper of the attribute applicable for specific solver
+ virtual EntityWrapperPtr createAttribute(AttributePtr theAttribute,
+ const GroupID& theGroup,
+ const EntityID& theSketchID = EID_UNKNOWN) const = 0;
+
+
+ /// \brief Convert entity to point
+ /// \return empty pointer if the entity is not a point
+ SKETCHSOLVER_EXPORT std::shared_ptr<GeomAPI_Pnt2d> point(EntityWrapperPtr theEntity) const;
+ /// \brief Convert entity to line
+ /// \return empty pointer if the entity is not a line
+ SKETCHSOLVER_EXPORT std::shared_ptr<GeomAPI_Lin2d> line(EntityWrapperPtr theEntity) const;
};
+typedef std::shared_ptr<SketchSolver_Builder> BuilderPtr;
+
#endif
#include <SketchSolver_Constraint.h>
#include <SketchSolver_Group.h>
#include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
#include <SketchPlugin_Arc.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Line.h>
#include <SketchPlugin_Point.h>
+#include <SketchPlugin_ConstraintAngle.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintDistance.h>
+#include <SketchPlugin_ConstraintEqual.h>
+#include <SketchPlugin_ConstraintHorizontal.h>
+#include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintMirror.h>
+#include <SketchPlugin_ConstraintParallel.h>
+#include <SketchPlugin_ConstraintPerpendicular.h>
+#include <SketchPlugin_ConstraintRadius.h>
+#include <SketchPlugin_ConstraintRigid.h>
+#include <SketchPlugin_ConstraintTangent.h>
+#include <SketchPlugin_ConstraintVertical.h>
+
#include <GeomAPI_Dir2d.h>
#include <GeomDataAPI_Point.h>
#include <GeomDataAPI_Point2D.h>
SketchSolver_Constraint::SketchSolver_Constraint(
ConstraintPtr theConstraint)
: myBaseConstraint(theConstraint),
- myGroup(0)
-{
-}
-
-SketchSolver_Constraint::~SketchSolver_Constraint()
+ myGroupID(GID_UNKNOWN),
+ myType(CONSTRAINT_UNKNOWN)
{
- std::map<AttributePtr, Slvs_hParam>::const_iterator anIt1 = myValueMap.begin();
- for (; anIt1 != myValueMap.end(); anIt1++)
- myStorage->removeParameter(anIt1->second);
- myValueMap.clear();
-
- std::map<AttributePtr, Slvs_hEntity>::const_iterator anIt2 = myAttributeMap.begin();
- for (; anIt2 != myAttributeMap.end(); anIt2++)
- myStorage->removeEntity(anIt2->second);
- myAttributeMap.clear();
-
- std::map<FeaturePtr, Slvs_hEntity>::iterator anIt3 = myFeatureMap.begin();
- while (!myFeatureMap.empty()) {
- std::shared_ptr<SketchPlugin_Feature> aFeature =
- std::dynamic_pointer_cast<SketchPlugin_Feature>(anIt3->first);
- Slvs_hEntity anEnt = anIt3->second;
- std::map<FeaturePtr, Slvs_hEntity>::iterator aRemIt = anIt3++;
- myFeatureMap.erase(aRemIt);
- if (!myGroup->isInteract(aFeature))
- myStorage->removeEntity(anEnt);
- }
-
- std::vector<Slvs_hConstraint>::const_iterator anIt4 = mySlvsConstraints.begin();
- for (; anIt4 != mySlvsConstraints.end(); anIt4++)
- myStorage->removeConstraint(*anIt4);
- mySlvsConstraints.clear();
}
-void SketchSolver_Constraint::setStorage(StoragePtr theStorage)
+void SketchSolver_Constraint::process(StoragePtr theStorage,
+ const GroupID& theGroupID,
+ const EntityID& theSketchID)
{
myStorage = theStorage;
+ myGroupID = theGroupID;
+ mySketchID = theSketchID;
+ // Process constraint according to its type
process();
}
-void SketchSolver_Constraint::setGroup(SketchSolver_Group* theGroup)
-{
- myGroup = theGroup;
- process();
-}
-void SketchSolver_Constraint::addFeature(FeaturePtr theFeature)
-{
- int aType;
- changeEntity(theFeature, aType);
+SketchSolver_ConstraintType SketchSolver_Constraint::TYPE(ConstraintPtr theConstraint)
+{
+ const std::string& aType = theConstraint->getKind();
+ if (aType == SketchPlugin_ConstraintCoincidence::ID())
+ return CONSTRAINT_COINCIDENCE;
+ else if (aType == SketchPlugin_ConstraintRigid::ID())
+ return CONSTRAINT_FIXED;
+ else if (aType == SketchPlugin_ConstraintHorizontal::ID())
+ return CONSTRAINT_HORIZONTAL;
+ else if (aType == SketchPlugin_ConstraintVertical::ID())
+ return CONSTRAINT_VERTICAL;
+ else if (aType == SketchPlugin_ConstraintAngle::ID())
+ return CONSTRAINT_ANGLE;
+ else if (aType == SketchPlugin_ConstraintDistance::ID())
+ return CONSTRAINT_DISTANCE;
+ else if (aType == SketchPlugin_ConstraintEqual::ID())
+ return CONSTRAINT_EQUAL;
+ else if (aType == SketchPlugin_ConstraintLength::ID())
+ return CONSTRAINT_PT_PT_DISTANCE;
+ else if (aType == SketchPlugin_ConstraintMirror::ID())
+ return CONSTRAINT_SYMMETRIC;
+ else if (aType == SketchPlugin_ConstraintParallel::ID())
+ return CONSTRAINT_PARALLEL;
+ else if (aType == SketchPlugin_ConstraintPerpendicular::ID())
+ return CONSTRAINT_PERPENDICULAR;
+ else if (aType == SketchPlugin_ConstraintRadius::ID())
+ return CONSTRAINT_RADIUS;
+ else if (aType == SketchPlugin_ConstraintTangent::ID())
+ return CONSTRAINT_TANGENT;
+ return CONSTRAINT_UNKNOWN;
}
-
void SketchSolver_Constraint::process()
{
cleanErrorMsg();
- if (!myBaseConstraint || !myStorage || myGroup == 0) {
- /// TODO: Put error message here
+ if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) {
+ // Not enough parameters are assigned
return;
}
- if (!mySlvsConstraints.empty()) // some data is changed, update constraint
- update(myBaseConstraint);
- int aConstrType = getType();
- double aValue = 0.0;
- std::vector<Slvs_hEntity> anAttributes;
+ SketchSolver_ConstraintType aConstrType = getType();
+ double aValue;
+ std::vector<EntityWrapperPtr> anAttributes;
getAttributes(aValue, anAttributes);
if (!myErrorMsg.empty())
return;
- if (aConstrType == SLVS_C_UNKNOWN)
+ if (anAttributes.empty()) {
+ myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+ return;
+ }
+ if (aConstrType == CONSTRAINT_UNKNOWN)
aConstrType = getType();
- Slvs_hGroup aGroupID = myGroup->getId();
- Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
- Slvs_Constraint aConstraint;
- if (mySlvsConstraints.empty())
- aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, aGroupID, aConstrType, aWorkplaneID,
- aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]);
- else {
- aConstraint = myStorage->getConstraint(mySlvsConstraints[0]);
- aConstraint.valA = aValue;
- static const int aNbAttrs = 6;
- Slvs_hEntity* aConstrAttrs[aNbAttrs] = {
- &aConstraint.ptA, &aConstraint.ptB,
- &aConstraint.entityA, &aConstraint.entityB,
- &aConstraint.entityC, &aConstraint.entityD};
- std::vector<Slvs_hEntity>::const_iterator anIter = anAttributes.begin();
- for (int i = 0; i < aNbAttrs && anIter != anAttributes.end(); i++, anIter++)
- *(aConstrAttrs[i]) = *anIter;
- }
+ BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+ std::list<ConstraintWrapperPtr> aNewConstraints = aBuilder->createConstraint(
+ myBaseConstraint, myGroupID, mySketchID, aConstrType,
+ aValue, anAttributes[0], anAttributes[1], anAttributes[2], anAttributes[3]);
+ myStorage->addConstraint(myBaseConstraint, aNewConstraints);
- Slvs_hConstraint anID = myStorage->addConstraint(aConstraint);
- if (mySlvsConstraints.empty())
- mySlvsConstraints.push_back(anID);
- else
- mySlvsConstraints[0] = anID;
adjustConstraint();
}
-bool SketchSolver_Constraint::checkAttributesChanged(ConstraintPtr theConstraint)
-{
- std::set<Slvs_hEntity> aCurAttrs; // list of currently used attributes
- std::vector<Slvs_hConstraint>::const_iterator aConstrIter = mySlvsConstraints.begin();
- for (; aConstrIter != mySlvsConstraints.end(); aConstrIter++) {
- Slvs_Constraint aConstr = myStorage->getConstraint(*aConstrIter);
- if (aConstr.ptA != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.ptA);
- if (aConstr.ptB != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.ptB);
- if (aConstr.entityA != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityA);
- if (aConstr.entityB != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityB);
- if (aConstr.entityC != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityC);
- if (aConstr.entityD != SLVS_E_UNKNOWN) aCurAttrs.insert(aConstr.entityD);
- }
- // Check the attrbutes of constraint are changed
- ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint;
- std::list<AttributePtr> anAttrList = aConstraint->data()->attributes(std::string());
- std::list<AttributePtr>::iterator anAttrIter = anAttrList.begin();
- for (; anAttrIter != anAttrList.end(); anAttrIter++) {
- AttributeRefAttrPtr aRefAttr =
- std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
- if (aRefAttr) {
- if (aRefAttr->isObject()) {
- FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
- std::map<FeaturePtr, Slvs_hEntity>::iterator aFIt = myFeatureMap.find(aFeature);
- if (aFeature) {
- if (aFIt == myFeatureMap.end())
- return true;
- // Additional check the points of entity
- if (aCurAttrs.find(aFIt->second) == aCurAttrs.end()) {
- Slvs_Entity anEntity = myStorage->getEntity(aFIt->second);
- bool isFound = false;
- for (int i = 0; i < 4 && !isFound; i++)
- if (anEntity.point[i] != SLVS_E_UNKNOWN &&
- aCurAttrs.find(anEntity.point[i]) != aCurAttrs.end())
- isFound = true;
- if (!isFound)
- return true;
- }
- }
- } else if (aRefAttr->attr()) {
- std::map<AttributePtr, Slvs_hEntity>::iterator anAIt = myAttributeMap.find(aRefAttr->attr());
- if (anAIt == myAttributeMap.end() || aCurAttrs.find(anAIt->second) == aCurAttrs.end())
- return true;
- }
- }
- AttributeRefListPtr aRefList =
- std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrIter);
- if (aRefList) {
- std::list<ObjectPtr> anItems = aRefList->list();
- std::list<ObjectPtr>::iterator anIt = anItems.begin();
- for (; anIt != anItems.end(); anIt++) {
- FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
- if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end())
- return true;
- }
- }
- }
- return false;
-}
-
-void SketchSolver_Constraint::update(ConstraintPtr theConstraint)
+void SketchSolver_Constraint::update()
{
cleanErrorMsg();
- bool needToRebuild = (theConstraint && theConstraint != myBaseConstraint);
- if (!needToRebuild)
- needToRebuild = checkAttributesChanged(theConstraint);
- if (needToRebuild) {
- if (theConstraint && theConstraint->getKind() != myBaseConstraint->getKind())
- return;
- remove(myBaseConstraint);
- if (theConstraint)
- myBaseConstraint = theConstraint;
- process();
- return;
- }
- // Update all attributes
- int aType;
- std::map<Slvs_hEntity, Slvs_hEntity> aRelocationMap;
- std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIter = myFeatureMap.begin();
- for (; aFeatIter != myFeatureMap.end(); aFeatIter++) {
- Slvs_hEntity aPrevID = aFeatIter->second;
- aFeatIter->second = changeEntity(aFeatIter->first, aType);
- if (aFeatIter->second != aPrevID)
- aRelocationMap[aPrevID] = aFeatIter->second;
- }
- std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
- for (; anAttrIter != myAttributeMap.end(); anAttrIter++) {
- Slvs_hEntity aPrevID = anAttrIter->second;
- anAttrIter->second = changeEntity(anAttrIter->first, aType);
- if (anAttrIter->second != aPrevID)
- aRelocationMap[aPrevID] = anAttrIter->second;
- }
-
- // Value if exists
- DataPtr aData = myBaseConstraint->data();
- if (!aData) return;
+ std::list<ConstraintWrapperPtr> aWrapper = myStorage->constraint(myBaseConstraint);
AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
- myBaseConstraint->attribute(SketchPlugin_Constraint::VALUE()));
- double aValue = aValueAttr ? aValueAttr->value() : 0.0;
-
- // Update constraint
- std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
- for (; aCIter != mySlvsConstraints.end(); aCIter++) {
- Slvs_Constraint aConstraint = myStorage->getConstraint(*aCIter);
- if (aValueAttr) {
- aConstraint.valA = aValue;
- if (aConstraint.type == SLVS_C_DIAMETER)
- aConstraint.valA *= 2.0;
- }
- Slvs_hEntity* aCoeffs[6] = {
- &aConstraint.ptA, &aConstraint.ptB,
- &aConstraint.entityA, &aConstraint.entityB,
- &aConstraint.entityC, &aConstraint.entityD};
- for (int i = 0; i < 6; i++) {
- if (*(aCoeffs[i]) == SLVS_E_UNKNOWN)
- continue;
- std::map<Slvs_hEntity, Slvs_hEntity>::iterator aFound = aRelocationMap.find(*(aCoeffs[i]));
- if (aFound != aRelocationMap.end())
- *(aCoeffs[i]) = aFound->second;
- }
- *aCIter = myStorage->addConstraint(aConstraint);
+ myBaseConstraint->attribute(SketchPlugin_Constraint::VALUE()));
+ if (aValueAttr) {
+ std::list<ConstraintWrapperPtr>::iterator aWIt = aWrapper.begin();
+ for (; aWIt != aWrapper.end(); ++aWIt)
+ (*aWIt)->setValue(aValueAttr->value());
}
+ myStorage->addConstraint(myBaseConstraint, aWrapper);
+
adjustConstraint();
}
-bool SketchSolver_Constraint::remove(ConstraintPtr theConstraint)
+bool SketchSolver_Constraint::remove()
{
cleanErrorMsg();
- if (theConstraint && theConstraint != myBaseConstraint)
- return false;
- if (mySlvsConstraints.empty())
- return true;
- bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints.front());
- if (isFullyRemoved) {
- myFeatureMap.clear();
- myAttributeMap.clear();
- myValueMap.clear();
- } else
- cleanRemovedEntities();
- mySlvsConstraints.clear();
- return true;
-}
-
-void SketchSolver_Constraint::cleanRemovedEntities()
-{
- std::set<Slvs_hParam> aRemovedParams;
- std::set<Slvs_hEntity> aRemovedEntities;
- std::set<Slvs_hConstraint> aRemovedConstraints;
- myStorage->getRemoved(aRemovedParams, aRemovedEntities, aRemovedConstraints);
- std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.begin();
- while (aFeatIt != myFeatureMap.end()) {
- if (aRemovedEntities.find(aFeatIt->second) == aRemovedEntities.end()) {
- aFeatIt++;
- continue;
- }
- std::map<FeaturePtr, Slvs_hEntity>::iterator aTmpIter = aFeatIt++;
- myFeatureMap.erase(aTmpIter);
- }
- std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIt = myAttributeMap.begin();
- while (anAttrIt != myAttributeMap.end()) {
- if (aRemovedEntities.find(anAttrIt->second) == aRemovedEntities.end()) {
- anAttrIt++;
- continue;
- }
- std::map<AttributePtr, Slvs_hEntity>::iterator aTmpIter = anAttrIt++;
- myAttributeMap.erase(aTmpIter);
- }
- std::map<AttributePtr, Slvs_hParam>::iterator aValIt = myValueMap.begin();
- while (aValIt != myValueMap.end()) {
- if (aRemovedParams.find(aValIt->second) == aRemovedParams.end()) {
- aValIt++;
- continue;
- }
- std::map<AttributePtr, Slvs_hParam>::iterator aTmpIter = aValIt++;
- myValueMap.erase(aTmpIter);
- }
- for (size_t i = 0; i < mySlvsConstraints.size(); i++)
- if (aRemovedConstraints.find(mySlvsConstraints[i]) != aRemovedConstraints.end()) {
- mySlvsConstraints.erase(mySlvsConstraints.begin() + i);
- i--;
- }
+ return myStorage->removeConstraint(myBaseConstraint);
}
void SketchSolver_Constraint::getAttributes(
double& theValue,
- std::vector<Slvs_hEntity>& theAttributes)
+ std::vector<EntityWrapperPtr>& theAttributes)
{
static const int anInitNbOfAttr = 4;
- theAttributes.assign(anInitNbOfAttr, SLVS_E_UNKNOWN);
+ theAttributes.assign(anInitNbOfAttr, EntityWrapperPtr());
DataPtr aData = myBaseConstraint->data();
+ BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+
+ myType = TYPE(myBaseConstraint);
AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
- aData->attribute(SketchPlugin_Constraint::VALUE()));
+ aData->attribute(SketchPlugin_Constraint::VALUE()));
theValue = aValueAttr ? aValueAttr->value() : 0.0;
int aPtInd = 0; // index of first point in the list of attributes
- int aEntInd = 2; // index of first antity in the list of attributes
+ int aEntInd = 2; // index of first entity in the list of attributes
std::list<AttributePtr> aConstrAttrs = aData->attributes(ModelAPI_AttributeRefAttr::typeId());
std::list<AttributePtr>::iterator anIter = aConstrAttrs.begin();
for (; anIter != aConstrAttrs.end(); anIter++) {
return;
}
- int aType = SLVS_E_UNKNOWN; // type of created entity
- Slvs_hEntity anEntity = myGroup->getAttributeId(aRefAttr);
- if (anEntity == SLVS_E_UNKNOWN)
- anEntity = changeEntity(aRefAttr, aType);
- else {
- Slvs_Entity anEnt = myStorage->getEntity(anEntity);
- aType = anEnt.type;
- }
+ myStorage->update(*anIter, myGroupID);
+ EntityWrapperPtr anEntity = myStorage->entity(*anIter);
- if (aType == SLVS_E_UNKNOWN)
+ SketchSolver_EntityType aType = anEntity->type();
+ if (aType == ENTITY_UNKNOWN)
continue;
- else if (aType == SLVS_E_POINT_IN_2D || aType == SLVS_E_POINT_IN_3D)
+ else if (aType == ENTITY_POINT)
theAttributes[aPtInd++] = anEntity; // the point is created
else { // another entity (not a point) is created
if (aEntInd < anInitNbOfAttr)
}
}
-Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributeRefAttrPtr theAttribute, int& theType)
-{
- // Convert the object of the attribute to the feature
- FeaturePtr aFeature;
- if (theAttribute->isObject() && theAttribute->object()) {
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- theAttribute->object());
- if (!aRC) {
- myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
- return SLVS_E_UNKNOWN;
- }
- std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
- aFeature = aDoc->feature(aRC);
-
- return changeEntity(aFeature, theType);
- }
-
- return changeEntity(theAttribute->attr(), theType);
-}
-
-Slvs_hEntity SketchSolver_Constraint::changeEntity(AttributePtr theEntity, int& theType)
+bool SketchSolver_Constraint::isUsed(FeaturePtr theFeature) const
{
- Slvs_hEntity aResult = SLVS_E_UNKNOWN;
- if (!theEntity || !isInitialized(theEntity)) {
- myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
- return SLVS_E_UNKNOWN;
- }
+ const std::list<ConstraintWrapperPtr>& aCList = myStorage->constraint(myBaseConstraint);
+ std::list<ConstraintWrapperPtr>::const_iterator aCIt = aCList.begin();
+ for (; aCIt != aCList.end(); ++aCIt)
+ if ((*aCIt)->isUsed(theFeature))
+ return true;
- // If the entity is already in the group, try to find it
- std::map<std::shared_ptr<ModelAPI_Attribute>, Slvs_hEntity>::const_iterator anEntIter =
- myAttributeMap.find(theEntity);
- Slvs_Entity aCurrentEntity;
- aCurrentEntity.h = SLVS_E_UNKNOWN;
- if (anEntIter != myAttributeMap.end())
- aCurrentEntity = myStorage->getEntity(anEntIter->second);
- else {
- aResult = myGroup->getAttributeId(theEntity);
- if (aResult != SLVS_E_UNKNOWN) {
- Slvs_Entity anEnt = myStorage->getEntity(aResult);
- theType = anEnt.type;
- myAttributeMap[theEntity] = aResult;
- return aResult;
- }
- }
+ std::list<AttributePtr> anAttrList = theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
+ std::list<AttributePtr>::const_iterator anAttrIt = anAttrList.begin();
+ for (; anAttrIt != anAttrList.end(); ++ anAttrIt)
+ if (isUsed(*anAttrIt))
+ return true;
- Slvs_hGroup aGroupID = myGroup->getId();
- // do not update entity from another group
- if (aCurrentEntity.h != SLVS_E_UNKNOWN && aGroupID != aCurrentEntity.group)
- return aCurrentEntity.h;
-
- // Point in 3D
- std::shared_ptr<GeomDataAPI_Point> aPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
- if (aPoint) {
- double aXYZ[3] = {aPoint->x(), aPoint->y(), aPoint->z()};
- Slvs_hParam aParams[3];
- for (int i = 0; i < 3; i++) {
- Slvs_Param aPar = aCurrentEntity.h != SLVS_E_UNKNOWN ?
- myStorage->getParameter(aCurrentEntity.param[i]) :
- Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
- aPar.val = aXYZ[i];
- aParams[i] = myStorage->addParameter(aPar);
- }
-
- if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
- aCurrentEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, aGroupID, aParams[0], aParams[1], aParams[2]);
- else { // update entity data
- for (int i = 0; i < 3; i++)
- aCurrentEntity.param[i] = aParams[i];
- }
- aResult = myStorage->addEntity(aCurrentEntity);
- } else {
- // All entities except 3D points are created on workplane. So, if there is no workplane yet, then error
- Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
- if (aWorkplaneID == SLVS_E_UNKNOWN)
- return SLVS_E_UNKNOWN;
-
- // Point in 2D
- std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
- if (aPoint2D) {
- double aXY[2] = {aPoint2D->x(), aPoint2D->y()};
- Slvs_hParam aParams[2];
- for (int i = 0; i < 2; i++) {
- Slvs_Param aPar = aCurrentEntity.h != SLVS_E_UNKNOWN ?
- myStorage->getParameter(aCurrentEntity.param[i]) :
- Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
- aPar.val = aXY[i];
- aParams[i] = myStorage->addParameter(aPar);
- }
-
- if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
- aCurrentEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aParams[0], aParams[1]);
- else { // update entity data
- for (int i = 0; i < 2; i++)
- aCurrentEntity.param[i] = aParams[i];
- }
- aResult = myStorage->addEntity(aCurrentEntity);
- } else {
- // Scalar value (used for the distance entities)
- AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theEntity);
- if (aScalar) {
- Slvs_Param aParam = aCurrentEntity.h != SLVS_E_UNKNOWN ?
- myStorage->getParameter(aCurrentEntity.param[0]) :
- Slvs_MakeParam(SLVS_E_UNKNOWN, aGroupID, 0.0);
- aParam.val = aScalar->value();
- Slvs_hParam aValue = myStorage->addParameter(aParam);
-
- if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
- aCurrentEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aValue);
- else
- aCurrentEntity.param[0] = aValue;
- aResult = myStorage->addEntity(aCurrentEntity);
- }
- }
- }
-
- myAttributeMap[theEntity] = aResult;
- theType = aCurrentEntity.type;
- return aResult;
-}
-
-Slvs_hEntity SketchSolver_Constraint::changeEntity(FeaturePtr theEntity, int& theType)
-{
- Slvs_hEntity aResult = SLVS_E_UNKNOWN;
- if (!theEntity || !theEntity->data() || !theEntity->data()->isValid())
- return SLVS_E_UNKNOWN;
- // If the entity is already in the group, try to find it
- std::map<FeaturePtr, Slvs_hEntity>::const_iterator anEntIter = myFeatureMap.find(theEntity);
- Slvs_Entity aCurrentEntity;
- aCurrentEntity.h = SLVS_E_UNKNOWN;
- if (anEntIter != myFeatureMap.end())
- aCurrentEntity = myStorage->getEntity(anEntIter->second);
- else {
- aResult = myGroup->getFeatureId(theEntity);
- if (aResult != SLVS_E_UNKNOWN) {
- Slvs_Entity anEnt = myStorage->getEntity(aResult);
- theType = anEnt.type;
- myFeatureMap[theEntity] = aResult;
- return aResult;
- }
- }
-
- Slvs_hGroup aGroupID = myGroup->getId();
- // do not update entity from another group
- if (aCurrentEntity.h != SLVS_E_UNKNOWN && aGroupID != aCurrentEntity.group)
- return aCurrentEntity.h;
-
- Slvs_hEntity aWorkplaneID = myGroup->getWorkplaneId();
- DataPtr aData = theEntity->data();
-
- // SketchPlugin features
- const std::string& aFeatureKind = theEntity->getKind();
- AttributePtr anAttribute;
- int anAttrType;
- // Line
- if (aFeatureKind == SketchPlugin_Line::ID()) {
- anAttribute = aData->attribute(SketchPlugin_Line::START_ID());
- if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
- Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType);
-
- anAttribute = aData->attribute(SketchPlugin_Line::END_ID());
- if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
- Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType);
-
- if (aCurrentEntity.h == SLVS_E_UNKNOWN) // New entity
- aCurrentEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID, aStart, aEnd);
- else {
- aCurrentEntity.point[0] = aStart;
- aCurrentEntity.point[1] = aEnd;
- }
- aResult = myStorage->addEntity(aCurrentEntity);
- }
- // Circle
- else if (aFeatureKind == SketchPlugin_Circle::ID()) {
- anAttribute = aData->attribute(SketchPlugin_Circle::CENTER_ID());
- if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
- Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType);
-
- anAttribute = aData->attribute(SketchPlugin_Circle::RADIUS_ID());
- if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
- Slvs_hEntity aRadius = changeEntity(anAttribute, anAttrType);
-
- if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity
- Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID);
- aCurrentEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID,
- aCenter, aWorkplane.normal, aRadius);
- } else {
- aCurrentEntity.point[0] = aCenter;
- aCurrentEntity.distance = aRadius;
- }
- aResult = myStorage->addEntity(aCurrentEntity);
- }
- // Arc
- else if (aFeatureKind == SketchPlugin_Arc::ID()) {
- anAttribute = aData->attribute(SketchPlugin_Arc::CENTER_ID());
- if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
- Slvs_hEntity aCenter = changeEntity(anAttribute, anAttrType);
-
- anAttribute = aData->attribute(SketchPlugin_Arc::START_ID());
- if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
- Slvs_hEntity aStart = changeEntity(anAttribute, anAttrType);
-
- anAttribute = aData->attribute(SketchPlugin_Arc::END_ID());
- if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
- Slvs_hEntity aEnd = changeEntity(anAttribute, anAttrType);
-
- if (aCurrentEntity.h == SLVS_E_UNKNOWN) { // New entity
- Slvs_Entity aWorkplane = myStorage->getEntity(aWorkplaneID);
- aCurrentEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, aGroupID, aWorkplaneID,
- aWorkplane.normal, aCenter, aStart, aEnd);
- } else {
- aCurrentEntity.point[0] = aCenter;
- aCurrentEntity.point[1] = aStart;
- aCurrentEntity.point[2] = aEnd;
- }
- aResult = myStorage->addEntity(aCurrentEntity);
- }
- // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
- else if (aFeatureKind == SketchPlugin_Point::ID()) {
- anAttribute = aData->attribute(SketchPlugin_Point::COORD_ID());
- if (!isInitialized(anAttribute)) return SLVS_E_UNKNOWN;
- // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier
- aResult = changeEntity(anAttribute, anAttrType);
- aCurrentEntity.type = SLVS_E_POINT_IN_3D;
- }
-
- if (aResult != SLVS_E_UNKNOWN) {
- myFeatureMap[theEntity] = aResult;
- theType = aCurrentEntity.type;
- }
- return aResult;
-}
-
-std::list<ConstraintPtr> SketchSolver_Constraint::constraints() const
-{
- std::list<ConstraintPtr> aConstraints;
- aConstraints.push_back(myBaseConstraint);
- return aConstraints;
+ return false;
}
-void SketchSolver_Constraint::refresh()
+bool SketchSolver_Constraint::isUsed(AttributePtr theAttribute) const
{
- cleanErrorMsg();
- std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
- while (anAttrIter != myAttributeMap.end()) {
- std::shared_ptr<GeomDataAPI_Point> aPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point>(anAttrIter->first);
- Slvs_Entity anEntity = myStorage->getEntity(anAttrIter->second);
- if (anEntity.h == SLVS_E_UNKNOWN) {
- std::map<AttributePtr, Slvs_hEntity>::iterator aTmpIter = anAttrIter++;
- myAttributeMap.erase(aTmpIter);
- continue;
- }
- if (aPoint) {
- double aXYZ[3];
- for (int i = 0; i < 3; i++) {
- Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]);
- aXYZ[i] = aPar.val;
- }
- if (fabs(aPoint->x() - aXYZ[0]) > tolerance ||
- fabs(aPoint->y() - aXYZ[1]) > tolerance ||
- fabs(aPoint->z() - aXYZ[2]) > tolerance)
- aPoint->setValue(aXYZ[0], aXYZ[1], aXYZ[2]);
- } else {
- // Point in 2D
- std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttrIter->first);
- if (aPoint2D) {
- double aXY[2];
- for (int i = 0; i < 2; i++) {
- Slvs_Param aPar = myStorage->getParameter(anEntity.param[i]);
- aXY[i] = aPar.val;
- }
- if (fabs(aPoint2D->x() - aXY[0]) > tolerance ||
- fabs(aPoint2D->y() - aXY[1]) > tolerance)
- aPoint2D->setValue(aXY[0], aXY[1]);
- } else {
- // Scalar value (used for the distance entities)
- AttributeDoublePtr aScalar =
- std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttrIter->first);
- if (aScalar) {
- Slvs_Param aPar = myStorage->getParameter(anEntity.param[0]);
- if (fabs(aScalar->value() - aPar.val) > tolerance)
- aScalar->setValue(aPar.val);
- }
- }
- }
- anAttrIter++;
+ AttributePtr anAttribute = theAttribute;
+ AttributeRefAttrPtr aRefAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
+ if (aRefAttr) {
+ if (aRefAttr->isObject())
+ return isUsed(ModelAPI_Feature::feature(aRefAttr->object()));
+ else
+ anAttribute = aRefAttr->attr();
}
- std::map<AttributePtr, Slvs_hParam>::iterator aValIter = myValueMap.begin();
- for (; aValIter != myValueMap.end(); aValIter++) {
- AttributeDoublePtr aScalar =
- std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttrIter->first);
- if (aScalar) {
- Slvs_Param aPar = myStorage->getParameter(anAttrIter->second);
- aScalar->setValue(aPar.val);
- }
- }
-}
-
-Slvs_hEntity SketchSolver_Constraint::getId(FeaturePtr theFeature) const
-{
- std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFIter = myFeatureMap.find(theFeature);
- if (aFIter == myFeatureMap.end())
- return SLVS_E_UNKNOWN;
- //// check the Feature is really in the storage
- //Slvs_Entity anEntity = myStorage->getEntity(aFIter->second);
- //if (anEntity.h == SLVS_E_UNKNOWN) {
- // // rebuild feature
- // int aType;
- // anEntity.h = const_cast<SketchSolver_Constraint*>(this)->changeEntity(aFIter->first, aType);
- // const_cast<SketchSolver_Constraint*>(this)->myFeatureMap[theFeature] = anEntity.h;
- //}
- //return anEntity.h;
- return aFIter->second;
-}
-
-Slvs_hEntity SketchSolver_Constraint::getId(AttributePtr theAttribute) const
-{
- std::map<AttributePtr, Slvs_hEntity>::const_iterator anAttrIter = myAttributeMap.find(theAttribute);
- if (anAttrIter == myAttributeMap.end())
- return SLVS_E_UNKNOWN;
- return anAttrIter->second;
-}
-
-bool SketchSolver_Constraint::isInitialized(AttributePtr theAttribute)
-{
- if (theAttribute->isInitialized())
- return true;
- myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+ const std::list<ConstraintWrapperPtr>& aCList = myStorage->constraint(myBaseConstraint);
+ std::list<ConstraintWrapperPtr>::const_iterator aCIt = aCList.begin();
+ for (; aCIt != aCList.end(); ++aCIt)
+ if ((*aCIt)->isUsed(theAttribute))
+ return true;
return false;
}
-
-void SketchSolver_Constraint::calculateMiddlePoint(
- const Slvs_Entity& theEntity, double theCoeff, double& theX, double& theY) const
-{
- if (theEntity.type == SLVS_E_LINE_SEGMENT) {
- double aStartEndXY[2][2];
- Slvs_Entity aPoint;
- for (int i = 0; i < 2; i++) {
- aPoint = myStorage->getEntity(theEntity.point[i]);
- for (int j = 0; j < 2; j++)
- aStartEndXY[i][j] = myStorage->getParameter(aPoint.param[j]).val;
- }
- theX = (1.0 - theCoeff) * aStartEndXY[0][0] + theCoeff * aStartEndXY[1][0];
- theY = (1.0 - theCoeff) * aStartEndXY[0][1] + theCoeff * aStartEndXY[1][1];
- } else if (theEntity.type == SLVS_E_ARC_OF_CIRCLE) {
- double anArcPoint[3][2];
- Slvs_Entity aPoint;
- for (int i = 0; i < 3; i++) {
- aPoint = myStorage->getEntity(theEntity.point[i]);
- for (int j = 0; j < 2; j++)
- anArcPoint[i][j] = myStorage->getParameter(aPoint.param[j]).val;
- }
- // 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];
- return;
- } else if (1 - theCoeff < tolerance) {
- theX = anArcPoint[0][0] + anArcPoint[2][0];
- theY = anArcPoint[0][1] + anArcPoint[2][1];
- return;
- }
-
- std::shared_ptr<GeomAPI_Dir2d> aStartDir(new GeomAPI_Dir2d(anArcPoint[1][0], anArcPoint[1][1]));
- std::shared_ptr<GeomAPI_Dir2d> 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;
- }
-}
-
void SketchSolver_Constraint::makeTemporary() const
{
- std::vector<Slvs_hConstraint>::const_iterator anIt = mySlvsConstraints.begin();
- for (; anIt != mySlvsConstraints.end(); anIt++)
- myStorage->addTemporaryConstraint(*anIt);
+ myStorage->setTemporary(myBaseConstraint);
}
#include <string>
#include <vector>
-class SketchSolver_Group;
-
/** \class SketchSolver_Constraint
* \ingroup Plugins
- * \brief Stores mapping between SketchPlugin and SolveSpace constraints data
+ * \brief Converts SketchPlugin constraint to the constraint applicable for solver
*/
class SketchSolver_Constraint
{
protected:
/// Default constructor
- SketchSolver_Constraint() {}
- /// Constructor based on SketchPlugin constraint
- SketchSolver_Constraint(ConstraintPtr theConstraint);
+ SketchSolver_Constraint()
+ : myGroupID(GID_UNKNOWN),
+ myType(CONSTRAINT_UNKNOWN)
+ {}
public:
- virtual ~SketchSolver_Constraint();
+ /// Constructor based on SketchPlugin constraint
+ SKETCHSOLVER_EXPORT SketchSolver_Constraint(ConstraintPtr theConstraint);
+
+ virtual ~SketchSolver_Constraint() {}
- /// \brief Initializes the storage of SolveSpace constraints
- void setStorage(StoragePtr theStorage);
- /// \brief Initializes group ID for this constraint
- void setGroup(SketchSolver_Group* theGroup);
+ /// \brief Initializes parameters and start constraint creation
+ /// \param theStorage [in] storage where to place new constraint
+ /// \param theGroupID [in] group for constraint
+ /// \param theSketchID [in] sketch for constraint
+ void process(StoragePtr theStorage, const GroupID& theGroupID, const EntityID& theSketchID);
/// \brief Update constraint
- virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
+ SKETCHSOLVER_EXPORT virtual void update();
/// \brief Tries to remove constraint
/// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
- virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+ SKETCHSOLVER_EXPORT virtual bool remove();
- /// \brief Update SketchPlugin attributes using the data obtained from SolveSpace entities
- virtual void refresh();
+ /// \brief Obtain a type of SketchPlugin constraint
+ SKETCHSOLVER_EXPORT static SketchSolver_ConstraintType TYPE(ConstraintPtr theConstraint);
/// \brief Returns the type of constraint
- virtual int getType() const = 0;
+ virtual SketchSolver_ConstraintType getType() const
+ { return myType; }
/// \brief The constraint is made temporary
void makeTemporary() const;
- /// \brief Checks the constraint is used by current object
- virtual bool hasConstraint(ConstraintPtr theConstraint) const
- { return theConstraint == myBaseConstraint; }
-
- /// \brief Return list of SketchPlugin constraints attached to this object
- virtual std::list<ConstraintPtr> constraints() const;
-
- /// \brief Return identifier of SolveSpace entity relating to the feature
- Slvs_hEntity getId(FeaturePtr theFeature) const;
- /// \brief Return identifier of SolveSpace entity relating to the attribute
- Slvs_hEntity getId(AttributePtr theAttribute) const;
-
- /// \brief Adds a feature to constraint and create its analogue in SolveSpace
- virtual void addFeature(FeaturePtr theFeature);
+ /// \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 theAttribute) const;
/// \brief Shows error message
const std::string& error() const
{ return myErrorMsg; }
protected:
- /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+ /// \brief Converts SketchPlugin constraint to a list of solver's constraints
virtual void process();
- /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+ /// \brief Generate list of attributes of constraint in order useful for constraints
/// \param[out] theValue numerical characteristic of constraint (e.g. distance)
/// \param[out] theAttributes list of attributes to be filled
- virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
-
- /// \brief Verify the attributes of constraint are changed (and constraint need to rebuild)
- /// \param[in] theConstraint constraint, which attributes should be checked (if NULL, the myBaseConstraint is used)
- /// \return \c true if some attributes are changed
- virtual bool checkAttributesChanged(ConstraintPtr theConstraint);
+ virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes);
/// \brief This method is used in derived objects to check consistency of constraint.
/// E.g. the distance between line and point may be signed.
virtual void adjustConstraint()
{}
- /// \brief Create or change SlveSpace entity according to the given attribute
- /// \param[in] theAttribute reference to the entity to be changed
- /// \param[out] theType type of created entity
- /// \return identifier of created/updated entity
- Slvs_hEntity changeEntity(AttributeRefAttrPtr theAttribute, int& theType);
- /// \brief Create or change SlveSpace entity according to the given attribute
- Slvs_hEntity changeEntity(AttributePtr theAttribute, int& theType);
- /// \brief Create or change SlveSpace entity according to the given feature
- Slvs_hEntity changeEntity(FeaturePtr theFeature, int& theType);
-
- /// \brief Calculate middle point on the specified entity
- /// \param[in] theEntity arc or line
- /// \param[in] theCoeff is a value in [0.0, 1.0] which shows the position of the point on the entity (0.0 - start point, 1.0 - end point)
- /// \param[out] theX X coordinate of middle point
- /// \param[out] theY Y coordinate of middle point
- void calculateMiddlePoint(const Slvs_Entity& theEntity, double theCoeff,
- double& theX, double& theY) const;
-
- /// \brief Removes the links to unused entities
- void cleanRemovedEntities();
-
/// \brief Removes last error
void cleanErrorMsg()
{ myErrorMsg.clear(); }
-private:
- /// \brief Sets error, if the attribute is not initialized
- bool isInitialized(AttributePtr theAttribute);
-
protected:
- SketchSolver_Group* myGroup; ///< the group which contains current constraint
- ConstraintPtr myBaseConstraint; ///< SketchPlugin constraint
- std::vector<Slvs_hConstraint> mySlvsConstraints; ///< list of indices of SolveSpace constraints, together which equivalent to SketchPlugin constraint
- std::map<FeaturePtr, Slvs_hEntity> myFeatureMap; ///< map feature to the entity it represents
- std::map<AttributePtr, Slvs_hEntity> myAttributeMap; ///< map attribute to the corresponding entity
- std::map<AttributePtr, Slvs_hParam> myValueMap; ///< list of attributes, which represents single value (e.g. distance) used in constraint
- StoragePtr myStorage; ///< storage, which contains all information about entities and constraints in current group
-
- std::string myErrorMsg; ///< error message
-};
-
-typedef std::shared_ptr<SketchSolver_Constraint> SolverConstraintPtr;
-
-
-
-/** \class SketchSolver_ConstraintParallel
- * \ingroup Plugins
- * \brief Convert Parallel constraint to SolveSpace structure
- */
-class SketchSolver_ConstraintParallel : public SketchSolver_Constraint
-{
-public:
- /// Constructor based on SketchPlugin constraint
- SketchSolver_ConstraintParallel(ConstraintPtr theConstraint) :
- SketchSolver_Constraint(theConstraint)
- {}
-
- virtual int getType() const
- { return SLVS_C_PARALLEL; }
-};
-
-
-/** \class SketchSolver_ConstraintPerpendicular
- * \ingroup Plugins
- * \brief Convert Perpendicular constraint to SolveSpace structure
- */
-class SketchSolver_ConstraintPerpendicular : public SketchSolver_Constraint
-{
-public:
- /// Constructor based on SketchPlugin constraint
- SketchSolver_ConstraintPerpendicular(ConstraintPtr theConstraint) :
- SketchSolver_Constraint(theConstraint)
- {}
+ GroupID myGroupID; ///< identifier of the group, the constraint belongs to
+ EntityID mySketchID; ///< identifier of the sketch, the constraint belongs to
+ ConstraintPtr myBaseConstraint; ///< base SketchPlugin constraint
+ StoragePtr myStorage; ///< storage, which contains all information about entities and constraints
+ SketchSolver_ConstraintType myType; ///< type of constraint
- virtual int getType() const
- { return SLVS_C_PERPENDICULAR; }
+ std::string myErrorMsg; ///< error message
};
-
-/** \class SketchSolver_ConstraintHorizontal
- * \ingroup Plugins
- * \brief Convert Horizontal constraint to SolveSpace structure
- */
-class SketchSolver_ConstraintHorizontal : public SketchSolver_Constraint
-{
-public:
- /// Constructor based on SketchPlugin constraint
- SketchSolver_ConstraintHorizontal(ConstraintPtr theConstraint) :
- SketchSolver_Constraint(theConstraint)
- {}
-
- virtual int getType() const
- { return SLVS_C_HORIZONTAL; }
-};
-
-
-/** \class SketchSolver_ConstraintVertical
- * \ingroup Plugins
- * \brief Convert Vertical constraint to SolveSpace structure
- */
-class SketchSolver_ConstraintVertical : public SketchSolver_Constraint
-{
-public:
- /// Constructor based on SketchPlugin constraint
- SketchSolver_ConstraintVertical(ConstraintPtr theConstraint) :
- SketchSolver_Constraint(theConstraint)
- {}
-
- virtual int getType() const
- { return SLVS_C_VERTICAL; }
-};
-
-
-/** \class SketchSolver_ConstraintRadius
- * \ingroup Plugins
- * \brief Convert Radius constraint to SolveSpace structure
- */
-class SketchSolver_ConstraintRadius : public SketchSolver_Constraint
-{
-public:
- /// Constructor based on SketchPlugin constraint
- SketchSolver_ConstraintRadius(ConstraintPtr theConstraint) :
- SketchSolver_Constraint(theConstraint)
- {}
-
- virtual int getType() const
- { return SLVS_C_DIAMETER; }
-
- virtual void adjustConstraint()
- {
- AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
- myBaseConstraint->attribute(SketchPlugin_Constraint::VALUE()));
- Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front());
- aConstraint.valA = 2.0 * aValueAttr->value();
- myStorage->updateConstraint(aConstraint);
- }
-};
+typedef std::shared_ptr<SketchSolver_Constraint> SolverConstraintPtr;
#endif
#include <SketchSolver_ConstraintAngle.h>
+#include <SketchSolver_Manager.h>
#include <GeomAPI_Dir2d.h>
#include <GeomAPI_Lin2d.h>
#include <cmath>
void SketchSolver_ConstraintAngle::getAttributes(
- double& theValue, std::vector<Slvs_hEntity>& theAttributes)
+ double& theValue, std::vector<EntityWrapperPtr>& theAttributes)
{
SketchSolver_Constraint::getAttributes(theValue, theAttributes);
void SketchSolver_ConstraintAngle::adjustConstraint()
{
static const double aTol = 1000. * tolerance;
- Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front());
+ BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+
+ ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front();
+ if (fabs(myAngle - aConstraint->value()) < aTol)
+ return;
+ myAngle = aConstraint->value();
bool isFixed[2][2];
std::shared_ptr<GeomAPI_Pnt2d> aPoints[2][2]; // start and end points of lines
- Slvs_hConstraint aFixedConstraint;
- Slvs_hEntity anEnt[2] = {aConstraint.entityA, aConstraint.entityB};
- for (int i = 0; i < 2; i++) {
- const Slvs_Entity& aLine = myStorage->getEntity(anEnt[i]);
- double aCoef = -1.0;
- for (int j = 0; j < 2; j++, aCoef += 2.0) {
- const Slvs_Entity& aPoint = myStorage->getEntity(aLine.point[j]);
- double aCoords[2];
- for (int k = 0; k < 2; k++)
- aCoords[k] = myStorage->getParameter(aPoint.param[k]).val;
- isFixed[i][j] = myStorage->isPointFixed(aPoint.h, aFixedConstraint, true);
- aPoints[i][j] = std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aCoords[0], aCoords[1]));
+ const std::list<EntityWrapperPtr>& aConstrLines = aConstraint->entities();
+ std::list<EntityWrapperPtr>::const_iterator aCLIt = aConstrLines.begin();
+ for (int i = 0; aCLIt != aConstrLines.end(); ++i, ++aCLIt) {
+ const std::list<EntityWrapperPtr>& aLinePoints = (*aCLIt)->subEntities();
+ std::list<EntityWrapperPtr>::const_iterator aLPIt = aLinePoints.begin();
+ for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt) {
+ isFixed[i][j] = ((*aLPIt)->group() != myGroupID);
+ aPoints[i][j] = aBuilder->point(*aLPIt);
}
}
+ if (isFixed[0][0] && isFixed[0][1] && isFixed[1][0] && isFixed[1][1])
+ return; // both lines are fixed => no need to update them
+
std::shared_ptr<GeomAPI_Lin2d> aLine[2] = {
std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])),
std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1]))
}
}
- aConstraint.other = false;
- for (int i = 0; i < 2; i++)
- if (aLine[i]->direction()->dot(aDir[i]) < 0.0)
- aConstraint.other = !aConstraint.other;
- myStorage->updateConstraint(aConstraint);
-
- bool isChanged = fabs(myAngle - aConstraint.valA) > aTol;
- // myAngle should be updated even if the angle of constraint is changed too little
- myAngle = aConstraint.valA;
- if (!isChanged)
- return; // the angle was not changed, no need to recalculate positions of lines
-
- if (isFixed[0][0] && isFixed[0][1] && isFixed[1][0] && isFixed[1][1])
- return; // both lines are fixed => no need to update them
-
// Recalculate positions of lines to avoid conflicting constraints
// while changing angle value several times
double cosA = cos(myAngle * PI / 180.0);
}
// Update positions of points
- const Slvs_Entity& anUpdLine = myStorage->getEntity(anEnt[aLineToUpd]);
- Slvs_Param aParam;
- for (int i = 0; i < 2; i++) {
- const Slvs_Entity& aPoint = myStorage->getEntity(anUpdLine.point[i]);
- aParam = myStorage->getParameter(aPoint.param[0]);
- aParam.val = aNewPoints[i]->x();
- myStorage->updateParameter(aParam);
- aParam = myStorage->getParameter(aPoint.param[1]);
- aParam.val = aNewPoints[i]->y();
- myStorage->updateParameter(aParam);
+ std::list<EntityWrapperPtr>::const_iterator anUpdLine = aConstrLines.begin();
+ if (aLineToUpd > 0) ++anUpdLine;
+ const std::list<EntityWrapperPtr>& anUpdPoints = (*anUpdLine)->subEntities();
+ std::list<EntityWrapperPtr>::const_iterator aPIt = anUpdPoints.begin();
+ for (int i = 0; aPIt != anUpdPoints.end(); ++aPIt, ++i) {
+ double aCoord[2] = {aNewPoints[i]->x(), aNewPoints[i]->y()};
+ const std::list<ParameterWrapperPtr>& aParams = (*aPIt)->parameters();
+ std::list<ParameterWrapperPtr>::const_iterator aParIt = aParams.begin();
+ for (int j = 0; aParIt != aParams.end(); ++j, ++aParIt)
+ (*aParIt)->setValue(aCoord[j]);
}
+
+ aBuilder->adjustConstraint(aConstraint);
+ myStorage->addConstraint(myBaseConstraint, aConstraint);
}
myAngle(0.0)
{}
- virtual int getType() const
- { return SLVS_C_ANGLE; }
-
/// \brief This method is used in derived objects to check consistence of constraint.
virtual void adjustConstraint();
protected:
- /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+ /// \brief Generate list of attributes of constraint in order useful for constraints
/// \param[out] theValue numerical characteristic of constraint (e.g. distance)
/// \param[out] theAttributes list of attributes to be filled
- virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
+ virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes);
private:
double myAngle;
#include <SketchSolver_ConstraintCoincidence.h>
#include <SketchSolver_Error.h>
-#include <SketchSolver_Group.h>
-
-#include <SketchPlugin_Point.h>
-#include <GeomDataAPI_Point2D.h>
-
-#include <map>
+#include <SketchSolver_Manager.h>
void SketchSolver_ConstraintCoincidence::getAttributes(
double& theValue,
- std::vector<Slvs_hEntity>& theAttributes)
+ std::vector<EntityWrapperPtr>& theAttributes)
{
SketchSolver_Constraint::getAttributes(theValue, theAttributes);
- if (!myErrorMsg.empty() || theAttributes[0] == SLVS_E_UNKNOWN)
+ if (!myErrorMsg.empty() || !theAttributes[0]) {
+ theAttributes.clear();
return;
+ }
- if (theAttributes[1] != SLVS_E_UNKNOWN) {
- myType = SLVS_C_POINTS_COINCIDENT;
-
- // set coordinates of slave (second) point equal to the master (first) point
- Slvs_Entity aFirst = myStorage->getEntity(theAttributes[0]);
- Slvs_Entity aSecond = myStorage->getEntity(theAttributes[1]);
- for (int i = 0; i < 4; i++)
- if (aFirst.param[i] != SLVS_E_UNKNOWN && aSecond.param[i] != SLVS_E_UNKNOWN) {
- Slvs_Param aPar1 = myStorage->getParameter(aFirst.param[i]);
- Slvs_Param aPar2 = myStorage->getParameter(aSecond.param[i]);
- aPar2.val = aPar1.val;
- myStorage->updateParameter(aPar2);
- }
+ if (theAttributes[1]) {
+ myType = CONSTRAINT_PT_PT_COINCIDENT;
+ // Set the slave (second) point the same as master (first) point.
+ // This will allow to skip adding point-point coincidence to the set of constraints
+ // and give us speed-up in solving the set of equations
+ myStorage->addCoincidentPoints(theAttributes[0], theAttributes[1]);
}
- else if (theAttributes[2] != SLVS_E_UNKNOWN) {
+ else if (theAttributes[2]) {
// check the type of entity (line or circle)
- Slvs_Entity anEnt = myStorage->getEntity(theAttributes[2]);
- if (anEnt.type == SLVS_E_LINE_SEGMENT)
- myType = SLVS_C_PT_ON_LINE;
- else if (anEnt.type == SLVS_E_CIRCLE || anEnt.type == SLVS_E_ARC_OF_CIRCLE)
- myType = SLVS_C_PT_ON_CIRCLE;
+ SketchSolver_EntityType anEntType = theAttributes[2]->type();
+ if (anEntType == ENTITY_LINE)
+ myType = CONSTRAINT_PT_ON_LINE;
+ else if (anEntType == ENTITY_CIRCLE || anEntType == ENTITY_ARC)
+ myType = CONSTRAINT_PT_ON_CIRCLE;
else
myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
} else
}
-bool SketchSolver_ConstraintCoincidence::hasConstraint(ConstraintPtr theConstraint) const
-{
- if (myBaseConstraint == theConstraint)
- return true;
- return myExtraCoincidence.find(theConstraint) != myExtraCoincidence.end();
-}
-
-std::list<ConstraintPtr> SketchSolver_ConstraintCoincidence::constraints() const
-{
- std::list<ConstraintPtr> aConstraints;
- aConstraints.push_back(myBaseConstraint);
- std::map<ConstraintPtr, Slvs_hConstraint>::const_iterator anIt = myExtraCoincidence.begin();
- for (; anIt != myExtraCoincidence.end(); anIt++)
- aConstraints.push_back(anIt->first);
- return aConstraints;
-}
-
-bool SketchSolver_ConstraintCoincidence::isCoincide(
- std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint) const
-{
- std::set<AttributePtr>::const_iterator anAttrIter = theConstraint->myCoincidentPoints.begin();
- for (; anAttrIter != theConstraint->myCoincidentPoints.end(); anAttrIter++)
- if (myCoincidentPoints.find(*anAttrIter) != myCoincidentPoints.end())
- return true;
- return false;
-}
-
-void SketchSolver_ConstraintCoincidence::attach(
- std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint)
+static bool isBase(const std::list<ConstraintWrapperPtr>& theConstraints, AttributePtr theAttribute)
{
- cleanErrorMsg();
- // Remove constraints from theConstraint
- std::vector<Slvs_hConstraint>::iterator aCIter = theConstraint->mySlvsConstraints.begin();
- for (; aCIter != theConstraint->mySlvsConstraints.end(); aCIter++)
- theConstraint->myStorage->removeConstraint(*aCIter);
-
- if (myStorage == theConstraint->myStorage) {
- // Clean removed items
- std::set<Slvs_hParam> aRemParams;
- std::set<Slvs_hEntity> aRemEnts;
- std::set<Slvs_hConstraint> aRemConstr;
- theConstraint->myStorage->getRemoved(aRemParams, aRemEnts, aRemConstr);
-
- if (!aRemEnts.empty()) {
- std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = theConstraint->myFeatureMap.begin();
- while (aFeatIt != theConstraint->myFeatureMap.end()) {
- if (aRemEnts.find(aFeatIt->second) != aRemEnts.end()) {
- // remove feature
- std::map<FeaturePtr, Slvs_hEntity>::iterator aRemoveIt = aFeatIt++;
- theConstraint->myFeatureMap.erase(aRemoveIt);
- } else
- ++aFeatIt;
- }
- std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIt = theConstraint->myAttributeMap.begin();
- while (anAttrIt != theConstraint->myAttributeMap.end()) {
- if (aRemEnts.find(anAttrIt->second) != aRemEnts.end()) {
- // remove attribute
- std::map<AttributePtr, Slvs_hEntity>::iterator aRemoveIt = anAttrIt++;
- theConstraint->myAttributeMap.erase(aRemoveIt);
- } else
- ++anAttrIt;
- }
- }
- }
-
- // Copy data.
- addConstraint(theConstraint->myBaseConstraint);
- std::map<ConstraintPtr, Slvs_hConstraint>::iterator aConstrIter =
- theConstraint->myExtraCoincidence.begin();
- for (; aConstrIter != theConstraint->myExtraCoincidence.end(); aConstrIter++)
- addConstraint(aConstrIter->first);
- // Clear the lists to not remove the entities on destruction
- theConstraint->mySlvsConstraints.clear();
- theConstraint->myFeatureMap.clear();
- theConstraint->myAttributeMap.clear();
-}
-
-Slvs_hConstraint SketchSolver_ConstraintCoincidence::addConstraint(
- Slvs_hEntity thePoint1, Slvs_hEntity thePoint2)
-{
- if (thePoint1 == thePoint2)
- return SLVS_E_UNKNOWN;
-
- bool hasDuplicated = myStorage->hasDuplicatedConstraint();
- Slvs_Constraint aNewConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
- SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(), 0.0, thePoint1, thePoint2,
- SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- Slvs_hConstraint aNewID = myStorage->addConstraint(aNewConstraint);
- if (!hasDuplicated && myStorage->hasDuplicatedConstraint()) {
- // the duplicated constraint appears
- myStorage->removeConstraint(aNewID);
- return SLVS_E_UNKNOWN;
- }
- mySlvsConstraints.push_back(aNewID);
- return aNewID;
-}
-
-Slvs_hConstraint SketchSolver_ConstraintCoincidence::addPointOnEntity(
- Slvs_hEntity thePoint, Slvs_hEntity theEntity)
-{
- // Check the point is not coincident with boundaries of the entity
- Slvs_Entity anEnt = myStorage->getEntity(theEntity);
- int aPos = anEnt.type == SLVS_E_LINE_SEGMENT ? 0 : 1;
- for (; anEnt.point[aPos] != SLVS_E_UNKNOWN; aPos++)
- if (anEnt.point[aPos] == thePoint ||
- myStorage->isCoincident(anEnt.point[aPos], thePoint))
- return SLVS_E_UNKNOWN;
-
- bool hasDuplicated = myStorage->hasDuplicatedConstraint();
- Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
- Slvs_hConstraint aType = anEnt.type == SLVS_E_LINE_SEGMENT ?
- SLVS_C_PT_ON_LINE : SLVS_C_PT_ON_CIRCLE;
- Slvs_Constraint aNewConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
- aType, myGroup->getWorkplaneId(), 0.0, aBaseCoincidence.ptA, SLVS_E_UNKNOWN,
- theEntity, SLVS_E_UNKNOWN);
- Slvs_hConstraint aNewID = myStorage->addConstraint(aNewConstraint);
- if (!hasDuplicated && myStorage->hasDuplicatedConstraint()) {
- // the duplicated constraint appears
- myStorage->removeConstraint(aNewID);
- return SLVS_E_UNKNOWN;
- }
- mySlvsConstraints.push_back(aNewID);
- return aNewID;
-}
-
-void SketchSolver_ConstraintCoincidence::addConstraint(ConstraintPtr theConstraint)
-{
- if (mySlvsConstraints.empty()) {
- // This constraint is empty, rebuild it from scratch
- myBaseConstraint = theConstraint;
- process();
- return;
- }
-
- std::list<AttributePtr> anAttrList =
- theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
- std::list<AttributePtr>::iterator anIter = anAttrList.begin();
- std::vector<Slvs_hEntity> aPoints;
- Slvs_hEntity anEntity = SLVS_E_UNKNOWN;
- int anEntType;
- for (; anIter != anAttrList.end(); anIter++) {
- Slvs_hEntity aPointID = SLVS_E_UNKNOWN;
- AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
- if (!aRefAttr)
- continue;
-
- AttributePtr aPointAttr;
- if (aRefAttr->isObject()) {
- FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
- std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFeatFound =
- myFeatureMap.find(aFeature);
- if (aFeatFound != myFeatureMap.end())
- anEntity = aFeatFound->second;
- else {
- anEntity = myGroup->getFeatureId(aFeature);
- if (anEntity == SLVS_E_UNKNOWN)
- anEntity = changeEntity(aFeature, anEntType);
- else {
- myFeatureMap[aFeature] = anEntity;
- // Obtain relations between attributes of the feature and SolveSpace entities
- std::list<AttributePtr> anAttrList =
- aFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
- std::list<AttributePtr>::iterator anIt = anAttrList.begin();
- for (; anIt != anAttrList.end(); ++anIt) {
- Slvs_hEntity anAttrID = myGroup->getAttributeId(*anIt);
- if (anAttrID != SLVS_E_UNKNOWN)
- myAttributeMap[*anIt] = anAttrID;
- }
- }
- }
- // If the feature is a point, add it to the list of coincident points
- if (aFeature->getKind() == SketchPlugin_Point::ID()) {
- aPointID = anEntity;
- anEntity = SLVS_E_UNKNOWN;
- aPointAttr = aFeature->attribute(SketchPlugin_Point::COORD_ID());
- }
- } else {
- aPointAttr = aRefAttr->attr();
- std::map<AttributePtr, Slvs_hEntity>::const_iterator anAttrFound =
- myAttributeMap.find(aPointAttr);
- if (anAttrFound != myAttributeMap.end())
- aPointID = anAttrFound->second;
- else {
- aPointID = myGroup->getAttributeId(aPointAttr);
- if (aPointID == SLVS_E_UNKNOWN)
- aPointID = changeEntity(aPointAttr, anEntType);
- }
- }
-
- if (aPointAttr) { // the point is found
- aPoints.push_back(aPointID);
- myCoincidentPoints.insert(aPointAttr);
- myAttributeMap[aPointAttr] = aPointID;
- }
- }
-
- Slvs_hConstraint aNewConstr = SLVS_E_UNKNOWN;
- if (anEntity != SLVS_E_UNKNOWN)
- aNewConstr = addPointOnEntity(aPoints.front(), anEntity);
- else { // coincidence between two points
- Slvs_Constraint aBaseCoincidence = myStorage->getConstraint(mySlvsConstraints.front());
- std::vector<Slvs_hEntity>::const_iterator aPtIter = aPoints.begin();
- for (; aPtIter != aPoints.end(); aPtIter++) {
- Slvs_hConstraint aC = addConstraint(aBaseCoincidence.ptA, *aPtIter);
- if (aC != SLVS_E_UNKNOWN)
- aNewConstr = aC;
- }
- }
- myExtraCoincidence[theConstraint] = aNewConstr;
-}
-
-void SketchSolver_ConstraintCoincidence::process()
-{
- SketchSolver_Constraint::process();
-
- // Fill the list of coincident points
- std::list<AttributePtr> anAttrList =
- myBaseConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
- std::list<AttributePtr>::iterator anIt = anAttrList.begin();
- for (; anIt != anAttrList.end(); anIt++) {
- AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIt);
- if (!aRefAttr || aRefAttr->isObject())
- continue;
- myCoincidentPoints.insert(aRefAttr->attr());
- }
-}
-
-bool SketchSolver_ConstraintCoincidence::remove(ConstraintPtr theConstraint)
-{
- cleanErrorMsg();
- if (mySlvsConstraints.empty())
- return true;
- ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint;
- int aPos = -1; // position of constraint in the list (-1 for base constraint)
- std::map<ConstraintPtr, Slvs_hConstraint>::iterator anExtraIt;
- if (aConstraint != myBaseConstraint) {
- anExtraIt = myExtraCoincidence.find(aConstraint);
- if (anExtraIt == myExtraCoincidence.end())
- return false; // there is no constraint, which is specified to remove
- else {
- bool isEmpty = anExtraIt->second == SLVS_E_UNKNOWN;
- if (!isEmpty) {
- isEmpty = true;
- for (aPos = 0; aPos < (int)mySlvsConstraints.size(); aPos++)
- if (mySlvsConstraints[aPos] == anExtraIt->second) {
- isEmpty = false;
- break;
- }
- aPos -= 1;
- }
- myExtraCoincidence.erase(anExtraIt);
- if (isEmpty)
- return false;
- }
- }
-
- bool isFullyRemoved = myStorage->removeConstraint(mySlvsConstraints[aPos+1]);
- mySlvsConstraints.erase(mySlvsConstraints.begin() + (1+aPos));
- if (aPos < 0 && !myExtraCoincidence.empty()) {
- anExtraIt = myExtraCoincidence.begin();
- // Remove invalid constraints
- while (anExtraIt != myExtraCoincidence.end()) {
- if (!anExtraIt->first->data() || !anExtraIt->first->data()->isValid()) {
- std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
- if (aTempIt->first != SLVS_E_UNKNOWN) {
- myStorage->removeConstraint(aTempIt->second);
- std::vector<Slvs_hConstraint>::iterator anIt = mySlvsConstraints.begin();
- for (; anIt != mySlvsConstraints.end(); anIt++)
- if (*anIt == aTempIt->second) {
- mySlvsConstraints.erase(anIt);
- break;
- }
- }
- myExtraCoincidence.erase(aTempIt);
- continue;
- }
- anExtraIt++;
- }
- // Find first non-extra conststraint
- anExtraIt = myExtraCoincidence.begin();
- while (anExtraIt != myExtraCoincidence.end() && anExtraIt->second == SLVS_E_UNKNOWN)
- anExtraIt++;
- if (anExtraIt != myExtraCoincidence.end()) {
- // Need to specify another base coincidence constraint
- myBaseConstraint = anExtraIt->first;
- myExtraCoincidence.erase(anExtraIt);
- if (mySlvsConstraints.empty()) {
- std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
- Slvs_Constraint aBase = myStorage->getConstraint(*aCIter);
- for (++aCIter; aCIter != mySlvsConstraints.end(); aCIter++) {
- Slvs_Constraint aConstr = myStorage->getConstraint(*aCIter);
- aConstr.ptA = aBase.ptA;
- myStorage->updateConstraint(aConstr);
- }
- }
- }
- }
- // Clear removed attributes
- std::set<Slvs_hParam> aParamRemoved;
- std::set<Slvs_hEntity> anEntRemoved;
- std::set<Slvs_hConstraint> aConstrRemoved;
- myStorage->getRemoved(aParamRemoved, anEntRemoved, aConstrRemoved);
- std::map<AttributePtr, Slvs_hEntity>::iterator anAttrIter = myAttributeMap.begin();
- while (anAttrIter != myAttributeMap.end()) {
- if (anEntRemoved.find(anAttrIter->second) != anEntRemoved.end()) {
- std::map<AttributePtr, Slvs_hEntity>::iterator aTempIt = anAttrIter++;
- myCoincidentPoints.erase(aTempIt->first);
- myAttributeMap.erase(aTempIt);
- continue;
- }
- anAttrIter++;
+ AttributePtr anAttribute = theAttribute;
+ FeaturePtr aFeature;
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
+ if (aRefAttr) {
+ if (aRefAttr->isObject())
+ aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+ else
+ anAttribute = aRefAttr->attr();
}
- // Go through remaining extra coincidence and try to add or remove them
- anExtraIt = myExtraCoincidence.begin();
- while (anExtraIt != myExtraCoincidence.end()) {
- if (anExtraIt->first == SLVS_E_UNKNOWN) {
- if (!anExtraIt->first->data() || !anExtraIt->first->data()->isValid()) {
- std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
- myExtraCoincidence.erase(aTempIt);
- continue;
- }
- if (mySlvsConstraints.empty()) {
- myBaseConstraint = anExtraIt->first;
- std::map<ConstraintPtr, Slvs_hConstraint>::iterator aTempIt = anExtraIt++;
- myExtraCoincidence.erase(aTempIt);
- process();
- continue;
- } else
- addConstraint(anExtraIt->first);
- }
- anExtraIt++;
+ std::list<ConstraintWrapperPtr>::const_iterator aCIt = theConstraints.begin();
+ for (; aCIt != theConstraints.end(); ++aCIt) {
+ std::list<EntityWrapperPtr> aSubs = (*aCIt)->entities();
+ std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
+ for (; aSIt != aSubs.end(); ++aSIt)
+ if ((aFeature && (*aSIt)->isBase(aFeature)) ||
+ (!aFeature && (*aSIt)->isBase(anAttribute)))
+ return true;
}
- return mySlvsConstraints.empty();
+ return false;
}
-
#include "SketchSolver.h"
#include <SketchSolver_Constraint.h>
-#include <SketchSolver_Storage.h>
/** \class SketchSolver_ConstraintCoincidence
* \ingroup Plugins
{
public:
/// Constructor based on SketchPlugin constraint
- SketchSolver_ConstraintCoincidence(ConstraintPtr theConstraint) :
- SketchSolver_Constraint(theConstraint),
- myType(SLVS_C_UNKNOWN)
+ SKETCHSOLVER_EXPORT SketchSolver_ConstraintCoincidence(ConstraintPtr theConstraint) :
+ SketchSolver_Constraint(theConstraint)
{}
- virtual int getType() const
- { return myType; }
-
- /// \brief Tries to remove constraint
- /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
- virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
-
- /// \brief Checks the constraint is used by current object
- virtual bool hasConstraint(ConstraintPtr theConstraint) const;
-
- /// \brief Return list of SketchPlugin constraints attached to this object
- virtual std::list<ConstraintPtr> constraints() const;
-
- /// \brief Verifies the two Coincidence constraints are intersects (have shared point)
- bool isCoincide(std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint) const;
-
- /// \brief Append all data of coincidence constaint to the current
- void attach(std::shared_ptr<SketchSolver_ConstraintCoincidence> theConstraint);
-
protected:
- /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
- virtual void process();
-
- /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+ /// \brief Generate list of attributes of constraint in order useful for constraints
/// \param[out] theValue numerical characteristic of constraint (e.g. distance)
/// \param[out] theAttributes list of attributes to be filled
- virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
-
-private:
- /// \brief Creates new coincidence constraint
- Slvs_hConstraint addConstraint(Slvs_hEntity thePoint1, Slvs_hEntity thePoint2);
-
- /// \brief Create full SolveSpace structure according to given constraint
- void addConstraint(ConstraintPtr theConstraint);
-
- /// \brief Create constraint of point concident to the line or circle
- Slvs_hConstraint addPointOnEntity(Slvs_hEntity thePoint, Slvs_hEntity theEntity);
-
-private:
- int myType; ///< type of constraint (applicable SLVS_C_POINTS_COINCIDENT or SLVS_C_PT_ON_LINE or SLVS_C_PT_ON_CIRCLE)
- std::map<ConstraintPtr, Slvs_hConstraint> myExtraCoincidence; ///< multiple coincidence of points
- std::set<AttributePtr> myCoincidentPoints; ///< list of points under the Coincidence constraint
+ virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes);
};
#endif
#include <SketchSolver_ConstraintDistance.h>
-#include <SketchSolver_Group.h>
#include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Lin2d.h>
+#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_XY.h>
#include <math.h>
-void SketchSolver_ConstraintDistance::process()
+void SketchSolver_ConstraintDistance::getAttributes(
+ double& theValue,
+ std::vector<EntityWrapperPtr>& theAttributes)
{
- cleanErrorMsg();
- if (!myBaseConstraint || !myStorage || myGroup == 0) {
- /// TODO: Put error message here
+ SketchSolver_Constraint::getAttributes(theValue, theAttributes);
+ if (!myErrorMsg.empty() || !theAttributes[0]) {
+ theAttributes.clear();
return;
}
- if (!mySlvsConstraints.empty()) // some data is changed, update constraint
- update(myBaseConstraint);
- double aValue;
- std::vector<Slvs_hEntity> anEntities;
- getAttributes(aValue, anEntities);
- if (!myErrorMsg.empty())
- return;
-
- // Obtain entities to identify the type of distance
- static const int aNbPoints = 2;
- Slvs_hEntity aPoint[aNbPoints] = {SLVS_E_UNKNOWN, SLVS_E_UNKNOWN};
- Slvs_hEntity aLine = SLVS_E_UNKNOWN;
- myType = SLVS_C_PT_PT_DISTANCE;
- int aPtPos = 0;
- std::vector<Slvs_hEntity>::iterator anEntIter = anEntities.begin();
- for (; anEntIter != anEntities.end(); anEntIter++) {
- if (*anEntIter == SLVS_E_UNKNOWN)
- continue;
- Slvs_Entity anEnt = myStorage->getEntity(*anEntIter);
- if (anEnt.type == SLVS_E_POINT_IN_2D || anEnt.type == SLVS_E_POINT_IN_3D) {
- if (aPtPos >= aNbPoints) {
- myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
- return;
- }
- aPoint[aPtPos++] = *anEntIter;
- }
- else if (anEnt.type == SLVS_E_LINE_SEGMENT) {
- if (myType == SLVS_C_PT_LINE_DISTANCE) {
- myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
- return;
- }
- aLine = *anEntIter;
- myType = SLVS_C_PT_LINE_DISTANCE;
- }
- }
-
- Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
- getType(), myGroup->getWorkplaneId(), aValue, aPoint[0], aPoint[1], aLine, SLVS_E_UNKNOWN);
- aConstraint.h = myStorage->addConstraint(aConstraint);
- mySlvsConstraints.push_back(aConstraint.h);
+ if (theAttributes[1])
+ myType = CONSTRAINT_PT_PT_DISTANCE;
+ else if (theAttributes[2] && theAttributes[2]->type() == ENTITY_LINE)
+ myType = CONSTRAINT_PT_LINE_DISTANCE;
+ else
+ theAttributes.clear();
myPrevValue = 0.0;
- adjustConstraint();
}
void SketchSolver_ConstraintDistance::adjustConstraint()
{
// Adjust point-line distance
- if (getType() != SLVS_C_PT_LINE_DISTANCE)
+ if (getType() != CONSTRAINT_PT_LINE_DISTANCE)
return;
// Check the sign of distance is changed
- Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front());
- if (fabs(myPrevValue) == fabs(aConstraint.valA)) {
- aConstraint.valA = myPrevValue;
- myStorage->updateConstraint(aConstraint);
+ ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front();
+ if (fabs(myPrevValue) == fabs(aConstraint->value())) {
+ aConstraint->setValue(myPrevValue);
+ myStorage->addConstraint(myBaseConstraint, aConstraint);
return;
}
// Get constraint parameters and check the sign of constraint value
- std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
- for (; aCIter != mySlvsConstraints.end(); aCIter++) {
- aConstraint = myStorage->getConstraint(*aCIter);
- Slvs_Entity aLine = myStorage->getEntity(aConstraint.entityA);
- // Obtain point and line coordinates
- Slvs_hEntity aPointID[3] = {aConstraint.ptA, aLine.point[0], aLine.point[1]};
- std::shared_ptr<GeomAPI_XY> aPoints[3];
- for (int i = 0; i < 3; i++) {
- Slvs_Entity aPoint = myStorage->getEntity(aPointID[i]);
- Slvs_Param aParams[2] = {
- myStorage->getParameter(aPoint.param[0]),
- myStorage->getParameter(aPoint.param[1])};
- aPoints[i] = std::shared_ptr<GeomAPI_XY>(new GeomAPI_XY(aParams[0].val, aParams[1].val));
- }
- std::shared_ptr<GeomAPI_XY> aLineVec = aPoints[2]->decreased(aPoints[1]);
- std::shared_ptr<GeomAPI_XY> aPtLineVec = aPoints[0]->decreased(aPoints[1]);
- if (aPtLineVec->cross(aLineVec) * aConstraint.valA < 0.0 || myIsNegative) {
- aConstraint.valA *= -1.0;
- myStorage->updateConstraint(aConstraint);
- myIsNegative = true;
- }
+ BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+ std::shared_ptr<GeomAPI_Pnt2d> aPoint;
+ std::shared_ptr<GeomAPI_Lin2d> aLine;
+ std::list<EntityWrapperPtr> aSubs = aConstraint->entities();
+ std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
+ for (; aSIt != aSubs.end(); ++aSIt) {
+ if ((*aSIt)->type() == ENTITY_POINT)
+ aPoint = aBuilder->point(*aSIt);
+ else if ((*aSIt)->type() == ENTITY_LINE)
+ aLine = aBuilder->line(*aSIt);
+ }
+
+ std::shared_ptr<GeomAPI_XY> aLineVec = aLine->direction()->xy();
+ std::shared_ptr<GeomAPI_XY> aPtLineVec = aPoint->xy()->decreased(aLine->location()->xy());
+ if (aPtLineVec->cross(aLineVec) * aConstraint->value() < 0.0 || myIsNegative) {
+ aConstraint->setValue(aConstraint->value() * (-1.0));
+ myStorage->addConstraint(myBaseConstraint, aConstraint);
+ myIsNegative = true;
}
}
-void SketchSolver_ConstraintDistance::update(ConstraintPtr theConstraint)
+void SketchSolver_ConstraintDistance::update()
{
- Slvs_Constraint aConstraint = myStorage->getConstraint(mySlvsConstraints.front());
- myPrevValue = aConstraint.valA;
- SketchSolver_Constraint::update(theConstraint);
+ ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front();
+ myPrevValue = aConstraint->value();
+
+ SketchSolver_Constraint::update();
}
/// Constructor based on SketchPlugin constraint
SketchSolver_ConstraintDistance(ConstraintPtr theConstraint) :
SketchSolver_Constraint(theConstraint),
- myType(SLVS_C_UNKNOWN),
myIsNegative(false)
{}
/// \brief Update constraint
- virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
-
- virtual int getType() const
- {return myType; }
+ virtual void update();
protected:
- /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
- virtual void process();
+ /// \brief Generate list of attributes of constraint in order useful for constraints
+ /// \param[out] theValue numerical characteristic of constraint (e.g. distance)
+ /// \param[out] theAttributes list of attributes to be filled
+ virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes);
/// \brief This method is used in derived objects to check consistence of constraint.
/// E.g. the distance between line and point may be signed.
virtual void adjustConstraint();
private:
- int myType; ///< type of constraint (applicable: SLVS_C_PT_PT_DISTANCE, SLVS_C_PT_LINE_DISTANCE)
double myPrevValue; ///< previous value of distance (for correct calculation of a distance sign)
bool myIsNegative; ///< \c true, if the point if placed rightside of line direction (SLVS_C_PT_LINE_DISTANCE only)
};
#include <SketchSolver_ConstraintEqual.h>
-#include <SketchSolver_Group.h>
#include <SketchSolver_Error.h>
-
-void SketchSolver_ConstraintEqual::process()
+void SketchSolver_ConstraintEqual::getAttributes(
+ double& theValue,
+ std::vector<EntityWrapperPtr>& theAttributes)
{
- cleanErrorMsg();
- if (!myBaseConstraint || !myStorage || myGroup == 0) {
- /// TODO: Put error message here
+ SketchSolver_Constraint::getAttributes(theValue, theAttributes);
+ if (!myErrorMsg.empty() || !theAttributes[2] || !theAttributes[3]) {
+ theAttributes.clear();
return;
}
- if (!mySlvsConstraints.empty()) // some data is changed, update constraint
- update(myBaseConstraint);
-
- double aValue;
- std::vector<Slvs_hEntity> anEntities;
- getAttributes(aValue, anEntities);
- if (!myErrorMsg.empty())
- return;
// Check the quantity of entities of each type
int aNbLines = 0;
int aNbArcs = 0;
int aNbCircs = 0;
bool isArcFirst = false; // in line-arc equivalence, the line should be first
- std::vector<Slvs_hEntity>::iterator anEntIter = anEntities.begin();
- for (; anEntIter != anEntities.end(); anEntIter++) {
- Slvs_Entity anEnt = myStorage->getEntity(*anEntIter);
- if (anEnt.type == SLVS_E_LINE_SEGMENT)
- aNbLines++;
- else if (anEnt.type == SLVS_E_CIRCLE)
- aNbCircs++;
- else if (anEnt.type == SLVS_E_ARC_OF_CIRCLE) {
- aNbArcs++;
+ std::vector<EntityWrapperPtr>::iterator anAttrIt = theAttributes.begin() + 2;
+ for (; anAttrIt != theAttributes.end(); ++anAttrIt) {
+ SketchSolver_EntityType aType = (*anAttrIt)->type();
+ if (aType == ENTITY_LINE)
+ ++aNbLines;
+ else if (aType == ENTITY_CIRCLE)
+ ++aNbCircs;
+ else if (aType == ENTITY_ARC) {
+ ++aNbArcs;
isArcFirst = (aNbLines == 0);
}
}
if (aNbLines + aNbArcs + aNbCircs != 2 ||
- (aNbLines == aNbCircs && aNbArcs == 0)) {
+ (aNbLines == aNbCircs && aNbArcs == 0)) {
myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
return;
}
switch (aNbLines) {
case 0:
- myType = SLVS_C_EQUAL_RADIUS;
+ myType = CONSTRAINT_EQUAL_RADIUS;
break;
case 1:
- myType = SLVS_C_EQUAL_LINE_ARC_LEN;
+ myType = CONSTRAINT_EQUAL_LINE_ARC;
if (isArcFirst) { // change the order of arc and line
- Slvs_hEntity aTmp = anEntities[2];
- anEntities[2] = anEntities[3];
- anEntities[3] = aTmp;
+ EntityWrapperPtr aTmp = theAttributes[2];
+ theAttributes[2] = theAttributes[3];
+ theAttributes[3] = aTmp;
}
break;
default:
- myType = SLVS_C_EQUAL_LENGTH_LINES;
+ myType = CONSTRAINT_EQUAL_LINES;
break;
}
-
- Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
- getType(), myGroup->getWorkplaneId(), aValue,
- anEntities[0], anEntities[1], anEntities[2], anEntities[3]);
- aConstraint.h = myStorage->addConstraint(aConstraint);
- mySlvsConstraints.push_back(aConstraint.h);
- adjustConstraint();
}
-
SketchSolver_Constraint(theConstraint)
{}
- virtual int getType() const
- { return myType; }
-
protected:
- /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
- virtual void process();
-
-private:
- int myType; ///< type of constraint (applicable: SLVS_C_EQUAL_LENGTH_LINES, SLVS_C_EQUAL_RADIUS, SLVS_C_EQUAL_LINE_ARC_LEN)
+ /// \brief Generate list of attributes of constraint in order useful for constraints
+ /// \param[out] theValue numerical characteristic of constraint (e.g. distance)
+ /// \param[out] theAttributes list of attributes to be filled
+ virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes);
};
#endif
+++ /dev/null
-#include <SketchSolver_ConstraintFillet.h>
-#include <SketchSolver_Group.h>
-#include <SketchSolver_Error.h>
-
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeRefAttr.h>
-#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_ResultConstruction.h>
-
-
-void SketchSolver_ConstraintFillet::getAttributes(
- double& theValue, std::vector<Slvs_hEntity>& theAttributes)
-{
- theAttributes.clear();
-
- DataPtr aData = myBaseConstraint->data();
- AttributeDoublePtr aValueAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
- aData->attribute(SketchPlugin_Constraint::VALUE()));
- theValue = aValueAttr ? aValueAttr->value() : 0.0;
-
- std::list<AttributePtr> aBaseAttrs = aData->attributes(ModelAPI_AttributeRefAttr::typeId());
- std::list<AttributePtr>::iterator anIter = aBaseAttrs.begin();
- for (; anIter != aBaseAttrs.end(); anIter++) {
- AttributeRefAttrPtr aRefAttr =
- std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
- if (!aRefAttr || !aRefAttr->isInitialized()) {
- myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
- return;
- }
-
- int aType = SLVS_E_UNKNOWN; // type of created entity
- Slvs_hEntity anEntity = myGroup->getAttributeId(aRefAttr);
- if (anEntity == SLVS_E_UNKNOWN)
- anEntity = changeEntity(aRefAttr, aType);
-
- if (aType == SLVS_E_UNKNOWN)
- continue;
- theAttributes.push_back(anEntity);
- }
-
- // Fillet objects
- AttributeRefListPtr aFilletRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- aData->attribute(SketchPlugin_Constraint::ENTITY_C()));
- if (!aFilletRefList || !aFilletRefList->isInitialized()) {
- myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
- return;
- }
- std::list<ObjectPtr> aFilletList = aFilletRefList->list();
- if (aFilletList.size() < theAttributes.size() + 1) {
- myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
- return;
- }
- FeaturePtr aFilletFeature;
- ResultConstructionPtr aRC;
- int aType;
- std::list<ObjectPtr>::iterator aFilIter = aFilletList.begin();
- for (int indEnt = 0; aFilIter != aFilletList.end(); aFilIter++, indEnt++) {
- aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aFilIter);
- aFilletFeature = aRC ? aRC->document()->feature(aRC) :
- std::dynamic_pointer_cast<ModelAPI_Feature>(*aFilIter);
- if (!aFilletFeature) {
- myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
- return;
- }
- Slvs_hEntity anEntity = changeEntity(aFilletFeature, aType);
- theAttributes.push_back(anEntity);
- }
-}
-
-void SketchSolver_ConstraintFillet::process()
-{
- cleanErrorMsg();
- if (!myBaseConstraint || !myStorage || myGroup == 0) {
- /// TODO: Put error message here
- return;
- }
- if (!mySlvsConstraints.empty()) // some data is changed, update constraint
- update(myBaseConstraint);
-
- double aValue;
- std::vector<Slvs_hEntity> anEntID;
- getAttributes(aValue, anEntID);
- if (!myErrorMsg.empty())
- return;
-
- // Obtain the entities itself:
- // First two are base entities
- // Second two are trimmed them
- // Last one is a fillet arc
- std::vector<Slvs_Entity> anEntities;
- std::vector<Slvs_hEntity>::iterator anIt = anEntID.begin();
- for (; anIt != anEntID.end(); anIt++)
- anEntities.push_back(myStorage->getEntity(*anIt));
-
- // Check the base entities have a coincident point
- Slvs_hEntity aPointsToFind[4];
- for (int i = 0; i < 2; i++) {
- int aShift = anEntities[i].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
- aPointsToFind[2*i] = anEntities[i].point[aShift];
- aPointsToFind[2*i+1]= anEntities[i].point[aShift+1];
- }
- // Search coincident points
- int aCoincInd[2]; // indices of coincident points on each entity (0 - first, 1 - last)
- bool isPointFound = false;
- for (int i = 0; i < 2 && !isPointFound; i++)
- for (int j = 2; j < 4 && !isPointFound; j++)
- if (myStorage->isEqual(aPointsToFind[i], aPointsToFind[j])) {
- aCoincInd[0] = i;
- aCoincInd[1] = j - 2;
- isPointFound = true;
- }
- if (!isPointFound) {
- // There is no coincident points between tangential objects. Generate error message
- myErrorMsg = SketchSolver_Error::NO_COINCIDENT_POINTS();
- return;
- }
-
- // For correct result, move floating points of fillet on the middle points of base objects
- Slvs_Entity aPoint;
- Slvs_Param aParam;
- double anArcPoints[3][2];
- for (int i = 0; i < 2; i++) {
- calculateMiddlePoint(anEntities[i], 0.1 + 0.8 * aCoincInd[i], anArcPoints[i+1][0], anArcPoints[i+1][1]);
- aPoint = myStorage->getEntity(anEntities[i+2].point[aCoincInd[i]]);
- for (int j = 0; j < 2; j++) {
- aParam = myStorage->getParameter(aPoint.param[j]);
- aParam.val = anArcPoints[i+1][j];
- aPoint.param[j] = myStorage->updateParameter(aParam);
- }
- }
- anArcPoints[0][0] = 0.5 * (anArcPoints[1][0] + anArcPoints[2][0]);
- anArcPoints[0][1] = 0.5 * (anArcPoints[1][1] + anArcPoints[2][1]);
- // Check the arc is need to be reversed
- double aSharedPoint[2];
- aPoint = myStorage->getEntity(aPointsToFind[aCoincInd[0]]);
- for (int j = 0; j < 2; j++)
- aSharedPoint[j] = myStorage->getParameter(aPoint.param[j]).val;
- double aCross = (anArcPoints[1][0] - anArcPoints[0][0]) * (aSharedPoint[1] - anArcPoints[0][1]) -
- (anArcPoints[1][1] - anArcPoints[0][1]) * (aSharedPoint[0] - anArcPoints[0][0]);
- if (aCross < 0.0) { // reverse fillet arc
- double aTmp;
- for (int j = 0; j < 2; j++) {
- aTmp = anArcPoints[1][j];
- anArcPoints[1][j] = anArcPoints[2][j];
- anArcPoints[2][j] = aTmp;
- }
- }
- // update fillet arc coordinates
- for (int indArcPt = 0; indArcPt < 3; indArcPt++) {
- aPoint = myStorage->getEntity(anEntities.back().point[indArcPt]);
- for (int j = 0; j < 2; j++) {
- aParam = myStorage->getParameter(aPoint.param[j]);
- aParam.val = anArcPoints[indArcPt][j];
- aPoint.param[j] = myStorage->updateParameter(aParam);
- }
- }
-
- for (int indEnt = 0; indEnt < 2; indEnt++) {
- int aShift = anEntities[indEnt].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
- // one point of fillet object should be coincident with the point on base, non-coincident with another base object
- Slvs_hEntity aBaseID = anEntities[indEnt].point[1 - aCoincInd[indEnt] + aShift];
- Slvs_hEntity aFilletID = anEntities[2 + indEnt].point[1 - aCoincInd[indEnt] + aShift];
- Slvs_Constraint aCoincConstr = Slvs_MakeConstraint(
- SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(),
- 0.0, aBaseID, aFilletID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- aCoincConstr.h = myStorage->addConstraint(aCoincConstr);
- mySlvsConstraints.push_back(aCoincConstr.h);
-
- // another point of fillet object should be placed on the base object
- Slvs_Constraint aPonCurveConstr;
- if (anEntities[indEnt].type == SLVS_E_ARC_OF_CIRCLE) {
- // centers of arcs should be coincident
- aBaseID = anEntities[indEnt].point[0];
- aFilletID = anEntities[2 + indEnt].point[0];
- aPonCurveConstr = Slvs_MakeConstraint(
- SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_POINTS_COINCIDENT, myGroup->getWorkplaneId(),
- 0.0, aBaseID, aFilletID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- } else {
- aFilletID = anEntities[2 + indEnt].point[aCoincInd[indEnt]];
- aPonCurveConstr = Slvs_MakeConstraint(
- SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_ON_LINE, myGroup->getWorkplaneId(),
- 0.0, aFilletID, SLVS_E_UNKNOWN, anEntities[indEnt].h, SLVS_E_UNKNOWN);
- }
- aPonCurveConstr.h = myStorage->addConstraint(aPonCurveConstr);
- mySlvsConstraints.push_back(aPonCurveConstr.h);
- }
-}
-
-bool SketchSolver_ConstraintFillet::remove(ConstraintPtr theConstraint)
-{
- cleanErrorMsg();
- if (theConstraint && theConstraint != myBaseConstraint)
- return false;
- bool isFullyRemoved = true;
- std::vector<Slvs_hEntity>::iterator aCIter = mySlvsConstraints.begin();
- for (; aCIter != mySlvsConstraints.end(); aCIter++)
- isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
- mySlvsConstraints.clear();
-
- if (isFullyRemoved) {
- myFeatureMap.clear();
- myAttributeMap.clear();
- myValueMap.clear();
- } else
- cleanRemovedEntities();
- return true;
-}
-
+++ /dev/null
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File: SketchSolver_ConstraintFillet.h
-// Created: 1 Apr 2015
-// Author: Artem ZHIDKOV
-
-#ifndef SketchSolver_ConstraintFillet_H_
-#define SketchSolver_ConstraintFillet_H_
-
-#include "SketchSolver.h"
-#include <SketchSolver_Constraint.h>
-
-/** \class SketchSolver_ConstraintFillet
- * \ingroup Plugins
- * \brief Convert fillet constraint to SolveSpace structure
- */
-class SketchSolver_ConstraintFillet : public SketchSolver_Constraint
-{
-public:
- /// Constructor based on SketchPlugin constraint
- SketchSolver_ConstraintFillet(ConstraintPtr theConstraint) :
- SketchSolver_Constraint(theConstraint)
- {}
-
- virtual int getType() const
- { return SLVS_C_FILLET; }
-
- /// \brief Tries to remove constraint
- /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
- virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
-
-protected:
- /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
- virtual void process();
-
- /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
- /// \param[out] theValue numerical characteristic of constraint (e.g. distance)
- /// \param[out] theAttributes list of attributes to be filled
- ///
- /// Parameter theAttributes contains 5 elements:
- /// Two first entities in theAttributes list correspond to base features of fillet,
- /// the next two entities represent trimmed base features and the last one is a fillet arc.
- virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
-};
-
-#endif
--- /dev/null
+#include <SketchSolver_ConstraintFixed.h>
+#include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_ConstraintRigid.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_AttributeDouble.h>
+
+#include <math.h>
+
+SketchSolver_ConstraintFixed::SketchSolver_ConstraintFixed(ConstraintPtr theConstraint)
+ : SketchSolver_Constraint()
+{
+ myBaseConstraint = theConstraint;
+ myType = CONSTRAINT_FIXED;
+ myFixedAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+ theConstraint->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
+}
+
+SketchSolver_ConstraintFixed::SketchSolver_ConstraintFixed(FeaturePtr theFeature)
+ : SketchSolver_Constraint(),
+ myBaseFeature(theFeature)
+{
+ myType = CONSTRAINT_FIXED;
+ process();
+}
+
+void SketchSolver_ConstraintFixed::process()
+{
+ cleanErrorMsg();
+ if ((!myBaseConstraint && !myBaseFeature) || !myStorage || myGroupID == GID_UNKNOWN) {
+ // Not enough parameters are assigned
+ return;
+ }
+
+ ParameterWrapperPtr aValue;
+ std::vector<EntityWrapperPtr> anEntities;
+ getAttributes(aValue, anEntities);
+ if (!myErrorMsg.empty() || anEntities.empty())
+ return;
+ fixFeature(anEntities.front());
+}
+
+void SketchSolver_ConstraintFixed::fixFeature(EntityWrapperPtr theFeature)
+{
+ // extract feature from the group
+ if (theFeature->baseAttribute())
+ myStorage->update(theFeature->baseAttribute(), GID_OUTOFGROUP);
+ else
+ myStorage->update(theFeature->baseFeature(), GID_OUTOFGROUP);
+}
+
+void SketchSolver_ConstraintFixed::getAttributes(
+ ParameterWrapperPtr& theValue,
+ std::vector<EntityWrapperPtr>& theAttributes)
+{
+ BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+
+ EntityWrapperPtr aSolverEntity;
+ if (myBaseFeature) {
+ // The feature is fixed.
+ myStorage->update(myBaseFeature, myGroupID);
+ aSolverEntity = myStorage->entity(myBaseFeature);
+ } else if (myBaseConstraint) {
+ // Constraint Fixed is added by user.
+ // Get the attribute of constraint (it should be alone in the list of constraints).
+ AttributePtr anAttr = myBaseConstraint->attribute(SketchPlugin_ConstraintRigid::ENTITY_A());
+ AttributeRefAttrPtr aRefAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttr);
+ if (!aRefAttr || !aRefAttr->isInitialized()) {
+ myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+ return;
+ }
+
+ myStorage->update(anAttr, myGroupID);
+ aSolverEntity = myStorage->entity(anAttr);
+ } else
+ myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
+
+ if (aSolverEntity)
+ theAttributes.push_back(aSolverEntity);
+}
+
+
+bool SketchSolver_ConstraintFixed::remove()
+{
+ cleanErrorMsg();
+ // Move fixed entities back to the current group
+ FeaturePtr aFeature = myBaseFeature;
+ if (myBaseConstraint && myFixedAttribute && myFixedAttribute->isObject())
+ aFeature = ModelAPI_Feature::feature(myFixedAttribute->object());
+ if (aFeature)
+ myStorage->update(aFeature, myGroupID);
+
+ // Remove constraint or base feature
+ if (myBaseConstraint) {
+ bool isRemoved = false;
+ if (aFeature)
+ isRemoved = myStorage->removeEntity(aFeature);
+ return SketchSolver_Constraint::remove() || isRemoved;
+ } else if (myBaseFeature)
+ myStorage->removeEntity(myBaseFeature);
+ return true;
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_ConstraintFixed.h
+// Created: 30 Mar 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_ConstraintFixed_H_
+#define SketchSolver_ConstraintFixed_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Constraint.h>
+
+/** \class SketchSolver_ConstraintFixed
+ * \ingroup Plugins
+ * \brief Stores data of the Fixed constraint
+ *
+ * Fixed constraint may have NULL basic SketchPlugin constraint,
+ * because the Fixed constraint may be temporary for correct moving of objects.
+ *
+ * Fixed constraint does not create a constraint, but builds the entities in separate group,
+ * so they will not be moved while resolving the set of constraints.
+ */
+class SketchSolver_ConstraintFixed : public SketchSolver_Constraint
+{
+public:
+ /// Creates constraint to manage the given constraint from plugin
+ SketchSolver_ConstraintFixed(ConstraintPtr theConstraint);
+ /// Creates temporary constraint based on feature
+ SketchSolver_ConstraintFixed(FeaturePtr theFeature);
+
+ /// \brief Tries to remove constraint
+ /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
+ virtual bool remove();
+
+protected:
+ /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
+ virtual void process();
+
+ /// \brief Generate list of attributes of constraint in order useful for constraints
+ /// \param[out] theValue numerical characteristic of constraint (e.g. distance)
+ /// \param[out] theAttributes list of attributes to be filled
+ virtual void getAttributes(ParameterWrapperPtr& theValue, std::vector<EntityWrapperPtr>& theAttributes);
+
+ /// \brief Fixed feature basing on its type
+ /// \param theFeature [in] feature, converted to solver specific format
+ virtual void fixFeature(EntityWrapperPtr theFeature);
+
+protected:
+ FeaturePtr myBaseFeature; ///< fixed feature (when it is set, myBaseConstraint should be NULL)
+
+private:
+ AttributeRefAttrPtr myFixedAttribute; ///< attribute of a fixed constraint (for correct remove)
+};
+
+#endif
#include <SketchSolver_ConstraintLength.h>
-#include <SketchSolver_Group.h>
#include <SketchSolver_Error.h>
-void SketchSolver_ConstraintLength::process()
+void SketchSolver_ConstraintLength::getAttributes(
+ double& theValue,
+ std::vector<EntityWrapperPtr>& theAttributes)
{
- cleanErrorMsg();
- if (!myBaseConstraint || !myStorage || myGroup == 0) {
- /// TODO: Put error message here
+ SketchSolver_Constraint::getAttributes(theValue, theAttributes);
+ if (!myErrorMsg.empty() || !theAttributes[2] ||
+ theAttributes[2]->type() != ENTITY_LINE) {
+ theAttributes.clear();
return;
}
- if (!mySlvsConstraints.empty()) // some data is changed, update constraint
- update(myBaseConstraint);
- double aValue;
- std::vector<Slvs_hEntity> anEntities;
- getAttributes(aValue, anEntities);
- if (!myErrorMsg.empty())
- return;
-
- // Check the entity is a line
- Slvs_Entity aLine = myStorage->getEntity(anEntities[2]);
- if (aLine.type != SLVS_E_LINE_SEGMENT){
- myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
- return;
- }
+ // Get boundary points of line segment and create point-point distance constraint
+ std::list<EntityWrapperPtr> aSubs = theAttributes[2]->subEntities();
+ theAttributes.assign(theAttributes.size(), EntityWrapperPtr());
+ std::vector<EntityWrapperPtr>::iterator anAttrIt = theAttributes.begin();
+ std::list<EntityWrapperPtr>::const_iterator aSubIt = aSubs.begin();
+ for (; aSubIt != aSubs.end(); ++aSubIt, ++anAttrIt)
+ *anAttrIt = *aSubIt;
- Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
- getType(), myGroup->getWorkplaneId(), aValue,
- aLine.point[0], aLine.point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- aConstraint.h = myStorage->addConstraint(aConstraint);
- mySlvsConstraints.push_back(aConstraint.h);
- adjustConstraint();
-}
-
-void SketchSolver_ConstraintLength::adjustConstraint()
-{
- // No need to store the line, which length is constrained
- // Upd: The line need to be stored to check that constraint
- // is changed/unchanged during modifications in GUI
- //myFeatureMap.clear();
+ myType = CONSTRAINT_PT_PT_DISTANCE;
}
SketchSolver_Constraint(theConstraint)
{}
- virtual int getType() const
- { return SLVS_C_PT_PT_DISTANCE; }
-
protected:
- /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
- virtual void process();
-
- /// \brief This method is used in derived objects to check consistence of constraint.
- /// E.g. the distance between line and point may be signed.
- virtual void adjustConstraint();
+ /// \brief Generate list of attributes of constraint in order useful for constraints
+ /// \param[out] theValue numerical characteristic of constraint (e.g. distance)
+ /// \param[out] theAttributes list of attributes to be filled
+ virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes);
};
#endif
+++ /dev/null
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File: SketchSolver_ConstraintManager.cpp
-// Created: 08 May 2014
-// Author: Artem ZHIDKOV
-
-#include "SketchSolver_ConstraintManager.h"
-
-#include <Events_Loop.h>
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_Data.h>
-#include <ModelAPI_Events.h>
-#include <ModelAPI_Object.h>
-#include <ModelAPI_ResultConstruction.h>
-#include <ModelAPI_Attribute.h>
-
-#include <SketchPlugin_Constraint.h>
-
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_Circle.h>
-#include <SketchPlugin_Line.h>
-#include <SketchPlugin_Point.h>
-#include <SketchPlugin_Sketch.h>
-#include <SketchPlugin_Feature.h>
-
-#include <list>
-#include <set>
-#include <memory>
-
-// Initialization of constraint manager self pointer
-SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::_self = 0;
-
-/// Global constraint manager object
-SketchSolver_ConstraintManager* myManager = SketchSolver_ConstraintManager::Instance();
-
-
-// ========================================================
-// ========= SketchSolver_ConstraintManager ===============
-// ========================================================
-SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::Instance()
-{
- if (!_self)
- _self = new SketchSolver_ConstraintManager();
- return _self;
-}
-
-SketchSolver_ConstraintManager::SketchSolver_ConstraintManager()
-{
- myGroups.clear();
- myIsComputed = false;
-
- // Register in event loop
- Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
- Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
- Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
- Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED));
-}
-
-SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
-{
- myGroups.clear();
-}
-
-// ============================================================================
-// Function: processEvent
-// Class: SketchSolver_Session
-// Purpose: listen the event loop and process the message
-// ============================================================================
-void SketchSolver_ConstraintManager::processEvent(
- const std::shared_ptr<Events_Message>& theMessage)
-{
- if (myIsComputed)
- return;
- if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)
- || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)
- || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) {
- std::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
- std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
- std::set<ObjectPtr> aFeatures = anUpdateMsg->objects();
-
- // Shows the message has at least one feature applicable for solver
- bool hasProperFeature = false;
-
- bool isMovedEvt = theMessage->eventID()
- == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED);
- if (isMovedEvt) {
- std::set<ObjectPtr>::iterator aFeatIter;
- for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
- std::shared_ptr<SketchPlugin_Feature> aSFeature =
- std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
- if (aSFeature) {
- moveEntity(aSFeature);
- hasProperFeature = true;
- }
- }
- } else {
- std::list<FeaturePtr> aSketchFeatures = SketchSolver_Group::selectApplicableFeatures(aFeatures);
- std::list<FeaturePtr>::iterator aFeatIter = aSketchFeatures.begin();
- for (; aFeatIter != aSketchFeatures.end(); ++aFeatIter) {
- if ((*aFeatIter)->getKind() == SketchPlugin_Sketch::ID()) {
- std::shared_ptr<ModelAPI_CompositeFeature> aSketch =
- std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aFeatIter);
- hasProperFeature = changeWorkplane(aSketch) || hasProperFeature;
- continue;
- }
- std::shared_ptr<SketchPlugin_Feature> aFeature =
- std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
- if (!aFeature)
- continue;
- hasProperFeature = changeConstraintOrEntity(aFeature) || hasProperFeature;
- }
- }
-
- // Solve the set of constraints
- if (hasProperFeature)
- resolveConstraints(isMovedEvt); // send update for movement in any case
- } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
- std::shared_ptr<ModelAPI_ObjectDeletedMessage> aDeleteMsg =
- std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
- const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
-
- // Find SketchPlugin_Sketch::ID() in groups. The constraint groups should be updated when an object removed from Sketch
- std::set<std::string>::const_iterator aFGrIter;
- for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
- if (aFGrIter->compare(ModelAPI_ResultConstruction::group()) == 0 ||
- aFGrIter->compare(ModelAPI_Feature::group()) == 0)
- break;
-
- if (aFGrIter != aFeatureGroups.end()) {
- std::vector<SketchSolver_Group*>::iterator aGroupIter = myGroups.begin();
- std::vector<SketchSolver_Group*> aSeparatedGroups;
- while (aGroupIter != myGroups.end()) {
- if (!(*aGroupIter)->isWorkplaneValid()) { // the group should be removed
- delete *aGroupIter;
- int aShift = aGroupIter - myGroups.begin();
- myGroups.erase(aGroupIter);
- aGroupIter = myGroups.begin() + aShift;
- continue;
- }
- if (!(*aGroupIter)->isConsistent()) { // some constraints were removed, try to split the group
- (*aGroupIter)->splitGroup(aSeparatedGroups);
- }
- aGroupIter++;
- }
- if (aSeparatedGroups.size() > 0)
- myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end());
- }
- }
-}
-
-// ============================================================================
-// Function: changeWorkplane
-// Class: SketchSolver_Session
-// Purpose: update workplane by given parameters of the sketch
-// ============================================================================
-bool SketchSolver_ConstraintManager::changeWorkplane(CompositeFeaturePtr theSketch)
-{
- bool aResult = true; // changed when a workplane wrongly updated
- bool isUpdated = false;
- // Try to update specified workplane in all groups
- std::vector<SketchSolver_Group*>::iterator aGroupIter;
- for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
- if ((*aGroupIter)->isBaseWorkplane(theSketch)) {
- isUpdated = true;
- if (!(*aGroupIter)->updateWorkplane())
- aResult = false;
- }
- // If the workplane is not updated, so this is a new workplane
- if (!isUpdated) {
- SketchSolver_Group* aNewGroup = new SketchSolver_Group(theSketch);
- // Verify that the group is created successfully
- if (!aNewGroup->isBaseWorkplane(theSketch) || !aNewGroup->isWorkplaneValid()) {
- delete aNewGroup;
- return false;
- }
- myGroups.push_back(aNewGroup);
- }
- return aResult;
-}
-
-// ============================================================================
-// Function: changeConstraintOrEntity
-// Class: SketchSolver_Session
-// Purpose: create/update the constraint or the feature and place it into appropriate group
-// ============================================================================
-bool SketchSolver_ConstraintManager::changeConstraintOrEntity(
- std::shared_ptr<SketchPlugin_Feature> theFeature)
-{
- // Search the groups which this feature touches
- std::set<Slvs_hGroup> aGroups;
- findGroups(theFeature, aGroups);
-
- std::shared_ptr<SketchPlugin_Constraint> aConstraint =
- std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
-
- // Process the groups list
- if (aGroups.size() == 0) {
- // There are no groups applicable for this constraint => create new one
- // The group will be created only for constraints, not for features
- if (!aConstraint) return false;
- std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(aConstraint);
- if (!aWP)
- return false;
- SketchSolver_Group* aGroup = new SketchSolver_Group(aWP);
- if (!aGroup->changeConstraint(aConstraint)) {
- delete aGroup;
- return false;
- }
- myGroups.push_back(aGroup);
- return true;
- } else if (aGroups.size() == 1) { // Only one group => add feature into it
- Slvs_hGroup aGroupId = *(aGroups.begin());
- std::vector<SketchSolver_Group*>::iterator aGroupIter;
- for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
- if ((*aGroupIter)->getId() == aGroupId) {
- // If the group is empty, the feature is not added (the constraint only)
- if (!aConstraint && !(*aGroupIter)->isEmpty())
- return (*aGroupIter)->updateFeature(theFeature);
- return (*aGroupIter)->changeConstraint(aConstraint);
- }
- } else if (aGroups.size() > 1) { // Several groups applicable for this feature => need to merge them
- std::set<Slvs_hGroup>::const_iterator aGroupsIter = aGroups.begin();
-
- // Search first group
- std::vector<SketchSolver_Group*>::iterator aFirstGroupIter;
- for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
- if ((*aFirstGroupIter)->getId() == *aGroupsIter)
- break;
- if (aFirstGroupIter == myGroups.end())
- return false;
-
- // Append other groups to the first one
- std::vector<SketchSolver_Group*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
- for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) {
- for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
- if ((*anOtherGroupIter)->getId() == *aGroupsIter)
- break;
- if (anOtherGroupIter == myGroups.end()) { // Group disappears
- anOtherGroupIter = aFirstGroupIter + 1;
- continue;
- }
-
- (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter);
- int aShiftFirst = aFirstGroupIter - myGroups.begin();
- int aShiftOther = anOtherGroupIter - myGroups.begin();
- delete *anOtherGroupIter;
- myGroups.erase(anOtherGroupIter);
- aFirstGroupIter = myGroups.begin() + aShiftFirst;
- anOtherGroupIter = myGroups.begin() + aShiftOther;
- }
-
- if (aConstraint)
- return (*aFirstGroupIter)->changeConstraint(aConstraint);
- return (*aFirstGroupIter)->updateFeature(theFeature);
- }
-
- // Something goes wrong
- return false;
-}
-
-// ============================================================================
-// Function: moveEntity
-// Class: SketchSolver_Session
-// Purpose: update element moved on the sketch, which is used by constraints
-// ============================================================================
-void SketchSolver_ConstraintManager::moveEntity(
- std::shared_ptr<SketchPlugin_Feature> theFeature)
-{
- std::vector<SketchSolver_Group*>::iterator aGroupIt = myGroups.begin();
- for (; aGroupIt != myGroups.end(); aGroupIt++)
- if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature))
- (*aGroupIt)->moveFeature(theFeature);
-}
-
-// ============================================================================
-// Function: findGroups
-// Class: SketchSolver_Session
-// Purpose: search groups of entities interacting with given feature
-// ============================================================================
-void SketchSolver_ConstraintManager::findGroups(
- std::shared_ptr<SketchPlugin_Feature> theFeature,
- std::set<Slvs_hGroup>& theGroupIDs) const
-{
- std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(theFeature);
-
- SketchSolver_Group* anEmptyGroup = 0; // appropriate empty group for specified constraint
- std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
- for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
- if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) {
- if (!(*aGroupIter)->isEmpty())
- theGroupIDs.insert((*aGroupIter)->getId());
- else if (!anEmptyGroup)
- anEmptyGroup = *aGroupIter;
- }
-
- // When only empty group is found, use it
- if (anEmptyGroup && theGroupIDs.empty())
- theGroupIDs.insert(anEmptyGroup->getId());
-}
-
-// ============================================================================
-// Function: findWorkplane
-// Class: SketchSolver_Session
-// Purpose: search workplane containing given feature
-// ============================================================================
-std::shared_ptr<ModelAPI_CompositeFeature> SketchSolver_ConstraintManager
-::findWorkplane(std::shared_ptr<SketchPlugin_Feature> theFeature) const
-{
- // Already verified workplanes
- std::set<std::shared_ptr<ModelAPI_CompositeFeature> > aVerified;
-
- std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
- for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
- std::shared_ptr<ModelAPI_CompositeFeature> aWP = (*aGroupIter)->getWorkplane();
- if (aVerified.find(aWP) != aVerified.end())
- continue;
-
- DataPtr aData = aWP->data();
- if (aData->isValid()) {
- std::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures = std::dynamic_pointer_cast<
- ModelAPI_AttributeRefList>(aData->attribute(SketchPlugin_Sketch::FEATURES_ID()));
- std::list<ObjectPtr> aFeaturesList = aWPFeatures->list();
- std::list<ObjectPtr>::const_iterator anIter;
- for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
- if (*anIter == theFeature)
- return aWP; // workplane is found
- }
- aVerified.insert(aWP);
- }
-
- return std::shared_ptr<ModelAPI_CompositeFeature>();
-}
-
-// ============================================================================
-// Function: resolveConstraints
-// Class: SketchSolver_Session
-// Purpose: change entities according to available constraints
-// ============================================================================
-void SketchSolver_ConstraintManager::resolveConstraints(const bool theForceUpdate)
-{
- myIsComputed = true;
- bool needToUpdate = false;
- static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
- // to avoid redisplay of each segment on update by solver one by one in the viewer
- bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
- if (isUpdateFlushed) {
- Events_Loop::loop()->setFlushed(anUpdateEvent, false);
- }
-
- std::vector<SketchSolver_Group*>::iterator aGroupIter;
- for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
- if ((*aGroupIter)->resolveConstraints())
- needToUpdate = true;
-
- // Features may be updated => now send events, but for all changed at once
- if (isUpdateFlushed) {
- Events_Loop::loop()->setFlushed(anUpdateEvent, true);
- }
- // Must be before flush because on "Updated" flush the results may be produced
- // and the creation event is appeared with many new objects. If myIsComputed these
- // events are missed in processEvents and some elements are not added.
- myIsComputed = false;
- if (needToUpdate || theForceUpdate)
- Events_Loop::loop()->flush(anUpdateEvent);
-}
-
+++ /dev/null
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File: SketchSolver_ConstraintManager.h
-// Created: 08 May 2014
-// Author: Artem ZHIDKOV
-
-#ifndef SketchSolver_ConstraintManager_H_
-#define SketchSolver_ConstraintManager_H_
-
-#include "SketchSolver.h"
-#include <SketchSolver_Solver.h>
-#include <SketchSolver_Group.h>
-
-#include <Events_Listener.h>
-#include <SketchPlugin_Constraint.h>
-
-#include <string.h>
-#include <slvs.h>
-
-#include <list>
-#include <map>
-#include <vector>
-#include <set>
-
-/** \class SketchSolver_ConstraintManager
- * \ingroup Plugins
- * \brief Listens the changes of SketchPlugin features and transforms the Constraint
- * feature into the format understandable by SolveSpace library.
- *
- * Constraints created for SolveSpace library are divided into the groups.
- * The division order based on connectedness of the features by the constraints.
- * The groups may be fused or separated according to the new constraints.
- *
- * \remark This is a singleton.
- */
-class SketchSolver_ConstraintManager : public Events_Listener
-{
- public:
- /** \brief Main method to create constraint manager
- * \return pointer to the singleton
- */
- static SketchSolver_ConstraintManager* Instance();
-
- /** \brief Implementation of Event Listener method
- * \param[in] theMessage the data of the event
- */
- virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage);
-
- protected:
- SketchSolver_ConstraintManager();
- ~SketchSolver_ConstraintManager();
-
- /** \brief Adds or updates a constraint or an entity in the suitable group
- * \param[in] theFeature sketch feature to be changed
- * \return \c true if the feature changed successfully
- */
- bool changeConstraintOrEntity(std::shared_ptr<SketchPlugin_Feature> theFeature);
-
- /** \brief Removes a constraint from the manager
- * \param[in] theConstraint constraint to be removed
- * \return \c true if the constraint removed successfully
- */
- bool removeConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
-
- /** \brief Adds or updates a workplane in the manager
- * \param[in] theSketch the feature to create or update workplane
- * \return \c true if the workplane changed successfully
- * \remark Type of theSketch is not verified inside
- */
- bool changeWorkplane(CompositeFeaturePtr theSketch);
-
- /** \brief Removes a workplane from the manager.
- * All groups based on such workplane will be removed too.
- * \param[in] theSketch the feature to be removed
- * \return \c true if the workplane removed successfully
- */
- bool removeWorkplane(std::shared_ptr<SketchPlugin_Sketch> theSketch);
-
- /** \brief Updates entity which is moved in GUI
- * \param[in] theFeature entity to be updated
- */
- void moveEntity(std::shared_ptr<SketchPlugin_Feature> theFeature);
-
- /** \brief Goes through the list of groups and solve the constraints
- * \param theForceUpdate flushes the update event in any case: something changed or not
- */
- void resolveConstraints(const bool theForceUpdate);
-
- private:
- /** \brief Searches list of groups which interact with specified feature
- * \param[in] theFeature object to be found
- * \param[out] theGroups list of group indexes interacted with the feature
- */
- void findGroups(std::shared_ptr<SketchPlugin_Feature> theFeature,
- std::set<Slvs_hGroup>& theGroupIDs) const;
-
- /** \brief Searches in the list of groups the workplane which constains specified feature
- * \param[in] theFeature object to be found
- * \return workplane containing the feature
- */
- std::shared_ptr<ModelAPI_CompositeFeature> findWorkplane(
- std::shared_ptr<SketchPlugin_Feature> theFeature) const;
-
- private:
- static SketchSolver_ConstraintManager* _self; ///< Self pointer to implement singleton functionality
- std::vector<SketchSolver_Group*> myGroups; ///< Groups of constraints
- /// true if computation is performed and all "updates" are generated by this algo
- /// and needs no recomputation
- bool myIsComputed;
-};
-
-#endif
#include <SketchSolver_ConstraintMirror.h>
-#include <SketchSolver_Group.h>
#include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeRefAttr.h>
#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_ResultConstruction.h>
-
-#include <GeomAPI_Dir2d.h>
-#include <GeomAPI_XY.h>
-
-#include <cmath>
void SketchSolver_ConstraintMirror::getAttributes(
- Slvs_Entity& theMirrorLine,
- std::vector<Slvs_Entity>& theBaseEntities,
- std::vector<Slvs_Entity>& theMirrorEntities)
+ EntityWrapperPtr& theMirrorLine,
+ std::vector<EntityWrapperPtr>& theBaseEntities,
+ std::vector<EntityWrapperPtr>& theMirrorEntities)
{
- DataPtr aData = myBaseConstraint->data();
- AttributeRefAttrPtr aMirLineAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- if (!aMirLineAttr || !aMirLineAttr->isInitialized() || !aMirLineAttr->isObject()) {
+ AttributePtr aMirLineAttr = myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A());
+ AttributeRefAttrPtr aMirLineRefAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(aMirLineAttr);
+ if (!aMirLineRefAttr || !aMirLineRefAttr->isInitialized() || !aMirLineRefAttr->isObject()) {
myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
return;
}
- int aType = SLVS_E_UNKNOWN; // type of created entity
- Slvs_hEntity anEntity = myGroup->getAttributeId(aMirLineAttr);
- if (anEntity == SLVS_E_UNKNOWN)
- anEntity = changeEntity(aMirLineAttr, aType);
- theMirrorLine = myStorage->getEntity(anEntity);
+
+ myType = TYPE(myBaseConstraint);
+ myStorage->update(aMirLineAttr, myGroupID);
+ theMirrorLine = myStorage->entity(aMirLineAttr);
// Create SolveSpace entity for all features
AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
FeaturePtr aFeature;
- ResultConstructionPtr aRC;
for (int i = 0; i < 2; i++) {
std::list<ObjectPtr>::iterator anIter = i == 0 ? aBaseList.begin() : aMirroredList.begin();
std::list<ObjectPtr>::iterator aEndIter = i == 0 ? aBaseList.end() : aMirroredList.end();
- std::vector<Slvs_Entity>* aList = i == 0 ? &theBaseEntities : & theMirrorEntities;
+ std::vector<EntityWrapperPtr>* aList = i == 0 ? &theBaseEntities : & theMirrorEntities;
for ( ; anIter != aEndIter; anIter++) {
- aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*anIter);
- aFeature = aRC ? aRC->document()->feature(aRC) :
- std::dynamic_pointer_cast<ModelAPI_Feature>(*anIter);
+ aFeature = ModelAPI_Feature::feature(*anIter);
if (!aFeature)
continue;
- anEntity = changeEntity(aFeature, aType);
- // Sort entities by their type
- std::vector<Slvs_Entity>::iterator anIt = aList->begin();
- for (; anIt != aList->end(); anIt++)
- if (aType < anIt->type)
- break;
-// aList->push_back(myStorage->getEntity(anEntity));
- aList->insert(anIt, myStorage->getEntity(anEntity));
+ myStorage->update(aFeature, myGroupID);
+ aList->push_back(myStorage->entity(aFeature));
}
}
void SketchSolver_ConstraintMirror::process()
{
cleanErrorMsg();
- if (!myBaseConstraint || !myStorage || myGroup == 0) {
- /// TODO: Put error message here
+ if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) {
+ // Not enough parameters are assigned
return;
}
- if (!mySlvsConstraints.empty()) // some data is changed, update constraint
- update(myBaseConstraint);
- Slvs_Entity aMirrorLine;
- std::vector<Slvs_Entity> aBaseList;
- std::vector<Slvs_Entity> aMirrorList;
+ EntityWrapperPtr aMirrorLine;
+ std::vector<EntityWrapperPtr> aBaseList;
+ std::vector<EntityWrapperPtr> aMirrorList;
getAttributes(aMirrorLine, aBaseList, aMirrorList);
if (!myErrorMsg.empty())
return;
return;
}
- Slvs_Constraint aConstraint;
- // Get coordinates of mirror line points for speed up
- double aStartEnd[4];
- for (int i = 0; i < 2; i++) {
- Slvs_Entity aPoint = myStorage->getEntity(aMirrorLine.point[i]);
- for (int j = 0; j < 2; j++)
- aStartEnd[2*i+j] = myStorage->getParameter(aPoint.param[j]).val;
- }
-
- std::vector<Slvs_Entity>::iterator aBaseIter = aBaseList.begin();
- std::vector<Slvs_Entity>::iterator aMirrorIter = aMirrorList.begin();
- for (; aBaseIter != aBaseList.end(); aBaseIter++, aMirrorIter++) {
- // Make aMirrorEnt parameters to be symmetric with aBaseEnt
- makeMirrorEntity(*aBaseIter, *aMirrorIter, aStartEnd);
-
- if (aBaseIter->type == SLVS_E_POINT_IN_2D) {
- aConstraint = Slvs_MakeConstraint(
- SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(),
- 0.0, aBaseIter->h, aMirrorIter->h, aMirrorLine.h, SLVS_E_UNKNOWN);
- aConstraint.h = myStorage->addConstraint(aConstraint);
- mySlvsConstraints.push_back(aConstraint.h);
- } else if (aBaseIter->type == SLVS_E_LINE_SEGMENT) {
- for (int i = 0; i < 2; i++) {
- aConstraint = Slvs_MakeConstraint(
- SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0,
- aBaseIter->point[i], aMirrorIter->point[i], aMirrorLine.h, SLVS_E_UNKNOWN);
- aConstraint.h = myStorage->addConstraint(aConstraint);
- mySlvsConstraints.push_back(aConstraint.h);
- }
- } else if (aBaseIter->type == SLVS_E_CIRCLE) {
- aConstraint = Slvs_MakeConstraint(
- SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0,
- aBaseIter->point[0], aMirrorIter->point[0], aMirrorLine.h, SLVS_E_UNKNOWN);
- aConstraint.h = myStorage->addConstraint(aConstraint);
- mySlvsConstraints.push_back(aConstraint.h);
- // Additional constraint for equal radii
- Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint(
- SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_EQUAL_RADIUS, myGroup->getWorkplaneId(),
- 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseIter->h, aMirrorIter->h);
- anEqRadConstr.h = myStorage->addConstraint(anEqRadConstr);
- mySlvsConstraints.push_back(anEqRadConstr.h);
- } else if (aBaseIter->type == SLVS_E_ARC_OF_CIRCLE) {
- // Workaround to avoid problems in SolveSpace.
- // The symmetry of two arcs will be done using symmetry of three points on these arcs:
- // start point, end point, and any other point on the arc
- Slvs_hEntity aBaseArcPoints[3] = {
- aBaseIter->point[1],
- aBaseIter->point[2],
- SLVS_E_UNKNOWN};
- Slvs_hEntity aMirrorArcPoints[3] = { // indices of points of arc, center corresponds center, first point corresponds last point
- aMirrorIter->point[2],
- aMirrorIter->point[1],
- SLVS_E_UNKNOWN};
-
- Slvs_Entity aBothArcs[2] = {*aBaseIter, *aMirrorIter};
- Slvs_hEntity aBothMiddlePoints[2];
- for (int i = 0; i < 2; i++) {
- double x, y;
- calculateMiddlePoint(aBothArcs[i], 0.5, x, y);
- Slvs_Param aParamX = Slvs_MakeParam(SLVS_E_UNKNOWN, myGroup->getId(), x);
- Slvs_Param aParamY = Slvs_MakeParam(SLVS_E_UNKNOWN, myGroup->getId(), y);
- aParamX.h = myStorage->addParameter(aParamX);
- aParamY.h = myStorage->addParameter(aParamY);
- Slvs_Entity aPoint = Slvs_MakePoint2d(SLVS_E_UNKNOWN, myGroup->getId(),
- myGroup->getWorkplaneId(), aParamX.h, aParamY.h);
- aBothMiddlePoints[i] = myStorage->addEntity(aPoint);
- // additional constraint point-on-curve
- Slvs_Constraint aPonCircConstr = Slvs_MakeConstraint(
- SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_ON_CIRCLE, myGroup->getWorkplaneId(),
- 0.0, aBothMiddlePoints[i], SLVS_E_UNKNOWN, aBothArcs[i].h, SLVS_E_UNKNOWN);
- aPonCircConstr.h = myStorage->addConstraint(aPonCircConstr);
- mySlvsConstraints.push_back(aPonCircConstr.h);
- if (i == 0) {
- // additional constraint for the point to be in the middle of a base arc
- Slvs_Entity aLine1 = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
- myGroup->getWorkplaneId(), aBothArcs[i].point[1], aBothMiddlePoints[i]);
- aLine1.h = myStorage->addEntity(aLine1);
- Slvs_Entity aLine2 = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
- myGroup->getWorkplaneId(), aBothArcs[i].point[2], aBothMiddlePoints[i]);
- aLine2.h = myStorage->addEntity(aLine2);
- Slvs_Constraint aMiddleConstr = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
- SLVS_C_EQUAL_LENGTH_LINES, myGroup->getWorkplaneId(),
- 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aLine1.h, aLine2.h);
- aMiddleConstr.h = myStorage->addConstraint(aMiddleConstr);
- mySlvsConstraints.push_back(aMiddleConstr.h);
- }
- }
-
- aBaseArcPoints[2] = aBothMiddlePoints[0];
- aMirrorArcPoints[2] = aBothMiddlePoints[1];
- for (int ind = 0; ind < 3; ind++) {
- Slvs_Constraint aConstraint = Slvs_MakeConstraint(
- SLVS_E_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(), 0.0,
- aBaseArcPoints[ind], aMirrorArcPoints[ind], aMirrorLine.h, SLVS_E_UNKNOWN);
- aConstraint.h = myStorage->addConstraint(aConstraint);
- mySlvsConstraints.push_back(aConstraint.h);
- }
+ std::list<ConstraintWrapperPtr> aNewConstraints;
+ SketchSolver_ConstraintType aConstrType = getType();
+ BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+ std::list<ConstraintWrapperPtr> aMirConstrList;
+
+ std::vector<EntityWrapperPtr>::iterator aBIt = aBaseList.begin();
+ std::vector<EntityWrapperPtr>::iterator aMIt = aMirrorList.begin();
+ for (; aBIt != aBaseList.end(); ++aBIt, ++aMIt) {
+ if ((*aBIt)->type() == ENTITY_ARC) {
+ // add new points on arcs and mirror them
+ EntityWrapperPtr aBasePnt = myStorage->calculateMiddlePoint(*aBIt, 0.5);
+ EntityWrapperPtr aMirrPnt = myStorage->calculateMiddlePoint(*aMIt, 0.5);
+ // point on base arc
+ aNewConstraints = aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID,
+ CONSTRAINT_PT_ON_CIRCLE, 0.0, aBasePnt, EntityWrapperPtr(), *aBIt);
+ aMirConstrList.insert(aMirConstrList.end(), aNewConstraints.begin(), aNewConstraints.end());
+ // point on mirrored arc
+ aNewConstraints = aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID,
+ CONSTRAINT_PT_ON_CIRCLE, 0.0, aMirrPnt, EntityWrapperPtr(), *aMIt);
+ aMirConstrList.insert(aMirConstrList.end(), aNewConstraints.begin(), aNewConstraints.end());
+ // mirror these points
+ aNewConstraints = aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID,
+ aConstrType, 0.0, aBasePnt, aMirrPnt, aMirrorLine);
+ aMirConstrList.insert(aMirConstrList.end(), aNewConstraints.begin(), aNewConstraints.end());
}
+ aNewConstraints = aBuilder->createConstraint(
+ myBaseConstraint, myGroupID, mySketchID, aConstrType,
+ 0.0, *aBIt, *aMIt, aMirrorLine);
+ aMirConstrList.insert(aMirConstrList.end(), aNewConstraints.begin(), aNewConstraints.end());
}
+
+ myStorage->addConstraint(myBaseConstraint, aMirConstrList);
}
-void SketchSolver_ConstraintMirror::update(ConstraintPtr theConstraint)
+void SketchSolver_ConstraintMirror::update()
{
cleanErrorMsg();
- if (!theConstraint || theConstraint == myBaseConstraint) {
- AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_C()));
- if (aMirroredRefList->size() != myNumberOfObjects) {
- remove(myBaseConstraint);
- process();
- return;
- }
+ AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+ myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_C()));
+ if (aMirroredRefList->size() != myNumberOfObjects) {
+ remove();
+ process();
+ return;
}
SketchSolver_Constraint::update();
}
-bool SketchSolver_ConstraintMirror::remove(ConstraintPtr theConstraint)
-{
- cleanErrorMsg();
- if (theConstraint && theConstraint != myBaseConstraint)
- return false;
- bool isFullyRemoved = true;
- std::vector<Slvs_hEntity>::iterator aCIter = mySlvsConstraints.begin();
- for (; aCIter != mySlvsConstraints.end(); aCIter++)
- isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
- mySlvsConstraints.clear();
-
- std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.begin();
- for (; aFeatIt != myFeatureMap.end(); aFeatIt++)
- myStorage->removeEntity(aFeatIt->second);
-
- if (isFullyRemoved) {
- myFeatureMap.clear();
- myAttributeMap.clear();
- myValueMap.clear();
- } else
- cleanRemovedEntities();
- return true;
-}
-
-bool SketchSolver_ConstraintMirror::checkAttributesChanged(ConstraintPtr theConstraint)
-{
- // First of all, check the mirror line is changed.
- // It may be changed to one of mirrored lines, which is already in this constraint
- // (this case is not marked as attribute changing)
- ConstraintPtr aConstraint = theConstraint ? theConstraint : myBaseConstraint;
- AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- if (!aRefAttr || !aRefAttr->isObject() || !aRefAttr->object())
- return true;
- FeaturePtr aMirrorLine = ModelAPI_Feature::feature(aRefAttr->object());
- if (!aMirrorLine)
- return true;
-
- std::map<FeaturePtr, Slvs_hEntity>::iterator aMirrorIter = myFeatureMap.find(aMirrorLine);
- if (aMirrorIter == myFeatureMap.end())
- return true;
-
- // Check the entity is not used as mirror line
- std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
- for (; aCIter != mySlvsConstraints.end(); aCIter++) {
- Slvs_Constraint aMirrorConstr = myStorage->getConstraint(*aCIter);
- if (aMirrorConstr.type != SLVS_C_SYMMETRIC_LINE)
- continue;
- if (aMirrorConstr.entityA != aMirrorIter->second)
- return true;
- else break; // check just one symmetric constraint
- }
-
- // Base verification
- return SketchSolver_Constraint::checkAttributesChanged(theConstraint);
-}
-
-void SketchSolver_ConstraintMirror::makeMirrorEntity(
- const Slvs_Entity& theBase,
- const Slvs_Entity& theMirror,
- const double theMirrorLine[]) const
-{
- Slvs_hEntity aBasePoint[4];
- Slvs_hEntity aMirrorPoint[4];
- for (int i = 0; i < 4; i++) {
- aBasePoint[i] = theBase.point[i];
- aMirrorPoint[i] = theMirror.point[i];
- }
- if (theBase.type == SLVS_E_ARC_OF_CIRCLE) {
- Slvs_hEntity aTmp = aMirrorPoint[2];
- aMirrorPoint[2] = aMirrorPoint[1];
- aMirrorPoint[1] = aTmp;
- adjustArcPoints(theBase);
- }
- if (theBase.type == SLVS_E_POINT_IN_2D || theBase.type == SLVS_E_POINT_IN_3D) {
- aBasePoint[0] = theBase.h;
- aMirrorPoint[0] = theMirror.h;
- }
-
- // Mirror line parameters
- std::shared_ptr<GeomAPI_XY> aLinePoints[2];
- for (int i = 0; i < 2; i++)
- aLinePoints[i] = std::shared_ptr<GeomAPI_XY>(
- new GeomAPI_XY(theMirrorLine[2*i], theMirrorLine[2*i+1]));
- // direction of a mirror line
- std::shared_ptr<GeomAPI_Dir2d> aDir = std::shared_ptr<GeomAPI_Dir2d>(
- new GeomAPI_Dir2d(aLinePoints[1]->added(aLinePoints[0]->multiplied(-1.0))));
- // orthogonal direction
- aDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aDir->y(), -aDir->x()));
-
- Slvs_hConstraint aFixed; // transient variable
- for (int i = 0; i < 4; i++) {
- if (aBasePoint[i] == SLVS_E_UNKNOWN || aMirrorPoint[i] == SLVS_E_UNKNOWN)
- continue;
- // check the mirror point is not fixed
- if (myStorage->isPointFixed(aMirrorPoint[i], aFixed, true))
- continue;
-
- Slvs_Entity aPointEnt = myStorage->getEntity(aBasePoint[i]);
- double aBaseX = myStorage->getParameter(aPointEnt.param[0]).val;
- double aBaseY = myStorage->getParameter(aPointEnt.param[1]).val;
- std::shared_ptr<GeomAPI_XY> aPoint = std::shared_ptr<GeomAPI_XY>(new GeomAPI_XY(aBaseX, aBaseY));
-
- std::shared_ptr<GeomAPI_XY> aVec = std::shared_ptr<GeomAPI_XY>(
- new GeomAPI_XY(aPoint->x() - aLinePoints[0]->x(), aPoint->y() - aLinePoints[0]->y()));
- double aDist = aVec->dot(aDir->xy());
- aPoint = aPoint->added(aDir->xy()->multiplied(-2.0 * aDist));
-
- Slvs_Entity aMirrorEnt = myStorage->getEntity(aMirrorPoint[i]);
- Slvs_Param aParam = Slvs_MakeParam(aMirrorEnt.param[0], myGroup->getId(), aPoint->x());
- myStorage->updateParameter(aParam);
- aParam = Slvs_MakeParam(aMirrorEnt.param[1], myGroup->getId(), aPoint->y());
- myStorage->updateParameter(aParam);
- }
-}
-
-void SketchSolver_ConstraintMirror::adjustArcPoints(const Slvs_Entity& theArc) const
-{
- Slvs_Param aParam;
- Slvs_Entity aPoint;
- double anArcParams[3][2];
- for (int i = 0; i < 3; i++) {
- aPoint = myStorage->getEntity(theArc.point[i]);
- for (int j = 0; j < 2; j++) {
- aParam = myStorage->getParameter(aPoint.param[j]);
- anArcParams[i][j] = aParam.val;
- if (i > 0)
- anArcParams[i][j] -= anArcParams[0][j];
- }
- }
- double aRad2 = anArcParams[1][0] * anArcParams[1][0] + anArcParams[1][1] * anArcParams[1][1];
- double aDist2 = anArcParams[2][0] * anArcParams[2][0] + anArcParams[2][1] * anArcParams[2][1];
- if (std::fabs(aRad2 - aDist2) < tolerance)
- return; // nothing to update (last point already on the arc)
- if (aDist2 < tolerance)
- return; // unable to update
- double aCoeff = std::sqrt(aRad2 / aDist2);
- anArcParams[2][0] *= aCoeff;
- anArcParams[2][1] *= aCoeff;
-
- // Update last point
- aPoint = myStorage->getEntity(theArc.point[2]);
- for (int i = 0; i < 2; i++) {
- aParam = Slvs_MakeParam(aPoint.param[i], myGroup->getId(),
- anArcParams[0][i] + anArcParams[2][i]);
- myStorage->updateParameter(aParam);
- }
-}
-
void SketchSolver_ConstraintMirror::adjustConstraint()
{
- AttributeRefAttrPtr aMirLineAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- if (!aMirLineAttr || !aMirLineAttr->isInitialized() || !aMirLineAttr->isObject()) {
- myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
- return;
- }
- ResultConstructionPtr aRC =
- std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aMirLineAttr->object());
- FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
- std::dynamic_pointer_cast<ModelAPI_Feature>(aMirLineAttr->object());
- std::map<FeaturePtr, Slvs_hEntity>::iterator aMirLineIter = myFeatureMap.find(aFeature);
- if (aMirLineIter == myFeatureMap.end())
- return;
- Slvs_Entity aMirrorLine = myStorage->getEntity(aMirLineIter->second);
-
- Slvs_Constraint aMirror;
- double aStartEnd[4];
- for (int i = 0; i < 2; i++) {
- Slvs_Entity aPoint = myStorage->getEntity(aMirrorLine.point[i]);
- for (int j = 0; j < 2; j++)
- aStartEnd[2*i+j] = myStorage->getParameter(aPoint.param[j]).val;
- }
+ BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
- // Calculate length of the mirror line and create temporary constraint
- double aLength = sqrt((aStartEnd[2] - aStartEnd[0]) * (aStartEnd[2] - aStartEnd[0]) +
- (aStartEnd[3] - aStartEnd[1]) * (aStartEnd[3] - aStartEnd[1]));
- if (aLength < tolerance) {
- if (myMirrorLineLength < 1.0)
- myMirrorLineLength = 1.0;
- } else
- myMirrorLineLength = aLength;
- std::list<Slvs_Constraint> aDist = myStorage->getConstraintsByType(SLVS_C_PT_PT_DISTANCE);
- std::list<Slvs_Constraint>::const_iterator aDIt = aDist.begin();
- for (; aDIt != aDist.end(); ++aDIt)
- if ((aDIt->ptA == aMirrorLine.point[0] && aDIt->ptB == aMirrorLine.point[1]) ||
- (aDIt->ptA == aMirrorLine.point[1] && aDIt->ptB == aMirrorLine.point[0]))
- break; // length of mirror line is already set
- if (aDIt == aDist.end()) {
- // check the points of mirror line is not fixed
- Slvs_hConstraint aFixed;
- if (!myStorage->isPointFixed(aMirrorLine.point[0], aFixed, true) ||
- !myStorage->isPointFixed(aMirrorLine.point[1], aFixed, true)) {
- // Add length constraint
- aMirror = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_PT_DISTANCE,
- myGroup->getWorkplaneId(), aLength, aMirrorLine.point[0], aMirrorLine.point[1],
- SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- aMirror.h = myStorage->addConstraint(aMirror);
- myStorage->addTemporaryConstraint(aMirror.h);
- }
- }
-
- // Search mirror between middle points on the arcs and recompute their coordinates
- std::map<Slvs_hEntity, Slvs_hEntity> aPointsOnCircles;
- std::list<Slvs_Constraint> aMirrorPonCirc;
- std::list<Slvs_Constraint> aPonCirc = myStorage->getConstraintsByType(SLVS_C_PT_ON_CIRCLE);
- std::vector<Slvs_hConstraint>::iterator aConstrIter = mySlvsConstraints.begin();
- for (; aConstrIter != mySlvsConstraints.end(); aConstrIter++) {
- aMirror = myStorage->getConstraint(*aConstrIter);
- if (aMirror.type != SLVS_C_SYMMETRIC_LINE)
- continue;
- if (aMirror.entityA != aMirrorLine.h)
- continue; // don't update another Mirror constraints
- Slvs_Constraint aPonCircA, aPonCircB;
- aPonCircA.h = SLVS_E_UNKNOWN;
- aPonCircB.h = SLVS_E_UNKNOWN;
- std::list<Slvs_Constraint>::iterator aPtIter = aPonCirc.begin();
- for (; aPtIter != aPonCirc.end(); aPtIter++) {
- if (aMirror.ptA == aPtIter->ptA)
- aPonCircA = *aPtIter;
- if (aMirror.ptB == aPtIter->ptA)
- aPonCircB = *aPtIter;
- }
- if (aPonCircA.h == SLVS_E_UNKNOWN || aPonCircB.h == SLVS_E_UNKNOWN)
- continue;
- aMirrorPonCirc.push_back(aMirror);
- // Store point IDs to avoid their recalculation twice
- aPointsOnCircles[aPonCircA.ptA] = aPonCircA.entityA;
- aPointsOnCircles[aPonCircB.ptA] = aPonCircB.entityA;
- }
-
- // Recalculate positions of mirroring points
- std::list<Slvs_Constraint> aMirrorList = myStorage->getConstraintsByType(SLVS_C_SYMMETRIC_LINE);
- std::list<Slvs_Constraint>::iterator aMirIter = aMirrorList.begin();
- for (; aMirIter != aMirrorList.end(); aMirIter++) {
- if (aMirIter->entityA != aMirrorLine.h)
- continue; // don't update another Mirror constraints
- if (aPointsOnCircles.find(aMirIter->ptA) != aPointsOnCircles.end())
- continue; // Avoid mirroring points on circles
- Slvs_Entity aBase = myStorage->getEntity(aMirIter->ptA);
- Slvs_Entity aMirror = myStorage->getEntity(aMirIter->ptB);
- makeMirrorEntity(aBase, aMirror, aStartEnd);
- }
-
- bool aNeedToResolve = myStorage->isNeedToResolve();
- for (aMirIter = aMirrorPonCirc.begin(); aMirIter != aMirrorPonCirc.end(); aMirIter++) {
- // Make centers of arcs symmetric
- Slvs_Entity aBaseArc = myStorage->getEntity(aPointsOnCircles[aMirIter->ptA]);
- Slvs_Entity aBasePoint = myStorage->getEntity(aBaseArc.point[0]);
- Slvs_Entity aMirrorArc = myStorage->getEntity(aPointsOnCircles[aMirIter->ptB]);
- Slvs_Entity aMirrorPoint = myStorage->getEntity(aMirrorArc.point[0]);
- makeMirrorEntity(aBasePoint, aMirrorPoint, aStartEnd);
- // Calculate middle point for base arc and mirrored point on mirror arc
- aBasePoint = myStorage->getEntity(aMirIter->ptA);
- Slvs_Param aParamX = myStorage->getParameter(aBasePoint.param[0]);
- Slvs_Param aParamY = myStorage->getParameter(aBasePoint.param[1]);
- calculateMiddlePoint(aBaseArc, 0.5, aParamX.val, aParamY.val);
- myStorage->updateParameter(aParamX);
- myStorage->updateParameter(aParamY);
- aMirrorPoint = myStorage->getEntity(aMirIter->ptB);
- aParamX = myStorage->getParameter(aMirrorPoint.param[0]);
- aParamY = myStorage->getParameter(aMirrorPoint.param[1]);
- calculateMiddlePoint(aMirrorArc, 0.5, aParamX.val, aParamY.val);
- myStorage->updateParameter(aParamX);
- myStorage->updateParameter(aParamY);
- }
- // Restore previous value to avoid looped recalculations of sketch
- myStorage->setNeedToResolve(aNeedToResolve);
+ const std::list<ConstraintWrapperPtr>& aConstraints = myStorage->constraint(myBaseConstraint);
+ std::list<ConstraintWrapperPtr>::const_iterator aCIt = aConstraints.begin();
+ for (; aCIt != aConstraints.end(); ++aCIt)
+ if ((*aCIt)->type() == CONSTRAINT_SYMMETRIC)
+ aBuilder->adjustConstraint(*aCIt);
}
/// Constructor based on SketchPlugin constraint
SketchSolver_ConstraintMirror(ConstraintPtr theConstraint) :
SketchSolver_Constraint(theConstraint),
- myNumberOfObjects(0),
- myMirrorLineLength(0.0)
+ myNumberOfObjects(0)
{}
- virtual int getType() const
- { return SLVS_C_SYMMETRIC_LINE; }
-
/// \brief Update constraint
- virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
-
- /// \brief Tries to remove constraint
- /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
- virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
+ virtual void update();
protected:
/// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
virtual void process();
- /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
+ /// \brief Generate list of attributes of constraint in order useful for constraints
/// \param[out] theValue numerical characteristic of constraint (e.g. distance)
/// \param[out] theAttributes list of attributes to be filled
- virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes)
+ virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes)
{ /* do nothing here */ }
- /// \brief Verify the attributes of constraint are changed (and constraint need to rebuild)
- /// \param[in] theConstraint constraint, which attributes should be checked (if NULL, the myBaseConstraint is used)
- /// \return \c true if some attributes are changed
- virtual bool checkAttributesChanged(ConstraintPtr theConstraint);
-
/// \brief Generate list of entities of mirror constraint
/// \param[out] theMirrorLine entity corresponding to mirror line
/// \param[out] theBaseEntities list of entities to mirror
/// \param[out] theMirrorEntities list of mirrored entities
- void getAttributes(Slvs_Entity& theMirrorLine,
- std::vector<Slvs_Entity>& theBaseEntities,
- std::vector<Slvs_Entity>& theMirrorEntities);
+ void getAttributes(EntityWrapperPtr& theMirrorLine,
+ std::vector<EntityWrapperPtr>& theBaseEntities,
+ std::vector<EntityWrapperPtr>& theMirrorEntities);
/// \brief This method is used in derived objects to check consistence of constraint.
/// E.g. the distance between line and point may be signed.
virtual void adjustConstraint();
-private:
- /// \brief Change parameters of entities to be symmetric relative a line,
- /// given by array of parameters (coordinates of first and last points)
- void makeMirrorEntity(const Slvs_Entity& theBase,
- const Slvs_Entity& theMirror,
- const double theMirrorLine[]) const;
-
- /// \brief Precisely update last point to be on arc
- void adjustArcPoints(const Slvs_Entity& theArc) const;
-
private:
size_t myNumberOfObjects; ///< number of previously mirrored objects
- double myMirrorLineLength; ///< length of mirror line (should be always greater than 0)
};
#endif
#include <SketchSolver_ConstraintMovement.h>
#include <SketchSolver_Error.h>
-#include <SketchSolver_Group.h>
+#include <SketchSolver_Manager.h>
#include <SketchPlugin_Arc.h>
#include <SketchPlugin_Circle.h>
#include <SketchPlugin_Line.h>
#include <SketchPlugin_Point.h>
-SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(FeaturePtr theFeature)
- : SketchSolver_ConstraintRigid(theFeature)
-{
- process();
-}
+#include <GeomDataAPI_Point2D.h>
+
void SketchSolver_ConstraintMovement::process()
{
cleanErrorMsg();
- if (!myBaseFeature || !myStorage || myGroup == 0) {
- /// TODO: Put error message here
+ if (!myBaseFeature || !myStorage || myGroupID == GID_UNKNOWN) {
+ // Not enough parameters are initialized
return;
}
- if (!mySlvsConstraints.empty()) // some data is changed, update constraint
- update(myBaseConstraint);
- double aValue;
- std::vector<Slvs_hEntity> anEntities;
- bool isFullyMoved;
- getAttributes(aValue, anEntities, isFullyMoved);
- if (!myErrorMsg.empty() || (myFeatureMap.empty() && myAttributeMap.empty()))
+ ParameterWrapperPtr aValue;
+ getAttributes(aValue, myMovedEntities);
+ if (!myErrorMsg.empty() || myMovedEntities.empty()) {
+ // Nothing to move, clear the feature to avoid changing its group
+ // after removing the Movement constraint.
+ myBaseFeature = FeaturePtr();
return;
-
- if (isFullyMoved)
- fixFeature();
- else {
- std::vector<Slvs_hEntity>::iterator anEntIt = anEntities.begin();
- for (; anEntIt != anEntities.end(); ++anEntIt)
- fixPoint(*anEntIt);
}
+
+ std::vector<EntityWrapperPtr>::iterator anEntIt = myMovedEntities.begin();
+ for (; anEntIt != myMovedEntities.end(); ++anEntIt)
+ fixFeature(*anEntIt);
}
-void SketchSolver_ConstraintMovement::getAttributes(
- double& theValue,
- std::vector<Slvs_hEntity>& theAttributes,
- bool& theIsFullyMoved)
+static std::list<EntityWrapperPtr> movedEntities(
+ EntityWrapperPtr theOld, StoragePtr theOldStorage,
+ EntityWrapperPtr theNew, StoragePtr theNewStorage)
{
- bool isComplexFeature = false;
- theValue = 0.0;
- theIsFullyMoved = true;
- int aType = SLVS_E_UNKNOWN; // type of created entity
- Slvs_hEntity anEntityID = SLVS_E_UNKNOWN;
- Slvs_hEntity anEntMaxID = myStorage->entityMaxID();
- anEntityID = myGroup->getFeatureId(myBaseFeature);
- if (anEntityID == SLVS_E_UNKNOWN) {
- anEntityID = changeEntity(myBaseFeature, aType);
- if (anEntityID == SLVS_E_UNKNOWN) {
- myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
- return;
- }
-
- // Check the entity is complex
- Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
- if (anEntity.point[0] != SLVS_E_UNKNOWN)
- isComplexFeature = true;
- else // simple entity
- theAttributes.push_back(anEntityID);
+ bool isFullyMoved = true;
+ std::list<EntityWrapperPtr> aMoved;
+ if (theOld->isEqual(theNew))
+ return aMoved;
+
+ std::list<EntityWrapperPtr> anOldSubs = theOld->subEntities();
+ std::list<EntityWrapperPtr> aNewSubs = theNew->subEntities();
+ std::list<EntityWrapperPtr>::const_iterator anOldIt = anOldSubs.begin();
+ std::list<EntityWrapperPtr>::const_iterator aNewIt = aNewSubs.begin();
+ for (; anOldIt != anOldSubs.end() && aNewIt != aNewSubs.end(); ++anOldIt, ++aNewIt) {
+ std::list<EntityWrapperPtr> aMovedSubs = movedEntities(
+ *anOldIt, theOldStorage, *aNewIt, theNewStorage);
+ if (aMovedSubs.size() != 1 || aMovedSubs.front() != *anOldIt)
+ isFullyMoved = false;
+ aMoved.insert(aMoved.end(), aMovedSubs.begin(), aMovedSubs.end());
}
- else {
- myFeatureMap[myBaseFeature] = anEntityID;
- isComplexFeature = true;
- }
-
- int aNbOutOfGroup = 0;
- if (isComplexFeature) {
- std::list<AttributePtr> aPoints =
- myBaseFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
- std::list<AttributePtr>::iterator anIt = aPoints.begin();
- for (; anIt != aPoints.end(); ++anIt) {
- std::map<AttributePtr, Slvs_hEntity>::const_iterator aFound = myAttributeMap.find(*anIt);
- Slvs_hEntity anAttr = aFound != myAttributeMap.end() ?
- aFound->second : myGroup->getAttributeId(*anIt);
- Slvs_Entity anAttrEnt = myStorage->getEntity(anAttr);
-
- // Check the attribute changes coordinates
- std::shared_ptr<GeomDataAPI_Point2D> aPt =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt);
- // Check the entity is not lying in the current group or it is not moved
- if (anAttr == SLVS_E_UNKNOWN || anAttrEnt.group != myGroup->getId() ||
- (anAttr <= anEntMaxID && !isMoved(aPt, anAttrEnt))) {
- if (anAttrEnt.group == SLVS_G_OUTOFGROUP)
- ++aNbOutOfGroup;
- theIsFullyMoved = false;
- }
- else {
- theAttributes.push_back(anAttr);
- // update point coordinates
- Slvs_Entity anAttrEnt = myStorage->getEntity(anAttr);
- double aNewPos[2] = {aPt->x(), aPt->y()};
- for (int i = 0; i < 2; i++) {
- Slvs_Param aParam = myStorage->getParameter(anAttrEnt.param[i]);
- aParam.val = aNewPos[i];
- myStorage->updateParameter(aParam);
- }
- }
- }
- }
-
- // Additional checking, which leads to fix whole feature, if it has fixed points
- if (!theIsFullyMoved) {
- Slvs_Entity aFeature = myStorage->getEntity(anEntityID);
- int aNbPoints = 4;
- while (aNbPoints > 0 && aFeature.point[aNbPoints-1] == SLVS_E_UNKNOWN)
- --aNbPoints;
- if (aNbPoints == aNbOutOfGroup + (int)theAttributes.size()) {
- theIsFullyMoved = true;
- return;
- }
- }
-
- // Leave only points which are used in constraints
- if (myStorage->isUsedByConstraints(anEntityID))
- return;
- std::vector<Slvs_hEntity>::iterator anIt = theAttributes.begin();
- while (anIt != theAttributes.end()) {
- if (myStorage->isUsedByConstraints(*anIt))
- ++anIt;
- else {
- int aShift = anIt - theAttributes.begin();
- theAttributes.erase(anIt);
- anIt = theAttributes.begin() + aShift;
- }
+ if (isFullyMoved) {
+ aMoved.clear();
+ aMoved.push_back(theOld);
}
+ return aMoved;
}
-bool SketchSolver_ConstraintMovement::isMoved(
- std::shared_ptr<GeomDataAPI_Point2D> thePoint, const Slvs_Entity& theEntity)
-{
- double aDeltaX = myStorage->getParameter(theEntity.param[0]).val;
- double aDeltaY = myStorage->getParameter(theEntity.param[1]).val;
- aDeltaX -= thePoint->x();
- aDeltaY -= thePoint->y();
- return aDeltaX * aDeltaX + aDeltaY * aDeltaY >= tolerance * tolerance;
-}
-void SketchSolver_ConstraintMovement::fixFeature()
+void SketchSolver_ConstraintMovement::getAttributes(
+ ParameterWrapperPtr& theValue,
+ std::vector<EntityWrapperPtr>& theAttributes)
{
- Slvs_hEntity anEntID = fixedEntity();
-
- std::string aKind;
- std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFIt = myFeatureMap.begin();
- for (; aFIt != myFeatureMap.end() && aKind.empty(); ++aFIt)
- if (aFIt->second == anEntID)
- aKind = aFIt->first->getKind();
- std::map<AttributePtr, Slvs_hEntity>::const_iterator anAtIt = myAttributeMap.begin();
- for (; anAtIt != myAttributeMap.end() && aKind.empty(); ++anAtIt)
- if (anAtIt->second == anEntID)
- aKind = anAtIt->first->attributeType();
+ // There will be build entities, according to the fixed feature, in the separate storage
+ // to check whether any point is moved
+ BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+ StoragePtr anOtherStorage = aBuilder->createStorage(myGroupID);
+ anOtherStorage->setSketch(myStorage->sketch());
+ if (!anOtherStorage->update(myBaseFeature, myGroupID))
+ return;
+ EntityWrapperPtr aNewEntity = anOtherStorage->entity(myBaseFeature);
+ EntityWrapperPtr anOldEntity = myStorage->entity(myBaseFeature);
- if (aKind == SketchPlugin_Line::ID()) {
- Slvs_Entity aLine = myStorage->getEntity(anEntID);
- fixLine(aLine);
- }
- else if (aKind == SketchPlugin_Arc::ID()) {
- Slvs_Entity anArc = myStorage->getEntity(anEntID);
- fixArc(anArc);
- }
- else if (aKind == SketchPlugin_Circle::ID()) {
- Slvs_Entity aCirc = myStorage->getEntity(anEntID);
- fixCircle(aCirc);
- }
- else if (aKind == SketchPlugin_Point::ID() || aKind == GeomDataAPI_Point2D::typeId()) {
- fixPoint(anEntID);
+ std::list<EntityWrapperPtr> aMoved;
+ if (aNewEntity && anOldEntity)
+ aMoved = movedEntities(anOldEntity, myStorage, aNewEntity, anOtherStorage);
+ else {
+ // get attributes moved
+ std::list<AttributePtr> anAttrList =
+ myBaseFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
+ std::list<AttributePtr>::const_iterator anIt = anAttrList.begin();
+ for (; anIt != anAttrList.end(); ++anIt) {
+ aNewEntity = anOtherStorage->entity(*anIt);
+ anOldEntity = myStorage->entity(*anIt);
+ if (!aNewEntity || !anOldEntity)
+ continue;
+ std::list<EntityWrapperPtr> aMovedAttr = movedEntities(
+ anOldEntity, myStorage, aNewEntity, anOtherStorage);
+ aMoved.insert(aMoved.end(), aMovedAttr.begin(), aMovedAttr.end());
+ }
}
+ theAttributes.clear();
+ theAttributes.insert(theAttributes.begin(), aMoved.begin(), aMoved.end());
}
-
#define SketchSolver_ConstraintMovement_H_
#include "SketchSolver.h"
-#include <SketchSolver_ConstraintRigid.h>
-
-#include <GeomDataAPI_Point2D.h>
+#include <SketchSolver_ConstraintFixed.h>
/** \class SketchSolver_ConstraintMovement
* \ingroup Plugins
- * \brief Stores data of Rigid (Fixed) constraint for the moved feature only
+ * \brief Stores data to the Fixed constraint for the moved feature only
*/
-class SketchSolver_ConstraintMovement : public SketchSolver_ConstraintRigid
+class SketchSolver_ConstraintMovement : public SketchSolver_ConstraintFixed
{
private:
/// Creates constraint to manage the given constraint from plugin
SketchSolver_ConstraintMovement(ConstraintPtr theConstraint)
- : SketchSolver_ConstraintRigid(theConstraint)
+ : SketchSolver_ConstraintFixed(theConstraint)
{}
public:
/// Creates temporary constraint based on feature
- SketchSolver_ConstraintMovement(FeaturePtr theFeature);
+ SketchSolver_ConstraintMovement(FeaturePtr theFeature)
+ : SketchSolver_ConstraintFixed(theFeature)
+ {}
protected:
/// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
/// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
/// \param[out] theValue numerical characteristic of constraint (e.g. distance)
- /// \param[out] theAttributes list of attributes to be filled
- /// \param[out] theIsFullyMoved shows that the feature is moved, in other case only one point of the feature is shifted
- virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes, bool& theIsFullyMoved);
-
- /// \brief Fixed feature basing on its type
- virtual void fixFeature();
+ /// \param[out] theAttributes list of attributes to be filled (list of moved entities or attributes)
+ virtual void getAttributes(ParameterWrapperPtr& theValue, std::vector<EntityWrapperPtr>& theAttributes);
private:
- /// \brief Check the coordinates of point are differ than coordinates of correponding SolveSpace entity
- bool isMoved(std::shared_ptr<GeomDataAPI_Point2D> thePoint, const Slvs_Entity& theEntity);
+ std::vector<EntityWrapperPtr> myMovedEntities; ///< list of entities that are moved
};
#endif
#include <SketchSolver_ConstraintMulti.h>
-#include <SketchSolver_Group.h>
#include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
-#include <SketchPlugin_Arc.h>
-
-#include <ModelAPI_AttributeDouble.h>
#include <ModelAPI_AttributeInteger.h>
#include <ModelAPI_AttributeRefAttr.h>
#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_ResultConstruction.h>
-
-#include <GeomAPI_Dir2d.h>
-#include <GeomAPI_XY.h>
-#include <math.h>
-
-void SketchSolver_ConstraintMulti::processEntities(const std::vector< std::vector<Slvs_hEntity> >& theEntAndCopies)
+void SketchSolver_ConstraintMulti::getEntitiesAndCopies(
+ std::list< std::list<EntityWrapperPtr> >& theEntAndCopies)
{
- // Keep all objects unchanged (only initial object may be changed by user)
- myCircsAndCopies.clear();
- std::vector<std::vector<Slvs_hEntity> >::const_iterator anEntIt = theEntAndCopies.begin();
- std::vector<Slvs_hEntity>::const_iterator aCpIt;
- for (; anEntIt != theEntAndCopies.end(); ++anEntIt) {
- std::vector<Slvs_hEntity> aCircs;
- aCpIt = anEntIt->begin();
- // Obtain initial points
- Slvs_Entity anInitial = myStorage->getEntity(*aCpIt);
- if (anInitial.type == SLVS_E_POINT_IN_2D || anInitial.type == SLVS_E_POINT_IN_3D)
- myInitialPoints.insert(anInitial.h);
- else {
- for (int i = 0; i < 4 && anInitial.point[i] != SLVS_E_UNKNOWN; i++)
- myInitialPoints.insert(anInitial.point[i]);
- }
-
- // Fix the copies
- for (++aCpIt; aCpIt != anEntIt->end(); ++aCpIt) {
- const Slvs_Entity& anEntity = myStorage->getEntity(*aCpIt);
- std::vector<Slvs_hConstraint> aNewConstr;
- if (anEntity.type == SLVS_E_CIRCLE) {
- aCircs.push_back(anEntity.distance);
- // for circles we fix only center
- aNewConstr = myStorage->fixEntity(anEntity.point[0]);
- } else
- aNewConstr = myStorage->fixEntity(*aCpIt);
- if (anEntity.type == SLVS_E_ARC_OF_CIRCLE)
- aCircs.push_back(anEntity.h);
- mySlvsConstraints.insert(mySlvsConstraints.end(), aNewConstr.begin(), aNewConstr.end());
- }
+ DataPtr aData = myBaseConstraint->data();
+
+ // Lists of objects and number of copies
+ AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+ aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
+ myNumberOfObjects = anInitialRefList->size();
+ myNumberOfCopies = aData->integer(nameNbObjects())->value() - 1;
+ if (myNumberOfCopies <= 0)
+ return;
- if (!aCircs.empty()) {
- if (anInitial.type == SLVS_E_CIRCLE)
- aCircs.insert(aCircs.begin(), anInitial.distance);
- else
- aCircs.insert(aCircs.begin(), anInitial.h);
- myCircsAndCopies.push_back(aCircs);
- }
+ AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+ aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
+ if (!aRefList || aRefList->size() == 0) {
+ myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+ return;
}
-}
-void SketchSolver_ConstraintMulti::update(ConstraintPtr theConstraint)
-{
- cleanErrorMsg();
- if (!theConstraint || theConstraint == myBaseConstraint) {
- AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- AttributeIntegerPtr aNbObjects = myBaseConstraint->integer(nameNbObjects());
- if (anInitialRefList->size() != myNumberOfObjects || aNbObjects->value()-1 != myNumberOfCopies) {
- remove(myBaseConstraint);
- process();
- return;
+ FeaturePtr aFeature;
+ std::list<EntityWrapperPtr> anEntities; // list of transformed entities
+ std::list<ObjectPtr> anObjectList = aRefList->list();
+ std::list<ObjectPtr>::iterator anObjIt = anObjectList.begin();
+ while (anObjIt != anObjectList.end()) {
+ anEntities.clear();
+ for (int i = 0; i <= myNumberOfCopies && anObjIt != anObjectList.end(); ++i, ++anObjIt) {
+ aFeature = ModelAPI_Feature::feature(*anObjIt);
+ if (!aFeature)
+ continue;
+
+ myStorage->update(aFeature);
+ anEntities.push_back(myStorage->entity(aFeature));
}
+ if (!anEntities.empty())
+ theEntAndCopies.push_back(anEntities);
}
-
- updateLocal();
- SketchSolver_Constraint::update();
}
-bool SketchSolver_ConstraintMulti::remove(ConstraintPtr theConstraint)
+void SketchSolver_ConstraintMulti::update()
{
- cleanErrorMsg();
- if (theConstraint && theConstraint != myBaseConstraint)
- return false;
- bool isFullyRemoved = true;
- std::vector<Slvs_hEntity>::iterator aCIter = mySlvsConstraints.begin();
- for (; aCIter != mySlvsConstraints.end(); aCIter++)
- isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
- mySlvsConstraints.clear();
-
- std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.begin();
- for (; aFeatIt != myFeatureMap.end(); aFeatIt++)
- myStorage->removeEntity(aFeatIt->second);
- myStorage->removeUnusedEntities();
-
- std::map<FeaturePtr, Slvs_hEntity> aFeatureMapCopy = myFeatureMap;
-
- if (isFullyRemoved) {
- myFeatureMap.clear();
- myAttributeMap.clear();
- myValueMap.clear();
- } else
- cleanRemovedEntities();
-
- // Restore initial features
- std::map<FeaturePtr, Slvs_hEntity>::iterator aFIter = aFeatureMapCopy.begin();
- for (; aFIter != aFeatureMapCopy.end(); ++aFIter)
- {
- if (myFeatureMap.find(aFIter->first) != myFeatureMap.end())
- continue; // the feature was not removed
- Slvs_hEntity anEntity = myGroup->getFeatureId(aFIter->first);
- if (anEntity != SLVS_E_UNKNOWN)
- myFeatureMap[aFIter->first] = anEntity;
- }
-
- // Clear list of rotated points
- myPointsAndCopies.clear();
- myInitialPoints.clear();
-
- return true;
+ update(false);
}
-void SketchSolver_ConstraintMulti::addFeature(FeaturePtr theFeature)
-{
- SketchSolver_Constraint::addFeature(theFeature);
- std::map<FeaturePtr, Slvs_hEntity>::iterator aFeatIt = myFeatureMap.find(theFeature);
- if (aFeatIt == myFeatureMap.end())
+void SketchSolver_ConstraintMulti::update(bool isForce)
+{
+ cleanErrorMsg();
+ AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+ myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
+ AttributeIntegerPtr aNbObjects = myBaseConstraint->integer(nameNbObjects());
+ if (anInitialRefList->size() != myNumberOfObjects || aNbObjects->value()-1 != myNumberOfCopies) {
+ remove();
+ process();
return;
+ }
- // store list of points of the feature
- const Slvs_Entity& theEntity = myStorage->getEntity(aFeatIt->second);
- for (int i = 0; i < 4; i++)
- if (theEntity.point[i] != SLVS_E_UNKNOWN)
- myPointsJustUpdated.insert(theEntity.point[i]);
+ // update derivative object
+ updateLocal();
+ if (isForce)
+ myAdjusted = false;
+ // update parent object
+ SketchSolver_Constraint::update();
}
void SketchSolver_ConstraintMulti::adjustConstraint()
if (myAdjusted)
return; // constraint already adjusted, don't do it once again
- double aRelCoord[2] = {0.0, 0.0}; // relative coordinates of point
- double anAbsCoord[2] = {0.0, 0.0}; // absolute coordinates of point
-
- std::list<Slvs_Constraint> aCoincident = myStorage->getConstraintsByType(SLVS_C_POINTS_COINCIDENT);
- std::list<Slvs_Constraint>::const_iterator aCoIt;
-
- // Update positions of all points to satisfy angles
- std::vector< std::vector<Slvs_hEntity> >::const_iterator aPointsIter = myPointsAndCopies.begin();
- std::vector<Slvs_hEntity>::const_iterator aCopyIter;
- for (; aPointsIter != myPointsAndCopies.end(); ++aPointsIter) {
- aCopyIter = aPointsIter->begin();
- const Slvs_Entity& anInitial = myStorage->getEntity(*aCopyIter);
- for (int i = 0; i < 2; i++)
- anAbsCoord[i] = myStorage->getParameter(anInitial.param[i]).val;
- getRelative(anAbsCoord[0], anAbsCoord[1], aRelCoord[0], aRelCoord[1]);
-
- // if the point is coincident with another one which is temporary fixed (moved by user),
- // we will update its position correspondingly
- Slvs_hConstraint aFixed;
- for (aCoIt = aCoincident.begin(); aCoIt != aCoincident.end(); ++aCoIt) {
- if ((aCoIt->ptA == anInitial.h && myInitialPoints.find(aCoIt->ptB) != myInitialPoints.end()) ||
- (aCoIt->ptB == anInitial.h && myInitialPoints.find(aCoIt->ptA) != myInitialPoints.end())) {
- Slvs_hEntity anOtherId = aCoIt->ptA == anInitial.h ? aCoIt->ptB : aCoIt->ptA;
- if (!myStorage->isTemporary(aFixed) &&
- myPointsJustUpdated.find(anOtherId) == myPointsJustUpdated.end())
- continue; // nothing to change
-
- const Slvs_Entity& anOtherPnt = myStorage->getEntity(anOtherId);
- for (int i = 0; i < 2; i++) {
- Slvs_Param anInitParam = myStorage->getParameter(anInitial.param[i]);
- const Slvs_Param& anOtherParam = myStorage->getParameter(anOtherPnt.param[i]);
- anInitParam.val = anOtherParam.val;
- myStorage->updateParameter(anInitParam);
- anAbsCoord[i] = anOtherParam.val;
- }
- getRelative(anAbsCoord[0], anAbsCoord[1], aRelCoord[0], aRelCoord[1]);
- }
- }
-
- // update copied points
- aCopyIter = aPointsIter->begin();
- for (++aCopyIter; aCopyIter != aPointsIter->end(); ++aCopyIter) {
- // transform coordinates
- transformRelative(aRelCoord[0], aRelCoord[1]);
- getAbsolute(aRelCoord[0], aRelCoord[1], anAbsCoord[0], anAbsCoord[1]);
-
- const Slvs_Entity& aTarget = myStorage->getEntity(*aCopyIter);
- for (int i = 0; i < 2; i++) {
- Slvs_Param aParam = myStorage->getParameter(aTarget.param[i]);
- aParam.val = anAbsCoord[i];
- myStorage->updateParameter(aParam);
- }
- }
- }
-
- std::list<Slvs_Constraint> aDiamConstr;
- for (aPointsIter = myCircsAndCopies.begin(); aPointsIter != myCircsAndCopies.end(); ++aPointsIter) {
- aCopyIter = aPointsIter->begin();
- const Slvs_Entity& anInitial = myStorage->getEntity(*aCopyIter);
- if (anInitial.type == SLVS_E_DISTANCE) {
- const Slvs_Param& anInitRad = myStorage->getParameter(anInitial.param[0]);
- for (++aCopyIter; aCopyIter != aPointsIter->end(); ++aCopyIter) {
- const Slvs_Entity& aCopy = myStorage->getEntity(*aCopyIter);
- Slvs_Param aCopyRad = myStorage->getParameter(aCopy.param[0]);
- aCopyRad.val = anInitRad.val;
- myStorage->updateParameter(aCopyRad);
- }
- } else if (anInitial.type == SLVS_E_ARC_OF_CIRCLE) {
- const Slvs_Entity& aCenterEnt = myStorage->getEntity(anInitial.point[0]);
- const Slvs_Entity& aStartEnt = myStorage->getEntity(anInitial.point[1]);
+ BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
- if (aDiamConstr.empty())
- aDiamConstr = myStorage->getConstraintsByType(SLVS_C_DIAMETER);
- // Calculate diameter of initial arc
- double aDiam = 0.0;
- for (int i = 0; i < 2; i++) {
- double d = myStorage->getParameter(aStartEnt.param[i]).val -
- myStorage->getParameter(aCenterEnt.param[i]).val;
- aDiam += d * d;
- }
- aDiam = sqrt(aDiam) * 2.0;
- // Update the Diameter constraints of copied arcs
- for (++aCopyIter; aCopyIter != aPointsIter->end(); ++aCopyIter) {
- std::list<Slvs_Constraint>::iterator aDCIt = aDiamConstr.begin();
- for (; aDCIt != aDiamConstr.end(); ++aDCIt)
- if (aDCIt->entityA == *aCopyIter) {
- aDCIt->valA = aDiam;
- myStorage->updateConstraint(*aDCIt);
- aDiamConstr.erase(aDCIt);
- break;
- }
- }
- }
- }
-
- myPointsJustUpdated.clear();
+ const std::list<ConstraintWrapperPtr>& aConstraints = myStorage->constraint(myBaseConstraint);
+ std::list<ConstraintWrapperPtr>::const_iterator anIt = aConstraints.begin();
+ for (; anIt != aConstraints.end(); ++anIt)
+ aBuilder->adjustConstraint(*anIt);
+ myStorage->addConstraint(myBaseConstraint, aConstraints);
myAdjusted = true;
}
-
-void SketchSolver_ConstraintMulti::checkCoincidence()
-{
- std::vector< std::vector<Slvs_hEntity> > aFilteredPoints; // points are filtered by their positions
-
- std::vector< std::vector<Slvs_hEntity> >::const_iterator aPCIt = myPointsAndCopies.begin();
- std::vector<Slvs_hEntity>::const_iterator aCIt;
- for (; aPCIt != myPointsAndCopies.end(); ++aPCIt) {
- aCIt = aPCIt->begin();
- // Skip first element, focus the copies only
- for (++aCIt; aCIt != aPCIt->end(); ++aCIt) {
- std::vector< std::vector<Slvs_hEntity> >::iterator aFilterIt = aFilteredPoints.begin();
- for (; aFilterIt != aFilteredPoints.end(); ++aFilterIt)
- if (myStorage->isEqual(*aCIt, aFilterIt->front())) {
- aFilterIt->push_back(*aCIt);
- break;
- }
- if (aFilterIt == aFilteredPoints.end()) {
- std::vector<Slvs_hEntity> aNewFilter(1, *aCIt);
- aFilteredPoints.push_back(aNewFilter);
- }
- }
- }
-
- // Check the coicidence of filtered points and remove extra fixation.
- // Also check separated points which are not fixed.
- std::vector< std::vector<Slvs_hEntity> >::iterator aFPIt = aFilteredPoints.begin();
- for (; aFPIt != aFilteredPoints.end(); ++aFPIt) {
- if (aFPIt->size() <= 1)
- continue;
- std::vector<Slvs_hEntity>::iterator anIt1, anIt2;
- for (anIt1 = aFPIt->begin(); anIt1 != aFPIt->end(); ++anIt1) {
- for (anIt2 = anIt1 + 1; anIt2 != aFPIt->end(); ++anIt2) {
- Slvs_hConstraint aFixed1, aFixed2;
- bool isFixed1 = myStorage->isPointFixed(*anIt1, aFixed1);
- bool isFixed2 = myStorage->isPointFixed(*anIt2, aFixed2);
- if (myStorage->isCoincident(*anIt1, *anIt2)) {
- if (!isFixed1 && isFixed2) {
- Slvs_hEntity aTmp = *anIt1;
- *anIt1 = *anIt2;
- *anIt2 = aTmp;
- } else if (isFixed1 && isFixed2) {
- // remove fixing of the second point
- myStorage->removeConstraint(aFixed2);
- std::vector<Slvs_hConstraint>::iterator aRemoveIt = mySlvsConstraints.begin();
- for (; aRemoveIt != mySlvsConstraints.end(); ++aRemoveIt)
- if (*aRemoveIt == aFixed2) {
- mySlvsConstraints.erase(aRemoveIt);
- break;
- }
- }
- } else {
- bool isFixed[2] = {
- myStorage->isPointFixed(*anIt1, aFixed1, true),
- myStorage->isPointFixed(*anIt2, aFixed2, true)
- };
-
- Slvs_hEntity aPoint[2] = {*anIt1, *anIt2};
- for (int i = 0; i < 2; i++)
- if (!isFixed[i]) {
- Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
- SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0,
- aPoint[i], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- aConstraint.h = myStorage->addConstraint(aConstraint);
- mySlvsConstraints.push_back(aConstraint.h);
- }
- }
- }
- }
- }
-}
myAdjusted(false)
{}
- virtual int getType() const
- { return SLVS_C_UNKNOWN; }
-
/// \brief Update constraint
- virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
-
- /// \brief Tries to remove constraint
- /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
- virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
-
- /// \brief Adds a feature to constraint and create its analogue in SolveSpace
- virtual void addFeature(FeaturePtr theFeature);
-
- /// \brief Update SketchPlugin attributes using the data obtained from SolveSpace entities
- virtual void refresh()
- {
- myAdjusted = false;
- SketchSolver_Constraint::refresh();
- }
-
- /// \brief Verifies, the coincidence between points of copied entities appears or disappears,
- /// and removes or adds fixing of corresponding points.
- void checkCoincidence();
+ virtual void update();
+ /// \brief Update constraint
+ void update(bool isForce);
protected:
/// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
{ /* do nothing here */ }
/// \brief Collect entities and their copies, like circles and arcs
- void processEntities(const std::vector< std::vector<Slvs_hEntity> >& theEntAndCopies);
+ void getEntitiesAndCopies(std::list< std::list<EntityWrapperPtr> >& theEntAndCopies);
/// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
/// \param[out] theValue numerical characteristic of constraint (e.g. distance)
/// \param[out] theAttributes list of attributes to be filled
- virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes)
+ virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes)
{ /* do nothing here */ }
/// \brief This method is used in derived objects to check consistence of constraint.
/// \brief Returns name of NUMBER_OF_COPIES parameter for corresponding feature
virtual const std::string& nameNbObjects() = 0;
-
-protected:
- /// \brief Convert absolute coordinates to relative coordinates
- virtual void getRelative(double theAbsX, double theAbsY, double& theRelX, double& theRelY) = 0;
- /// \brief Convert relative coordinates to absolute coordinates
- virtual void getAbsolute(double theRelX, double theRelY, double& theAbsX, double& theAbsY) = 0;
- /// \brief Apply transformation for relative coordinates
- virtual void transformRelative(double& theX, double& theY) = 0;
protected:
- size_t myNumberOfObjects; ///< number of previous initial objects
- size_t myNumberOfCopies; ///< number of previous copies of initial objects
-
- std::vector< std::vector<Slvs_hEntity> > myPointsAndCopies; ///< list of initial points and their copies
- std::vector< std::vector<Slvs_hEntity> > myCircsAndCopies; ///< list of circles and their copies (to change their radii together)
-
- std::set<Slvs_hEntity> myPointsJustUpdated; ///< list of points touched by user
- std::set<Slvs_hEntity> myInitialPoints; ///< list of points containing initial objects
+ int myNumberOfObjects; ///< number of previous initial objects
+ int myNumberOfCopies; ///< number of previous copies of initial objects
bool myAdjusted; ///< the constraint is already adjusted (to not do it several times)
};
#include <SketchSolver_ConstraintMultiRotation.h>
-#include <SketchSolver_Group.h>
#include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
-#include <SketchPlugin_Arc.h>
#include <SketchPlugin_MultiRotation.h>
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeInteger.h>
-#include <ModelAPI_AttributeRefAttr.h>
-#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_ResultConstruction.h>
-
-#include <GeomAPI_Dir2d.h>
-#include <GeomAPI_XY.h>
-
#include <math.h>
void SketchSolver_ConstraintMultiRotation::getAttributes(
- Slvs_hEntity& theCenter, double& theAngle,
- std::vector< std::vector<Slvs_hEntity> >& thePoints,
- std::vector< std::vector<Slvs_hEntity> >& theEntities)
+ EntityWrapperPtr& theCenter, double& theAngle,
+ std::list< std::list<EntityWrapperPtr> >& theEntities)
{
DataPtr aData = myBaseConstraint->data();
theAngle = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
return;
}
- int aType = SLVS_E_UNKNOWN; // type of created entity
- Slvs_hEntity anEntityID = myGroup->getAttributeId(aCenterAttr);
- if (anEntityID == SLVS_E_UNKNOWN)
- anEntityID = changeEntity(aCenterAttr, aType);
- theCenter = anEntityID;
-
- // Lists of objects and number of copies
- AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
- myNumberOfObjects = anInitialRefList->size();
- myNumberOfCopies = (size_t) aData->integer(SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID())->value() - 1;
- if (myNumberOfCopies <= 0)
- return;
- AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
- if (!aRefList) {
- myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
- return;
- }
- // Obtain all points of initial features and store them into separate lists
- // containing their translated copies.
- // Also all circles and arc collected too, because they will be constrained by equal radii.
- FeaturePtr aFeature;
- ResultConstructionPtr aRC;
- static const size_t MAX_POINTS = 3;
- std::vector<Slvs_hEntity> aPoints[MAX_POINTS]; // lists of points of features
- std::vector<Slvs_hEntity> anEntities;
- std::list<ObjectPtr> anObjectList = aRefList->list();
- std::list<ObjectPtr>::iterator anObjectIter = anObjectList.begin();
- while (anObjectIter != anObjectList.end()) {
- for (size_t i = 0; i < MAX_POINTS; ++i)
- aPoints[i].clear();
- anEntities.clear();
-
- for (size_t i = 0; i <= myNumberOfCopies && anObjectIter != anObjectList.end(); i++, anObjectIter++) {
- aFeature = ModelAPI_Feature::feature(*anObjectIter);
- if (!aFeature)
- continue;
- anEntityID = changeEntity(aFeature, aType);
- anEntities.push_back(anEntityID);
- Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
- switch (aType) {
- case SLVS_E_POINT_IN_2D:
- case SLVS_E_POINT_IN_3D:
- aPoints[0].push_back(anEntityID);
- break;
- case SLVS_E_LINE_SEGMENT:
- aPoints[0].push_back(anEntity.point[0]); // start point of line
- aPoints[1].push_back(anEntity.point[1]); // end point of line
- break;
- case SLVS_E_CIRCLE:
- aPoints[0].push_back(anEntity.point[0]); // center of circle
- break;
- case SLVS_E_ARC_OF_CIRCLE:
- aPoints[0].push_back(anEntity.point[0]); // center of arc
- aPoints[1].push_back(anEntity.point[1]); // start point of arc
- aPoints[2].push_back(anEntity.point[2]); // end point of arc
- break;
- default:
- myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
- return;
- }
- }
-
- for (size_t i = 0; i < MAX_POINTS; ++i)
- if (!aPoints[i].empty())
- thePoints.push_back(aPoints[i]);
- if (!anEntities.empty())
- theEntities.push_back(anEntities);
- }
+ myType = CONSTRAINT_MULTI_ROTATION;
+
+ myStorage->update(aCenterAttr, GID_OUTOFGROUP);
+ theCenter = myStorage->entity(aCenterAttr);
+
+ getEntitiesAndCopies(theEntities);
}
void SketchSolver_ConstraintMultiRotation::process()
{
cleanErrorMsg();
- if (!myBaseConstraint || !myStorage || myGroup == 0) {
+ if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) {
/// TODO: Put error message here
return;
}
- if (!mySlvsConstraints.empty()) // some data is changed, update constraint
- update(myBaseConstraint);
- std::vector<std::vector<Slvs_hEntity> > anEntitiesAndCopies;
- getAttributes(myRotationCenter, myAngle, myPointsAndCopies, anEntitiesAndCopies);
+ EntityWrapperPtr aRotationCenter;
+ std::list<std::list<EntityWrapperPtr> > anEntitiesAndCopies;
+ getAttributes(aRotationCenter, myAngle, anEntitiesAndCopies);
if (!myErrorMsg.empty())
return;
- // Set the rotation center unchanged during constraint recalculation
- Slvs_Constraint aConstraint;
- if (!myStorage->isPointFixed(myRotationCenter, aConstraint.h, true)) {
- aConstraint = Slvs_MakeConstraint(
- SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0,
- myRotationCenter, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- aConstraint.h = myStorage->addConstraint(aConstraint);
- mySlvsConstraints.push_back(aConstraint.h);
+ BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+ std::list<ConstraintWrapperPtr> aRotConstraints;
+
+ std::list< std::list<EntityWrapperPtr> >::iterator anEntIt = anEntitiesAndCopies.begin();
+ for (; anEntIt != anEntitiesAndCopies.end(); ++anEntIt) {
+ std::list<ConstraintWrapperPtr> aNewConstraints =
+ aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID, myType,
+ myAngle, aRotationCenter, EntityWrapperPtr(), *anEntIt);
+ aRotConstraints.insert(aRotConstraints.end(), aNewConstraints.begin(), aNewConstraints.end());
}
+ myStorage->addConstraint(myBaseConstraint, aRotConstraints);
myAdjusted = false;
- processEntities(anEntitiesAndCopies);
adjustConstraint();
}
myAdjusted = false;
// update angle value
myAngle = aValue;
+
+ // update center
+ AttributePtr aCenterAttr = myBaseConstraint->attribute(SketchPlugin_MultiRotation::CENTER_ID());
+ if (myStorage->update(aCenterAttr, myGroupID)) {
+ myStorage->update(aCenterAttr, GID_UNKNOWN);
+ myAdjusted = false;
+ }
}
void SketchSolver_ConstraintMultiRotation::adjustConstraint()
myStorage->setNeedToResolve(false);
return;
}
- if (myAdjusted)
- return;
- std::list<Slvs_Constraint> aCoincident = myStorage->getConstraintsByType(SLVS_C_POINTS_COINCIDENT);
- std::list<Slvs_Constraint>::const_iterator aCoIt;
-
- // Check overconstrained on rotation center (if it is coincident with other fixed point)
- Slvs_hConstraint aFixedCenter;
- if (myStorage->isPointFixed(myRotationCenter, aFixedCenter, false)) {
- Slvs_hConstraint aFixed;
- for (aCoIt = aCoincident.begin(); aCoIt != aCoincident.end(); ++aCoIt)
- if ((aCoIt->ptA == myRotationCenter && myStorage->isPointFixed(aCoIt->ptB, aFixed, true)) ||
- (aCoIt->ptB == myRotationCenter && myStorage->isPointFixed(aCoIt->ptA, aFixed, true))) {
- // Un-fix the center
- myStorage->removeConstraint(aFixedCenter);
- std::vector<Slvs_hConstraint>::iterator aSCIt = mySlvsConstraints.begin();
- for (; aSCIt != mySlvsConstraints.end(); ++aSCIt)
- if (*aSCIt == aFixedCenter) {
- mySlvsConstraints.erase(aSCIt);
- break;
- }
- }
- }
-
- // Obtain coordinates of rotation center
- Slvs_Entity aRotCenter = myStorage->getEntity(myRotationCenter);
- myCenterCoord[0] = myStorage->getParameter(aRotCenter.param[0]).val;
- myCenterCoord[1] = myStorage->getParameter(aRotCenter.param[1]).val;
-
- myRotationVal[0] = sin(myAngle * PI / 180.0);
- myRotationVal[1] = cos(myAngle * PI / 180.0);
+ const std::list<ConstraintWrapperPtr>& aConstraints = myStorage->constraint(myBaseConstraint);
+ std::list<ConstraintWrapperPtr>::const_iterator aCIt = aConstraints.begin();
+ for (; aCIt != aConstraints.end(); ++aCIt)
+ (*aCIt)->setValue(myAngle);
SketchSolver_ConstraintMulti::adjustConstraint();
}
-void SketchSolver_ConstraintMultiRotation::getRelative(
- double theAbsX, double theAbsY, double& theRelX, double& theRelY)
-{
- theRelX = theAbsX - myCenterCoord[0];
- theRelY = theAbsY - myCenterCoord[1];
-}
-
-void SketchSolver_ConstraintMultiRotation::getAbsolute(
- double theRelX, double theRelY, double& theAbsX, double& theAbsY)
-{
- theAbsX = theRelX + myCenterCoord[0];
- theAbsY = theRelY + myCenterCoord[1];
-}
-
-void SketchSolver_ConstraintMultiRotation::transformRelative(double& theX, double& theY)
-{
- // rotate direction
- // myRotationVal[0] = sinA, myRotationVal[1] = cosA
- double aTemp = theX * myRotationVal[1] - theY * myRotationVal[0];
- theY = theX * myRotationVal[0] + theY * myRotationVal[1];
- theX = aTemp;
-}
-
const std::string& SketchSolver_ConstraintMultiRotation::nameNbObjects()
{
return SketchPlugin_MultiRotation::NUMBER_OF_OBJECTS_ID();
SketchSolver_ConstraintMulti(theConstraint)
{}
- virtual int getType() const
- { return SLVS_C_MULTI_ROTATION; }
-
protected:
/// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
virtual void process();
/// \brief Generate list of rotated entities
- /// \param[out] theCenter ID of central point of rotation
+ /// \param[out] theCenter central point of rotation
/// \param[out] theAngle rotation angle
- /// \param[out] thePoints list of IDs of initial points and their rotated copies
- /// \param[out] theEntities list of IDs of entities and their rotated copies
- void getAttributes(Slvs_hEntity& theCenter, double& theAngle,
- std::vector< std::vector<Slvs_hEntity> >& thePoints,
- std::vector< std::vector<Slvs_hEntity> >& theEntities);
+ /// \param[out] theEntities list of entities and their rotated copies
+ void getAttributes(EntityWrapperPtr& theCenter, double& theAngle,
+ std::list< std::list<EntityWrapperPtr> >& theEntities);
/// \brief This method is used in derived objects to check consistence of constraint.
virtual void adjustConstraint();
/// \brief Update parameters (called from base class)
virtual void updateLocal();
-private:
- /// \brief Convert absolute coordinates to relative coordinates
- virtual void getRelative(double theAbsX, double theAbsY, double& theRelX, double& theRelY);
- /// \brief Convert relative coordinates to absolute coordinates
- virtual void getAbsolute(double theRelX, double theRelY, double& theAbsX, double& theAbsY);
- /// \brief Apply transformation for relative coordinates
- virtual void transformRelative(double& theX, double& theY);
-
private:
/// \brief Returns name of NUMBER_OF_COPIES parameter for corresponding feature
virtual const std::string& nameNbObjects();
-
-private:
- Slvs_hEntity myRotationCenter; ///< ID of center of rotation
double myAngle; ///< angle of rotation
-
- double myCenterCoord[2]; ///< coordinates of rotation center
- double myRotationVal[2]; ///< sinus and cosinus of rotation angle
};
#endif
#include <SketchSolver_ConstraintMultiTranslation.h>
-#include <SketchSolver_Group.h>
#include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
-#include <SketchPlugin_Arc.h>
#include <SketchPlugin_MultiTranslation.h>
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeInteger.h>
-#include <ModelAPI_AttributeRefAttr.h>
-#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_ResultConstruction.h>
-#include <ModelAPI_Data.h>
-
-#include <GeomAPI_Dir2d.h>
-#include <GeomAPI_XY.h>
-
-#include <math.h>
-
void SketchSolver_ConstraintMultiTranslation::getAttributes(
- Slvs_hEntity& theStartPoint, Slvs_hEntity& theEndPoint,
- std::vector< std::vector<Slvs_hEntity> >& thePoints,
- std::vector< std::vector<Slvs_hEntity> >& theEntities)
+ EntityWrapperPtr& theStartPoint, EntityWrapperPtr& theEndPoint,
+ std::list< std::list<EntityWrapperPtr> >& theEntities)
{
DataPtr aData = myBaseConstraint->data();
AttributePtr aStartPointAttr = aData->attribute(SketchPlugin_MultiTranslation::START_POINT_ID());
return;
}
- int aType = SLVS_E_UNKNOWN; // type of created entity
- Slvs_hEntity anEntityID = myGroup->getAttributeId(aStartPointAttr);
- if (anEntityID == SLVS_E_UNKNOWN)
- anEntityID = changeEntity(aStartPointAttr, aType);
- theStartPoint = anEntityID;
- anEntityID = myGroup->getAttributeId(aEndPointAttr);
- if (anEntityID == SLVS_E_UNKNOWN)
- anEntityID = changeEntity(aEndPointAttr, aType);
- theEndPoint = anEntityID;
-
- // Lists of objects and number of copies
- AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- aData->attribute(SketchPlugin_Constraint::ENTITY_A()));
- myNumberOfObjects = anInitialRefList->size();
- myNumberOfCopies = (size_t) aData->integer(SketchPlugin_MultiTranslation::NUMBER_OF_OBJECTS_ID())->value() - 1;
- if (myNumberOfCopies <= 0)
- return;
-
- AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
- myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
- if (!aRefList) {
- myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
- return;
- }
+ myType = CONSTRAINT_MULTI_TRANSLATION;
- // Obtain all points of initial features and store them into separate lists
- // containing their translated copies.
- // Also all circles and arc collected too, because they will be constrained by equal radii.
- FeaturePtr aFeature;
- ResultConstructionPtr aRC;
- static const size_t MAX_POINTS = 3;
- std::vector<Slvs_hEntity> aPoints[MAX_POINTS]; // lists of points of features
- std::vector<Slvs_hEntity> anEntities; // list of translated entities
- std::list<ObjectPtr> anObjectList = aRefList->list();
- std::list<ObjectPtr>::iterator anObjectIter = anObjectList.begin();
- while (anObjectIter != anObjectList.end()) {
- for (size_t i = 0; i < MAX_POINTS; i++)
- aPoints[i].clear();
- anEntities.clear();
+ myStorage->update(aStartPointAttr);
+ theStartPoint = myStorage->entity(aStartPointAttr);
+ myStorage->update(aEndPointAttr);
+ theEndPoint = myStorage->entity(aEndPointAttr);
- for (size_t i = 0; i <= myNumberOfCopies && anObjectIter != anObjectList.end(); i++, anObjectIter++) {
- aFeature = ModelAPI_Feature::feature(*anObjectIter);
- if (!aFeature)
- continue;
- anEntityID = changeEntity(aFeature, aType);
- anEntities.push_back(anEntityID);
- Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
- switch (aType) {
- case SLVS_E_POINT_IN_2D:
- case SLVS_E_POINT_IN_3D:
- aPoints[0].push_back(anEntityID);
- break;
- case SLVS_E_LINE_SEGMENT:
- aPoints[0].push_back(anEntity.point[0]); // start point of line
- aPoints[1].push_back(anEntity.point[1]); // end point of line
- break;
- case SLVS_E_CIRCLE:
- aPoints[0].push_back(anEntity.point[0]); // center of circle
- break;
- case SLVS_E_ARC_OF_CIRCLE:
- aPoints[0].push_back(anEntity.point[0]); // center of arc
- aPoints[1].push_back(anEntity.point[1]); // start point of arc
- aPoints[2].push_back(anEntity.point[2]); // end point of arc
- break;
- default:
- myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
- return;
- }
- }
+ getEntitiesAndCopies(theEntities);
- for (size_t i = 0; i < MAX_POINTS; ++i)
- if (!aPoints[i].empty())
- thePoints.push_back(aPoints[i]);
- if (!anEntities.empty())
- theEntities.push_back(anEntities);
- }
}
void SketchSolver_ConstraintMultiTranslation::process()
{
cleanErrorMsg();
- if (!myBaseConstraint || !myStorage || myGroup == 0) {
+ if (!myBaseConstraint || !myStorage || myGroupID == GID_UNKNOWN) {
/// TODO: Put error message here
return;
}
- if (!mySlvsConstraints.empty()) // some data is changed, update constraint
- update(myBaseConstraint);
- Slvs_hEntity aStartPoint, aEndPoint;
- std::vector<std::vector<Slvs_hEntity> > anEntitiesAndCopies;
- getAttributes(aStartPoint, aEndPoint, myPointsAndCopies, anEntitiesAndCopies);
+ EntityWrapperPtr aStartPoint, aEndPoint;
+ std::list<std::list<EntityWrapperPtr> > anEntitiesAndCopies;
+ getAttributes(aStartPoint, aEndPoint, anEntitiesAndCopies);
if (!myErrorMsg.empty())
return;
- // Create translation line
- if (myTranslationLine == SLVS_E_UNKNOWN) {
- Slvs_Entity aTranslationLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(),
- myGroup->getWorkplaneId(), aStartPoint, aEndPoint);
- aTranslationLine.h = myStorage->addEntity(aTranslationLine);
- myTranslationLine = aTranslationLine.h;
- } else {
- Slvs_Entity aTranslationLine = myStorage->getEntity(myTranslationLine);
- if (aTranslationLine.point[0] != aStartPoint || aTranslationLine.point[1] != aEndPoint) {
- aTranslationLine.point[0] = aStartPoint;
- aTranslationLine.point[1] = aEndPoint;
- myStorage->updateEntity(aTranslationLine);
- }
+ BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+ std::list<ConstraintWrapperPtr> aTransConstraints;
+
+ std::list< std::list<EntityWrapperPtr> >::iterator anEntIt = anEntitiesAndCopies.begin();
+ for (; anEntIt != anEntitiesAndCopies.end(); ++anEntIt) {
+ std::list<ConstraintWrapperPtr> aNewConstraints =
+ aBuilder->createConstraint(myBaseConstraint, myGroupID, mySketchID, myType,
+ 0.0, aStartPoint, aEndPoint, *anEntIt);
+ aTransConstraints.insert(aTransConstraints.end(), aNewConstraints.begin(), aNewConstraints.end());
}
+ myStorage->addConstraint(myBaseConstraint, aTransConstraints);
myAdjusted = false;
- processEntities(anEntitiesAndCopies);
adjustConstraint();
}
-void SketchSolver_ConstraintMultiTranslation::adjustConstraint()
-{
- if (myAdjusted)
- return;
-
- Slvs_Entity aTranslationLine = myStorage->getEntity(myTranslationLine);
- Slvs_hConstraint aFixed; // temporary variable
- // Set the translation line unchanged during constraint recalculation
- for (int i = 0; i < 2; i++) {
- if (myStorage->isPointFixed(aTranslationLine.point[i], aFixed, true))
- continue;
- Slvs_Constraint aConstraint = Slvs_MakeConstraint(
- SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_WHERE_DRAGGED, myGroup->getWorkplaneId(), 0.0,
- aTranslationLine.point[i], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- aConstraint.h = myStorage->addConstraint(aConstraint);
- myStorage->addTemporaryConstraint(aConstraint.h);
- }
-
- // Check if the distance between point is 0, no need to resolve constraints (just wait another values)
- double aXY[4];
- for (int i = 0; i < 2; i++) {
- Slvs_Entity aPnt = myStorage->getEntity(aTranslationLine.point[i]);
- aXY[2*i] = myStorage->getParameter(aPnt.param[0]).val;
- aXY[2*i+1] = myStorage->getParameter(aPnt.param[1]).val;
- }
- myDelta[0] = aXY[2] - aXY[0];
- myDelta[1] = aXY[3] - aXY[1];
- if (fabs(myDelta[0]) + fabs(myDelta[1]) < tolerance) {
- myStorage->setNeedToResolve(false);
- return;
- }
-
- SketchSolver_ConstraintMulti::adjustConstraint();
-}
-
-void SketchSolver_ConstraintMultiTranslation::getRelative(
- double theAbsX, double theAbsY, double& theRelX, double& theRelY)
-{
- theRelX = theAbsX;
- theRelY = theAbsY;
-}
-
-void SketchSolver_ConstraintMultiTranslation::getAbsolute(
- double theRelX, double theRelY, double& theAbsX, double& theAbsY)
-{
- theAbsX = theRelX;
- theAbsY = theRelY;
-}
-
-void SketchSolver_ConstraintMultiTranslation::transformRelative(double& theX, double& theY)
-{
- // translate coordinates
- theX += myDelta[0];
- theY += myDelta[1];
-}
-
const std::string& SketchSolver_ConstraintMultiTranslation::nameNbObjects()
{
return SketchPlugin_MultiTranslation::NUMBER_OF_OBJECTS_ID();
public:
/// Constructor based on SketchPlugin constraint
SketchSolver_ConstraintMultiTranslation(ConstraintPtr theConstraint) :
- SketchSolver_ConstraintMulti(theConstraint),
- myTranslationLine(SLVS_E_UNKNOWN)
+ SketchSolver_ConstraintMulti(theConstraint)
{}
- virtual int getType() const
- { return SLVS_C_MULTI_TRANSLATION; }
-
protected:
/// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
virtual void process();
/// \brief Generate list of translated entities
- /// \param[out] theStartPoint ID of start point of translation
- /// \param[out] theEndPoint ID of final point of translation
- /// \param[out] thePoints list of IDs of initial points and their translated copies
- /// \param[out] theEntities list of IDs of entities and their translated copies
- void getAttributes(Slvs_hEntity& theStartPoint, Slvs_hEntity& theEndPoint,
- std::vector< std::vector<Slvs_hEntity> >& thePoints,
- std::vector< std::vector<Slvs_hEntity> >& theEntities);
-
- /// \brief This method is used in derived objects to check consistence of constraint.
- virtual void adjustConstraint();
+ /// \param[out] theStartPoint start point of translation
+ /// \param[out] theEndPoint final point of translation
+ /// \param[out] theEntities list of entities and their translated copies
+ void getAttributes(EntityWrapperPtr& theStartPoint, EntityWrapperPtr& theEndPoint,
+ std::list< std::list<EntityWrapperPtr> >& theEntities);
/// \brief Update parameters (called from base class)
virtual void updateLocal()
{}
-private:
- /// \brief Convert absolute coordinates to relative coordinates
- virtual void getRelative(double theAbsX, double theAbsY, double& theRelX, double& theRelY);
- /// \brief Convert relative coordinates to absolute coordinates
- virtual void getAbsolute(double theRelX, double theRelY, double& theAbsX, double& theAbsY);
- /// \brief Apply transformation for relative coordinates
- virtual void transformRelative(double& theX, double& theY);
-
private:
/// \brief Returns name of NUMBER_OF_COPIES parameter for corresponding feature
virtual const std::string& nameNbObjects();
-
-private:
- Slvs_hEntity myTranslationLine; ///< ID of translation line
-
- double myDelta[2]; ///< increment of translation
};
#endif
+++ /dev/null
-#include <SketchSolver_ConstraintParametric.h>
-#include <SketchSolver_Error.h>
-#include <SketchSolver_Group.h>
-
-#include <GeomDataAPI_Point2D.h>
-
-SketchSolver_ConstraintParametric::SketchSolver_ConstraintParametric(AttributePtr theAttribute)
- : SketchSolver_ConstraintRigid(ConstraintPtr()),
- myBaseAttribute(theAttribute)
-{
- process();
-}
-
-void SketchSolver_ConstraintParametric::process()
-{
- cleanErrorMsg();
- if (!myBaseAttribute || !myStorage || myGroup == 0) {
- /// TODO: Put error message here
- return;
- }
- if (!mySlvsConstraints.empty()) // some data is changed, update constraint
- update(myBaseConstraint);
-
- Slvs_hEntity anAttrID;
- getAttributes(anAttrID);
- if (!myErrorMsg.empty() || (myFeatureMap.empty() && myAttributeMap.empty()))
- return;
-
- myHorizLineID = SLVS_E_UNKNOWN;
- myVertLineID = SLVS_E_UNKNOWN;
-
- std::shared_ptr<GeomDataAPI_Point2D> aPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(myBaseAttribute);
- if (!aPoint)
- return;
- if (!aPoint->textX().empty()) {
- // Create vertical line with fixed boundary point
- Slvs_Entity aLine = createLine(aPoint->x(), -100.0, aPoint->x(), 100.0);
- // Place point on line
- Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
- SLVS_C_PT_ON_LINE, myGroup->getWorkplaneId(), 0.0, anAttrID, SLVS_E_UNKNOWN,
- aLine.h, SLVS_E_UNKNOWN);
- aConstraint.h = myStorage->addConstraint(aConstraint);
- mySlvsConstraints.push_back(aConstraint.h);
- myVertLineID = aLine.h;
- myX = aPoint->x();
- }
- if (!aPoint->textY().empty()) {
- // Create horizontal line with fixed boundary points
- Slvs_Entity aLine = createLine(-100.0, aPoint->y(), 100.0, aPoint->y());
- // Place point on line
- Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
- SLVS_C_PT_ON_LINE, myGroup->getWorkplaneId(), 0.0, anAttrID, SLVS_E_UNKNOWN,
- aLine.h, SLVS_E_UNKNOWN);
- aConstraint.h = myStorage->addConstraint(aConstraint);
- mySlvsConstraints.push_back(aConstraint.h);
- myHorizLineID = aLine.h;
- myY = aPoint->y();
- }
-}
-
-
-void SketchSolver_ConstraintParametric::getAttributes(Slvs_hEntity& theAttributeID)
-{
- int aType = SLVS_E_UNKNOWN; // type of created entity
- theAttributeID = SLVS_E_UNKNOWN;
- theAttributeID = myGroup->getAttributeId(myBaseAttribute);
- if (theAttributeID == SLVS_E_UNKNOWN) {
- theAttributeID = changeEntity(myBaseAttribute, aType);
- if (theAttributeID == SLVS_E_UNKNOWN) {
- myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
- return;
- }
- }
- else
- myAttributeMap[myBaseAttribute] = theAttributeID;
-}
-
-
-void SketchSolver_ConstraintParametric::update(ConstraintPtr theConstraint)
-{
- cleanErrorMsg();
- if (!theConstraint || theConstraint == myBaseConstraint) {
- std::shared_ptr<GeomDataAPI_Point2D> aPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(myBaseAttribute);
- if (aPoint && ((!aPoint->textX().empty() && myVertLineID == SLVS_E_UNKNOWN) ||
- (!aPoint->textY().empty() && myHorizLineID == SLVS_E_UNKNOWN))) {
- remove();
- process();
- return;
- }
- }
- adjustConstraint();
-}
-
-void SketchSolver_ConstraintParametric::refresh()
-{
- Slvs_hEntity aBasePointID = myAttributeMap[myBaseAttribute];
- const Slvs_Entity& aBasePoint = myStorage->getEntity(aBasePointID);
- double aXY[2];
- aXY[0] = myVertLineID != SLVS_E_UNKNOWN ? myX : myStorage->getParameter(aBasePoint.param[0]).val;
- aXY[1] = myHorizLineID != SLVS_E_UNKNOWN ? myY : myStorage->getParameter(aBasePoint.param[1]).val;
-
- std::list<Slvs_Constraint> aCoincidence = myStorage->getConstraintsByType(SLVS_C_POINTS_COINCIDENT);
- std::list<Slvs_Constraint>::const_iterator aCIt = aCoincidence.begin();
- for (; aCIt != aCoincidence.end(); ++aCIt) {
- if (aCIt->ptA != aBasePointID && aCIt->ptB != aBasePointID)
- continue;
- Slvs_hEntity anOtherPointID = aCIt->ptA == aBasePointID ? aCIt->ptB : aCIt->ptA;
- const Slvs_Entity& aPoint = myStorage->getEntity(anOtherPointID);
- for (int i = 0; i < 2; i++) {
- Slvs_Param aParam = myStorage->getParameter(aPoint.param[i]);
- aParam.val = aXY[i];
- myStorage->updateParameter(aParam);
- }
- }
-}
-
-void SketchSolver_ConstraintParametric::adjustConstraint()
-{
- std::shared_ptr<GeomDataAPI_Point2D> aPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(myBaseAttribute);
- if (!aPoint)
- return;
-
- if (!aPoint->textX().empty()) {
- const Slvs_Entity& aLine = myStorage->getEntity(myVertLineID);
- const Slvs_Entity& aStartPoint = myStorage->getEntity(aLine.point[0]);
- Slvs_Param aParX = myStorage->getParameter(aStartPoint.param[0]);
- aParX.val = aPoint->x();
- myStorage->updateParameter(aParX);
- myX = aParX.val;
- }
- if (!aPoint->textY().empty()) {
- const Slvs_Entity& aLine = myStorage->getEntity(myHorizLineID);
- const Slvs_Entity& aStartPoint = myStorage->getEntity(aLine.point[0]);
- Slvs_Param aParY = myStorage->getParameter(aStartPoint.param[1]);
- aParY.val = aPoint->y();
- myStorage->updateParameter(aParY);
- myY = aParY.val;
- }
-}
-
-
-Slvs_Entity SketchSolver_ConstraintParametric::createLine(
- double theStartX, double theStartY, double theEndX, double theEndY)
-{
- // Start point
- Slvs_Param aParX = Slvs_MakeParam(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP, theStartX);
- Slvs_Param aParY = Slvs_MakeParam(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP, theStartY);
- aParX.h = myStorage->addParameter(aParX);
- aParY.h = myStorage->addParameter(aParY);
- Slvs_Entity aStartPoint = Slvs_MakePoint2d(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP,
- myGroup->getWorkplaneId(), aParX.h, aParY.h);
- aStartPoint.h = myStorage->addEntity(aStartPoint);
-
- // End point
- aParX = Slvs_MakeParam(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP, theEndX);
- aParY = Slvs_MakeParam(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP, theEndY);
- aParX.h = myStorage->addParameter(aParX);
- aParY.h = myStorage->addParameter(aParY);
- Slvs_Entity aEndPoint = Slvs_MakePoint2d(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP,
- myGroup->getWorkplaneId(), aParX.h, aParY.h);
- aEndPoint.h = myStorage->addEntity(aEndPoint);
-
- // Line
- Slvs_Entity aLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, SLVS_G_OUTOFGROUP,
- myGroup->getWorkplaneId(), aStartPoint.h, aEndPoint.h);
- aLine.h = myStorage->addEntity(aLine);
- return aLine;
-}
+++ /dev/null
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File: SketchSolver_ConstraintParametric.h
-// Created: 15 Jun 2015
-// Author: Artem ZHIDKOV
-
-#ifndef SketchSolver_ConstraintParametric_H_
-#define SketchSolver_ConstraintParametric_H_
-
-#include "SketchSolver.h"
-#include <SketchSolver_ConstraintRigid.h>
-
-/** \class SketchSolver_ConstraintParametric
- * \ingroup Plugins
- * \brief Stores data of Rigid (Fixed) constraint for the attribute
- * which coordinates are given by parametric expression
- */
-class SketchSolver_ConstraintParametric : public SketchSolver_ConstraintRigid
-{
-private:
- /// Creates constraint to manage the given constraint from plugin
- SketchSolver_ConstraintParametric()
- : SketchSolver_ConstraintRigid(ConstraintPtr())
- {}
-
-public:
- /// Creates temporary constraint based on feature
- SketchSolver_ConstraintParametric(AttributePtr theAttribute);
-
- /// \brief Update constraint
- virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
-
- /// \brief Update points coincident with parametric one
- virtual void refresh();
-
-protected:
- /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
- virtual void process();
-
- /// \brief Convert attribute to the entity
- /// \param[out] theAttributeID identifier of the entity related to the attribute
- virtual void getAttributes(Slvs_hEntity& theAttributeID);
-
- /// \brief This method is used in derived objects to check consistence of constraint.
- virtual void adjustConstraint();
-
-private:
- /// \brief Create SolveSpace line with given coordinates
- /// \return created line
- Slvs_Entity createLine(double theStartX, double theStartY, double theEndX, double theEndY);
-
-private:
- AttributePtr myBaseAttribute; ///< attribute given by expression
- Slvs_hEntity myHorizLineID; ///< identifier of horizontal line, containing the point
- Slvs_hEntity myVertLineID; ///< identifier of vertical line, containing the point
- double myX, myY;
-};
-
-#endif
+++ /dev/null
-#include <SketchSolver_ConstraintRigid.h>
-#include <SketchSolver_Error.h>
-#include <SketchSolver_Group.h>
-
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_Circle.h>
-#include <SketchPlugin_ConstraintRigid.h>
-#include <SketchPlugin_Line.h>
-#include <SketchPlugin_Point.h>
-
-#include <GeomAPI_Pnt2d.h>
-#include <GeomAPI_XY.h>
-#include <GeomDataAPI_Point2D.h>
-#include <ModelAPI_AttributeDouble.h>
-
-#include <math.h>
-
-SketchSolver_ConstraintRigid::SketchSolver_ConstraintRigid(FeaturePtr theFeature)
- : SketchSolver_Constraint(),
- myBaseFeature(theFeature)
-{
- process();
-}
-
-void SketchSolver_ConstraintRigid::process()
-{
- cleanErrorMsg();
- if ((!myBaseConstraint && !myBaseFeature) || !myStorage || myGroup == 0) {
- /// TODO: Put error message here
- return;
- }
- if (!mySlvsConstraints.empty()) // some data is changed, update constraint
- update(myBaseConstraint);
-
- double aValue;
- std::vector<Slvs_hEntity> anEntities;
- getAttributes(aValue, anEntities);
- if (!myErrorMsg.empty() || (myFeatureMap.empty() && myAttributeMap.empty()))
- return;
- fixFeature();
-}
-
-void SketchSolver_ConstraintRigid::update(ConstraintPtr theConstraint)
-{
- cleanErrorMsg();
- if (theConstraint && theConstraint == myBaseConstraint &&
- theConstraint->getKind() == myBaseConstraint->getKind() &&
- checkAttributesChanged(theConstraint)) {
- // remove previous constraint and set the given one
- remove(myBaseConstraint);
- myBaseConstraint = theConstraint;
- process();
- }
-}
-
-static void fixEntity(StoragePtr theStorage, const Slvs_hEntity& theEntID)
-{
- Slvs_Entity anEntity = theStorage->getEntity(theEntID);
- anEntity.group = SLVS_G_OUTOFGROUP;
- theStorage->updateEntity(anEntity);
- // move out of group all sub-entities
- for (int i = 0; i < 4; ++i)
- if (anEntity.point[i] != SLVS_E_UNKNOWN)
- fixEntity(theStorage, anEntity.point[i]);
- // move out of group the radius of circle
- if (anEntity.distance != SLVS_E_UNKNOWN)
- fixEntity(theStorage, anEntity.distance);
- // move out of group parameters
- for (int i = 0; i < 4; ++i)
- if (anEntity.param[i] != SLVS_E_UNKNOWN) {
- Slvs_Param aParam = theStorage->getParameter(anEntity.param[i]);
- aParam.group = SLVS_G_OUTOFGROUP;
- theStorage->updateParameter(aParam);
- }
-}
-
-void SketchSolver_ConstraintRigid::fixFeature()
-{
- Slvs_hEntity anEntID = fixedEntity();
- if (anEntID != SLVS_E_UNKNOWN)
- fixEntity(myStorage, anEntID);
-}
-
-Slvs_hEntity SketchSolver_ConstraintRigid::fixedEntity() const
-{
- Slvs_hEntity anEntID = SLVS_E_UNKNOWN;
- if (myBaseConstraint) {
- AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
- if (aRefAttr->isObject()) {
- FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
- std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFound = myFeatureMap.find(aFeature);
- if (aFound != myFeatureMap.end())
- anEntID = aFound->second;
- } else {
- std::map<AttributePtr, Slvs_hEntity>::const_iterator aFound = myAttributeMap.find(aRefAttr->attr());
- if (aFound != myAttributeMap.end())
- anEntID = aFound->second;
- }
- }
- else if (myBaseFeature) {
- std::map<FeaturePtr, Slvs_hEntity>::const_iterator aFound = myFeatureMap.find(myBaseFeature);
- if (aFound != myFeatureMap.end())
- anEntID = aFound->second;
- }
- return anEntID;
-}
-
-void SketchSolver_ConstraintRigid::getAttributes(
- double& theValue,
- std::vector<Slvs_hEntity>& theAttributes)
-{
- theValue = 0.0;
- int aType = SLVS_E_UNKNOWN; // type of created entity
- Slvs_hEntity anEntityID = SLVS_E_UNKNOWN;
- if (myBaseConstraint) {
- // Get the attribute of constraint
- AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
- myBaseConstraint->attribute(SketchPlugin_ConstraintRigid::ENTITY_A()));
- if (!aRefAttr || !aRefAttr->isInitialized()) {
- myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
- return;
- }
- anEntityID = myGroup->getAttributeId(aRefAttr);
- if (anEntityID == SLVS_E_UNKNOWN)
- anEntityID = changeEntity(aRefAttr, aType);
- } else {
- anEntityID = myGroup->getFeatureId(myBaseFeature);
- if (anEntityID == SLVS_E_UNKNOWN)
- anEntityID = changeEntity(myBaseFeature, aType);
- else
- myFeatureMap[myBaseFeature] = anEntityID;
- }
-
- if (anEntityID == SLVS_E_UNKNOWN) {
- myErrorMsg = SketchSolver_Error::NOT_INITIALIZED();
- return;
- }
-
- // Check the entity is complex
- Slvs_Entity anEntity = myStorage->getEntity(anEntityID);
- if (anEntity.point[0] != SLVS_E_UNKNOWN) {
- for (int i = 0; i < 4 && anEntity.point[i]; i++)
- theAttributes.push_back(anEntity.point[i]);
- } else // simple entity
- theAttributes.push_back(anEntityID);
-}
-
-
-bool SketchSolver_ConstraintRigid::remove(ConstraintPtr theConstraint)
-{
- cleanErrorMsg();
- if (theConstraint && theConstraint != myBaseConstraint)
- return false;
- bool isFullyRemoved = true;
-
- std::vector<Slvs_hConstraint>::iterator aCIter = mySlvsConstraints.begin();
- for (; aCIter != mySlvsConstraints.end(); ++aCIter)
- isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved;
-
- std::map<FeaturePtr, Slvs_hEntity>::iterator aFIter = myFeatureMap.begin();
- for (; aFIter != myFeatureMap.end(); ++aFIter)
- isFullyRemoved = myStorage->removeEntity(aFIter->second) && isFullyRemoved;
-
- std::map<AttributePtr, Slvs_hEntity>::iterator anAtIter = myAttributeMap.begin();
- for (; anAtIter != myAttributeMap.end(); ++anAtIter)
- isFullyRemoved = myStorage->removeEntity(anAtIter->second) && isFullyRemoved;
-
- if (isFullyRemoved) {
- myFeatureMap.clear();
- myAttributeMap.clear();
- myValueMap.clear();
- mySlvsConstraints.clear();
- } else
- cleanRemovedEntities();
- return true;
-}
-
-Slvs_hConstraint SketchSolver_ConstraintRigid::fixPoint(const Slvs_hEntity& thePointID)
-{
- if (thePointID == SLVS_E_UNKNOWN)
- return SLVS_C_UNKNOWN;
-
- Slvs_Constraint aConstraint;
- Slvs_hConstraint aConstrID = SLVS_E_UNKNOWN;
- bool isFixed = myStorage->isPointFixed(thePointID, aConstrID, true);
- bool isForceUpdate = (isFixed && !myBaseConstraint &&
- myStorage->isTemporary(aConstrID));
- if (!isForceUpdate) { // create new constraint
- if (isFixed) return aConstrID;
- aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(), getType(), myGroup->getWorkplaneId(),
- 0.0, thePointID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- aConstraint.h = myStorage->addConstraint(aConstraint);
- mySlvsConstraints.push_back(aConstraint.h);
- if (!myBaseConstraint)
- myStorage->addConstraintWhereDragged(aConstraint.h);
- } else { // update already existent constraint
- if (!isFixed || aConstrID == SLVS_C_UNKNOWN || myBaseConstraint)
- return SLVS_C_UNKNOWN;
- aConstraint = myStorage->getConstraint(aConstrID);
- aConstraint.ptA = thePointID;
- myStorage->addConstraint(aConstraint);
- if (!myBaseConstraint)
- myStorage->addConstraintWhereDragged(aConstraint.h);
- }
- return aConstraint.h;
-}
-
-void SketchSolver_ConstraintRigid::fixLine(const Slvs_Entity& theLine)
-{
- Slvs_Constraint anEqual;
- if (myStorage->isAxisParallel(theLine.h)) {
- // Fix one point and a line length
- Slvs_hConstraint aFixed;
- if (!myStorage->isPointFixed(theLine.point[0], aFixed, true) &&
- !myStorage->isPointFixed(theLine.point[1], aFixed, true))
- fixPoint(theLine.point[0]);
- if (!myStorage->isUsedInEqual(theLine.h, anEqual)) {
- // Check the distance is not set yet
- std::list<Slvs_Constraint> aDistConstr = myStorage->getConstraintsByType(SLVS_C_PT_PT_DISTANCE);
- std::list<Slvs_Constraint>::const_iterator aDIt = aDistConstr.begin();
- for (; aDIt != aDistConstr.end(); aDIt++)
- if ((aDIt->ptA == theLine.point[0] && aDIt->ptB == theLine.point[1]) ||
- (aDIt->ptA == theLine.point[1] && aDIt->ptB == theLine.point[0]))
- return;
- // Calculate distance between points on the line
- double aCoords[4];
- for (int i = 0; i < 2; i++) {
- Slvs_Entity aPnt = myStorage->getEntity(theLine.point[i]);
- for (int j = 0; j < 2; j++) {
- Slvs_Param aParam = myStorage->getParameter(aPnt.param[j]);
- aCoords[2*i+j] = aParam.val;
- }
- }
- double aLength = sqrt((aCoords[2] - aCoords[0]) * (aCoords[2] - aCoords[0]) +
- (aCoords[3] - aCoords[1]) * (aCoords[3] - aCoords[1]));
- // fix line length
- Slvs_Constraint aDistance = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(),
- SLVS_C_PT_PT_DISTANCE, myGroup->getWorkplaneId(), aLength,
- theLine.point[0], theLine.point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- aDistance.h = myStorage->addConstraint(aDistance);
- mySlvsConstraints.push_back(aDistance.h);
- }
- return;
- }
- else if (myStorage->isUsedInEqual(theLine.h, anEqual)) {
- // Check another entity of Equal is already fixed
- Slvs_hEntity anOtherEntID = anEqual.entityA == theLine.h ? anEqual.entityB : anEqual.entityA;
- if (myStorage->isEntityFixed(anOtherEntID, true)) {
- // Fix start point of the line (if end point is not fixed yet) ...
- Slvs_hConstraint anEndFixedID = SLVS_E_UNKNOWN;
- bool isFixed = myStorage->isPointFixed(theLine.point[1], anEndFixedID, true);
- if (isFixed == SLVS_E_UNKNOWN)
- fixPoint(theLine.point[0]);
- // ... and create fixed point lying on this line
- Slvs_hEntity aPointToCopy = anEndFixedID == SLVS_E_UNKNOWN ? theLine.point[1] : theLine.point[0];
- // Firstly, search already fixed point on line
- bool isPonLineFixed = false;
- Slvs_hEntity aFixedPoint;
- std::list<Slvs_Constraint> aPonLineList = myStorage->getConstraintsByType(SLVS_C_PT_ON_LINE);
- std::list<Slvs_Constraint>::const_iterator aPLIter = aPonLineList.begin();
- for (; aPLIter != aPonLineList.end() && !isPonLineFixed; aPLIter++)
- if (aPLIter->entityA == theLine.h) {
- isPonLineFixed = myStorage->isPointFixed(aPLIter->ptA, anEndFixedID);
- aFixedPoint = aPLIter->ptA;
- }
-
- if (isPonLineFixed) { // update existent constraint
- myStorage->copyEntity(aPointToCopy, aFixedPoint);
- } else { // create new constraint
- Slvs_hEntity aCopied = myStorage->copyEntity(aPointToCopy);
- Slvs_Constraint aPonLine = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_PT_ON_LINE,
- myGroup->getWorkplaneId(), 0.0, aCopied, SLVS_E_UNKNOWN, theLine.h, SLVS_E_UNKNOWN);
- aPonLine.h = myStorage->addConstraint(aPonLine);
- mySlvsConstraints.push_back(aPonLine.h);
- fixPoint(aCopied);
- }
- return;
- }
- }
-
- for (int i = 0; i < 2; i++)
- fixPoint(theLine.point[i]);
-}
-
-void SketchSolver_ConstraintRigid::fixCircle(const Slvs_Entity& theCircle)
-{
- bool isFixRadius = true;
- // Verify the arc is under Equal constraint
- Slvs_Constraint anEqual;
- if (myStorage->isUsedInEqual(theCircle.h, anEqual)) {
- // Check another entity of Equal is already fixed
- Slvs_hEntity anOtherEntID = anEqual.entityA == theCircle.h ? anEqual.entityB : anEqual.entityA;
- if (myStorage->isEntityFixed(anOtherEntID, true))
- isFixRadius = false;
- }
-
- fixPoint(theCircle.point[0]);
-
- if (isFixRadius) {
- // Search the radius is already fixed
- std::list<Slvs_Constraint> aDiamConstr = myStorage->getConstraintsByType(SLVS_C_DIAMETER);
- std::list<Slvs_Constraint>::const_iterator aDiamIter = aDiamConstr.begin();
- for (; aDiamIter != aDiamConstr.end(); aDiamIter++)
- if (aDiamIter->entityA == theCircle.h)
- return;
-
- // Fix radius of a circle
- AttributeDoublePtr aRadiusAttr = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
- myFeatureMap.begin()->first->attribute(SketchPlugin_Circle::RADIUS_ID()));
- Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_DIAMETER,
- myGroup->getWorkplaneId(), aRadiusAttr->value() * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN,
- myFeatureMap.begin()->second, SLVS_E_UNKNOWN);
- aFixedR.h = myStorage->addConstraint(aFixedR);
- mySlvsConstraints.push_back(aFixedR.h);
- }
-}
-
-void SketchSolver_ConstraintRigid::fixArc(const Slvs_Entity& theArc)
-{
- bool isFixRadius = true;
- std::list<Slvs_hEntity> aPointsToFix;
- aPointsToFix.push_back(theArc.point[1]);
- aPointsToFix.push_back(theArc.point[2]);
-
- // Verify the arc is under Equal constraint
- Slvs_Constraint anEqual;
- if (myStorage->isUsedInEqual(theArc.h, anEqual)) {
- // Check another entity of Equal is already fixed
- Slvs_hEntity anOtherEntID = anEqual.entityA == theArc.h ? anEqual.entityB : anEqual.entityA;
- if (myStorage->isEntityFixed(anOtherEntID, true)) {
- isFixRadius = false;
- Slvs_Entity anOtherEntity = myStorage->getEntity(anOtherEntID);
- if (anOtherEntity.type == SLVS_E_LINE_SEGMENT) {
- aPointsToFix.pop_back();
- aPointsToFix.push_back(theArc.point[0]);
- }
- }
- }
-
- Slvs_hConstraint aConstrID;
- int aNbPointsToFix = 2; // number of fixed points for the arc
- if (myStorage->isPointFixed(theArc.point[0], aConstrID, true))
- aNbPointsToFix--;
-
- // Radius of the arc
- FeaturePtr aFeature = myFeatureMap.begin()->first;
- std::shared_ptr<GeomAPI_Pnt2d> aCenter = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->pnt();
- std::shared_ptr<GeomAPI_Pnt2d> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aFeature->attribute(SketchPlugin_Arc::START_ID()))->pnt();
- double aRadius = aCenter->distance(aStart);
-
- // Update end point of the arc to be on a curve
- std::shared_ptr<GeomAPI_Pnt2d> anEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aFeature->attribute(SketchPlugin_Arc::END_ID()))->pnt();
- double aDistance = anEnd->distance(aCenter);
- std::shared_ptr<GeomAPI_XY> aDir = anEnd->xy()->decreased(aCenter->xy());
- if (aDistance < tolerance)
- aDir = aStart->xy()->decreased(aCenter->xy())->multiplied(-1.0);
- else
- aDir = aDir->multiplied(aRadius / aDistance);
- double xy[2] = {aCenter->x() + aDir->x(), aCenter->y() + aDir->y()};
- Slvs_Entity aEndPoint = myStorage->getEntity(theArc.point[2]);
- for (int i = 0; i < 2; i++) {
- Slvs_Param aParam = myStorage->getParameter(aEndPoint.param[i]);
- aParam.val = xy[i];
- myStorage->updateParameter(aParam);
- }
-
- std::list<Slvs_hEntity>::iterator aPtIt = aPointsToFix.begin();
- for (; aNbPointsToFix > 0; aPtIt++, aNbPointsToFix--)
- fixPoint(*aPtIt);
-
- if (isFixRadius) {
- // Fix radius of the arc
- bool isExists = false;
- std::list<Slvs_Constraint> aDiamConstraints = myStorage->getConstraintsByType(SLVS_C_DIAMETER);
- std::list<Slvs_Constraint>::iterator anIt = aDiamConstraints.begin();
- for (; anIt != aDiamConstraints.end() && !isExists; anIt++)
- if (anIt->entityA == theArc.h)
- isExists = true;
- if (!isExists) {
- Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), SLVS_C_DIAMETER,
- myGroup->getWorkplaneId(), aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN,
- myFeatureMap.begin()->second, SLVS_E_UNKNOWN);
- aFixedR.h = myStorage->addConstraint(aFixedR);
- mySlvsConstraints.push_back(aFixedR.h);
- if (!myBaseConstraint)
- myStorage->addConstraintWhereDragged(aFixedR.h);
- }
- }
-}
+++ /dev/null
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File: SketchSolver_ConstraintRigid.h
-// Created: 30 Mar 2015
-// Author: Artem ZHIDKOV
-
-#ifndef SketchSolver_ConstraintRigid_H_
-#define SketchSolver_ConstraintRigid_H_
-
-#include "SketchSolver.h"
-#include <SketchSolver_Constraint.h>
-
-/** \class SketchSolver_ConstraintRigid
- * \ingroup Plugins
- * \brief Stores data of Rigid (Fixed) constraint
- *
- * Rigid constraint may have NULL basic SketchPlugin constraint,
- * because the Rigid constraint may be temporary for correct moving of objects.
- *
- * Rigid constraint does not create a constraint, but builds the entities in separate group,
- * so they will not be moved while resolving the set of constraints.
- */
-class SketchSolver_ConstraintRigid : public SketchSolver_Constraint
-{
-public:
- /// Creates constraint to manage the given constraint from plugin
- SketchSolver_ConstraintRigid(ConstraintPtr theConstraint)
- : SketchSolver_Constraint(theConstraint)
- {}
- /// Creates temporary constraint based on feature
- SketchSolver_ConstraintRigid(FeaturePtr theFeature);
-
- /// \brief Update constraint
- virtual void update(ConstraintPtr theConstraint = ConstraintPtr());
-
- /// \brief Tries to remove constraint
- /// \return \c false, if current constraint contains another SketchPlugin constraints (like for multiple coincidence)
- virtual bool remove(ConstraintPtr theConstraint = ConstraintPtr());
-
- /// \brief Returns the type of constraint
- virtual int getType() const
- { return SLVS_C_WHERE_DRAGGED; }
-
-protected:
- /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
- virtual void process();
-
- /// \brief Generate list of attributes of constraint in order useful for SolveSpace constraints
- /// \param[out] theValue numerical characteristic of constraint (e.g. distance)
- /// \param[out] theAttributes list of attributes to be filled
- virtual void getAttributes(double& theValue, std::vector<Slvs_hEntity>& theAttributes);
-
- /// \brief Fixed feature basing on its type
- virtual void fixFeature();
-
- /// \brief Fix given point
- /// \return ID of the Fixed constraint
- Slvs_hConstraint fixPoint(const Slvs_hEntity& thePointID);
-
- /// \brief Returns ID of fixed entity
- Slvs_hEntity fixedEntity() const;
-
- /// \brief Fixing line position (start and end points)
- void fixLine(const Slvs_Entity& theLine);
- /// \brief Fixing circle (center and radius)
- void fixCircle(const Slvs_Entity& theCircle);
- /// \brief The arc is fixed differently to avoid SolveSpace problems (overconstraint)
- ///
- /// There will be fixed start and end points and the radius of the arc.
- void fixArc(const Slvs_Entity& theArc);
-
-protected:
- FeaturePtr myBaseFeature; ///< fixed feature (when it is set, myBaseConstraint should be NULL)
-};
-
-#endif
#include <SketchSolver_ConstraintTangent.h>
-#include <SketchSolver_Group.h>
#include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
+#include <GeomAPI_Pnt2d.h>
-void SketchSolver_ConstraintTangent::process()
+
+/// \brief Check whether the entities has only one shared point
+static bool hasSingleCoincidence(EntityWrapperPtr theEntity1, EntityWrapperPtr theEntity2)
{
- cleanErrorMsg();
- if (!myBaseConstraint || !myStorage || myGroup == 0) {
- /// TODO: Put error message here
- return;
+ BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+
+ const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
+ const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
+
+ std::list<EntityWrapperPtr>::const_iterator aStartIt1 = aPoints1.begin();
+ if (theEntity1->type() == ENTITY_ARC) ++aStartIt1; // skip center of arc
+ std::list<EntityWrapperPtr>::const_iterator aStartIt2 = aPoints2.begin();
+ if (theEntity2->type() == ENTITY_ARC) ++aStartIt2; // skip center of arc
+
+ int aNbCoinc = 0;
+ std::list<EntityWrapperPtr>::const_iterator anIt1, anIt2;
+ for (anIt1 = aStartIt1; anIt1 != aPoints1.end(); ++anIt1) {
+ std::shared_ptr<GeomAPI_Pnt2d> aPt1 = aBuilder->point(*anIt1);
+ for (anIt2 = aStartIt2; anIt2 != aPoints2.end(); ++anIt2) {
+ std::shared_ptr<GeomAPI_Pnt2d> aPt2 = aBuilder->point(*anIt2);
+ if (aPt1->distance(aPt2) < tolerance)
+ ++aNbCoinc;
+ }
}
- if (!mySlvsConstraints.empty()) // some data is changed, update constraint
- update(myBaseConstraint);
+ return aNbCoinc == 1;
+}
+
- double aValue;
- std::vector<Slvs_hEntity> anEntID;
- getAttributes(aValue, anEntID);
- if (!myErrorMsg.empty())
+void SketchSolver_ConstraintTangent::getAttributes(
+ double& theValue,
+ std::vector<EntityWrapperPtr>& theAttributes)
+{
+ SketchSolver_Constraint::getAttributes(theValue, theAttributes);
+ if (!myErrorMsg.empty() || !theAttributes[2] || !theAttributes[3]) {
+ theAttributes.clear();
return;
+ }
+
// Check the quantity of entities of each type and their order (arcs first)
int aNbLines = 0;
int aNbArcs = 0;
- Slvs_Entity anEntities[2];
- myType = SLVS_C_CURVE_CURVE_TANGENT;
- std::vector<Slvs_hEntity>::iterator anEntIter = anEntID.begin();
- for (; anEntIter != anEntID.end(); anEntIter++) {
- Slvs_Entity anEnt = myStorage->getEntity(*anEntIter);
- if (anEnt.type == SLVS_E_LINE_SEGMENT) {
- if (aNbLines == 0)
- anEntities[1 + aNbLines] = anEnt;
- aNbLines++;
- myType = SLVS_C_ARC_LINE_TANGENT;
- }
- else if (anEnt.type == SLVS_E_ARC_OF_CIRCLE) {
- if (aNbArcs < 2)
- anEntities[aNbArcs] = anEnt;
- aNbArcs++;
+ bool isSwap = false; // whether need to swap arguments (arc goes before line)
+ std::vector<EntityWrapperPtr>::iterator anEntIt = theAttributes.begin() + 2;
+ for (; anEntIt != theAttributes.end(); ++anEntIt) {
+ if ((*anEntIt)->type() == ENTITY_LINE)
+ ++aNbLines;
+ else if ((*anEntIt)->type() == ENTITY_ARC) {
+ ++aNbArcs;
+ isSwap = aNbLines > 0;
}
}
- if (aNbLines + aNbArcs != 2) {
- myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
- return;
- } else if (aNbArcs < 1) {
+ if (aNbArcs < 1) {
myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE();
return;
}
-
- // It is necessary to identify which points of entities are coincident
- int aSlvsOtherFlag = 0;
- int aSlvsOther2Flag = 0;
- // Obtain start and end points of entities
- Slvs_hEntity aPointsToFind[4];
- for (int i = 0; i < 2; i++) {
- int aShift = anEntities[i].type == SLVS_E_ARC_OF_CIRCLE ? 1 : 0;
- aPointsToFind[2*i] = anEntities[i].point[aShift];
- aPointsToFind[2*i+1]= anEntities[i].point[aShift+1];
- }
- // Search coincident points
- bool isPointFound = false;
- for (int i = 0; i < 2 && !isPointFound; i++)
- for (int j = 2; j < 4 && !isPointFound; j++)
- if (myStorage->isEqual(aPointsToFind[i], aPointsToFind[j])) {
- aSlvsOtherFlag = i;
- aSlvsOther2Flag = j - 2;
- isPointFound = true;
- }
- if (!isPointFound) {
- // There is no coincident points between tangential objects. Generate error message
- myErrorMsg = SketchSolver_Error::NO_COINCIDENT_POINTS();
+ if (aNbLines == 1 && aNbArcs == 1)
+ myType = CONSTRAINT_TANGENT_ARC_LINE;
+ else if (aNbArcs == 2)
+ myType = CONSTRAINT_TANGENT_ARC_ARC;
+ else {
+ myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
return;
}
- Slvs_Constraint aConstraint = Slvs_MakeConstraint(SLVS_C_UNKNOWN, myGroup->getId(),
- getType(), myGroup->getWorkplaneId(), aValue,
- SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, anEntities[0].h, anEntities[1].h);
- aConstraint.other = aSlvsOtherFlag;
- aConstraint.other2 = aSlvsOther2Flag;
- aConstraint.h = myStorage->addConstraint(aConstraint);
- mySlvsConstraints.push_back(aConstraint.h);
- adjustConstraint();
-}
+ if (!hasSingleCoincidence(theAttributes[2], theAttributes[3]))
+ myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+ if (isSwap) {
+ EntityWrapperPtr aTemp = theAttributes[2];
+ theAttributes[2] = theAttributes[3];
+ theAttributes[3] = aTemp;
+ }
+}
SketchSolver_Constraint(theConstraint)
{}
- virtual int getType() const
- { return myType; }
-
protected:
- /// \brief Converts SketchPlugin constraint to a list of SolveSpace constraints
- virtual void process();
-
-private:
- int myType; ///< type of constraint (applicable: SLVS_C_ARC_LINE_TANGENT, SLVS_C_CURVE_CURVE_TANGENT)
+ /// \brief Generate list of attributes of constraint in order useful for constraints
+ /// \param[out] theValue numerical characteristic of constraint (e.g. distance)
+ /// \param[out] theAttributes list of attributes to be filled
+ virtual void getAttributes(double& theValue, std::vector<EntityWrapperPtr>& theAttributes);
};
#endif
+++ /dev/null
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File: SketchSolver_FeatureStorage.cpp
-// Created: 23 Mar 2015
-// Author: Artem ZHIDKOV
-
-#include <SketchSolver_FeatureStorage.h>
-
-#include <ModelAPI_AttributeRefAttr.h>
-#include <ModelAPI_AttributeRefList.h>
-#include <ModelAPI_ResultConstruction.h>
-#include <GeomDataAPI_Point2D.h>
-
-void SketchSolver_FeatureStorage::changeConstraint(ConstraintPtr theConstraint)
-{
- std::list<AttributePtr> anAttributes = theConstraint->data()->attributes(std::string());
- std::list<AttributePtr>::iterator anIter = anAttributes.begin();
- for (; anIter != anAttributes.end(); anIter++) {
- AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
- if (aRefAttr) {
- if (!aRefAttr->isObject()) {
- changeAttribute(aRefAttr->attr(), theConstraint);
- continue;
- }
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- aRefAttr->object());
- FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
- std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
- if (aFeature)
- changeFeature(aFeature, theConstraint);
- continue;
- }
- AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
- if (aRefList) {
- std::list<ObjectPtr> aList = aRefList->list();
- std::list<ObjectPtr>::iterator aListIter = aList.begin();
- for (; aListIter != aList.end(); aListIter++) {
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- *aListIter);
- FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
- std::dynamic_pointer_cast<ModelAPI_Feature>(*aListIter);
- if (aFeature)
- changeFeature(aFeature, theConstraint);
- }
- continue;
- }
- changeAttribute(*anIter, theConstraint);
- }
- myConstraints.insert(theConstraint);
-}
-
-void SketchSolver_FeatureStorage::removeConstraint(ConstraintPtr theConstraint)
-{
- DataPtr aData = theConstraint->data();
- if (aData) { // Constraint has data. Iterate through its attributes and remove them
- std::list<AttributePtr> anAttributes = aData->attributes(std::string());
- std::list<AttributePtr>::iterator anIter = anAttributes.begin();
- for (; anIter != anAttributes.end(); anIter++) {
- AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
- if (aRefAttr) {
- if (!aRefAttr->isObject()) {
- removeAttribute(aRefAttr->attr(), theConstraint);
- continue;
- }
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- aRefAttr->object());
- FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
- std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
- if (aFeature)
- removeFeature(aFeature, theConstraint);
- continue;
- }
- AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
- if (aRefList) {
- std::list<ObjectPtr> aList = aRefList->list();
- std::list<ObjectPtr>::iterator aListIter = aList.begin();
- for (; aListIter != aList.end(); aListIter++) {
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- *aListIter);
- FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
- std::dynamic_pointer_cast<ModelAPI_Feature>(*aListIter);
- if (aFeature)
- removeFeature(aFeature, theConstraint);
- }
- continue;
- }
- removeAttribute(*anIter, theConstraint);
- }
- } else { // Constraint has no data. Search the links on it in the lists of back references for features and attributes
- std::set<ConstraintPtr>::iterator aCIter;
- MapFeatureConstraint::iterator aFeatIter = myFeatures.begin();
- while (aFeatIter != myFeatures.end()) {
- aCIter = aFeatIter->second.find(theConstraint);
- if (aCIter != aFeatIter->second.end()) {
- FeaturePtr aFeature = aFeatIter->first;
- aFeatIter++;
- removeFeature(aFeature, theConstraint);
- continue;
- }
- aFeatIter++;
- }
- std::set<FeaturePtr>::iterator aFIter;
- MapAttributeFeature::iterator anAttrIter = myAttributes.begin();
- while (anAttrIter != myAttributes.end()) {
- aFIter = anAttrIter->second.find(theConstraint);
- if (aFIter != anAttrIter->second.end()) {
- anAttrIter->second.erase(aFIter);
- if (anAttrIter->second.empty()) {
- MapAttributeFeature::iterator aTmpIter = anAttrIter; // stores iterator for the next element, while the current is deleting
- aTmpIter++;
- myAttributes.erase(anAttrIter);
- anAttrIter = aTmpIter;
- continue;
- }
- }
- anAttrIter++;
- }
- }
- myConstraints.erase(theConstraint);
-}
-
-bool SketchSolver_FeatureStorage::isInteract(ConstraintPtr theConstraint) const
-{
- if (myConstraints.empty() || myConstraints.find(theConstraint) != myConstraints.end())
- return true;
-
- DataPtr aData = theConstraint->data();
- if (!aData)
- return false;
-
- std::list<AttributePtr> anAttributes = aData->attributes(std::string());
- std::list<AttributePtr>::iterator anIter = anAttributes.begin();
- for (; anIter != anAttributes.end(); anIter++) {
- AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
- if (aRefAttr) {
- if (!aRefAttr->isObject()) {
- if (isInteract(aRefAttr->attr()))
- return true;
- continue;
- }
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- aRefAttr->object());
- FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
- std::dynamic_pointer_cast<ModelAPI_Feature>(aRefAttr->object());
- if (aFeature)
- if (isInteract(aFeature))
- return true;
- continue;
- }
- AttributeRefListPtr aRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anIter);
- if (aRefList) {
- std::list<ObjectPtr> aList = aRefList->list();
- std::list<ObjectPtr>::iterator aListIter = aList.begin();
- for (; aListIter != aList.end(); aListIter++) {
- ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
- *aListIter);
- FeaturePtr aFeature = aRC ? aRC->document()->feature(aRC) :
- std::dynamic_pointer_cast<ModelAPI_Feature>(*aListIter);
- if (aFeature)
- if (isInteract(aFeature))
- return true;
- }
- continue;
- }
- if (isInteract(*anIter))
- return true;
- }
- return false;
-}
-
-
-void SketchSolver_FeatureStorage::changeFeature(FeaturePtr theFeature)
-{
- std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
- std::list<AttributePtr>::iterator anIter = anAttributes.begin();
- for (; anIter != anAttributes.end(); anIter++) {
- AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
- if (aRefAttr) {
- if (!aRefAttr->isObject())
- changeAttribute(aRefAttr->attr(), theFeature);
- continue;
- }
- changeAttribute(*anIter, theFeature);
- }
- if (myFeatures.find(theFeature) == myFeatures.end())
- myFeatures[theFeature] = std::set<ConstraintPtr>();
-}
-
-void SketchSolver_FeatureStorage::changeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint)
-{
- // Change all attributes of the feature
- changeFeature(theFeature);
- // Add back reference feature to constraint
- myFeatures[theFeature].insert(theConstraint);
-}
-
-void SketchSolver_FeatureStorage::removeFeature(FeaturePtr theFeature)
-{
- MapFeatureConstraint::iterator aFeatIter = myFeatures.find(theFeature);
- if (aFeatIter == myFeatures.end())
- return; // no such feature
-
- std::set<ConstraintPtr> aConstraints = aFeatIter->second;
- std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
- for (; aCIter != aConstraints.end(); aCIter++)
- removeFeature(theFeature, *aCIter);
-}
-
-void SketchSolver_FeatureStorage::removeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint)
-{
- MapFeatureConstraint::iterator aFeatIter = myFeatures.find(theFeature);
- if (aFeatIter == myFeatures.end())
- return; // no such feature
-
- if (theFeature->data()) {
- std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
- std::list<AttributePtr>::iterator anIter = anAttributes.begin();
- for (; anIter != anAttributes.end(); anIter++) {
- AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
- if (aRefAttr) {
- if (!aRefAttr->isObject())
- removeAttribute(aRefAttr->attr(), theFeature);
- continue;
- }
- removeAttribute(*anIter, theFeature);
- }
- } else {
- // iterate on attributes to find items refered to theFeature
- MapAttributeFeature::iterator anIter = myAttributes.begin();
- while (anIter != myAttributes.end()) {
- if (anIter->second.find(theFeature) != anIter->second.end()) {
- anIter->second.erase(theFeature);
- if (anIter->second.empty()) {
- MapAttributeFeature::iterator aDeadIter = anIter++;
- myAttributes.erase(aDeadIter);
- continue;
- }
- }
- anIter++;
- }
- }
-
- aFeatIter->second.erase(theConstraint);
- if (aFeatIter->second.empty())
- myFeatures.erase(aFeatIter);
-}
-
-bool SketchSolver_FeatureStorage::isInteract(FeaturePtr theFeature) const
-{
- if (myFeatures.find(theFeature) != myFeatures.end())
- return true;
- if (!theFeature->data() || !theFeature->data()->isValid())
- return false;
-
- std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
- std::list<AttributePtr>::iterator anIter = anAttributes.begin();
- for (; anIter != anAttributes.end(); anIter++) {
- AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anIter);
- if (aRefAttr) {
- if (!aRefAttr->isObject())
- if (isInteract(aRefAttr->attr()))
- return true;
- continue;
- }
- if (isInteract(*anIter))
- return true;
- }
- return false;
-}
-
-
-void SketchSolver_FeatureStorage::changeAttribute(AttributePtr theAttribute)
-{
- if (myAttributes.find(theAttribute) == myAttributes.end())
- myAttributes[theAttribute] = std::set<FeaturePtr>();
-}
-
-void SketchSolver_FeatureStorage::changeAttribute(AttributePtr theAttribute, FeaturePtr theFeature)
-{
- MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute);
- if (anAttrIter == myAttributes.end()) {
- std::set<FeaturePtr> aFeatures;
- aFeatures.insert(theFeature);
- myAttributes[theAttribute] = aFeatures;
- return;
- }
- anAttrIter->second.insert(theFeature);
-}
-
-void SketchSolver_FeatureStorage::removeAttribute(AttributePtr theAttribute)
-{
- MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute);
- if (anAttrIter == myAttributes.end())
- return;
-
- std::set<FeaturePtr> aFeatures = anAttrIter->second;
- std::set<FeaturePtr>::iterator aFeatIter = aFeatures.begin();
- for (; aFeatIter != aFeatures.end(); aFeatIter++)
- removeAttribute(theAttribute, *aFeatIter);
-}
-
-void SketchSolver_FeatureStorage::removeAttribute(AttributePtr theAttribute, FeaturePtr theFeature)
-{
- MapAttributeFeature::iterator anAttrIter = myAttributes.find(theAttribute);
- if (anAttrIter == myAttributes.end())
- return; // no such attribute
-
- anAttrIter->second.erase(theFeature);
- if (!anAttrIter->second.empty())
- return;
-
- // Check there is no features containing such attribute
- MapFeatureConstraint::iterator aFeatIter = myFeatures.begin();
- for (; aFeatIter != myFeatures.end(); aFeatIter++) {
- DataPtr aData = aFeatIter->first->data();
- if (!aData || !aData->isValid())
- continue;
- std::list<AttributePtr> anAttrList = aData->attributes(GeomDataAPI_Point2D::typeId());
- std::list<AttributePtr>::iterator anAtIt = anAttrList.begin();
- for (; anAtIt != anAttrList.end(); anAtIt++) {
- std::shared_ptr<GeomDataAPI_Point2D> aPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anAtIt);
- if (aPoint == theAttribute)
- anAttrIter->second.insert(aFeatIter->first);
- }
- }
- if (anAttrIter->second.empty())
- myAttributes.erase(anAttrIter);
-}
-
-bool SketchSolver_FeatureStorage::isInteract(AttributePtr theAttribute) const
-{
- return myAttributes.find(theAttribute) != myAttributes.end();
-}
-
-
-bool SketchSolver_FeatureStorage::isConsistent() const
-{
- // Check the constraints are valid
- std::set<ConstraintPtr>::const_iterator aCIter = myConstraints.begin();
- for (; aCIter != myConstraints.end(); aCIter++)
- if (!(*aCIter)->data() || !(*aCIter)->data()->isValid())
- return false;
- // Check the features are valid
- MapFeatureConstraint::const_iterator aFIter = myFeatures.begin();
- for (; aFIter != myFeatures.end(); aFIter++)
- if (!aFIter->first->data() || !aFIter->first->data()->isValid())
- return false;
- return true;
-}
-
-std::set<ConstraintPtr> SketchSolver_FeatureStorage::getConstraints(FeaturePtr theFeature) const
-{
- std::set<ConstraintPtr> aResult;
- MapFeatureConstraint::const_iterator aFeatIter = myFeatures.find(theFeature);
- if (aFeatIter != myFeatures.end())
- aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end());
-
- std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
- std::list<AttributePtr>::const_iterator anAttrIter = anAttributes.begin();
- for (; anAttrIter != anAttributes.end(); anAttrIter++) {
- MapAttributeFeature::const_iterator anIt = myAttributes.find(*anAttrIter);
- if (anIt == myAttributes.end())
- continue;
- std::set<FeaturePtr>::const_iterator aFIter = anIt->second.begin();
- for (; aFIter != anIt->second.end(); aFIter++) {
- aFeatIter = myFeatures.find(*aFIter);
- if (aFeatIter != myFeatures.end())
- aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end());
- else {
- ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(*aFIter);
- if (aConstraint)
- aResult.insert(aConstraint);
- }
- }
- }
- return aResult;
-}
-
-std::set<ConstraintPtr> SketchSolver_FeatureStorage::getConstraints(AttributePtr theAttribute) const
-{
- std::set<ConstraintPtr> aResult;
- MapAttributeFeature::const_iterator anIt = myAttributes.find(theAttribute);
- if (anIt == myAttributes.end())
- return aResult;
- std::set<FeaturePtr>::const_iterator aFIter = anIt->second.begin();
- MapFeatureConstraint::const_iterator aFeatIter;
- for (; aFIter != anIt->second.end(); aFIter++) {
- aFeatIter = myFeatures.find(*aFIter);
- if (aFeatIter != myFeatures.end())
- aResult.insert(aFeatIter->second.begin(), aFeatIter->second.end());
- else {
- ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(*aFIter);
- if (aConstraint)
- aResult.insert(aConstraint);
- }
- }
- return aResult;
-}
-
-void SketchSolver_FeatureStorage::blockEvents(bool isBlocked) const
-{
- std::set<ConstraintPtr>::iterator aCIter = myConstraints.begin();
- for (; aCIter != myConstraints.end(); aCIter++)
- if ((*aCIter)->data() && (*aCIter)->data()->isValid())
- (*aCIter)->data()->blockSendAttributeUpdated(isBlocked);
-
- MapFeatureConstraint::const_iterator aFIter = myFeatures.begin();
- for (; aFIter != myFeatures.end(); aFIter++)
- if (aFIter->first->data() && aFIter->first->data()->isValid())
- aFIter->first->data()->blockSendAttributeUpdated(isBlocked);
-
- MapAttributeFeature::const_iterator anAtIter = myAttributes.begin();
- for (; anAtIter != myAttributes.end(); anAtIter++)
- if (anAtIter->first->owner() && anAtIter->first->owner()->data() &&
- anAtIter->first->owner()->data()->isValid())
- anAtIter->first->owner()->data()->blockSendAttributeUpdated(isBlocked);
-}
+++ /dev/null
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File: SketchSolver_FeatureStorage.h
-// Created: 23 Mar 2015
-// Author: Artem ZHIDKOV
-
-#ifndef SketchSolver_FeatureStorage_H_
-#define SketchSolver_FeatureStorage_H_
-
-#include <SketchSolver.h>
-#include <SketchPlugin_Feature.h>
-#include <SketchPlugin_Constraint.h>
-
-#include <set>
-#include <map>
-
-typedef std::map<FeaturePtr, std::set<ConstraintPtr> > MapFeatureConstraint;
-typedef std::map<AttributePtr, std::set<FeaturePtr> > MapAttributeFeature;
-
-/** \class SketchSolver_FeatureStorage
- * \ingroup Plugins
- * \brief Collects information about SketchPlugin constraints used in specific group
- */
-class SketchSolver_FeatureStorage
-{
-public:
- SketchSolver_FeatureStorage() {}
-
- /// \brief Adds or changes a constraint and all features it uses in the storage
- void changeConstraint(ConstraintPtr theConstraint);
- /// \brief Removes a constraint and all its features not used by other constraints
- void removeConstraint(ConstraintPtr theConstraint);
- /// \brief Verifies a constraint is used in the current storage
- bool isInteract(ConstraintPtr theConstraint) const;
-
- /// \brief Adds or changes a feature in the storage
- void changeFeature(FeaturePtr theFeature);
- /// \brief Adds or changes a feature in the storage. The feature is used in specified constraint
- void changeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint);
- /// \brief Removes a feature
- void removeFeature(FeaturePtr theFeature);
- /// \brief Removes a feature according to a given constraint
- void removeFeature(FeaturePtr theFeature, ConstraintPtr theConstraint);
- /// \brief Verifies a feature is used in the current storage
- bool isInteract(FeaturePtr theFeature) const;
-
- /// \brief Adds or changes an attribute in the storage
- void changeAttribute(AttributePtr theAttribute);
- /// \brief Adds or changes a attribute in the storage.
- /// The attribute is used in specified feature or constraint (theFeature)
- void changeAttribute(AttributePtr theAttribute, FeaturePtr theFeature);
- /// \brief Removes an attribute
- void removeAttribute(AttributePtr theAttribute);
- /// \brief Removes an attribute according to a given feature
- void removeAttribute(AttributePtr theAttribute, FeaturePtr theFeature);
- /// \brief Verifies an attribute is used in the current storage
- bool isInteract(AttributePtr theAttribute) const;
-
- /// \brief Check the features is not removed
- bool isConsistent() const;
-
- /// \brief Prepares list of constraints, which using specified feature or its attributes
- std::set<ConstraintPtr> getConstraints(FeaturePtr theFeature) const;
- /// \brief Prepares list of constraints, which using specified attribute
- std::set<ConstraintPtr> getConstraints(AttributePtr theAttribute) const;
-
- /// \brief Block/unblock events of changing attributes of the features
- void blockEvents(bool isBlocked) const;
-
-private:
- std::set<ConstraintPtr> myConstraints; ///< list of SketchPlugin constraints used in the current group
- MapFeatureConstraint myFeatures; ///< list of features used in the group and corresponding constraints which use the feature
- MapAttributeFeature myAttributes; ///< list of attributes used in the group and corresponding features which are based on the attribute
-};
-
-typedef std::shared_ptr<SketchSolver_FeatureStorage> FeatureStoragePtr;
-
-#endif // SketchSolver_FeatureStorage_H_
#include "SketchSolver_Group.h"
-#include <SketchSolver_Builder.h>
#include <SketchSolver_Constraint.h>
#include <SketchSolver_ConstraintCoincidence.h>
#include <SketchSolver_ConstraintMulti.h>
#include <SketchSolver_Error.h>
+#include <SketchSolver_Manager.h>
#include <Events_Error.h>
#include <Events_Loop.h>
-#include <GeomAPI_XY.h>
-#include <GeomAPI_Dir2d.h>
-#include <GeomAPI_Pnt2d.h>
-#include <GeomDataAPI_Dir.h>
-#include <GeomDataAPI_Point.h>
-#include <GeomDataAPI_Point2D.h>
-#include <ModelAPI_AttributeDouble.h>
#include <ModelAPI_AttributeString.h>
-#include <ModelAPI_Document.h>
#include <ModelAPI_Events.h>
-#include <ModelAPI_ResultConstruction.h>
#include <ModelAPI_Session.h>
#include <ModelAPI_Validator.h>
-#include <SketchPlugin_Constraint.h>
#include <SketchPlugin_ConstraintAngle.h>
#include <SketchPlugin_ConstraintCoincidence.h>
#include <SketchPlugin_ConstraintDistance.h>
#include <SketchPlugin_ConstraintRigid.h>
#include <SketchPlugin_ConstraintTangent.h>
#include <SketchPlugin_ConstraintVertical.h>
-#include <SketchPlugin_Feature.h>
#include <SketchPlugin_MultiRotation.h>
#include <SketchPlugin_MultiTranslation.h>
-#include <SketchPlugin_Sketch.h>
-
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_Circle.h>
-#include <SketchPlugin_Line.h>
-#include <SketchPlugin_Point.h>
-#include <SketchPlugin_Sketch.h>
#include <math.h>
#include <assert.h>
{
public:
/// \brief Return vacant index
- static Slvs_hGroup NEW_GROUP() { return ++myGroupIndex; }
+ static GroupID NEW_GROUP() { return ++myGroupIndex; }
/// \brief Removes the index
- static void REMOVE_GROUP(const Slvs_hGroup& theIndex) {
+ static void REMOVE_GROUP(const GroupID& theIndex) {
if (myGroupIndex == theIndex)
myGroupIndex--;
}
private:
GroupIndexer() {};
- static Slvs_hGroup myGroupIndex; ///< index of the group
+ static GroupID myGroupIndex; ///< index of the group
};
-Slvs_hGroup GroupIndexer::myGroupIndex = SLVS_G_OUTOFGROUP;
+GroupID GroupIndexer::myGroupIndex = GID_OUTOFGROUP;
static void sendMessage(const char* theMessageName)
myPrevSolved(true)
{
// Initialize workplane
- myWorkplaneID = SLVS_E_UNKNOWN;
-#ifndef NDEBUG
- assert(addWorkplane(theWorkplane));
-#else
+ myWorkplaneID = EID_UNKNOWN;
addWorkplane(theWorkplane);
-#endif
}
SketchSolver_Group::~SketchSolver_Group()
// Class: SketchSolver_Group
// Purpose: verify are there any entities in the group used by given constraint
// ============================================================================
-bool SketchSolver_Group::isInteract(
- std::shared_ptr<SketchPlugin_Feature> theFeature) const
+bool SketchSolver_Group::isInteract(FeaturePtr theFeature) const
{
// Empty group interacts with everything
- if (isEmpty()) return true;
- ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
- if (aConstraint)
- return myFeatureStorage->isInteract(aConstraint);
- return myFeatureStorage->isInteract(std::dynamic_pointer_cast<ModelAPI_Feature>(theFeature));
-}
-
-// check the entity is really exists
-static void checkEntity(StoragePtr theStorage, Slvs_hEntity& theEntity)
-{
- if (theEntity == SLVS_E_UNKNOWN)
- return;
- Slvs_Entity anEnt = theStorage->getEntity(theEntity);
- theEntity = anEnt.h;
-}
-
-// ============================================================================
-// Function: getFeatureId
-// Class: SketchSolver_Group
-// Purpose: Find the identifier of the feature, if it already exists in the group
-// ============================================================================
-Slvs_hEntity SketchSolver_Group::getFeatureId(FeaturePtr theFeature) const
-{
- Slvs_hEntity aResult = SLVS_E_UNKNOWN;
- if (!myFeatureStorage)
- return aResult;
- // Obtain regular constraints interacting with the feature and find its ID
- ConstraintConstraintMap::const_iterator aCIter = myConstraints.begin();
- for (; aCIter != myConstraints.end(); ++aCIter) {
- aResult = aCIter->second->getId(theFeature);
- checkEntity(myStorage, aResult);
- if (aResult != SLVS_E_UNKNOWN)
- return aResult;
- }
- // The feature is not found, check it in the temporary constraints
- std::set<SolverConstraintPtr>::iterator aTmpCIter = myTempConstraints.begin();
- for (; aTmpCIter != myTempConstraints.end() && aResult == SLVS_E_UNKNOWN; ++aTmpCIter) {
- aResult = (*aTmpCIter)->getId(theFeature);
- checkEntity(myStorage, aResult);
- }
- return aResult;
-}
-
-// ============================================================================
-// Function: getAttributeId
-// Class: SketchSolver_Group
-// Purpose: Find the identifier of the attribute, if it already exists in the group
-// ============================================================================
-Slvs_hEntity SketchSolver_Group::getAttributeId(AttributePtr theAttribute) const
-{
- Slvs_hEntity aResult = SLVS_E_UNKNOWN;
- if (!myFeatureStorage)
- return aResult;
- // Obtain regular constraints interacting with the attribute and find its ID
- ConstraintConstraintMap::const_iterator aCIter = myConstraints.begin();
- for (; aCIter != myConstraints.end(); ++aCIter) {
- aResult = aCIter->second->getId(theAttribute);
- checkEntity(myStorage, aResult);
- if (aResult != SLVS_E_UNKNOWN)
- return aResult;
- }
- // The attribute is not found, check it in the temporary constraints
- std::set<SolverConstraintPtr>::const_iterator aTmpCIter = myTempConstraints.begin();
- for (; aTmpCIter != myTempConstraints.end() && aResult == SLVS_E_UNKNOWN; ++aTmpCIter) {
- aResult = (*aTmpCIter)->getId(theAttribute);
- checkEntity(myStorage, aResult);
- }
- // Last chance to find attribute in parametric constraints
- std::map<AttributePtr, SolverConstraintPtr>::const_iterator aParIter =
- myParametricConstraints.find(theAttribute);
- if (aParIter != myParametricConstraints.end()) {
- aResult = aParIter->second->getId(theAttribute);
- checkEntity(myStorage, aResult);
- }
- return aResult;
+ if (isEmpty())
+ return true;
+ // Check interaction with the storage
+ return myStorage->isInteract(theFeature);
}
// ============================================================================
std::shared_ptr<SketchPlugin_Constraint> theConstraint)
{
// There is no workplane yet, something wrong
- if (myWorkplaneID == SLVS_E_UNKNOWN)
+ if (myWorkplaneID == EID_UNKNOWN)
return false;
if (!theConstraint || !theConstraint->data())
if (!checkFeatureValidity(theConstraint))
return false;
+ BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+
bool isNewConstraint = myConstraints.find(theConstraint) == myConstraints.end();
if (isNewConstraint) {
// Add constraint to the current group
- SolverConstraintPtr aConstraint =
- SketchSolver_Builder::getInstance()->createConstraint(theConstraint);
+ SolverConstraintPtr aConstraint = aBuilder->createConstraint(theConstraint);
if (!aConstraint)
return false;
- aConstraint->setGroup(this);
- aConstraint->setStorage(myStorage);
+ aConstraint->process(myStorage, getId(), getWorkplaneId());
if (!aConstraint->error().empty()) {
if (aConstraint->error() == SketchSolver_Error::NOT_INITIALIZED())
return false; // some attribute are not initialized yet, don't show message
Events_Error::send(aConstraint->error(), this);
}
-
- // Additional verification of coincidence of several points
- if (theConstraint->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
- bool hasMultiCoincidence = false;
- ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
- for (; aCIter != myConstraints.end(); ++aCIter) {
- std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoincidence =
- std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aCIter->second);
- if (!aCoincidence)
- continue;
- std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoinc2 =
- std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aConstraint);
- if (aCoincidence != aCoinc2 && aCoincidence->isCoincide(aCoinc2)) {
- aCoinc2->attach(aCoincidence);
- // update other coincidences
- ConstraintConstraintMap::iterator anIt = aCIter;
- for (++anIt; anIt != myConstraints.end(); ++anIt)
- if (anIt->second == aCIter->second)
- anIt->second = aCoinc2;
- aCIter->second = aCoinc2;
- hasMultiCoincidence = true;
- }
- }
-
- if (hasMultiCoincidence)
- notifyMultiConstraints();
- }
myConstraints[theConstraint] = aConstraint;
}
else
myConstraints[theConstraint]->update();
- // Fix base features for fillet
- if (isNewConstraint && theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) {
- std::list<AttributePtr> anAttrList =
- theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
- std::list<AttributePtr>::iterator anAttrIter = anAttrList.begin();
- for (; anAttrIter != anAttrList.end(); anAttrIter++) {
- AttributeRefAttrPtr aRefAttr =
- std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
- if (!aRefAttr || !aRefAttr->isObject())
- continue;
- FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
- SolverConstraintPtr aConstraint =
- SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature);
- if (!aConstraint)
- continue;
- aConstraint->setGroup(this);
- aConstraint->setStorage(myStorage);
- setTemporary(aConstraint);
- }
- }
// Fix mirror line
if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) {
AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
theConstraint->attribute(SketchPlugin_ConstraintMirror::ENTITY_A()));
if (aRefAttr && aRefAttr->isObject()) {
- FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+ std::shared_ptr<SketchPlugin_Feature> aFeature =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(
+ ModelAPI_Feature::feature(aRefAttr->object()));
if (aFeature) {
- SolverConstraintPtr aConstraint =
- SketchSolver_Builder::getInstance()->createRigidConstraint(aFeature);
+ SolverConstraintPtr aConstraint = aBuilder->createFixedConstraint(aFeature);
if (aConstraint) {
- aConstraint->setGroup(this);
- aConstraint->setStorage(myStorage);
+ aConstraint->process(myStorage, getId(), getWorkplaneId());
setTemporary(aConstraint);
}
}
}
}
-
- if (!myFeatureStorage)
- myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
- myFeatureStorage->changeConstraint(theConstraint);
-
- // Check the attributes of constraint are given by parametric expression
- std::list<AttributePtr> anAttributes =
- theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
- std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
- for (; anAttrIt != anAttributes.end(); ++anAttrIt) {
- AttributeRefAttrPtr aRefAttr =
- std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIt);
- if (!aRefAttr)
- continue;
-
- std::shared_ptr<GeomDataAPI_Point2D> aPoint;
- if (aRefAttr->isObject()) {
- FeaturePtr aFeat = ModelAPI_Feature::feature(aRefAttr->object());
- if (aFeat->getKind() != SketchPlugin_Point::ID())
- continue;
- aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aFeat->attribute(SketchPlugin_Point::COORD_ID()));
- } else
- aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
-
- if (!aPoint || (aPoint->textX().empty() && aPoint->textY().empty()))
- continue;
-
- std::map<AttributePtr, SolverConstraintPtr>::iterator aFound =
- myParametricConstraints.find(aPoint);
- if (aFound == myParametricConstraints.end()) {
- SolverConstraintPtr aConstraint =
- SketchSolver_Builder::getInstance()->createParametricConstraint(aPoint);
- if (!aConstraint)
- continue;
- aConstraint->setGroup(this);
- aConstraint->setStorage(myStorage);
- myParametricConstraints[aPoint] = aConstraint;
- } else
- aFound->second->update();
- }
-
return true;
}
myChangedConstraints.clear();
}
-bool SketchSolver_Group::updateFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
+bool SketchSolver_Group::updateFeature(FeaturePtr theFeature)
{
if (!checkFeatureValidity(theFeature))
return false;
-
- std::set<ConstraintPtr> aConstraints =
- myFeatureStorage->getConstraints(std::dynamic_pointer_cast<ModelAPI_Feature>(theFeature));
- if (aConstraints.empty())
- return false;
- std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
- for (; aCIter != aConstraints.end(); aCIter++) {
- ConstraintConstraintMap::iterator aSolConIter = myConstraints.find(*aCIter);
- if (aSolConIter == myConstraints.end() || !aSolConIter->first->data() ||
- !aSolConIter->first->data()->isValid())
- continue;
- myFeatureStorage->changeFeature(theFeature, aSolConIter->first);
-
- aSolConIter->second->addFeature(theFeature);
- myChangedConstraints.insert(aSolConIter->first);
- }
-
- // Search attributes of the feature in the set of parametric constraints and update them
- std::list<AttributePtr> anAttrList =
- theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
- std::list<AttributePtr>::iterator anAttrIt = anAttrList.begin();
- for (; anAttrIt != anAttrList.end(); ++anAttrIt) {
- std::map<AttributePtr, SolverConstraintPtr>::iterator aFound =
- myParametricConstraints.find(*anAttrIt);
- if (aFound != myParametricConstraints.end())
- aFound->second->update();
- else {
- std::shared_ptr<GeomDataAPI_Point2D> aPoint =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anAttrIt);
- if (aPoint && (!aPoint->textX().empty() || !aPoint->textY().empty())) {
- // Create new parametric constraint
- SolverConstraintPtr aConstraint =
- SketchSolver_Builder::getInstance()->createParametricConstraint(*anAttrIt);
- if (!aConstraint)
- continue;
- aConstraint->setGroup(this);
- aConstraint->setStorage(myStorage);
- myParametricConstraints[*anAttrIt] = aConstraint;
- }
- }
- }
- return true;
+ myStorage->refresh(true);
+ return myStorage->update(theFeature);
}
-void SketchSolver_Group::moveFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
+void SketchSolver_Group::moveFeature(FeaturePtr theFeature)
{
- // Firstly, create temporary rigid constraint
- SolverConstraintPtr aConstraint =
- SketchSolver_Builder::getInstance()->createMovementConstraint(theFeature);
+ BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+
+ // Firstly, revert changes in the fixed entities
+ myStorage->refresh(true);
+
+ // Secondly, search attributes of the feature in the list of the Multi constraints and update them
+ ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
+ for (; aCIt != myConstraints.end(); ++aCIt) {
+ if ((aCIt->second->getType() == CONSTRAINT_MULTI_ROTATION ||
+ aCIt->second->getType() == CONSTRAINT_MULTI_TRANSLATION)
+ && aCIt->second->isUsed(theFeature))
+ std::dynamic_pointer_cast<SketchSolver_ConstraintMulti>(aCIt->second)->update(true);
+ }
+
+ // Then, create temporary rigid constraint
+ SolverConstraintPtr aConstraint = aBuilder->createMovementConstraint(theFeature);
if (!aConstraint)
return;
- aConstraint->setGroup(this);
- aConstraint->setStorage(myStorage);
+ aConstraint->process(myStorage, getId(), getWorkplaneId());
if (aConstraint->error().empty())
setTemporary(aConstraint);
- // Secondly, update the feature
- updateFeature(theFeature);
-}
-
-// ============================================================================
-// Function: fixFeaturesList
-// Class: SketchSolver_Group
-// Purpose: Apply temporary rigid constraints for the list of features
-// ============================================================================
-void SketchSolver_Group::fixFeaturesList(AttributeRefListPtr theList)
-{
- std::list<ObjectPtr> aList = theList->list();
- std::list<ObjectPtr>::iterator anIt = aList.begin();
- std::list<FeaturePtr> aFeatures;
- // Sort features, at begining there are features used by Equal constraint
- for (; anIt != aList.end(); anIt++) {
- if (!(*anIt))
- continue;
- FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
- std::set<ConstraintPtr> aConstraints = myFeatureStorage->getConstraints(aFeature);
- std::set<ConstraintPtr>::iterator aCIter = aConstraints.begin();
- for (; aCIter != aConstraints.end(); aCIter++)
- if ((*aCIter)->getKind() == SketchPlugin_ConstraintEqual::ID())
- break;
- if (aCIter != aConstraints.end())
- aFeatures.push_front(aFeature);
- else
- aFeatures.push_back(aFeature);
- }
-
- std::list<FeaturePtr>::iterator aFeatIter = aFeatures.begin();
- for (; aFeatIter != aFeatures.end(); aFeatIter++) {
- SolverConstraintPtr aConstraint =
- SketchSolver_Builder::getInstance()->createRigidConstraint(*aFeatIter);
- if (!aConstraint)
- continue;
- aConstraint->setGroup(this);
- aConstraint->setStorage(myStorage);
- setTemporary(aConstraint);
- }
}
// ============================================================================
// ============================================================================
bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch)
{
- if (myWorkplaneID != SLVS_E_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID())
+ if (myWorkplaneID != EID_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID())
return false; // the workplane already exists or the function parameter is not Sketch
mySketch = theSketch;
- updateWorkplane();
+ if (!updateWorkplane()) {
+ mySketch = CompositeFeaturePtr();
+ return false;
+ }
return true;
}
// ============================================================================
bool SketchSolver_Group::updateWorkplane()
{
+ BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
if (!myStorage) // Create storage if not exists
- myStorage = StoragePtr(new SketchSolver_Storage);
- SketchSolver_Builder* aBuilder = SketchSolver_Builder::getInstance();
+ myStorage = aBuilder->createStorage(getId());
- std::vector<Slvs_Entity> anEntities;
- std::vector<Slvs_Param> aParams;
- if (!aBuilder->createWorkplane(mySketch, anEntities, aParams))
- return false;
-
- if (myWorkplaneID == SLVS_E_UNKNOWN) {
- myWorkplaneID = anEntities.back().h;
- // Add new workplane elements
- std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
- for (; aParIter != aParams.end(); aParIter++) {
- aParIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
- aParIter->group = SLVS_G_OUTOFGROUP;
- aParIter->h = myStorage->addParameter(*aParIter);
- }
- std::vector<Slvs_Entity>::iterator anEntIter = anEntities.begin();
- for (; anEntIter != anEntities.end(); anEntIter++) {
- anEntIter->h = SLVS_E_UNKNOWN; // the ID should be generated by storage
- anEntIter->group = SLVS_G_OUTOFGROUP;
- anEntIter->wrkpl = myWorkplaneID;
- for (int i = 0; i < 4; i++)
- if (anEntIter->param[i] != SLVS_E_UNKNOWN)
- anEntIter->param[i] = aParams[anEntIter->param[i]-1].h;
- for (int i = 0; i < 4; i++)
- if (anEntIter->point[i] != SLVS_E_UNKNOWN)
- anEntIter->point[i] = anEntities[anEntIter->point[i]-1].h;
- anEntIter->h = myStorage->addEntity(*anEntIter);
- }
- } else {
- // Update existent workplane
- const Slvs_Entity& aWP = myStorage->getEntity(myWorkplaneID);
- const Slvs_Entity& anOrigin = myStorage->getEntity(aWP.point[0]);
- const Slvs_Entity& aNormal = myStorage->getEntity(aWP.normal);
- // Get parameters and update them
- Slvs_hParam aWPParams[7] = {
- anOrigin.param[0], anOrigin.param[1], anOrigin.param[2],
- aNormal.param[0], aNormal.param[1], aNormal.param[2], aNormal.param[3]
- };
- std::vector<Slvs_Param>::iterator aParIter = aParams.begin();
- for (int i = 0; aParIter != aParams.end(); aParIter++, i++) {
- Slvs_Param aParam = myStorage->getParameter(aWPParams[i]);
- aParam.val = aParIter->val;
- myStorage->updateParameter(aParam);
- }
+ // sketch should be unchanged, set it out of current group
+ bool isUpdated = myStorage->update(FeaturePtr(mySketch), GID_OUTOFGROUP);
+ if (isUpdated) {
+ EntityWrapperPtr anEntity = myStorage->entity(FeaturePtr(mySketch));
+ myWorkplaneID = anEntity->id();
}
- return myWorkplaneID > 0;
+ return isUpdated;
}
// ============================================================================
bool aResolved = false;
bool isGroupEmpty = isEmpty();
if (myStorage->isNeedToResolve() && !isGroupEmpty) {
- myConstrSolver.setGroupID(myID);
- myConstrSolver.calculateFailedConstraints(false);
- myStorage->initializeSolver(myConstrSolver);
+ if (!mySketchSolver)
+ mySketchSolver = SketchSolver_Manager::instance()->builder()->createSolver();
- int aResult = SLVS_RESULT_OKAY;
+ mySketchSolver->setGroup(myID);
+ mySketchSolver->calculateFailedConstraints(false);
+ myStorage->initializeSolver(mySketchSolver);
+
+ SketchSolver_SolveStatus aResult = STATUS_OK;
try {
if (myStorage->hasDuplicatedConstraint())
- aResult = SLVS_RESULT_INCONSISTENT;
+ aResult = STATUS_INCONSISTENT;
else {
// To avoid overconstraint situation, we will remove temporary constraints one-by-one
// and try to find the case without overconstraint
bool isLastChance = false;
- int aNbTemp = myStorage->numberTemporary();
+ size_t aNbTemp = myStorage->nbTemporary();
while (true) {
- aResult = myConstrSolver.solve();
- if (aResult == SLVS_RESULT_OKAY || isLastChance)
+ aResult = mySketchSolver->solve();
+ if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET || isLastChance)
break;
- if (aNbTemp <= 0) {
+ if (aNbTemp == 0) {
// try to update parameters and resolve once again
ConstraintConstraintMap::iterator aConstrIt = myConstraints.begin();
for (; aConstrIt != myConstraints.end(); ++aConstrIt)
aConstrIt->second->update();
isLastChance = true;
} else
- aNbTemp = myStorage->deleteTemporaryConstraint();
- myConstrSolver.calculateFailedConstraints(true); // something failed => need to find it
- myStorage->initializeSolver(myConstrSolver);
+ aNbTemp = myStorage->removeTemporary();
+ mySketchSolver->calculateFailedConstraints(true); // something failed => need to find it
+ myStorage->initializeSolver(mySketchSolver);
}
}
} catch (...) {
}
return false;
}
- if (aResult == SLVS_RESULT_OKAY) { // solution succeeded, store results into correspondent attributes
- myFeatureStorage->blockEvents(true);
- // First refresh parametric constraints to satisfy parameters
- std::map<AttributePtr, SolverConstraintPtr>::iterator aParIter = myParametricConstraints.begin();
- for (; aParIter != myParametricConstraints.end(); ++aParIter)
- aParIter->second->refresh();
- // Update all other constraints
- ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin();
- for (; aConstrIter != myConstraints.end(); ++aConstrIter)
- aConstrIter->second->refresh();
- myFeatureStorage->blockEvents(false);
+ if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET) { // solution succeeded, store results into correspondent attributes
+ myStorage->refresh();
if (!myPrevSolved) {
getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue("");
// the error message should be changed before sending the message
aResolved = true;
} else if (!isGroupEmpty) {
- myFeatureStorage->blockEvents(true);
// Check there are constraints Fixed. If they exist, update parameters by stored values
ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
for (; aCIt != myConstraints.end(); ++aCIt)
if (aCIt->first->getKind() == SketchPlugin_ConstraintRigid::ID()) {
- aCIt->second->refresh();
aResolved = true;
+ break;
}
- myFeatureStorage->blockEvents(false);
+ if (aCIt != myConstraints.end())
+ myStorage->refresh();
}
removeTemporaryConstraints();
myStorage->setNeedToResolve(false);
// If specified group is empty, no need to merge
if (theGroup.isEmpty())
return;
- if (!myFeatureStorage)
- myFeatureStorage = FeatureStoragePtr(new SketchSolver_FeatureStorage);
std::set<ObjectPtr> aConstraints;
ConstraintConstraintMap::const_iterator aConstrIter = theGroup.myConstraints.begin();
// Class: SketchSolver_Group
// Purpose: divide the group into several subgroups
// ============================================================================
-void SketchSolver_Group::splitGroup(std::vector<SketchSolver_Group*>& theCuts)
+void SketchSolver_Group::splitGroup(std::list<SketchSolver_Group*>& theCuts)
{
+ // New storage will be used in trimmed way to store the list of constraint interacted together.
+ StoragePtr aNewStorage = SketchSolver_Manager::instance()->builder()->createStorage(getId());
+ std::list<ConstraintWrapperPtr> aDummyVec; // empty vector to avoid creation of solver's constraints
+
// Obtain constraints, which should be separated
- FeatureStoragePtr aNewFeatStorage(new SketchSolver_FeatureStorage);
- std::vector<ConstraintPtr> anUnusedConstraints;
+ std::list<ConstraintPtr> anUnusedConstraints;
ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
for ( ; aCIter != myConstraints.end(); aCIter++) {
- std::list<ConstraintPtr> aBaseConstraints = aCIter->second->constraints();
- std::list<ConstraintPtr>::iterator anIter = aBaseConstraints.begin();
- for (; anIter != aBaseConstraints.end(); anIter++)
- if (aNewFeatStorage->isInteract(*anIter)) {
- aNewFeatStorage->changeConstraint(*anIter);
- } else
- anUnusedConstraints.push_back(*anIter);
+ if (aNewStorage->isInteract(FeaturePtr(aCIter->first)))
+ aNewStorage->addConstraint(aCIter->first, aDummyVec);
+ else
+ anUnusedConstraints.push_back(aCIter->first);
}
// Check the unused constraints once again, because they may become interacted with new storage since adding constraints
- std::vector<ConstraintPtr>::iterator aUnuseIt = anUnusedConstraints.begin();
+ std::list<ConstraintPtr>::iterator aUnuseIt = anUnusedConstraints.begin();
while (aUnuseIt != anUnusedConstraints.end()) {
- if (aNewFeatStorage->isInteract(*aUnuseIt)) {
- aNewFeatStorage->changeConstraint(*aUnuseIt);
+ if (aNewStorage->isInteract(FeaturePtr(*aUnuseIt))) {
+ aNewStorage->addConstraint(*aUnuseIt, aDummyVec);
anUnusedConstraints.erase(aUnuseIt);
aUnuseIt = anUnusedConstraints.begin();
continue;
aUnuseIt++;
}
- std::vector<SketchSolver_Group*>::iterator aCutsIter;
+ std::list<SketchSolver_Group*>::iterator aCutsIter;
aUnuseIt = anUnusedConstraints.begin();
- for ( ; aUnuseIt != anUnusedConstraints.end(); aUnuseIt++) {
+ for ( ; aUnuseIt != anUnusedConstraints.end(); ++aUnuseIt) {
// Remove unused constraints
removeConstraint(*aUnuseIt);
// Try to append constraint to already existent group
- for (aCutsIter = theCuts.begin(); aCutsIter != theCuts.end(); aCutsIter++)
+ for (aCutsIter = theCuts.begin(); aCutsIter != theCuts.end(); ++aCutsIter)
if ((*aCutsIter)->isInteract(*aUnuseIt)) {
(*aCutsIter)->changeConstraint(*aUnuseIt);
break;
SketchSolver_Group* aGroup = new SketchSolver_Group(mySketch);
aGroup->changeConstraint(*aUnuseIt);
theCuts.push_back(aGroup);
+ } else {
+ // Find other groups interacting with constraint
+ std::list<SketchSolver_Group*>::iterator aBaseGroupIt = aCutsIter;
+ for (++aCutsIter; aCutsIter != theCuts.end(); ++aCutsIter)
+ if ((*aCutsIter)->isInteract(*aUnuseIt)) {
+ (*aBaseGroupIt)->mergeGroups(**aCutsIter);
+ std::list<SketchSolver_Group*>::iterator aRemoveIt = aCutsIter--;
+ theCuts.erase(aRemoveIt);
+ }
}
}
-
- // Update feature storage
- myFeatureStorage = aNewFeatStorage;
}
// ============================================================================
// ============================================================================
bool SketchSolver_Group::isConsistent()
{
- if (!myFeatureStorage) // no one constraint is initialized yet
+ if (isEmpty()) // no one constraint is initialized yet
return true;
- bool aResult = myFeatureStorage->isConsistent();
+ // Check the features and constraint is the storage are valid
+ bool aResult = myStorage->isConsistent();
+ if (aResult) {
+ // additional check of consistency of the Fixed constraint,
+ // because they are not added to the storage
+ ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
+ for (; aCIter != myConstraints.end(); ++aCIter)
+ if (aCIter->first->getKind() == SketchPlugin_ConstraintRigid::ID() &&
+ (!aCIter->first->data() || !aCIter->first->data()->isValid())) {
+ aResult = false;
+ break;
+ }
+ }
if (!aResult) {
- // remove invalid entities
+ // remove invalid constraints
std::set<ConstraintPtr> anInvalidConstraints;
ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
for (; aCIter != myConstraints.end(); ++aCIter) {
std::set<ConstraintPtr>::const_iterator aRemoveIt = anInvalidConstraints.begin();
for (; aRemoveIt != anInvalidConstraints.end(); ++aRemoveIt)
removeConstraint(*aRemoveIt);
+ // remove invalid features
+ myStorage->removeInvalidEntities();
}
return aResult;
}
std::set<SolverConstraintPtr>::iterator aTmpIt = myTempConstraints.begin();
for (; aTmpIt != myTempConstraints.end(); ++aTmpIt)
(*aTmpIt)->remove();
- myTempConstraints.clear();
- while (myStorage->numberTemporary())
- myStorage->deleteTemporaryConstraint();
- // Clean lists of removed entities in the storage
- std::set<Slvs_hParam> aRemPar;
- std::set<Slvs_hEntity> aRemEnt;
- std::set<Slvs_hConstraint> aRemCon;
- myStorage->getRemoved(aRemPar, aRemEnt, aRemCon);
+ size_t aNbTemp = myStorage->nbTemporary();
+ if (aNbTemp > 0)
+ myStorage->removeTemporary(aNbTemp);
+
+ if (!myTempConstraints.empty())
+ myStorage->verifyFixed();
myStorage->setNeedToResolve(false);
+ myTempConstraints.clear();
}
// ============================================================================
void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
{
bool isFullyRemoved = true;
- myFeatureStorage->removeConstraint(theConstraint);
ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
for (; aCIter != myConstraints.end(); aCIter++)
- if (aCIter->second->hasConstraint(theConstraint)) {
- if (!aCIter->second->remove(theConstraint)) // the constraint is not fully removed
+ if (aCIter->first == theConstraint) {
+ if (!aCIter->second->remove()) // the constraint is not fully removed
isFullyRemoved = false;
break;
}
if (aCIter == myConstraints.end())
return;
- // Remove entities not used by constraints
- myStorage->removeUnusedEntities();
-
if (isFullyRemoved)
myConstraints.erase(aCIter);
else if (aCIter != myConstraints.end() &&
}
if (aCIter->first != theConstraint)
aMultiCoinc.push_back(aCIter->first);
- aCIter->second->remove(aCIter->first);
+ aCIter->second->remove();
ConstraintConstraintMap::iterator aRemoveIt = aCIter++;
myConstraints.erase(aRemoveIt);
}
std::list<ConstraintPtr>::iterator anIt = aMultiCoinc.begin();
for (; anIt != aMultiCoinc.end(); ++anIt)
changeConstraint(*anIt);
-
- notifyMultiConstraints();
}
}
// ============================================================================
// Function: setTemporary
// Class: SketchSolver_Group
-// Purpose: append given constraint to th group of temporary constraints
+// Purpose: append given constraint to the group of temporary constraints
// ============================================================================
void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint)
{
return aFactory->validate(theFeature);
}
-// ============================================================================
-// Function: notifyMultiConstraints
-// Class: SketchSolver_Group
-// Purpose: Update Multi-Translation/-Rotation constraints due to multi coincidence appears/disappears
-// ============================================================================
-void SketchSolver_Group::notifyMultiConstraints()
-{
- ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
- for (; aCIter != myConstraints.end(); ++aCIter) {
- if (aCIter->first->getKind() == SketchPlugin_MultiRotation::ID() ||
- aCIter->first->getKind() == SketchPlugin_MultiTranslation::ID()) {
- std::shared_ptr<SketchSolver_ConstraintMulti> aMulti =
- std::dynamic_pointer_cast<SketchSolver_ConstraintMulti>(aCIter->second);
- aMulti->checkCoincidence();
- }
- }
-}
-
#include "SketchSolver.h"
#include <SketchSolver_Constraint.h>
#include <SketchSolver_Storage.h>
-#include <SketchSolver_FeatureStorage.h>
-#include <SketchSolver_Solver.h>
+#include <SketchSolver_ISolver.h>
#include <SketchPlugin_Constraint.h>
-#include <ModelAPI_Data.h>
#include <ModelAPI_Feature.h>
-#include <ModelAPI_AttributeRefList.h>
#include <memory>
#include <list>
#include <map>
-#include <vector>
#include <set>
typedef std::map<ConstraintPtr, SolverConstraintPtr> ConstraintConstraintMap;
~SketchSolver_Group();
/// \brief Returns group's unique identifier
- inline const Slvs_hGroup& getId() const
+ inline const GroupID& getId() const
{
return myID;
}
/// \brief Returns identifier of the workplane
- inline const Slvs_hEntity& getWorkplaneId() const
+ inline const EntityID& getWorkplaneId() const
{
return myWorkplaneID;
}
- /// \brief Find the identifier of the feature, if it already exists in the group
- Slvs_hEntity getFeatureId(FeaturePtr theFeature) const;
- /// \brief Find the identifier of the attribute, if it already exists in the group
- Slvs_hEntity getAttributeId(AttributePtr theAttribute) const;
-
/// \brief Returns true if the group has no constraints yet
inline bool isEmpty() const
{
/** \brief Updates the data corresponding the specified feature
* \param[in] theFeature the feature to be updated
*/
- bool updateFeature(std::shared_ptr<SketchPlugin_Feature> theFeature);
+ bool updateFeature(FeaturePtr theFeature);
/** \brief Updates the data corresponding the specified feature moved in GUI.
* Additional Fixed constraints are created.
* \param[in] theFeature the feature to be updated
*/
- void moveFeature(std::shared_ptr<SketchPlugin_Feature> theFeature);
+ void moveFeature(FeaturePtr theFeature);
/** \brief Verifies the feature attributes are used in this group
* \param[in] theFeature constraint or any other object for verification of interaction
* \return \c true if some of attributes are used in current group
*/
- bool isInteract(std::shared_ptr<SketchPlugin_Feature> theFeature) const;
+ bool isInteract(FeaturePtr theFeature) const;
/** \brief Verifies the specified feature is equal to the base workplane for this group
* \param[in] theWorkplane the feature to be compared with base workplane
/** \brief Cut from the group several subgroups, which are not connected to the current one by any constraint
* \param[out] theCuts enlarge this list by newly created groups
*/
- void splitGroup(std::vector<SketchSolver_Group*>& theCuts);
+ void splitGroup(std::list<SketchSolver_Group*>& theCuts);
/** \brief Start solution procedure if necessary and update attributes of features
* \return \c false when no need to solve constraints
*/
bool addWorkplane(CompositeFeaturePtr theSketch);
- /// \brief Apply temporary rigid constraints for the list of features
- void fixFeaturesList(AttributeRefListPtr theList);
-
- /// \brief Append given constraint to th group of temporary constraints
+ /// \brief Append given constraint to the group of temporary constraints
void setTemporary(SolverConstraintPtr theConstraint);
/// \brief Verifies is the feature valid
/// \brief Update just changed constraints
void updateConstraints();
- /// \brief Update Multi-Translation/-Rotation constraints due to multi coincidence appears/disappears
- void notifyMultiConstraints();
-
private:
- Slvs_hGroup myID; ///< Index of the group
- Slvs_hEntity myWorkplaneID; ///< Index of workplane, the group is based on
+ GroupID myID; ///< Index of the group
+ EntityID myWorkplaneID; ///< Index of workplane, the group is based on
CompositeFeaturePtr mySketch; ///< Sketch is equivalent to workplane
ConstraintConstraintMap myConstraints; ///< List of constraints
std::set<SolverConstraintPtr> myTempConstraints; ///< List of temporary constraints
std::set<ConstraintPtr> myChangedConstraints; ///< List of just updated constraints
StoragePtr myStorage; ///< Container for the set of SolveSpace constraints and their entities
- FeatureStoragePtr myFeatureStorage; ///< Container for the set of SketchPlugin features and their dependencies
- SketchSolver_Solver myConstrSolver; ///< Solver for set of equations obtained by constraints
+ SolverPtr mySketchSolver; ///< Solver for set of equations obtained by constraints
bool myPrevSolved; ///< Indicates that previous solving was done correctly
};
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_IConstraintWrapper.h
+// Created: 30 Nov 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_IConstraintWrapper_H_
+#define SketchSolver_IConstraintWrapper_H_
+
+#include <SketchSolver_IEntityWrapper.h>
+
+#include <SketchPlugin_Constraint.h>
+
+#include <list>
+#include <memory>
+
+/// Types of constraints
+enum SketchSolver_ConstraintType {
+ CONSTRAINT_UNKNOWN = 0,
+ CONSTRAINT_COINCIDENCE, // base coincidence if we don't know exact type yet
+ CONSTRAINT_PT_PT_COINCIDENT,
+ CONSTRAINT_PT_ON_LINE,
+ CONSTRAINT_PT_ON_CIRCLE,
+ CONSTRAINT_DISTANCE, // base distance if we don't know the measured objects yet
+ CONSTRAINT_PT_PT_DISTANCE,
+ CONSTRAINT_PT_LINE_DISTANCE,
+ CONSTRAINT_RADIUS,
+ CONSTRAINT_ANGLE,
+ CONSTRAINT_FIXED,
+ CONSTRAINT_HORIZONTAL,
+ CONSTRAINT_VERTICAL,
+ CONSTRAINT_PARALLEL,
+ CONSTRAINT_PERPENDICULAR,
+ CONSTRAINT_SYMMETRIC,
+ CONSTRAINT_EQUAL, // base equality if we don't know the measured objects yet
+ CONSTRAINT_EQUAL_LINES,
+ CONSTRAINT_EQUAL_LINE_ARC,
+ CONSTRAINT_EQUAL_RADIUS,
+ CONSTRAINT_TANGENT, // base tangency if we don't know the measured objects yet
+ CONSTRAINT_TANGENT_ARC_LINE,
+ CONSTRAINT_TANGENT_ARC_ARC,
+ CONSTRAINT_MULTI_TRANSLATION,
+ CONSTRAINT_MULTI_ROTATION
+};
+
+/**
+ * Wrapper providing operations with constraints regardless the solver.
+ */
+class SketchSolver_IConstraintWrapper
+{
+public:
+ virtual ~SketchSolver_IConstraintWrapper() {}
+
+ /// \brief Return base feature
+ const ConstraintPtr& baseConstraint() const
+ { return myBaseConstraint; }
+
+ /// \brief Return ID of current entity
+ virtual ConstraintID id() const = 0;
+
+ /// \brief Change group for the constraint
+ virtual void setGroup(const GroupID& theGroup) = 0;
+ /// \brief Return identifier of the group the constraint belongs to
+ virtual GroupID group() const = 0;
+
+ /// \brief Return type of current entity
+ virtual SketchSolver_ConstraintType type() const = 0;
+
+ /// \brief Assign list of constrained objects
+ void setEntities(const std::list<EntityWrapperPtr>& theEntities)
+ { myConstrained = theEntities; }
+ /// \brief Return list of constrained objects
+ const std::list<EntityWrapperPtr>& entities() const
+ { return myConstrained; }
+
+ /// \brief Assign numeric parameter of constraint
+ virtual void setValue(const double& theValue)
+ { myValue = theValue; }
+ /// \brief Return numeric parameter of constraint
+ const double& value() const
+ { return myValue; }
+
+ /// \brief Verify the feature is used in the constraint
+ virtual bool isUsed(FeaturePtr theFeature) const = 0;
+ /// \brief Verify the attribute is used in the constraint
+ virtual bool isUsed(AttributePtr theAttribute) const = 0;
+
+ /// \brief Compare current constraint with other
+ virtual bool isEqual(const std::shared_ptr<SketchSolver_IConstraintWrapper>& theOther) = 0;
+
+ /// \brief Update values of parameters of this constraint by the parameters of given one
+ /// \return \c true if some parameters change their values
+ virtual bool update(const std::shared_ptr<SketchSolver_IConstraintWrapper>& theOther) = 0;
+
+protected:
+ ConstraintPtr myBaseConstraint;
+ std::list<EntityWrapperPtr> myConstrained;
+ double myValue;
+};
+
+typedef std::shared_ptr<SketchSolver_IConstraintWrapper> ConstraintWrapperPtr;
+
+#endif
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_IEntityWrapper.h
+// Created: 30 Nov 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_IEntityWrapper_H_
+#define SketchSolver_IEntityWrapper_H_
+
+#include <SketchSolver.h>
+#include <SketchSolver_IParameterWrapper.h>
+
+#include <ModelAPI_Attribute.h>
+#include <ModelAPI_Feature.h>
+
+#include <list>
+#include <memory>
+
+/// Types of entities
+enum SketchSolver_EntityType {
+ ENTITY_UNKNOWN = 0,
+ ENTITY_SCALAR,
+ ENTITY_POINT,
+ ENTITY_NORMAL,
+ ENTITY_LINE,
+ ENTITY_CIRCLE,
+ ENTITY_ARC,
+ ENTITY_SKETCH
+};
+
+/**
+ * Wrapper providing operations with entities regardless the solver.
+ */
+class SketchSolver_IEntityWrapper
+{
+public:
+ virtual ~SketchSolver_IEntityWrapper() {}
+
+ /// \brief Return base feature
+ const FeaturePtr& baseFeature() const
+ { return myBaseFeature; }
+ /// \brief Return base attribute
+ const AttributePtr& baseAttribute() const
+ { return myBaseAttribute; }
+
+ /// \brief Check the feature is basis for this wrapper
+ bool isBase(FeaturePtr theFeature) const
+ { return myBaseFeature && myBaseFeature == theFeature; }
+ /// \brief Check the attribute is basis for this wrapper
+ bool isBase(AttributePtr theAttribute) const
+ { return myBaseAttribute && myBaseAttribute == theAttribute; }
+
+ /// \brief Assign list of parameters for this entity
+ void setParameters(const std::list<ParameterWrapperPtr>& theParams)
+ { myParameters = theParams; }
+ /// \brief Return list of parameters
+ const std::list<ParameterWrapperPtr>& parameters() const
+ { return myParameters; }
+
+ /// \brief Assign list of sub-entities
+ void setSubEntities(const std::list<std::shared_ptr<SketchSolver_IEntityWrapper> >& theEntities)
+ { mySubEntities = theEntities; }
+ /// \brief Return list of sub-entities
+ const std::list<std::shared_ptr<SketchSolver_IEntityWrapper> >& subEntities() const
+ { return mySubEntities; }
+
+ /// \brief Return ID of current entity
+ virtual EntityID id() const = 0;
+
+ /// \brief Change group for the entity
+ virtual void setGroup(const GroupID& theGroup) = 0;
+ /// \brief Return identifier of the group the entity belongs to
+ virtual GroupID group() const = 0;
+
+ /// \brief Return type of current entity
+ virtual SketchSolver_EntityType type() const = 0;
+
+ /// \brief Verify the feature is used in the entity
+ virtual bool isUsed(FeaturePtr theFeature) const = 0;
+ /// \brief Verify the attribute is used in the entity
+ virtual bool isUsed(AttributePtr theAttribute) const = 0;
+
+ /// \brief Compare current entity with other
+ virtual bool isEqual(const std::shared_ptr<SketchSolver_IEntityWrapper>& theOther) = 0;
+
+ /// \brief Update values of parameters of this entity by the parameters of given one
+ /// \return \c true if some parameters change their values
+ virtual bool update(const std::shared_ptr<SketchSolver_IEntityWrapper>& theOther) = 0;
+
+protected:
+ FeaturePtr myBaseFeature;
+ AttributePtr myBaseAttribute;
+
+ std::list<ParameterWrapperPtr> myParameters;
+ std::list<std::shared_ptr<SketchSolver_IEntityWrapper> > mySubEntities;
+};
+
+typedef std::shared_ptr<SketchSolver_IEntityWrapper> EntityWrapperPtr;
+
+#endif
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_IParameterWrapper.h
+// Created: 1 Dec 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_IParameterWrapper_H_
+#define SketchSolver_IParameterWrapper_H_
+
+#include <SketchSolver.h>
+
+#include <memory>
+
+/**
+ * Wrapper providing operations with parameters regardless the solver.
+ */
+class SketchSolver_IParameterWrapper
+{
+public:
+ virtual ~SketchSolver_IParameterWrapper() {}
+
+ /// \brief Return ID of current parameter
+ virtual ParameterID id() const = 0;
+
+ /// \brief Change group for the parameter
+ virtual void setGroup(const GroupID& theGroup) = 0;
+ /// \brief Return identifier of the group the parameter belongs to
+ virtual GroupID group() const = 0;
+
+ /// \brief Change value of parameter
+ virtual void setValue(double theValue) = 0;
+ /// \brief Return value of parameter
+ virtual double value() const = 0;
+
+ /// \brief Set or unset flag the parameter is given by expression
+ void setIsParametric(bool isParametric)
+ { myIsParametric = isParametric; }
+ /// \brief Show the parameter is an expression
+ bool isParametric() const
+ { return myIsParametric; }
+
+ /// \brief Compare current parameter with other
+ virtual bool isEqual(const std::shared_ptr<SketchSolver_IParameterWrapper>& theOther) = 0;
+
+ /// \brief Update value of parameter by the given one
+ /// \return \c true if the value of parameter is changed
+ virtual bool update(const std::shared_ptr<SketchSolver_IParameterWrapper>& theOther) = 0;
+
+protected:
+ bool myIsParametric; ///< indicate the parameter is given by parametric expression
+};
+
+typedef std::shared_ptr<SketchSolver_IParameterWrapper> ParameterWrapperPtr;
+
+#endif
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_ISolver.h
+// Created: 30 Nov 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_ISolver_H_
+#define SketchSolver_ISolver_H_
+
+#include <SketchSolver.h>
+
+#include <memory>
+
+/// The result of constraints solution
+enum SketchSolver_SolveStatus {
+ STATUS_OK,
+ STATUS_INCONSISTENT,
+ STATUS_EMPTYSET,
+ STATUS_FAILED // set if no one other status is applicable
+};
+
+
+/**
+ * Interface providing operations to solve sketches.
+ */
+class SketchSolver_ISolver
+{
+public:
+ virtual ~SketchSolver_ISolver() {}
+
+ /// \brief Changes the ID of the group to solve
+ void setGroup(const GroupID& theGroupID)
+ { myGroup = theGroupID; }
+
+ /// \brief Set or unset the flag which allows to find all failed constraints
+ void calculateFailedConstraints(bool theSic)
+ { myFindFaileds = theSic; }
+
+ /// \brief Solve the set of equations
+ /// \return identifier whether solution succeeded
+ virtual SketchSolver_SolveStatus solve() = 0;
+
+protected:
+ GroupID myGroup; ///< ID of the group to be solved
+ bool myFindFaileds; ///< flag to find conflicting or inappropriate constraints
+};
+
+typedef std::shared_ptr<SketchSolver_ISolver> SolverPtr;
+
+#endif
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_Manager.cpp
+// Created: 08 May 2014
+// Author: Artem ZHIDKOV
+
+#include "SketchSolver_Manager.h"
+
+#include <Events_Loop.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_Object.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Attribute.h>
+
+#include <SketchPlugin_Constraint.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_Sketch.h>
+#include <SketchPlugin_Feature.h>
+
+#include <list>
+#include <set>
+#include <memory>
+
+// Initialization of constraint manager self pointer
+SketchSolver_Manager* SketchSolver_Manager::mySelf = 0;
+
+/// Global constraint manager object
+SketchSolver_Manager* myManager = SketchSolver_Manager::instance();
+
+
+// ========================================================
+// ========= SketchSolver_Manager ===============
+// ========================================================
+SketchSolver_Manager* SketchSolver_Manager::instance()
+{
+ if (!mySelf)
+ mySelf = new SketchSolver_Manager();
+ return mySelf;
+}
+
+SketchSolver_Manager::SketchSolver_Manager()
+{
+ myGroups.clear();
+ myIsComputed = false;
+
+ // Register in event loop
+ Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_CREATED));
+ Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+ Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_DELETED));
+ Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_OBJECT_MOVED));
+}
+
+SketchSolver_Manager::~SketchSolver_Manager()
+{
+ myGroups.clear();
+}
+
+void SketchSolver_Manager::setBuilder(BuilderPtr theBuilder)
+{
+ myBuilder = theBuilder;
+}
+
+BuilderPtr SketchSolver_Manager::builder()
+{
+ return myBuilder;
+}
+
+// ============================================================================
+// Function: processEvent
+// Purpose: listen the event loop and process the message
+// ============================================================================
+void SketchSolver_Manager::processEvent(
+ const std::shared_ptr<Events_Message>& theMessage)
+{
+ if (myIsComputed)
+ return;
+ if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_CREATED)
+ || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED)
+ || theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED)) {
+ std::shared_ptr<ModelAPI_ObjectUpdatedMessage> anUpdateMsg =
+ std::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
+ std::set<ObjectPtr> aFeatures = anUpdateMsg->objects();
+
+ // Shows the message has at least one feature applicable for solver
+ bool hasProperFeature = false;
+
+ bool isMovedEvt = theMessage->eventID()
+ == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED);
+ if (isMovedEvt) {
+ std::set<ObjectPtr>::iterator aFeatIter;
+ for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
+ std::shared_ptr<SketchPlugin_Feature> aSFeature =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
+ if (aSFeature) {
+ moveEntity(aSFeature);
+ hasProperFeature = true;
+ }
+ }
+ } else {
+ std::list<FeaturePtr> aSketchFeatures = SketchSolver_Group::selectApplicableFeatures(aFeatures);
+ std::list<FeaturePtr>::iterator aFeatIter = aSketchFeatures.begin();
+ for (; aFeatIter != aSketchFeatures.end(); ++aFeatIter) {
+ if ((*aFeatIter)->getKind() == SketchPlugin_Sketch::ID()) {
+ std::shared_ptr<ModelAPI_CompositeFeature> aSketch =
+ std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aFeatIter);
+ hasProperFeature = changeWorkplane(aSketch) || hasProperFeature;
+ continue;
+ }
+ std::shared_ptr<SketchPlugin_Feature> aFeature =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
+ if (!aFeature)
+ continue;
+ hasProperFeature = changeFeature(aFeature) || hasProperFeature;
+ }
+ }
+
+ // Solve the set of constraints
+ if (hasProperFeature)
+ resolveConstraints(isMovedEvt); // send update for movement in any case
+ } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
+ std::shared_ptr<ModelAPI_ObjectDeletedMessage> aDeleteMsg =
+ std::dynamic_pointer_cast<ModelAPI_ObjectDeletedMessage>(theMessage);
+ const std::set<std::string>& aFeatureGroups = aDeleteMsg->groups();
+
+ // Find SketchPlugin_Sketch::ID() in groups. The constraint groups should be updated when an object removed from Sketch
+ std::set<std::string>::const_iterator aFGrIter;
+ for (aFGrIter = aFeatureGroups.begin(); aFGrIter != aFeatureGroups.end(); aFGrIter++)
+ if (aFGrIter->compare(ModelAPI_ResultConstruction::group()) == 0 ||
+ aFGrIter->compare(ModelAPI_Feature::group()) == 0)
+ break;
+
+ if (aFGrIter != aFeatureGroups.end()) {
+ std::vector<SketchSolver_Group*>::iterator aGroupIter = myGroups.begin();
+ std::list<SketchSolver_Group*> aSeparatedGroups;
+ while (aGroupIter != myGroups.end()) {
+ if (!(*aGroupIter)->isWorkplaneValid()) { // the group should be removed
+ delete *aGroupIter;
+ int aShift = aGroupIter - myGroups.begin();
+ myGroups.erase(aGroupIter);
+ aGroupIter = myGroups.begin() + aShift;
+ continue;
+ }
+ if (!(*aGroupIter)->isConsistent()) { // some constraints were removed, try to split the group
+ (*aGroupIter)->splitGroup(aSeparatedGroups);
+ }
+ aGroupIter++;
+ }
+ if (aSeparatedGroups.size() > 0)
+ myGroups.insert(myGroups.end(), aSeparatedGroups.begin(), aSeparatedGroups.end());
+ }
+ }
+}
+
+// ============================================================================
+// Function: changeWorkplane
+// Purpose: update workplane by given parameters of the sketch
+// ============================================================================
+bool SketchSolver_Manager::changeWorkplane(CompositeFeaturePtr theSketch)
+{
+ bool aResult = true; // changed when a workplane wrongly updated
+ bool isUpdated = false;
+ // Try to update specified workplane in all groups
+ std::vector<SketchSolver_Group*>::iterator aGroupIter;
+ for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+ if ((*aGroupIter)->isBaseWorkplane(theSketch)) {
+ isUpdated = true;
+ aResult = false;
+ }
+ // If the workplane is not updated, so this is a new workplane
+ if (!isUpdated) {
+ SketchSolver_Group* aNewGroup = new SketchSolver_Group(theSketch);
+ // Verify that the group is created successfully
+ if (!aNewGroup->isBaseWorkplane(theSketch) || !aNewGroup->isWorkplaneValid()) {
+ delete aNewGroup;
+ return false;
+ }
+ myGroups.push_back(aNewGroup);
+ }
+ return aResult;
+}
+
+// ============================================================================
+// Function: changeConstraintOrEntity
+// Purpose: create/update the constraint or the feature and place it into appropriate group
+// ============================================================================
+bool SketchSolver_Manager::changeFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
+{
+ // Search the groups which this feature touches
+ std::set<GroupID> aGroups;
+ findGroups(theFeature, aGroups);
+
+ std::shared_ptr<SketchPlugin_Constraint> aConstraint =
+ std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
+
+ // Process the groups list
+ if (aGroups.size() == 0) {
+ // There are no groups applicable for this constraint => create new one
+ // The group will be created only for constraints, not for features
+ if (!aConstraint) return false;
+ std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(aConstraint);
+ if (!aWP)
+ return false;
+ SketchSolver_Group* aGroup = new SketchSolver_Group(aWP);
+ if (!aGroup->changeConstraint(aConstraint)) {
+ delete aGroup;
+ return false;
+ }
+ myGroups.push_back(aGroup);
+ return true;
+ } else if (aGroups.size() == 1) { // Only one group => add feature into it
+ GroupID aGroupId = *(aGroups.begin());
+ std::vector<SketchSolver_Group*>::iterator aGroupIter;
+ for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+ if ((*aGroupIter)->getId() == aGroupId) {
+ // If the group is empty, the feature is not added (the constraint only)
+ if (!aConstraint && !(*aGroupIter)->isEmpty())
+ return (*aGroupIter)->updateFeature(theFeature);
+ return (*aGroupIter)->changeConstraint(aConstraint);
+ }
+ } else if (aGroups.size() > 1) { // Several groups applicable for this feature => need to merge them
+ std::set<GroupID>::const_iterator aGroupsIter = aGroups.begin();
+
+ // Search first group
+ std::vector<SketchSolver_Group*>::iterator aFirstGroupIter;
+ for (aFirstGroupIter = myGroups.begin(); aFirstGroupIter != myGroups.end(); aFirstGroupIter++)
+ if ((*aFirstGroupIter)->getId() == *aGroupsIter)
+ break;
+ if (aFirstGroupIter == myGroups.end())
+ return false;
+
+ // Append other groups to the first one
+ std::vector<SketchSolver_Group*>::iterator anOtherGroupIter = aFirstGroupIter + 1;
+ for (aGroupsIter++; aGroupsIter != aGroups.end(); aGroupsIter++) {
+ for (; anOtherGroupIter != myGroups.end(); anOtherGroupIter++)
+ if ((*anOtherGroupIter)->getId() == *aGroupsIter)
+ break;
+ if (anOtherGroupIter == myGroups.end()) { // Group disappears
+ anOtherGroupIter = aFirstGroupIter + 1;
+ continue;
+ }
+
+ (*aFirstGroupIter)->mergeGroups(**anOtherGroupIter);
+ int aShiftFirst = aFirstGroupIter - myGroups.begin();
+ int aShiftOther = anOtherGroupIter - myGroups.begin();
+ delete *anOtherGroupIter;
+ myGroups.erase(anOtherGroupIter);
+ aFirstGroupIter = myGroups.begin() + aShiftFirst;
+ anOtherGroupIter = myGroups.begin() + aShiftOther;
+ }
+
+ if (aConstraint)
+ return (*aFirstGroupIter)->changeConstraint(aConstraint);
+ return (*aFirstGroupIter)->updateFeature(theFeature);
+ }
+
+ // Something goes wrong
+ return false;
+}
+
+// ============================================================================
+// Function: moveEntity
+// Purpose: update element moved on the sketch, which is used by constraints
+// ============================================================================
+void SketchSolver_Manager::moveEntity(std::shared_ptr<SketchPlugin_Feature> theFeature)
+{
+ std::vector<SketchSolver_Group*>::iterator aGroupIt = myGroups.begin();
+ for (; aGroupIt != myGroups.end(); aGroupIt++)
+ if (!(*aGroupIt)->isEmpty() && (*aGroupIt)->isInteract(theFeature))
+ (*aGroupIt)->moveFeature(theFeature);
+}
+
+// ============================================================================
+// Function: findGroups
+// Purpose: search groups of entities interacting with given feature
+// ============================================================================
+void SketchSolver_Manager::findGroups(
+ std::shared_ptr<SketchPlugin_Feature> theFeature,
+ std::set<GroupID>& theGroupIDs) const
+{
+ std::shared_ptr<ModelAPI_CompositeFeature> aWP = findWorkplane(theFeature);
+
+ SketchSolver_Group* anEmptyGroup = 0; // appropriate empty group for specified constraint
+ std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
+ for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+ if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) {
+ if (!(*aGroupIter)->isEmpty())
+ theGroupIDs.insert((*aGroupIter)->getId());
+ else if (!anEmptyGroup)
+ anEmptyGroup = *aGroupIter;
+ }
+
+ // When only empty group is found, use it
+ if (anEmptyGroup && theGroupIDs.empty())
+ theGroupIDs.insert(anEmptyGroup->getId());
+}
+
+// ============================================================================
+// Function: findWorkplane
+// Purpose: search workplane containing given feature
+// ============================================================================
+std::shared_ptr<ModelAPI_CompositeFeature> SketchSolver_Manager
+::findWorkplane(std::shared_ptr<SketchPlugin_Feature> theFeature) const
+{
+ // Already verified workplanes
+ std::set<std::shared_ptr<ModelAPI_CompositeFeature> > aVerified;
+
+ std::vector<SketchSolver_Group*>::const_iterator aGroupIter;
+ for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) {
+ std::shared_ptr<ModelAPI_CompositeFeature> aWP = (*aGroupIter)->getWorkplane();
+ if (aVerified.find(aWP) != aVerified.end())
+ continue;
+
+ DataPtr aData = aWP->data();
+ if (aData->isValid()) {
+ std::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures = std::dynamic_pointer_cast<
+ ModelAPI_AttributeRefList>(aData->attribute(SketchPlugin_Sketch::FEATURES_ID()));
+ std::list<ObjectPtr> aFeaturesList = aWPFeatures->list();
+ std::list<ObjectPtr>::const_iterator anIter;
+ for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
+ if (*anIter == theFeature)
+ return aWP; // workplane is found
+ }
+ aVerified.insert(aWP);
+ }
+
+ return std::shared_ptr<ModelAPI_CompositeFeature>();
+}
+
+// ============================================================================
+// Function: resolveConstraints
+// Purpose: change entities according to available constraints
+// ============================================================================
+void SketchSolver_Manager::resolveConstraints(const bool theForceUpdate)
+{
+ myIsComputed = true;
+ bool needToUpdate = false;
+ static Events_ID anUpdateEvent = Events_Loop::eventByName(EVENT_OBJECT_UPDATED);
+ // to avoid redisplay of each segment on update by solver one by one in the viewer
+ bool isUpdateFlushed = Events_Loop::loop()->isFlushed(anUpdateEvent);
+ if (isUpdateFlushed) {
+ Events_Loop::loop()->setFlushed(anUpdateEvent, false);
+ }
+
+ std::vector<SketchSolver_Group*>::iterator aGroupIter;
+ for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+ if ((*aGroupIter)->resolveConstraints())
+ needToUpdate = true;
+
+ // Features may be updated => now send events, but for all changed at once
+ if (isUpdateFlushed) {
+ Events_Loop::loop()->setFlushed(anUpdateEvent, true);
+ }
+ // Must be before flush because on "Updated" flush the results may be produced
+ // and the creation event is appeared with many new objects. If myIsComputed these
+ // events are missed in processEvents and some elements are not added.
+ myIsComputed = false;
+ if (needToUpdate || theForceUpdate)
+ Events_Loop::loop()->flush(anUpdateEvent);
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SketchSolver_Manager.h
+// Created: 08 May 2014
+// Author: Artem ZHIDKOV
+
+#ifndef SketchSolver_Manager_H_
+#define SketchSolver_Manager_H_
+
+#include "SketchSolver.h"
+#include <SketchSolver_Group.h>
+#include <SketchSolver_Builder.h>
+
+#include <Events_Listener.h>
+#include <SketchPlugin_Constraint.h>
+
+#include <vector>
+#include <set>
+
+/** \class SketchSolver_Manager
+ * \ingroup Plugins
+ * \brief Listens the changes of SketchPlugin features and transforms the Constraint
+ * feature into the format understandable by SolveSpace library.
+ *
+ * Constraints created for SolveSpace library are divided into the groups.
+ * The division order based on connectedness of the features by the constraints.
+ * The groups may be fused or separated according to the new constraints.
+ *
+ * \remark This is a singleton.
+ */
+class SketchSolver_Manager : public Events_Listener
+{
+public:
+ /** \brief Main method to create constraint manager
+ * \return pointer to the singleton
+ */
+ SKETCHSOLVER_EXPORT static SketchSolver_Manager* instance();
+
+ /** \brief Implementation of Event Listener method
+ * \param[in] theMessage the data of the event
+ */
+ virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage);
+
+ /// \brief Initialize builder for solver's data structure entities
+ /// \param theBuilder [in] solver's specific builder
+ SKETCHSOLVER_EXPORT void setBuilder(BuilderPtr theBuilder);
+ /// \brief Returns the builder specific for the solver
+ BuilderPtr builder();
+
+protected:
+ SketchSolver_Manager();
+ ~SketchSolver_Manager();
+
+ /** \brief Adds or updates a constraint or an entity in the suitable group
+ * \param[in] theFeature sketch feature to be changed
+ * \return \c true if the feature changed successfully
+ */
+ bool changeFeature(std::shared_ptr<SketchPlugin_Feature> theFeature);
+
+ /** \brief Removes a constraint from the manager
+ * \param[in] theConstraint constraint to be removed
+ * \return \c true if the constraint removed successfully
+ */
+ bool removeConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
+
+ /** \brief Adds or updates a workplane in the manager
+ * \param[in] theSketch the feature to create or update workplane
+ * \return \c true if the workplane changed successfully
+ * \remark Type of theSketch is not verified inside
+ */
+ bool changeWorkplane(CompositeFeaturePtr theSketch);
+
+ /** \brief Removes a workplane from the manager.
+ * All groups based on such workplane will be removed too.
+ * \param[in] theSketch the feature to be removed
+ * \return \c true if the workplane removed successfully
+ */
+ bool removeWorkplane(std::shared_ptr<SketchPlugin_Sketch> theSketch);
+
+ /** \brief Updates entity which is moved in GUI
+ * \param[in] theFeature entity to be updated
+ */
+ void moveEntity(std::shared_ptr<SketchPlugin_Feature> theFeature);
+
+ /** \brief Goes through the list of groups and solve the constraints
+ * \param theForceUpdate flushes the update event in any case: something changed or not
+ */
+ void resolveConstraints(const bool theForceUpdate);
+
+private:
+ /** \brief Searches list of groups which interact with specified feature
+ * \param[in] theFeature object to be found
+ * \param[out] theGroups list of group indexes interacted with the feature
+ */
+ void findGroups(std::shared_ptr<SketchPlugin_Feature> theFeature,
+ std::set<GroupID>& theGroupIDs) const;
+
+ /** \brief Searches in the list of groups the workplane which contains specified feature
+ * \param[in] theFeature object to be found
+ * \return workplane containing the feature
+ */
+ std::shared_ptr<ModelAPI_CompositeFeature> findWorkplane(
+ std::shared_ptr<SketchPlugin_Feature> theFeature) const;
+
+private:
+ static SketchSolver_Manager* mySelf; ///< Self pointer to implement singleton functionality
+ std::vector<SketchSolver_Group*> myGroups; ///< Groups of constraints
+ BuilderPtr myBuilder; ///< Builder for solver's entities
+ /// true if computation is performed and all "updates" are generated by this algo
+ /// and needs no recomputation
+ bool myIsComputed;
+};
+
+#endif
+++ /dev/null
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File: SketchSolver_Solver.cpp
-// Created: 07 May 2014
-// Author: Artem ZHIDKOV
-
-#include "SketchSolver_Solver.h"
-#include <Events_LongOp.h>
-
-SketchSolver_Solver::SketchSolver_Solver()
-{
- myGroupID = 0;
- // Nullify all elements of the set of equations
- myEquationsSystem.param = 0;
- myEquationsSystem.params = 0;
- myEquationsSystem.entity = 0;
- myEquationsSystem.entities = 0;
- myEquationsSystem.constraint = 0;
- myEquationsSystem.constraints = 0;
- myEquationsSystem.failed = 0;
- myEquationsSystem.faileds = 0;
-
- myEquationsSystem.dragged[0] = 0;
- myEquationsSystem.dragged[1] = 0;
- myEquationsSystem.dragged[2] = 0;
- myEquationsSystem.dragged[3] = 0;
-
- // If the set of constraints is inconsistent,
- // the failed field will contain wrong constraints
- myEquationsSystem.calculateFaileds = 0;
-}
-
-SketchSolver_Solver::~SketchSolver_Solver()
-{
- if (myEquationsSystem.constraint)
- delete[] myEquationsSystem.constraint;
- myEquationsSystem.constraint = 0;
- if (myEquationsSystem.failed)
- delete[] myEquationsSystem.failed;
- myEquationsSystem.failed = 0;
-}
-
-void SketchSolver_Solver::setParameters(Slvs_Param* theParameters, int theSize)
-{
- myEquationsSystem.param = theParameters;
- myEquationsSystem.params = theSize;
-}
-
-
-void SketchSolver_Solver::setDraggedParameters(const Slvs_hParam* theDragged)
-{
- for (unsigned int i = 0; i < 4; i++)
- myEquationsSystem.dragged[i] = theDragged[i];
-}
-
-void SketchSolver_Solver::setEntities(Slvs_Entity* theEntities, int theSize)
-{
- myEquationsSystem.entity = theEntities;
- myEquationsSystem.entities = theSize;
-}
-
-void SketchSolver_Solver::setConstraints(Slvs_Constraint* theConstraints, int theSize)
-{
- if (!myEquationsSystem.constraint) {
- myEquationsSystem.constraint = new Slvs_Constraint[theSize];
- myEquationsSystem.constraints = theSize;
- myEquationsSystem.failed = new Slvs_hConstraint[theSize];
- }
- else if (myEquationsSystem.constraints != theSize) {
- if (theSize > myEquationsSystem.constraints) {
- delete[] myEquationsSystem.constraint;
- myEquationsSystem.constraint = new Slvs_Constraint[theSize];
- if (myEquationsSystem.failed)
- delete[] myEquationsSystem.failed;
- myEquationsSystem.failed = new Slvs_hConstraint[theSize];
- }
- myEquationsSystem.constraints = theSize;
- }
- memcpy(myEquationsSystem.constraint, theConstraints, theSize * sizeof(Slvs_Constraint));
- memset(myEquationsSystem.failed, SLVS_C_UNKNOWN, theSize * sizeof(Slvs_hConstraint));
-}
-
-
-int SketchSolver_Solver::solve()
-{
- if (myEquationsSystem.constraints <= 0)
- return SLVS_RESULT_EMPTY_SET;
-
- Events_LongOp::start(this);
- Slvs_Solve(&myEquationsSystem, myGroupID);
- Events_LongOp::end(this);
-
- return myEquationsSystem.result;
-}
-
-bool SketchSolver_Solver::getResult(std::vector<Slvs_Param>& theParameters)
-{
- if (myEquationsSystem.result != SLVS_RESULT_OKAY)
- return false;
-
- if (theParameters.size() != myEquationsSystem.params)
- return false; // number of parameters is not the same
-
- std::vector<Slvs_Param>::iterator aParamIter = theParameters.begin();
- for (int i = 0; i < myEquationsSystem.params; i++, aParamIter++) {
- if (myEquationsSystem.param[i].h != aParamIter->h)
- return false; // sequence of parameters was changed
- aParamIter->val = myEquationsSystem.param[i].val;
- }
-
- return true;
-}
+++ /dev/null
-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File: SketchSolver_Solver.h
-// Created: 07 May 2014
-// Author: Artem ZHIDKOV
-
-#ifndef SketchSolver_Solver_H_
-#define SketchSolver_Solver_H_
-
-#include "SketchSolver.h"
-
-// Need to be defined before including SolveSpace to avoid additional dependances on Windows platform
-#if defined(WIN32) && !defined(HAVE_C99_INTEGER_TYPES)
-typedef unsigned int UINT32;
-#else
-#include <stdint.h>
-#endif
-#include <string.h>
-#include <slvs.h>
-
-#include <vector>
-
-#define SLVS_RESULT_EMPTY_SET -1
-
-// Unknown constraint (for error reporting)
-#define SLVS_C_UNKNOWN 0
-// Fillet constraint identifier
-#define SLVS_C_FILLET 100100
-// Multi-rotation constraint identifier
-#define SLVS_C_MULTI_ROTATION 100101
-// Multi-translation constraint identifier
-#define SLVS_C_MULTI_TRANSLATION 100102
-// Unknown entity
-#define SLVS_E_UNKNOWN 0
-// Unknown group
-#define SLVS_G_UNKNOWN 0
-// Group ID to store external objects
-#define SLVS_G_OUTOFGROUP 1
-
-/**
- * The main class that performs the high-level operations for connection to the SolveSpace.
- */
-class SketchSolver_Solver
-{
- public:
- SketchSolver_Solver();
- ~SketchSolver_Solver();
-
- /** \brief Initialize the ID of the group
- */
- inline void setGroupID(Slvs_hGroup theGroupID)
- {
- myGroupID = theGroupID;
- }
-
- /** \brief Change array of parameters
- * \param[in] theParameters pointer to the array of parameters
- * \param[in] theSize size of this array
- */
- void setParameters(Slvs_Param* theParameters, int theSize);
-
- /** \brief Change array of entities
- * \param[in] theEntities pointer to the array of entities
- * \param[in] theSize size of this array
- */
- void setEntities(Slvs_Entity* theEntities, int theSize);
-
- /** \brief Change array of constraints
- * \param[in] theConstraints pointer to the array of constraints
- * \param[in] theSize size of this array
- */
- void setConstraints(Slvs_Constraint* theConstraints, int theSize);
-
- /** \brief Store the parameters of the point which was moved by user.
- * The solver will watch this items to be constant
- * \param[in] theDragged list of parameters (not more than 4) which should not be changed during solving
- */
- void setDraggedParameters(const Slvs_hParam* theDragged);
-
- /** \brief Set or unset the flag which allows to find all failed constraints
- */
- void calculateFailedConstraints(bool theSic)
- { myEquationsSystem.calculateFaileds = theSic ? 1 : 0; }
-
- /** \brief Solve the set of equations
- * \return identifier whether solution succeeded
- */
- int solve();
-
- /** \brief Updates the list of parameters by calculated values
- * \param[in,out] theParameters parameters to be updated
- * \return \c true if parameters are updated correctly
- */
- bool getResult(std::vector<Slvs_Param>& theParameters);
-
- private:
- Slvs_hGroup myGroupID; ///< identifier of the group to be solved
- Slvs_System myEquationsSystem; ///< set of equations for solving in SolveSpace
-};
-
-#endif
// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
// File: SketchSolver_Storage.cpp
-// Created: 18 Mar 2015
+// Created: 30 Nov 2015
// Author: Artem ZHIDKOV
#include <SketchSolver_Storage.h>
+#include <SketchSolver_Manager.h>
-#include <GeomAPI_Pnt2d.h>
-#include <GeomAPI_XY.h>
-#include <math.h>
+#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_AttributeRefAttr.h>
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
-/** \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<typename T>
-static int Search(const uint32_t& theEntityID, const std::vector<T>& 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);
+/// \brief Verify two vectors of constraints are equal.
+/// Vectors differ by the order of elements are equal.
+static bool isEqual(const std::list<ConstraintWrapperPtr>& theCVec1,
+ const std::list<ConstraintWrapperPtr>& theCVec2);
-SketchSolver_Storage::SketchSolver_Storage()
- : myParamMaxID(SLVS_E_UNKNOWN),
- myEntityMaxID(SLVS_E_UNKNOWN),
- myConstrMaxID(SLVS_C_UNKNOWN),
- myFixed(SLVS_E_UNKNOWN),
- myNeedToResolve(false),
- myDuplicatedConstraint(false)
+void SketchSolver_Storage::addConstraint(ConstraintPtr theConstraint,
+ ConstraintWrapperPtr theSolverConstraint)
{
+ std::list<ConstraintWrapperPtr> aConstrList(1, theSolverConstraint);
+ addConstraint(theConstraint, aConstrList);
}
-Slvs_hParam SketchSolver_Storage::addParameter(const Slvs_Param& theParam)
+void SketchSolver_Storage::addConstraint(
+ ConstraintPtr theConstraint,
+ std::list<ConstraintWrapperPtr> theSolverConstraints)
{
- if (theParam.h > 0 && theParam.h <= myParamMaxID) {
- // parameter is already used, rewrite it
- return updateParameter(theParam);
- }
-
- Slvs_Param aParam = theParam;
- if (aParam.h > myParamMaxID)
- myParamMaxID = aParam.h;
- else
- aParam.h = ++myParamMaxID;
- myParameters.push_back(aParam);
- myNeedToResolve = true;
- return aParam.h;
-}
+ std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
+ aFound = myConstraintMap.find(theConstraint);
+ if (aFound == myConstraintMap.end() || !isEqual(aFound->second, theSolverConstraints))
+ setNeedToResolve(true);
-Slvs_hParam SketchSolver_Storage::updateParameter(const Slvs_Param& theParam)
-{
- if (theParam.h > 0 && theParam.h <= myParamMaxID) {
- // parameter already used, rewrite it
- int aPos = Search(theParam.h, myParameters);
- if (aPos >= 0 && aPos < (int)myParameters.size()) {
- if (IsNotEqual(myParameters[aPos], theParam))
- myUpdatedParameters.insert(theParam.h);
- myParameters[aPos] = theParam;
- return theParam.h;
- }
+ // Do not add point-point coincidence, because it is already made by setting
+ // the same parameters for both points
+ if (!theSolverConstraints.empty() &&
+ theSolverConstraints.front()->type() != CONSTRAINT_PT_PT_COINCIDENT) {
+ std::list<ConstraintWrapperPtr>::iterator aCIt = theSolverConstraints.begin();
+ for (; aCIt != theSolverConstraints.end(); ++aCIt)
+ update(*aCIt);
}
-
- // Parameter is not found, add new one
- Slvs_Param aParam = theParam;
- aParam.h = 0;
- return addParameter(aParam);
+ myConstraintMap[theConstraint] = theSolverConstraints;
}
-bool SketchSolver_Storage::removeParameter(const Slvs_hParam& theParamID)
+void SketchSolver_Storage::addEntity(FeaturePtr theFeature,
+ EntityWrapperPtr theSolverEntity)
{
- int aPos = Search(theParamID, myParameters);
- if (aPos >= 0 && aPos < (int)myParameters.size()) {
- // Firstly, search the parametes is not used elsewhere
- std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
- for (; anEntIter != myEntities.end(); anEntIter++) {
- for (int i = 0; i < 4; i++)
- if (anEntIter->param[i] == theParamID)
- return false;
- }
- // Remove parameter
- myParameters.erase(myParameters.begin() + aPos);
- myParamMaxID = myParameters.empty() ? SLVS_E_UNKNOWN : myParameters.back().h;
- myNeedToResolve = true;
- myRemovedParameters.insert(theParamID);
- return true;
- }
- return false;
-}
-
-const Slvs_Param& SketchSolver_Storage::getParameter(const Slvs_hParam& theParamID) const
-{
- int aPos = Search(theParamID, myParameters);
- if (aPos >= 0 && aPos < (int)myParameters.size())
- return myParameters[aPos];
+ std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFound = myFeatureMap.find(theFeature);
+ if (aFound == myFeatureMap.end() || !aFound->second->isEqual(theSolverEntity))
+ setNeedToResolve(true); // the entity is new or modified
- // Parameter is not found, return empty object
- static Slvs_Param aDummy;
- aDummy.h = 0;
- return aDummy;
+ myFeatureMap[theFeature] = theSolverEntity;
}
-
-Slvs_hEntity SketchSolver_Storage::addEntity(const Slvs_Entity& theEntity)
+void SketchSolver_Storage::addEntity(AttributePtr theAttribute,
+ EntityWrapperPtr theSolverEntity)
{
- if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
- // Entity is already used, rewrite it
- return updateEntity(theEntity);
- }
+ std::map<AttributePtr, EntityWrapperPtr>::const_iterator aFound = myAttributeMap.find(theAttribute);
+ if (aFound == myAttributeMap.end() || !aFound->second->isEqual(theSolverEntity))
+ setNeedToResolve(true); // the entity is new or modified
- Slvs_Entity aEntity = theEntity;
- if (aEntity.h > myEntityMaxID)
- myEntityMaxID = aEntity.h;
- else
- aEntity.h = ++myEntityMaxID;
- myEntities.push_back(aEntity);
- myNeedToResolve = true;
- return aEntity.h;
+ myAttributeMap[theAttribute] = theSolverEntity;
}
-Slvs_hEntity SketchSolver_Storage::updateEntity(const Slvs_Entity& theEntity)
-{
- if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
- // Entity already used, rewrite it
- int aPos = Search(theEntity.h, myEntities);
- if (aPos >= 0 && aPos < (int)myEntities.size()) {
- myNeedToResolve = myNeedToResolve || IsNotEqual(myEntities[aPos], theEntity);
- myEntities[aPos] = theEntity;
- return theEntity.h;
- }
- }
-
- // Entity is not found, add new one
- Slvs_Entity aEntity = theEntity;
- aEntity.h = 0;
- return addEntity(aEntity);
-}
-
-bool SketchSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID)
-{
- bool aResult = true;
- int aPos = Search(theEntityID, myEntities);
- if (aPos >= 0 && aPos < (int)myEntities.size()) {
- // Firstly, check the entity and its attributes is not used elsewhere
- std::set<Slvs_hEntity> anEntAndSubs;
- anEntAndSubs.insert(theEntityID);
- for (int i = 0; i < 4; i++)
- if (myEntities[aPos].point[i] != SLVS_E_UNKNOWN)
- anEntAndSubs.insert(myEntities[aPos].point[i]);
-
- std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
- for (; anEntIter != myEntities.end(); anEntIter++) {
- for (int i = 0; i < 4; i++)
- if (anEntAndSubs.find(anEntIter->point[i]) != anEntAndSubs.end())
- return false;
- if (anEntAndSubs.find(anEntIter->distance) != anEntAndSubs.end())
- return false;
- }
- std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
- for (; aConstrIter != myConstraints.end(); aConstrIter++) {
- Slvs_hEntity anEntIDs[6] = {aConstrIter->ptA, aConstrIter->ptB,
- aConstrIter->entityA, aConstrIter->entityB,
- aConstrIter->entityC, aConstrIter->entityD};
- for (int i = 0; i < 6; i++)
- if (anEntAndSubs.find(anEntIDs[i]) != anEntAndSubs.end())
- return false;
- }
- // The entity is not used, remove it and its parameters
- Slvs_Entity anEntity = myEntities[aPos];
- myEntities.erase(myEntities.begin() + aPos);
- myEntityMaxID = myEntities.empty() ? SLVS_E_UNKNOWN : myEntities.back().h;
- if (anEntity.distance != SLVS_E_UNKNOWN)
- aResult = aResult && removeParameter(anEntity.distance);
- for (int i = 0; i < 4; i++)
- if (anEntity.param[i] != SLVS_E_UNKNOWN)
- aResult = removeParameter(anEntity.param[i]) && aResult;
- for (int i = 0; i < 4; i++)
- if (anEntity.point[i] != SLVS_E_UNKNOWN)
- aResult = removeEntity(anEntity.point[i]) && aResult;
- myNeedToResolve = true;
- myRemovedEntities.insert(theEntityID);
- if (anEntity.type == SLVS_E_POINT_IN_2D || anEntity.type == SLVS_E_POINT_IN_3D)
- removeCoincidentPoint(theEntityID);
- }
- return aResult;
-}
-void SketchSolver_Storage::removeUnusedEntities()
+bool SketchSolver_Storage::update(FeaturePtr theFeature, const GroupID& theGroup)
{
- std::set<Slvs_hEntity> anUnusedEntities;
- std::vector<Slvs_Entity>::const_iterator aEIt = myEntities.begin();
- for (; aEIt != myEntities.end(); ++aEIt) {
- if (aEIt->h == aEIt->wrkpl) {
- // don't remove workplane
- anUnusedEntities.erase(aEIt->point[0]);
- anUnusedEntities.erase(aEIt->normal);
- continue;
+ bool isUpdated = false;
+ EntityWrapperPtr aRelated = entity(theFeature);
+ if (!aRelated) { // Feature is not exist, create it
+ std::list<EntityWrapperPtr> aSubs;
+ // Firstly, create/update its attributes
+ std::list<AttributePtr> anAttrs =
+ theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
+ std::list<AttributePtr>::const_iterator anIt = anAttrs.begin();
+ for (; anIt != anAttrs.end(); ++anIt) {
+ isUpdated = update(*anIt, theGroup) || isUpdated;
+ aSubs.push_back(entity(*anIt));
}
- anUnusedEntities.insert(aEIt->h);
- }
-
- std::vector<Slvs_Constraint>::const_iterator aCIt = myConstraints.begin();
- for (; aCIt != myConstraints.end(); ++aCIt) {
- Slvs_hEntity aSubs[6] = {
- aCIt->entityA, aCIt->entityB,
- aCIt->entityC, aCIt->entityD,
- aCIt->ptA, aCIt->ptB};
- for (int i = 0; i < 6; i++) {
- if (aSubs[i] != SLVS_E_UNKNOWN) {
- anUnusedEntities.erase(aSubs[i]);
- int aPos = Search(aSubs[i], myEntities);
- if (aPos >= 0 && aPos < (int)myEntities.size()) {
- for (int j = 0; j < 4; j++)
- if (myEntities[aPos].point[j] != SLVS_E_UNKNOWN)
- anUnusedEntities.erase(myEntities[aPos].point[j]);
- if (myEntities[aPos].distance != SLVS_E_UNKNOWN)
- anUnusedEntities.erase(myEntities[aPos].distance);
- }
- }
+ // If the feature is a circle, add its radius as a sub
+ if (theFeature->getKind() == SketchPlugin_Circle::ID()) {
+ AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID());
+ isUpdated = update(aRadius, theGroup) || isUpdated;
+ aSubs.push_back(entity(aRadius));
}
- }
-
- std::set<Slvs_hEntity>::const_iterator anEntIt = anUnusedEntities.begin();
- while (anEntIt != anUnusedEntities.end()) {
- int aPos = Search(*anEntIt, myEntities);
- if (aPos < 0 && aPos >= (int)myEntities.size())
- continue;
- Slvs_Entity anEntity = myEntities[aPos];
- // Remove entity if and only if all its parameters unused
- bool isUsed = false;
- if (anEntity.distance != SLVS_E_UNKNOWN &&
- anUnusedEntities.find(anEntity.distance) == anUnusedEntities.end())
- isUsed = true;
- for (int i = 0; i < 4 && !isUsed; i++)
- if (anEntity.point[i] != SLVS_E_UNKNOWN &&
- anUnusedEntities.find(anEntity.point[i]) == anUnusedEntities.end())
- isUsed = true;
- if (isUsed) {
- anUnusedEntities.erase(anEntity.distance);
- for (int i = 0; i < 4; i++)
- if (anEntity.point[i] != SLVS_E_UNKNOWN)
- anUnusedEntities.erase(anEntity.point[i]);
- std::set<Slvs_hEntity>::iterator aRemoveIt = anEntIt++;
- anUnusedEntities.erase(aRemoveIt);
- continue;
+ // If the feature if circle or arc, we need to add normal of the sketch to the list of subs
+ if (theFeature->getKind() == SketchPlugin_Arc::ID() ||
+ theFeature->getKind() == SketchPlugin_Circle::ID()) {
+ EntityWrapperPtr aNormal = getNormal();
+ if (aNormal) aSubs.push_back(aNormal);
}
- ++anEntIt;
- }
-
- for (anEntIt = anUnusedEntities.begin(); anEntIt != anUnusedEntities.end(); ++anEntIt) {
- int aPos = Search(*anEntIt, myEntities);
- if (aPos >= 0 && aPos < (int)myEntities.size()) {
- // Remove entity and its parameters
- Slvs_Entity anEntity = myEntities[aPos];
- myEntities.erase(myEntities.begin() + aPos);
- myEntityMaxID = myEntities.empty() ? SLVS_E_UNKNOWN : myEntities.back().h;
- if (anEntity.distance != SLVS_E_UNKNOWN)
- removeParameter(anEntity.distance);
- for (int i = 0; i < 4; i++)
- if (anEntity.param[i] != SLVS_E_UNKNOWN)
- removeParameter(anEntity.param[i]);
- for (int i = 0; i < 4; i++)
- if (anEntity.point[i] != SLVS_E_UNKNOWN)
- removeEntity(anEntity.point[i]);
- myRemovedEntities.insert(*anEntIt);
- if (anEntity.type == SLVS_E_POINT_IN_2D || anEntity.type == SLVS_E_POINT_IN_3D)
- removeCoincidentPoint(*anEntIt);
- }
- }
-
- if (!anUnusedEntities.empty())
- myNeedToResolve = true;
-}
-
-bool SketchSolver_Storage::isUsedByConstraints(const Slvs_hEntity& theEntityID) const
-{
- std::vector<Slvs_Constraint>::const_iterator aCIt = myConstraints.begin();
- for (; aCIt != myConstraints.end(); ++aCIt) {
- Slvs_hEntity aSubs[6] = {
- aCIt->entityA, aCIt->entityB,
- aCIt->entityC, aCIt->entityD,
- aCIt->ptA, aCIt->ptB};
- for (int i = 0; i < 6; i++)
- if (aSubs[i] != SLVS_E_UNKNOWN && aSubs[i] == theEntityID)
- return true;
- }
- return false;
-}
-
-const Slvs_Entity& SketchSolver_Storage::getEntity(const Slvs_hEntity& theEntityID) const
-{
- int aPos = Search(theEntityID, myEntities);
- if (aPos >= 0 && aPos < (int)myEntities.size())
- return myEntities[aPos];
-
- // Entity is not found, return empty object
- static Slvs_Entity aDummy;
- aDummy.h = SLVS_E_UNKNOWN;
- return aDummy;
-}
-
-Slvs_hEntity SketchSolver_Storage::copyEntity(const Slvs_hEntity& theCopied)
-{
- int aPos = Search(theCopied, myEntities);
- if (aPos < 0 || aPos >= (int)myEntities.size())
- return SLVS_E_UNKNOWN;
-
- Slvs_Entity aCopy = myEntities[aPos];
- aCopy.h = SLVS_E_UNKNOWN;
- int i = 0;
- while (aCopy.point[i] != SLVS_E_UNKNOWN) {
- aCopy.point[i] = copyEntity(aCopy.point[i]);
- i++;
- }
- if (aCopy.param[0] != SLVS_E_UNKNOWN) {
- aPos = Search(aCopy.param[0], myParameters);
- i = 0;
- while (aCopy.param[i] != SLVS_E_UNKNOWN) {
- Slvs_Param aNewParam = myParameters[aPos];
- aNewParam.h = SLVS_E_UNKNOWN;
- aCopy.param[i] = addParameter(aNewParam);
- i++;
- aPos++;
- }
- }
- return addEntity(aCopy);
-}
-
-void SketchSolver_Storage::copyEntity(const Slvs_hEntity& theFrom, const Slvs_hEntity& theTo)
-{
- int aPosFrom = Search(theFrom, myEntities);
- int aPosTo = Search(theTo, myEntities);
- if (aPosFrom < 0 || aPosFrom >= (int)myEntities.size() ||
- aPosTo < 0 || aPosTo >= (int)myEntities.size())
- return;
-
- Slvs_Entity aEntFrom = myEntities[aPosFrom];
- Slvs_Entity aEntTo = myEntities[aPosTo];
- int i = 0;
- while (aEntFrom.point[i] != SLVS_E_UNKNOWN) {
- copyEntity(aEntFrom.point[i], aEntTo.point[i]);
- i++;
- }
- if (aEntFrom.param[0] != SLVS_E_UNKNOWN) {
- aPosFrom = Search(aEntFrom.param[0], myParameters);
- aPosTo = Search(aEntTo.param[0], myParameters);
- i = 0;
- while (aEntFrom.param[i] != SLVS_E_UNKNOWN) {
- myParameters[aPosTo++].val = myParameters[aPosFrom++].val;
- i++;
- }
- }
-}
-
-
-bool SketchSolver_Storage::isPointFixed(
- const Slvs_hEntity& thePointID, Slvs_hConstraint& theFixed, bool theAccurate) const
-{
- // Search the set of coincident points
- std::set<Slvs_hEntity> aCoincident;
- aCoincident.insert(thePointID);
- std::vector< std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
- for (; aCPIter != myCoincidentPoints.end(); aCPIter++)
- if (aCPIter->find(thePointID) != aCPIter->end()) {
- aCoincident = *aCPIter;
- break;
- }
-
- // Check whether one of coincident points is out-of-group
- std::set<Slvs_hEntity>::const_iterator aCoincIt = aCoincident.begin();
- for (; aCoincIt != aCoincident.end(); ++aCoincIt) {
- Slvs_Entity aPoint = getEntity(*aCoincIt);
- if (aPoint.group == SLVS_G_OUTOFGROUP)
- return true;
- }
-
- // Search the Rigid constraint
- theFixed = SLVS_C_UNKNOWN;
- std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
- for (; aConstrIter != myConstraints.end(); aConstrIter++)
- if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
- aCoincident.find(aConstrIter->ptA) != aCoincident.end()) {
- theFixed = aConstrIter->h;
- if (aConstrIter->ptA == thePointID)
- return true;
- }
- if (theFixed != SLVS_C_UNKNOWN)
- return true;
-
- if (theAccurate) {
- // Try to find the fixed entity which uses such point or its coincidence
- std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
- for (; anEntIter != myEntities.end(); anEntIter++) {
- for (int i = 0; i < 4; i++) {
- Slvs_hEntity aPt = anEntIter->point[i];
- if (aPt != SLVS_E_UNKNOWN &&
- (aPt == thePointID || aCoincident.find(aPt) != aCoincident.end())) {
- if (isEntityFixed(anEntIter->h, true))
- return true;
- }
- }
- }
- }
- return SLVS_E_UNKNOWN;
-}
-
-bool SketchSolver_Storage::isEntityFixed(const Slvs_hEntity& theEntityID, bool theAccurate) const
-{
- int aPos = Search(theEntityID, myEntities);
- if (aPos < 0 || aPos >= (int)myEntities.size())
- return false;
-
- // Firstly, find how many points are under Rigid constraint
- int aNbFixed = 0;
- for (int i = 0; i < 4; i++) {
- Slvs_hEntity aPoint = myEntities[aPos].point[i];
- if (aPoint == SLVS_E_UNKNOWN)
- continue;
-
- std::set<Slvs_hEntity> aCoincident;
- aCoincident.insert(aPoint);
- std::vector< std::set<Slvs_hEntity> >::const_iterator aCPIter = myCoincidentPoints.begin();
- for (; aCPIter != myCoincidentPoints.end(); aCPIter++)
- if (aCPIter->find(aPoint) != aCPIter->end()) {
- aCoincident = *aCPIter;
- break;
- }
-
- // Search the Rigid constraint
- std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
- for (; aConstrIter != myConstraints.end(); aConstrIter++)
- if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
- aCoincident.find(aConstrIter->ptA) != aCoincident.end())
- aNbFixed++;
- }
-
- std::list<Slvs_Constraint> aList;
- std::list<Slvs_Constraint>::iterator anIt;
- Slvs_hConstraint aTempID; // used in isPointFixed() method
-
- if (myEntities[aPos].type == SLVS_E_LINE_SEGMENT) {
- if (aNbFixed == 2)
- return true;
- else if (aNbFixed == 0 || !theAccurate)
- return false;
- // Additional check (the line may be fixed if it is used by different constraints):
- // 1. The line is used in Equal constraint, another entity is fixed and there is a fixed point on line
- aList = getConstraintsByType(SLVS_C_PT_ON_LINE);
- for (anIt = aList.begin(); anIt != aList.end(); anIt++)
- if (anIt->entityA == theEntityID && isPointFixed(anIt->ptA, aTempID))
- break;
- if (anIt != aList.end()) {
- aList = getConstraintsByType(SLVS_C_EQUAL_LENGTH_LINES);
- aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN));
- for (anIt = aList.begin(); anIt != aList.end(); anIt++)
- if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
- Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
- if (isEntityFixed(anOther, false))
- return true;
- }
- }
- // 2. The line is used in Parallel/Perpendicular/Vertical/Horizontal and Length constraints
- aList = getConstraintsByType(SLVS_C_PARALLEL);
- aList.splice(aList.end(), getConstraintsByType(SLVS_C_PERPENDICULAR));
- aList.splice(aList.end(), getConstraintsByType(SLVS_C_VERTICAL));
- aList.splice(aList.end(), getConstraintsByType(SLVS_C_HORIZONTAL));
- for (anIt = aList.begin(); anIt != aList.end(); anIt++)
- if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
- Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
- if (isEntityFixed(anOther, false))
- break;
- }
- if (anIt != aList.end()) {
- aList = getConstraintsByType(SLVS_C_PT_PT_DISTANCE);
- for (anIt = aList.begin(); anIt != aList.end(); anIt++)
- if ((anIt->ptA == myEntities[aPos].point[0] && anIt->ptB == myEntities[aPos].point[1]) ||
- (anIt->ptA == myEntities[aPos].point[1] && anIt->ptB == myEntities[aPos].point[0]))
- return true;
- }
- // 3. Another verifiers ...
- } else if (myEntities[aPos].type == SLVS_E_CIRCLE) {
- if (aNbFixed == 0)
+ // Secondly, convert feature
+ BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+ aRelated = aBuilder->createFeature(theFeature, aSubs, theGroup);
+ if (!aRelated)
return false;
- // Search for Diameter constraint
- aList = getConstraintsByType(SLVS_C_DIAMETER);
- for (anIt = aList.begin(); anIt != aList.end(); anIt++)
- if (anIt->entityA == theEntityID)
- return true;
- if (!theAccurate)
- return false;
- // Additional check (the circle may be fixed if it is used by different constraints):
- // 1. The circle is used in Equal constraint and another entity is fixed
- aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS);
- for (anIt = aList.begin(); anIt != aList.end(); anIt++)
- if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
- Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
- if (isEntityFixed(anOther, false))
- return true;
- }
- // 2. Another verifiers ...
- } else if (myEntities[aPos].type == SLVS_E_ARC_OF_CIRCLE) {
- if (aNbFixed > 2)
- return true;
- else if (aNbFixed <= 1)
- return false;
- // Search for Diameter constraint
- aList = getConstraintsByType(SLVS_C_DIAMETER);
- for (anIt = aList.begin(); anIt != aList.end(); anIt++)
- if (anIt->entityA == theEntityID)
- return true;
- if (!theAccurate)
- return false;
- // Additional check (the arc may be fixed if it is used by different constraints):
- // 1. The arc is used in Equal constraint and another entity is fixed
- aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS);
- aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN));
- for (anIt = aList.begin(); anIt != aList.end(); anIt++)
- if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
- Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
- if (isEntityFixed(anOther, false))
- return true;
- }
- // 2. Another verifiers ...
- }
- return false;
-}
-
-
-Slvs_hConstraint SketchSolver_Storage::addConstraint(const Slvs_Constraint& theConstraint)
-{
- if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
- // Constraint is already used, rewrite it
- return updateConstraint(theConstraint);
- }
-
- Slvs_Constraint aConstraint = theConstraint;
-
- // Find a constraint with same type uses same arguments to show user overconstraint situation
- std::vector<Slvs_Constraint>::iterator aCIt = myConstraints.begin();
- for (; aCIt != myConstraints.end(); aCIt++) {
- if (aConstraint.type != aCIt->type)
- continue;
- if (aConstraint.ptA == aCIt->ptA && aConstraint.ptB == aCIt->ptB &&
- aConstraint.entityA == aCIt->entityA && aConstraint.entityB == aCIt->entityB &&
- aConstraint.entityC == aCIt->entityC && aConstraint.entityD == aCIt->entityD)
- myDuplicatedConstraint = true;
- }
-
- if (aConstraint.h > myConstrMaxID)
- myConstrMaxID = aConstraint.h;
- else
- aConstraint.h = ++myConstrMaxID;
- myConstraints.push_back(aConstraint);
- myNeedToResolve = true;
- if (aConstraint.type == SLVS_C_POINTS_COINCIDENT)
- addCoincidentPoints(aConstraint.ptA, aConstraint.ptB);
- return aConstraint.h;
+ addEntity(theFeature, aRelated);
+ } else if (theGroup != GID_UNKNOWN)
+ changeGroup(aRelated, theGroup);
+ return update(aRelated) || isUpdated;
}
-Slvs_hConstraint SketchSolver_Storage::updateConstraint(const Slvs_Constraint& theConstraint)
+bool SketchSolver_Storage::update(AttributePtr theAttribute, const GroupID& theGroup)
{
- if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
- // Constraint already used, rewrite it
- int aPos = Search(theConstraint.h, myConstraints);
- if (aPos >= 0 && aPos < (int)myConstraints.size()) {
- myNeedToResolve = myNeedToResolve || IsNotEqual(myConstraints[aPos], theConstraint);
- myConstraints[aPos] = theConstraint;
- if (theConstraint.type == SLVS_C_POINTS_COINCIDENT)
- addCoincidentPoints(theConstraint.ptA, theConstraint.ptB);
- return theConstraint.h;
- }
+ AttributePtr anAttribute = theAttribute;
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
+ if (aRefAttr) {
+ if (aRefAttr->isObject()) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+ return update(aFeature, theGroup);
+ } else
+ anAttribute = aRefAttr->attr();
}
- // Constraint is not found, add new one
- Slvs_Constraint aConstraint = theConstraint;
- aConstraint.h = 0;
- return addConstraint(aConstraint);
+ EntityWrapperPtr aRelated = entity(anAttribute);
+ if (!aRelated) { // Attribute is not exist, create it
+ BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
+ aRelated = aBuilder->createAttribute(anAttribute, theGroup);
+ if (!aRelated)
+ return false;
+ addEntity(anAttribute, aRelated);
+ } else if (theGroup != GID_UNKNOWN)
+ changeGroup(aRelated, theGroup);
+ return update(aRelated);
}
-bool SketchSolver_Storage::removeConstraint(const Slvs_hConstraint& theConstraintID)
-{
- bool aResult = true;
- int aPos = Search(theConstraintID, myConstraints);
- if (aPos >= 0 && aPos < (int)myConstraints.size()) {
- Slvs_Constraint aConstraint = myConstraints[aPos];
- myConstraints.erase(myConstraints.begin() + aPos);
- myConstrMaxID = myConstraints.empty() ? SLVS_E_UNKNOWN : myConstraints.back().h;
- myNeedToResolve = true;
- myRemovedConstraints.insert(theConstraintID);
- if (aConstraint.type == SLVS_C_POINTS_COINCIDENT)
- removeCoincidence(aConstraint);
- // Remove all entities
- Slvs_hEntity anEntities[6] = {aConstraint.ptA, aConstraint.ptB,
- aConstraint.entityA, aConstraint.entityB,
- aConstraint.entityC, aConstraint.entityD};
- for (int i = 0; i < 6; i++)
- if (anEntities[i] != SLVS_E_UNKNOWN)
- aResult = removeEntity(anEntities[i]) && aResult;
- // remove temporary fixed point, if available
- if (myFixed == theConstraintID)
- myFixed = SLVS_E_UNKNOWN;
- if (myDuplicatedConstraint) {
- // Check the duplicated constraints are still available
- myDuplicatedConstraint = false;
- std::vector<Slvs_Constraint>::const_iterator anIt1 = myConstraints.begin();
- std::vector<Slvs_Constraint>::const_iterator anIt2 = myConstraints.begin();
- for (; anIt1 != myConstraints.end() && !myDuplicatedConstraint; anIt1++)
- for (anIt2 = anIt1+1; anIt2 != myConstraints.end() && !myDuplicatedConstraint; anIt2++) {
- if (anIt1->type != anIt2->type)
- continue;
- if (anIt1->ptA == anIt2->ptA && anIt1->ptB == anIt2->ptB &&
- anIt1->entityA == anIt2->entityA && anIt1->entityB == anIt2->entityB &&
- anIt1->entityC == anIt2->entityC && anIt1->entityD == anIt2->entityD)
- myDuplicatedConstraint = true;
- }
- }
- }
- return aResult;
-}
-const Slvs_Constraint& SketchSolver_Storage::getConstraint(const Slvs_hConstraint& theConstraintID) const
+const std::list<ConstraintWrapperPtr>& SketchSolver_Storage::constraint(
+ const ConstraintPtr& theConstraint) const
{
- int aPos = Search(theConstraintID, myConstraints);
- if (aPos >= 0 && aPos < (int)myConstraints.size())
- return myConstraints[aPos];
+ static std::list<ConstraintWrapperPtr> aDummy;
- // Constraint is not found, return empty object
- static Slvs_Constraint aDummy;
- aDummy.h = 0;
+ std::map<ConstraintPtr, std::list<ConstraintWrapperPtr>>::const_iterator
+ aFound = myConstraintMap.find(theConstraint);
+ if (aFound != myConstraintMap.end())
+ return aFound->second;
return aDummy;
}
-std::list<Slvs_Constraint> SketchSolver_Storage::getConstraintsByType(int theConstraintType) const
-{
- std::list<Slvs_Constraint> aResult;
- std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
- for (; aCIter != myConstraints.end(); aCIter++)
- if (aCIter->type == theConstraintType)
- aResult.push_back(*aCIter);
- return aResult;
-}
-
-
-void SketchSolver_Storage::addConstraintWhereDragged(const Slvs_hConstraint& theConstraintID)
-{
- if (myFixed != SLVS_E_UNKNOWN)
- return; // the point is already fixed
- int aPos = Search(theConstraintID, myConstraints);
- if (aPos >= 0 && aPos < (int)myConstraints.size())
- myFixed = theConstraintID;
-}
-
-void SketchSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID)
+const EntityWrapperPtr& SketchSolver_Storage::entity(const FeaturePtr& theFeature) const
{
- myTemporaryConstraints.insert(theConstraintID);
-}
+ static EntityWrapperPtr aDummy;
-void SketchSolver_Storage::removeTemporaryConstraints()
-{
- myTemporaryConstraints.clear();
-}
-
-int SketchSolver_Storage::deleteTemporaryConstraint()
-{
- if (myTemporaryConstraints.empty())
- return 0;
- // Search the point-on-line or a non-rigid constraint
- std::set<Slvs_hConstraint>::iterator aCIt = myTemporaryConstraints.begin();
- for (; aCIt != myTemporaryConstraints.end(); aCIt++) {
- int aPos = Search(*aCIt, myConstraints);
- if (aPos >= (int)myConstraints.size() || myConstraints[aPos].type != SLVS_C_WHERE_DRAGGED)
- break;
- std::vector<Slvs_Constraint>::iterator anIt = myConstraints.begin();
- for (; anIt != myConstraints.end(); anIt++)
- if (anIt->type == SLVS_C_PT_ON_LINE && anIt->ptA == myConstraints[aPos].ptA)
- break;
- if (anIt != myConstraints.end())
- break;
- }
- if (aCIt == myTemporaryConstraints.end())
- aCIt = myTemporaryConstraints.begin();
- bool aNewFixed = (*aCIt == myFixed);
- removeConstraint(*aCIt);
- myTemporaryConstraints.erase(aCIt);
- if (aNewFixed) {
- for (aCIt = myTemporaryConstraints.begin(); aCIt != myTemporaryConstraints.end(); aCIt++) {
- int aPos = Search(*aCIt, myConstraints);
- if (myConstraints[aPos].type == SLVS_C_WHERE_DRAGGED) {
- myFixed = *aCIt;
- break;
- }
- }
- }
- return (int)myTemporaryConstraints.size();
-}
-
-bool SketchSolver_Storage::isTemporary(const Slvs_hConstraint& theConstraintID) const
-{
- return myTemporaryConstraints.find(theConstraintID) != myTemporaryConstraints.end();
-}
-
-
-void SketchSolver_Storage::getRemoved(
- std::set<Slvs_hParam>& theParameters,
- std::set<Slvs_hEntity>& theEntities,
- std::set<Slvs_hConstraint>& theConstraints)
-{
- theParameters = myRemovedParameters;
- theEntities = myRemovedEntities;
- theConstraints = myRemovedConstraints;
-
- myRemovedParameters.clear();
- myRemovedEntities.clear();
- myRemovedConstraints.clear();
+ std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFound = myFeatureMap.find(theFeature);
+ if (aFound != myFeatureMap.end())
+ return aFound->second;
+ return aDummy;
}
-void SketchSolver_Storage::initializeSolver(SketchSolver_Solver& theSolver)
+const EntityWrapperPtr& SketchSolver_Storage::entity(const AttributePtr& theAttribute) const
{
- theSolver.setParameters(myParameters.data(), (int)myParameters.size());
- theSolver.setEntities(myEntities.data(), (int)myEntities.size());
+ static EntityWrapperPtr aDummy;
- // Copy constraints excluding the fixed one
- std::vector<Slvs_Constraint> aConstraints = myConstraints;
- if (myFixed != SLVS_E_UNKNOWN) {
- Slvs_hEntity aFixedPoint = SLVS_E_UNKNOWN;
- std::vector<Slvs_Constraint>::iterator anIt = aConstraints.begin();
- for (; anIt != aConstraints.end(); anIt++)
- if (anIt->h == myFixed) {
- aFixedPoint = anIt->ptA;
- aConstraints.erase(anIt);
- break;
- }
- // set dragged parameters
- int aPos = Search(aFixedPoint, myEntities);
- theSolver.setDraggedParameters(myEntities[aPos].param);
- }
- theSolver.setConstraints(aConstraints.data(), (int)aConstraints.size());
-}
+ std::map<AttributePtr, EntityWrapperPtr>::const_iterator
+ aFound = myAttributeMap.find(theAttribute);
+ if (aFound != myAttributeMap.end())
+ return aFound->second;
-void SketchSolver_Storage::addCoincidentPoints(
- const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2)
-{
- std::vector< std::set<Slvs_hEntity> >::iterator aCIter = myCoincidentPoints.begin();
- std::vector< std::set<Slvs_hEntity> >::iterator aFoundIter = myCoincidentPoints.end(); // already found coincidence
- bool isFound = false;
- for (; aCIter != myCoincidentPoints.end(); aCIter++) {
- bool isFirstFound = aCIter->find(thePoint1) != aCIter->end();
- bool isSecondFound = aCIter->find(thePoint2) != aCIter->end();
- isFound = isFound || isFirstFound || isSecondFound;
- if (isFirstFound && isSecondFound)
- break; // already coincident
- else if (isFirstFound || isSecondFound) {
- if (aFoundIter != myCoincidentPoints.end()) {
- // merge two sets
- aFoundIter->insert(aCIter->begin(), aCIter->end());
- myCoincidentPoints.erase(aCIter);
- break;
- } else
- aFoundIter = aCIter;
- aCIter->insert(thePoint1);
- aCIter->insert(thePoint2);
- }
- }
- // coincident points not found
- if (!isFound) {
- std::set<Slvs_hEntity> aNewSet;
- aNewSet.insert(thePoint1);
- aNewSet.insert(thePoint2);
- myCoincidentPoints.push_back(aNewSet);
+ AttributeRefAttrPtr aRefAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
+ if (aRefAttr) {
+ if (aRefAttr->isObject()) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+ return entity(aFeature);
+ } else
+ return entity(aRefAttr->attr());
}
+ return aDummy;
}
-void SketchSolver_Storage::removeCoincidentPoint(const Slvs_hEntity& thePoint)
-{
- std::vector< std::set<Slvs_hEntity> >::iterator aCIter = myCoincidentPoints.begin();
- for (; aCIter != myCoincidentPoints.end(); aCIter++)
- if (aCIter->find(thePoint) != aCIter->end()) {
- aCIter->erase(thePoint);
- if (aCIter->size() <= 1)
- myCoincidentPoints.erase(aCIter);
- break;
- }
-}
-
-void SketchSolver_Storage::removeCoincidence(const Slvs_Constraint& theCoincidence)
+bool SketchSolver_Storage::isInteract(const FeaturePtr& theFeature) const
{
- // Find set of coincident points
- std::vector< std::set<Slvs_hEntity> >::iterator aCIt = myCoincidentPoints.begin();
- for (; aCIt != myCoincidentPoints.end(); ++aCIt)
- if (aCIt->find(theCoincidence.ptA) != aCIt->end() ||
- aCIt->find(theCoincidence.ptB) != aCIt->end())
- break;
- if (aCIt == myCoincidentPoints.end())
- return;
-
- // Leave only the points which are still coincident
- std::set<Slvs_hEntity> aRemainCoincidence;
- std::vector<Slvs_Constraint>::const_iterator aConstrIt = myConstraints.begin();
- for (; aConstrIt != myConstraints.end(); ++aConstrIt) {
- if (aConstrIt->type != SLVS_C_POINTS_COINCIDENT)
- continue;
- if (aCIt->find(aConstrIt->ptA) != aCIt->end() ||
- aCIt->find(aConstrIt->ptB) != aCIt->end()) {
- aRemainCoincidence.insert(aConstrIt->ptA);
- aRemainCoincidence.insert(aConstrIt->ptB);
- }
- }
- if (aRemainCoincidence.size() <= 1)
- myCoincidentPoints.erase(aCIt);
- else
- aCIt->swap(aRemainCoincidence);
-}
+ if (!theFeature)
+ return false;
+ if (myConstraintMap.empty())
+ return true; // empty storage interacts with each feature
-bool SketchSolver_Storage::isCoincident(
- const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const
-{
- std::vector< std::set<Slvs_hEntity> >::const_iterator aCIter = myCoincidentPoints.begin();
- for (; aCIter != myCoincidentPoints.end(); aCIter++)
- if (aCIter->find(thePoint1) != aCIter->end() && aCIter->find(thePoint2) != aCIter->end())
+ ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
+ if (aConstraint) {
+ if (myConstraintMap.find(aConstraint) != myConstraintMap.end())
return true;
- return false;
-}
-
-bool SketchSolver_Storage::isEqual(
- const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const
-{
- if (isCoincident(thePoint1, thePoint2))
+ } else if (myFeatureMap.find(theFeature) != myFeatureMap.end())
return true;
- // Precise checking of coincidence: verify that points have equal coordinates
- int aEnt1Pos = Search(thePoint1, myEntities);
- int aEnt2Pos = Search(thePoint2, myEntities);
- if (aEnt1Pos >= 0 && aEnt1Pos < (int)myEntities.size() &&
- aEnt2Pos >= 0 && aEnt2Pos < (int)myEntities.size()) {
- double aDist[2];
- int aParamPos;
- for (int i = 0; i < 2; i++) {
- aParamPos = Search(myEntities[aEnt1Pos].param[i], myParameters);
- aDist[i] = myParameters[aParamPos].val;
- aParamPos = Search(myEntities[aEnt2Pos].param[i], myParameters);
- aDist[i] -= myParameters[aParamPos].val;
- }
- if (aDist[0] * aDist[0] + aDist[1] * aDist[1] < tolerance * tolerance)
+ std::list<AttributePtr> anAttrList = theFeature->data()->attributes(std::string());
+ std::list<AttributePtr>::const_iterator anIt = anAttrList.begin();
+ for (; anIt != anAttrList.end(); ++anIt)
+ if (isInteract(*anIt))
return true;
- }
+
return false;
}
-
-std::vector<Slvs_hConstraint> SketchSolver_Storage::fixEntity(const Slvs_hEntity& theEntity)
+bool SketchSolver_Storage::isInteract(const AttributePtr& theAttribute) const
{
- std::vector<Slvs_hConstraint> aNewConstraints;
+ if (!theAttribute)
+ return false;
- int aPos = Search(theEntity, myEntities);
- if (aPos >= 0 && aPos < (int)myEntities.size()) {
- switch (myEntities[aPos].type) {
- case SLVS_E_POINT_IN_2D:
- case SLVS_E_POINT_IN_3D:
- fixPoint(myEntities[aPos], aNewConstraints);
- break;
- case SLVS_E_LINE_SEGMENT:
- fixLine(myEntities[aPos], aNewConstraints);
- break;
- case SLVS_E_CIRCLE:
- fixCircle(myEntities[aPos], aNewConstraints);
- break;
- case SLVS_E_ARC_OF_CIRCLE:
- fixArc(myEntities[aPos], aNewConstraints);
- break;
- default:
- break;
- }
- }
+ AttributeRefAttrPtr aRefAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(theAttribute);
+ if (!aRefAttr)
+ return myAttributeMap.find(theAttribute) != myAttributeMap.end();
+ if (!aRefAttr->isObject())
+ return myAttributeMap.find(aRefAttr->attr()) != myAttributeMap.end();
- return aNewConstraints;
+ FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
+ return isInteract(aFeature);
}
-void SketchSolver_Storage::fixPoint(const Slvs_Entity& thePoint,
- std::vector<Slvs_hConstraint>& theCreated)
+bool SketchSolver_Storage::isConsistent() const
{
- Slvs_Constraint aConstraint;
- Slvs_hConstraint aConstrID = SLVS_E_UNKNOWN;
- bool isFixed = isPointFixed(thePoint.h, aConstrID, true);
- bool isForceUpdate = (isFixed && isTemporary(aConstrID));
- if (!isForceUpdate) { // create new constraint
- if (isFixed) return;
- aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, thePoint.group, SLVS_C_WHERE_DRAGGED, thePoint.wrkpl,
- 0.0, thePoint.h, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- aConstraint.h = addConstraint(aConstraint);
- theCreated.push_back(aConstraint.h);
- } else { // update already existent constraint
- if (!isFixed || aConstrID == SLVS_E_UNKNOWN)
- return;
- int aPos = Search(aConstrID, myConstraints);
- if (aPos >= 0 && aPos < (int)myConstraints.size())
- myConstraints[aPos].ptA = thePoint.h;
- }
+ // Check the constraints are valid
+ std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
+ aCIter = myConstraintMap.begin();
+ for (; aCIter != myConstraintMap.end(); ++aCIter)
+ if (!aCIter->first->data() || !aCIter->first->data()->isValid())
+ return false;
+ // Check the features are valid
+ std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
+ for (; aFIter != myFeatureMap.end(); aFIter++)
+ if (!aFIter->first->data() || !aFIter->first->data()->isValid())
+ return false;
+ return true;
+}
+
+void SketchSolver_Storage::removeInvalidEntities()
+{
+ // Remove invalid constraints
+ std::list<ConstraintPtr> anInvalidConstraints;
+ std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
+ aCIter = myConstraintMap.begin();
+ for (; aCIter != myConstraintMap.end(); ++aCIter)
+ if (!aCIter->first->data() || !aCIter->first->data()->isValid())
+ anInvalidConstraints.push_back(aCIter->first);
+ std::list<ConstraintPtr>::const_iterator anInvCIt = anInvalidConstraints.begin();
+ for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt)
+ removeConstraint(*anInvCIt);
+ // Remove invalid features
+ std::list<FeaturePtr> anInvalidFeatures;
+ std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
+ for (; aFIter != myFeatureMap.end(); aFIter++)
+ if (!aFIter->first->data() || !aFIter->first->data()->isValid())
+ anInvalidFeatures.push_back(aFIter->first);
+ std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
+ for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
+ removeEntity(*anInvFIt);
+}
+
+EntityWrapperPtr SketchSolver_Storage::getNormal() const
+{
+ EntityWrapperPtr aSketch = sketch();
+ if (!aSketch)
+ return aSketch;
+
+ // Find normal entity
+ const std::list<EntityWrapperPtr>& aSketchSubs = aSketch->subEntities();
+ std::list<EntityWrapperPtr>::const_iterator aSIt = aSketchSubs.begin();
+ for (; aSIt != aSketchSubs.end(); ++aSIt)
+ if ((*aSIt)->type() == ENTITY_NORMAL)
+ return *aSIt;
+ return EntityWrapperPtr();
+}
+
+const EntityWrapperPtr& SketchSolver_Storage::sketch() const
+{
+ static EntityWrapperPtr aDummySketch;
+
+ std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
+ for (; aFIt != myFeatureMap.end(); ++aFIt)
+ if (aFIt->second->type() == ENTITY_SKETCH)
+ break;
+ if (aFIt == myFeatureMap.end())
+ return aDummySketch;
+ return aFIt->second;
}
-void SketchSolver_Storage::fixLine(const Slvs_Entity& theLine,
- std::vector<Slvs_hConstraint>& theCreated)
+void SketchSolver_Storage::setSketch(const EntityWrapperPtr& theSketch)
{
- Slvs_Entity aPoint[2] = {
- getEntity(theLine.point[0]),
- getEntity(theLine.point[1])
- };
-
- Slvs_Constraint anEqual;
- if (isAxisParallel(theLine.h)) {
- // Fix one point and a line length
- Slvs_hConstraint aFixed;
- if (!isPointFixed(theLine.point[0], aFixed, true) &&
- !isPointFixed(theLine.point[1], aFixed, true))
- fixPoint(aPoint[0], theCreated);
- if (!isUsedInEqual(theLine.h, anEqual)) {
- // Check the distance is not set yet
- std::vector<Slvs_Constraint>::const_iterator aDistIt = myConstraints.begin();
- for (; aDistIt != myConstraints.end(); ++aDistIt)
- if ((aDistIt->type == SLVS_C_PT_PT_DISTANCE) &&
- ((aDistIt->ptA == theLine.point[0] && aDistIt->ptB == theLine.point[1]) ||
- (aDistIt->ptA == theLine.point[1] && aDistIt->ptB == theLine.point[0])))
- return;
- // Calculate distance between points on the line
- double aCoords[4];
- for (int i = 0; i < 2; i++)
- for (int j = 0; j < 2; j++) {
- Slvs_Param aParam = getParameter(aPoint[i].param[j]);
- aCoords[2*i+j] = aParam.val;
- }
-
- double aLength = sqrt((aCoords[2] - aCoords[0]) * (aCoords[2] - aCoords[0]) +
- (aCoords[3] - aCoords[1]) * (aCoords[3] - aCoords[1]));
- // fix line length
- Slvs_Constraint aDistance = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theLine.group,
- SLVS_C_PT_PT_DISTANCE, theLine.wrkpl, aLength,
- theLine.point[0], theLine.point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
- aDistance.h = addConstraint(aDistance);
- theCreated.push_back(aDistance.h);
- }
+ if (sketch())
return;
- }
- else if (isUsedInEqual(theLine.h, anEqual)) {
- // Check another entity of Equal is already fixed
- Slvs_hEntity anOtherEntID = anEqual.entityA == theLine.h ? anEqual.entityB : anEqual.entityA;
- if (isEntityFixed(anOtherEntID, true)) {
- // Fix start point of the line (if end point is not fixed yet) ...
- Slvs_hConstraint anEndFixedID = SLVS_E_UNKNOWN;
- bool isFixed = isPointFixed(theLine.point[1], anEndFixedID, true);
- if (isFixed == SLVS_E_UNKNOWN)
- fixPoint(aPoint[0], theCreated);
- // ... and create fixed point lying on this line
- Slvs_hEntity aPointToCopy = anEndFixedID == SLVS_E_UNKNOWN ? theLine.point[1] : theLine.point[0];
- // Firstly, search already fixed point on line
- bool isPonLineFixed = false;
- Slvs_hEntity aFixedPoint;
- std::vector<Slvs_Constraint>::const_iterator aPLIter = myConstraints.begin();
- for (; aPLIter != myConstraints.end() && !isPonLineFixed; ++aPLIter)
- if (aPLIter->type == SLVS_C_PT_ON_LINE && aPLIter->entityA == theLine.h) {
- isPonLineFixed = isPointFixed(aPLIter->ptA, anEndFixedID);
- aFixedPoint = aPLIter->ptA;
- }
-
- if (isPonLineFixed) { // update existent constraint
- copyEntity(aPointToCopy, aFixedPoint);
- } else { // create new constraint
- Slvs_hEntity aCopied = copyEntity(aPointToCopy);
- Slvs_Constraint aPonLine = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theLine.group, SLVS_C_PT_ON_LINE,
- theLine.wrkpl, 0.0, aCopied, SLVS_E_UNKNOWN, theLine.h, SLVS_E_UNKNOWN);
- aPonLine.h = addConstraint(aPonLine);
- theCreated.push_back(aPonLine.h);
- fixPoint(getEntity(aCopied), theCreated);
- }
- return;
- }
- }
-
- // Fix both points
- for (int i = 0; i < 2; i++)
- fixPoint(aPoint[i], theCreated);
+ addEntity(FeaturePtr(), theSketch);
}
-void SketchSolver_Storage::fixCircle(const Slvs_Entity& theCircle,
- std::vector<Slvs_hConstraint>& theCreated)
+void SketchSolver_Storage::blockEvents(bool isBlocked) const
{
- bool isFixRadius = true;
- // Verify the arc is under Equal constraint
- Slvs_Constraint anEqual;
- if (isUsedInEqual(theCircle.h, anEqual)) {
- // Check another entity of Equal is already fixed
- Slvs_hEntity anOtherEntID = anEqual.entityA == theCircle.h ? anEqual.entityB : anEqual.entityA;
- if (isEntityFixed(anOtherEntID, true))
- isFixRadius = false;
- }
+ std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
+ aCIter = myConstraintMap.begin();
+ for (; aCIter != myConstraintMap.end(); aCIter++)
+ if (aCIter->first->data() && aCIter->first->data()->isValid())
+ aCIter->first->data()->blockSendAttributeUpdated(isBlocked);
- fixPoint(getEntity(theCircle.point[0]), theCreated);
+ std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
+ for (; aFIter != myFeatureMap.end(); aFIter++)
+ if (aFIter->first->data() && aFIter->first->data()->isValid())
+ aFIter->first->data()->blockSendAttributeUpdated(isBlocked);
- if (isFixRadius) {
- // Search the radius is already fixed
- std::vector<Slvs_Constraint>::const_iterator aDiamIter = myConstraints.begin();
- for (; aDiamIter != myConstraints.end(); ++aDiamIter)
- if (aDiamIter->type == SLVS_C_DIAMETER && aDiamIter->entityA == theCircle.h)
- return;
-
- // Fix radius of a circle
- const Slvs_Entity& aRadEnt = getEntity(theCircle.distance);
- double aRadius = getParameter(aRadEnt.param[0]).val;
- Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theCircle.group, SLVS_C_DIAMETER,
- theCircle.wrkpl, aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, theCircle.h, SLVS_E_UNKNOWN);
- aFixedR.h = addConstraint(aFixedR);
- theCreated.push_back(aFixedR.h);
- }
+ std::map<AttributePtr, EntityWrapperPtr>::const_iterator anAtIter = myAttributeMap.begin();
+ for (; anAtIter != myAttributeMap.end(); anAtIter++)
+ if (anAtIter->first->owner() && anAtIter->first->owner()->data() &&
+ anAtIter->first->owner()->data()->isValid())
+ anAtIter->first->owner()->data()->blockSendAttributeUpdated(isBlocked);
}
-void SketchSolver_Storage::fixArc(const Slvs_Entity& theArc,
- std::vector<Slvs_hConstraint>& theCreated)
-{
- Slvs_Entity aPoint[3] = {
- getEntity(theArc.point[0]),
- getEntity(theArc.point[1]),
- getEntity(theArc.point[2])
- };
-
- bool isFixRadius = true;
- std::list<Slvs_Entity> aPointsToFix;
- aPointsToFix.push_back(aPoint[1]);
- aPointsToFix.push_back(aPoint[2]);
-
- // Verify the arc is under Equal constraint
- Slvs_Constraint anEqual;
- if (isUsedInEqual(theArc.h, anEqual)) {
- // Check another entity of Equal is already fixed
- Slvs_hEntity anOtherEntID = anEqual.entityA == theArc.h ? anEqual.entityB : anEqual.entityA;
- if (isEntityFixed(anOtherEntID, true)) {
- isFixRadius = false;
- Slvs_Entity anOtherEntity = getEntity(anOtherEntID);
- if (anOtherEntity.type == SLVS_E_LINE_SEGMENT) {
- aPointsToFix.pop_back();
- aPointsToFix.push_back(aPoint[0]);
- }
- }
- }
-
- Slvs_hConstraint aConstrID;
- int aNbPointsToFix = 2; // number of fixed points for the arc
- if (isPointFixed(theArc.point[0], aConstrID, true))
- aNbPointsToFix--;
-
- double anArcPoints[3][2];
- for (int i = 0; i < 3; i++) {
- const Slvs_Entity& aPointOnArc = getEntity(theArc.point[i]);
- for (int j = 0; j < 2; j++)
- anArcPoints[i][j] = getParameter(aPointOnArc.param[j]).val;
- }
-
- // Radius of the arc
- std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(anArcPoints[0][0], anArcPoints[0][1]));
- std::shared_ptr<GeomAPI_Pnt2d> aStart(new GeomAPI_Pnt2d(anArcPoints[1][0], anArcPoints[1][1]));
- double aRadius = aCenter->distance(aStart);
- // Update end point of the arc to be on a curve
- std::shared_ptr<GeomAPI_Pnt2d> anEnd(new GeomAPI_Pnt2d(anArcPoints[2][0], anArcPoints[2][1]));
- double aDistance = anEnd->distance(aCenter);
- std::shared_ptr<GeomAPI_XY> aDir = anEnd->xy()->decreased(aCenter->xy());
- if (aDistance < tolerance)
- aDir = aStart->xy()->decreased(aCenter->xy())->multiplied(-1.0);
- else
- aDir = aDir->multiplied(aRadius / aDistance);
- double xy[2] = {aCenter->x() + aDir->x(), aCenter->y() + aDir->y()};
- const Slvs_Entity& aEndPoint = getEntity(theArc.point[2]);
- for (int i = 0; i < 2; i++) {
- Slvs_Param aParam = getParameter(aEndPoint.param[i]);
- aParam.val = xy[i];
- updateParameter(aParam);
- }
-
- std::list<Slvs_Entity>::iterator aPtIt = aPointsToFix.begin();
- for (; aNbPointsToFix > 0; aPtIt++, aNbPointsToFix--)
- fixPoint(*aPtIt, theCreated);
-
- if (isFixRadius) {
- // Fix radius of the arc
- bool isExists = false;
- std::vector<Slvs_Constraint>::iterator anIt = myConstraints.begin();
- for (; anIt != myConstraints.end() && !isExists; ++anIt)
- if (anIt->type == SLVS_C_DIAMETER && anIt->entityA == theArc.h)
- isExists = true;
- if (!isExists) {
- Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theArc.group, SLVS_C_DIAMETER,
- theArc.wrkpl, aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, theArc.h, SLVS_E_UNKNOWN);
- aFixedR.h = addConstraint(aFixedR);
- theCreated.push_back(aFixedR.h);
- }
- }
-}
-bool SketchSolver_Storage::isAxisParallel(const Slvs_hEntity& theEntity) const
-{
- std::vector<Slvs_Constraint>::const_iterator anIter = myConstraints.begin();
- for (; anIter != myConstraints.end(); anIter++)
- if ((anIter->type == SLVS_C_HORIZONTAL || anIter->type == SLVS_C_VERTICAL) &&
- anIter->entityA == theEntity)
- return true;
- return false;
-}
-bool SketchSolver_Storage::isUsedInEqual(
- const Slvs_hEntity& theEntity, Slvs_Constraint& theEqual) const
-{
- // Check the entity is used in Equal constraint
- std::vector<Slvs_Constraint>::const_iterator anEqIter = myConstraints.begin();
- for (; anEqIter != myConstraints.end(); anEqIter++)
- if ((anEqIter->type == SLVS_C_EQUAL_LENGTH_LINES ||
- anEqIter->type == SLVS_C_EQUAL_LINE_ARC_LEN ||
- anEqIter->type == SLVS_C_EQUAL_RADIUS) &&
- (anEqIter->entityA == theEntity || anEqIter->entityB == theEntity)) {
- theEqual = *anEqIter;
- return true;
- }
- return false;
-}
-bool SketchSolver_Storage::isNeedToResolve()
+// ============== Auxiliary functions ====================================
+bool isEqual(const std::list<ConstraintWrapperPtr>& theCVec1,
+ const std::list<ConstraintWrapperPtr>& theCVec2)
{
- if (myConstraints.empty())
+ if (theCVec1.size() != theCVec2.size())
return false;
- if (!myNeedToResolve) {
- // Verify the updated parameters are used in constraints
- std::set<Slvs_hEntity> aPoints;
- std::vector<Slvs_Entity>::const_iterator anEntIt = myEntities.begin();
- for (; anEntIt != myEntities.end(); ++anEntIt) {
- for (int i = 0; i < 4 && anEntIt->param[i] != SLVS_E_UNKNOWN; ++i)
- if (myUpdatedParameters.find(anEntIt->param[i]) != myUpdatedParameters.end()) {
- aPoints.insert(anEntIt->h);
- break;
- }
- }
- std::set<Slvs_hEntity> anEntities = aPoints;
- for (anEntIt = myEntities.begin(); anEntIt != myEntities.end(); ++anEntIt) {
- for (int i = 0; i < 4 && anEntIt->point[i] != SLVS_E_UNKNOWN; ++i)
- if (aPoints.find(anEntIt->point[i]) != aPoints.end()) {
- anEntities.insert(anEntIt->h);
- break;
- }
- }
-
- std::vector<Slvs_Constraint>::const_iterator aCIt = myConstraints.begin();
- for (; aCIt != myConstraints.end() && !myNeedToResolve; ++aCIt) {
- Slvs_hEntity anAttrs[6] =
- {aCIt->ptA, aCIt->ptB, aCIt->entityA, aCIt->entityB, aCIt->entityC, aCIt->entityD};
- for (int i = 0; i < 6; i++)
- if (anAttrs[i] != SLVS_E_UNKNOWN && anEntities.find(anAttrs[i]) != anEntities.end()) {
- myNeedToResolve = true;
- break;
- }
- }
+ std::list<bool> aChecked(theCVec2.size(), false);
+ std::list<ConstraintWrapperPtr>::const_iterator anIt1 = theCVec1.begin();
+ for (; anIt1 != theCVec1.end(); ++anIt1) {
+ std::list<ConstraintWrapperPtr>::const_iterator anIt2 = theCVec2.begin();
+ std::list<bool>::iterator aCheckIt = aChecked.begin();
+ while (aCheckIt != aChecked.end() && *aCheckIt) {
+ ++aCheckIt;
+ ++anIt2;
+ }
+ for (; anIt2 != theCVec2.end(); ++anIt2, ++aCheckIt)
+ if (!(*aCheckIt) && (*anIt1)->isEqual(*anIt2)) {
+ *aCheckIt = true;
+ break;
+ }
+ // the same constraint is not found
+ if (anIt2 == theCVec2.end())
+ return false;
}
-
- myUpdatedParameters.clear();
- return myNeedToResolve;
-}
-
-
-
-
-
-
-// ========================================================
-// ========= Auxiliary functions ===============
-// ========================================================
-
-template<typename T>
-int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
-{
- int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
- int aVecSize = theEntities.size();
- if (theEntities.empty())
- return 1;
- while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
- aResIndex--;
- while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
- aResIndex++;
- if (aResIndex == -1 || (aResIndex < aVecSize && theEntities[aResIndex].h != theEntityID))
- aResIndex = aVecSize;
- return aResIndex;
-}
-
-bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2)
-{
- return fabs(theParam1.val - theParam2.val) > tolerance;
-}
-
-bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2)
-{
- int i = 0;
- for (; theEntity1.param[i] != 0 && i < 4; i++)
- if (theEntity1.param[i] != theEntity2.param[i])
- return true;
- i = 0;
- for (; theEntity1.point[i] != 0 && i < 4; i++)
- if (theEntity1.point[i] != theEntity2.point[i])
- return true;
- return false;
-}
-
-bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2)
-{
- return theConstraint1.ptA != theConstraint2.ptA ||
- theConstraint1.ptB != theConstraint2.ptB ||
- theConstraint1.entityA != theConstraint2.entityA ||
- theConstraint1.entityB != theConstraint2.entityB ||
- theConstraint1.entityC != theConstraint2.entityC ||
- theConstraint1.entityD != theConstraint2.entityD ||
- fabs(theConstraint1.valA - theConstraint2.valA) > tolerance;
+ return true;
}
// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
// File: SketchSolver_Storage.h
-// Created: 18 Mar 2015
+// Created: 30 Nov 2015
// Author: Artem ZHIDKOV
#ifndef SketchSolver_Storage_H_
#define SketchSolver_Storage_H_
-#include "SketchSolver.h"
-#include <SketchSolver_Solver.h>
+#include <SketchSolver.h>
+#include <SketchSolver_IConstraintWrapper.h>
+#include <SketchSolver_IEntityWrapper.h>
+#include <SketchSolver_IParameterWrapper.h>
+#include <SketchSolver_ISolver.h>
-#include <list>
-#include <memory>
-#include <set>
-#include <vector>
+#include <ModelAPI_Attribute.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_Feature.h>
+#include <SketchPlugin_Constraint.h>
/** \class SketchSolver_Storage
* \ingroup Plugins
- * \brief Contains all necessary data in SolveSpace format to solve a single group of constraints
+ * \brief Interface to map SketchPlugin features to the entities of corresponding solver.
*/
class SketchSolver_Storage
{
-public:
+private:
SketchSolver_Storage();
+ SketchSolver_Storage(const SketchSolver_Storage&);
+ SketchSolver_Storage& operator=(const SketchSolver_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 Returns maximal ID of entities in this storage
- const Slvs_hEntity& entityMaxID() const
- { return myEntityMaxID; }
-
- /// \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<Slvs_Constraint> getConstraintsByType(int theConstraintType) const;
- /// \brief Returns quantity of constraints in this storage
- size_t nbConstraints() const
- { return myConstraints.size(); }
-
- /// \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(); }
+public:
+ SketchSolver_Storage(const GroupID& theGroup)
+ : myGroupID(theGroup),
+ myNeedToResolve(false)
+ {}
+
+ /// \brief Change mapping between constraint from SketchPlugin and
+ /// a constraint applicable for corresponding solver.
+ /// \param theConstraint [in] original SketchPlugin constraint
+ /// \param theSolverConstraint [in] solver's constraints
+ SKETCHSOLVER_EXPORT void addConstraint(ConstraintPtr theConstraint,
+ ConstraintWrapperPtr theSolverConstraints);
+ /// \brief Change mapping between constraint from SketchPlugin and
+ /// the list of constraints applicable for corresponding solver.
+ /// \param theConstraint [in] original SketchPlugin constraint
+ /// \param theSolverConstraints [in] list of solver's constraints
+ SKETCHSOLVER_EXPORT
+ void addConstraint(ConstraintPtr theConstraint,
+ std::list<ConstraintWrapperPtr> theSolverConstraints);
+
+ /// \brief Convert feature to the form applicable for specific solver and map it
+ /// \param theFeature [in] feature to convert
+ /// \param theGroup [in] id of the group where the feature should be placed
+ /// \return \c true if the feature has been created or updated
+ SKETCHSOLVER_EXPORT bool update(FeaturePtr theFeature, const GroupID& theGroup = GID_UNKNOWN);
+ /// \brief Convert attribute to the form applicable for specific solver and map it
+ /// \param theFeature [in] feature to convert
+ /// \return \c true if the attribute has been created or updated
+ SKETCHSOLVER_EXPORT bool update(AttributePtr theAttribute, const GroupID& theGroup = GID_UNKNOWN);
+
+ /// \brief Returns constraint related to corresponding constraint
+ SKETCHSOLVER_EXPORT
+ const std::list<ConstraintWrapperPtr>& constraint(const ConstraintPtr& theConstraint) const;
+
+ /// \brief Returns entity related to corresponding feature
+ SKETCHSOLVER_EXPORT const EntityWrapperPtr& entity(const FeaturePtr& theFeature) const;
+ /// \brief Returns entity related to corresponding attribute
+ SKETCHSOLVER_EXPORT const EntityWrapperPtr& entity(const AttributePtr& theAttribute) const;
+
+ /// \brief Return parsed sketch entity
+ const EntityWrapperPtr& sketch() const;
+ /// \brief Set parsed sketch entity.
+ /// Be careful, this method does not update fields of the storage specific for the solver.
+ /// Does not update if the sketch already exists.
+ void setSketch(const EntityWrapperPtr& theSketch);
+
+ /// \brief Mark two points as coincident
+ virtual void addCoincidentPoints(EntityWrapperPtr theMaster, EntityWrapperPtr theSlave) = 0;
+
+ /// \brief Shows the storage has any constraint twice
+ virtual bool hasDuplicatedConstraint() const = 0;
+
+ /// \brief Removes constraint from the storage
+ /// \return \c true if the constraint and all its parameters are removed successfully
+ virtual bool removeConstraint(ConstraintPtr theConstraint) = 0;
+ /// \brief Removes feature from the storage
+ /// \return \c true if the feature and its attributes are removed successfully;
+ /// \c false if the feature or any it attribute is used by remaining constraints.
+ virtual bool removeEntity(FeaturePtr theFeature) = 0;
+ /// \brief Removes attribute from the storage
+ /// \return \c true if the attribute is not used by remaining features and constraints
+ virtual bool removeEntity(AttributePtr theAttribute) = 0;
+
+ /// \brief Remove all features became invalid
+ SKETCHSOLVER_EXPORT void removeInvalidEntities();
+
+ /// \brief Mark specified constraint as temporary
+ virtual void setTemporary(ConstraintPtr theConstraint) = 0;
+ /// \brief Returns number of temporary constraints
+ virtual size_t nbTemporary() const = 0;
+ /// \brief Remove temporary constraints
+ /// \param theNbConstraints [in] number of temporary constraints to be deleted
+ /// \return number of remaining temporary constraints
+ virtual size_t removeTemporary(size_t theNbConstraints = 1) = 0;
+
+ /// \brief Check whether the feature or its attributes are used by this storage
+ /// \param theFeature [in] feature to be checked
+ /// \return \c true if the feature interacts with the storage
+ bool isInteract(const FeaturePtr& theFeature) const;
+ /// \brief Check whether the attribute is used by this storage
+ /// \param theAttribute [in] attribute to be checked
+ /// \return \c true if the attribute interacts with the storage
+ bool isInteract(const AttributePtr& theAttribute) const;
+
+ /// \brief Check the features is not removed
+ bool isConsistent() const;
/// \brief Shows the sketch should be resolved
- bool isNeedToResolve();
-
- /// \brief Shows the storage has the same constraint twice
- bool hasDuplicatedConstraint() const
- { return myDuplicatedConstraint; }
-
+ virtual bool isNeedToResolve()
+ { return myNeedToResolve; }
/// \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<Slvs_hParam>& theParameters,
- std::set<Slvs_hEntity>& theEntities,
- std::set<Slvs_hConstraint>& 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<Slvs_hConstraint> fixEntity(const Slvs_hEntity& theEntity);
+ /// \brief Initialize solver by constraints, entities and parameters
+ virtual void initializeSolver(SolverPtr theSolver) = 0;
+
+ /// \brief Update SketchPlugin features after resolving constraints
+ /// \param theFixedOnly [in] if \c true the fixed points will be updated only
+ virtual void refresh(bool theFixedOnly = false) const = 0;
+
+ /// \brief Check if some parameters or entities are returned
+ /// to the current group after removing temporary constraints
+ virtual void verifyFixed() = 0;
+
+ /// \brief Calculate point on theBase entity. Value theCoeff is in [0.0 .. 1.0] and
+ /// shows the distance from the start point.
+ virtual EntityWrapperPtr calculateMiddlePoint(EntityWrapperPtr theBase,
+ double theCoeff) = 0;
+
+protected:
+ /// \brief Change mapping feature from SketchPlugin and
+ /// the entity applicable for corresponding solver.
+ /// \param theFeature [in] original SketchPlugin feature
+ /// \param theSolverEntity [in] solver's entity, created outside
+ SKETCHSOLVER_EXPORT
+ void addEntity(FeaturePtr theFeature,
+ EntityWrapperPtr theSolverEntity);
+
+ /// \brief Change mapping attribute of a feature and the entity applicable for corresponding solver.
+ /// \param theAttribute [in] original attribute
+ /// \param theSolverEntity [in] solver's entity, created outside
+ SKETCHSOLVER_EXPORT
+ void addEntity(AttributePtr theAttribute,
+ EntityWrapperPtr theSolverEntity);
+
+ /// \brief Update constraint's data
+ /// \return \c true if any value is updated
+ virtual bool update(ConstraintWrapperPtr& theConstraint) = 0;
+ /// \brief Update entity's data
+ /// \return \c true if any value is updated
+ virtual bool update(EntityWrapperPtr& theEntity) = 0;
+ /// \brief Update parameter's data
+ /// \return \c true if the value of parameter is updated
+ virtual bool update(ParameterWrapperPtr& theParameter) = 0;
+
+ /// \brief Remove constraint
+ /// \return \c true if the constraint and all its parameters are removed successfully
+ virtual bool remove(ConstraintWrapperPtr theConstraint) = 0;
+ /// \brief Remove entity
+ /// \return \c true if the entity and all its parameters are removed successfully
+ virtual bool remove(EntityWrapperPtr theEntity) = 0;
+ /// \brief Remove parameter
+ /// \return \c true if the parameter has been removed
+ virtual bool remove(ParameterWrapperPtr theParameter) = 0;
+
+ /// \brief Update the group for the given entity, its sub-entities and parameters
+ virtual void changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup) = 0;
+ /// \brief Update the group for the given parameter
+ virtual void changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup) = 0;
+
+ /// \brief Block or unblock events when refreshing features
+ SKETCHSOLVER_EXPORT void blockEvents(bool isBlocked) const;
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<Slvs_hConstraint>& 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<Slvs_hConstraint>& 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<Slvs_hConstraint>& 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<Slvs_hConstraint>& theCreated);
+ /// \brief Find the normal of the sketch
+ EntityWrapperPtr getNormal() const;
-private:
- Slvs_hParam myParamMaxID; ///< current parameter index (may differs with the number of parameters)
- std::vector<Slvs_Param> 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<Slvs_Entity> 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<Slvs_Constraint> myConstraints; ///< list of constraints used in the current group (sorted by the identifier)
+protected:
+ GroupID myGroupID; ///< identifier of the group, this storage belongs to
- std::vector< std::set<Slvs_hEntity> > myCoincidentPoints; ///< lists of coincident points
- Slvs_hConstraint myFixed; ///< identifier of one of temporary constraints to fix separate point
+ /// map SketchPlugin constraint to a list of solver's constraints
+ std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> > myConstraintMap;
+ /// map SketchPlugin feature to solver's entity
+ std::map<FeaturePtr, EntityWrapperPtr> myFeatureMap;
+ /// map attribute to solver's entity
+ std::map<AttributePtr, EntityWrapperPtr> myAttributeMap;
bool myNeedToResolve; ///< parameters are changed and group needs to be resolved
- bool myDuplicatedConstraint; ///< shows the storage has same constraint twice
-
- std::set<Slvs_hConstraint> myTemporaryConstraints; ///< list of transient constraints
- std::set<Slvs_hParam> myRemovedParameters; ///< list of just removed parameters (cleared when returning to applicant)
- std::set<Slvs_hEntity> myRemovedEntities; ///< list of just removed entities (cleared when returning to applicant)
- std::set<Slvs_hConstraint> myRemovedConstraints; ///< list of just removed constraints (cleared when returning to applicant)
- std::set<Slvs_hParam> myUpdatedParameters; ///< list of just updated parameters (cleared when isNeedToResolve() called)
};
typedef std::shared_ptr<SketchSolver_Storage> StoragePtr;
--- /dev/null
+## Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+FIND_PACKAGE(SolveSpace REQUIRED)
+
+SET(PROJECT_HEADERS
+ SolveSpaceSolver_Solver.h
+ SolveSpaceSolver_Builder.h
+ SolveSpaceSolver_Storage.h
+ SolveSpaceSolver_EntityWrapper.h
+ SolveSpaceSolver_ParameterWrapper.h
+ SolveSpaceSolver_ConstraintWrapper.h
+ SolveSpaceSolver_ConstraintType.h
+)
+
+SET(PROJECT_SOURCES
+ SolveSpaceSolver_Solver.cpp
+ SolveSpaceSolver_Builder.cpp
+ SolveSpaceSolver_Storage.cpp
+ SolveSpaceSolver_EntityWrapper.cpp
+ SolveSpaceSolver_ParameterWrapper.cpp
+ SolveSpaceSolver_ConstraintWrapper.cpp
+)
+
+SET(PROJECT_LIBRARIES
+ ${SOLVESPACE_LIBRARIES}
+ SketchSolver
+ ModelAPI
+ GeomAPI
+)
+
+INCLUDE_DIRECTORIES(
+ ${SOLVESPACE_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(SolveSpaceSolver MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS})
+TARGET_LINK_LIBRARIES(SolveSpaceSolver ${PROJECT_LIBRARIES})
+INSTALL(TARGETS SolveSpaceSolver DESTINATION plugins)
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SolveSpaceSolver_Builder.cpp
+// Created: 25 Mar 2015
+// Author: Artem ZHIDKOV
+
+#include <SolveSpaceSolver_Builder.h>
+#include <SolveSpaceSolver_Solver.h>
+#include <SolveSpaceSolver_Storage.h>
+#include <SolveSpaceSolver_ParameterWrapper.h>
+#include <SolveSpaceSolver_EntityWrapper.h>
+#include <SolveSpaceSolver_ConstraintWrapper.h>
+#include <SolveSpaceSolver_ConstraintType.h>
+
+#include <SketchSolver_Manager.h>
+
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+#include <GeomDataAPI_Dir.h>
+#include <GeomDataAPI_Point.h>
+#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_Attribute.h>
+#include <ModelAPI_AttributeRefAttr.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_Circle.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+
+#include <math.h>
+
+
+static EntityWrapperPtr createLine(FeaturePtr theFeature,
+ const std::list<EntityWrapperPtr>& theAttributes,
+ const GroupID& theGroupID,
+ const EntityID& theSketchID);
+static EntityWrapperPtr createCircle(FeaturePtr theFeature,
+ const std::list<EntityWrapperPtr>& theAttributes,
+ const GroupID& theGroupID,
+ const EntityID& theSketchID);
+static EntityWrapperPtr createArc(FeaturePtr theFeature,
+ const std::list<EntityWrapperPtr>& theAttributes,
+ const GroupID& theGroupID,
+ const EntityID& theSketchID);
+
+/// \brief Set flags of constraint to identify which points are coincident in the Tangency
+/// (for more information, see SolveSpace documentation)
+static void adjustTangency(ConstraintWrapperPtr theConstraint);
+/// \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 SolveSpaceSolver_Builder::mySelf = SolveSpaceSolver_Builder::getInstance();
+
+BuilderPtr SolveSpaceSolver_Builder::getInstance()
+{
+ if (!mySelf) {
+ mySelf = BuilderPtr(new SolveSpaceSolver_Builder);
+ SketchSolver_Manager::instance()->setBuilder(mySelf);
+ }
+ return mySelf;
+}
+
+StoragePtr SolveSpaceSolver_Builder::createStorage(const GroupID& theGroup) const
+{
+ return StoragePtr(new SolveSpaceSolver_Storage(theGroup));
+}
+
+SolverPtr SolveSpaceSolver_Builder::createSolver() const
+{
+ return SolverPtr(new SolveSpaceSolver_Solver);
+}
+
+
+std::list<ConstraintWrapperPtr> SolveSpaceSolver_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
+{
+ if (theType == CONSTRAINT_SYMMETRIC)
+ return createMirror(theConstraint, theGroupID, theSketchID,
+ thePoint1, thePoint2, theEntity1);
+
+ int aType = ConstraintType::toSolveSpace(theType);
+ if (aType == SLVS_C_UNKNOWN)
+ return std::list<ConstraintWrapperPtr>();
+
+ Slvs_hEntity aSlvsEntities[4] = {SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN};
+ EntityWrapperPtr anOriginal[4] = {thePoint1, thePoint2, theEntity1, theEntity2};
+ std::list<EntityWrapperPtr> aConstrAttrList; // to be filled
+ for (int i = 0; i < 4; ++i) {
+ if (!anOriginal[i])
+ continue;
+ aSlvsEntities[i] = (Slvs_hEntity)anOriginal[i]->id();
+ if (aSlvsEntities[i] == SLVS_E_UNKNOWN)
+ return std::list<ConstraintWrapperPtr>(); // entity is not added into a storage, constraint can not be created
+ aConstrAttrList.push_back(anOriginal[i]);
+ }
+
+ Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+ SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
+ theValue, aSlvsEntities[0], aSlvsEntities[1], aSlvsEntities[2], aSlvsEntities[3]);
+ ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
+ aResult->setValue(theValue);
+ aResult->setEntities(aConstrAttrList);
+ adjustConstraint(aResult);
+
+ return std::list<ConstraintWrapperPtr>(1, aResult);
+}
+
+std::list<ConstraintWrapperPtr> SolveSpaceSolver_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<EntityWrapperPtr>& theTrsfEnt) const
+{
+ if (theType != CONSTRAINT_MULTI_ROTATION && theType != CONSTRAINT_MULTI_TRANSLATION)
+ return std::list<ConstraintWrapperPtr>();
+
+ int aType = ConstraintType::toSolveSpace(theType);
+ if (aType == SLVS_C_UNKNOWN)
+ return std::list<ConstraintWrapperPtr>();
+
+ Slvs_Constraint aConstraint =
+ Slvs_MakeConstraint(SLVS_C_UNKNOWN, (Slvs_hGroup)theGroupID, aType, (Slvs_hEntity)theSketchID,
+ theValue, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+
+ std::list<EntityWrapperPtr> aConstrAttrList = theTrsfEnt;
+ if (thePoint2)
+ aConstrAttrList.push_front(thePoint2);
+ aConstrAttrList.push_front(thePoint1);
+
+ ConstraintWrapperPtr aResult(new SolveSpaceSolver_ConstraintWrapper(theConstraint, aConstraint));
+ aResult->setValue(theValue);
+ aResult->setEntities(aConstrAttrList);
+ return std::list<ConstraintWrapperPtr>(1, aResult);
+}
+
+
+std::list<ConstraintWrapperPtr> SolveSpaceSolver_Builder::createMirror(
+ ConstraintPtr theConstraint,
+ const GroupID& theGroupID,
+ const EntityID& theSketchID,
+ const EntityWrapperPtr& theEntity1,
+ const EntityWrapperPtr& theEntity2,
+ const EntityWrapperPtr& theMirrorLine) const
+{
+ Slvs_Constraint aConstraint;
+ std::list<ConstraintWrapperPtr> aResult;
+ std::list<EntityWrapperPtr> aConstrAttrList;
+ if (theEntity1->type() == ENTITY_POINT) {
+ if (theEntity2->group() == theGroupID) // theEntity2 is not fixed
+ makeMirrorPoints(theEntity1, theEntity2, theMirrorLine);
+
+ aConstraint = Slvs_MakeConstraint(
+ SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID, SLVS_C_SYMMETRIC_LINE, (Slvs_hEntity)theSketchID,
+ 0.0, (Slvs_hEntity)theEntity1->id(), (Slvs_hEntity)theEntity2->id(),
+ (Slvs_hEntity)theMirrorLine->id(), SLVS_E_UNKNOWN);
+
+ aConstrAttrList.push_back(theEntity1);
+ aConstrAttrList.push_back(theEntity2);
+ aConstrAttrList.push_back(theMirrorLine);
+
+ ConstraintWrapperPtr aWrapper(new SolveSpaceSolver_ConstraintWrapper(
+ theConstraint, aConstraint));
+ aWrapper->setEntities(aConstrAttrList);
+ aResult.push_back(aWrapper);
+ }
+ else if (theEntity1->type() == ENTITY_LINE) {
+ const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
+ const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
+ std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
+ std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
+ for (; anIt1 != aPoints1.end() && anIt2 != aPoints2.end(); ++anIt1, ++anIt2) {
+ std::list<ConstraintWrapperPtr> 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<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
+ std::list<EntityWrapperPtr>::const_iterator anIt1 = aPoints1.begin();
+ for (; anIt1 != aPoints1.end(); ++anIt1)
+ if ((*anIt1)->type() == ENTITY_POINT)
+ break;
+ const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
+ std::list<EntityWrapperPtr>::const_iterator anIt2 = aPoints2.begin();
+ for (; anIt2 != aPoints2.end(); ++anIt2)
+ if ((*anIt2)->type() == ENTITY_POINT)
+ break;
+
+ std::list<ConstraintWrapperPtr> 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);
+
+ std::list<ConstraintWrapperPtr> aMrrList;
+ std::list<EntityWrapperPtr>::const_iterator anIt1 = theEntity1->subEntities().begin();
+ std::list<EntityWrapperPtr>::const_iterator anIt2 = theEntity2->subEntities().begin();
+ if ((*anIt2)->group() == theGroupID) // mirrored point is not fixed
+ makeMirrorPoints(theEntity1->subEntities().front(),
+ theEntity2->subEntities().front(), theMirrorLine);
+
+ // Workaround to avoid problems in SolveSpace.
+ // The symmetry of two arcs will be done using symmetry of three points on these arcs:
+ // start point, end point, and any other point on the arc
+ std::list<EntityWrapperPtr> aBaseArcPoints(++anIt1, theEntity1->subEntities().end());
+ std::list<EntityWrapperPtr> aMirrorArcPoints(++anIt2, theEntity2->subEntities().end());
+ // indices of points of arc, center corresponds center, first point corresponds last point
+ aMirrorArcPoints.reverse();
+
+ anIt1 = aBaseArcPoints.begin();
+ anIt2 = aMirrorArcPoints.begin();
+ for (; anIt1 != aBaseArcPoints.end(); ++anIt1, ++anIt2) {
+ aMrrList = createMirror(theConstraint, theGroupID, theSketchID, *anIt1, *anIt2, theMirrorLine);
+ aResult.insert(aResult.end(), aMrrList.begin(), aMrrList.end());
+ }
+ // Restore event sending
+ aMirrArc->data()->blockSendAttributeUpdated(false);
+ }
+ return aResult;
+}
+
+void SolveSpaceSolver_Builder::adjustConstraint(ConstraintWrapperPtr theConstraint) const
+{
+ SketchSolver_ConstraintType aType = theConstraint->type();
+ // Update flags in constraints
+ if (aType == CONSTRAINT_TANGENT_ARC_ARC || aType == CONSTRAINT_TANGENT_ARC_LINE)
+ adjustTangency(theConstraint);
+ else 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 SolveSpaceSolver_Builder::createFeature(
+ FeaturePtr theFeature,
+ const std::list<EntityWrapperPtr>& theAttributes,
+ const GroupID& theGroupID,
+ const EntityID& theSketchID) const
+{
+ static EntityWrapperPtr aDummy;
+ if (!theFeature->data()->isValid())
+ return aDummy;
+
+ // Sketch
+ CompositeFeaturePtr aSketch = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
+ if (aSketch)
+ return createSketchEntity(aSketch, theGroupID);
+
+ // SketchPlugin features
+ std::shared_ptr<SketchPlugin_Feature> aFeature =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(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, theSketchID);
+ // Circle
+ else if (aFeatureKind == SketchPlugin_Circle::ID())
+ return createCircle(theFeature, theAttributes,theGroupID, theSketchID);
+ // Arc
+ else if (aFeatureKind == SketchPlugin_Arc::ID())
+ return createArc(theFeature, theAttributes,theGroupID, theSketchID);
+ // 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, theSketchID);
+ if (!aSub)
+ return aDummy;
+
+ const Slvs_Entity& aSubEnt =
+ std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(aSub)->entity();
+ EntityWrapperPtr aNewEntity(new SolveSpaceSolver_EntityWrapper(theFeature, aSubEnt));
+ aNewEntity->setSubEntities(std::list<EntityWrapperPtr>(1, aSub));
+ return aNewEntity;
+ }
+
+ // wrong entity
+ return aDummy;
+}
+
+EntityWrapperPtr SolveSpaceSolver_Builder::createAttribute(
+ AttributePtr theAttribute,
+ const GroupID& theGroupID,
+ const EntityID& theSketchID) const
+{
+ AttributePtr anAttribute = theAttribute;
+ AttributeRefAttrPtr aRefAttr =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
+ if (aRefAttr) {
+ if (aRefAttr->isObject()) {
+ // do not create features here
+ return EntityWrapperPtr();
+ } else
+ anAttribute = aRefAttr->attr();
+ }
+
+ std::list<ParameterWrapperPtr> aParameters;
+ Slvs_Entity anEntity;
+ anEntity.type = 0;
+
+ // Point in 3D
+ std::shared_ptr<GeomDataAPI_Point> aPoint =
+ std::dynamic_pointer_cast<GeomDataAPI_Point>(theAttribute);
+ if (aPoint) {
+ aParameters.push_back(createParameter(theGroupID, aPoint->x(), !aPoint->textX().empty()));
+ aParameters.push_back(createParameter(theGroupID, aPoint->y(), !aPoint->textY().empty()));
+ aParameters.push_back(createParameter(theGroupID, aPoint->z(), !aPoint->textZ().empty()));
+ // Create entity (parameters are not filled)
+ anEntity = Slvs_MakePoint3d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
+ SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+ } else {
+ // Point in 2D
+ std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
+ if (aPoint2D) {
+ aParameters.push_back(createParameter(theGroupID, aPoint2D->x(), !aPoint2D->textX().empty()));
+ aParameters.push_back(createParameter(theGroupID, aPoint2D->y(), !aPoint2D->textY().empty()));
+ // Create entity (parameters are not filled)
+ anEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
+ (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+ } else {
+ // Scalar value (used for the distance entities)
+ AttributeDoublePtr aScalar =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
+ if (aScalar) {
+ aParameters.push_back(createParameter(theGroupID, aScalar->value(), !aScalar->text().empty()));
+ // Create entity (parameter is not filled)
+ anEntity = Slvs_MakeDistance(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
+ (Slvs_hEntity)theSketchID, SLVS_E_UNKNOWN);
+ }
+ }
+ }
+
+ if (anEntity.type == 0) {
+ // unknown attribute type
+ return EntityWrapperPtr();
+ }
+
+ EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(theAttribute, anEntity));
+ aResult->setParameters(aParameters);
+ return aResult;
+}
+
+
+
+EntityWrapperPtr SolveSpaceSolver_Builder::createSketchEntity(
+ CompositeFeaturePtr theSketch,
+ const GroupID& theGroupID) const
+{
+ DataPtr aSketchData = theSketch->data();
+ if (!aSketchData || !aSketchData->isValid())
+ return EntityWrapperPtr(); // the sketch is incorrect
+
+ // Get parameters of workplane
+ AttributePtr aDirX = aSketchData->attribute(SketchPlugin_Sketch::DIRX_ID());
+ AttributePtr aNorm = aSketchData->attribute(SketchPlugin_Sketch::NORM_ID());
+ AttributePtr anOrigin = aSketchData->attribute(SketchPlugin_Sketch::ORIGIN_ID());
+ if (!anOrigin->isInitialized() || !aNorm->isInitialized() || !aDirX->isInitialized())
+ return EntityWrapperPtr();
+
+ EntityWrapperPtr aNewEnt;
+ std::list<EntityWrapperPtr> aSubs;
+
+ // Create SolveSpace entity corresponding to the sketch origin
+ aNewEnt = createAttribute(anOrigin, theGroupID);
+ if (!aNewEnt)
+ return EntityWrapperPtr();
+ aSubs.push_back(aNewEnt);
+
+ // Create SolveSpace entity corresponding the the sketch normal
+ aNewEnt = createNormal(aNorm, aDirX, theGroupID);
+ if (!aNewEnt)
+ return EntityWrapperPtr();
+ aSubs.push_back(aNewEnt);
+
+ // Create workplane
+ Slvs_Entity aWorkplane = Slvs_MakeWorkplane(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
+ SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+
+ aNewEnt = EntityWrapperPtr(
+ new SolveSpaceSolver_EntityWrapper(FeaturePtr(theSketch), aWorkplane));
+ aNewEnt->setSubEntities(aSubs);
+ return aNewEnt;
+}
+
+EntityWrapperPtr SolveSpaceSolver_Builder::createNormal(
+ AttributePtr theNormal,
+ AttributePtr theDirX,
+ const GroupID& theGroupID) const
+{
+ std::shared_ptr<GeomDataAPI_Dir> aNorm = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormal);
+ std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
+ if (!aDirX || !aNorm ||
+ (fabs(aDirX->x()) + fabs(aDirX->y()) + fabs(aDirX->z()) < tolerance) ||
+ !aNorm->isInitialized())
+ return EntityWrapperPtr();
+ // calculate Y direction
+ std::shared_ptr<GeomAPI_Dir> 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<ParameterWrapperPtr> 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;
+}
+
+ParameterWrapperPtr SolveSpaceSolver_Builder::createParameter(
+ const GroupID& theGroup, const double theValue, const bool theExpr) const
+{
+ Slvs_Param aParam = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroup, theValue);
+ ParameterWrapperPtr aWrapper(new SolveSpaceSolver_ParameterWrapper(aParam));
+ aWrapper->setIsParametric(theExpr);
+ return aWrapper;
+}
+
+
+
+
+
+// ================ Auxiliary functions ==========================
+EntityWrapperPtr createLine(FeaturePtr theFeature,
+ const std::list<EntityWrapperPtr>& theAttributes,
+ const GroupID& theGroupID,
+ const EntityID& theSketchID)
+{
+ EntityWrapperPtr aNewEntity;
+ std::list<EntityWrapperPtr> aSubs;
+
+ AttributePtr aStart = theFeature->attribute(SketchPlugin_Line::START_ID());
+ AttributePtr aEnd = theFeature->attribute(SketchPlugin_Line::END_ID());
+ if (!aStart->isInitialized() || !aEnd->isInitialized())
+ return aNewEntity;
+
+ EntityWrapperPtr aStartEnt, aEndEnt;
+ std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
+ for (; anIt != theAttributes.end(); ++anIt) {
+ std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
+ std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
+ if (aSlvsEntity->isBase(aStart))
+ aStartEnt = aSlvsEntity;
+ else if (aSlvsEntity->isBase(aEnd))
+ aEndEnt = aSlvsEntity;
+ }
+ if (!aStartEnt || !aEndEnt)
+ return aNewEntity;
+
+ aSubs.push_back(aStartEnt);
+ aSubs.push_back(aEndEnt);
+ Slvs_Entity anEntity = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
+ (Slvs_hEntity)theSketchID, (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
+
+ aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
+ aNewEntity->setSubEntities(aSubs);
+ return aNewEntity;
+}
+
+EntityWrapperPtr createCircle(FeaturePtr theFeature,
+ const std::list<EntityWrapperPtr>& theAttributes,
+ const GroupID& theGroupID,
+ const EntityID& theSketchID)
+{
+ EntityWrapperPtr aNewEntity;
+ std::list<EntityWrapperPtr> aSubs;
+
+ AttributePtr aCenter = theFeature->attribute(SketchPlugin_Circle::CENTER_ID());
+ AttributePtr aRadius = theFeature->attribute(SketchPlugin_Circle::RADIUS_ID());
+ if (!aCenter->isInitialized() || !aRadius->isInitialized())
+ return aNewEntity;
+
+ EntityWrapperPtr aCenterEnt, aRadiusEnt, aNormalEnt;
+ std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
+ for (; anIt != theAttributes.end(); ++anIt) {
+ std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
+ std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
+ if (aSlvsEntity->isBase(aCenter))
+ aCenterEnt = aSlvsEntity;
+ else if (aSlvsEntity->isBase(aRadius))
+ aRadiusEnt = aSlvsEntity;
+ else if (aSlvsEntity->type() == ENTITY_NORMAL)
+ aNormalEnt = aSlvsEntity;
+ }
+ if (!aCenterEnt || !aRadiusEnt || !aNormalEnt)
+ return aNewEntity;
+
+ aSubs.push_back(aCenterEnt);
+ aSubs.push_back(aRadiusEnt);
+ Slvs_Entity anEntity = Slvs_MakeCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
+ (Slvs_hEntity)theSketchID, (Slvs_hEntity)aCenterEnt->id(),
+ (Slvs_hEntity)aNormalEnt->id(), (Slvs_hEntity)aRadiusEnt->id());
+
+ aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
+ aNewEntity->setSubEntities(aSubs);
+ return aNewEntity;
+}
+
+EntityWrapperPtr createArc(FeaturePtr theFeature,
+ const std::list<EntityWrapperPtr>& theAttributes,
+ const GroupID& theGroupID,
+ const EntityID& theSketchID)
+{
+ EntityWrapperPtr aNewEntity;
+ std::list<EntityWrapperPtr> 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;
+
+ EntityWrapperPtr aCenterEnt, aStartEnt, aEndEnt, aNormalEnt;
+ std::list<EntityWrapperPtr>::const_iterator anIt = theAttributes.begin();
+ for (; anIt != theAttributes.end(); ++anIt) {
+ std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSlvsEntity =
+ std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
+ if (aSlvsEntity->isBase(aCenter))
+ aCenterEnt = aSlvsEntity;
+ else if (aSlvsEntity->isBase(aStart))
+ aStartEnt = aSlvsEntity;
+ else if (aSlvsEntity->isBase(aEnd))
+ aEndEnt = aSlvsEntity;
+ else if (aSlvsEntity->type() == ENTITY_NORMAL)
+ aNormalEnt = aSlvsEntity;
+ }
+ if (!aCenterEnt || !aStartEnt || !aEndEnt || !aNormalEnt)
+ return aNewEntity;
+
+ aSubs.push_back(aCenterEnt);
+ aSubs.push_back(aStartEnt);
+ aSubs.push_back(aEndEnt);
+ Slvs_Entity anEntity = Slvs_MakeArcOfCircle(SLVS_E_UNKNOWN, (Slvs_hGroup)theGroupID,
+ (Slvs_hEntity)theSketchID, (Slvs_hEntity)aNormalEnt->id(),
+ (Slvs_hEntity)aCenterEnt->id(), (Slvs_hEntity)aStartEnt->id(), (Slvs_hEntity)aEndEnt->id());
+
+ aNewEntity = EntityWrapperPtr(new SolveSpaceSolver_EntityWrapper(theFeature, anEntity));
+ aNewEntity->setSubEntities(aSubs);
+ return aNewEntity;
+}
+
+
+void adjustTangency(ConstraintWrapperPtr theConstraint)
+{
+ BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
+
+ std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
+ std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
+
+ // Collect start, end points of entities
+ std::shared_ptr<GeomAPI_Pnt2d> aStartEntPoints[2][2];
+ bool isCoinc[2][2] = {false};
+ const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
+ std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
+ for (int i = 0; aSIt != aSubs.end(); ++aSIt, ++i) {
+ const std::list<EntityWrapperPtr>& aPoints = (*aSIt)->subEntities();
+ std::list<EntityWrapperPtr>::const_iterator aPIt = aPoints.begin();
+ if ((*aSIt)->type() == ENTITY_ARC)
+ ++aPIt;
+ for (int j = 0; aPIt != aPoints.end(); ++aPIt, ++j) {
+ aStartEntPoints[i][j] = aBuilder->point(*aPIt);
+ if (i > 0) { // check coincidence
+ for (int k = 0; k < 2; ++k)
+ if (aStartEntPoints[i][j]->distance(aStartEntPoints[0][k]) < tolerance)
+ isCoinc[0][k] = isCoinc[i][j] = true;
+ }
+ }
+ }
+
+ Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
+ if (isCoinc[0][0] == false && isCoinc[0][1] == true)
+ aSlvsConstraint.other = 1;
+ else aSlvsConstraint.other = 0;
+ if (isCoinc[1][0] == false && isCoinc[1][1] == true)
+ aSlvsConstraint.other2 = 1;
+ else aSlvsConstraint.other2 = 0;
+}
+
+void adjustAngle(ConstraintWrapperPtr theConstraint)
+{
+ BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
+
+ std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
+ std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
+
+ std::shared_ptr<GeomAPI_Pnt2d> aPoints[2][2]; // start and end points of lines
+ const std::list<EntityWrapperPtr>& aConstrLines = aConstraint->entities();
+ std::list<EntityWrapperPtr>::const_iterator aCLIt = aConstrLines.begin();
+ for (int i = 0; aCLIt != aConstrLines.end(); ++i, ++aCLIt) {
+ const std::list<EntityWrapperPtr>& aLinePoints = (*aCLIt)->subEntities();
+ std::list<EntityWrapperPtr>::const_iterator aLPIt = aLinePoints.begin();
+ for (int j = 0; aLPIt != aLinePoints.end(); ++j, ++aLPIt)
+ aPoints[i][j] = aBuilder->point(*aLPIt);
+ }
+
+ std::shared_ptr<GeomAPI_Lin2d> aLine[2] = {
+ std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[0][0], aPoints[0][1])),
+ std::shared_ptr<GeomAPI_Lin2d>(new GeomAPI_Lin2d(aPoints[1][0], aPoints[1][1]))
+ };
+ std::shared_ptr<GeomAPI_Pnt2d> 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<GeomAPI_Dir2d> aDir[2];
+ for (int i = 0; i < 2; i++) {
+ if (aDist[i][1] > fabs(aDist[i][0]))
+ aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(
+ aPoints[i][1]->xy()->decreased(anIntersection->xy())));
+ else {
+ aDir[i] = std::shared_ptr<GeomAPI_Dir2d>(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;
+ }
+ }
+ }
+
+ Slvs_Constraint& aSlvsConstraint = aConstraint->changeConstraint();
+ aSlvsConstraint.other = false;
+ for (int i = 0; i < 2; i++)
+ if (aLine[i]->direction()->dot(aDir[i]) < 0.0)
+ aSlvsConstraint.other = !aSlvsConstraint.other;
+}
+
+void adjustMirror(ConstraintWrapperPtr theConstraint)
+{
+ std::vector<EntityWrapperPtr> aPoints;
+ EntityWrapperPtr aMirrorLine;
+
+ const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
+ std::list<EntityWrapperPtr>::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 = SolveSpaceSolver_Builder::getInstance();
+
+ std::shared_ptr<GeomAPI_Lin2d> aMirrorLine = aBuilder->line(theMirrorLine);
+ std::shared_ptr<GeomAPI_Dir2d> aMLDir = aMirrorLine->direction();
+ // orthogonal direction
+ aMLDir = std::shared_ptr<GeomAPI_Dir2d>(new GeomAPI_Dir2d(aMLDir->y(), -aMLDir->x()));
+
+ std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(theOriginal);
+ std::shared_ptr<GeomAPI_XY> 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<ParameterWrapperPtr>::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<SolveSpaceSolver_EntityWrapper>(theMirrored)->baseAttribute();
+ if (anAttr) {
+ std::shared_ptr<GeomDataAPI_Point2D> aMirroredPnt = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
+ aMirroredPnt->setValue(aCoord[0], aCoord[1]);
+ }
+}
+
+static void rotate(EntityWrapperPtr theSource, EntityWrapperPtr theDest,
+ std::shared_ptr<GeomAPI_Pnt2d> theCenter,
+ double theSin, double theCos)
+{
+ std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSource =
+ std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theSource);
+ std::shared_ptr<SolveSpaceSolver_EntityWrapper> aDest =
+ std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theDest);
+
+ if (theSource->type() == ENTITY_POINT) {
+ // Rotate single point
+ std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSource->baseAttribute());
+ std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aDest->baseAttribute());
+ if (aSrcAttr && aDstAttr) {
+ std::shared_ptr<GeomAPI_XY> 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 = aDest->baseFeature();
+ if (aDestFeature)
+ aDestFeature->data()->blockSendAttributeUpdated(true);
+
+ // Rotate points of the feature
+ const std::list<EntityWrapperPtr>& aSrcSubs = theSource->subEntities();
+ const std::list<EntityWrapperPtr>& aDstSubs = theDest->subEntities();
+ std::list<EntityWrapperPtr>::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<GeomAPI_XY> theDelta)
+{
+ std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSource =
+ std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theSource);
+ std::shared_ptr<SolveSpaceSolver_EntityWrapper> aDest =
+ std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theDest);
+
+ if (theSource->type() == ENTITY_POINT) {
+ // Translate single point
+ std::shared_ptr<GeomDataAPI_Point2D> aSrcAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aSource->baseAttribute());
+ std::shared_ptr<GeomDataAPI_Point2D> aDstAttr =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aDest->baseAttribute());
+ if (aSrcAttr && aDstAttr)
+ aDstAttr->setValue(aSrcAttr->x() + theDelta->x(), aSrcAttr->y() + theDelta->y());
+ return;
+ }
+
+ FeaturePtr aDestFeature = aDest->baseFeature();
+ if (aDestFeature)
+ aDestFeature->data()->blockSendAttributeUpdated(true);
+
+ // Translate points of the feature
+ const std::list<EntityWrapperPtr>& aSrcSubs = theSource->subEntities();
+ const std::list<EntityWrapperPtr>& aDstSubs = theDest->subEntities();
+ std::list<EntityWrapperPtr>::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 = SolveSpaceSolver_Builder::getInstance();
+
+ double anAngleRad = theConstraint->value() * PI / 180.0;
+ double aSin = sin(anAngleRad);
+ double aCos = cos(anAngleRad);
+
+ const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
+ std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
+
+ std::shared_ptr<GeomAPI_Pnt2d> aCenter = aBuilder->point(*aSIt++);
+ std::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
+ for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
+ rotate(*aPrevIt, *aSIt, aCenter, aSin, aCos);
+}
+
+void adjustMultiTranslation(ConstraintWrapperPtr theConstraint)
+{
+ BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
+
+ const std::list<EntityWrapperPtr>& aSubs = theConstraint->entities();
+ std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
+
+ std::shared_ptr<GeomAPI_Pnt2d> aStartPnt = aBuilder->point(*aSIt++);
+ std::shared_ptr<GeomAPI_Pnt2d> aEndPnt = aBuilder->point(*aSIt++);
+ std::shared_ptr<GeomAPI_XY> aDelta = aEndPnt->xy()->decreased(aStartPnt->xy());
+
+ std::list<EntityWrapperPtr>::const_iterator aPrevIt = aSIt++;
+ for (; aSIt != aSubs.end(); ++aPrevIt, ++aSIt)
+ translate(*aPrevIt, *aSIt, aDelta);
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SolveSpaceSolver_Builder.h
+// Created: 25 Mar 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SolveSpaceSolver_Builder_H_
+#define SolveSpaceSolver_Builder_H_
+
+#include <SketchSolver_Builder.h>
+#include <SketchSolver_Constraint.h>
+
+#include <SketchPlugin_Constraint.h>
+
+#include <ModelAPI_CompositeFeature.h>
+
+/** \class SolveSpaceSolver_Builder
+ * \ingroup Plugins
+ * \brief Create bridges between SketchPlugin constraints and SolveSpace constraints
+ */
+class SolveSpaceSolver_Builder : public SketchSolver_Builder
+{
+private:
+ /// Default constructor
+ SolveSpaceSolver_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<ConstraintWrapperPtr>
+ 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<ConstraintWrapperPtr>
+ 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<EntityWrapperPtr>& 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<EntityWrapperPtr>& 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;
+
+private:
+ /// \brief Create necessary constraints to make two object symmetric relatively a given line
+ std::list<ConstraintWrapperPtr> 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;
+
+ /// \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
+ ParameterWrapperPtr createParameter(const GroupID& theGroup,
+ const double theValue = 0.0,
+ const bool theExpr = false) const;
+
+private:
+ static BuilderPtr mySelf;
+};
+
+#endif
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SolveSpaceSolver_ConstraintType.h
+// Created: 8 Dec 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SolveSpaceSolver_ConstraintType_H_
+#define SolveSpaceSolver_ConstraintType_H_
+
+#include <SketchSolver_IConstraintWrapper.h>
+#include <SolveSpaceSolver_Solver.h>
+
+namespace ConstraintType
+{
+ /// \brief Convert constraint type from SketchSolver to SolveSpace
+ static int toSolveSpace(SketchSolver_ConstraintType theType)
+ {
+ switch (theType) {
+ case CONSTRAINT_PT_PT_COINCIDENT: return SLVS_C_POINTS_COINCIDENT;
+ case CONSTRAINT_PT_ON_LINE: return SLVS_C_PT_ON_LINE;
+ case CONSTRAINT_PT_ON_CIRCLE: return SLVS_C_PT_ON_CIRCLE;
+ case CONSTRAINT_PT_PT_DISTANCE: return SLVS_C_PT_PT_DISTANCE;
+ case CONSTRAINT_PT_LINE_DISTANCE: return SLVS_C_PT_LINE_DISTANCE;
+ case CONSTRAINT_ANGLE: return SLVS_C_ANGLE;
+ case CONSTRAINT_RADIUS: return SLVS_C_DIAMETER;
+ case CONSTRAINT_FIXED: return SLVS_C_WHERE_DRAGGED;
+ case CONSTRAINT_HORIZONTAL: return SLVS_C_HORIZONTAL;
+ case CONSTRAINT_VERTICAL: return SLVS_C_VERTICAL;
+ case CONSTRAINT_PARALLEL: return SLVS_C_PARALLEL;
+ case CONSTRAINT_PERPENDICULAR: return SLVS_C_PERPENDICULAR;
+ case CONSTRAINT_SYMMETRIC: return SLVS_C_SYMMETRIC_LINE;
+ case CONSTRAINT_EQUAL_LINES: return SLVS_C_EQUAL_LENGTH_LINES;
+ case CONSTRAINT_EQUAL_LINE_ARC: return SLVS_C_EQUAL_LINE_ARC_LEN;
+ case CONSTRAINT_EQUAL_RADIUS: return SLVS_C_EQUAL_RADIUS;
+ case CONSTRAINT_TANGENT_ARC_LINE: return SLVS_C_ARC_LINE_TANGENT;
+ case CONSTRAINT_TANGENT_ARC_ARC: return SLVS_C_CURVE_CURVE_TANGENT;
+ case CONSTRAINT_MULTI_ROTATION: return SLVS_C_MULTI_ROTATION;
+ case CONSTRAINT_MULTI_TRANSLATION: return SLVS_C_MULTI_TRANSLATION;
+ default: break;
+ }
+ return SLVS_C_UNKNOWN;
+ }
+
+ /// \brief Convert constraint type from SolveSpace to SketchSolver
+ static SketchSolver_ConstraintType fromSolveSpace(int theType)
+ {
+ switch (theType) {
+ case SLVS_C_POINTS_COINCIDENT: return CONSTRAINT_PT_PT_COINCIDENT;
+ case SLVS_C_PT_ON_LINE: return CONSTRAINT_PT_ON_LINE;
+ case SLVS_C_PT_ON_CIRCLE: return CONSTRAINT_PT_ON_CIRCLE;
+ case SLVS_C_PT_PT_DISTANCE: return CONSTRAINT_PT_PT_DISTANCE;
+ case SLVS_C_PT_LINE_DISTANCE: return CONSTRAINT_PT_LINE_DISTANCE;
+ case SLVS_C_EQUAL_LENGTH_LINES: return CONSTRAINT_EQUAL_LINES;
+ case SLVS_C_EQUAL_LINE_ARC_LEN: return CONSTRAINT_EQUAL_LINE_ARC;
+ case SLVS_C_SYMMETRIC_LINE: return CONSTRAINT_SYMMETRIC;
+ case SLVS_C_HORIZONTAL: return CONSTRAINT_HORIZONTAL;
+ case SLVS_C_VERTICAL: return CONSTRAINT_VERTICAL;
+ case SLVS_C_DIAMETER: return CONSTRAINT_RADIUS;
+ case SLVS_C_ANGLE: return CONSTRAINT_ANGLE;
+ case SLVS_C_PARALLEL: return CONSTRAINT_PARALLEL;
+ case SLVS_C_PERPENDICULAR: return CONSTRAINT_PERPENDICULAR;
+ case SLVS_C_ARC_LINE_TANGENT: return CONSTRAINT_TANGENT_ARC_LINE;
+ case SLVS_C_EQUAL_RADIUS: return CONSTRAINT_EQUAL_RADIUS;
+ case SLVS_C_WHERE_DRAGGED: return CONSTRAINT_FIXED;
+ case SLVS_C_CURVE_CURVE_TANGENT: return CONSTRAINT_TANGENT_ARC_ARC;
+ case SLVS_C_MULTI_ROTATION: return CONSTRAINT_MULTI_ROTATION;
+ case SLVS_C_MULTI_TRANSLATION: return CONSTRAINT_MULTI_TRANSLATION;
+ default: break;
+ }
+ return CONSTRAINT_UNKNOWN;
+ }
+}
+
+
+#endif
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SolveSpaceSolver_ConstraintWrapper.cpp
+// Created: 2 Dec 2015
+// Author: Artem ZHIDKOV
+
+#include <SolveSpaceSolver_ConstraintWrapper.h>
+#include <SolveSpaceSolver_ConstraintType.h>
+#include <math.h>
+
+SolveSpaceSolver_ConstraintWrapper::SolveSpaceSolver_ConstraintWrapper(
+ const ConstraintPtr& theOriginal,
+ const Slvs_Constraint& theConstraint)
+ : mySlvsConstraint(theConstraint)
+{
+ myBaseConstraint = theOriginal;
+ myValue = mySlvsConstraint.valA;
+}
+
+ConstraintID SolveSpaceSolver_ConstraintWrapper::id() const
+{
+ return (ConstraintID)mySlvsConstraint.h;
+}
+
+void SolveSpaceSolver_ConstraintWrapper::setGroup(const GroupID& theGroup)
+{
+ mySlvsConstraint.group = (Slvs_hGroup)theGroup;
+ std::list<EntityWrapperPtr>::iterator aSubsIt = myConstrained.begin();
+ for (; aSubsIt != myConstrained.end(); ++aSubsIt)
+ (*aSubsIt)->setGroup(theGroup);
+}
+
+SketchSolver_ConstraintType SolveSpaceSolver_ConstraintWrapper::type() const
+{
+ return ConstraintType::fromSolveSpace(mySlvsConstraint.type);
+}
+
+void SolveSpaceSolver_ConstraintWrapper::setValue(const double& theValue)
+{
+ double aValue = theValue;
+ if (type() == CONSTRAINT_RADIUS)
+ aValue *= 2.0; // NOTE: SolveSpace uses constraint DIAMETER
+
+ SketchSolver_IConstraintWrapper::setValue(aValue);
+}
+
+bool SolveSpaceSolver_ConstraintWrapper::isUsed(FeaturePtr theFeature) const
+{
+ std::list<EntityWrapperPtr>::const_iterator anIt = myConstrained.begin();
+ for (; anIt != myConstrained.end(); ++anIt)
+ if ((*anIt)->isUsed(theFeature))
+ return true;
+ return false;
+}
+
+bool SolveSpaceSolver_ConstraintWrapper::isUsed(AttributePtr theAttribute) const
+{
+ std::list<EntityWrapperPtr>::const_iterator anIt = myConstrained.begin();
+ for (; anIt != myConstrained.end(); ++anIt)
+ if ((*anIt)->isUsed(theAttribute))
+ return true;
+ return false;
+}
+
+bool SolveSpaceSolver_ConstraintWrapper::isEqual(const ConstraintWrapperPtr& theOther)
+{
+ const Slvs_Constraint anOtherConstraint =
+ std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(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<EntityWrapperPtr>& anOtherSubs = theOther->entities();
+ if (myConstrained.size() != anOtherSubs.size())
+ return false;
+ std::list<EntityWrapperPtr>::const_iterator aMySubsIt = myConstrained.begin();
+ std::list<EntityWrapperPtr>::const_iterator anOtherSubsIt = anOtherSubs.begin();
+ for (; aMySubsIt != myConstrained.end(); ++aMySubsIt, ++anOtherSubsIt)
+ if (!(*aMySubsIt)->isEqual(*anOtherSubsIt))
+ return false;
+ return true;
+}
+
+bool SolveSpaceSolver_ConstraintWrapper::update(const ConstraintWrapperPtr& theOther)
+{
+ bool isUpdated = false;
+
+ std::list<EntityWrapperPtr> aMySubs = entities();
+ std::list<EntityWrapperPtr> anOtherSubs = theOther->entities();
+ std::list<EntityWrapperPtr>::const_iterator aMySubsIt = aMySubs.begin();
+ std::list<EntityWrapperPtr>::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;
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SolveSpaceSolver_ConstraintWrapper.h
+// Created: 2 Dec 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SolveSpaceSolver_ConstraintWrapper_H_
+#define SolveSpaceSolver_ConstraintWrapper_H_
+
+#include <SketchSolver_IConstraintWrapper.h>
+#include <SolveSpaceSolver_Solver.h>
+
+
+/**
+ * Wrapper providing operations with SovleSpace constraints.
+ */
+class SolveSpaceSolver_ConstraintWrapper : public SketchSolver_IConstraintWrapper
+{
+public:
+ SolveSpaceSolver_ConstraintWrapper(const ConstraintPtr& theOriginal,
+ const Slvs_Constraint& theConstraint);
+
+ /// \brief Return SolveSpace constraint
+ const Slvs_Constraint& constraint() const
+ { return mySlvsConstraint; }
+ /// \brief Return SolveSpace constraint to change
+ Slvs_Constraint& changeConstraint()
+ { return mySlvsConstraint; }
+
+ /// \brief Return ID of current entity
+ virtual ConstraintID id() const;
+
+ /// \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 (GroupID)mySlvsConstraint.group; }
+
+ /// \brief Return type of current entity
+ virtual SketchSolver_ConstraintType type() const;
+
+ /// \brief Assign numeric parameter of constraint
+ virtual void setValue(const double& theValue);
+
+ /// \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<SketchSolver_IConstraintWrapper>& theOther);
+
+private:
+ Slvs_Constraint mySlvsConstraint;
+};
+
+#endif
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SolveSpaceSolver_EntityWrapper.cpp
+// Created: 2 Dec 2015
+// Author: Artem ZHIDKOV
+
+#include <SolveSpaceSolver_EntityWrapper.h>
+
+SolveSpaceSolver_EntityWrapper::SolveSpaceSolver_EntityWrapper(
+ const FeaturePtr theFeature, const Slvs_Entity& theEntity)
+ : myEntity(theEntity)
+{
+ myBaseFeature = theFeature;
+}
+
+SolveSpaceSolver_EntityWrapper::SolveSpaceSolver_EntityWrapper(
+ const AttributePtr theAttribute, const Slvs_Entity& theEntity)
+ : myEntity(theEntity)
+{
+ myBaseAttribute = theAttribute;
+}
+
+EntityID SolveSpaceSolver_EntityWrapper::id() const
+{
+ return (EntityID)myEntity.h;
+}
+
+void SolveSpaceSolver_EntityWrapper::setGroup(const GroupID& theGroup)
+{
+ myEntity.group = (Slvs_hGroup)theGroup;
+ std::list<EntityWrapperPtr>::iterator aSubsIt = mySubEntities.begin();
+ for (; aSubsIt != mySubEntities.end(); ++aSubsIt)
+ (*aSubsIt)->setGroup(theGroup);
+ std::list<ParameterWrapperPtr>::iterator aPIt = myParameters.begin();
+ for (; aPIt != myParameters.end(); ++aPIt)
+ (*aPIt)->setGroup(theGroup);
+}
+
+SketchSolver_EntityType SolveSpaceSolver_EntityWrapper::type() const
+{
+ switch (myEntity.type) {
+ case SLVS_E_POINT_IN_3D:
+ case SLVS_E_POINT_IN_2D: return ENTITY_POINT;
+ case SLVS_E_LINE_SEGMENT: return ENTITY_LINE;
+ case SLVS_E_CIRCLE: return ENTITY_CIRCLE;
+ case SLVS_E_ARC_OF_CIRCLE: return ENTITY_ARC;
+ case SLVS_E_NORMAL_IN_3D:
+ case SLVS_E_NORMAL_IN_2D: return ENTITY_NORMAL;
+ case SLVS_E_DISTANCE: return ENTITY_SCALAR;
+ case SLVS_E_WORKPLANE: return ENTITY_SKETCH;
+ default: break;
+ }
+ return ENTITY_UNKNOWN;
+}
+
+bool SolveSpaceSolver_EntityWrapper::isUsed(FeaturePtr theFeature) const
+{
+ if (isBase(theFeature))
+ return true;
+
+ std::list<EntityWrapperPtr>::const_iterator anIt = mySubEntities.begin();
+ for (; anIt != mySubEntities.end(); ++anIt)
+ if ((*anIt)->isUsed(theFeature))
+ return true;
+ return false;
+}
+
+bool SolveSpaceSolver_EntityWrapper::isUsed(AttributePtr theAttribute) const
+{
+ if (isBase(theAttribute))
+ return true;
+
+ std::list<EntityWrapperPtr>::const_iterator anIt = mySubEntities.begin();
+ for (; anIt != mySubEntities.end(); ++anIt)
+ if ((*anIt)->isUsed(theAttribute))
+ return true;
+ return false;
+}
+
+bool SolveSpaceSolver_EntityWrapper::isEqual(const EntityWrapperPtr& theOther)
+{
+ if (type() != theOther->type())
+ return false;
+
+ // Verify Equality of sub-entities
+ const std::list<EntityWrapperPtr>& anOtherSubs = theOther->subEntities();
+ if (mySubEntities.size() != anOtherSubs.size())
+ return false;
+ std::list<EntityWrapperPtr>::const_iterator aMySubsIt = mySubEntities.begin();
+ std::list<EntityWrapperPtr>::const_iterator anOtherSubsIt = anOtherSubs.begin();
+ for (; aMySubsIt != mySubEntities.end(); ++aMySubsIt, ++anOtherSubsIt)
+ if (!(*aMySubsIt)->isEqual(*anOtherSubsIt))
+ return false;
+
+ // Verify equality of parameters
+ const std::list<ParameterWrapperPtr>& anOtherParams = theOther->parameters();
+ if (myParameters.size() != anOtherParams.size())
+ return false;
+ std::list<ParameterWrapperPtr>::const_iterator aMyIt = myParameters.begin();
+ std::list<ParameterWrapperPtr>::const_iterator anOtherIt = anOtherParams.begin();
+ for (; aMyIt != myParameters.end(); ++aMyIt, ++anOtherIt)
+ if (!(*aMyIt)->isEqual(*anOtherIt))
+ return false;
+ return true;
+}
+
+bool SolveSpaceSolver_EntityWrapper::update(const EntityWrapperPtr& theOther)
+{
+ bool isUpdated = false;
+
+ std::list<EntityWrapperPtr> aMySubs = subEntities();
+ std::list<EntityWrapperPtr> anOtherSubs = theOther->subEntities();
+ std::list<EntityWrapperPtr>::const_iterator aMySubsIt = aMySubs.begin();
+ std::list<EntityWrapperPtr>::const_iterator anOtherSubsIt = anOtherSubs.begin();
+ for (; aMySubsIt != aMySubs.end() && anOtherSubsIt != anOtherSubs.end();
+ ++aMySubsIt, ++anOtherSubsIt)
+ isUpdated = (*aMySubsIt)->update(*anOtherSubsIt) || isUpdated;
+
+ std::list<ParameterWrapperPtr> aMyParams = parameters();
+ std::list<ParameterWrapperPtr> anOtherParams = theOther->parameters();
+ std::list<ParameterWrapperPtr>::const_iterator aMyParIt = aMyParams.begin();
+ std::list<ParameterWrapperPtr>::const_iterator anOtherParIt = anOtherParams.begin();
+ for (; aMyParIt != aMyParams.end() && anOtherParIt != anOtherParams.end();
+ ++aMyParIt, ++anOtherParIt)
+ isUpdated = (*aMyParIt)->update(*anOtherParIt);
+ return isUpdated;
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SolveSpaceSolver_EntityWrapper.h
+// Created: 2 Dec 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SolveSpaceSolver_EntityWrapper_H_
+#define SolveSpaceSolver_EntityWrapper_H_
+
+#include <SketchSolver_IEntityWrapper.h>
+#include <SolveSpaceSolver_Solver.h>
+
+/**
+ * Wrapper providing operations with SolveSpace entities.
+ */
+class SolveSpaceSolver_EntityWrapper : public SketchSolver_IEntityWrapper
+{
+public:
+ SolveSpaceSolver_EntityWrapper(const FeaturePtr theFeature, const Slvs_Entity& theEntity);
+ SolveSpaceSolver_EntityWrapper(const AttributePtr theAttribute, const Slvs_Entity& theEntity);
+
+ /// \brief Return SolveSpace entity
+ const Slvs_Entity& entity() const
+ { return myEntity; }
+ /// \brief Return SolveSpace entity to change
+ Slvs_Entity& changeEntity()
+ { return myEntity; }
+
+ /// \brief Return ID of current entity
+ virtual EntityID id() const;
+
+ /// \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 (GroupID)myEntity.group; }
+
+ /// \brief Return type of current entity
+ virtual SketchSolver_EntityType type() const;
+
+ /// \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 std::shared_ptr<SketchSolver_IEntityWrapper>& theOther);
+
+private:
+ Slvs_Entity myEntity;
+};
+
+#endif
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SolveSpaceSolver_ParameterWrapper.cpp
+// Created: 2 Dec 2015
+// Author: Artem ZHIDKOV
+
+#include <SolveSpaceSolver_ParameterWrapper.h>
+
+#include <math.h>
+
+SolveSpaceSolver_ParameterWrapper::SolveSpaceSolver_ParameterWrapper(const Slvs_Param& theParam)
+ : myParameter(theParam)
+{
+}
+
+ParameterID SolveSpaceSolver_ParameterWrapper::id() const
+{
+ return (ParameterID)myParameter.h;
+}
+
+void SolveSpaceSolver_ParameterWrapper::setValue(double theValue)
+{
+ myParameter.val = theValue;
+}
+
+double SolveSpaceSolver_ParameterWrapper::value() const
+{
+ return myParameter.val;
+}
+
+bool SolveSpaceSolver_ParameterWrapper::isEqual(const ParameterWrapperPtr& theOther)
+{
+ std::shared_ptr<SolveSpaceSolver_ParameterWrapper> anOtherParam =
+ std::dynamic_pointer_cast<SolveSpaceSolver_ParameterWrapper>(theOther);
+ return anOtherParam && fabs(value() - anOtherParam->value()) < tolerance;
+}
+
+bool SolveSpaceSolver_ParameterWrapper::update(const ParameterWrapperPtr& theOther)
+{
+ std::shared_ptr<SolveSpaceSolver_ParameterWrapper> anOther =
+ std::dynamic_pointer_cast<SolveSpaceSolver_ParameterWrapper>(theOther);
+ if (fabs(value() - anOther->value()) < tolerance)
+ return false;
+ myParameter.val = anOther->value();
+ myIsParametric = theOther->isParametric();
+ return true;
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SolveSpaceSolver_ParameterWrapper.h
+// Created: 2 Dec 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SolveSpaceSolver_ParameterWrapper_H_
+#define SolveSpaceSolver_ParameterWrapper_H_
+
+#include <SketchSolver_IParameterWrapper.h>
+#include <SolveSpaceSolver_Solver.h>
+
+/**
+ * Wrapper providing operations with parameters in SolveSpace.
+ */
+class SolveSpaceSolver_ParameterWrapper : public SketchSolver_IParameterWrapper
+{
+public:
+ SolveSpaceSolver_ParameterWrapper(const Slvs_Param& theParam);
+
+ /// \brief Return SolveSpace parameter
+ const Slvs_Param& parameter() const
+ { return myParameter; }
+ /// \brief Return SolveSpace parameter to change
+ Slvs_Param& changeParameter()
+ { return myParameter; }
+
+ /// \brief Return ID of current parameter
+ virtual ParameterID id() const;
+
+ /// \brief Change group for the parameter
+ virtual void setGroup(const GroupID& theGroup)
+ { myParameter.group = (Slvs_hGroup)theGroup; }
+
+ /// \brief Return identifier of the group the parameter belongs to
+ virtual GroupID group() const
+ { return (GroupID)myParameter.group; }
+
+ /// \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 std::shared_ptr<SketchSolver_IParameterWrapper>& theOther);
+
+private:
+ Slvs_Param myParameter;
+};
+
+#endif
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SolveSpaceSolver_Solver.cpp
+// Created: 07 May 2014
+// Author: Artem ZHIDKOV
+
+#include "SolveSpaceSolver_Solver.h"
+#include <Events_LongOp.h>
+
+SolveSpaceSolver_Solver::SolveSpaceSolver_Solver()
+{
+ // Nullify all elements of the set of equations
+ myEquationsSystem.param = 0;
+ myEquationsSystem.params = 0;
+ myEquationsSystem.entity = 0;
+ myEquationsSystem.entities = 0;
+ myEquationsSystem.constraint = 0;
+ myEquationsSystem.constraints = 0;
+ myEquationsSystem.failed = 0;
+ myEquationsSystem.faileds = 0;
+
+ myEquationsSystem.dragged[0] = 0;
+ myEquationsSystem.dragged[1] = 0;
+ myEquationsSystem.dragged[2] = 0;
+ myEquationsSystem.dragged[3] = 0;
+
+ // If the set of constraints is inconsistent,
+ // the failed field will contain wrong constraints
+ myEquationsSystem.calculateFaileds = 0;
+}
+
+SolveSpaceSolver_Solver::~SolveSpaceSolver_Solver()
+{
+ if (myEquationsSystem.constraint)
+ delete[] myEquationsSystem.constraint;
+ myEquationsSystem.constraint = 0;
+ if (myEquationsSystem.failed)
+ delete[] myEquationsSystem.failed;
+ myEquationsSystem.failed = 0;
+}
+
+void SolveSpaceSolver_Solver::setParameters(Slvs_Param* theParameters, int theSize)
+{
+ myEquationsSystem.param = theParameters;
+ myEquationsSystem.params = theSize;
+}
+
+
+void SolveSpaceSolver_Solver::setDraggedParameters(const Slvs_hParam* theDragged)
+{
+ for (unsigned int i = 0; i < 4; i++)
+ myEquationsSystem.dragged[i] = theDragged[i];
+}
+
+void SolveSpaceSolver_Solver::setEntities(Slvs_Entity* theEntities, int theSize)
+{
+ myEquationsSystem.entity = theEntities;
+ myEquationsSystem.entities = theSize;
+}
+
+void SolveSpaceSolver_Solver::setConstraints(Slvs_Constraint* theConstraints, int theSize)
+{
+ if (!myEquationsSystem.constraint) {
+ myEquationsSystem.constraint = new Slvs_Constraint[theSize];
+ myEquationsSystem.constraints = theSize;
+ myEquationsSystem.failed = new Slvs_hConstraint[theSize];
+ }
+ else if (myEquationsSystem.constraints != theSize) {
+ if (theSize > myEquationsSystem.constraints) {
+ delete[] myEquationsSystem.constraint;
+ myEquationsSystem.constraint = new Slvs_Constraint[theSize];
+ if (myEquationsSystem.failed)
+ delete[] myEquationsSystem.failed;
+ myEquationsSystem.failed = new Slvs_hConstraint[theSize];
+ }
+ myEquationsSystem.constraints = theSize;
+ }
+ memcpy(myEquationsSystem.constraint, theConstraints, theSize * sizeof(Slvs_Constraint));
+ memset(myEquationsSystem.failed, SLVS_C_UNKNOWN, theSize * sizeof(Slvs_hConstraint));
+}
+
+
+SketchSolver_SolveStatus SolveSpaceSolver_Solver::solve()
+{
+ if (myEquationsSystem.constraints <= 0)
+ return STATUS_EMPTYSET;
+
+ myEquationsSystem.calculateFaileds = myFindFaileds ? 1 : 0;
+
+ Events_LongOp::start(this);
+ Slvs_Solve(&myEquationsSystem, myGroup);
+ Events_LongOp::end(this);
+
+ SketchSolver_SolveStatus aStatus;
+ switch (myEquationsSystem.result) {
+ case SLVS_RESULT_OKAY:
+ aStatus = STATUS_OK;
+ break;
+ case SLVS_RESULT_INCONSISTENT:
+ case SLVS_RESULT_DIDNT_CONVERGE:
+ case SLVS_RESULT_TOO_MANY_UNKNOWNS:
+ aStatus = STATUS_INCONSISTENT;
+ break;
+ default:
+ aStatus = STATUS_FAILED;
+ }
+ return aStatus;
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SolveSpaceSolver_Solver.h
+// Created: 07 May 2014
+// Author: Artem ZHIDKOV
+
+#ifndef SolveSpaceSolver_Solver_H_
+#define SolveSpaceSolver_Solver_H_
+
+#include <SketchSolver_ISolver.h>
+
+// 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 <stdint.h>
+#endif
+#include <string.h>
+#include <slvs.h>
+
+#include <vector>
+
+// Unknown constraint (for error reporting)
+#define SLVS_C_UNKNOWN 0
+// Fillet constraint identifier
+#define SLVS_C_FILLET 100100
+// Multi-rotation constraint identifier
+#define SLVS_C_MULTI_ROTATION 100101
+// Multi-translation constraint identifier
+#define SLVS_C_MULTI_TRANSLATION 100102
+// Unknown entity
+#define SLVS_E_UNKNOWN 0
+// Unknown group
+#define SLVS_G_UNKNOWN 0
+// Group ID to store external objects
+#define SLVS_G_OUTOFGROUP 1
+
+/** \class SolveSpaceSolver_Solver
+ * \ingroup Plugins
+ * \brief Performs high-level operations to solve sketch in SolveSpace.
+ */
+class SolveSpaceSolver_Solver : public SketchSolver_ISolver
+{
+ public:
+ SolveSpaceSolver_Solver();
+ virtual ~SolveSpaceSolver_Solver();
+
+ /** \brief Change array of parameters
+ * \param[in] theParameters pointer to the array of parameters
+ * \param[in] theSize size of this array
+ */
+ void setParameters(Slvs_Param* theParameters, int theSize);
+
+ /** \brief Change array of entities
+ * \param[in] theEntities pointer to the array of entities
+ * \param[in] theSize size of this array
+ */
+ void setEntities(Slvs_Entity* theEntities, int theSize);
+
+ /** \brief Change array of constraints
+ * \param[in] theConstraints pointer to the array of constraints
+ * \param[in] theSize size of this array
+ */
+ void setConstraints(Slvs_Constraint* theConstraints, int theSize);
+
+ /** \brief Store the parameters of the point which was moved by user.
+ * The solver will watch this items to be constant
+ * \param[in] theDragged list of parameters (not more than 4) which should not be changed during solving
+ */
+ void setDraggedParameters(const Slvs_hParam* theDragged);
+
+ /** \brief Solve the set of equations
+ * \return identifier whether solution succeeded
+ */
+ virtual SketchSolver_SolveStatus solve();
+
+ private:
+ Slvs_System myEquationsSystem; ///< set of equations for solving in SolveSpace
+};
+
+#endif
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SolveSpaceSolver_Storage.cpp
+// Created: 18 Mar 2015
+// Author: Artem ZHIDKOV
+
+#include <SolveSpaceSolver_Storage.h>
+#include <SolveSpaceSolver_ConstraintWrapper.h>
+#include <SolveSpaceSolver_EntityWrapper.h>
+#include <SolveSpaceSolver_ParameterWrapper.h>
+#include <SolveSpaceSolver_Builder.h>
+
+#include <GeomAPI_Dir2d.h>
+#include <GeomAPI_Pnt2d.h>
+#include <GeomAPI_XY.h>
+#include <math.h>
+#include <assert.h>
+
+#include <GeomDataAPI_Point.h>
+#include <GeomDataAPI_Point2D.h>
+#include <ModelAPI_AttributeDouble.h>
+
+/** \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<typename T>
+static int Search(const uint32_t& theEntityID, const std::vector<T>& 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 constraints to be different
+static bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2);
+
+
+SolveSpaceSolver_Storage::SolveSpaceSolver_Storage(const GroupID& theGroup)
+ : SketchSolver_Storage(theGroup),
+ myWorkplaneID(SLVS_E_UNKNOWN),
+ myParamMaxID(SLVS_E_UNKNOWN),
+ myEntityMaxID(SLVS_E_UNKNOWN),
+ myConstrMaxID(SLVS_C_UNKNOWN),
+ myFixed(SLVS_E_UNKNOWN),
+ myDuplicatedConstraint(false)
+{
+}
+
+bool SolveSpaceSolver_Storage::update(ConstraintWrapperPtr& theConstraint)
+{
+ bool isUpdated = false;
+ std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
+ std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
+ Slvs_Constraint aSlvsConstr = getConstraint((Slvs_hConstraint)aConstraint->id());
+ if (aSlvsConstr.h == SLVS_C_UNKNOWN)
+ aSlvsConstr = aConstraint->constraint();
+
+ // update value of constraint if exist
+ if (fabs(aSlvsConstr.valA - theConstraint->value()) > tolerance) {
+ aSlvsConstr.valA = theConstraint->value();
+ isUpdated = true;
+ }
+
+ // update constrained entities
+ Slvs_hEntity* aPnts[2] = {&aSlvsConstr.ptA, &aSlvsConstr.ptB};
+ Slvs_hEntity* anEnts[4] = {&aSlvsConstr.entityA, &aSlvsConstr.entityB,
+ &aSlvsConstr.entityC, &aSlvsConstr.entityD};
+ int aPtInd = 0;
+ int aEntInd = 0;
+
+ std::list<EntityWrapperPtr> anEntities = theConstraint->entities();
+ std::list<EntityWrapperPtr>::iterator anIt = anEntities.begin();
+ for (; anIt != anEntities.end(); ++anIt) {
+ isUpdated = update(*anIt) || isUpdated;
+
+ Slvs_hEntity anID = (Slvs_hEntity)(*anIt)->id();
+ if ((*anIt)->type() == ENTITY_POINT) {
+ if (*(aPnts[aPtInd]) != anID) {
+ *(aPnts[aPtInd]) = anID;
+ isUpdated = true;
+ }
+ ++aPtInd;
+ } else {
+ if (*(anEnts[aEntInd]) != anID) {
+ *(anEnts[aEntInd]) = anID;
+ isUpdated = true;
+ }
+ ++aEntInd;
+ }
+ }
+
+ // update constraint itself (do not update constraints Multi)
+ if (aSlvsConstr.type != SLVS_C_MULTI_ROTATION && aSlvsConstr.type != SLVS_C_MULTI_TRANSLATION) {
+ if (aSlvsConstr.wrkpl == SLVS_E_UNKNOWN && myWorkplaneID != SLVS_E_UNKNOWN)
+ aSlvsConstr.wrkpl = myWorkplaneID;
+ if (aSlvsConstr.group == SLVS_G_UNKNOWN)
+ aSlvsConstr.group = (Slvs_hGroup)myGroupID;
+ Slvs_hConstraint aConstrID = updateConstraint(aSlvsConstr);
+ if (aSlvsConstr.h == SLVS_C_UNKNOWN) {
+ aConstraint->changeConstraint() = getConstraint(aConstrID);
+ isUpdated = true;
+ }
+ }
+ return isUpdated;
+}
+
+bool SolveSpaceSolver_Storage::update(EntityWrapperPtr& theEntity)
+{
+ bool isUpdated = false;
+ std::shared_ptr<SolveSpaceSolver_EntityWrapper> anEntity =
+ std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theEntity);
+ Slvs_Entity aSlvsEnt = getEntity((Slvs_hEntity)anEntity->id());
+ if (aSlvsEnt.h == SLVS_E_UNKNOWN)
+ aSlvsEnt = anEntity->entity();
+
+ std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
+ std::list<ParameterWrapperPtr>::iterator aPIt;
+ // if the entity is an attribute, need to update its coordinates
+ if (anEntity->baseAttribute()) {
+ BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
+ EntityWrapperPtr anUpdAttr = aBuilder->createAttribute(anEntity->baseAttribute(), GID_UNKNOWN);
+ if (anUpdAttr) {
+ std::list<ParameterWrapperPtr> anUpdParams = anUpdAttr->parameters();
+ std::list<ParameterWrapperPtr>::iterator anUpdIt = anUpdParams.begin();
+ for (aPIt = aParams.begin(); aPIt != aParams.end() && anUpdIt != anUpdParams.end();
+ ++aPIt, ++anUpdIt) {
+ (*aPIt)->update(*anUpdIt);
+ }
+ }
+ }
+
+ // update parameters
+ int anInd = 0;
+ for (aPIt = aParams.begin(); aPIt != aParams.end(); ++aPIt, ++anInd) {
+ assert(anInd < 4);
+ isUpdated = update(*aPIt) || isUpdated;
+ if (aSlvsEnt.param[anInd] != (Slvs_hEntity)(*aPIt)->id()) {
+ isUpdated = true;
+ aSlvsEnt.param[anInd] = (Slvs_hEntity)(*aPIt)->id();
+ }
+ }
+
+ // update sub-entities
+ std::list<EntityWrapperPtr> aSubEntities = theEntity->subEntities();
+ std::list<EntityWrapperPtr>::iterator aSIt = aSubEntities.begin();
+ for (anInd = 0; aSIt != aSubEntities.end(); ++aSIt, ++anInd) {
+ assert(anInd < 4);
+ isUpdated = update(*aSIt) || isUpdated;
+
+ Slvs_hEntity anID = Slvs_hEntity((*aSIt)->id());
+ if ((*aSIt)->type() == ENTITY_NORMAL)
+ aSlvsEnt.normal = anID;
+ else if ((*aSIt)->type() == ENTITY_SCALAR)
+ aSlvsEnt.distance = anID;
+ else if (aSlvsEnt.point[anInd] != anID) {
+ aSlvsEnt.point[anInd] = anID;
+ isUpdated = true;
+ }
+ }
+
+ // update entity itself
+ if (aSlvsEnt.wrkpl == SLVS_E_UNKNOWN && myWorkplaneID != SLVS_E_UNKNOWN)
+ aSlvsEnt.wrkpl = myWorkplaneID;
+ if (aSlvsEnt.group == SLVS_G_UNKNOWN)
+ aSlvsEnt.group = (Slvs_hGroup)myGroupID;
+ Slvs_hEntity anEntID = updateEntity(aSlvsEnt);
+ if (aSlvsEnt.h == SLVS_E_UNKNOWN) {
+ anEntity->changeEntity() = getEntity(anEntID);
+ isUpdated = true;
+
+ if (anEntity->type() == ENTITY_SKETCH)
+ storeWorkplane(anEntity);
+ }
+ return isUpdated;
+}
+
+bool SolveSpaceSolver_Storage::update(ParameterWrapperPtr& theParameter)
+{
+ std::shared_ptr<SolveSpaceSolver_ParameterWrapper> aParameter =
+ std::dynamic_pointer_cast<SolveSpaceSolver_ParameterWrapper>(theParameter);
+ const Slvs_Param& aParam = getParameter((Slvs_hParam)aParameter->id());
+ if (aParam.h != SLVS_E_UNKNOWN && fabs(aParam.val - aParameter->value()) < tolerance)
+ return false;
+ Slvs_Param aParamToUpd = aParameter->parameter();
+ if (aParamToUpd.group == SLVS_G_UNKNOWN)
+ aParamToUpd.group = aParameter->isParametric() ? (Slvs_hGroup)GID_OUTOFGROUP : (Slvs_hGroup)myGroupID;
+ Slvs_hParam anID = updateParameter(aParamToUpd);
+ if (aParam.h == SLVS_E_UNKNOWN) // new parameter
+ aParameter->changeParameter() = getParameter(anID);
+ return true;
+}
+
+void SolveSpaceSolver_Storage::storeWorkplane(EntityWrapperPtr theSketch)
+{
+ myWorkplaneID = (Slvs_hEntity)theSketch->id();
+
+ // Update sub-entities of the sketch
+ std::list<EntityWrapperPtr> aSubEntities = theSketch->subEntities();
+ std::list<EntityWrapperPtr>::iterator aSIt = aSubEntities.begin();
+ for (; aSIt != aSubEntities.end(); ++aSIt) {
+ std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSub =
+ std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*aSIt);
+ aSub->changeEntity().wrkpl = myWorkplaneID;
+ }
+
+ // Update all stored entities
+ std::vector<Slvs_Entity>::iterator anIt = myEntities.begin();
+ for (; anIt != myEntities.end(); ++anIt)
+ anIt->wrkpl = myWorkplaneID;
+}
+
+void SolveSpaceSolver_Storage::changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup)
+{
+ std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
+ std::list<ParameterWrapperPtr>::iterator aPIt = aParams.begin();
+ for (; aPIt != aParams.end(); ++aPIt)
+ changeGroup(*aPIt, theGroup);
+
+ std::list<EntityWrapperPtr> aSubs = theEntity->subEntities();
+ std::list<EntityWrapperPtr>::iterator aSIt = aSubs.begin();
+ for (; aSIt != aSubs.end(); ++aSIt)
+ changeGroup(*aSIt, theGroup);
+
+ if (theEntity->group() != theGroup) {
+ theEntity->setGroup(theGroup);
+ int aPos = Search((Slvs_hEntity)theEntity->id(), myEntities);
+ if (aPos >= 0 && aPos < (int)myEntities.size()) {
+ myEntities[aPos].group = (Slvs_hGroup)theGroup;
+ setNeedToResolve(true);
+ }
+ }
+}
+
+void SolveSpaceSolver_Storage::changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup)
+{
+ GroupID aGroup = theGroup;
+ if (theParam->isParametric())
+ aGroup = GID_OUTOFGROUP;
+ if (theParam->group() == aGroup)
+ return;
+
+ theParam->setGroup(aGroup);
+ int aPos = Search((Slvs_hParam)theParam->id(), myParameters);
+ if (aPos >= 0 && aPos < (int)myParameters.size()) {
+ myParameters[aPos].group = (Slvs_hGroup)aGroup;
+ setNeedToResolve(true);
+ }
+}
+
+void SolveSpaceSolver_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<EntityWrapperPtr>();
+ 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<EntityWrapperPtr> aNewSlaves = aSlaveFound->second;
+ aNewSlaves.insert(aSlaveFound->first);
+ myCoincidentPoints.erase(aSlaveFound);
+
+ std::set<EntityWrapperPtr>::const_iterator aSlIt = aNewSlaves.begin();
+ for (; aSlIt != aNewSlaves.end(); ++aSlIt)
+ addCoincidentPoints(theMaster, *aSlIt);
+ } else {
+ // Update the slave if it was used in constraints and features
+ replaceInFeatures(theSlave, theMaster);
+ replaceInConstraints(theSlave, theMaster);
+
+ // Remove slave entity
+ removeEntity((Slvs_hEntity)theSlave->id());
+
+ std::shared_ptr<SolveSpaceSolver_EntityWrapper> aPointMaster =
+ std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theMaster);
+ std::shared_ptr<SolveSpaceSolver_EntityWrapper> aPointSlave =
+ std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theSlave);
+ aPointSlave->changeEntity() = aPointMaster->entity();
+ aPointSlave->setParameters(aPointMaster->parameters());
+
+ aMasterFound->second.insert(theSlave);
+ }
+}
+
+void SolveSpaceSolver_Storage::replaceInFeatures(
+ EntityWrapperPtr theSource, EntityWrapperPtr theDest)
+{
+ std::map<FeaturePtr, EntityWrapperPtr>::const_iterator anIt = myFeatureMap.begin();
+ for (; anIt != myFeatureMap.end(); ++anIt) {
+ bool isUpdated = false;
+ std::list<EntityWrapperPtr> aSubs = anIt->second->subEntities();
+ std::list<EntityWrapperPtr>::iterator aSubIt = aSubs.begin();
+ for (; aSubIt != aSubs.end(); ++aSubIt)
+ if ((*aSubIt)->id() == theSource->id()) {
+ (*aSubIt)->update(theDest);
+ isUpdated = true;
+ }
+
+ if (!isUpdated)
+ continue;
+
+ std::shared_ptr<SolveSpaceSolver_EntityWrapper> aWrapper =
+ std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(anIt->second);
+ // update SolveSpace entity
+ Slvs_Entity anEnt = aWrapper->entity();
+ for (int i = 0; i < 4; ++i)
+ if (anEnt.point[i] == (Slvs_hEntity)theSource->id())
+ anEnt.point[i] = (Slvs_hEntity)theDest->id();
+ anEnt.h = updateEntity(anEnt);
+ aWrapper->changeEntity() = anEnt;
+
+ // update sub-entities
+ aWrapper->setSubEntities(aSubs);
+ }
+}
+
+void SolveSpaceSolver_Storage::replaceInConstraints(
+ EntityWrapperPtr theSource, EntityWrapperPtr theDest)
+{
+ std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
+ anIt = myConstraintMap.begin();
+ std::list<ConstraintWrapperPtr>::const_iterator aCIt;
+ for (; anIt != myConstraintMap.end(); ++anIt)
+ for (aCIt = anIt->second.begin(); aCIt != anIt->second.end(); ++aCIt) {
+ // Do not process coincidence between points
+ // (these constraints are stored to keep the structure of constraints).
+ if ((*aCIt)->type() == CONSTRAINT_PT_PT_COINCIDENT)
+ continue;
+
+ bool isUpdated = false;
+ std::list<EntityWrapperPtr> aSubs = (*aCIt)->entities();
+ std::list<EntityWrapperPtr>::iterator aSubIt = aSubs.begin();
+ for (; aSubIt != aSubs.end(); ++aSubIt)
+ if ((*aSubIt)->id() == theSource->id()) {
+ (*aSubIt)->update(theDest);
+ isUpdated = true;
+ }
+
+ if (!isUpdated)
+ continue;
+
+ std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aWrapper =
+ std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(*aCIt);
+ // change constraint entities
+ Slvs_Constraint aConstr = aWrapper->constraint();
+ if (aConstr.ptA == (Slvs_hEntity)theSource->id())
+ aConstr.ptA = (Slvs_hEntity)theDest->id();
+ if (aConstr.ptB == (Slvs_hEntity)theSource->id())
+ aConstr.ptB = (Slvs_hEntity)theDest->id();
+
+ // check the constraint is duplicated
+ std::vector<Slvs_Constraint>::const_iterator aSlvsCIt = myConstraints.begin();
+ for (; aSlvsCIt != myConstraints.end(); ++aSlvsCIt)
+ if (aConstr.h != aSlvsCIt->h &&
+ aConstr.type == aSlvsCIt->type &&
+ aConstr.ptA == aSlvsCIt->ptA && aConstr.ptB == aSlvsCIt->ptB &&
+ aConstr.entityA == aSlvsCIt->entityA && aConstr.entityB == aSlvsCIt->entityB &&
+ aConstr.entityC == aSlvsCIt->entityC && aConstr.entityD == aSlvsCIt->entityD) {
+ removeConstraint(aConstr.h);
+ aConstr = *aSlvsCIt;
+ break;
+ }
+
+ if (aSlvsCIt != myConstraints.end()) {
+ // constraint is duplicated, search its wrapper to add the mapping
+ std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
+ anIt2 = myConstraintMap.begin();
+ std::list<ConstraintWrapperPtr>::const_iterator aCIt2;
+ for (; anIt2 != myConstraintMap.end(); ++anIt2)
+ for (aCIt2 = anIt2->second.begin(); aCIt2 != anIt2->second.end(); ++aCIt2)
+ if ((Slvs_hConstraint)(*aCIt2)->id() == aConstr.h) {
+ addSameConstraints(*aCIt2, aWrapper);
+ break;
+ }
+ } else
+ aConstr.h = updateConstraint(aConstr);
+ aWrapper->changeConstraint() = aConstr;
+
+ // update sub-entities
+ aWrapper->setEntities(aSubs);
+ }
+}
+
+void SolveSpaceSolver_Storage::addSameConstraints(ConstraintWrapperPtr theConstraint1,
+ ConstraintWrapperPtr theConstraint2)
+{
+ SameConstraintMap::iterator anIt = myEqualConstraints.begin();
+ for (; anIt != myEqualConstraints.end(); ++anIt) {
+ if (anIt->find(theConstraint1) != anIt->end()) {
+ anIt->insert(theConstraint2);
+ return;
+ }
+ else if (anIt->find(theConstraint2) != anIt->end()) {
+ anIt->insert(theConstraint1);
+ return;
+ }
+ }
+ // group not found => create new one
+ std::set<ConstraintWrapperPtr> aNewGroup;
+ aNewGroup.insert(theConstraint1);
+ aNewGroup.insert(theConstraint2);
+ myEqualConstraints.push_back(aNewGroup);
+}
+
+
+EntityWrapperPtr SolveSpaceSolver_Storage::calculateMiddlePoint(
+ EntityWrapperPtr theBase, double theCoeff)
+{
+ BuilderPtr aBuilder = SolveSpaceSolver_Builder::getInstance();
+
+ std::shared_ptr<GeomAPI_XY> aMidPoint;
+ if (theBase->type() == ENTITY_LINE) {
+ std::shared_ptr<GeomAPI_Pnt2d> aPoints[2];
+ const std::list<EntityWrapperPtr>& aSubs = theBase->subEntities();
+ std::list<EntityWrapperPtr>::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<EntityWrapperPtr>& aSubs = theBase->subEntities();
+ std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
+ for (int i = 0; i < 3; ++i, ++anIt) {
+ std::shared_ptr<GeomAPI_Pnt2d> 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<GeomAPI_Dir2d> aStartDir(new GeomAPI_Dir2d(anArcPoint[1][0], anArcPoint[1][1]));
+ std::shared_ptr<GeomAPI_Dir2d> 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<GeomAPI_XY>(new GeomAPI_XY(theX, theY));
+ }
+
+ if (!aMidPoint)
+ return EntityWrapperPtr();
+
+ std::list<ParameterWrapperPtr> aParameters;
+ Slvs_Param aParam1 = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)myGroupID, aMidPoint->x());
+ aParam1.h = addParameter(aParam1);
+ aParameters.push_back(ParameterWrapperPtr(new SolveSpaceSolver_ParameterWrapper(aParam1)));
+ Slvs_Param aParam2 = Slvs_MakeParam(SLVS_E_UNKNOWN, (Slvs_hGroup)myGroupID, aMidPoint->y());
+ aParam2.h = addParameter(aParam2);
+ aParameters.push_back(ParameterWrapperPtr(new SolveSpaceSolver_ParameterWrapper(aParam2)));
+ // Create entity (parameters are not filled)
+ Slvs_Entity anEntity = Slvs_MakePoint2d(SLVS_E_UNKNOWN, (Slvs_hGroup)myGroupID,
+ (Slvs_hEntity)myWorkplaneID, aParam1.h, aParam2.h);
+ anEntity.h = addEntity(anEntity);
+
+ EntityWrapperPtr aResult(new SolveSpaceSolver_EntityWrapper(AttributePtr(), anEntity));
+ aResult->setParameters(aParameters);
+ return aResult;
+}
+
+
+
+
+
+
+Slvs_hParam SolveSpaceSolver_Storage::addParameter(const Slvs_Param& theParam)
+{
+ if (theParam.h > 0 && theParam.h <= myParamMaxID) {
+ // parameter is already used, rewrite it
+ return updateParameter(theParam);
+ }
+
+ Slvs_Param aParam = theParam;
+ if (aParam.h > myParamMaxID)
+ myParamMaxID = aParam.h;
+ else
+ aParam.h = ++myParamMaxID;
+ myParameters.push_back(aParam);
+ myNeedToResolve = true;
+ return aParam.h;
+}
+
+Slvs_hParam SolveSpaceSolver_Storage::updateParameter(const Slvs_Param& theParam)
+{
+ if (theParam.h > 0 && theParam.h <= myParamMaxID) {
+ // parameter already used, rewrite it
+ int aPos = Search(theParam.h, myParameters);
+ if (aPos >= 0 && aPos < (int)myParameters.size()) {
+ if (IsNotEqual(myParameters[aPos], theParam)) {
+ myUpdatedParameters.insert(theParam.h);
+ setNeedToResolve(true);
+ }
+ myParameters[aPos] = theParam;
+ return theParam.h;
+ }
+ }
+
+ // Parameter is not found, add new one
+ Slvs_Param aParam = theParam;
+ aParam.h = 0;
+ return addParameter(aParam);
+}
+
+bool SolveSpaceSolver_Storage::removeParameter(const Slvs_hParam& theParamID)
+{
+ int aPos = Search(theParamID, myParameters);
+ if (aPos >= 0 && aPos < (int)myParameters.size()) {
+ // Firstly, search the parameter is not used elsewhere
+ std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
+ for (; anEntIter != myEntities.end(); anEntIter++) {
+ for (int i = 0; i < 4; i++)
+ if (anEntIter->param[i] == theParamID)
+ return false;
+ }
+ // Remove parameter
+ myParameters.erase(myParameters.begin() + aPos);
+ myParamMaxID = myParameters.empty() ? SLVS_E_UNKNOWN : myParameters.back().h;
+ myNeedToResolve = true;
+ }
+ return true;
+}
+
+const Slvs_Param& SolveSpaceSolver_Storage::getParameter(const Slvs_hParam& theParamID) const
+{
+ int aPos = Search(theParamID, myParameters);
+ if (aPos >= 0 && aPos < (int)myParameters.size())
+ return myParameters[aPos];
+
+ // Parameter is not found, return empty object
+ static Slvs_Param aDummy;
+ aDummy.h = 0;
+ return aDummy;
+}
+
+
+Slvs_hEntity SolveSpaceSolver_Storage::addEntity(const Slvs_Entity& theEntity)
+{
+ if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
+ // Entity is already used, rewrite it
+ return updateEntity(theEntity);
+ }
+
+ Slvs_Entity aEntity = theEntity;
+ if (aEntity.h > myEntityMaxID)
+ myEntityMaxID = aEntity.h;
+ else
+ aEntity.h = ++myEntityMaxID;
+ myEntities.push_back(aEntity);
+ myNeedToResolve = true;
+ return aEntity.h;
+}
+
+Slvs_hEntity SolveSpaceSolver_Storage::updateEntity(const Slvs_Entity& theEntity)
+{
+ if (theEntity.h > 0 && theEntity.h <= myEntityMaxID) {
+ // Entity already used, rewrite it
+ int aPos = Search(theEntity.h, myEntities);
+ if (aPos >= 0 && aPos < (int)myEntities.size()) {
+ myNeedToResolve = myNeedToResolve || IsNotEqual(myEntities[aPos], theEntity);
+ myEntities[aPos] = theEntity;
+ return theEntity.h;
+ }
+ }
+
+ // Entity is not found, add new one
+ Slvs_Entity aEntity = theEntity;
+ aEntity.h = 0;
+ return addEntity(aEntity);
+}
+
+bool SolveSpaceSolver_Storage::removeEntity(const Slvs_hEntity& theEntityID)
+{
+ bool aResult = true;
+ int aPos = Search(theEntityID, myEntities);
+ if (aPos >= 0 && aPos < (int)myEntities.size()) {
+ // Firstly, check the entity and its attributes is not used elsewhere
+ std::set<Slvs_hEntity> anEntAndSubs;
+ anEntAndSubs.insert(theEntityID);
+ for (int i = 0; i < 4; i++)
+ if (myEntities[aPos].point[i] != SLVS_E_UNKNOWN)
+ anEntAndSubs.insert(myEntities[aPos].point[i]);
+
+ std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
+ for (; anEntIter != myEntities.end(); anEntIter++) {
+ if (anEntAndSubs.find(anEntIter->h) != anEntAndSubs.end())
+ continue;
+ for (int i = 0; i < 4; i++)
+ if (anEntAndSubs.find(anEntIter->point[i]) != anEntAndSubs.end())
+ return false;
+ if (anEntAndSubs.find(anEntIter->distance) != anEntAndSubs.end())
+ return false;
+ }
+ std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+ for (; aConstrIter != myConstraints.end(); aConstrIter++) {
+ Slvs_hEntity anEntIDs[6] = {aConstrIter->ptA, aConstrIter->ptB,
+ aConstrIter->entityA, aConstrIter->entityB,
+ aConstrIter->entityC, aConstrIter->entityD};
+ for (int i = 0; i < 6; i++)
+ if (anEntAndSubs.find(anEntIDs[i]) != anEntAndSubs.end())
+ return false;
+ }
+ // The entity is not used, remove it and its parameters
+ Slvs_Entity anEntity = myEntities[aPos];
+ myEntities.erase(myEntities.begin() + aPos);
+ myEntityMaxID = myEntities.empty() ? SLVS_E_UNKNOWN : myEntities.back().h;
+ if (anEntity.distance != SLVS_E_UNKNOWN)
+ aResult = aResult && removeParameter(anEntity.distance);
+ for (int i = 0; i < 4; i++)
+ if (anEntity.param[i] != SLVS_E_UNKNOWN)
+ aResult = removeParameter(anEntity.param[i]) && aResult;
+ for (int i = 0; i < 4; i++)
+ if (anEntity.point[i] != SLVS_E_UNKNOWN)
+ aResult = removeEntity(anEntity.point[i]) && aResult;
+ myNeedToResolve = true;
+ }
+ return aResult;
+}
+
+void SolveSpaceSolver_Storage::removeUnusedEntities()
+{
+ std::set<Slvs_hEntity> anUnusedEntities;
+ std::vector<Slvs_Entity>::const_iterator aEIt = myEntities.begin();
+ for (; aEIt != myEntities.end(); ++aEIt) {
+ if (aEIt->h == aEIt->wrkpl) {
+ // don't remove workplane
+ anUnusedEntities.erase(aEIt->point[0]);
+ anUnusedEntities.erase(aEIt->normal);
+ continue;
+ }
+ anUnusedEntities.insert(aEIt->h);
+ }
+
+ std::vector<Slvs_Constraint>::const_iterator aCIt = myConstraints.begin();
+ for (; aCIt != myConstraints.end(); ++aCIt) {
+ Slvs_hEntity aSubs[6] = {
+ aCIt->entityA, aCIt->entityB,
+ aCIt->entityC, aCIt->entityD,
+ aCIt->ptA, aCIt->ptB};
+ for (int i = 0; i < 6; i++) {
+ if (aSubs[i] != SLVS_E_UNKNOWN) {
+ anUnusedEntities.erase(aSubs[i]);
+ int aPos = Search(aSubs[i], myEntities);
+ if (aPos >= 0 && aPos < (int)myEntities.size()) {
+ for (int j = 0; j < 4; j++)
+ if (myEntities[aPos].point[j] != SLVS_E_UNKNOWN)
+ anUnusedEntities.erase(myEntities[aPos].point[j]);
+ if (myEntities[aPos].distance != SLVS_E_UNKNOWN)
+ anUnusedEntities.erase(myEntities[aPos].distance);
+ }
+ }
+ }
+ }
+
+ std::set<Slvs_hEntity>::const_iterator anEntIt = anUnusedEntities.begin();
+ while (anEntIt != anUnusedEntities.end()) {
+ int aPos = Search(*anEntIt, myEntities);
+ if (aPos < 0 && aPos >= (int)myEntities.size())
+ continue;
+ Slvs_Entity anEntity = myEntities[aPos];
+ // Remove entity if and only if all its parameters unused
+ bool isUsed = false;
+ if (anEntity.distance != SLVS_E_UNKNOWN &&
+ anUnusedEntities.find(anEntity.distance) == anUnusedEntities.end())
+ isUsed = true;
+ for (int i = 0; i < 4 && !isUsed; i++)
+ if (anEntity.point[i] != SLVS_E_UNKNOWN &&
+ anUnusedEntities.find(anEntity.point[i]) == anUnusedEntities.end())
+ isUsed = true;
+ if (isUsed) {
+ anUnusedEntities.erase(anEntity.distance);
+ for (int i = 0; i < 4; i++)
+ if (anEntity.point[i] != SLVS_E_UNKNOWN)
+ anUnusedEntities.erase(anEntity.point[i]);
+ std::set<Slvs_hEntity>::iterator aRemoveIt = anEntIt++;
+ anUnusedEntities.erase(aRemoveIt);
+ continue;
+ }
+ ++anEntIt;
+ }
+
+ for (anEntIt = anUnusedEntities.begin(); anEntIt != anUnusedEntities.end(); ++anEntIt) {
+ int aPos = Search(*anEntIt, myEntities);
+ if (aPos >= 0 && aPos < (int)myEntities.size()) {
+ // Remove entity and its parameters
+ Slvs_Entity anEntity = myEntities[aPos];
+ myEntities.erase(myEntities.begin() + aPos);
+ myEntityMaxID = myEntities.empty() ? SLVS_E_UNKNOWN : myEntities.back().h;
+ if (anEntity.distance != SLVS_E_UNKNOWN)
+ removeParameter(anEntity.distance);
+ for (int i = 0; i < 4; i++)
+ if (anEntity.param[i] != SLVS_E_UNKNOWN)
+ removeParameter(anEntity.param[i]);
+ for (int i = 0; i < 4; i++)
+ if (anEntity.point[i] != SLVS_E_UNKNOWN)
+ removeEntity(anEntity.point[i]);
+ }
+ }
+
+ if (!anUnusedEntities.empty())
+ myNeedToResolve = true;
+}
+
+bool SolveSpaceSolver_Storage::isUsedByConstraints(const Slvs_hEntity& theEntityID) const
+{
+ std::vector<Slvs_Constraint>::const_iterator aCIt = myConstraints.begin();
+ for (; aCIt != myConstraints.end(); ++aCIt) {
+ Slvs_hEntity aSubs[6] = {
+ aCIt->entityA, aCIt->entityB,
+ aCIt->entityC, aCIt->entityD,
+ aCIt->ptA, aCIt->ptB};
+ for (int i = 0; i < 6; i++)
+ if (aSubs[i] != SLVS_E_UNKNOWN && aSubs[i] == theEntityID)
+ return true;
+ }
+ return false;
+}
+
+const Slvs_Entity& SolveSpaceSolver_Storage::getEntity(const Slvs_hEntity& theEntityID) const
+{
+ int aPos = Search(theEntityID, myEntities);
+ if (aPos >= 0 && aPos < (int)myEntities.size())
+ return myEntities[aPos];
+
+ // Entity is not found, return empty object
+ static Slvs_Entity aDummy;
+ aDummy.h = SLVS_E_UNKNOWN;
+ return aDummy;
+}
+
+Slvs_hEntity SolveSpaceSolver_Storage::copyEntity(const Slvs_hEntity& theCopied)
+{
+ int aPos = Search(theCopied, myEntities);
+ if (aPos < 0 || aPos >= (int)myEntities.size())
+ return SLVS_E_UNKNOWN;
+
+ Slvs_Entity aCopy = myEntities[aPos];
+ aCopy.h = SLVS_E_UNKNOWN;
+ int i = 0;
+ while (aCopy.point[i] != SLVS_E_UNKNOWN) {
+ aCopy.point[i] = copyEntity(aCopy.point[i]);
+ i++;
+ }
+ if (aCopy.param[0] != SLVS_E_UNKNOWN) {
+ aPos = Search(aCopy.param[0], myParameters);
+ i = 0;
+ while (aCopy.param[i] != SLVS_E_UNKNOWN) {
+ Slvs_Param aNewParam = myParameters[aPos];
+ aNewParam.h = SLVS_E_UNKNOWN;
+ aCopy.param[i] = addParameter(aNewParam);
+ i++;
+ aPos++;
+ }
+ }
+ return addEntity(aCopy);
+}
+
+void SolveSpaceSolver_Storage::copyEntity(const Slvs_hEntity& theFrom, const Slvs_hEntity& theTo)
+{
+ int aPosFrom = Search(theFrom, myEntities);
+ int aPosTo = Search(theTo, myEntities);
+ if (aPosFrom < 0 || aPosFrom >= (int)myEntities.size() ||
+ aPosTo < 0 || aPosTo >= (int)myEntities.size())
+ return;
+
+ Slvs_Entity aEntFrom = myEntities[aPosFrom];
+ Slvs_Entity aEntTo = myEntities[aPosTo];
+ int i = 0;
+ while (aEntFrom.point[i] != SLVS_E_UNKNOWN) {
+ copyEntity(aEntFrom.point[i], aEntTo.point[i]);
+ i++;
+ }
+ if (aEntFrom.param[0] != SLVS_E_UNKNOWN) {
+ aPosFrom = Search(aEntFrom.param[0], myParameters);
+ aPosTo = Search(aEntTo.param[0], myParameters);
+ i = 0;
+ while (aEntFrom.param[i] != SLVS_E_UNKNOWN) {
+ myParameters[aPosTo++].val = myParameters[aPosFrom++].val;
+ i++;
+ }
+ }
+}
+
+
+bool SolveSpaceSolver_Storage::isPointFixed(
+ const Slvs_hEntity& thePointID, Slvs_hConstraint& theFixed, bool theAccurate) const
+{
+ // Search the set of coincident points
+ std::set<Slvs_hEntity> aCoincident;
+ aCoincident.insert(thePointID);
+
+ // Check whether one of coincident points is out-of-group
+ std::set<Slvs_hEntity>::const_iterator aCoincIt = aCoincident.begin();
+ for (; aCoincIt != aCoincident.end(); ++aCoincIt) {
+ Slvs_Entity aPoint = getEntity(*aCoincIt);
+ if (aPoint.group == SLVS_G_OUTOFGROUP)
+ return true;
+ }
+
+ // Search the Rigid constraint
+ theFixed = SLVS_C_UNKNOWN;
+ std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+ for (; aConstrIter != myConstraints.end(); aConstrIter++)
+ if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
+ aCoincident.find(aConstrIter->ptA) != aCoincident.end()) {
+ theFixed = aConstrIter->h;
+ if (aConstrIter->ptA == thePointID)
+ return true;
+ }
+ if (theFixed != SLVS_C_UNKNOWN)
+ return true;
+
+ if (theAccurate) {
+ // Try to find the fixed entity which uses such point or its coincidence
+ std::vector<Slvs_Entity>::const_iterator anEntIter = myEntities.begin();
+ for (; anEntIter != myEntities.end(); anEntIter++) {
+ for (int i = 0; i < 4; i++) {
+ Slvs_hEntity aPt = anEntIter->point[i];
+ if (aPt != SLVS_E_UNKNOWN &&
+ (aPt == thePointID || aCoincident.find(aPt) != aCoincident.end())) {
+ if (isEntityFixed(anEntIter->h, true))
+ return true;
+ }
+ }
+ }
+ }
+ return SLVS_E_UNKNOWN;
+}
+
+bool SolveSpaceSolver_Storage::isEntityFixed(const Slvs_hEntity& theEntityID, bool theAccurate) const
+{
+ int aPos = Search(theEntityID, myEntities);
+ if (aPos < 0 || aPos >= (int)myEntities.size())
+ return false;
+
+ // Firstly, find how many points are under Rigid constraint
+ int aNbFixed = 0;
+ for (int i = 0; i < 4; i++) {
+ Slvs_hEntity aPoint = myEntities[aPos].point[i];
+ if (aPoint == SLVS_E_UNKNOWN)
+ continue;
+
+ std::set<Slvs_hEntity> aCoincident;
+ aCoincident.insert(aPoint);
+
+ // Search the Rigid constraint
+ std::vector<Slvs_Constraint>::const_iterator aConstrIter = myConstraints.begin();
+ for (; aConstrIter != myConstraints.end(); aConstrIter++)
+ if (aConstrIter->type == SLVS_C_WHERE_DRAGGED &&
+ aCoincident.find(aConstrIter->ptA) != aCoincident.end())
+ aNbFixed++;
+ }
+
+ std::list<Slvs_Constraint> aList;
+ std::list<Slvs_Constraint>::iterator anIt;
+ Slvs_hConstraint aTempID; // used in isPointFixed() method
+
+ if (myEntities[aPos].type == SLVS_E_LINE_SEGMENT) {
+ if (aNbFixed == 2)
+ return true;
+ else if (aNbFixed == 0 || !theAccurate)
+ return false;
+ // Additional check (the line may be fixed if it is used by different constraints):
+ // 1. The line is used in Equal constraint, another entity is fixed and there is a fixed point on line
+ aList = getConstraintsByType(SLVS_C_PT_ON_LINE);
+ for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+ if (anIt->entityA == theEntityID && isPointFixed(anIt->ptA, aTempID))
+ break;
+ if (anIt != aList.end()) {
+ aList = getConstraintsByType(SLVS_C_EQUAL_LENGTH_LINES);
+ aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN));
+ for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+ if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
+ Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
+ if (isEntityFixed(anOther, false))
+ return true;
+ }
+ }
+ // 2. The line is used in Parallel/Perpendicular/Vertical/Horizontal and Length constraints
+ aList = getConstraintsByType(SLVS_C_PARALLEL);
+ aList.splice(aList.end(), getConstraintsByType(SLVS_C_PERPENDICULAR));
+ aList.splice(aList.end(), getConstraintsByType(SLVS_C_VERTICAL));
+ aList.splice(aList.end(), getConstraintsByType(SLVS_C_HORIZONTAL));
+ for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+ if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
+ Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
+ if (isEntityFixed(anOther, false))
+ break;
+ }
+ if (anIt != aList.end()) {
+ aList = getConstraintsByType(SLVS_C_PT_PT_DISTANCE);
+ for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+ if ((anIt->ptA == myEntities[aPos].point[0] && anIt->ptB == myEntities[aPos].point[1]) ||
+ (anIt->ptA == myEntities[aPos].point[1] && anIt->ptB == myEntities[aPos].point[0]))
+ return true;
+ }
+ // 3. Another verifiers ...
+ } else if (myEntities[aPos].type == SLVS_E_CIRCLE) {
+ if (aNbFixed == 0)
+ return false;
+ // Search for Diameter constraint
+ aList = getConstraintsByType(SLVS_C_DIAMETER);
+ for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+ if (anIt->entityA == theEntityID)
+ return true;
+ if (!theAccurate)
+ return false;
+ // Additional check (the circle may be fixed if it is used by different constraints):
+ // 1. The circle is used in Equal constraint and another entity is fixed
+ aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS);
+ for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+ if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
+ Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
+ if (isEntityFixed(anOther, false))
+ return true;
+ }
+ // 2. Another verifiers ...
+ } else if (myEntities[aPos].type == SLVS_E_ARC_OF_CIRCLE) {
+ if (aNbFixed > 2)
+ return true;
+ else if (aNbFixed <= 1)
+ return false;
+ // Search for Diameter constraint
+ aList = getConstraintsByType(SLVS_C_DIAMETER);
+ for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+ if (anIt->entityA == theEntityID)
+ return true;
+ if (!theAccurate)
+ return false;
+ // Additional check (the arc may be fixed if it is used by different constraints):
+ // 1. The arc is used in Equal constraint and another entity is fixed
+ aList = getConstraintsByType(SLVS_C_EQUAL_RADIUS);
+ aList.splice(aList.end(), getConstraintsByType(SLVS_C_EQUAL_LINE_ARC_LEN));
+ for (anIt = aList.begin(); anIt != aList.end(); anIt++)
+ if (anIt->entityA == theEntityID || anIt->entityB == theEntityID) {
+ Slvs_hEntity anOther = anIt->entityA == theEntityID ? anIt->entityB : anIt->entityA;
+ if (isEntityFixed(anOther, false))
+ return true;
+ }
+ // 2. Another verifiers ...
+ }
+ return false;
+}
+
+
+Slvs_hConstraint SolveSpaceSolver_Storage::addConstraint(const Slvs_Constraint& theConstraint)
+{
+ if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
+ // Constraint is already used, rewrite it
+ return updateConstraint(theConstraint);
+ }
+
+ Slvs_Constraint aConstraint = theConstraint;
+
+ // Find a constraint with same type uses same arguments to show user overconstraint situation
+ std::vector<Slvs_Constraint>::iterator aCIt = myConstraints.begin();
+ for (; aCIt != myConstraints.end(); aCIt++) {
+ if (aConstraint.type != aCIt->type)
+ continue;
+ if (aConstraint.ptA == aCIt->ptA && aConstraint.ptB == aCIt->ptB &&
+ aConstraint.entityA == aCIt->entityA && aConstraint.entityB == aCIt->entityB &&
+ aConstraint.entityC == aCIt->entityC && aConstraint.entityD == aCIt->entityD)
+ myDuplicatedConstraint = true;
+ }
+
+ if (aConstraint.h > myConstrMaxID)
+ myConstrMaxID = aConstraint.h;
+ else
+ aConstraint.h = ++myConstrMaxID;
+ myConstraints.push_back(aConstraint);
+ myNeedToResolve = true;
+ return aConstraint.h;
+}
+
+Slvs_hConstraint SolveSpaceSolver_Storage::updateConstraint(const Slvs_Constraint& theConstraint)
+{
+ if (theConstraint.h > 0 && theConstraint.h <= myConstrMaxID) {
+ // Constraint already used, rewrite it
+ int aPos = Search(theConstraint.h, myConstraints);
+ if (aPos >= 0 && aPos < (int)myConstraints.size()) {
+ myNeedToResolve = myNeedToResolve || IsNotEqual(myConstraints[aPos], theConstraint);
+ myConstraints[aPos] = theConstraint;
+ return theConstraint.h;
+ }
+ }
+
+ // Constraint is not found, add new one
+ Slvs_Constraint aConstraint = theConstraint;
+ aConstraint.h = 0;
+ return addConstraint(aConstraint);
+}
+
+bool SolveSpaceSolver_Storage::removeConstraint(const Slvs_hConstraint& theConstraintID)
+{
+ bool aResult = true;
+ int aPos = Search(theConstraintID, myConstraints);
+ if (aPos >= 0 && aPos < (int)myConstraints.size()) {
+ Slvs_Constraint aConstraint = myConstraints[aPos];
+ myConstraints.erase(myConstraints.begin() + aPos);
+ myConstrMaxID = myConstraints.empty() ? SLVS_E_UNKNOWN : myConstraints.back().h;
+ myNeedToResolve = true;
+
+ // Remove all entities
+ Slvs_hEntity anEntities[6] = {aConstraint.ptA, aConstraint.ptB,
+ aConstraint.entityA, aConstraint.entityB,
+ aConstraint.entityC, aConstraint.entityD};
+ for (int i = 0; i < 6; i++)
+ if (anEntities[i] != SLVS_E_UNKNOWN)
+ aResult = removeEntity(anEntities[i]) && aResult;
+ // remove temporary fixed point, if available
+ if (myFixed == theConstraintID)
+ myFixed = SLVS_E_UNKNOWN;
+ if (myDuplicatedConstraint) {
+ // Check the duplicated constraints are still available
+ myDuplicatedConstraint = false;
+ std::vector<Slvs_Constraint>::const_iterator anIt1 = myConstraints.begin();
+ std::vector<Slvs_Constraint>::const_iterator anIt2 = myConstraints.begin();
+ for (; anIt1 != myConstraints.end() && !myDuplicatedConstraint; anIt1++)
+ for (anIt2 = anIt1+1; anIt2 != myConstraints.end() && !myDuplicatedConstraint; anIt2++) {
+ if (anIt1->type != anIt2->type)
+ continue;
+ if (anIt1->ptA == anIt2->ptA && anIt1->ptB == anIt2->ptB &&
+ anIt1->entityA == anIt2->entityA && anIt1->entityB == anIt2->entityB &&
+ anIt1->entityC == anIt2->entityC && anIt1->entityD == anIt2->entityD)
+ myDuplicatedConstraint = true;
+ }
+ }
+ }
+ return aResult;
+}
+
+const Slvs_Constraint& SolveSpaceSolver_Storage::getConstraint(const Slvs_hConstraint& theConstraintID) const
+{
+ int aPos = Search(theConstraintID, myConstraints);
+ if (aPos >= 0 && aPos < (int)myConstraints.size())
+ return myConstraints[aPos];
+
+ // Constraint is not found, return empty object
+ static Slvs_Constraint aDummy;
+ aDummy.h = 0;
+ return aDummy;
+}
+
+std::list<Slvs_Constraint> SolveSpaceSolver_Storage::getConstraintsByType(int theConstraintType) const
+{
+ std::list<Slvs_Constraint> aResult;
+ std::vector<Slvs_Constraint>::const_iterator aCIter = myConstraints.begin();
+ for (; aCIter != myConstraints.end(); aCIter++)
+ if (aCIter->type == theConstraintType)
+ aResult.push_back(*aCIter);
+ return aResult;
+}
+
+
+void SolveSpaceSolver_Storage::addConstraintWhereDragged(const Slvs_hConstraint& theConstraintID)
+{
+ if (myFixed != SLVS_E_UNKNOWN)
+ return; // the point is already fixed
+ int aPos = Search(theConstraintID, myConstraints);
+ if (aPos >= 0 && aPos < (int)myConstraints.size())
+ myFixed = theConstraintID;
+}
+
+void SolveSpaceSolver_Storage::addTemporaryConstraint(const Slvs_hConstraint& theConstraintID)
+{
+ myTemporaryConstraints.insert(theConstraintID);
+}
+
+void SolveSpaceSolver_Storage::removeAllTemporary()
+{
+ myTemporaryConstraints.clear();
+}
+
+size_t SolveSpaceSolver_Storage::removeTemporary(size_t theNbConstraints)
+{
+ if (myTemporaryConstraints.empty())
+ return 0;
+ // Search the point-on-line or a non-rigid constraint
+ std::set<Slvs_hConstraint>::iterator aCIt = myTemporaryConstraints.begin();
+ for (; aCIt != myTemporaryConstraints.end(); aCIt++) {
+ int aPos = Search(*aCIt, myConstraints);
+ if (aPos >= (int)myConstraints.size() || myConstraints[aPos].type != SLVS_C_WHERE_DRAGGED)
+ break;
+ std::vector<Slvs_Constraint>::iterator anIt = myConstraints.begin();
+ for (; anIt != myConstraints.end(); anIt++)
+ if (anIt->type == SLVS_C_PT_ON_LINE && anIt->ptA == myConstraints[aPos].ptA)
+ break;
+ if (anIt != myConstraints.end())
+ break;
+ }
+ if (aCIt == myTemporaryConstraints.end())
+ aCIt = myTemporaryConstraints.begin();
+ bool aNewFixed = false;
+
+ size_t aNbRemain = theNbConstraints;
+ while (aNbRemain > 0 && aCIt != myTemporaryConstraints.end()) {
+ aNewFixed = aNewFixed || (*aCIt == myFixed);
+ --aNbRemain;
+
+ std::set<Slvs_hConstraint>::iterator aRemoveIt = aCIt++;
+ removeConstraint(*aRemoveIt);
+ myTemporaryConstraints.erase(aRemoveIt);
+ if (aCIt == myTemporaryConstraints.end())
+ aCIt = myTemporaryConstraints.begin();
+ }
+
+ if (aNewFixed) {
+ for (aCIt = myTemporaryConstraints.begin(); aCIt != myTemporaryConstraints.end(); aCIt++) {
+ int aPos = Search(*aCIt, myConstraints);
+ if (myConstraints[aPos].type == SLVS_C_WHERE_DRAGGED) {
+ myFixed = *aCIt;
+ break;
+ }
+ }
+ }
+ return myTemporaryConstraints.size();
+}
+
+bool SolveSpaceSolver_Storage::isTemporary(const Slvs_hConstraint& theConstraintID) const
+{
+ return myTemporaryConstraints.find(theConstraintID) != myTemporaryConstraints.end();
+}
+
+
+
+void SolveSpaceSolver_Storage::initializeSolver(SolverPtr theSolver)
+{
+ std::shared_ptr<SolveSpaceSolver_Solver> aSolver =
+ std::dynamic_pointer_cast<SolveSpaceSolver_Solver>(theSolver);
+ if (!aSolver)
+ return;
+
+ if (myConstraints.empty()) {
+ // Adjust all arc to place their points correctly
+ std::vector<Slvs_Entity>::const_iterator anEntIt = myEntities.begin();
+ for (; anEntIt != myEntities.end(); ++anEntIt)
+ if (anEntIt->type == SLVS_E_ARC_OF_CIRCLE)
+ adjustArc(*anEntIt);
+ }
+
+ aSolver->setParameters(myParameters.data(), (int)myParameters.size());
+ aSolver->setEntities(myEntities.data(), (int)myEntities.size());
+
+ // Copy constraints excluding the fixed one
+ std::vector<Slvs_Constraint> aConstraints = myConstraints;
+ if (myFixed != SLVS_E_UNKNOWN) {
+ Slvs_hEntity aFixedPoint = SLVS_E_UNKNOWN;
+ std::vector<Slvs_Constraint>::iterator anIt = aConstraints.begin();
+ for (; anIt != aConstraints.end(); anIt++)
+ if (anIt->h == myFixed) {
+ aFixedPoint = anIt->ptA;
+ aConstraints.erase(anIt);
+ break;
+ }
+ // set dragged parameters
+ int aPos = Search(aFixedPoint, myEntities);
+ aSolver->setDraggedParameters(myEntities[aPos].param);
+ }
+ aSolver->setConstraints(aConstraints.data(), (int)aConstraints.size());
+}
+
+
+bool SolveSpaceSolver_Storage::isEqual(
+ const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) const
+{
+ // Precise checking of coincidence: verify that points have equal coordinates
+ int aEnt1Pos = Search(thePoint1, myEntities);
+ int aEnt2Pos = Search(thePoint2, myEntities);
+ if (aEnt1Pos >= 0 && aEnt1Pos < (int)myEntities.size() &&
+ aEnt2Pos >= 0 && aEnt2Pos < (int)myEntities.size()) {
+ double aDist[2];
+ int aParamPos;
+ for (int i = 0; i < 2; i++) {
+ aParamPos = Search(myEntities[aEnt1Pos].param[i], myParameters);
+ aDist[i] = myParameters[aParamPos].val;
+ aParamPos = Search(myEntities[aEnt2Pos].param[i], myParameters);
+ aDist[i] -= myParameters[aParamPos].val;
+ }
+ if (aDist[0] * aDist[0] + aDist[1] * aDist[1] < tolerance * tolerance)
+ return true;
+ }
+ return false;
+}
+
+
+std::vector<Slvs_hConstraint> SolveSpaceSolver_Storage::fixEntity(const Slvs_hEntity& theEntity)
+{
+ std::vector<Slvs_hConstraint> aNewConstraints;
+
+ int aPos = Search(theEntity, myEntities);
+ if (aPos >= 0 && aPos < (int)myEntities.size()) {
+ switch (myEntities[aPos].type) {
+ case SLVS_E_POINT_IN_2D:
+ case SLVS_E_POINT_IN_3D:
+ fixPoint(myEntities[aPos], aNewConstraints);
+ break;
+ case SLVS_E_LINE_SEGMENT:
+ fixLine(myEntities[aPos], aNewConstraints);
+ break;
+ case SLVS_E_CIRCLE:
+ fixCircle(myEntities[aPos], aNewConstraints);
+ break;
+ case SLVS_E_ARC_OF_CIRCLE:
+ fixArc(myEntities[aPos], aNewConstraints);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return aNewConstraints;
+}
+
+void SolveSpaceSolver_Storage::fixPoint(const Slvs_Entity& thePoint,
+ std::vector<Slvs_hConstraint>& theCreated)
+{
+ Slvs_Constraint aConstraint;
+ Slvs_hConstraint aConstrID = SLVS_E_UNKNOWN;
+ bool isFixed = isPointFixed(thePoint.h, aConstrID, true);
+ bool isForceUpdate = (isFixed && isTemporary(aConstrID));
+ if (!isForceUpdate) { // create new constraint
+ if (isFixed) return;
+ aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, thePoint.group, SLVS_C_WHERE_DRAGGED, thePoint.wrkpl,
+ 0.0, thePoint.h, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+ aConstraint.h = addConstraint(aConstraint);
+ theCreated.push_back(aConstraint.h);
+ } else { // update already existent constraint
+ if (!isFixed || aConstrID == SLVS_E_UNKNOWN)
+ return;
+ int aPos = Search(aConstrID, myConstraints);
+ if (aPos >= 0 && aPos < (int)myConstraints.size())
+ myConstraints[aPos].ptA = thePoint.h;
+ }
+}
+
+void SolveSpaceSolver_Storage::fixLine(const Slvs_Entity& theLine,
+ std::vector<Slvs_hConstraint>& theCreated)
+{
+ Slvs_Entity aPoint[2] = {
+ getEntity(theLine.point[0]),
+ getEntity(theLine.point[1])
+ };
+
+ Slvs_Constraint anEqual;
+ if (isAxisParallel(theLine.h)) {
+ // Fix one point and a line length
+ Slvs_hConstraint aFixed;
+ if (!isPointFixed(theLine.point[0], aFixed, true) &&
+ !isPointFixed(theLine.point[1], aFixed, true))
+ fixPoint(aPoint[0], theCreated);
+ if (!isUsedInEqual(theLine.h, anEqual)) {
+ // Check the distance is not set yet
+ std::vector<Slvs_Constraint>::const_iterator aDistIt = myConstraints.begin();
+ for (; aDistIt != myConstraints.end(); ++aDistIt)
+ if ((aDistIt->type == SLVS_C_PT_PT_DISTANCE) &&
+ ((aDistIt->ptA == theLine.point[0] && aDistIt->ptB == theLine.point[1]) ||
+ (aDistIt->ptA == theLine.point[1] && aDistIt->ptB == theLine.point[0])))
+ return;
+ // Calculate distance between points on the line
+ double aCoords[4];
+ for (int i = 0; i < 2; i++)
+ for (int j = 0; j < 2; j++) {
+ Slvs_Param aParam = getParameter(aPoint[i].param[j]);
+ aCoords[2*i+j] = aParam.val;
+ }
+
+ double aLength = sqrt((aCoords[2] - aCoords[0]) * (aCoords[2] - aCoords[0]) +
+ (aCoords[3] - aCoords[1]) * (aCoords[3] - aCoords[1]));
+ // fix line length
+ Slvs_Constraint aDistance = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theLine.group,
+ SLVS_C_PT_PT_DISTANCE, theLine.wrkpl, aLength,
+ theLine.point[0], theLine.point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+ aDistance.h = addConstraint(aDistance);
+ theCreated.push_back(aDistance.h);
+ }
+ return;
+ }
+ else if (isUsedInEqual(theLine.h, anEqual)) {
+ // Check another entity of Equal is already fixed
+ Slvs_hEntity anOtherEntID = anEqual.entityA == theLine.h ? anEqual.entityB : anEqual.entityA;
+ if (isEntityFixed(anOtherEntID, true)) {
+ // Fix start point of the line (if end point is not fixed yet) ...
+ Slvs_hConstraint anEndFixedID = SLVS_E_UNKNOWN;
+ bool isFixed = isPointFixed(theLine.point[1], anEndFixedID, true);
+ if (isFixed == SLVS_E_UNKNOWN)
+ fixPoint(aPoint[0], theCreated);
+ // ... and create fixed point lying on this line
+ Slvs_hEntity aPointToCopy = anEndFixedID == SLVS_E_UNKNOWN ? theLine.point[1] : theLine.point[0];
+ // Firstly, search already fixed point on line
+ bool isPonLineFixed = false;
+ Slvs_hEntity aFixedPoint;
+ std::vector<Slvs_Constraint>::const_iterator aPLIter = myConstraints.begin();
+ for (; aPLIter != myConstraints.end() && !isPonLineFixed; ++aPLIter)
+ if (aPLIter->type == SLVS_C_PT_ON_LINE && aPLIter->entityA == theLine.h) {
+ isPonLineFixed = isPointFixed(aPLIter->ptA, anEndFixedID);
+ aFixedPoint = aPLIter->ptA;
+ }
+
+ if (isPonLineFixed) { // update existent constraint
+ copyEntity(aPointToCopy, aFixedPoint);
+ } else { // create new constraint
+ Slvs_hEntity aCopied = copyEntity(aPointToCopy);
+ Slvs_Constraint aPonLine = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theLine.group, SLVS_C_PT_ON_LINE,
+ theLine.wrkpl, 0.0, aCopied, SLVS_E_UNKNOWN, theLine.h, SLVS_E_UNKNOWN);
+ aPonLine.h = addConstraint(aPonLine);
+ theCreated.push_back(aPonLine.h);
+ fixPoint(getEntity(aCopied), theCreated);
+ }
+ return;
+ }
+ }
+
+ // Fix both points
+ for (int i = 0; i < 2; i++)
+ fixPoint(aPoint[i], theCreated);
+}
+
+void SolveSpaceSolver_Storage::fixCircle(const Slvs_Entity& theCircle,
+ std::vector<Slvs_hConstraint>& theCreated)
+{
+ bool isFixRadius = true;
+ // Verify the arc is under Equal constraint
+ Slvs_Constraint anEqual;
+ if (isUsedInEqual(theCircle.h, anEqual)) {
+ // Check another entity of Equal is already fixed
+ Slvs_hEntity anOtherEntID = anEqual.entityA == theCircle.h ? anEqual.entityB : anEqual.entityA;
+ if (isEntityFixed(anOtherEntID, true))
+ isFixRadius = false;
+ }
+
+ fixPoint(getEntity(theCircle.point[0]), theCreated);
+
+ if (isFixRadius) {
+ // Search the radius is already fixed
+ std::vector<Slvs_Constraint>::const_iterator aDiamIter = myConstraints.begin();
+ for (; aDiamIter != myConstraints.end(); ++aDiamIter)
+ if (aDiamIter->type == SLVS_C_DIAMETER && aDiamIter->entityA == theCircle.h)
+ return;
+
+ // Fix radius of a circle
+ const Slvs_Entity& aRadEnt = getEntity(theCircle.distance);
+ double aRadius = getParameter(aRadEnt.param[0]).val;
+ Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theCircle.group, SLVS_C_DIAMETER,
+ theCircle.wrkpl, aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, theCircle.h, SLVS_E_UNKNOWN);
+ aFixedR.h = addConstraint(aFixedR);
+ theCreated.push_back(aFixedR.h);
+ }
+}
+
+void SolveSpaceSolver_Storage::fixArc(const Slvs_Entity& theArc,
+ std::vector<Slvs_hConstraint>& theCreated)
+{
+ Slvs_Entity aPoint[3] = {
+ getEntity(theArc.point[0]),
+ getEntity(theArc.point[1]),
+ getEntity(theArc.point[2])
+ };
+
+ bool isFixRadius = true;
+ std::list<Slvs_Entity> aPointsToFix;
+ aPointsToFix.push_back(aPoint[1]);
+ aPointsToFix.push_back(aPoint[2]);
+
+ // Verify the arc is under Equal constraint
+ Slvs_Constraint anEqual;
+ if (isUsedInEqual(theArc.h, anEqual)) {
+ // Check another entity of Equal is already fixed
+ Slvs_hEntity anOtherEntID = anEqual.entityA == theArc.h ? anEqual.entityB : anEqual.entityA;
+ if (isEntityFixed(anOtherEntID, true)) {
+ isFixRadius = false;
+ Slvs_Entity anOtherEntity = getEntity(anOtherEntID);
+ if (anOtherEntity.type == SLVS_E_LINE_SEGMENT) {
+ aPointsToFix.pop_back();
+ aPointsToFix.push_back(aPoint[0]);
+ }
+ }
+ }
+
+ Slvs_hConstraint aConstrID;
+ int aNbPointsToFix = 2; // number of fixed points for the arc
+ if (isPointFixed(theArc.point[0], aConstrID, true))
+ aNbPointsToFix--;
+
+ double anArcPoints[3][2];
+ for (int i = 0; i < 3; i++) {
+ const Slvs_Entity& aPointOnArc = getEntity(theArc.point[i]);
+ for (int j = 0; j < 2; j++)
+ anArcPoints[i][j] = getParameter(aPointOnArc.param[j]).val;
+ }
+
+ // Radius of the arc
+ std::shared_ptr<GeomAPI_Pnt2d> aCenter(new GeomAPI_Pnt2d(anArcPoints[0][0], anArcPoints[0][1]));
+ std::shared_ptr<GeomAPI_Pnt2d> aStart(new GeomAPI_Pnt2d(anArcPoints[1][0], anArcPoints[1][1]));
+ double aRadius = aCenter->distance(aStart);
+
+ // Update end point of the arc to be on a curve
+ std::shared_ptr<GeomAPI_Pnt2d> anEnd(new GeomAPI_Pnt2d(anArcPoints[2][0], anArcPoints[2][1]));
+ double aDistance = anEnd->distance(aCenter);
+ std::shared_ptr<GeomAPI_XY> aDir = anEnd->xy()->decreased(aCenter->xy());
+ if (aDistance < tolerance)
+ aDir = aStart->xy()->decreased(aCenter->xy())->multiplied(-1.0);
+ else
+ aDir = aDir->multiplied(aRadius / aDistance);
+ double xy[2] = {aCenter->x() + aDir->x(), aCenter->y() + aDir->y()};
+ const Slvs_Entity& aEndPoint = getEntity(theArc.point[2]);
+ for (int i = 0; i < 2; i++) {
+ Slvs_Param aParam = getParameter(aEndPoint.param[i]);
+ aParam.val = xy[i];
+ updateParameter(aParam);
+ }
+
+ std::list<Slvs_Entity>::iterator aPtIt = aPointsToFix.begin();
+ for (; aNbPointsToFix > 0; aPtIt++, aNbPointsToFix--)
+ fixPoint(*aPtIt, theCreated);
+
+ if (isFixRadius) {
+ // Fix radius of the arc
+ bool isExists = false;
+ std::vector<Slvs_Constraint>::iterator anIt = myConstraints.begin();
+ for (; anIt != myConstraints.end() && !isExists; ++anIt)
+ if (anIt->type == SLVS_C_DIAMETER && anIt->entityA == theArc.h)
+ isExists = true;
+ if (!isExists) {
+ Slvs_Constraint aFixedR = Slvs_MakeConstraint(SLVS_E_UNKNOWN, theArc.group, SLVS_C_DIAMETER,
+ theArc.wrkpl, aRadius * 2.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, theArc.h, SLVS_E_UNKNOWN);
+ aFixedR.h = addConstraint(aFixedR);
+ theCreated.push_back(aFixedR.h);
+ }
+ }
+}
+
+
+bool SolveSpaceSolver_Storage::isAxisParallel(const Slvs_hEntity& theEntity) const
+{
+ std::vector<Slvs_Constraint>::const_iterator anIter = myConstraints.begin();
+ for (; anIter != myConstraints.end(); anIter++)
+ if ((anIter->type == SLVS_C_HORIZONTAL || anIter->type == SLVS_C_VERTICAL) &&
+ anIter->entityA == theEntity)
+ return true;
+ return false;
+}
+
+bool SolveSpaceSolver_Storage::isUsedInEqual(
+ const Slvs_hEntity& theEntity, Slvs_Constraint& theEqual) const
+{
+ // Check the entity is used in Equal constraint
+ std::vector<Slvs_Constraint>::const_iterator anEqIter = myConstraints.begin();
+ for (; anEqIter != myConstraints.end(); anEqIter++)
+ if ((anEqIter->type == SLVS_C_EQUAL_LENGTH_LINES ||
+ anEqIter->type == SLVS_C_EQUAL_LINE_ARC_LEN ||
+ anEqIter->type == SLVS_C_EQUAL_RADIUS) &&
+ (anEqIter->entityA == theEntity || anEqIter->entityB == theEntity)) {
+ theEqual = *anEqIter;
+ return true;
+ }
+ return false;
+}
+
+void SolveSpaceSolver_Storage::setTemporary(ConstraintPtr theConstraint)
+{
+ // TODO
+}
+
+bool SolveSpaceSolver_Storage::removeConstraint(ConstraintPtr theConstraint)
+{
+ std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::iterator
+ aFound = myConstraintMap.find(theConstraint);
+ if (aFound == myConstraintMap.end())
+ return true; // no constraint, already deleted
+
+ // Remove constraint
+ std::list<ConstraintWrapperPtr> aConstrList = aFound->second;
+ myConstraintMap.erase(aFound);
+ // Remove SolveSpace constraints
+ bool isFullyRemoved = true;
+ std::list<ConstraintWrapperPtr>::iterator anIt = aConstrList.begin();
+ while (anIt != aConstrList.end()) {
+ if (remove(*anIt)) {
+ std::list<ConstraintWrapperPtr>::iterator aRemoveIt = anIt++;
+ aConstrList.erase(aRemoveIt);
+ } else {
+ isFullyRemoved = false;
+ ++anIt;
+ }
+ }
+ if (!isFullyRemoved)
+ myConstraintMap[theConstraint] = aConstrList;
+ return isFullyRemoved;
+}
+
+template <class ENT_TYPE>
+static bool isUsed(ConstraintWrapperPtr theConstraint, ENT_TYPE theEntity)
+{
+ std::list<EntityWrapperPtr>::const_iterator anEntIt = theConstraint->entities().begin();
+ for (; anEntIt != theConstraint->entities().end(); ++anEntIt)
+ if (std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anEntIt)->isBase(theEntity))
+ return true;
+ return false;
+}
+
+static bool isUsed(EntityWrapperPtr theFeature, AttributePtr theSubEntity)
+{
+ std::list<EntityWrapperPtr>::const_iterator aSubIt = theFeature->subEntities().begin();
+ for (; aSubIt != theFeature->subEntities().end(); ++aSubIt)
+ if (std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*aSubIt)->isBase(theSubEntity))
+ return true;
+ return false;
+}
+
+bool SolveSpaceSolver_Storage::isUsed(FeaturePtr theFeature) const
+{
+ std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
+ aCIt = myConstraintMap.begin();
+ std::list<ConstraintWrapperPtr>::const_iterator aCWIt;
+ for (; aCIt != myConstraintMap.end(); ++aCIt)
+ for (aCWIt = aCIt->second.begin(); aCWIt != aCIt->second.end(); ++aCWIt)
+ if (::isUsed(*aCWIt, theFeature))
+ return true;
+ // check attributes
+ std::list<AttributePtr> anAttrList = theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
+ std::list<AttributePtr>::const_iterator anIt = anAttrList.begin();
+ for (; anIt != anAttrList.end(); ++anIt)
+ if (isUsed(*anIt))
+ return true;
+ return false;
+}
+
+bool SolveSpaceSolver_Storage::isUsed(AttributePtr theAttribute) const
+{
+ AttributePtr anAttribute = theAttribute;
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
+ if (aRefAttr) {
+ if (aRefAttr->isObject())
+ return isUsed(ModelAPI_Feature::feature(aRefAttr->object()));
+ else
+ anAttribute = aRefAttr->attr();
+ }
+
+ std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
+ aCIt = myConstraintMap.begin();
+ std::list<ConstraintWrapperPtr>::const_iterator aCWIt;
+ for (; aCIt != myConstraintMap.end(); ++aCIt)
+ for (aCWIt = aCIt->second.begin(); aCWIt != aCIt->second.end(); ++aCWIt)
+ if (::isUsed(*aCWIt, anAttribute))
+ return true;
+ return false;
+}
+
+
+bool SolveSpaceSolver_Storage::removeEntity(FeaturePtr theFeature)
+{
+ std::map<FeaturePtr, EntityWrapperPtr>::iterator aFound = myFeatureMap.find(theFeature);
+ if (aFound == myFeatureMap.end())
+ return false; // feature not found, nothing to delete
+
+ // Check the feature is not used by constraints
+ if (isUsed(theFeature))
+ return false; // the feature is used, don't remove it
+
+ // Remove feature
+ EntityWrapperPtr anEntity = aFound->second;
+ myFeatureMap.erase(aFound);
+ if (remove(anEntity))
+ return true;
+ // feature is not removed, revert operation
+ myFeatureMap[theFeature] = anEntity;
+ return false;
+}
+
+bool SolveSpaceSolver_Storage::removeEntity(AttributePtr theAttribute)
+{
+ std::map<AttributePtr, EntityWrapperPtr>::iterator aFound = myAttributeMap.find(theAttribute);
+ if (aFound == myAttributeMap.end())
+ return false; // attribute not found, nothing to delete
+
+ // Check the attribute is not used by constraints
+ if (isUsed(theAttribute))
+ return false; // the attribute is used, don't remove it
+ // Check the attribute is not used by other features
+ std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
+ for (; aFIt != myFeatureMap.end(); ++aFIt)
+ if (::isUsed(aFIt->second, theAttribute)) // the attribute is used, don't remove it
+ return false;
+
+ // Remove attribute
+ EntityWrapperPtr anEntity = aFound->second;
+ myAttributeMap.erase(aFound);
+ if (remove(anEntity))
+ return true;
+ // attribute is not removed, revert operation
+ myAttributeMap[theAttribute] = anEntity;
+ return false;
+}
+
+
+bool SolveSpaceSolver_Storage::remove(ConstraintWrapperPtr theConstraint)
+{
+ std::shared_ptr<SolveSpaceSolver_ConstraintWrapper> aConstraint =
+ std::dynamic_pointer_cast<SolveSpaceSolver_ConstraintWrapper>(theConstraint);
+
+ // verify whether the constraint has duplicated
+ SameConstraintMap::iterator anEqIt = myEqualConstraints.begin();
+ for (; anEqIt != myEqualConstraints.end(); ++anEqIt)
+ if (anEqIt->find(aConstraint) != anEqIt->end()) {
+ anEqIt->erase(aConstraint);
+ break;
+ }
+ if (anEqIt != myEqualConstraints.end())
+ return true;
+
+ bool isFullyRemoved = removeConstraint((Slvs_hConstraint)aConstraint->id());
+
+ std::list<EntityWrapperPtr>::const_iterator anIt = aConstraint->entities().begin();
+ for (; anIt != aConstraint->entities().end(); ++anIt) {
+ std::shared_ptr<SolveSpaceSolver_EntityWrapper> anEntity =
+ std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anIt);
+ FeaturePtr aBaseFeature = anEntity->baseFeature();
+ if (aBaseFeature)
+ isFullyRemoved = removeEntity(aBaseFeature) && isFullyRemoved;
+ else
+ isFullyRemoved = removeEntity(anEntity->baseAttribute()) && isFullyRemoved;
+ }
+
+ return isFullyRemoved;
+}
+
+bool SolveSpaceSolver_Storage::remove(EntityWrapperPtr theEntity)
+{
+ std::shared_ptr<SolveSpaceSolver_EntityWrapper> anEntity =
+ std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(theEntity);
+ bool isFullyRemoved = removeEntity((Slvs_hEntity)anEntity->id());
+
+ std::list<EntityWrapperPtr>::const_iterator anEntIt = anEntity->subEntities().begin();
+ for (; anEntIt != anEntity->subEntities().end(); ++anEntIt) {
+ std::shared_ptr<SolveSpaceSolver_EntityWrapper> aSubEntity =
+ std::dynamic_pointer_cast<SolveSpaceSolver_EntityWrapper>(*anEntIt);
+ FeaturePtr aBaseFeature = aSubEntity->baseFeature();
+ if (aBaseFeature)
+ isFullyRemoved = removeEntity(aBaseFeature) && isFullyRemoved;
+ else
+ isFullyRemoved = removeEntity(aSubEntity->baseAttribute()) && isFullyRemoved;
+ }
+
+ std::list<ParameterWrapperPtr>::const_iterator aParIt = anEntity->parameters().begin();
+ for (; aParIt != anEntity->parameters().end(); ++aParIt)
+ isFullyRemoved = remove(*aParIt) && isFullyRemoved;
+ return isFullyRemoved;
+}
+
+bool SolveSpaceSolver_Storage::remove(ParameterWrapperPtr theParameter)
+{
+ return removeParameter((Slvs_hParam)theParameter->id());
+}
+
+
+void SolveSpaceSolver_Storage::refresh(bool theFixedOnly) const
+{
+ blockEvents(true);
+
+ std::map<AttributePtr, EntityWrapperPtr>::const_iterator anIt = myAttributeMap.begin();
+ std::list<ParameterWrapperPtr> aParams;
+ std::list<ParameterWrapperPtr>::const_iterator aParIt;
+ for (; anIt != myAttributeMap.end(); ++anIt) {
+ // 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) {
+ std::shared_ptr<SolveSpaceSolver_ParameterWrapper> aWrapper =
+ std::dynamic_pointer_cast<SolveSpaceSolver_ParameterWrapper>(*aParIt);
+ if (!theFixedOnly || aWrapper->group() == GID_OUTOFGROUP || aWrapper->isParametric()) {
+ aWrapper->changeParameter().val = getParameter((Slvs_hParam)aWrapper->id()).val;
+ aCoords[i] = aWrapper->value();
+ isUpd[i] = true;
+ }
+ }
+ if (!isUpd[0] && !isUpd[1] && !isUpd[2])
+ continue; // nothing is updated
+
+ std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2D>(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<AttributePtr, EntityWrapperPtr>::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<GeomDataAPI_Point2D>(aLocIt->first);
+ aPoint2D->setValue(aCoords[0], aCoords[1]);
+ }
+ }
+ continue;
+ }
+ AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
+ if (aScalar) {
+ if (isUpd[0] && fabs(aScalar->value() - aCoords[0]) > tolerance)
+ aScalar->setValue(aCoords[0]);
+ continue;
+ }
+ std::shared_ptr<GeomDataAPI_Point> aPoint =
+ std::dynamic_pointer_cast<GeomDataAPI_Point>(anIt->first);
+ if (aPoint) {
+ if ((isUpd[0] && fabs(aPoint->x() - aCoords[0]) > tolerance) ||
+ (isUpd[1] && fabs(aPoint->y() - aCoords[1]) > tolerance) ||
+ (isUpd[2] && fabs(aPoint->z() - aCoords[2]) > tolerance))
+ if (!isUpd[0]) aCoords[0] = aPoint->x();
+ if (!isUpd[1]) aCoords[1] = aPoint->y();
+ if (!isUpd[2]) aCoords[2] = aPoint->z();
+ aPoint->setValue(aCoords[0], aCoords[1], aCoords[2]);
+ continue;
+ }
+ }
+
+ blockEvents(false);
+}
+
+void SolveSpaceSolver_Storage::verifyFixed()
+{
+ std::map<AttributePtr, EntityWrapperPtr>::iterator anAttrIt = myAttributeMap.begin();
+ for (; anAttrIt != myAttributeMap.end(); ++anAttrIt) {
+ const std::list<ParameterWrapperPtr>& aParameters = anAttrIt->second->parameters();
+ std::list<ParameterWrapperPtr>::const_iterator aParIt = aParameters.begin();
+ for (; aParIt != aParameters.end(); ++aParIt)
+ if ((*aParIt)->group() == GID_OUTOFGROUP) {
+ Slvs_Param aParam = getParameter((Slvs_hParam)(*aParIt)->id());
+ if (aParam.group != (Slvs_hParam)GID_OUTOFGROUP) {
+ aParam.group = (Slvs_hParam)GID_OUTOFGROUP;
+ updateParameter(aParam);
+ }
+ }
+ }
+}
+
+
+void SolveSpaceSolver_Storage::adjustArc(const Slvs_Entity& theArc)
+{
+ double anArcPoints[3][2];
+ double aDist[3] = {0.0};
+ bool isFixed[3] = {false};
+ for (int i = 0; i < 3; ++i) {
+ Slvs_Entity aPoint = getEntity(theArc.point[i]);
+ isFixed[i] = (aPoint.group != (Slvs_hGroup)myGroupID);
+ anArcPoints[i][0] = getParameter(aPoint.param[0]).val;
+ anArcPoints[i][1] = getParameter(aPoint.param[1]).val;
+ if (i > 0) {
+ anArcPoints[i][0] -= anArcPoints[0][0];
+ anArcPoints[i][1] -= anArcPoints[0][1];
+ aDist[i] = sqrt(anArcPoints[i][0] * anArcPoints[i][0] +
+ anArcPoints[i][1] * anArcPoints[i][1]);
+ }
+ }
+
+ if (fabs(aDist[1] - aDist[2]) < tolerance)
+ return;
+
+ int anInd = 2;
+ while (anInd > 0 && isFixed[anInd])
+ --anInd;
+ if (anInd < 1)
+ return; // adjust only start or end point of the arc
+
+ anArcPoints[anInd][0] /= aDist[anInd];
+ anArcPoints[anInd][1] /= aDist[anInd];
+
+ Slvs_Entity aPoint = getEntity(theArc.point[anInd]);
+ for (int i = 0; i < 2; ++i) {
+ Slvs_Param aParam = getParameter(aPoint.param[i]);
+ aParam.val = anArcPoints[0][i] + aDist[3-anInd] * anArcPoints[anInd][i];
+ updateParameter(aParam);
+ }
+}
+
+
+
+
+
+
+
+// ========================================================
+// ========= Auxiliary functions ===============
+// ========================================================
+
+template<typename T>
+int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
+{
+ int aResIndex = theEntityID <= theEntities.size() ? theEntityID - 1 : 0;
+ int aVecSize = theEntities.size();
+ if (theEntities.empty())
+ return 1;
+ while (aResIndex >= 0 && theEntities[aResIndex].h > theEntityID)
+ aResIndex--;
+ while (aResIndex < aVecSize && aResIndex >= 0 && theEntities[aResIndex].h < theEntityID)
+ aResIndex++;
+ if (aResIndex == -1 || (aResIndex < aVecSize && theEntities[aResIndex].h != theEntityID))
+ aResIndex = aVecSize;
+ return aResIndex;
+}
+
+bool IsNotEqual(const Slvs_Param& theParam1, const Slvs_Param& theParam2)
+{
+ return fabs(theParam1.val - theParam2.val) > tolerance;
+}
+
+bool IsNotEqual(const Slvs_Entity& theEntity1, const Slvs_Entity& theEntity2)
+{
+ int i = 0;
+ for (; theEntity1.param[i] != 0 && i < 4; i++)
+ if (theEntity1.param[i] != theEntity2.param[i])
+ return true;
+ i = 0;
+ for (; theEntity1.point[i] != 0 && i < 4; i++)
+ if (theEntity1.point[i] != theEntity2.point[i])
+ return true;
+ return false;
+}
+
+bool IsNotEqual(const Slvs_Constraint& theConstraint1, const Slvs_Constraint& theConstraint2)
+{
+ return theConstraint1.ptA != theConstraint2.ptA ||
+ theConstraint1.ptB != theConstraint2.ptB ||
+ theConstraint1.entityA != theConstraint2.entityA ||
+ theConstraint1.entityB != theConstraint2.entityB ||
+ theConstraint1.entityC != theConstraint2.entityC ||
+ theConstraint1.entityD != theConstraint2.entityD ||
+ fabs(theConstraint1.valA - theConstraint2.valA) > tolerance;
+}
--- /dev/null
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
+// File: SolveSpaceSolver_Storage.h
+// Created: 18 Mar 2015
+// Author: Artem ZHIDKOV
+
+#ifndef SolveSpaceSolver_Storage_H_
+#define SolveSpaceSolver_Storage_H_
+
+#include <SketchSolver_Storage.h>
+#include <SolveSpaceSolver_Solver.h>
+
+#include <list>
+#include <memory>
+#include <set>
+#include <vector>
+
+typedef std::map<EntityWrapperPtr, std::set<EntityWrapperPtr> > CoincidentPointsMap;
+typedef std::list< std::set<ConstraintWrapperPtr> > SameConstraintMap;
+
+/** \class SolveSpaceSolver_Storage
+ * \ingroup Plugins
+ * \brief Contains all necessary data in SolveSpace format to solve a single group of constraints
+ */
+class SolveSpaceSolver_Storage : public SketchSolver_Storage
+{
+public:
+ SolveSpaceSolver_Storage(const GroupID& theGroup);
+
+// ============= Inherited from SketchSolver_Storage =============
+
+ /// \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 Removes constraint from the storage
+ /// \return \c true if the constraint and all its parameters are remove successfully
+ virtual bool removeConstraint(ConstraintPtr theConstraint);
+ /// \brief Removes feature from the storage
+ /// \return \c true if the feature and its attributes are removed successfully;
+ /// \c false if the feature or any it attribute is used by remaining constraints.
+ virtual bool removeEntity(FeaturePtr theFeature);
+ /// \brief Removes attribute from the storage
+ /// \return \c true if the attribute is not used by remaining features and constraints
+ virtual bool removeEntity(AttributePtr theAttribute);
+
+ /// \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 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);
+
+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 =============
+public:
+ /// \brief Obtain and store identifier of sketch
+ void storeWorkplane(EntityWrapperPtr theSketch);
+
+ /** \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 Returns maximal ID of entities in this storage
+ const Slvs_hEntity& entityMaxID() const
+ { return myEntityMaxID; }
+
+ /// \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<Slvs_Constraint> getConstraintsByType(int theConstraintType) const;
+ /// \brief Returns quantity of constraints in this storage
+ size_t nbConstraints() const
+ { return myConstraints.size(); }
+
+ /// \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 Mark specified constraint as temporary
+ virtual void setTemporary(ConstraintPtr theConstraint);
+ /// \brief Remove all transient constraints
+ void removeAllTemporary();
+ /// \brief Remove temporary constraint s. Preferable to remove the points under Point-on-Line constraint
+ /// \param theNbConstraints [in] number of temporary constraints to be deleted
+ /// \return Number of remaining temporary constraints
+ virtual size_t removeTemporary(size_t theNbConstraints);
+ /// \brief Checks the constraint is temporary
+ bool isTemporary(const Slvs_hConstraint& theConstraintID) const;
+ /// \brief Number of temporary constraints
+ virtual size_t nbTemporary() const
+ { return myTemporaryConstraints.size(); }
+
+ /// \brief Shows the storage has the same constraint twice
+ virtual bool hasDuplicatedConstraint() const
+ { return myDuplicatedConstraint; }
+
+ /// \brief Initialize constraint solver by the entities collected by current storage
+ virtual void initializeSolver(SolverPtr theSolver);
+
+public:
+ /// \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<Slvs_hConstraint> 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<Slvs_hConstraint>& 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<Slvs_hConstraint>& 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<Slvs_hConstraint>& 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<Slvs_hConstraint>& theCreated);
+
+ /// \brief Update arc points to be on circle sharp.
+ void adjustArc(const Slvs_Entity& theArc);
+
+ /// \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;
+
+ /// \brief Replace sub-entity theSource in all features by theDest
+ void replaceInFeatures(EntityWrapperPtr theSource, EntityWrapperPtr theDest);
+ /// \brief Replace constrained entity theSource by theDest in all constraints;
+ void replaceInConstraints(EntityWrapperPtr theSource, EntityWrapperPtr theDest);
+
+ /// \brief Add pair of constraints which have same representation in SolveSpace notation.
+ ///
+ /// These constraints may be different and become the same after the substitution
+ /// of point coincidence.
+ void addSameConstraints(ConstraintWrapperPtr theConstraint1, ConstraintWrapperPtr theConstraint2);
+
+private:
+ Slvs_hEntity myWorkplaneID; ///< identifier of workplane
+
+ Slvs_hParam myParamMaxID; ///< current parameter index (may differs with the number of parameters)
+ std::vector<Slvs_Param> 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<Slvs_Entity> 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<Slvs_Constraint> myConstraints; ///< list of constraints used in the current group (sorted by the identifier)
+
+ CoincidentPointsMap myCoincidentPoints; ///< lists of coincident points (first is a master point, second is a set of slaves)
+ Slvs_hConstraint myFixed; ///< identifier of one of temporary constraints to fix separate point
+
+ bool myDuplicatedConstraint; ///< shows the storage has same constraint twice
+
+ std::set<Slvs_hConstraint> myTemporaryConstraints; ///< list of transient constraints
+ std::set<Slvs_hParam> myUpdatedParameters; ///< list of just updated parameters (cleared when isNeedToResolve() called)
+
+ SameConstraintMap myEqualConstraints; ///< list of groups of equal constraints
+};
+
+#endif