void CmdPartSection::activated(int iMsg) { unsigned int n = getSelection().countObjectsOfType(Part::Feature::getClassTypeId()); if (n != 2) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), QObject::tr("Select two shapes please.")); return; } std::vector<Gui::SelectionSingleton::SelObj> Sel = getSelection().getSelection(); std::string FeatName = getUniqueObjectName("Section"); std::string BaseName = Sel[0].FeatName; std::string ToolName = Sel[1].FeatName; openCommand("Section"); doCommand(Doc,"App.activeDocument().addObject(\"Part::Section\",\"%s\")",FeatName.c_str()); doCommand(Doc,"App.activeDocument().%s.Base = App.activeDocument().%s",FeatName.c_str(),BaseName.c_str()); doCommand(Doc,"App.activeDocument().%s.Tool = App.activeDocument().%s",FeatName.c_str(),ToolName.c_str()); doCommand(Gui,"Gui.activeDocument().hide('%s')",BaseName.c_str()); doCommand(Gui,"Gui.activeDocument().hide('%s')",ToolName.c_str()); doCommand(Gui,"Gui.activeDocument().%s.LineColor = Gui.activeDocument().%s.ShapeColor", FeatName.c_str(),BaseName.c_str()); updateActive(); commitCommand(); }
void CmdPartDesignMigrate::activated(int iMsg) { Q_UNUSED(iMsg); App::Document *doc = getDocument(); std::set<PartDesign::Feature*> migrateFeatures; // Retrive all PartDesign Features objects and filter out features already belongs to some body for ( const auto & feat: doc->getObjects( ) ) { if( feat->isDerivedFrom( PartDesign::Feature::getClassTypeId() ) && !PartDesign::Body::findBodyOf( feat ) && PartDesign::Body::isSolidFeature ( feat ) ) { migrateFeatures.insert ( static_cast <PartDesign::Feature *>( feat ) ); } } if ( migrateFeatures.empty() ) { if ( !PartDesignGui::isModernWorkflow ( doc ) ) { // If there is nothing to migrate and workflow is still old just set it to modern PartDesignGui::WorkflowManager::instance()->forceWorkflow ( doc, PartDesignGui::Workflow::Modern ); } else { // Huh? nothing to migrate? QMessageBox::warning ( 0, QObject::tr ( "Nothing to migrate" ), QObject::tr ( "No PartDesign features which doesn't belong to a body found." " Nothing to migrate." ) ); } return; } // Note: this action is undoable, should it be? PartDesignGui::WorkflowManager::instance()->forceWorkflow ( doc, PartDesignGui::Workflow::Modern ); // Put features into chains. Each chain should become a separate body. std::list< std::list<PartDesign::Feature *> > featureChains; std::list<PartDesign::Feature *> chain; //< the current chain we are working on for (auto featIt = migrateFeatures.begin(); !migrateFeatures.empty(); ) { Part::Feature *base = (*featIt)->getBaseObject( /*silent =*/ true ); chain.push_front ( *featIt ); if ( !base || !base->isDerivedFrom (PartDesign::Feature::getClassTypeId () ) || PartDesignGui::isAnyNonPartDesignLinksTo ( static_cast <PartDesign::Feature *>(base), /*respectGroups=*/ true ) ) { // a feature based on nothing as well as on non-partdesign solid starts a new chain auto newChainIt = featureChains.emplace (featureChains.end()); newChainIt->splice (newChainIt->end(), chain); } else { // we are basing on some partdesign feature which supposed to belong to some body PartDesign::Feature *baseFeat = static_cast <PartDesign::Feature *>( base ); auto baseFeatSetIt = find ( migrateFeatures.begin (), migrateFeatures.end (), baseFeat ); if ( baseFeatSetIt != migrateFeatures.end() ) { // base feature is pending for migration, switch to it and continue over migrateFeatures.erase(featIt); featIt = baseFeatSetIt; continue; } else { // The base feature seems already assigned to some chain // Find which std::list<PartDesign::Feature *>::iterator baseFeatIt; auto chainIt = std::find_if( featureChains.begin(), featureChains.end(), [baseFeat, &baseFeatIt] ( std::list<PartDesign::Feature *>&chain ) mutable -> bool { baseFeatIt = std::find( chain.begin(), chain.end(), baseFeat ); return baseFeatIt != chain.end(); } ); if ( chainIt != featureChains.end() ) { assert (baseFeatIt != chainIt->end()); if ( std::next ( baseFeatIt ) == chainIt->end() ) { // just append our chain to already found chainIt->splice ( chainIt->end(), chain ); // TODO If we will hit a third part everything will be messed up again. // Probably it will require a yet another smart-ass find_if. (2015-08-10, Fat-Zer) } else { // We have a fork of a partDesign feature here // add a chain for current body auto newChainIt = featureChains.emplace (featureChains.end()); newChainIt->splice (newChainIt->end(), chain); // add a chain for forked one newChainIt = featureChains.emplace (featureChains.end()); newChainIt->splice (newChainIt->end(), *chainIt, std::next ( baseFeatIt ), chainIt->end()); } } else { // The feature is not present in list pending for migration, // This generally shouldn't happen but may be if we run into some broken file // Try to find out the body we should insert into // TODO Some error/warning is needed here (2015-08-10, Fat-Zer) auto newChainIt = featureChains.emplace (featureChains.end()); newChainIt->splice (newChainIt->end(), chain); } } } migrateFeatures.erase ( featIt ); featIt = migrateFeatures.begin (); // TODO Align visibility (2015-08-17, Fat-Zer) } /* for */ // TODO make it work without parts (2015-09-04, Fat-Zer) // add a part if there is no active yet App::Part *actPart = PartDesignGui::assertActivePart (); if (!actPart) { return; } // do the actual migration Gui::Command::openCommand("Migrate legacy part design features to Bodies"); for ( auto chainIt = featureChains.begin(); !featureChains.empty(); featureChains.erase (chainIt), chainIt = featureChains.begin () ) { #ifndef FC_DEBUG if ( chainIt->empty () ) { // prevent crash in release in case of errors continue; } #else assert ( !chainIt->empty () ); #endif Part::Feature *base = chainIt->front()->getBaseObject ( /*silent =*/ true ); // Find a suitable chain to work with for( ; chainIt != featureChains.end(); chainIt ++) { base = chainIt->front()->getBaseObject ( /*silent =*/ true ); if (!base || !base->isDerivedFrom ( PartDesign::Feature::getClassTypeId () ) ) { break; // no base is ok } else { // The base feature is a PartDesign, it's a fork, try to reassign it to a body... base = PartDesign::Body::findBodyOf ( base ); if ( base ) { break; } } } if ( chainIt == featureChains.end() ) { // Shouldn't happen, may be only in case of some circular dependency? // TODO Some error message (2015-08-11, Fat-Zer) chainIt = featureChains.begin(); base = chainIt->front()->getBaseObject ( /*silent =*/ true ); } // Construct a Pretty Body name based on the Tip std::string bodyName = getUniqueObjectName ( std::string ( chainIt->back()->getNameInDocument() ).append ( "Body" ).c_str () ) ; // Create a body for the chain doCommand ( Doc,"App.activeDocument().addObject('PartDesign::Body','%s')", bodyName.c_str () ); doCommand ( Doc,"App.activeDocument().%s.addObject(App.ActiveDocument.%s)", actPart->getNameInDocument (), bodyName.c_str () ); if (base) { doCommand ( Doc,"App.activeDocument().%s.BaseFeature = App.activeDocument().%s", bodyName.c_str (), base->getNameInDocument () ); } // Fill the body with features for ( auto feature: *chainIt ) { if ( feature->isDerivedFrom ( PartDesign::ProfileBased::getClassTypeId() ) ) { // add the sketch and also reroute it if needed PartDesign::ProfileBased *sketchBased = static_cast<PartDesign::ProfileBased *> ( feature ); Part::Part2DObject *sketch = sketchBased->getVerifiedSketch( /*silent =*/ true); if ( sketch ) { doCommand ( Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)", bodyName.c_str (), sketch->getNameInDocument() ); if ( sketch->isDerivedFrom ( Sketcher::SketchObject::getClassTypeId() ) ) { try { PartDesignGui::fixSketchSupport ( static_cast<Sketcher::SketchObject *> ( sketch ) ); } catch (Base::Exception &) { QMessageBox::critical(Gui::getMainWindow(), QObject::tr("Sketch plane cannot be migrated"), QObject::tr("Please edit '%1' and redefine it to use a Base or " "Datum plane as the sketch plane."). arg(QString::fromUtf8(sketch->Label.getValue()) ) ); } } else { // TODO Message that sketchbased is based not on a sketch (2015-08-11, Fat-Zer) } } } doCommand ( Doc,"App.activeDocument().%s.addObject(App.activeDocument().%s)", bodyName.c_str (), feature->getNameInDocument() ); PartDesignGui::relinkToBody ( feature ); } } updateActive(); }
void CmdPartDesignBody::activated(int iMsg) { Q_UNUSED(iMsg); if ( !PartDesignGui::assureModernWorkflow( getDocument() ) ) return; App::Part *actPart = PartDesignGui::getActivePart (); App::Part* partOfBaseFeature = nullptr; std::vector<App::DocumentObject*> features = getSelection().getObjectsOfType(Part::Feature::getClassTypeId()); App::DocumentObject* baseFeature = nullptr; bool viewAll = features.empty(); if (!features.empty()) { if (features.size() == 1) { baseFeature = features[0]; if ( baseFeature->isDerivedFrom ( PartDesign::Feature::getClassTypeId() ) && PartDesign::Body::findBodyOf ( baseFeature ) ) { // Prevent creating bodies based on features already belonging to other bodies QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Bad base feature"), QObject::tr("Body can't be based on a PartDesign feature.")); baseFeature = nullptr; } else if (PartDesign::Body::findBodyOf ( baseFeature )){ QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Bad base feature"), QObject::tr("%1 already belongs to a body, can't use it as base feature for another body.") .arg(QString::fromUtf8(baseFeature->Label.getValue()))); baseFeature = nullptr; } else if ( baseFeature->isDerivedFrom ( Part::BodyBase::getClassTypeId() ) ) { // Prevent creating bodies based on bodies QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Bad base feature"), QObject::tr("Body can't be based on another body.")); baseFeature = nullptr; } else { partOfBaseFeature = App::Part::getPartOfObject(baseFeature); if (partOfBaseFeature != 0 && partOfBaseFeature != actPart){ //prevent cross-part mess QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Bad base feature"), QObject::tr("Base feature (%1) belongs to other part.") .arg(QString::fromUtf8(baseFeature->Label.getValue()))); baseFeature = nullptr; }; } } else { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Bad base feature"), QObject::tr("Body may be based no more than on one feature.")); return; } } openCommand("Add a Body"); std::string bodyName = getUniqueObjectName("Body"); // add the Body feature itself, and make it active doCommand(Doc,"App.activeDocument().addObject('PartDesign::Body','%s')", bodyName.c_str()); if (baseFeature) { if (partOfBaseFeature){ //withdraw base feature from Part, otherwise visibility mandess results doCommand(Doc,"App.activeDocument().%s.removeObject(App.activeDocument().%s)", partOfBaseFeature->getNameInDocument(), baseFeature->getNameInDocument()); } doCommand(Doc,"App.activeDocument().%s.BaseFeature = App.activeDocument().%s", bodyName.c_str(), baseFeature->getNameInDocument()); } addModule(Gui,"PartDesignGui"); // import the Gui module only once a session doCommand(Gui::Command::Gui, "Gui.activeView().setActiveObject('%s', App.activeDocument().%s)", PDBODYKEY, bodyName.c_str()); // Make the "Create sketch" prompt appear in the task panel doCommand(Gui,"Gui.Selection.clearSelection()"); doCommand(Gui,"Gui.Selection.addSelection(App.ActiveDocument.%s)", bodyName.c_str()); if (actPart) { doCommand(Doc,"App.activeDocument().%s.addObject(App.ActiveDocument.%s)", actPart->getNameInDocument(), bodyName.c_str()); } // The method 'SoCamera::viewBoundingBox' is still declared as protected in Coin3d versions // older than 4.0. #if COIN_MAJOR_VERSION >= 4 // if no part feature was there then auto-adjust the camera if (viewAll) { Gui::Document* doc = Gui::Application::Instance->getDocument(getDocument()); Gui::View3DInventor* view = doc ? qobject_cast<Gui::View3DInventor*>(doc->getActiveView()) : nullptr; if (view) { SoCamera* camera = view->getViewer()->getCamera(); SbViewportRegion vpregion = view->getViewer()->getViewportRegion(); float aspectratio = vpregion.getViewportAspectRatio(); float size = Gui::ViewProviderOrigin::defaultSize(); SbBox3f bbox; bbox.setBounds(-size,-size,-size,size,size,size); camera->viewBoundingBox(bbox, aspectratio, 1.0f); } } #endif updateActive(); }