From 1bbe11ce617a6cac19ceb26a5d5c6bb48354d99e Mon Sep 17 00:00:00 2001 From: azv Date: Thu, 23 Apr 2015 15:11:44 +0300 Subject: [PATCH] Update Multi-Translation tool to be used by solver --- .../SketchPlugin_MultiTranslation.cpp | 37 --- .../SketchPlugin_MultiTranslation.h | 1 - src/SketchSolver/CMakeLists.txt | 2 + src/SketchSolver/SketchSolver_Builder.cpp | 4 + ...ketchSolver_ConstraintMultiTranslation.cpp | 287 ++++++++++++++++++ .../SketchSolver_ConstraintMultiTranslation.h | 64 ++++ src/SketchSolver/SketchSolver_Group.cpp | 6 +- src/SketchSolver/SketchSolver_Solver.h | 6 +- 8 files changed, 366 insertions(+), 41 deletions(-) create mode 100644 src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp create mode 100644 src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h diff --git a/src/SketchPlugin/SketchPlugin_MultiTranslation.cpp b/src/SketchPlugin/SketchPlugin_MultiTranslation.cpp index a59283eb5..6809511af 100644 --- a/src/SketchPlugin/SketchPlugin_MultiTranslation.cpp +++ b/src/SketchPlugin/SketchPlugin_MultiTranslation.cpp @@ -161,16 +161,6 @@ void SketchPlugin_MultiTranslation::execute() } } - // Recalculate positions of features - aTargetList = aRefListOfTranslated->list(); - aTargetIter = aTargetList.begin(); - while (aTargetIter != aTargetList.end()) { - ObjectPtr anInitialObject = *aTargetIter++; - for (int i = 0; i < aNbCopies && aTargetIter != aTargetList.end(); i++, aTargetIter++) - shiftFeature(anInitialObject, *aTargetIter, - aShiftVec->x() * (i + 1), aShiftVec->y() * (i + 1)); - } - // send events to update the sub-features by the solver if (isUpdateFlushed) Events_Loop::loop()->setFlushed(anUpdateEvent, true); @@ -217,30 +207,3 @@ ObjectPtr SketchPlugin_MultiTranslation::copyFeature(ObjectPtr theObject) } return ObjectPtr(); } - -void SketchPlugin_MultiTranslation::shiftFeature( - ObjectPtr theInitial, ObjectPtr theTarget, double theDeltaX, double theDeltaY) -{ - FeaturePtr anInitialFeature = ModelAPI_Feature::feature(theInitial); - FeaturePtr aTargetFeature = ModelAPI_Feature::feature(theTarget); - - // block feature update - aTargetFeature->data()->blockSendAttributeUpdated(true); - - std::list anInitAttrList = - anInitialFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); - std::list aTargetAttrList = - aTargetFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); - std::list::iterator anInitIt = anInitAttrList.begin(); - std::list::iterator aTargetIt = aTargetAttrList.begin(); - for (; anInitIt != anInitAttrList.end(); anInitIt++, aTargetIt++) { - std::shared_ptr aPointFrom = - std::dynamic_pointer_cast(*anInitIt); - std::shared_ptr aPointTo = - std::dynamic_pointer_cast(*aTargetIt); - aPointTo->setValue(aPointFrom->x() + theDeltaX, aPointFrom->y() + theDeltaY); - } - - // unblock feature update - aTargetFeature->data()->blockSendAttributeUpdated(false); -} diff --git a/src/SketchPlugin/SketchPlugin_MultiTranslation.h b/src/SketchPlugin/SketchPlugin_MultiTranslation.h index 18e3c4afc..f741d2ee7 100644 --- a/src/SketchPlugin/SketchPlugin_MultiTranslation.h +++ b/src/SketchPlugin/SketchPlugin_MultiTranslation.h @@ -80,7 +80,6 @@ class SketchPlugin_MultiTranslation : public SketchPlugin_ConstraintBase private: ObjectPtr copyFeature(ObjectPtr theObject); - void shiftFeature(ObjectPtr theInitial, ObjectPtr theTarget, double theDeltaX, double theDeltaY); }; #endif diff --git a/src/SketchSolver/CMakeLists.txt b/src/SketchSolver/CMakeLists.txt index d8070e05f..2cc5190ef 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_ConstraintMultiTranslation.h SketchSolver_Builder.h SketchSolver_Group.h SketchSolver_ConstraintManager.h @@ -34,6 +35,7 @@ SET(PROJECT_SOURCES SketchSolver_ConstraintMirror.cpp SketchSolver_ConstraintRigid.cpp SketchSolver_ConstraintTangent.cpp + SketchSolver_ConstraintMultiTranslation.cpp SketchSolver_Builder.cpp SketchSolver_Group.cpp SketchSolver_ConstraintManager.cpp diff --git a/src/SketchSolver/SketchSolver_Builder.cpp b/src/SketchSolver/SketchSolver_Builder.cpp index 82cf9669c..c0e1b2bbe 100644 --- a/src/SketchSolver/SketchSolver_Builder.cpp +++ b/src/SketchSolver/SketchSolver_Builder.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,7 @@ #include #include #include +#include #include @@ -118,6 +120,8 @@ SolverConstraintPtr SketchSolver_Builder::createConstraint(ConstraintPtr theCons return SolverConstraintPtr(new SketchSolver_ConstraintVertical(theConstraint)); } else if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID()) { return SolverConstraintPtr(new SketchSolver_ConstraintRigid(theConstraint)); + } else if (theConstraint->getKind() == SketchPlugin_MultiTranslation::ID()) { + return SolverConstraintPtr(new SketchSolver_ConstraintMultiTranslation(theConstraint)); } return aResult; } diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp new file mode 100644 index 000000000..e304a7e04 --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.cpp @@ -0,0 +1,287 @@ +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + + +void SketchSolver_ConstraintMultiTranslation::getAttributes( + Slvs_hEntity& theStartPoint, Slvs_hEntity& theEndPoint, + std::vector >& thePoints, + std::vector >& theCircular) +{ + DataPtr aData = myBaseConstraint->data(); + AttributePtr aStartPointAttr = aData->attribute(SketchPlugin_MultiTranslation::START_POINT_ID()); + AttributePtr aEndPointAttr = aData->attribute(SketchPlugin_MultiTranslation::END_POINT_ID()); + if (!aStartPointAttr || !aStartPointAttr->isInitialized() || + !aEndPointAttr || !aEndPointAttr->isInitialized()) { + myErrorMsg = SketchSolver_Error::NOT_INITIALIZED(); + 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( + aData->attribute(SketchPlugin_Constraint::ENTITY_A())); + myNumberOfObjects = anInitialRefList->size(); + myNumberOfCopies = (size_t)std::dynamic_pointer_cast( + aData->attribute(SketchPlugin_MultiTranslation::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_ConstraintMultiTranslation::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 aStartPoint, aEndPoint; + std::vector > aPointsAndCopies; + std::vector > aCircsAndCopies; + getAttributes(aStartPoint, aEndPoint, aPointsAndCopies, aCircsAndCopies); + if (!myErrorMsg.empty()) + return; + + // Create lines between neighbor translated points and make them parallel to the translation line. + // Also these lines should have equal lengths. + Slvs_Constraint aConstraint; + Slvs_Entity aTranslationLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(), + myGroup->getWorkplaneId(), aStartPoint, aEndPoint); + aTranslationLine.h = myStorage->addEntity(aTranslationLine); + myTranslationLine = aTranslationLine.h; + std::vector >::iterator aCopyIter = aPointsAndCopies.begin(); + for (; aCopyIter != aPointsAndCopies.end(); aCopyIter++) { + size_t aSize = aCopyIter->size(); + for (size_t i = 0; i < aSize - 1; i++) { + Slvs_Entity aLine = Slvs_MakeLineSegment(SLVS_E_UNKNOWN, myGroup->getId(), + myGroup->getWorkplaneId(), (*aCopyIter)[i], (*aCopyIter)[i+1]); + 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, aTranslationLine.h, aLine.h); + aConstraint.h = myStorage->addConstraint(aConstraint); + mySlvsConstraints.push_back(aConstraint.h); + // Parallel constraint + aConstraint = Slvs_MakeConstraint(SLVS_E_UNKNOWN, myGroup->getId(), + SLVS_C_PARALLEL, myGroup->getWorkplaneId(), 0.0, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, + aTranslationLine.h, aLine.h); + aConstraint.h = myStorage->addConstraint(aConstraint); + mySlvsConstraints.push_back(aConstraint.h); + } + } + // 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 translation line unchanged during constraint recalculation + for (int i = 0; i < 2; i++) { + if (myStorage->isPointFixed(aTranslationLine.point[i], aConstraint.h, true)) + continue; + 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); + mySlvsConstraints.push_back(aConstraint.h); + } + + adjustConstraint(); +} + +void SketchSolver_ConstraintMultiTranslation::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; + } + } + SketchSolver_Constraint::update(); +} + +bool SketchSolver_ConstraintMultiTranslation::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_ConstraintMultiTranslation::adjustConstraint() +{ + Slvs_Entity aTranslationLine = myStorage->getEntity(myTranslationLine); + // 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; + } + double aDelta[2] = {aXY[2] - aXY[0], aXY[3] - aXY[1]}; + if (fabs(aDelta[0]) + fabs(aDelta[1]) < tolerance) { + myStorage->setNeedToResolve(false); + return; + } + + // Update positions of all points to satisfy distances + std::list aParallel = myStorage->getConstraintsByType(SLVS_C_PARALLEL); + std::list::iterator aParIt = aParallel.begin(); + std::vector::iterator aCIt; + Slvs_hConstraint aFixed; // temporary variable + for (; aParIt != aParallel.end(); aParIt++) { + for (aCIt = mySlvsConstraints.begin(); aCIt != mySlvsConstraints.end(); aCIt++) + if (aParIt->h == *aCIt) + break; + if (aCIt == mySlvsConstraints.end()) + continue; + Slvs_Entity aLine = myStorage->getEntity(aParIt->entityB); + if (myStorage->isPointFixed(aLine.point[1], aFixed)) + continue; + Slvs_Entity aStart = myStorage->getEntity(aLine.point[0]); + Slvs_Entity aEnd = myStorage->getEntity(aLine.point[1]); + for (int i = 0; i < 2; i++) { + Slvs_Param aFrom = myStorage->getParameter(aStart.param[i]); + Slvs_Param aTo = myStorage->getParameter(aEnd.param[i]); + aTo.val = aFrom.val + aDelta[i]; + myStorage->updateParameter(aTo); + } + } + + // update positions of centers of arcs for correct radius calculation + std::list aRadii = myStorage->getConstraintsByType(SLVS_C_EQUAL_RADIUS); + std::map::iterator aFeatIt; + for (aParIt = aRadii.begin(); aParIt != aRadii.end(); aParIt++) { + int aNbFound = 0; // number of arcs used in translation + for (aFeatIt = myFeatureMap.begin(); aFeatIt != myFeatureMap.end(); aFeatIt++) + if (aFeatIt->second == aParIt->entityA || aFeatIt->second == aParIt->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(aParIt->entityA); + Slvs_Entity anArcB = myStorage->getEntity(aParIt->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++) { + Slvs_Param aFrom = myStorage->getParameter(aCenterA.param[i]); + Slvs_Param aTo = myStorage->getParameter(aCenterB.param[i]); + aTo.val = aFrom.val + aDelta[i]; + myStorage->updateParameter(aTo); + } + } +} diff --git a/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h new file mode 100644 index 000000000..b02551f07 --- /dev/null +++ b/src/SketchSolver/SketchSolver_ConstraintMultiTranslation.h @@ -0,0 +1,64 @@ +// Copyright (C) 2014-20xx CEA/DEN, EDF R&D + +// File: SketchSolver_ConstraintMultiTranslation.h +// Created: 1 Apr 2015 +// Author: Artem ZHIDKOV + +#ifndef SketchSolver_ConstraintMultiTranslation_H_ +#define SketchSolver_ConstraintMultiTranslation_H_ + +#include "SketchSolver.h" +#include + +/** \class SketchSolver_ConstraintMultiTranslation + * \ingroup Plugins + * \brief Convert translated features to the list of SolveSpace constraints + */ +class SketchSolver_ConstraintMultiTranslation : public SketchSolver_Constraint +{ +public: + SketchSolver_ConstraintMultiTranslation(ConstraintPtr theConstraint) : + SketchSolver_Constraint(theConstraint), + myNumberOfObjects(0), + myNumberOfCopies(0) + {} + + virtual int getType() const + { return SLVS_C_MULTI_TRANSLATION; } + + /// \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 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] theCircular list of IDs of arcs and circles and their copies + void getAttributes(Slvs_hEntity& theStartPoint, Slvs_hEntity& theEndPoint, + 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 myTranslationLine; ///< ID of translation line +}; + +#endif diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index 8a5267be2..bd5585934 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -272,8 +273,7 @@ bool SketchSolver_Group::updateFeature(std::shared_ptr the void SketchSolver_Group::moveFeature(std::shared_ptr theFeature) { - updateFeature(theFeature); - // Temporary rigid constraint + // Firstly, create temporary rigid constraint SolverConstraintPtr aConstraint = SketchSolver_Builder::getInstance()->createRigidConstraint(theFeature); if (!aConstraint) @@ -282,6 +282,8 @@ void SketchSolver_Group::moveFeature(std::shared_ptr theFe aConstraint->setStorage(myStorage); if (aConstraint->error().empty()) setTemporary(aConstraint); + // Secondly, update the feature + updateFeature(theFeature); } // ============================================================================ diff --git a/src/SketchSolver/SketchSolver_Solver.h b/src/SketchSolver/SketchSolver_Solver.h index bdc23ce28..46e83afd0 100644 --- a/src/SketchSolver/SketchSolver_Solver.h +++ b/src/SketchSolver/SketchSolver_Solver.h @@ -25,7 +25,11 @@ typedef unsigned int UINT32; // Unknown constraint (for error reporting) #define SLVS_C_UNKNOWN 0 // Fillet constraint identifier -#define SLVS_C_FILLET 100100 +#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 -- 2.39.2