X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_ConstraintMulti.cpp;h=7b8cbd68eee6adb4f12f00156d4c176a55ba0bb0;hb=11e506a02bbd919d5977b3a25cd4cd84ba54fda4;hp=0980dab4e5c460be9784fd595d22d727b414cd4a;hpb=171168995ff6ef55815a68c857d1ed10c2476137;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_ConstraintMulti.cpp b/src/SketchSolver/SketchSolver_ConstraintMulti.cpp index 0980dab4e..7b8cbd68e 100644 --- a/src/SketchSolver/SketchSolver_ConstraintMulti.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintMulti.cpp @@ -1,306 +1,262 @@ +// Copyright (C) 2014-2019 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + #include -#include #include +#include -#include - -#include +#include #include #include #include -#include - -#include -#include +#include +#include +#include +#include +#include -#include +static void createCopiedEntity(const FeaturePtr& theFeature, const StoragePtr& theStorage) +{ + EntityWrapperPtr anEntity = theStorage->entity(theFeature); + if (anEntity) { + std::shared_ptr aSketchFeature = + std::dynamic_pointer_cast(theFeature); + if (!anEntity->isExternal() && aSketchFeature->isCopy()) + theStorage->makeExternal(anEntity); + } +} -void SketchSolver_ConstraintMulti::processEntities(const std::vector< std::vector >& theEntAndCopies) +void SketchSolver_ConstraintMulti::getEntities(std::list& theEntities) { - // Keep all objects unchanged (only initial object may be changed by user) - myCircsAndCopies.clear(); - std::vector >::const_iterator anEntIt = theEntAndCopies.begin(); - std::vector::const_iterator aCpIt; - for (; anEntIt != theEntAndCopies.end(); ++anEntIt) { - std::vector 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]); - } + myAdjusted = false; + + // Lists of objects and number of copies + AttributeRefListPtr anInitialRefList = + myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_A()); + myNumberOfObjects = anInitialRefList->size(); + myNumberOfCopies = myBaseConstraint->integer(nameNbObjects())->value() - 1; + if (myNumberOfCopies <= 0) + return; - // Fix the copies - for (++aCpIt; aCpIt != anEntIt->end(); ++aCpIt) { - const Slvs_Entity& anEntity = myStorage->getEntity(*aCpIt); - std::vector 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()); - } + AttributeRefListPtr aRefList = + myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_B()); + if (!aRefList || aRefList->size() == 0) { + myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); + 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); + FeaturePtr aFeature; + std::list anObjectList = aRefList->list(); + std::list::iterator anObjIt = anObjectList.begin(); + // execute for the feature is not called yet + if ((myNumberOfCopies + 1) * myNumberOfObjects != aRefList->size()) + myNumberOfCopies = aRefList->size() / myNumberOfObjects - 1; + + while (anObjIt != anObjectList.end()) { + aFeature = ModelAPI_Feature::feature(*anObjIt++); + if (!aFeature) + continue; + + // the entity is not created, so it is a copy in "multi" constraint, force its creation + if (!myStorage->update(aFeature)) + myStorage->update(aFeature, true); + theEntities.push_back(myStorage->entity(aFeature)); + myOriginalFeatures.insert(aFeature); + for (int i = 0; i < myNumberOfCopies && anObjIt != anObjectList.end(); ++i, ++anObjIt) { + // just add copied features into the list of objects + aFeature = ModelAPI_Feature::feature(*anObjIt); + if (aFeature) { + createCopiedEntity(aFeature, myStorage); + myCopiedFeatures.insert(aFeature); + } } } } -void SketchSolver_ConstraintMulti::update(ConstraintPtr theConstraint) +bool SketchSolver_ConstraintMulti::remove() { - cleanErrorMsg(); - if (!theConstraint || theConstraint == myBaseConstraint) { - AttributeRefListPtr anInitialRefList = std::dynamic_pointer_cast( - myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); - AttributeIntegerPtr aNbCopies = myBaseConstraint->integer(nameNbCopies()); - if (anInitialRefList->size() != myNumberOfObjects || aNbCopies->value() != myNumberOfCopies) { - remove(myBaseConstraint); - process(); - return; - } + myStorage->unsubscribeUpdates(this); + + // "Multi" constraint has been removed, thus all copy features become non-copied, + // add them once again to be a common feature + std::set::iterator anIt = myCopiedFeatures.begin(); + for (; anIt != myCopiedFeatures.end(); ++anIt) { + EntityWrapperPtr anEntity = myStorage->entity(*anIt); + if (anEntity) { + std::shared_ptr aSketchFeature = + std::dynamic_pointer_cast(*anIt); + if (anEntity->isExternal() && !aSketchFeature->isExternal()) + myStorage->makeNonExternal(anEntity); + } else if ((*anIt)->data() && (*anIt)->data()->isValid()) + myStorage->update(*anIt, true); } - updateLocal(); - SketchSolver_Constraint::update(); + myOriginalFeatures.clear(); + myCopiedFeatures.clear(); + return SketchSolver_Constraint::remove(); } -bool SketchSolver_ConstraintMulti::remove(ConstraintPtr theConstraint) +void SketchSolver_ConstraintMulti::update() { 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); - myStorage->removeUnusedEntities(); - - std::map aFeatureMapCopy = myFeatureMap; - - if (isFullyRemoved) { - myFeatureMap.clear(); - myAttributeMap.clear(); - myValueMap.clear(); - } else - cleanRemovedEntities(); - - // Restore initial features - std::map::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; + AttributeRefListPtr anInitialRefList = + myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_A()); + AttributeIntegerPtr aNbObjects = myBaseConstraint->integer(nameNbObjects()); + if (!anInitialRefList || !aNbObjects) + return; // the "Multi" constraint is in queue to remove + bool isUpdated = + anInitialRefList->size() != myNumberOfObjects || aNbObjects->value()-1 != myNumberOfCopies; + if (!isUpdated) { + // additional check that the features and their copies are changed + AttributeRefListPtr aRefList = + myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_B()); + if (aRefList && aRefList->size() != 0) { + FeaturePtr aFeature; + std::list anObjectList = aRefList->list(); + std::list::iterator anObjIt = anObjectList.begin(); + for (; anObjIt != anObjectList.end(); ++anObjIt) { + aFeature = ModelAPI_Feature::feature(*anObjIt); + if (aFeature && myOriginalFeatures.find(aFeature) == myOriginalFeatures.end() && + myCopiedFeatures.find(aFeature) == myCopiedFeatures.end()) { + isUpdated = true; + break; + } + } + } else + isUpdated = true; + } + if (isUpdated) { + remove(); + process(); } - // Clear list of rotated points - myPointsAndCopies.clear(); - myInitialPoints.clear(); - - return true; + // update derived object + updateLocal(); + adjustConstraint(); } -void SketchSolver_ConstraintMulti::addFeature(FeaturePtr theFeature) +void SketchSolver_ConstraintMulti::adjustConstraint() { - SketchSolver_Constraint::addFeature(theFeature); - - std::map::iterator aFeatIt = myFeatureMap.find(theFeature); - if (aFeatIt == myFeatureMap.end()) + AttributeRefListPtr aRefList = + myBaseConstraint->reflist(SketchPlugin_Constraint::ENTITY_B()); + if (!aRefList || aRefList->size() == 0) { + myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE(); 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]); -} + FeaturePtr anOriginal, aFeature; + std::list::iterator aXIt, aYIt; -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 aCoincident = myStorage->getConstraintsByType(SLVS_C_POINTS_COINCIDENT); - std::list::const_iterator aCoIt; - - // Update positions of all points to satisfy angles - std::vector< std::vector >::const_iterator aPointsIter = myPointsAndCopies.begin(); - std::vector::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]); - } - } + std::list anObjectList = aRefList->list(); + std::list::iterator anObjIt = anObjectList.begin(); + while (anObjIt != anObjectList.end()) { + anOriginal = ModelAPI_Feature::feature(*anObjIt++); + if (!anOriginal) + continue; - // 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); - } + // Fill lists of coordinates of points composing a feature + std::list aX, aY; + double aXCoord, aYCoord; + std::list aPoints = + anOriginal->data()->attributes(GeomDataAPI_Point2D::typeId()); + std::list::iterator aPtIt = aPoints.begin(); + for (; aPtIt != aPoints.end(); ++aPtIt) { + AttributePoint2DPtr aPoint2D = std::dynamic_pointer_cast(*aPtIt); + if (aPoint2D->isInitialized()) { + aXCoord = aPoint2D->x(); + aYCoord = aPoint2D->y(); + getRelative(aXCoord, aYCoord, aXCoord, aYCoord); + } else + aXCoord = aYCoord = 0; + + aX.push_back(aXCoord); + aY.push_back(aYCoord); } - } - std::list 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]); - - 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::iterator aDCIt = aDiamConstr.begin(); - for (; aDCIt != aDiamConstr.end(); ++aDCIt) - if (aDCIt->entityA == *aCopyIter) { - aDCIt->valA = aDiam; - myStorage->updateConstraint(*aDCIt); - aDiamConstr.erase(aDCIt); - break; - } + // Calculate positions of copied features + for (int i = 0; i < myNumberOfCopies && anObjIt != anObjectList.end(); ++i, ++anObjIt) { + aFeature = ModelAPI_Feature::feature(*anObjIt); + if (!aFeature) + continue; + + if (myIsEventsBlocked) + aFeature->data()->blockSendAttributeUpdated(true); + + if (aFeature->getKind() == SketchPlugin_Circle::ID()) // update circle's radius + aFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue( + anOriginal->real(SketchPlugin_Circle::RADIUS_ID())->value()); + + aPoints = aFeature->data()->attributes(GeomDataAPI_Point2D::typeId()); + for (aPtIt = aPoints.begin(), aXIt = aX.begin(), aYIt = aY.begin(); + aPtIt != aPoints.end(); ++aXIt, ++aYIt, ++aPtIt) { + if (!(*aPtIt)->isInitialized()) + continue; + transformRelative(*aXIt, *aYIt); + getAbsolute(*aXIt, *aYIt, aXCoord, aYCoord); + + AttributePoint2DPtr aPoint2D = + std::dynamic_pointer_cast(*aPtIt); + aPoint2D->setValue(aXCoord, aYCoord); } + + // update transformed entity if it exists in the storage + if (myStorage->entity(aFeature)) + myStorage->update(aFeature); } } - myPointsJustUpdated.clear(); myAdjusted = true; } -void SketchSolver_ConstraintMulti::checkCoincidence() +void SketchSolver_ConstraintMulti::notify(const FeaturePtr& theFeature, + PlaneGCSSolver_Update*) { - std::vector< std::vector > aFilteredPoints; // points are filtered by their positions - - std::vector< std::vector >::const_iterator aPCIt = myPointsAndCopies.begin(); - std::vector::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 >::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 aNewFilter(1, *aCIt); - aFilteredPoints.push_back(aNewFilter); - } - } - } + if (myOriginalFeatures.find(theFeature) == myOriginalFeatures.end() && + myCopiedFeatures.find(theFeature) == myCopiedFeatures.end()) + return; // the feature is not used by constraint => nothing to update - // Check the coicidence of filtered points and remove extra fixation. - // Also check separated points which are not fixed. - std::vector< std::vector >::iterator aFPIt = aFilteredPoints.begin(); - for (; aFPIt != aFilteredPoints.end(); ++aFPIt) { - if (aFPIt->size() <= 1) - continue; - std::vector::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::iterator aRemoveIt = mySlvsConstraints.begin(); - for (; aRemoveIt != mySlvsConstraints.end(); ++aRemoveIt) - if (*aRemoveIt == aFixed2) { - mySlvsConstraints.erase(aRemoveIt); - break; - } - } - } else { - bool isFixed[2] = {isFixed1, isFixed2}; - 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); - } - } - } - } + if (myIsProcessingNotify) + return; // "notify" is already processing + + // do not adjust "multi"-constraint if the number of objects is changed, + // wait until the constraint is updated (issue #2425: changing number of copies by parameter) + if (myNumberOfCopies + 1 == myBaseConstraint->integer(nameNbObjects())->value()) { + myIsProcessingNotify = true; + + // update derivative object + updateLocal(); + myAdjusted = false; + adjustConstraint(); + + myIsProcessingNotify = false; } } + +void SketchSolver_ConstraintMulti::blockEvents(bool isBlocked) +{ + myIsEventsBlocked = isBlocked; + + std::set::iterator anIt = myOriginalFeatures.begin(); + for (; anIt != myOriginalFeatures.end(); ++anIt) + (*anIt)->data()->blockSendAttributeUpdated(isBlocked); + for (anIt = myCopiedFeatures.begin(); anIt != myCopiedFeatures.end(); ++anIt) + (*anIt)->data()->blockSendAttributeUpdated(isBlocked); + + SketchSolver_Constraint::blockEvents(isBlocked); +}