From 561727ada1614fb2cf4b863b846cd9831344a616 Mon Sep 17 00:00:00 2001 From: azv Date: Thu, 23 Apr 2015 17:29:57 +0300 Subject: [PATCH] Update Multi-Rotation tool to be used by solver --- .../SketchPlugin_MultiRotation.cpp | 25 +- .../SketchPlugin_MultiTranslation.cpp | 5 +- src/SketchSolver/CMakeLists.txt | 2 + src/SketchSolver/SketchSolver_Builder.cpp | 4 + .../SketchSolver_ConstraintMultiRotation.cpp | 304 ++++++++++++++++++ .../SketchSolver_ConstraintMultiRotation.h | 65 ++++ src/SketchSolver/SketchSolver_Group.cpp | 1 - 7 files changed, 391 insertions(+), 15 deletions(-) create mode 100644 src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp create mode 100644 src/SketchSolver/SketchSolver_ConstraintMultiRotation.h diff --git a/src/SketchPlugin/SketchPlugin_MultiRotation.cpp b/src/SketchPlugin/SketchPlugin_MultiRotation.cpp index 130a8ff62..86f6943fa 100644 --- a/src/SketchPlugin/SketchPlugin_MultiRotation.cpp +++ b/src/SketchPlugin/SketchPlugin_MultiRotation.cpp @@ -133,9 +133,10 @@ void SketchPlugin_MultiRotation::execute() aTargetList.insert(aTargetIter, anObject); } else { // remove object - std::list::iterator aRemoveIt = aTargetIter; - ObjectPtr anObject = *(--aRemoveIt); + std::list::iterator aRemoveIt = aTargetIter++; + ObjectPtr anObject = *aRemoveIt; aTargetList.erase(aRemoveIt); + aRefListOfRotated->remove(anObject); // remove the corresponding feature from the sketch ResultConstructionPtr aRC = std::dynamic_pointer_cast(anObject); @@ -166,16 +167,16 @@ void SketchPlugin_MultiRotation::execute() } } - if (fabs(anAngle) > 1.e-12) { - // Recalculate positions of features - aTargetList = aRefListOfRotated->list(); - aTargetIter = aTargetList.begin(); - while (aTargetIter != aTargetList.end()) { - ObjectPtr anInitialObject = *aTargetIter++; - for (int i = 0; i < aNbCopies && aTargetIter != aTargetList.end(); i++, aTargetIter++) - rotateFeature(anInitialObject, *aTargetIter, aCenter->x(), aCenter->y(), anAngle * (i + 1)); - } - } +//// if (fabs(anAngle) > 1.e-12) { +//// // Recalculate positions of features +//// aTargetList = aRefListOfRotated->list(); +//// aTargetIter = aTargetList.begin(); +//// while (aTargetIter != aTargetList.end()) { +//// ObjectPtr anInitialObject = *aTargetIter++; +//// for (int i = 0; i < aNbCopies && aTargetIter != aTargetList.end(); i++, aTargetIter++) +//// rotateFeature(anInitialObject, *aTargetIter, aCenter->x(), aCenter->y(), anAngle * (i + 1)); +//// } +//// } // send events to update the sub-features by the solver if (isUpdateFlushed) diff --git a/src/SketchPlugin/SketchPlugin_MultiTranslation.cpp b/src/SketchPlugin/SketchPlugin_MultiTranslation.cpp index 6809511af..e7b850ec2 100644 --- a/src/SketchPlugin/SketchPlugin_MultiTranslation.cpp +++ b/src/SketchPlugin/SketchPlugin_MultiTranslation.cpp @@ -128,9 +128,10 @@ void SketchPlugin_MultiTranslation::execute() aTargetList.insert(aTargetIter, anObject); } else { // remove object - std::list::iterator aRemoveIt = aTargetIter; - ObjectPtr anObject = *(--aRemoveIt); + std::list::iterator aRemoveIt = aTargetIter++; + ObjectPtr anObject = *aRemoveIt; aTargetList.erase(aRemoveIt); + aRefListOfTranslated->remove(anObject); // remove the corresponding feature from the sketch ResultConstructionPtr aRC = std::dynamic_pointer_cast(anObject); diff --git a/src/SketchSolver/CMakeLists.txt b/src/SketchSolver/CMakeLists.txt index 2cc5190ef..29e2ef1e7 100644 --- a/src/SketchSolver/CMakeLists.txt +++ b/src/SketchSolver/CMakeLists.txt @@ -16,6 +16,7 @@ SET(PROJECT_HEADERS SketchSolver_ConstraintMirror.h SketchSolver_ConstraintRigid.h SketchSolver_ConstraintTangent.h + SketchSolver_ConstraintMultiRotation.h SketchSolver_ConstraintMultiTranslation.h SketchSolver_Builder.h SketchSolver_Group.h @@ -35,6 +36,7 @@ SET(PROJECT_SOURCES SketchSolver_ConstraintMirror.cpp SketchSolver_ConstraintRigid.cpp SketchSolver_ConstraintTangent.cpp + SketchSolver_ConstraintMultiRotation.cpp SketchSolver_ConstraintMultiTranslation.cpp SketchSolver_Builder.cpp SketchSolver_Group.cpp diff --git a/src/SketchSolver/SketchSolver_Builder.cpp b/src/SketchSolver/SketchSolver_Builder.cpp index c0e1b2bbe..bc992f26d 100644 --- a/src/SketchSolver/SketchSolver_Builder.cpp +++ b/src/SketchSolver/SketchSolver_Builder.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,7 @@ #include #include #include +#include #include #include @@ -122,6 +124,8 @@ SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theCons return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theConstraint)); } else if (theConstraint->getKind() == SketchPlugin_MultiTranslation::ID()) { return SolverConstraintPtr(new SketchSolver_ConstraintMultiTranslation(theConstraint)); + } else if (theConstraint->getKind() == SketchPlugin_MultiRotation::ID()) { + return SolverConstraintPtr(new SketchSolver_ConstraintMultiRotation(theConstraint)); } return aResult; } diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp new file mode 100644 index 000000000..9dc080f16 --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.cpp @@ -0,0 +1,304 @@ +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#define PI 3.1415926535897932 + +void SketchSolver_ConstraintMultiRotation::getAttributes( + Slvs_hEntity& theCenter, double& theAngle, + std::vector >& thePoints, + std::vector >& theCircular) +{ + DataPtr aData = myBaseConstraint->data(); + theAngle = std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_MultiRotation::ANGLE_ID()))->value(); + + AttributePtr aCenterAttr = aData->attribute(SketchPlugin_MultiRotation::CENTER_ID()); + if (!aCenterAttr || !aCenterAttr->isInitialized()) { + 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( + aData->attribute(SketchPlugin_Constraint::ENTITY_A())); + myNumberOfObjects = anInitialRefList->size(); + myNumberOfCopies = (size_t)std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_MultiRotation::NUMBER_OF_COPIES_ID()))->value(); + AttributeRefListPtr aRefList = std::dynamic_pointer_cast( + 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; + std::vector aPoints[2]; // lists of points of features + std::vector aCircs; // list of circular objects + std::list anObjectList = aRefList->list(); + std::list::iterator anObjectIter = anObjectList.begin(); + while (anObjectIter != anObjectList.end()) { + aPoints[0].clear(); + aPoints[1].clear(); + aCircs.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); + 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 + aCircs.push_back(anEntityID); + break; + case SLVS_E_ARC_OF_CIRCLE: + aPoints[0].push_back(anEntity.point[1]); // start point of arc + aPoints[1].push_back(anEntity.point[2]); // end point of arc + aCircs.push_back(anEntityID); + break; + default: + myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); + return; + } + } + + if (!aPoints[0].empty()) + thePoints.push_back(aPoints[0]); + if (!aPoints[1].empty()) + thePoints.push_back(aPoints[1]); + if (!aCircs.empty()) + theCircular.push_back(aCircs); + } +} + +void SketchSolver_ConstraintMultiRotation::process() +{ + cleanErrorMsg(); + if (!myBaseConstraint || !myStorage || myGroup == 0) { + /// TODO: Put error message here + return; + } + if (!mySlvsConstraints.empty()) // some data is changed, update constraint + update(myBaseConstraint); + + Slvs_hEntity aCenter; + std::vector > aPointsAndCopies; + std::vector > aCircsAndCopies; + getAttributes(aCenter, myAngle, aPointsAndCopies, aCircsAndCopies); + if (!myErrorMsg.empty()) + return; + + // Create lines between neighbor rotated points and make angle between them equal to anAngle. + // Also these lines should have equal lengths. + Slvs_Constraint aConstraint; + myRotationCenter = aCenter; + Slvs_Entity aPrevLine; + std::vector >::iterator aCopyIter = aPointsAndCopies.begin(); + for (; aCopyIter != aPointsAndCopies.end(); aCopyIter++) { + size_t aSize = aCopyIter->size(); + if (aSize <= 1) continue; + + aPrevLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(), + myGroup->getWorkplaneId(), aCenter, (*aCopyIter)[0]); + aPrevLine.h = myStorage->addEntity(aPrevLine); + for (size_t i = 1; i < aSize; i++) { + Slvs_Entity aLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(), + myGroup->getWorkplaneId(), aCenter, (*aCopyIter)[i]); + aLine.h = myStorage->addEntity(aLine); + // Equal length constraint + aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), + SLVS_C_EQUAL_LENGTH_LINES, myGroup->getWorkplaneId(), 0.0, + SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aPrevLine.h, aLine.h); + aConstraint.h = myStorage->addConstraint(aConstraint); + mySlvsConstraints.push_back(aConstraint.h); + // Angle constraint + aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), + SLVS_C_ANGLE, myGroup->getWorkplaneId(), fabs(myAngle), SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, + aPrevLine.h, aLine.h); + if (myAngle < 0.0) // clockwise rotation + aConstraint.other = true; + aConstraint.h = myStorage->addConstraint(aConstraint); + mySlvsConstraints.push_back(aConstraint.h); + + aPrevLine = aLine; + } + } + // Equal radii constraints + for (aCopyIter = aCircsAndCopies.begin(); aCopyIter != aCircsAndCopies.end(); aCopyIter++) { + size_t aSize = aCopyIter->size(); + for (size_t i = 0; i < aSize - 1; i++) { + aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), + SLVS_C_EQUAL_RADIUS, myGroup->getWorkplaneId(), 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, + (*aCopyIter)[i], (*aCopyIter)[i+1]); + aConstraint.h = myStorage->addConstraint(aConstraint); + mySlvsConstraints.push_back(aConstraint.h); + } + } + + // Set the rotation center unchanged during constraint recalculation + 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); + } + + adjustConstraint(); +} + +void SketchSolver_ConstraintMultiRotation::update(ConstraintPtr theConstraint) +{ + cleanErrorMsg(); + if (!theConstraint || theConstraint == myBaseConstraint) { + AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast( + myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); + if (anInitialRefList->size() != myNumberOfObjects) { + remove(myBaseConstraint); + process(); + return; + } + } + + // update angle value + myAngle = std::dynamic_pointer_cast( + myBaseConstraint->attribute(SketchPlugin_MultiRotation::ANGLE_ID()))->value(); + + SketchSolver_Constraint::update(); +} + +bool SketchSolver_ConstraintMultiRotation::remove(ConstraintPtr theConstraint) +{ + cleanErrorMsg(); + if (theConstraint && theConstraint != myBaseConstraint) + return false; + bool isFullyRemoved = true; + std::vector::iterator aCIter = mySlvsConstraints.begin(); + for (; aCIter != mySlvsConstraints.end(); aCIter++) + isFullyRemoved = myStorage->removeConstraint(*aCIter) && isFullyRemoved; + mySlvsConstraints.clear(); + + std::map::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; +} + +void SketchSolver_ConstraintMultiRotation::adjustConstraint() +{ + if (abs(myAngle) < tolerance) { + myStorage->setNeedToResolve(false); + return; + } + + // Obtain coordinates of rotation center + Slvs_Entity aRotCenter = myStorage->getEntity(myRotationCenter); + double aCenterXY[2]; + for (int i = 0; i < 2; i++) + aCenterXY[i] = myStorage->getParameter(aRotCenter.param[i]).val; + + double cosA = cos(myAngle * PI / 180.0); + double sinA = sin(myAngle * PI / 180.0); + + // Update positions of all points to satisfy angles + std::list aConstrAngle = myStorage->getConstraintsByType(SLVS_C_ANGLE); + std::list::iterator anAngIt = aConstrAngle.begin(); + std::vector::iterator aCIt; + Slvs_hConstraint aFixed; // temporary variable + double aVec[2]; // coordinates of vector defining a line + Slvs_Param aTarget[2]; // parameter to be changed + for (; anAngIt != aConstrAngle.end(); anAngIt++) { + for (aCIt = mySlvsConstraints.begin(); aCIt != mySlvsConstraints.end(); aCIt++) + if (anAngIt->h == *aCIt) + break; + if (aCIt == mySlvsConstraints.end()) + continue; + Slvs_Entity aLineA = myStorage->getEntity(anAngIt->entityA); + Slvs_Entity aLineB = myStorage->getEntity(anAngIt->entityB); + if (myStorage->isPointFixed(aLineB.point[1], aFixed)) + continue; + Slvs_Entity aPointA = myStorage->getEntity(aLineA.point[1]); + Slvs_Entity aPointB = myStorage->getEntity(aLineB.point[1]); + for (int i = 0; i < 2; i++) { + aVec[i] = myStorage->getParameter(aPointA.param[i]).val - aCenterXY[i]; + aTarget[i] = myStorage->getParameter(aPointB.param[i]); + } + aTarget[0].val = aCenterXY[0] + aVec[0] * cosA - aVec[1] * sinA; + aTarget[1].val = aCenterXY[1] + aVec[0] * sinA + aVec[1] * cosA; + myStorage->updateParameter(aTarget[0]); + myStorage->updateParameter(aTarget[1]); + + anAngIt->valA = myAngle; + myStorage->updateConstraint(*anAngIt); + } + + // update positions of centers of arcs for correct radius calculation + std::list aRadii = myStorage->getConstraintsByType(SLVS_C_EQUAL_RADIUS); + std::map::iterator aFeatIt; + for (anAngIt = aRadii.begin(); anAngIt != aRadii.end(); anAngIt++) { + int aNbFound = 0; // number of arcs used in translation + for (aFeatIt = myFeatureMap.begin(); aFeatIt != myFeatureMap.end(); aFeatIt++) + if (aFeatIt->second == anAngIt->entityA || aFeatIt->second == anAngIt->entityB) { + if (aFeatIt->first->getKind() == SketchPlugin_Arc::ID()) + aNbFound++; + else + break; + } + if (aNbFound != 2) + continue; + // two arcs were found, update their centers + Slvs_Entity anArcA = myStorage->getEntity(anAngIt->entityA); + Slvs_Entity anArcB = myStorage->getEntity(anAngIt->entityB); + if (myStorage->isPointFixed(anArcB.point[0], aFixed)) + continue; + Slvs_Entity aCenterA = myStorage->getEntity(anArcA.point[0]); + Slvs_Entity aCenterB = myStorage->getEntity(anArcB.point[0]); + for (int i = 0; i < 2; i++) { + aVec[i] = myStorage->getParameter(aCenterA.param[i]).val - aCenterXY[i]; + aTarget[i] = myStorage->getParameter(aCenterB.param[i]); + } + aTarget[0].val = aCenterXY[0] + aVec[0] * cosA - aVec[1] * sinA; + aTarget[1].val = aCenterXY[1] + aVec[0] * sinA + aVec[1] * cosA; + myStorage->updateParameter(aTarget[0]); + myStorage->updateParameter(aTarget[1]); + } +} diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h new file mode 100644 index 000000000..e9d0bd147 --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintMultiRotation.h @@ -0,0 +1,65 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_ConstraintMultiRotation.h +// Created: 1 Apr 2015 +// Author: Artem ZHIDKOV + +#ifndef SketchSolver_ConstraintMultiRotation_H_ +#define SketchSolver_ConstraintMultiRotation_H_ + +#include "SketchSolver.h" +#include + +/** \class SketchSolver_ConstraintMultiRotation + * \ingroup Plugins + * \brief Convert rotated features to the list of SolveSpace constraints + */ +class SketchSolver_ConstraintMultiRotation : public SketchSolver_Constraint +{ +public: + SketchSolver_ConstraintMultiRotation(ConstraintPtr theConstraint) : + SketchSolver_Constraint(theConstraint), + myNumberOfObjects(0), + myNumberOfCopies(0) + {} + + virtual int getType() const + { return SLVS_C_MULTI_ROTATION; } + + /// \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()); + +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& theAttributes) + { /* do nothing here */ } + + /// \brief Generate list of rotated entities + /// \param[out] theCenter ID of central point of rotation + /// \param[out] theAngle rotation angle + /// \param[out] thePoints list of IDs of initial points and their rotated copies + /// \param[out] theCircular list of IDs of arcs and circles and their copies + void getAttributes(Slvs_hEntity& theCenter, double& theAngle, + std::vector >& thePoints, + std::vector >& theCircular); + + /// \brief This method is used in derived objects to check consistence of constraint. + virtual void adjustConstraint(); + +private: + size_t myNumberOfObjects; ///< number of previous initial objects + size_t myNumberOfCopies; ///< number of previous copies of initial objects + Slvs_hEntity myRotationCenter; ///< ID of center of rotation + double myAngle; ///< angle of rotation +}; + +#endif diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index bd5585934..41d5522f4 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -33,7 +33,6 @@ #include #include #include -#include #include #include -- 2.39.2