X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModel%2FModel_Objects.cpp;h=b30356fffe7c4449f063a15733bfd1930b54c124;hb=dc19b4c930a9c2cf5db509fc81586deab00e7417;hp=2dafa892936d21324a40d1c1a3f8c9854660ae06;hpb=182ef2125296294187cf8da27dc36d6415083140;p=modules%2Fshaper.git diff --git a/src/Model/Model_Objects.cpp b/src/Model/Model_Objects.cpp index 2dafa8929..b30356fff 100644 --- a/src/Model/Model_Objects.cpp +++ b/src/Model/Model_Objects.cpp @@ -12,10 +12,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -29,6 +31,8 @@ #include #include #include +#include +#include static const int TAG_OBJECTS = 2; // tag of the objects sub-tree (features, results) @@ -49,7 +53,8 @@ void Model_Objects::setOwner(DocumentPtr theDoc) { myDoc = theDoc; // update all fields and recreate features and result objects if needed - synchronizeFeatures(false, true, true); + TDF_LabelList aNoUpdated; + synchronizeFeatures(aNoUpdated, true, true); myHistory.clear(); } @@ -57,16 +62,24 @@ Model_Objects::~Model_Objects() { // delete all features of this document Events_Loop* aLoop = Events_Loop::loop(); - NCollection_DataMap::Iterator aFeaturesIter(myFeatures); - for(; aFeaturesIter.More(); aFeaturesIter.Next()) { + // erase one by one to avoid access from the feature destructor itself from he map + // blocks the flush signals to avoid the temporary objects visualization in the viewer + // they should not be shown in order to do not lose highlight by erasing them + bool isActive = aLoop->activateFlushes(false); + + while(!myFeatures.IsEmpty()) { + NCollection_DataMap::Iterator aFeaturesIter(myFeatures); FeaturePtr aFeature = aFeaturesIter.Value(); static Events_ID EVENT_DISP = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY); ModelAPI_EventCreator::get()->sendDeleted(myDoc, ModelAPI_Feature::group()); ModelAPI_EventCreator::get()->sendUpdated(aFeature, EVENT_DISP); - aFeature->eraseResults(); + aFeature->removeResults(0, false); + //aFeature->eraseResults(); aFeature->erase(); + myFeatures.UnBind(aFeaturesIter.Key()); } - myFeatures.Clear(); + aLoop->activateFlushes(isActive); + aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED)); aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED)); aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY)); @@ -105,11 +118,8 @@ void Model_Objects::addFeature(FeaturePtr theFeature, const FeaturePtr theAfterT if (!theFeature->isAction()) { // do not add action to the data model TDF_Label aFeaturesLab = featuresLabel(); TDF_Label aFeatureLab = aFeaturesLab.NewChild(); - initData(theFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS); - // keep the feature ID to restore document later correctly - TDataStd_Comment::Set(aFeatureLab, theFeature->getKind().c_str()); - myFeatures.Bind(aFeatureLab, theFeature); - // store feature in the features array + // store feature in the features array: before "initData" because in macro features + // in initData it creates new features, appeared later than this TDF_Label aPrevFeateureLab; if (theAfterThis.get()) { // searching for the previous feature label std::shared_ptr aPrevData = @@ -119,11 +129,21 @@ void Model_Objects::addFeature(FeaturePtr theFeature, const FeaturePtr theAfterT } } AddToRefArray(aFeaturesLab, aFeatureLab, aPrevFeateureLab); + + // keep the feature ID to restore document later correctly + TDataStd_Comment::Set(aFeatureLab, theFeature->getKind().c_str()); + myFeatures.Bind(aFeatureLab, theFeature); + // must be after binding to the map because of "Box" macro feature that + // creates other features in "initData" + initData(theFeature, aFeatureLab, TAG_FEATURE_ARGUMENTS); // event: feature is added static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED); ModelAPI_EventCreator::get()->sendUpdated(theFeature, anEvent); theFeature->setDisabled(false); // by default created feature is enabled updateHistory(ModelAPI_Feature::group()); + } else { // make feature has not-null data anyway + theFeature->setData(Model_Data::invalidData()); + theFeature->setDoc(myDoc); } } @@ -165,14 +185,14 @@ void Model_Objects::refsToFeature(FeaturePtr theFeature, // check the feature: it must have no depended objects on it // the dependencies can be in the feature results std::list::const_iterator aResIter = theFeature->results().cbegin(); - for(; aResIter != theFeature->results().cend(); aResIter++) { + for (; aResIter != theFeature->results().cend(); aResIter++) { ResultPtr aResult = (*aResIter); std::shared_ptr aData = - std::dynamic_pointer_cast(aResult->data()); + std::dynamic_pointer_cast(aResult->data()); if (aData.get() != NULL) { const std::set& aRefs = aData->refsToMe(); std::set::const_iterator aRefIt = aRefs.begin(), aRefLast = aRefs.end(); - for(; aRefIt != aRefLast; aRefIt++) { + for (; aRefIt != aRefLast; aRefIt++) { FeaturePtr aFeature = std::dynamic_pointer_cast((*aRefIt)->owner()); if (aFeature.get() != NULL) theRefs.insert(aFeature); @@ -185,7 +205,7 @@ void Model_Objects::refsToFeature(FeaturePtr theFeature, if (aData && !aData->refsToMe().empty()) { const std::set& aRefs = aData->refsToMe(); std::set::const_iterator aRefIt = aRefs.begin(), aRefLast = aRefs.end(); - for(; aRefIt != aRefLast; aRefIt++) { + for (; aRefIt != aRefLast; aRefIt++) { FeaturePtr aFeature = std::dynamic_pointer_cast((*aRefIt)->owner()); if (aFeature.get() != NULL) theRefs.insert(aFeature); @@ -201,14 +221,7 @@ void Model_Objects::refsToFeature(FeaturePtr theFeature, void Model_Objects::removeFeature(FeaturePtr theFeature) { std::shared_ptr aData = std::static_pointer_cast(theFeature->data()); - if (aData) { - TDF_Label aFeatureLabel = aData->label().Father(); - if (myFeatures.IsBound(aFeatureLabel)) - myFeatures.UnBind(aFeatureLabel); - else - return; // not found feature => do not remove - - clearHistory(theFeature); + if (aData && aData->isValid()) { // checking that the sub-element of composite feature is removed: if yes, inform the owner std::set > aRefs; refsToFeature(theFeature, aRefs, false); @@ -220,16 +233,23 @@ void Model_Objects::removeFeature(FeaturePtr theFeature) aComposite->removeFeature(theFeature); } } + // this must be before erase since theFeature erasing removes all information about + // the feature results and groups of results + // To reproduce: create sketch, extrusion, remove sketch => constructions tree is not updated + clearHistory(theFeature); // erase fields theFeature->erase(); + + TDF_Label aFeatureLabel = aData->label().Father(); + if (myFeatures.IsBound(aFeatureLabel)) + myFeatures.UnBind(aFeatureLabel); + static Events_ID EVENT_DISP = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY); ModelAPI_EventCreator::get()->sendUpdated(theFeature, EVENT_DISP); // erase all attributes under the label of feature aFeatureLabel.ForgetAllAttributes(); // remove it from the references array - if (theFeature->isInHistory()) { - RemoveFromRefArray(featuresLabel(), aFeatureLabel); - } + RemoveFromRefArray(featuresLabel(), aFeatureLabel); // event: feature is deleted ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), ModelAPI_Feature::group()); // the redisplay signal should be flushed in order to erase the feature presentation in the viewer @@ -238,6 +258,59 @@ void Model_Objects::removeFeature(FeaturePtr theFeature) } } +void Model_Objects::moveFeature(FeaturePtr theMoved, FeaturePtr theAfterThis) +{ + TDF_Label aFeaturesLab = featuresLabel(); + Handle(TDataStd_ReferenceArray) aRefs; + if (!aFeaturesLab.FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) + return; + TDF_Label anAfterLab, aMovedLab = + std::dynamic_pointer_cast(theMoved->data())->label().Father(); + if (theAfterThis.get()) + anAfterLab = std::dynamic_pointer_cast(theAfterThis->data())->label().Father(); + + Handle(TDataStd_HLabelArray1) aNewArray = + new TDataStd_HLabelArray1(aRefs->Lower(), aRefs->Upper()); + int aPassedMovedFrom = 0; // the prev feature location is found and passed + int aPassedMovedTo = 0; // the feature is added and this location is passed + if (!theAfterThis.get()) { // null means that inserted feature must be the first + aNewArray->SetValue(aRefs->Lower(), aMovedLab); + aPassedMovedTo = 1; + } + for (int a = aRefs->Lower(); a <= aRefs->Upper(); a++) { + if (aPassedMovedTo == 0 && aRefs->Value(a) == anAfterLab) { // add two + aPassedMovedTo++; + aNewArray->SetValue(a - aPassedMovedFrom, anAfterLab); + if (a + 1 - aPassedMovedFrom <= aRefs->Upper()) + aNewArray->SetValue(a + 1 - aPassedMovedFrom, aMovedLab); + } else if (aPassedMovedFrom == 0 && aRefs->Value(a) == aMovedLab) { // skip + aPassedMovedFrom++; + } else { // just copy one + if (a - aPassedMovedFrom + aPassedMovedTo <= aRefs->Upper()) + aNewArray->SetValue(a - aPassedMovedFrom + aPassedMovedTo, aRefs->Value(a)); + } + } + if (!aPassedMovedFrom || !aPassedMovedTo) {// not found: unknown situation + if (!aPassedMovedFrom) { + static std::string aMovedFromError("The moved feature is not found"); + Events_Error::send(aMovedFromError); + } else { + static std::string aMovedToError("The 'after' feature for movement is not found"); + Events_Error::send(aMovedToError); + } + return; + } + // store the new array + aRefs->SetInternalArray(aNewArray); + // update the feature and the history + clearHistory(theMoved); + // make sure all (selection) attributes of moved feature will be updated + theMoved->data()->setUpdateID(0); + static Events_ID EVENT_UPD = Events_Loop::loop()->eventByName(EVENT_OBJECT_UPDATED); + ModelAPI_EventCreator::get()->sendUpdated(theMoved, EVENT_UPD); + ModelAPI_EventCreator::get()->sendReordered(theMoved->document(), theMoved->groupName()); +} + void Model_Objects::clearHistory(ObjectPtr theObj) { if (theObj) { @@ -247,8 +320,13 @@ void Model_Objects::clearHistory(ObjectPtr theObj) myHistory.erase(aHIter); // erase from map => this means that it is not synchronized if (theObj->groupName() == ModelAPI_Feature::group()) { // clear results group of the feature FeaturePtr aFeature = std::dynamic_pointer_cast(theObj); - if (aFeature->firstResult().get()) - clearHistory(aFeature->firstResult()); + std::string aResultGroup = featureResultGroup(aFeature); + if (!aResultGroup.empty()) { + std::map >::iterator aHIter = + myHistory.find(aResultGroup); + if (aHIter != myHistory.end()) + myHistory.erase(aHIter); // erase from map => this means that it is not synchronized + } } } } @@ -266,18 +344,21 @@ void Model_Objects::createHistory(const std::string& theGroupID) for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) { FeaturePtr aFeature = feature(aRefs->Value(a)); if (aFeature.get()) { - if (isFeature) { // here may be also disabled features - if (aFeature->isInHistory()) { - aResult.push_back(aFeature); - } - } else if (!aFeature->isDisabled()) { // iterate all results of not-disabled feature - const std::list >& aResults = aFeature->results(); - std::list >::const_iterator aRIter = aResults.begin(); - for (; aRIter != aResults.cend(); aRIter++) { - ResultPtr aRes = *aRIter; - if (aRes->groupName() != theGroupID) break; // feature have only same group results - if (!aRes->isDisabled() && aRes->isInHistory() && !aRes->isConcealed()) { - aResult.push_back(*aRIter); + // if feature is in sub-component, remove it from history: it is in sub-tree of sub-component + if (!ModelAPI_Tools::compositeOwner(aFeature).get()) { + if (isFeature) { // here may be also disabled features + if (aFeature->isInHistory()) { + aResult.push_back(aFeature); + } + } else if (!aFeature->isDisabled()) { // iterate all results of not-disabled feature + const std::list >& aResults = aFeature->results(); + std::list >::const_iterator aRIter = aResults.begin(); + for (; aRIter != aResults.cend(); aRIter++) { + ResultPtr aRes = *aRIter; + if (aRes->groupName() != theGroupID) break; // feature have only same group results + if (!aRes->isDisabled() && aRes->isInHistory() && !aRes->isConcealed()) { + aResult.push_back(*aRIter); + } } } } @@ -314,14 +395,36 @@ ObjectPtr Model_Objects::object(TDF_Label theLabel) return feature(theLabel); TDF_Label aFeatureLabel = theLabel.Father().Father(); // let's suppose it is result aFeature = feature(aFeatureLabel); + bool isSubResult = false; + if (!aFeature.get() && aFeatureLabel.Depth() > 1) { // let's suppose this is sub-result of result + aFeatureLabel = aFeatureLabel.Father().Father(); + aFeature = feature(aFeatureLabel); + isSubResult = true; + } if (aFeature) { const std::list >& aResults = aFeature->results(); std::list >::const_iterator aRIter = aResults.cbegin(); for (; aRIter != aResults.cend(); aRIter++) { - std::shared_ptr aResData = std::dynamic_pointer_cast( - (*aRIter)->data()); - if (aResData->label().Father().IsEqual(theLabel)) - return *aRIter; + if (isSubResult) { + ResultCompSolidPtr aCompRes = std::dynamic_pointer_cast(*aRIter); + if (aCompRes) { + int aNumSubs = aCompRes->numberOfSubs(); + for(int a = 0; a < aNumSubs; a++) { + ResultPtr aSub = aCompRes->subResult(a); + if (aSub.get()) { + std::shared_ptr aSubData = std::dynamic_pointer_cast( + aSub->data()); + if (aSubData->label().Father().IsEqual(theLabel)) + return aSub; + } + } + } + } else { + std::shared_ptr aResData = std::dynamic_pointer_cast( + (*aRIter)->data()); + if (aResData->label().Father().IsEqual(theLabel)) + return *aRIter; + } } } return FeaturePtr(); // not found @@ -329,6 +432,8 @@ ObjectPtr Model_Objects::object(TDF_Label theLabel) ObjectPtr Model_Objects::object(const std::string& theGroupID, const int theIndex) { + if (theIndex == -1) + return ObjectPtr(); createHistory(theGroupID); return myHistory[theGroupID][theIndex]; } @@ -380,9 +485,10 @@ void Model_Objects::allResults(const std::string& theGroupID, std::listgroupName() != theGroupID) break; // feature have only same group results - if (aRes->isInHistory() && !aRes->isConcealed()) { + // iterate also concealed: ALL RESULTS (for translation parts undo/redo management) + //if (aRes->isInHistory() && !aRes->isConcealed()) { theResults.push_back(*aRIter); - } + //} } } } @@ -401,7 +507,7 @@ void Model_Objects::setUniqueName(FeaturePtr theFeature) return; // not needed, name is already defined std::string aName; // result // first count all features of such kind to start with index = count + 1 - int aNumObjects = 0; + int aNumObjects = -1; // this feature is already in this map NCollection_DataMap::Iterator aFIter(myFeatures); for (; aFIter.More(); aFIter.Next()) { if (aFIter.Value()->getKind() == theFeature->getKind()) @@ -450,7 +556,7 @@ void Model_Objects::initData(ObjectPtr theObj, TDF_Label theLab, const int theTa } void Model_Objects::synchronizeFeatures( - const bool theMarkUpdated, const bool theUpdateReferences, const bool theFlush) + const TDF_LabelList& theUpdated, const bool theUpdateReferences, const bool theFlush) { Model_Document* anOwner = std::dynamic_pointer_cast(myDoc).get(); if (!anOwner) // this may happen on creation of document: nothing there, so nothing to synchronize @@ -463,7 +569,18 @@ void Model_Objects::synchronizeFeatures( static Events_ID aRedispEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY); static Events_ID aDeleteEvent = Events_Loop::eventByName(EVENT_OBJECT_DELETED); static Events_ID aToHideEvent = aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY); - aLoop->activateFlushes(false); + bool isActive = aLoop->activateFlushes(false); + + // collect all updated labels map + TDF_LabelMap anUpdatedMap; + TDF_ListIteratorOfLabelList anUpdatedIter(theUpdated); + for(; anUpdatedIter.More(); anUpdatedIter.Next()) { + TDF_Label& aFeatureLab = anUpdatedIter.Value(); + while(aFeatureLab.Depth() > 3) + aFeatureLab = aFeatureLab.Father(); + if (myFeatures.IsBound(aFeatureLab)) + anUpdatedMap.Add(aFeatureLab); + } // update all objects by checking are they on labels or not std::set aNewFeatures, aKeptFeatures; @@ -486,33 +603,28 @@ void Model_Objects::synchronizeFeatures( aNewFeatures.insert(aFeature); initData(aFeature, aFeatureLabel, TAG_FEATURE_ARGUMENTS); updateHistory(aFeature); + aFeature->setDisabled(false); // by default created feature is enabled (this allows to recreate the results before "setCurrent" is called) // event: model is updated ModelAPI_EventCreator::get()->sendUpdated(aFeature, aCreateEvent); } else { // nothing is changed, both iterators are incremented aFeature = myFeatures.Find(aFeatureLabel); aKeptFeatures.insert(aFeature); - if (theMarkUpdated) { + if (anUpdatedMap.Contains(aFeatureLabel)) { ModelAPI_EventCreator::get()->sendUpdated(aFeature, anUpdateEvent); + if (aFeature->getKind() == "Parameter") { // if parameters are changed, update the results (issue 937) + const std::list >& aResults = aFeature->results(); + std::list >::const_iterator aRIter = aResults.begin(); + for (; aRIter != aResults.cend(); aRIter++) { + std::shared_ptr aRes = *aRIter; + if (aRes->data()->isValid() && !aRes->isDisabled()) { + ModelAPI_EventCreator::get()->sendUpdated(aRes, anUpdateEvent); + } + } + } } } } - // update results of the features (after features created because they may be connected, like sketch and sub elements) - std::list aComposites; // composites must be updated after their subs (issue 360) - TDF_ChildIDIterator aLabIter2(featuresLabel(), TDataStd_Comment::GetID()); - for (; aLabIter2.More(); aLabIter2.Next()) { - TDF_Label aFeatureLabel = aLabIter2.Value()->Label(); - if (myFeatures.IsBound(aFeatureLabel)) { // a new feature is inserted - FeaturePtr aFeature = myFeatures.Find(aFeatureLabel); - if (std::dynamic_pointer_cast(aFeature).get()) - aComposites.push_back(aFeature); - updateResults(aFeature); - } - } - std::list::iterator aComposite = aComposites.begin(); - for(; aComposite != aComposites.end(); aComposite++) { - updateResults(*aComposite); - } // check all features are checked: if not => it was removed NCollection_DataMap::Iterator aFIter(myFeatures); @@ -540,17 +652,41 @@ void Model_Objects::synchronizeFeatures( if (theUpdateReferences) { synchronizeBackRefs(); } - if (theMarkUpdated) { // this means there is no control what was modified => remove history cash + // update results of the features (after features created because they may be connected, like sketch and sub elements) + // After synchronisation of back references because sketch must be set in sub-elements before "execute" by updateResults + std::list aComposites; // composites must be updated after their subs (issue 360) + TDF_ChildIDIterator aLabIter2(featuresLabel(), TDataStd_Comment::GetID()); + for (; aLabIter2.More(); aLabIter2.Next()) { + TDF_Label aFeatureLabel = aLabIter2.Value()->Label(); + if (myFeatures.IsBound(aFeatureLabel)) { // a new feature is inserted + FeaturePtr aFeature = myFeatures.Find(aFeatureLabel); + if (std::dynamic_pointer_cast(aFeature).get()) + aComposites.push_back(aFeature); + updateResults(aFeature); + } + } + std::list::iterator aComposite = aComposites.begin(); + for(; aComposite != aComposites.end(); aComposite++) { + updateResults(*aComposite); + } + + // the synchronize should be done after updateResults in order to correct back references of updated results + if (theUpdateReferences) { + synchronizeBackRefs(); + } + if (!theUpdated.IsEmpty()) { // this means there is no control what was modified => remove history cash myHistory.clear(); } anOwner->executeFeatures() = false; - aLoop->activateFlushes(true); + aLoop->activateFlushes(isActive); if (theFlush) { aLoop->flush(aCreateEvent); aLoop->flush(aDeleteEvent); aLoop->flush(anUpdateEvent); + aLoop->flush(aCreateEvent); // after update of features, there could be results created + aLoop->flush(aDeleteEvent); // or deleted aLoop->flush(aRedispEvent); aLoop->flush(aToHideEvent); } @@ -575,10 +711,24 @@ void Model_Objects::synchronizeBackRefs() for (; aRIter != aResults.cend(); aRIter++) { std::shared_ptr aResData = std::dynamic_pointer_cast((*aRIter)->data()); - if (aResData) { + if (aResData.get()) { aConcealed.push_back(std::pair(*aRIter, (*aRIter)->isConcealed())); aResData->eraseBackReferences(); } + // iterate sub-bodies of compsolid + ResultCompSolidPtr aComp = std::dynamic_pointer_cast(*aRIter); + if (aComp.get()) { + int aNumSub = aComp->numberOfSubs(); + for(int a = 0; a < aNumSub; a++) { + ResultPtr aSub = aComp->subResult(a); + std::shared_ptr aResData = + std::dynamic_pointer_cast(aSub->data()); + if (aResData.get()) { + aConcealed.push_back(std::pair(aSub, aSub->isConcealed())); + aResData->eraseBackReferences(); + } + } + } } } @@ -648,7 +798,8 @@ void Model_Objects::storeResult(std::shared_ptr theFeatureData, if (theResult->data()->name().empty()) { // if was not initialized, generate event and set a name std::stringstream aNewName; aNewName<name(); - if (theResultIndex > 0) // if there are several results, add unique prefix starting from second + // if there are several results (issue #899: any number of result), add unique prefix starting from second + if (theResultIndex > 0 || theResult->groupName() == ModelAPI_ResultBody::group()) aNewName<<"_"<data()->setName(aNewName.str()); } @@ -675,14 +826,27 @@ std::shared_ptr Model_Objects::createBody( const std::shared_ptr& theFeatureData, const int theIndex) { TDF_Label aLab = resultLabel(theFeatureData, theIndex); - TDataStd_Comment::Set(aLab, ModelAPI_ResultBody::group().c_str()); - ObjectPtr anOldObject = object(aLab); + // for feature create compsolid, but for result sub create body: + // only one level of recursion is supported now + ResultPtr aResultOwner = std::dynamic_pointer_cast(theFeatureData->owner()); + ObjectPtr anOldObject; + if (aResultOwner.get()) { + TDataStd_Comment::Set(aLab, ModelAPI_ResultBody::group().c_str()); + } else { // in compsolid (higher level result) old object probably may be found + TDataStd_Comment::Set(aLab, ModelAPI_ResultCompSolid::group().c_str()); + anOldObject = object(aLab); + } std::shared_ptr aResult; if (anOldObject) { aResult = std::dynamic_pointer_cast(anOldObject); } if (!aResult) { - aResult = std::shared_ptr(new Model_ResultBody); + // create compsolid anyway; if it is compsolid, it will create sub-bodies internally + if (aResultOwner.get()) { + aResult = std::shared_ptr(new Model_ResultBody); + } else { + aResult = std::shared_ptr(new Model_ResultCompSolid); + } storeResult(theFeatureData, aResult, theIndex); } return aResult; @@ -705,6 +869,15 @@ std::shared_ptr Model_Objects::createPart( return aResult; } +std::shared_ptr Model_Objects::copyPart( + const std::shared_ptr& theOrigin, + const std::shared_ptr& theFeatureData, const int theIndex) +{ + std::shared_ptr aResult = createPart(theFeatureData, theIndex); + aResult->data()->reference(Model_ResultPart::BASE_REF_ID())->setValue(theOrigin); + return aResult; +} + std::shared_ptr Model_Objects::createGroup( const std::shared_ptr& theFeatureData, const int theIndex) { @@ -745,11 +918,32 @@ std::shared_ptr Model_Objects::feature( std::shared_ptr aData = std::dynamic_pointer_cast(theResult->data()); if (aData) { TDF_Label aFeatureLab = aData->label().Father().Father().Father(); - return feature(aFeatureLab); + FeaturePtr aFeature = feature(aFeatureLab); + if (!aFeature.get() && aFeatureLab.Depth() > 1) { // this may be sub-result of result + aFeatureLab = aFeatureLab.Father().Father(); + aFeature = feature(aFeatureLab); + } + return aFeature; } return FeaturePtr(); } +std::string Model_Objects::featureResultGroup(FeaturePtr theFeature) +{ + if (theFeature->data()->isValid()) { + TDF_ChildIterator aLabIter(resultLabel(theFeature->data(), 0).Father()); + if (aLabIter.More()) { + TDF_Label anArgLab = aLabIter.Value(); + Handle(TDataStd_Comment) aGroup; + if (aLabIter.Value().FindAttribute(TDataStd_Comment::GetID(), aGroup)) { + return TCollection_AsciiString(aGroup->Get()).ToCString(); + } + } + } + static std::string anEmpty; + return anEmpty; // not found +} + void Model_Objects::updateResults(FeaturePtr theFeature) { // for not persistent is will be done by parametric updater automatically @@ -758,10 +952,11 @@ void Model_Objects::updateResults(FeaturePtr theFeature) std::list::const_iterator aResIter = theFeature->results().cbegin(); while(aResIter != theFeature->results().cend()) { ResultPtr aBody = std::dynamic_pointer_cast(*aResIter); - if (aBody) { - if (!aBody->data()->isValid()) { + if (aBody.get()) { + std::shared_ptr aData = std::dynamic_pointer_cast(aBody->data()); + if (!aData.get() || !aData->isValid() || (!aBody->isDisabled() && aData->isDeleted())) { // found a disappeared result => remove it - theFeature->removeResult(aBody); + theFeature->eraseResultFromList(aBody); // start iterate from beginning because iterator is corrupted by removing aResIter = theFeature->results().cbegin(); continue; @@ -783,10 +978,15 @@ void Model_Objects::updateResults(FeaturePtr theFeature) TDF_Label anArgLab = aLabIter.Value(); Handle(TDataStd_Comment) aGroup; if (anArgLab.FindAttribute(TDataStd_Comment::GetID(), aGroup)) { - if (aGroup->Get() == ModelAPI_ResultBody::group().c_str()) { + if (aGroup->Get() == ModelAPI_ResultBody::group().c_str() || + aGroup->Get() == ModelAPI_ResultCompSolid::group().c_str()) { aNewBody = createBody(theFeature->data(), aResIndex); } else if (aGroup->Get() == ModelAPI_ResultPart::group().c_str()) { - aNewBody = createPart(theFeature->data(), aResIndex); + std::shared_ptr aNewP = createPart(theFeature->data(), aResIndex); + theFeature->setResult(aNewP, aResIndex); + if (!aNewP->partDoc().get()) + theFeature->execute(); // create the part result: it is better to restore the previous result if it is possible + break; } else if (aGroup->Get() == ModelAPI_ResultConstruction::group().c_str()) { theFeature->execute(); // construction shapes are needed for sketch solver break; @@ -800,7 +1000,7 @@ void Model_Objects::updateResults(FeaturePtr theFeature) TCollection_AsciiString(aGroup->Get()).ToCString()); } } - if (aNewBody) { + if (aNewBody && !aNewBody->data()->isDeleted()) { theFeature->setResult(aNewBody, aResIndex); } } @@ -831,12 +1031,13 @@ ResultPtr Model_Objects::findByName(const std::string theName) FeaturePtr Model_Objects::nextFeature(FeaturePtr theCurrent, const bool theReverse) { std::shared_ptr aData = std::static_pointer_cast(theCurrent->data()); - if (aData) { + if (aData && aData->isValid()) { TDF_Label aFeatureLabel = aData->label().Father(); Handle(TDataStd_ReferenceArray) aRefs; if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) { for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) { // iterate all existing features - if (aRefs->Value(a).IsEqual(aFeatureLabel)) { + TDF_Label aCurLab = aRefs->Value(a); + if (aCurLab.IsEqual(aFeatureLabel)) { a += theReverse ? -1 : 1; if (a >= aRefs->Lower() && a <= aRefs->Upper()) return feature(aRefs->Value(a)); @@ -866,6 +1067,63 @@ FeaturePtr Model_Objects::lastFeature() return FeaturePtr(); // no features at all } +bool Model_Objects::isLater(FeaturePtr theLater, FeaturePtr theCurrent) const +{ + std::shared_ptr aLaterD = std::static_pointer_cast(theLater->data()); + std::shared_ptr aCurrentD = std::static_pointer_cast(theCurrent->data()); + if (aLaterD && aLaterD->isValid() && aCurrentD && aCurrentD->isValid()) { + TDF_Label aLaterL = aLaterD->label().Father(); + TDF_Label aCurrentL = aCurrentD->label().Father(); + int aLaterI = -1, aCurentI = -1; // not found yet state + Handle(TDataStd_ReferenceArray) aRefs; + if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) { + for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) { // iterate all existing features + TDF_Label aCurLab = aRefs->Value(a); + if (aCurLab.IsEqual(aLaterL)) { + aLaterI = a; + } else if (aCurLab.IsEqual(aCurrentL)) { + aCurentI = a; + } else continue; + if (aLaterI != -1 && aCurentI != -1) // both are found + return aLaterI > aCurentI; + } + } + } + return false; // not found, or something is wrong +} + +std::list > Model_Objects::allFeatures() +{ + std::list > aResult; + Handle(TDataStd_ReferenceArray) aRefs; + if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) { + for(int a = aRefs->Lower(); a <= aRefs->Upper(); a++) { + FeaturePtr aFeature = feature(aRefs->Value(a)); + if (aFeature.get()) + aResult.push_back(aFeature); + } + } + return aResult; +} + +int Model_Objects::numInternalFeatures() +{ + Handle(TDataStd_ReferenceArray) aRefs; + if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) { + return aRefs->Upper() - aRefs->Lower() + 1; + } + return 0; // invalid +} + +std::shared_ptr Model_Objects::internalFeature(const int theIndex) +{ + Handle(TDataStd_ReferenceArray) aRefs; + if (featuresLabel().FindAttribute(TDataStd_ReferenceArray::GetID(), aRefs)) { + return feature(aRefs->Value(aRefs->Lower() + theIndex)); + } + return FeaturePtr(); // invalid +} + Standard_Integer HashCode(const TDF_Label& theLab, const Standard_Integer theUpper) { return TDF_LabelMapHasher::HashCode(theLab, theUpper);