void TaskSketchBasedParameters::onSelectReference(const bool pressed, const bool edge, const bool face, const bool planar) {
    // Note: Even if there is no solid, App::Plane and Part::Datum can still be selected

    PartDesign::ProfileBased* pcSketchBased = static_cast<PartDesign::ProfileBased*>(vp->getObject());

    // The solid this feature will be fused to
    App::DocumentObject* prevSolid = pcSketchBased->getBaseObject( /* silent =*/ true );

    if (pressed) {
        Gui::Document* doc = Gui::Application::Instance->activeDocument();
        if (doc) {
            if (pcSketchBased)
                doc->setHide(pcSketchBased->getNameInDocument());
            if (prevSolid)
                doc->setShow(prevSolid->getNameInDocument());
        }
        Gui::Selection().clearSelection();
        Gui::Selection().addSelectionGate
            (new ReferenceSelection(prevSolid, edge, face, planar));
    } else {
        Gui::Selection().rmvSelectionGate();
        Gui::Document* doc = Gui::Application::Instance->activeDocument();
        if (doc) {
            if (pcSketchBased)
                doc->setShow(pcSketchBased->getNameInDocument());
            if (prevSolid)
                doc->setHide(prevSolid->getNameInDocument());
        }
    }
}
const QString TaskSketchBasedParameters::onAddSelection(const Gui::SelectionChanges& msg)
{
    // Note: The validity checking has already been done in ReferenceSelection.cpp
    PartDesign::ProfileBased* pcSketchBased = static_cast<PartDesign::ProfileBased*>(vp->getObject());
    App::DocumentObject* selObj = pcSketchBased->getDocument()->getObject(msg.pObjectName);
    if (selObj == pcSketchBased)
        return QString::fromLatin1("");
    std::string subname = msg.pSubName;
    QString refStr;

    // Remove subname for planes and datum features
    if (PartDesign::Feature::isDatum(selObj)) {
        subname = "";
        refStr = QString::fromLatin1(selObj->getNameInDocument());
    } else {
        int faceId = std::atoi(&subname[4]);
        refStr = QString::fromLatin1(selObj->getNameInDocument()) + QString::fromLatin1(":") + QObject::tr("Face") + QString::number(faceId);
    }

    std::vector<std::string> upToFaces(1,subname);
    pcSketchBased->UpToFace.setValue(selObj, upToFaces);
    recomputeFeature();

    return refStr;
}
void TaskRevolutionParameters::onAxisChanged(int num)
{
    if (blockUpdate)
        return;
    PartDesign::ProfileBased* pcRevolution = static_cast<PartDesign::ProfileBased*>(vp->getObject());

    if(axesInList.size() == 0)
        return;

    App::DocumentObject *oldRefAxis = propReferenceAxis->getValue();
    std::vector<std::string> oldSubRefAxis = propReferenceAxis->getSubValues();

    App::PropertyLinkSub &lnk = *(axesInList[num]);
    if(lnk.getValue() == 0){
        // enter reference selection mode
        TaskSketchBasedParameters::onSelectReference(true, true, false, true);
    } else {
        if (! pcRevolution->getDocument()->isIn(lnk.getValue())){
            Base::Console().Error("Object was deleted\n");
            return;
        }
        propReferenceAxis->Paste(lnk);
        exitSelectionMode();
    }

    App::DocumentObject *newRefAxis = propReferenceAxis->getValue();
    const std::vector<std::string> &newSubRefAxis = propReferenceAxis->getSubValues();
    if (oldRefAxis != newRefAxis ||
        oldSubRefAxis.size() != newSubRefAxis.size() ||
        oldSubRefAxis[0] != newSubRefAxis[0]) {
        bool reversed = propReversed->getValue();
        if(pcRevolution->isDerivedFrom(PartDesign::Revolution::getClassTypeId()))
            reversed = static_cast<PartDesign::Revolution*>(pcRevolution)->suggestReversed();
        if(pcRevolution->isDerivedFrom(PartDesign::Groove::getClassTypeId()))
            reversed = static_cast<PartDesign::Groove*>(pcRevolution)->suggestReversed();

        if (reversed != propReversed->getValue()) {
            propReversed->setValue(reversed);
            ui->checkBoxReversed->blockSignals(true);
            ui->checkBoxReversed->setChecked(reversed);
            ui->checkBoxReversed->blockSignals(false);
        }
    }

    recomputeFeature();
}
void TaskRevolutionParameters::getReferenceAxis(App::DocumentObject*& obj, std::vector<std::string>& sub) const
{
    if (axesInList.size() == 0)
        throw Base::Exception("Not initialized!");

    int num = ui->axis->currentIndex();
    const App::PropertyLinkSub &lnk = *(axesInList[num]);
    if(lnk.getValue() == 0){
        throw Base::Exception("Still in reference selection mode; reference wasn't selected yet");
    } else {
        PartDesign::ProfileBased* pcRevolution = static_cast<PartDesign::ProfileBased*>(vp->getObject());
        if (! pcRevolution->getDocument()->isIn(lnk.getValue())){
            throw Base::Exception("Object was deleted");
            return;
        }
        obj = lnk.getValue();
        sub = lnk.getSubValues();
    }
}
Beispiel #5
0
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();
}
TaskRevolutionParameters::TaskRevolutionParameters(PartDesignGui::ViewProvider* RevolutionView, QWidget *parent)
    : TaskSketchBasedParameters(RevolutionView, parent, "PartDesign_Revolution",tr("Revolution parameters"))
{
    // we need a separate container widget to add all controls to
    proxy = new QWidget(this);
    ui = new Ui_TaskRevolutionParameters();
    ui->setupUi(proxy);
    QMetaObject::connectSlotsByName(this);

    connect(ui->revolveAngle, SIGNAL(valueChanged(double)),
            this, SLOT(onAngleChanged(double)));
    connect(ui->axis, SIGNAL(activated(int)),
            this, SLOT(onAxisChanged(int)));
    connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)),
            this, SLOT(onMidplane(bool)));
    connect(ui->checkBoxReversed, SIGNAL(toggled(bool)),
            this, SLOT(onReversed(bool)));
    connect(ui->checkBoxUpdateView, SIGNAL(toggled(bool)),
            this, SLOT(onUpdateView(bool)));

    this->groupLayout()->addWidget(proxy);

    // Temporarily prevent unnecessary feature recomputes
    ui->revolveAngle->blockSignals(true);
    ui->axis->blockSignals(true);
    ui->checkBoxMidplane->blockSignals(true);
    ui->checkBoxReversed->blockSignals(true);

    //bind property mirrors
    PartDesign::ProfileBased* pcFeat = static_cast<PartDesign::ProfileBased*>(vp->getObject());
    if (pcFeat->isDerivedFrom(PartDesign::Revolution::getClassTypeId())) {
        PartDesign::Revolution* rev = static_cast<PartDesign::Revolution*>(vp->getObject());
        this->propAngle = &(rev->Angle);
        this->propMidPlane = &(rev->Midplane);
        this->propReferenceAxis = &(rev->ReferenceAxis);
        this->propReversed = &(rev->Reversed);
    } else {
        assert(pcFeat->isDerivedFrom(PartDesign::Groove::getClassTypeId()));
        PartDesign::Groove* rev = static_cast<PartDesign::Groove*>(vp->getObject());
        this->propAngle = &(rev->Angle);
        this->propMidPlane = &(rev->Midplane);
        this->propReferenceAxis = &(rev->ReferenceAxis);
        this->propReversed = &(rev->Reversed);
    }

    double l = propAngle->getValue();
    bool mirrored = propMidPlane->getValue();
    bool reversed = propReversed->getValue();

    ui->revolveAngle->setValue(l);
    blockUpdate = false;
    updateUI();


    ui->checkBoxMidplane->setChecked(mirrored);
    ui->checkBoxReversed->setChecked(reversed);

    PartDesign::ProfileBased* sketchBased = static_cast<PartDesign::ProfileBased*>(vp->getObject());
    // TODO This is quite ugly better redo it (2015-11-02, Fat-Zer)
    if ( sketchBased->isDerivedFrom(PartDesign::Revolution::getClassTypeId() ) ) {
        ui->revolveAngle->bind(static_cast<PartDesign::Revolution *> ( sketchBased )->Angle);
    } else if ( sketchBased->isDerivedFrom(PartDesign::Groove::getClassTypeId() ) ) {
        ui->revolveAngle->bind(static_cast<PartDesign::Groove *> ( sketchBased )->Angle);
    }

    ui->revolveAngle->blockSignals(false);
    ui->axis->blockSignals(false);
    ui->checkBoxMidplane->blockSignals(false);
    ui->checkBoxReversed->blockSignals(false);

    setFocus ();

    //show the parts coordinate system axis for selection
    PartDesign::Body * body = PartDesign::Body::findBodyOf ( vp->getObject () );
    if(body) {
        try {
            App::Origin *origin = body->getOrigin();
            ViewProviderOrigin* vpOrigin;
            vpOrigin = static_cast<ViewProviderOrigin*>(Gui::Application::Instance->getViewProvider(origin));
            vpOrigin->setTemporaryVisibility(true, false);
        } catch (const Base::Exception &ex) {
            Base::Console().Error ("%s\n", ex.what () );
        }
     }
}