bool
CornerPinOverlayInteract::onOverlayPenUp(TimeValue time,
                                         const RenderScale & /*renderScale*/,
                                         ViewIdx view,
                                         const QPointF & /*viewportPos*/,
                                         const QPointF & /*pos*/,
                                         double /*pressure*/,
                                         TimeValue /*timestamp*/)
{
    // do not show interact if knob is secret or not enabled
    // see https://github.com/MrKepzie/Natron/issues/932
    KnobDoublePtr from1Knob = _imp->from[0].lock();

    if ( !from1Knob || !from1Knob->shouldDrawOverlayInteract() ) {
        return false;
    }

    bool didSomething = _imp->dragging != -1;

    if ( !_imp->interactiveDrag && (_imp->dragging != -1) ) {
        // no need to redraw overlay since it is slave to the paramaters
        if (_imp->useFromDrag) {
            KnobDoublePtr knob = _imp->from[_imp->dragging].lock();
            assert(knob);
            std::vector<double> val(2);
            val[0] = _imp->fromDrag[_imp->dragging].x;
            val[1] = _imp->fromDrag[_imp->dragging].y;
            knob->setValueAcrossDimensions(val, DimIdx(0), view, eValueChangedReasonUserEdited);
        } else {
            KnobDoublePtr knob = _imp->to[_imp->dragging].lock();
            assert(knob);
            std::vector<double> val(2);
            val[0] = _imp->toDrag[_imp->dragging].x;
            val[1] = _imp->toDrag[_imp->dragging].y;

            if (_imp->toPointsAutoKeyingEnabled) {
                knob->setValueAtTimeAcrossDimensions(time, val, DimIdx(0), view, eValueChangedReasonUserEdited);

                // Also set a keyframe on other points
                for (int i = 0; i < 4; ++i) {
                    if (i == _imp->dragging) {
                        continue;
                    }
                    std::vector<double> values(2);
                    KnobDoublePtr toPoint = _imp->to[i].lock();
                    values[0] = toPoint->getValueAtTime(time, DimIdx(0));
                    values[1] = toPoint->getValueAtTime(time, DimIdx(1));
                    toPoint->setValueAtTimeAcrossDimensions(time, values, DimIdx(0), view, eValueChangedReasonUserEdited);
                }
            } else {
                knob->setValueAcrossDimensions(val, DimIdx(0), view, eValueChangedReasonUserEdited);
            }
        }
    }
    _imp->dragging = -1;

    return didSomething;
} // onOverlayPenUp
Esempio n. 2
0
void
TrackMarker::setKeyFrameOnCenterAndPatternAtTime(TimeValue time)
{
    KnobDoublePtr center = _imp->center.lock();

    {
        std::vector<double> values(2);
        values[0] = center->getValueAtTime(time);
        values[1] = center->getValueAtTime(time, DimIdx(1));
        center->setValueAtTimeAcrossDimensions(time, values);
    }

    KnobDoublePtr patternCorners[4] = {_imp->patternBtmLeft.lock(), _imp->patternTopLeft.lock(), _imp->patternTopRight.lock(), _imp->patternBtmRight.lock()};
    for (int c = 0; c < 4; ++c) {
        KnobDoublePtr k = patternCorners[c];
        std::vector<double> values(2);
        values[0] = k->getValueAtTime(time, DimIdx(0));
        values[1] = k->getValueAtTime(time, DimIdx(1));
        k->setValueAcrossDimensions(values);
    }
}
Esempio n. 3
0
void
TrackerHelper::trackMarkers(const std::list<TrackMarkerPtr >& markers,
                             TimeValue start,
                             TimeValue end,
                             TimeValue frameStep,
                            const ViewerNodePtr& viewer)
{
    if ( markers.empty() ) {
        Q_EMIT trackingFinished();
        return;
    }

    TrackerParamsProviderPtr provider = _imp->provider.lock();
    if (!provider) {
        Q_EMIT trackingFinished();
        return;
    }

    NodePtr trackerNode = provider->getTrackerNode();
    if (!trackerNode) {
        Q_EMIT trackingFinished();
        return;
    }

    if (trackerNode->hasMandatoryInputDisconnected()) {
        Q_EMIT trackingFinished();
        return;
    }



    // The channels we are going to use for tracking
    bool enabledChannels[3];
    provider->getTrackChannels(&enabledChannels[0], &enabledChannels[1], &enabledChannels[2]);


    double formatWidth, formatHeight;
    Format f;
    trackerNode->getApp()->getProject()->getProjectDefaultFormat(&f);
    formatWidth = f.width();
    formatHeight = f.height();

    bool autoKeyingOnEnabledParamEnabled = provider->canDisableMarkersAutomatically();

    /// The accessor and its cache is local to a track operation, it is wiped once the whole sequence track is finished.
    boost::shared_ptr<TrackerFrameAccessor> accessor( new TrackerFrameAccessor(trackerNode, enabledChannels, formatHeight) );
    boost::shared_ptr<mv::AutoTrack> trackContext( new mv::AutoTrack( accessor.get() ) );
    std::vector<TrackMarkerAndOptionsPtr > trackAndOptions;
    mv::TrackRegionOptions mvOptions;
    /*
     Get the global parameters for the LivMV track: pre-blur sigma, No iterations, normalized intensities, etc...
     */
    _imp->beginLibMVOptionsForTrack(&mvOptions);

    /*
     For the given markers, do the following:
     - Get the "User" keyframes that have been set and create a LibMV marker for each keyframe as well as for the "start" time
     - Set the "per-track" parameters that were given by the user, that is the mv::TrackRegionOptions
     - t->mvMarker will contain the marker that evolves throughout the tracking
     */
    int trackIndex = 0;
    for (std::list<TrackMarkerPtr >::const_iterator it = markers.begin(); it != markers.end(); ++it, ++trackIndex) {

        if (autoKeyingOnEnabledParamEnabled) {
            (*it)->setEnabledAtTime(start, true);
        }

        TrackMarkerAndOptionsPtr t(new TrackMarkerAndOptions);
        t->natronMarker = *it;

        int mode_i = (*it)->getMotionModelKnob()->getValue();
        mvOptions.mode = motionModelIndexToLivMVMode(mode_i);

        // Set a keyframe on the marker to initialize its position
        {
            KnobDoublePtr centerKnob = (*it)->getCenterKnob();
            std::vector<double> values(2);
            values[0] = centerKnob->getValueAtTime(start, DimIdx(0));
            values[1] = centerKnob->getValueAtTime(start, DimIdx(1));
            centerKnob->setValueAtTimeAcrossDimensions(start, values);
        }

        // For a translation warp, we do not need to add an animation curve for the pattern which stays constant.
        if (mvOptions.mode != libmv::TrackRegionOptions::TRANSLATION) {
            KnobDoublePtr patternCorners[4];
            patternCorners[0] = (*it)->getPatternBtmLeftKnob();
            patternCorners[1] = (*it)->getPatternBtmRightKnob();
            patternCorners[2] = (*it)->getPatternTopRightKnob();
            patternCorners[3] = (*it)->getPatternTopLeftKnob();
            for (int c = 0; c < 4; ++c) {
                KnobDoublePtr k = patternCorners[c];
                std::vector<double> values(2);
                values[0] = k->getValueAtTime(start, DimIdx(0));
                values[1] = k->getValueAtTime(start, DimIdx(1));
                k->setValueAcrossDimensions(values);
            }
        }

        std::set<double> userKeys;
        t->natronMarker->getMasterKeyFrameTimes(ViewIdx(0), &userKeys);

        if ( userKeys.empty() ) {
            // Set a user keyframe on tracking start if the marker does not have any user keys
            t->natronMarker->setKeyFrame(start, ViewSetSpec(0), 0);
        }

        PreviouslyTrackedFrameSet previousFramesOrdered;

        // Make sure to create a marker at the start time
        userKeys.insert(start);


        // Add a libmv marker for all keyframes
        for (std::set<double>::iterator it2 = userKeys.begin(); it2 != userKeys.end(); ++it2) {

            // Add the marker to the markers ordered only if it can contribute to predicting its next position
            if ( ( (frameStep > 0) && (*it2 <= start) ) || ( (frameStep < 0) && (*it2 >= start) ) ) {
                previousFramesOrdered.insert( PreviouslyComputedTrackFrame(TimeValue(*it2), true) );
            }
        }


        //For all already tracked frames which are not keyframes, add them to the AutoTrack too
        std::set<double> centerKeys;
        t->natronMarker->getCenterKeyframes(&centerKeys);

        for (std::set<double>::iterator it2 = centerKeys.begin(); it2 != centerKeys.end(); ++it2) {
            if ( userKeys.find(*it2) != userKeys.end() ) {
                continue;
            }

            // Add the marker to the markers ordered only if it can contribute to predicting its next position
            if ( ( ( (frameStep > 0) && (*it2 < start) ) || ( (frameStep < 0) && (*it2 > start) ) ) ) {
                previousFramesOrdered.insert( PreviouslyComputedTrackFrame(TimeValue(*it2), false) );
            }
        }


        // Taken from libmv, only initialize the filter to this amount of frames (max)
        const int max_frames_to_predict_from = 20;
        std::list<mv::Marker> previouslyComputedMarkersOrdered;

        // Find the first keyframe that's not considered to go before start or end
        PreviouslyTrackedFrameSet::iterator prevFramesIt = previousFramesOrdered.lower_bound(PreviouslyComputedTrackFrame(start, false));
        if (frameStep < 0) {
            if (prevFramesIt != previousFramesOrdered.end()) {
                while (prevFramesIt != previousFramesOrdered.end() && (int)previouslyComputedMarkersOrdered.size() != max_frames_to_predict_from) {

                    mv::Marker mvMarker;

                    TrackerHelperPrivate::natronTrackerToLibMVTracker(true, enabledChannels, *t->natronMarker, trackIndex, TimeValue(prevFramesIt->frame), frameStep, formatHeight, &mvMarker);
                    trackContext->AddMarker(mvMarker);

                    // insert in the front of the list so that the order is reversed
                    previouslyComputedMarkersOrdered.push_front(mvMarker);
                    ++prevFramesIt;
                }
            }
            // previouslyComputedMarkersOrdered is now ordererd by decreasing order
        } else {

            if (prevFramesIt != previousFramesOrdered.end()) {
                while (prevFramesIt != previousFramesOrdered.begin() && (int)previouslyComputedMarkersOrdered.size() != max_frames_to_predict_from) {

                    mv::Marker mvMarker;

                    TrackerHelperPrivate::natronTrackerToLibMVTracker(true, enabledChannels, *t->natronMarker, trackIndex, TimeValue(prevFramesIt->frame), frameStep, formatHeight, &mvMarker);
                    trackContext->AddMarker(mvMarker);

                    // insert in the front of the list so that the order is reversed
                    previouslyComputedMarkersOrdered.push_front(mvMarker);
                    --prevFramesIt;
                }
                if (prevFramesIt == previousFramesOrdered.begin() && (int)previouslyComputedMarkersOrdered.size() != max_frames_to_predict_from) {
                    mv::Marker mvMarker;

                    TrackerHelperPrivate::natronTrackerToLibMVTracker(true, enabledChannels, *t->natronMarker, trackIndex, TimeValue(prevFramesIt->frame), frameStep, formatHeight, &mvMarker);
                    trackContext->AddMarker(mvMarker);

                    // insert in the front of the list so that the order is reversed
                    previouslyComputedMarkersOrdered.push_front(mvMarker);

                }
            }
            // previouslyComputedMarkersOrdered is now ordererd by increasing order
        }


        // There must be at least 1 marker at the start time
        assert( !previouslyComputedMarkersOrdered.empty() );

        // Initialise the kalman state with the marker at the position

        std::list<mv::Marker>::iterator mIt = previouslyComputedMarkersOrdered.begin();
        t->mvState.Init(*mIt, frameStep);
        ++mIt;
        for (; mIt != previouslyComputedMarkersOrdered.end(); ++mIt) {
            mv::Marker predictedMarker;
            if ( !t->mvState.PredictForward(mIt->frame, &predictedMarker) ) {
                break;
            } else {
                t->mvState.Update(*mIt);
            }
        }


        t->mvOptions = mvOptions;
        trackAndOptions.push_back(t);
    }
    
    
    /*
     Launch tracking in the scheduler thread.
     */
    boost::shared_ptr<TrackArgs> args( new TrackArgs(start, end, frameStep, trackerNode->getApp()->getTimeLine(), viewer, trackContext, accessor, trackAndOptions, formatWidth, formatHeight, autoKeyingOnEnabledParamEnabled) );
    _imp->scheduler->track(args);
} // TrackerHelper::trackMarkers
bool
CornerPinOverlayInteract::onOverlayPenMotion(TimeValue time,
                                             const RenderScale & /*renderScale*/,
                                             ViewIdx view,
                                             const QPointF & /*viewportPos*/,
                                             const QPointF & penPos,
                                             double /*pressure*/,
                                             TimeValue /*timestamp*/)
{
    // do not show interact if knob is secret or not enabled
    // see https://github.com/MrKepzie/Natron/issues/932
    KnobDoublePtr from1Knob = _imp->from[0].lock();

    if ( !from1Knob || !from1Knob->shouldDrawOverlayInteract() ) {
        return false;
    }

    RenderScale pscale;
    getPixelScale(pscale.x, pscale.y);

    OfxPointD to[4];
    OfxPointD from[4];
    bool enable[4];
    bool useFrom;

    if (_imp->dragging == -1) {
        for (int i = 0; i < 4; ++i) {
            _imp->getFrom(time, i, &from[i].x, &from[i].y);
            _imp->getTo(time, i, &to[i].x, &to[i].y);
            enable[i] = _imp->getEnabled(time, i);
        }
        useFrom = _imp->getUseFromPoints(time);
    } else {
        for (int i = 0; i < 4; ++i) {
            to[i] = _imp->toDrag[i];
            from[i] = _imp->fromDrag[i];
            enable[i] = _imp->enableDrag[i];
        }
        useFrom = _imp->useFromDrag;
    }

    if (!useFrom && !_imp->areToPointsAnimated()) {
        return false;
    }

    OfxPointD p[4];
    OfxPointD q[4];
    int enableBegin = 4;
    int enableEnd = 0;
    for (int i = 0; i < 4; ++i) {
        if (enable[i]) {
            if (useFrom) {
                p[i] = from[i];
                q[i] = to[i];
            } else {
                q[i] = from[i];
                p[i] = to[i];
            }
            if (i < enableBegin) {
                enableBegin = i;
            }
            if (i + 1 > enableEnd) {
                enableEnd = i + 1;
            }
        }
    }
    bool didSomething = false;
    bool valuesChanged = false;
    OfxPointD delta;
    delta.x = penPos.x() - _imp->lastPenPos.x();
    delta.y = penPos.y() - _imp->lastPenPos.y();

    _imp->hovering = -1;

    for (int i = enableBegin; i < enableEnd; ++i) {
        if (enable[i]) {
            if (_imp->dragging == i) {
                if (useFrom) {
                    from[i].x += delta.x;
                    from[i].y += delta.y;
                    _imp->fromDrag[i] = from[i];
                } else {
                    to[i].x += delta.x;
                    to[i].y += delta.y;
                    _imp->toDrag[i] = to[i];
                }
                valuesChanged = true;
            } else if ( CornerPinOverlayInteractPrivate::isNearby(penPos, p[i].x, p[i].y, CornerPinOverlayInteractPrivate::pointTolerance(), pscale) ) {
                _imp->hovering = i;
                didSomething = true;
            }
        }
    }

    if ( (_imp->dragging != -1) && _imp->interactiveDrag && valuesChanged ) {
        // no need to redraw overlay since it is slave to the paramaters

        if (_imp->useFromDrag) {
            KnobDoublePtr knob = _imp->from[_imp->dragging].lock();
            assert(knob);
            std::vector<double> val(2);
            val[0] = from[_imp->dragging].x;
            val[1] = from[_imp->dragging].y;
            knob->setValueAcrossDimensions(val, DimIdx(0), view, eValueChangedReasonUserEdited);
        } else {
            KnobDoublePtr knob = _imp->to[_imp->dragging].lock();
            assert(knob);
            std::vector<double> val(2);
            val[0] = to[_imp->dragging].x;
            val[1] = to[_imp->dragging].y;

            if (_imp->toPointsAutoKeyingEnabled) {
                knob->setValueAtTimeAcrossDimensions(time, val, DimIdx(0), view, eValueChangedReasonUserEdited);

                // Also set a keyframe on other points
                for (int i = 0; i < 4; ++i) {
                    if (i == _imp->dragging) {
                        continue;
                    }
                    std::vector<double> values(2);
                    KnobDoublePtr toPoint = _imp->to[i].lock();
                    values[0] = toPoint->getValueAtTime(time, DimIdx(0));
                    values[1] = toPoint->getValueAtTime(time, DimIdx(1));
                    toPoint->setValueAtTimeAcrossDimensions(time, values, DimIdx(0), view, eValueChangedReasonUserEdited);
                }
            } else {
                knob->setValueAcrossDimensions(val, DimIdx(0), view, eValueChangedReasonUserEdited);
            }
        }
    }

    _imp->lastPenPos = penPos;
    
    return didSomething || valuesChanged;
} // onOverlayPenMotion