X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_ConstraintGroup.cpp;h=1a3f1b104803a316ce5a0d29fb10e6fdfb48576d;hb=78ee6c26e0b4e8a14ef4b2beedf6e7f83479bd7f;hp=b1a6d73e0b3c0643158681b87278dbbf74a71123;hpb=46c278a1438e8998efa453854471b8dbd78d4277;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_ConstraintGroup.cpp b/src/SketchSolver/SketchSolver_ConstraintGroup.cpp index b1a6d73e0..1a3f1b104 100644 --- a/src/SketchSolver/SketchSolver_ConstraintGroup.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintGroup.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -117,7 +116,11 @@ bool SketchSolver_ConstraintGroup::isInteract( theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[i]) ); if (!aCAttrRef) continue; - if (myEntityMap.find(aCAttrRef->attr()) != myEntityMap.end()) + if (!aCAttrRef->isFeature() && + myEntityAttrMap.find(aCAttrRef->attr()) != myEntityAttrMap.end()) + return true; + if (aCAttrRef->isFeature() && + myEntityFeatMap.find(aCAttrRef->feature()) != myEntityFeatMap.end()) return true; } @@ -167,6 +170,9 @@ bool SketchSolver_ConstraintGroup::changeConstraint( myNeedToSolve = true; aConstrIter->valA = aDistance; } + // SketchPlugin circle defined by its radius, but SolveSpace uses constraint for diameter + if (aConstrType == SLVS_C_DIAMETER) + aDistance *= 2.0; } Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint @@ -178,51 +184,30 @@ bool SketchSolver_ConstraintGroup::changeConstraint( theConstraint->data()->attribute(aConstraintAttributes[indAttr]) ); if (!aConstrAttr) continue; - aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr()); + + // For the length constraint the start and end points of the line should be added to the entities list instead of line + if (aConstrType == SLVS_C_PT_PT_DISTANCE && theConstraint->getKind().compare("SketchConstraintLength") == 0) + { + boost::shared_ptr aData = aConstrAttr->feature()->data(); + aConstrEnt[indAttr] = changeEntity(aData->attribute(LINE_ATTR_START)); + aConstrEnt[indAttr+1] = changeEntity(aData->attribute(LINE_ATTR_END)); + break; // there should be no other entities + } + else if (aConstrAttr->isFeature()) + aConstrEnt[indAttr] = changeEntity(aConstrAttr->feature()); + else + aConstrEnt[indAttr] = changeEntity(aConstrAttr->attr()); } if (aConstrMapIter == myConstraintMap.end()) { // Several points may be coincident, it is not necessary to store all constraints between them. // Try to find sequence of coincident points which connects the points of new constraint - if (aConstrType == SLVS_C_POINTS_COINCIDENT) + if (aConstrType == SLVS_C_POINTS_COINCIDENT && + !addCoincidentPoints(aConstrEnt[0], aConstrEnt[1])) { - std::vector< std::set >::iterator aCoPtIter = myCoincidentPoints.begin(); - std::vector< std::set >::iterator aFirstFound = myCoincidentPoints.end(); - for ( ; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) - { - bool isFound[2] = { // indicate which point ID was already in coincidence constraint - aCoPtIter->find(aConstrEnt[0]) != aCoPtIter->end(), - aCoPtIter->find(aConstrEnt[1]) != aCoPtIter->end(), - }; - if (isFound[0] && isFound[1]) // points are already connected by coincidence constraints => no need to additional one - return false; - if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1])) - { - if (aFirstFound != myCoincidentPoints.end()) - { // there are two groups of coincident points connected by created constraint => merge them - int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin(); - int aCurrentShift = aCoPtIter - myCoincidentPoints.begin(); - aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end()); - myCoincidentPoints.erase(aCoPtIter); - aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift; - aCoPtIter = myCoincidentPoints.begin() + aCurrentShift; - } - else - { - aCoPtIter->insert(aConstrEnt[isFound[0] ? 1 : 0]); - aFirstFound = aCoPtIter; - } - } - } - // No points were found, need to create new set - if (aFirstFound == myCoincidentPoints.end()) - { - std::set aNewSet; - aNewSet.insert(aConstrEnt[0]); - aNewSet.insert(aConstrEnt[1]); - myCoincidentPoints.push_back(aNewSet); - } + myExtraCoincidence.insert(theConstraint); // the constraint is stored for further purposes + return false; } // Create SolveSpace constraint structure @@ -245,9 +230,9 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity( { // If the entity is already in the group, try to find it std::map, Slvs_hEntity>::const_iterator - aEntIter = myEntityMap.find(theEntity); + aEntIter = myEntityAttrMap.find(theEntity); std::vector::const_iterator aParamIter; // looks at first parameter of already existent entity or at the end of vector otherwise - if (aEntIter == myEntityMap.end()) // no such entity => should be created + if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created aParamIter = myParams.end(); else { // the entity already exists @@ -255,6 +240,7 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity( int aParamPos = Search(myEntities[aEntPos].param[0], myParams); aParamIter = myParams.begin() + aParamPos; } + const bool isEntExists = (aEntIter != myEntityAttrMap.end()); // defines that the entity already exists // Look over supported types of entities @@ -267,13 +253,13 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity( Slvs_hParam aY = changeParameter(aPoint->y(), aParamIter); Slvs_hParam aZ = changeParameter(aPoint->z(), aParamIter); - if (aEntIter != myEntityMap.end()) // the entity already exists + if (isEntExists) return aEntIter->second; // New entity Slvs_Entity aPtEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ); myEntities.push_back(aPtEntity); - myEntityMap[theEntity] = aPtEntity.h; + myEntityAttrMap[theEntity] = aPtEntity.h; return aPtEntity.h; } @@ -289,13 +275,13 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity( Slvs_hParam aU = changeParameter(aPoint2D->x(), aParamIter); Slvs_hParam aV = changeParameter(aPoint2D->y(), aParamIter); - if (aEntIter != myEntityMap.end()) // the entity already exists + if (isEntExists) return aEntIter->second; // New entity Slvs_Entity aPt2DEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV); myEntities.push_back(aPt2DEntity); - myEntityMap[theEntity] = aPt2DEntity.h; + myEntityAttrMap[theEntity] = aPt2DEntity.h; return aPt2DEntity.h; } @@ -306,18 +292,39 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity( { Slvs_hParam aValue = changeParameter(aScalar->value(), aParamIter); - if (aEntIter != myEntityMap.end()) // the entity already exists + if (isEntExists) return aEntIter->second; // New entity Slvs_Entity aDistance = Slvs_MakeDistance(++myEntityMaxID, myID, myWorkplane.h, aValue); myEntities.push_back(aDistance); - myEntityMap[theEntity] = aDistance.h; + myEntityAttrMap[theEntity] = aDistance.h; return aDistance.h; } + /// \todo Other types of entities + + // Unsupported or wrong entity type + return SLVS_E_UNKNOWN; +} + + +// ============================================================================ +// Function: changeEntity +// Class: SketchSolver_ConstraintGroup +// Purpose: create/update the element defined by the feature affected by any constraint +// ============================================================================ +Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity( + boost::shared_ptr theEntity) +{ + // If the entity is already in the group, try to find it + std::map, Slvs_hEntity>::const_iterator + aEntIter = myEntityFeatMap.find(theEntity); + // defines that the entity already exists + const bool isEntExists = (myEntityFeatMap.find(theEntity) != myEntityFeatMap.end()); + // SketchPlugin features - boost::shared_ptr aFeature = + boost::shared_ptr aFeature; boost::dynamic_pointer_cast(theEntity); if (aFeature) { // Verify the feature by its kind @@ -329,13 +336,13 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity( Slvs_hEntity aStart = changeEntity(aFeature->data()->attribute(LINE_ATTR_START)); Slvs_hEntity aEnd = changeEntity(aFeature->data()->attribute(LINE_ATTR_END)); - if (aEntIter != myEntityMap.end()) // the entity already exists + if (isEntExists) return aEntIter->second; // New entity Slvs_Entity aLineEntity = Slvs_MakeLineSegment(++myEntityMaxID, myID, myWorkplane.h, aStart, aEnd); myEntities.push_back(aLineEntity); - myEntityMap[theEntity] = aLineEntity.h; + myEntityFeatMap[theEntity] = aLineEntity.h; return aLineEntity.h; } // Circle @@ -344,14 +351,14 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity( Slvs_hEntity aCenter = changeEntity(aFeature->data()->attribute(CIRCLE_ATTR_CENTER)); Slvs_hEntity aRadius = changeEntity(aFeature->data()->attribute(CIRCLE_ATTR_RADIUS)); - if (aEntIter != myEntityMap.end()) // the entity already exists + if (isEntExists) return aEntIter->second; // New entity Slvs_Entity aCircleEntity = Slvs_MakeCircle(++myEntityMaxID, myID, myWorkplane.h, aCenter, myWorkplane.normal, aRadius); myEntities.push_back(aCircleEntity); - myEntityMap[theEntity] = aCircleEntity.h; + myEntityFeatMap[theEntity] = aCircleEntity.h; return aCircleEntity.h; } // Arc @@ -361,13 +368,13 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity( Slvs_hEntity aStart = changeEntity(aFeature->data()->attribute(ARC_ATTR_START)); Slvs_hEntity aEnd = changeEntity(aFeature->data()->attribute(ARC_ATTR_END)); - if (aEntIter != myEntityMap.end()) // the entity already exists + if (isEntExists) return aEntIter->second; Slvs_Entity anArcEntity = Slvs_MakeArcOfCircle(++myEntityMaxID, myID, myWorkplane.h, myWorkplane.normal, aCenter, aStart, aEnd); myEntities.push_back(anArcEntity); - myEntityMap[theEntity] = anArcEntity.h; + myEntityFeatMap[theEntity] = anArcEntity.h; return anArcEntity.h; } // Point (it has low probability to be an attribute of constraint, so it is checked at the end) @@ -375,16 +382,16 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity( { Slvs_hEntity aPoint = changeEntity(aFeature->data()->attribute(POINT_ATTR_COORD)); - if (aEntIter != myEntityMap.end()) // the entity already exists + if (isEntExists) return aEntIter->second; // Both the sketch point and its attribute (coordinates) link to the same SolveSpace point identifier - myEntityMap[theEntity] = aPoint; + myEntityFeatMap[theEntity] = aPoint; return aPoint; } } - /// \todo Other types of entities + /// \todo Other types of features // Unsupported or wrong entity type return SLVS_E_UNKNOWN; @@ -418,9 +425,9 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeNormal( // Try to find existent normal std::map, Slvs_hEntity>::const_iterator - aEntIter = myEntityMap.find(theNorm); + aEntIter = myEntityAttrMap.find(theNorm); std::vector::const_iterator aParamIter; // looks to the first parameter of already existent entity or to the end of vector otherwise - if (aEntIter == myEntityMap.end()) // no such entity => should be created + if (aEntIter == myEntityAttrMap.end()) // no such entity => should be created aParamIter = myParams.end(); else { // the entity already exists, update it @@ -434,14 +441,14 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeNormal( for (int i = 0; i < 4; i++) aNormParams[i] = changeParameter(aNormCoord[i], aParamIter); - if (aEntIter != myEntityMap.end()) // the entity already exists + if (aEntIter != myEntityAttrMap.end()) // the entity already exists return aEntIter->second; // Create a normal Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID, aNormParams[0], aNormParams[1], aNormParams[2], aNormParams[3]); myEntities.push_back(aNormal); - myEntityMap[theNorm] = aNormal.h; + myEntityAttrMap[theNorm] = aNormal.h; return aNormal.h; } @@ -454,7 +461,7 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeNormal( bool SketchSolver_ConstraintGroup::addWorkplane( boost::shared_ptr theSketch) { - if (myWorkplane.h || theSketch->getKind().compare("Sketch") != 0) + if (myWorkplane.h || theSketch->getKind().compare(SKETCH_KIND) != 0) return false; // the workplane already exists or the function parameter is not Sketch mySketch = theSketch; @@ -543,9 +550,10 @@ void SketchSolver_ConstraintGroup::resolveConstraints() if (!myConstrSolver.getResult(myParams)) return; + // We should go through the attributes map, because only attributes have valued parameters std::map, Slvs_hEntity>::iterator - anEntIter = myEntityMap.begin(); - for ( ; anEntIter != myEntityMap.end(); anEntIter++) + anEntIter = myEntityAttrMap.begin(); + for ( ; anEntIter != myEntityAttrMap.end(); anEntIter++) updateAttribute(anEntIter->first, anEntIter->second); } /// \todo Implement error handling @@ -566,84 +574,17 @@ void SketchSolver_ConstraintGroup::mergeGroups( if (theGroup.myConstraintMap.empty()) return ; - // NOTE: The possibility, that some elements are placed into both groups, is around 0, - // so the objects should be copied with changing the indexes - - // Maps between old and new indexes of SolveSpace elements: - std::map aParamMap; - std::map anEntityMap; + // Map between old and new indexes of SolveSpace constraints std::map aConstrMap; - // Go through copying constraints - std::vector::const_iterator aConstrIter = theGroup.myConstraints.begin(); - for ( ; aConstrIter != theGroup.myConstraints.end(); aConstrIter++) - { - Slvs_Constraint aConstraintCopy = *aConstrIter; - // Go through constraint entities - Slvs_hEntity* anEntities[CONSTRAINT_ATTR_SIZE] = { - &(aConstraintCopy.ptA), &(aConstraintCopy.ptB), - &(aConstraintCopy.entityA), &(aConstraintCopy.entityB) - }; - for (int indEnt = 0; indEnt < CONSTRAINT_ATTR_SIZE; indEnt++) - { - if (*(anEntities[indEnt]) == 0) - continue; - if (anEntityMap.find(*(anEntities[indEnt])) != anEntityMap.end()) - { // entity is already copied - *(anEntities[indEnt]) = anEntityMap[*(anEntities[indEnt])]; - continue; - } - - // Copy entity - Slvs_Entity anEntityCopy = theGroup.myEntities[Search(*(anEntities[indEnt]), theGroup.myEntities)]; - // Go through entity parameters - const int aNbEntParams = 4; // maximal number of entity parameters - for (int indPrm = 0; indPrm < aNbEntParams; indPrm++) - { - if (anEntityCopy.param[indPrm] == 0) - continue; - if (aParamMap.find(anEntityCopy.param[indPrm]) != aParamMap.end()) - { - anEntityCopy.param[indPrm] = aParamMap[anEntityCopy.param[indPrm]]; - continue; - } - - Slvs_Param aParamCopy = theGroup.myParams[Search(anEntityCopy.param[indPrm], theGroup.myParams)]; - aParamMap[aParamCopy.h] = ++myParamMaxID; - aParamCopy.h = myParamMaxID; - myParams.push_back(aParamCopy); - } - - anEntityMap[anEntityCopy.h] = ++myEntityMaxID; - anEntityCopy.h = myEntityMaxID; - myEntities.push_back(anEntityCopy); - *(anEntities[indEnt]) = anEntityCopy.h; - } - - aConstraintCopy.h = ++myConstrMaxID; - myConstraints.push_back(aConstraintCopy); - aConstrMap[aConstrIter->h] = aConstraintCopy.h; - } - - // Append maps of SketchPlugin to SolveSpace parameters + // Add all constraints from theGroup to the current group std::map, Slvs_hConstraint>::const_iterator - aSPConstrMapIter = theGroup.myConstraintMap.begin(); - for ( ; aSPConstrMapIter!= theGroup.myConstraintMap.end(); aSPConstrMapIter++) - { - std::map::iterator aFind = aConstrMap.find(aSPConstrMapIter->second); - if (aFind != aConstrMap.end()) - myConstraintMap[aSPConstrMapIter->first] = aFind->second; - } - - std::map, Slvs_hEntity>::const_iterator - aSPEntMapIter = theGroup.myEntityMap.begin(); - for ( ; aSPEntMapIter != theGroup.myEntityMap.end(); aSPEntMapIter++) { - std::map::iterator aFind = anEntityMap.find(aSPEntMapIter->second); - if (aFind != anEntityMap.end()) - myEntityMap[aSPEntMapIter->first] = aFind->second; - } + aConstrIter = theGroup.myConstraintMap.begin(); + for ( ; aConstrIter != theGroup.myConstraintMap.end(); aConstrIter++) + if (changeConstraint(aConstrIter->first)) + aConstrMap[aConstrIter->second] = myConstrMaxID; // the constraint was added => store its ID - // Add temporary constraints + // Add temporary constraints from theGroup std::list::const_iterator aTempConstrIter = theGroup.myTempConstraints.begin(); for ( ; aTempConstrIter != theGroup.myTempConstraints.end(); aTempConstrIter++) { @@ -651,15 +592,14 @@ void SketchSolver_ConstraintGroup::mergeGroups( if (aFind != aConstrMap.end()) myTempConstraints.push_back(aFind->second); } - myTempConstraints.sort(); if (myTempPointWhereDragged.empty()) myTempPointWhereDragged = theGroup.myTempPointWhereDragged; else if (!theGroup.myTempPointWhereDragged.empty()) { // Need to create additional transient constraint std::map, Slvs_hEntity>::const_iterator - aFeatureIter = theGroup.myEntityMap.begin(); - for (; aFeatureIter != theGroup.myEntityMap.end(); aFeatureIter++) + aFeatureIter = theGroup.myEntityAttrMap.begin(); + for (; aFeatureIter != theGroup.myEntityAttrMap.end(); aFeatureIter++) if (aFeatureIter->second == myTempPointWDrgdID) { addTemporaryConstraintWhereDragged(aFeatureIter->first); @@ -667,121 +607,168 @@ void SketchSolver_ConstraintGroup::mergeGroups( } } - // Merge the lists of coincidence points. As the groups were separated, there was - // no coincidence constraint, so each two points from different groups don't coincide - myCoincidentPoints.insert(myCoincidentPoints.end(), - theGroup.myCoincidentPoints.begin(), - theGroup.myCoincidentPoints.end()); - myNeedToSolve = myNeedToSolve || theGroup.myNeedToSolve; } // ============================================================================ -// Function: updateGroup +// Function: splitGroup // Class: SketchSolver_ConstraintGroup -// Purpose: search removed entities and constraints +// Purpose: divide the group into several subgroups // ============================================================================ -bool SketchSolver_ConstraintGroup::updateGroup() +void SketchSolver_ConstraintGroup::splitGroup(std::vector& theCuts) { - // Check for valid sketch - if (!mySketch->data()->isValid()) - return true; - - // Fast check for constraint validity. If all constraints are valid, no need to update the group - std::map, Slvs_hConstraint>::reverse_iterator - aConstrIter = myConstraintMap.rbegin(); - bool isAllValid = true; - for ( ; isAllValid && aConstrIter != myConstraintMap.rend(); aConstrIter++) - if (!aConstrIter->first->data()->isValid()) - isAllValid = false; - if (isAllValid) - return false; - - // Remove invalid constraints. - // There only constraint will be deleted (parameters and entities) will be removed below - std::list< boost::shared_ptr > aConstrToDelete; - std::map anEntToDelete; // entities will be removed if no valid constraints use them - std::map aCoincPtToDelete; // list of entities (points) used in coincidence constaints which will be removed; - for (aConstrIter = myConstraintMap.rbegin(); aConstrIter != myConstraintMap.rend(); aConstrIter++) + // Divide constraints and entities into several groups + std::vector< std::set > aGroupsEntities; + std::vector< std::set > aGroupsConstr; + int aMaxNbEntities = 0; // index of the group with maximal nuber of elements (this group will be left in the current) + std::vector::const_iterator aConstrIter = myConstraints.begin(); + for ( ; aConstrIter != myConstraints.end(); aConstrIter++) { - bool isValid = aConstrIter->first->data()->isValid(); - - int aConstrPos = Search(aConstrIter->second, myConstraints); - if (aConstrPos < (int)myConstraints.size()) + Slvs_hEntity aConstrEnt[] = { + aConstrIter->ptA, aConstrIter->ptB, + aConstrIter->entityA, aConstrIter->entityB}; + std::vector anIndexes; + // Go through the groupped entities and find even one of entities of current constraint + std::vector< std::set >::iterator aGrEntIter; + for (aGrEntIter = aGroupsEntities.begin(); aGrEntIter != aGroupsEntities.end(); aGrEntIter++) { - Slvs_hEntity aConstrEnt[] = { - myConstraints[aConstrPos].ptA, myConstraints[aConstrPos].ptB, - myConstraints[aConstrPos].entityA, myConstraints[aConstrPos].entityB}; + bool isFound = false; + for (int i = 0; i < 4 && !isFound; i++) + if (aConstrEnt[i] != 0) + isFound = (aGrEntIter->find(aConstrEnt[i]) != aGrEntIter->end()); + if (isFound) + anIndexes.push_back(aGrEntIter - aGroupsEntities.begin()); + } + // Add new group if no one is found + if (anIndexes.empty()) + { + std::set aNewGrEnt; + for (int i = 0; i < 4; i++) + if (aConstrEnt[i] != 0) + aNewGrEnt.insert(aConstrEnt[i]); + std::set aNewGrConstr; + aNewGrConstr.insert(aConstrIter->h); + + aGroupsEntities.push_back(aNewGrEnt); + aGroupsConstr.push_back(aNewGrConstr); + if (aNewGrEnt.size() > aGroupsEntities[aMaxNbEntities].size()) + aMaxNbEntities = aGroupsEntities.size() - 1; + } + else if (anIndexes.size() == 1) + { // Add entities indexes into the found group + aGrEntIter = aGroupsEntities.begin() + anIndexes.front(); for (int i = 0; i < 4; i++) - if (aConstrEnt[i] != SLVS_E_UNKNOWN) - { - if (anEntToDelete.find(aConstrEnt[i]) == anEntToDelete.end()) - { - anEntToDelete[aConstrEnt[i]] = !isValid; - aCoincPtToDelete[aConstrEnt[i]] = !isValid && (myConstraints[aConstrPos].type == SLVS_C_POINTS_COINCIDENT); - } - else if (isValid) // constraint is valid => no need to remove its entities - { - anEntToDelete[aConstrEnt[i]] = false; - aCoincPtToDelete[aConstrEnt[i]] = false; - } - } - if (!isValid) + if (aConstrEnt[i] != 0) + aGrEntIter->insert(aConstrEnt[i]); + aGroupsConstr[anIndexes.front()].insert(aConstrIter->h); + if (aGrEntIter->size() > aGroupsEntities[aMaxNbEntities].size()) + aMaxNbEntities = aGrEntIter - aGroupsEntities.begin(); + } + else + { // There are found several connected groups, merge them + std::vector< std::set >::iterator aFirstGroup = + aGroupsEntities.begin() + anIndexes.front(); + std::vector< std::set >::iterator aFirstConstr = + aGroupsConstr.begin() + anIndexes.front(); + std::vector::iterator anInd = anIndexes.begin(); + for (++anInd; anInd != anIndexes.end(); anInd++) + { + aFirstGroup->insert(aGroupsEntities[*anInd].begin(), aGroupsEntities[*anInd].end()); + aFirstConstr->insert(aGroupsConstr[*anInd].begin(), aGroupsConstr[*anInd].end()); + } + if (aFirstGroup->size() > aGroupsEntities[aMaxNbEntities].size()) + aMaxNbEntities = anIndexes.front(); + // Remove merged groups + for (anInd = anIndexes.end() - 1; anInd != anIndexes.begin(); anInd--) { - myConstraints.erase(myConstraints.begin() + aConstrPos); - if (aConstrIter->second == myConstrMaxID) // When the constraint with highest ID is removed, decrease indexer - myConstrMaxID--; - aConstrToDelete.push_front(aConstrIter->first); + aGroupsEntities.erase(aGroupsEntities.begin() + (*anInd)); + aGroupsConstr.erase(aGroupsConstr.begin() + (*anInd)); } } } - std::list< boost::shared_ptr >::iterator aDelIter; - for (aDelIter = aConstrToDelete.begin(); aDelIter != aConstrToDelete.end(); aDelIter++) - myConstraintMap.erase(*aDelIter); - // Remove invalid and unused entities - std::map::reverse_iterator aEDelIter; - std::map::reverse_iterator aPtDelIter = aCoincPtToDelete.rbegin(); - for (aEDelIter = anEntToDelete.rbegin(); aEDelIter != anEntToDelete.rend(); aEDelIter++, aPtDelIter++) + if (aGroupsEntities.size() <= 1) + return ; + + // Remove the group with maximum elements as it will be left in the current group + aGroupsEntities.erase(aGroupsEntities.begin() + aMaxNbEntities); + aGroupsConstr.erase(aGroupsConstr.begin() + aMaxNbEntities); + + // Add new groups of constraints and divide current group + std::vector aNewGroups; + for (int i = aGroupsEntities.size(); i > 0; i--) + { + SketchSolver_ConstraintGroup* aG = new SketchSolver_ConstraintGroup(mySketch); + aNewGroups.push_back(aG); + } + std::map, Slvs_hConstraint>::const_iterator + aConstrMapIter = myConstraintMap.begin(); + int aConstrMapPos = 0; // position of iterator in the map (used to restore iterator after removing constraint) + while (aConstrMapIter != myConstraintMap.end()) { - if (aEDelIter->second) // remove entity + std::vector< std::set >::const_iterator aGIter = aGroupsConstr.begin(); + std::vector::iterator aGroup = aNewGroups.begin(); + for ( ; aGIter != aGroupsConstr.end(); aGIter++, aGroup++) + if (aGIter->find(aConstrMapIter->second) != aGIter->end()) + { + (*aGroup)->changeConstraint(aConstrMapIter->first); + removeConstraint(aConstrMapIter->first); + // restore iterator + aConstrMapIter = myConstraintMap.begin(); + for (int i = 0; i < aConstrMapPos; i++) + aConstrMapIter++; + break; + } + if (aGIter == aGroupsConstr.end()) { - int anEntPos = Search(aEDelIter->first, myEntities); - std::vector::iterator aEntIter = myEntities.begin() + anEntPos; - // Number of parameters for the entity - int aNbParams = 0; - while (aEntIter->param[aNbParams]) aNbParams++; - if (aNbParams == 0) continue; - // Decrease parameter indexer if there are deleted parameter with higher IDs - if (aEntIter->param[aNbParams-1] == myParamMaxID) - myParamMaxID -= aNbParams; - // Remove parameters of the entity - int aParamPos = Search(aEntIter->param[0], myParams); - myParams.erase(myParams.begin() + aParamPos, - myParams.begin() + aParamPos + aNbParams); - - // Remove entity - if (aEDelIter->first == myEntityMaxID) - myEntityMaxID--; - myEntities.erase(myEntities.begin() + anEntPos); - // Remove such entity from myEntityMap - std::map, Slvs_hEntity>::iterator - anEntMapIter = myEntityMap.begin(); - for ( ; anEntMapIter != myEntityMap.end(); anEntMapIter++) - if (anEntMapIter->second == aEDelIter->first) - break; - if (anEntMapIter != myEntityMap.end()) - myEntityMap.erase(anEntMapIter); + aConstrMapIter++; + aConstrMapPos++; } - if (aPtDelIter->second) // remove link for this entity from list of coincident points + } + + theCuts.insert(theCuts.end(), aNewGroups.begin(), aNewGroups.end()); +} + +// ============================================================================ +// Function: updateGroup +// Class: SketchSolver_ConstraintGroup +// Purpose: search removed entities and constraints +// ============================================================================ +bool SketchSolver_ConstraintGroup::updateGroup() +{ + std::map, Slvs_hConstraint>::reverse_iterator + aConstrIter = myConstraintMap.rbegin(); + bool isAllValid = true; + bool isCCRemoved = false; // indicates that at least one of coincidence constraints was removed + while (isAllValid && aConstrIter != myConstraintMap.rend()) + { + if (!aConstrIter->first->data()->isValid()) { - std::vector< std::set >::iterator aCoPtIter = myCoincidentPoints.begin(); - for ( ; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) - aCoPtIter->erase(aPtDelIter->first); + if (aConstrIter->first->getKind().compare("SketchConstraintCoincidence") == 0) + isCCRemoved = true; + std::map, Slvs_hConstraint>::reverse_iterator + aCopyIter = aConstrIter++; + removeConstraint(aCopyIter->first); + isAllValid = false; } + else aConstrIter++; } - return false; + // Probably, need to update coincidence constraints + if (isCCRemoved && !myExtraCoincidence.empty()) + { + // Make a copy, because the new list of unused constrtaints will be generated + std::set< boost::shared_ptr > anExtraCopy = myExtraCoincidence; + myExtraCoincidence.clear(); + + std::set< boost::shared_ptr >::iterator + aCIter = anExtraCopy.begin(); + for ( ; aCIter != anExtraCopy.end(); aCIter++) + if ((*aCIter)->data()->isValid()) + changeConstraint(*aCIter); + } + + return !isAllValid; } // ============================================================================ @@ -840,7 +827,7 @@ void SketchSolver_ConstraintGroup::updateAttribute( void SketchSolver_ConstraintGroup::updateEntityIfPossible( boost::shared_ptr theEntity) { - if (myEntityMap.find(theEntity) != myEntityMap.end()) + if (myEntityAttrMap.find(theEntity) != myEntityAttrMap.end()) { // If the attribute is a point and it is changed (the group needs to rebuild), // probably user has dragged this point into this position, @@ -879,8 +866,8 @@ void SketchSolver_ConstraintGroup::addTemporaryConstraintWhereDragged( { // Find identifier of the entity std::map, Slvs_hEntity>::const_iterator - anEntIter = myEntityMap.find(theEntity); - if (anEntIter == myEntityMap.end()) + anEntIter = myEntityAttrMap.find(theEntity); + if (anEntIter == myEntityAttrMap.end()) return ; // If this is a first dragged point, its parameters should be placed @@ -953,6 +940,153 @@ void SketchSolver_ConstraintGroup::removeTemporaryConstraints() myTempPointWhereDragged.clear(); } +// ============================================================================ +// Function: removeConstraint +// Class: SketchSolver_ConstraintGroup +// Purpose: remove constraint and all unused entities +// ============================================================================ +void SketchSolver_ConstraintGroup::removeConstraint(boost::shared_ptr theConstraint) +{ + std::map, Slvs_hConstraint>::iterator + anIterToRemove = myConstraintMap.find(theConstraint); + if (anIterToRemove == myConstraintMap.end()) + return ; + + Slvs_hConstraint aCnstrToRemove = anIterToRemove->second; + // Remove constraint from the map + myConstraintMap.erase(anIterToRemove); + + // Find unused entities + int aConstrPos = Search(aCnstrToRemove, myConstraints); + std::set anEntToRemove; + Slvs_hEntity aCnstEnt[] = {myConstraints[aConstrPos].ptA, myConstraints[aConstrPos].ptB, + myConstraints[aConstrPos].entityA, myConstraints[aConstrPos].entityB}; + for (int i = 0; i < 4; i++) + if (aCnstEnt[i] != 0) + anEntToRemove.insert(aCnstEnt[i]); + myConstraints.erase(myConstraints.begin() + aConstrPos); + if (aCnstrToRemove == myConstrMaxID) + myConstrMaxID--; + std::vector::const_iterator aConstrIter = myConstraints.begin(); + for ( ; aConstrIter != myConstraints.end(); aConstrIter++) + { + Slvs_hEntity aEnts[] = {aConstrIter->ptA, aConstrIter->ptB, + aConstrIter->entityA, aConstrIter->entityB}; + for (int i = 0; i < 4; i++) + if (aEnts[i] != 0 && anEntToRemove.find(aEnts[i]) != anEntToRemove.end()) + anEntToRemove.erase(aEnts[i]); + } + + if (anEntToRemove.empty()) + return ; + + // Remove unused entities + std::map, Slvs_hEntity>::iterator + anEntAttrIter = myEntityAttrMap.begin(); + while (anEntAttrIter != myEntityAttrMap.end()) + { + if (anEntToRemove.find(anEntAttrIter->second) != anEntToRemove.end()) + { + std::map, Slvs_hEntity>::iterator + aRemovedIter = anEntAttrIter; + anEntAttrIter++; + myEntityAttrMap.erase(aRemovedIter); + } + else anEntAttrIter++; + } + std::map, Slvs_hEntity>::iterator + anEntFeatIter = myEntityFeatMap.begin(); + while (anEntFeatIter != myEntityFeatMap.end()) + { + if (anEntToRemove.find(anEntFeatIter->second) != anEntToRemove.end()) + { + std::map, Slvs_hEntity>::iterator + aRemovedIter = anEntFeatIter; + anEntFeatIter++; + myEntityFeatMap.erase(aRemovedIter); + } + else anEntFeatIter++; + } + std::set::const_reverse_iterator aRemIter = anEntToRemove.rbegin(); + for ( ; aRemIter != anEntToRemove.rend(); aRemIter++) + { + unsigned int anEntPos = Search(*aRemIter, myEntities); + if (anEntPos >= myEntities.size()) + continue; + unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams); + if (aParamPos >= myParams.size()) + continue; + int aNbParams = 0; + while (myEntities[anEntPos].param[aNbParams] != 0) + aNbParams++; + if (myEntities[anEntPos].param[aNbParams-1] == myParamMaxID) + myParamMaxID -= aNbParams; + myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams); + if (*aRemIter == myEntityMaxID) + myEntityMaxID--; + myEntities.erase(myEntities.begin() + anEntPos); + + // Remove entity's ID from the lists of conincident points + std::vector< std::set >::iterator aCoPtIter = myCoincidentPoints.begin(); + for ( ; aCoPtIter != myCoincidentPoints.end(); aCoPtIter++) + aCoPtIter->erase(*aRemIter); + } + if (myCoincidentPoints.size() == 1 && myCoincidentPoints.front().empty()) + myCoincidentPoints.clear(); +} + + +// ============================================================================ +// Function: addCoincidentPoints +// Class: SketchSolver_ConstraintGroup +// Purpose: add coincident point the appropriate list of such points +// ============================================================================ +bool SketchSolver_ConstraintGroup::addCoincidentPoints( + const Slvs_hEntity& thePoint1, const Slvs_hEntity& thePoint2) +{ + std::vector< std::set >::iterator aCoPtIter = myCoincidentPoints.begin(); + std::vector< std::set >::iterator aFirstFound = myCoincidentPoints.end(); + while (aCoPtIter != myCoincidentPoints.end()) + { + bool isFound[2] = { // indicate which point ID was already in coincidence constraint + aCoPtIter->find(thePoint1) != aCoPtIter->end(), + aCoPtIter->find(thePoint2) != aCoPtIter->end(), + }; + if (isFound[0] && isFound[1]) // points are already connected by coincidence constraints => no need additional one + return false; + if ((isFound[0] && !isFound[1]) || (!isFound[0] && isFound[1])) + { + if (aFirstFound != myCoincidentPoints.end()) + { // there are two groups of coincident points connected by created constraint => merge them + int aFirstFoundShift = aFirstFound - myCoincidentPoints.begin(); + int aCurrentShift = aCoPtIter - myCoincidentPoints.begin(); + aFirstFound->insert(aCoPtIter->begin(), aCoPtIter->end()); + myCoincidentPoints.erase(aCoPtIter); + aFirstFound = myCoincidentPoints.begin() + aFirstFoundShift; + aCoPtIter = myCoincidentPoints.begin() + aCurrentShift; + continue; + } + else + { + aCoPtIter->insert(isFound[0] ? thePoint2 : thePoint1); + aFirstFound = aCoPtIter; + } + } + aCoPtIter++; + } + // No points were found, need to create new set + if (aFirstFound == myCoincidentPoints.end()) + { + std::set aNewSet; + aNewSet.insert(thePoint1); + aNewSet.insert(thePoint2); + myCoincidentPoints.push_back(aNewSet); + } + + return true; +} + + // ========================================================