bool
PointOverlayInteract::onOverlayPenDown(TimeValue time,
                                       const RenderScale & renderScale,
                                       ViewIdx view,
                                       const QPointF & viewportPos,
                                       const QPointF & penPos,
                                       double pressure,
                                       TimeValue timestamp,
                                       PenType /*pen*/)
{
    KnobDoublePtr knob = _imp->param.lock();

    // do not show interact if knob is secret or not enabled
    // see https://github.com/MrKepzie/Natron/issues/932
    if ( !knob || !knob->shouldDrawOverlayInteract() ) {
        return false;
    }

    _imp->lastPenPos = penPos;


    bool motion = onOverlayPenMotion(time, renderScale, view, viewportPos, penPos, pressure, timestamp);
    Q_UNUSED(motion);
    if (_imp->state == ePositionInteractStatePoised) {
        _imp->state = ePositionInteractStatePicked;
        _imp->interactiveDrag = _imp->getInteractive();

        return true;
    }

    return false;

}
Exemple #2
0
void
TrackMarker::resetCenter()
{
    TrackerContextPtr context = getContext();

    assert(context);
    NodePtr input = context->getNode()->getInput(0);
    if (input) {
        SequenceTime time = input->getApp()->getTimeLine()->currentFrame();
        RenderScale scale;
        scale.x = scale.y = 1;
        RectD rod;
        bool isProjectFormat;
        StatusEnum stat = input->getEffectInstance()->getRegionOfDefinition_public(input->getHashValue(), time, scale, ViewIdx(0), &rod, &isProjectFormat);
        Point center;
        center.x = 0;
        center.y = 0;
        if (stat == eStatusOK) {
            center.x = (rod.x1 + rod.x2) / 2.;
            center.y = (rod.y1 + rod.y2) / 2.;
        }

        KnobDoublePtr centerKnob = getCenterKnob();
        centerKnob->setValue(center.x, ViewSpec::current(), 0);
        centerKnob->setValue(center.y, ViewSpec::current(), 1);
    }
}
Exemple #3
0
void
TrackMarker::resetTrack()
{
    Point curCenter;
    KnobDoublePtr centerKnob = getCenterKnob();

    curCenter.x = centerKnob->getValue();
    curCenter.y = centerKnob->getValue(DimIdx(1));

    const KnobsVec& knobs = getKnobs();
    for (KnobsVec::const_iterator it = knobs.begin(); it != knobs.end(); ++it) {
        if (*it != centerKnob) {
            (*it)->resetToDefaultValue(DimSpec::all(), ViewSetSpec::all());
        } else {
            (*it)->removeAnimation(ViewSetSpec::all(), DimSpec::all(), eValueChangedReasonUserEdited);

            std::vector<double> values(2);
            values[0] = curCenter.x;
            values[1] = curCenter.y;
            centerKnob->setValueAcrossDimensions(values);
        }
    }

    removeAnimation(ViewSetSpec::all(), DimSpec::all(), eValueChangedReasonUserEdited);
}
Exemple #4
0
void
TrackMarker::resetTrack()
{
    Point curCenter;
    KnobDoublePtr knob = getCenterKnob();

    curCenter.x = knob->getValue(0);
    curCenter.y = knob->getValue(1);

    EffectInstancePtr effect = getContext()->getNode()->getEffectInstance();
    effect->beginChanges();

    const KnobsVec& knobs = getKnobs();
    for (KnobsVec::const_iterator it = knobs.begin(); it != knobs.end(); ++it) {
        if (*it != knob) {
            for (int i = 0; i < (*it)->getDimension(); ++i) {
                (*it)->resetToDefaultValue(i);
            }
        } else {
            for (int i = 0; i < (*it)->getDimension(); ++i) {
                (*it)->removeAnimation(ViewSpec::current(), i);
            }
            knob->setValue(curCenter.x, ViewSpec::current(), 0);
            knob->setValue(curCenter.y, ViewSpec::current(), 1);
        }
    }
    effect->endChanges();
    removeAllUserKeyframes();
}
Exemple #5
0
QPointF
ViewerNode::getWipeCenter() const
{
    KnobDoublePtr wipeCenter = _imp->wipeCenter.lock();
    QPointF r;
    r.rx() = wipeCenter->getValue();
    r.ry() = wipeCenter->getValue(DimIdx(1));
    return r;
}
Exemple #6
0
void
TrackMarker::resetOffset()
{
    KnobDoublePtr knob = getOffsetKnob();

    for (int i = 0; i < knob->getDimension(); ++i) {
        knob->resetToDefaultValue(i);
    }
}
    void getTo(TimeValue time,
               int index,
               double* tx,
               double* ty) const
    {
        KnobDoublePtr knob = to[index].lock();

        assert(knob);
        *tx = knob->getValueAtTime(time, DimIdx(0));
        *ty = knob->getValueAtTime(time, DimIdx(1));
    }
Exemple #8
0
void
ViewerNode::setUserRoI(const RectD& rect)
{
    KnobDoublePtr btmLeft = _imp->userRoIBtmLeftKnob.lock();
    KnobDoublePtr size = _imp->userRoISizeKnob.lock();
    std::vector<double> values(2);
    values[0] = rect.x1;
    values[1] = rect.y1;
    btmLeft->setValueAcrossDimensions(values, DimIdx(0), ViewSetSpec::all(), eValueChangedReasonUserEdited);
    values[0] = rect.x2 - rect.x1;
    values[1] = rect.y2 - rect.y1;
    size->setValueAcrossDimensions(values, DimIdx(0), ViewSetSpec::all(), eValueChangedReasonUserEdited);
}
Exemple #9
0
void
TrackArgs::getRedrawAreasNeeded(TimeValue time,
                                std::list<RectD>* canonicalRects) const
{
    for (std::vector<TrackMarkerAndOptionsPtr >::const_iterator it = _imp->tracks.begin(); it != _imp->tracks.end(); ++it) {
        if ( !(*it)->natronMarker->isEnabled(time) ) {
            continue;
        }
        KnobDoublePtr searchBtmLeft = (*it)->natronMarker->getSearchWindowBottomLeftKnob();
        KnobDoublePtr searchTopRight = (*it)->natronMarker->getSearchWindowTopRightKnob();
        KnobDoublePtr centerKnob = (*it)->natronMarker->getCenterKnob();
        KnobDoublePtr offsetKnob = (*it)->natronMarker->getOffsetKnob();
        Point offset, center, btmLeft, topRight;
        offset.x = offsetKnob->getValueAtTime(time, DimIdx(0));
        offset.y = offsetKnob->getValueAtTime(time, DimIdx(1));

        center.x = centerKnob->getValueAtTime(time, DimIdx(0));
        center.y = centerKnob->getValueAtTime(time, DimIdx(1));

        btmLeft.x = searchBtmLeft->getValueAtTime(time, DimIdx(0)) + center.x + offset.x;
        btmLeft.y = searchBtmLeft->getValueAtTime(time, DimIdx(1)) + center.y + offset.y;

        topRight.x = searchTopRight->getValueAtTime(time, DimIdx(0)) + center.x + offset.x;
        topRight.y = searchTopRight->getValueAtTime(time, DimIdx(1)) + center.y + offset.y;

        RectD rect;
        rect.x1 = btmLeft.x;
        rect.y1 = btmLeft.y;
        rect.x2 = topRight.x;
        rect.y2 = topRight.y;
        canonicalRects->push_back(rect);
    }
}
Exemple #10
0
RectI
TrackMarker::getMarkerImageRoI(int time) const
{
    const unsigned int mipmapLevel = 0;
    Point center, offset;
    KnobDoublePtr centerKnob = getCenterKnob();
    KnobDoublePtr offsetKnob = getOffsetKnob();

    center.x = centerKnob->getValueAtTime(time, 0);
    center.y = centerKnob->getValueAtTime(time, 1);

    offset.x = offsetKnob->getValueAtTime(time, 0);
    offset.y = offsetKnob->getValueAtTime(time, 1);

    RectD roiCanonical;
    KnobDoublePtr swBl = getSearchWindowBottomLeftKnob();
    KnobDoublePtr swTr = getSearchWindowTopRightKnob();

    roiCanonical.x1 = swBl->getValueAtTime(time, 0) + center.x + offset.x;
    roiCanonical.y1 = swBl->getValueAtTime(time, 1) + center.y + offset.y;
    roiCanonical.x2 = swTr->getValueAtTime(time, 0) + center.x + offset.x;
    roiCanonical.y2 = swTr->getValueAtTime(time, 1) + center.y + offset.y;

    RectI roi;
    NodePtr node = getContext()->getNode();
    NodePtr input = node->getInput(0);
    if (!input) {
        return RectI();
    }
    roiCanonical.toPixelEnclosing(mipmapLevel, input ? input->getEffectInstance()->getAspectRatio(-1) : 1., &roi);

    return roi;
}
void
TrackerNodePrivate::resetTransformParamsAnimation()
{
    {
        // Revert animation on the corner pin
        KnobDoublePtr toPointsKnob[4];
        KnobBoolPtr enabledPointsKnob[4];
        for (int i = 0; i < 4; ++i) {
            toPointsKnob[i] = toPoints[i].lock();
            enabledPointsKnob[i] = enableToPoint[i].lock();
        }


        for (int i = 0; i < 4; ++i) {
            toPointsKnob[i]->resetToDefaultValue(DimSpec::all(), ViewSetSpec::all());
            enabledPointsKnob[i]->resetToDefaultValue(DimSpec::all(), ViewSetSpec::all());
        }
    }
    KnobDoublePtr centerKnob = center.lock();

    centerKnob->resetToDefaultValue(DimSpec::all(), ViewSetSpec::all());
    {
        // Revert animation on the transform
        KnobDoublePtr translationKnob = translate.lock();
        KnobDoublePtr scaleKnob = scale.lock();
        KnobDoublePtr rotationKnob = rotate.lock();

        translationKnob->resetToDefaultValue(DimSpec::all(), ViewSetSpec::all());

        scaleKnob->resetToDefaultValue(DimSpec::all(), ViewSetSpec::all());

        rotationKnob->resetToDefaultValue(DimSpec::all(), ViewSetSpec::all());
    }
}
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
 bool areToPointsAnimated() const
 {
     bool hasAnimation = true;
     for (int i = 0; i < 4; ++i) {
         KnobDoublePtr knob = to[i].lock();
         for (int d = 0; d < 2; ++d) {
             bool dimHasAnim = knob->isAnimated(DimIdx(d), ViewIdx(0));
             if (!dimHasAnim) {
                 hasAnimation = false;
                 break;
             }
         }
         if (!hasAnimation) {
             break;
         }
     }
     return hasAnimation;
 }
bool
PointOverlayInteract::onOverlayPenUp(TimeValue time,
                                     const RenderScale & renderScale,
                                     ViewIdx view,
                                     const QPointF & viewportPos,
                                     const QPointF & penPos,
                                     double pressure,
                                     TimeValue timestamp)
{
    KnobDoublePtr knob = _imp->param.lock();

    // do not show interact if knob is secret or not enabled
    // see https://github.com/MrKepzie/Natron/issues/932
    if ( !knob || !knob->shouldDrawOverlayInteract() ) {
        return false;
    }

    RenderScale pscale;
    getPixelScale(pscale.x, pscale.y);
    
    bool didSomething = false;
    if (_imp->state == ePositionInteractStatePicked) {
        if (!_imp->interactiveDrag) {
            std::vector<double> p(2);
            p[0] = fround(_imp->lastPenPos.x(), pscale.x);
            p[1] = fround(_imp->lastPenPos.y(), pscale.y);
            for (int i = 0; i < 2; ++i) {
                if (knob->getValueIsNormalized(DimIdx(i)) != eValueIsNormalizedNone) {
                    p[i] = knob->normalize(DimIdx(i), time, p[i]);
                }
            }

            knob->setValueAcrossDimensions(p, DimIdx(0), view, eValueChangedReasonUserEdited);
        }

        _imp->state = ePositionInteractStateInactive;
        bool motion = onOverlayPenMotion(time, renderScale, view, viewportPos, penPos, pressure, timestamp);
        Q_UNUSED(motion);
        didSomething = true;
    }
    
    return didSomething;
} // onOverlayPenUp
bool
PointOverlayInteract::onOverlayFocusLost(TimeValue /*time*/,
                                         const RenderScale & /*renderScale*/,
                                         ViewIdx /*view*/)
{
    KnobDoublePtr knob = _imp->param.lock();

    // do not show interact if knob is secret or not enabled
    // see https://github.com/MrKepzie/Natron/issues/932
    if ( !knob || !knob->shouldDrawOverlayInteract() ) {
        return false;
    }

    if (_imp->state != ePositionInteractStateInactive) {
        _imp->state = ePositionInteractStateInactive;
        // state changed, must redraw
        redraw();
    }

    return false;
}
Exemple #16
0
void
TrackMarker::resetCenter()
{
    KnobItemsTablePtr model = getModel();
    if (!model) {
        return;
    }
    RectD rod;
    NodePtr input = model->getNode()->getInput(0);
    if (!input) {
        Format f;
        getApp()->getProject()->getProjectDefaultFormat(&f);
        rod = f.toCanonicalFormat();
    } else {
        TimeValue time(input->getApp()->getTimeLine()->currentFrame());
        RenderScale scale(1.);
        RectD rod;
        {
            GetRegionOfDefinitionResultsPtr results;
            ActionRetCodeEnum stat = input->getEffectInstance()->getRegionOfDefinition_public(time, scale, ViewIdx(0), &results);
            if (!isFailureRetCode(stat)) {
                rod = results->getRoD();
            }
        }
        Point center;
        center.x = 0;
        center.y = 0;
        center.x = (rod.x1 + rod.x2) / 2.;
        center.y = (rod.y1 + rod.y2) / 2.;


        KnobDoublePtr centerKnob = getCenterKnob();
        centerKnob->setValue(center.x, ViewSetSpec::all(), DimIdx(0));
        centerKnob->setValue(center.y, ViewSetSpec::all(), DimIdx(1));
    }
}
Exemple #17
0
void
TrackMarker::setKeyFrameOnCenterAndPatternAtTime(int time)
{
    KnobDoublePtr center = _imp->center.lock();

    for (int i = 0; i < center->getDimension(); ++i) {
        double v = center->getValueAtTime(time, i);
        center->setValueAtTime(time, v, ViewSpec::all(), i);
    }

    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];
        for (int i = 0; i < k->getDimension(); ++i) {
            double v = k->getValueAtTime(time, i);
            k->setValueAtTime(time, v, ViewSpec::all(), i);
        }
    }
}
Exemple #18
0
RectD
ViewerNode::getUserRoI() const
{
    RectD ret;
    KnobDoublePtr btmLeft = _imp->userRoIBtmLeftKnob.lock();
    KnobDoublePtr size = _imp->userRoISizeKnob.lock();
    ret.x1 = btmLeft->getValue();
    ret.y1 = btmLeft->getValue(DimIdx(1));
    ret.x2 = ret.x1 + size->getValue();
    ret.y2 = ret.y1 + size->getValue(DimIdx(1));
    return ret;
}
Exemple #19
0
RectD
TrackMarker::getMarkerImageRoI(TimeValue time) const
{
    Point center, offset;
    KnobDoublePtr centerKnob = getCenterKnob();
    KnobDoublePtr offsetKnob = getOffsetKnob();

    center.x = centerKnob->getValueAtTime(time, DimIdx(0));
    center.y = centerKnob->getValueAtTime(time, DimIdx(1));

    offset.x = offsetKnob->getValueAtTime(time, DimIdx(0));
    offset.y = offsetKnob->getValueAtTime(time, DimIdx(1));

    RectD roiCanonical;
    KnobDoublePtr swBl = getSearchWindowBottomLeftKnob();
    KnobDoublePtr swTr = getSearchWindowTopRightKnob();

    roiCanonical.x1 = swBl->getValueAtTime(time, DimIdx(0)) + center.x + offset.x;
    roiCanonical.y1 = swBl->getValueAtTime(time, DimIdx(1)) + center.y + offset.y;
    roiCanonical.x2 = swTr->getValueAtTime(time, DimIdx(0)) + center.x + offset.x;
    roiCanonical.y2 = swTr->getValueAtTime(time, DimIdx(1)) + center.y + offset.y;

    return roiCanonical;
}
Exemple #20
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);
    }
}
Exemple #21
0
TEST_F(BaseTest, SetValues)
{
    NodePtr generator = createNode(_generatorPluginID);

    assert(generator);
    KnobIPtr knob = generator->getKnobByName("noiseZSlope");
    KnobDoublePtr radius = boost::dynamic_pointer_cast<KnobDouble>(knob);
    EXPECT_TRUE(radius != 0);
    if (!radius) {
        return;
    }
    radius->setValue(0.5);
    EXPECT_TRUE(radius->getValue() == 0.5);

    //Check that linear interpolation is working as intended
    KeyFrame kf;
    radius->setInterpolationAtTime(eCurveChangeReasonInternal, ViewSpec::all(),  0, 0, eKeyframeTypeLinear, &kf);
    radius->setValueAtTime(0, 0., ViewSpec::all(), 0);
    radius->setValueAtTime(100, 1., ViewSpec::all(), 0);
    for (int i = 0; i <= 100; ++i) {
        double v = radius->getValueAtTime(i);
        EXPECT_TRUE(std::abs(v - i / 100.) < 1e-6);
    }
}
Exemple #22
0
void
TrackMarker::resetOffset()
{
    KnobDoublePtr knob = getOffsetKnob();
    knob->resetToDefaultValue(DimSpec::all(), ViewSetSpec::all());
}
Exemple #23
0
void
TrackMarker::initializeKnobs()
{
    KnobItemsTablePtr model = getModel();
    EffectInstancePtr effect;
    if (model) {
        effect = model->getNode()->getEffectInstance();
    }
    KnobIntPtr defPatternSizeKnob, defSearchSizeKnob;
    KnobChoicePtr defMotionModelKnob;
    defPatternSizeKnob = toKnobInt(effect->getKnobByName(kTrackerUIParamDefaultMarkerPatternWinSize));
    defSearchSizeKnob = toKnobInt(effect->getKnobByName(kTrackerUIParamDefaultMarkerSearchWinSize));
    defMotionModelKnob = toKnobChoice(effect->getKnobByName(kTrackerUIParamDefaultMotionModel));

    double patternHalfSize = defPatternSizeKnob ? defPatternSizeKnob->getValue() / 2. : 21;
    double searchHalfSize = defSearchSizeKnob ? defSearchSizeKnob->getValue() / 2. : 71;

    int defMotionModel_i = defMotionModelKnob ? defMotionModelKnob->getValue() : 0;

    KnobDoublePtr swbbtmLeft = createKnob<KnobDouble>(kTrackerParamSearchWndBtmLeft, 2);

    swbbtmLeft->setLabel(tr(kTrackerParamSearchWndBtmLeftLabel));
    swbbtmLeft->setDefaultValue(-searchHalfSize, DimIdx(0));
    swbbtmLeft->setDefaultValue(-searchHalfSize, DimIdx(1));
    swbbtmLeft->setHintToolTip( tr(kTrackerParamSearchWndBtmLeftHint) );
    _imp->searchWindowBtmLeft = swbbtmLeft;

    KnobDoublePtr swbtRight = createKnob<KnobDouble>(kTrackerParamSearchWndTopRight, 2);
    swbtRight->setLabel(tr(kTrackerParamSearchWndTopRightLabel));
    swbtRight->setDefaultValue(searchHalfSize, DimIdx(0));
    swbtRight->setDefaultValue(searchHalfSize, DimIdx(1));
    swbtRight->setHintToolTip( tr(kTrackerParamSearchWndTopRightHint) );
    _imp->searchWindowTopRight = swbtRight;


    KnobDoublePtr ptLeft = createKnob<KnobDouble>(kTrackerParamPatternTopLeft, 2);
    ptLeft->setLabel(tr(kTrackerParamPatternTopLeftLabel));
    ptLeft->setDefaultValue(-patternHalfSize, DimIdx(0));
    ptLeft->setDefaultValue(patternHalfSize, DimIdx(1));
    ptLeft->setHintToolTip( tr(kTrackerParamPatternTopLeftHint) );
    _imp->patternTopLeft = ptLeft;

    KnobDoublePtr ptRight = createKnob<KnobDouble>(kTrackerParamPatternTopRight, 2);
    ptRight->setLabel(tr(kTrackerParamPatternTopRightLabel));
    ptRight->setDefaultValue(patternHalfSize, DimIdx(0));
    ptRight->setDefaultValue(patternHalfSize, DimIdx(1));
    ptRight->setHintToolTip( tr(kTrackerParamPatternTopRightHint) );
    _imp->patternTopRight = ptRight;

    KnobDoublePtr pBRight = createKnob<KnobDouble>(kTrackerParamPatternBtmRight, 2);
    pBRight->setLabel(tr(kTrackerParamPatternBtmRightLabel));
    pBRight->setDefaultValue(patternHalfSize, DimIdx(0));
    pBRight->setDefaultValue(-patternHalfSize, DimIdx(1));
    pBRight->setHintToolTip( tr(kTrackerParamPatternBtmRightHint) );
    _imp->patternBtmRight = pBRight;

    KnobDoublePtr pBLeft = createKnob<KnobDouble>(kTrackerParamPatternBtmLeft, 2);
    pBLeft->setLabel(tr(kTrackerParamPatternBtmLeftLabel));
    pBLeft->setDefaultValue(-patternHalfSize, DimIdx(0));
    pBLeft->setDefaultValue(-patternHalfSize, DimIdx(1));
    pBLeft->setHintToolTip( tr(kTrackerParamPatternBtmLeftHint) );
    _imp->patternBtmLeft = pBLeft;

    KnobDoublePtr centerKnob = createKnob<KnobDouble>(kTrackerParamCenter, 2);
    centerKnob->setLabel(tr(kTrackerParamCenterLabel));
    centerKnob->setHintToolTip( tr(kTrackerParamCenterHint) );
    _imp->center = centerKnob;

    KnobDoublePtr offsetKnob = createKnob<KnobDouble>(kTrackerParamOffset, 2);
    offsetKnob->setLabel(tr(kTrackerParamOffsetLabel));
    offsetKnob->setHintToolTip( tr(kTrackerParamOffsetHint) );
    _imp->offset = offsetKnob;

#ifdef NATRON_TRACK_MARKER_USE_WEIGHT
    KnobDoublePtr weightKnob = createKnob<KnobDouble>(kTrackerParamTrackWeight, 1);
    weightKnob->setLabel(tr(kTrackerParamTrackWeightLabel));
    weightKnob->setHintToolTip( tr(kTrackerParamTrackWeightHint) );
    weightKnob->setDefaultValue(1.);
    weightKnob->setAnimationEnabled(false);
    weightKnob->setRange(0., 1.);
    _imp->weight = weightKnob;
#endif

    KnobChoicePtr mmodelKnob = createKnob<KnobChoice>(kTrackerParamMotionModel, 1);
    mmodelKnob->setHintToolTip( tr(kTrackerParamMotionModelHint) );
    mmodelKnob->setLabel(tr(kTrackerParamMotionModelLabel));
    {
        std::vector<ChoiceOption> choices, helps;
        std::map<int, std::string> icons;
        TrackerNodePrivate::getMotionModelsAndHelps(true, &choices, &icons);
        mmodelKnob->populateChoices(choices);
        mmodelKnob->setIcons(icons);
    }

    mmodelKnob->setDefaultValue(defMotionModel_i);
    _imp->motionModel = mmodelKnob;

    KnobDoublePtr errKnob = createKnob<KnobDouble>(kTrackerParamError, 1);
    errKnob->setLabel(tr(kTrackerParamErrorLabel));
    _imp->error = errKnob;

    KnobBoolPtr enableKnob = createKnob<KnobBool>(kTrackerParamEnabled, 1);
    enableKnob->setLabel(tr(kTrackerParamEnabledLabel));
    enableKnob->setHintToolTip( tr(kTrackerParamEnabledHint) );
    enableKnob->setAnimationEnabled(true);
    enableKnob->setDefaultValue(true);
    _imp->enabled = enableKnob;

    addColumn(kKnobTableItemColumnLabel, DimIdx(0));
    addColumn(kTrackerParamEnabled, DimIdx(0));
    addColumn(kTrackerParamMotionModel, DimIdx(0));
    addColumn(kTrackerParamCenter, DimIdx(0));
    addColumn(kTrackerParamCenter, DimIdx(1));
    addColumn(kTrackerParamOffset, DimIdx(0));
    addColumn(kTrackerParamOffset, DimIdx(1));
    addColumn(kTrackerParamError, DimIdx(0));

} // TrackMarker::initializeKnobs
Exemple #24
0
void
TrackMarkerPM::initializeKnobs()
{
    TrackMarker::initializeKnobs();
    NodePtr thisNode = getModel()->getNode();
    NodePtr node;
    {
        CreateNodeArgsPtr args(CreateNodeArgs::create( PLUGINID_OFX_TRACKERPM, NodeCollectionPtr() ));
        args->setProperty<bool>(kCreateNodeArgsPropVolatile, true);
        args->setProperty<bool>(kCreateNodeArgsPropNoNodeGUI, true);
        args->setProperty<std::string>(kCreateNodeArgsPropNodeInitialName, "TrackerPMNode");

        node = getApp()->createNode(args);
        if (!node) {
            throw std::runtime_error("Couldn't create plug-in " PLUGINID_OFX_TRACKERPM);
        }
        if (thisNode) {
            NodePtr inputNode = thisNode->getInput(0);
            if (inputNode) {
                node->connectInput(inputNode, 0);
            }
        }
        trackerNode = node;
    }

    KnobItemsTablePtr model = getModel();
    EffectInstancePtr effect;
    if (model) {
        effect = model->getNode()->getEffectInstance();
    }

    trackPrevButton = getNodeKnob<KnobButton>(node, kTrackerPMParamTrackingPrevious);
    trackNextButton = getNodeKnob<KnobButton>(node, kTrackerPMParamTrackingNext);
    KnobDoublePtr center = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingCenterPoint);
    centerKnob = center;

    // Slave the center knob and unslave when tracking
    if ( !center->linkTo(getCenterKnob()) ) {
        throw std::runtime_error("Could not link center");
    }

    KnobDoublePtr offset = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingOffset);

    // Slave the offset knob
    if ( !offset->linkTo( getOffsetKnob() ) ) {
        throw std::runtime_error("Could not link offset");
    }

    offsetKnob = offset;

    // Ref frame is set for each
    refFrameKnob = getNodeKnob<KnobInt>(node, kTrackerPMParamTrackingReferenceFrame);

    // Enable reference frame
    KnobBoolPtr enableRefFrameKnob = getNodeKnob<KnobBool>(node, kTrackerPMParamTrackingEnableReferenceFrame);
    enableRefFrameKnob->setValue(true);

    KnobChoicePtr scoreType = getNodeKnob<KnobChoice>(node, kTrackerPMParamScore);
    if (effect) {
#ifdef kTrackerParamPatternMatchingScoreType
        KnobIPtr modelKnob = effect->getKnobByName(kTrackerParamPatternMatchingScoreType);
        if (modelKnob) {
            if ( !scoreType->linkTo(modelKnob) ) {
                throw std::runtime_error("Could not link scoreType");
            }
        }
#endif
    }

    scoreTypeKnob = scoreType;

    KnobDoublePtr correlationScore = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingCorrelationScore);
    correlationScoreKnob = correlationScore;

    KnobDoublePtr patternBtmLeft = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingPatternBoxBtmLeft);
    patternBtmLeftKnob = patternBtmLeft;

    // Slave the search window and pattern of the node to the parameters of the marker
    (void)patternBtmLeft->linkTo(getPatternBtmLeftKnob());

    KnobDoublePtr patternTopRight = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingPatternBoxTopRight);
    patternTopRightKnob = patternTopRight;
    (void)patternTopRight->linkTo(getPatternTopRightKnob());

    KnobDoublePtr searchWindowBtmLeft = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingSearchBoxBtmLeft);
    searchWindowBtmLeftKnob = searchWindowBtmLeft;
    (void)searchWindowBtmLeft->linkTo(getSearchWindowBottomLeftKnob());

    KnobDoublePtr searchWindowTopRight = getNodeKnob<KnobDouble>(node, kTrackerPMParamTrackingSearchBoxTopRight);
    searchWindowTopRightKnob = searchWindowTopRight;
    (void)searchWindowTopRight->linkTo(getSearchWindowTopRightKnob());

} // TrackMarkerPM::initializeKnobs
void
TrackerNodePrivate::computeTransformParamsFromTracksEnd(double refTime,
                                                        double maxFittingError,
                                                        const QList<TransformData>& results)
{
    QList<TransformData> validResults;
    for (QList<TransformData>::const_iterator it = results.begin(); it != results.end(); ++it) {
        if (it->valid) {
            validResults.push_back(*it);
        }
    }

    KnobIntPtr smoothKnob = smoothTransform.lock();
    int smoothTJitter, smoothRJitter, smoothSJitter;

    smoothTJitter = smoothKnob->getValue(DimIdx(0));
    smoothRJitter = smoothKnob->getValue(DimIdx(1));
    smoothSJitter = smoothKnob->getValue(DimIdx(2));

    KnobDoublePtr translationKnob = translate.lock();
    KnobDoublePtr scaleKnob = scale.lock();
    KnobDoublePtr rotationKnob = rotate.lock();
    KnobDoublePtr fittingErrorKnob = fittingError.lock();
    KnobStringPtr fittingWarningKnob = fittingErrorWarning.lock();
    int halfTJitter = smoothTJitter / 2;
    int halfRJitter = smoothRJitter / 2;
    int halfSJitter = smoothSJitter / 2;



    translationKnob->blockValueChanges();
    scaleKnob->blockValueChanges();
    rotationKnob->blockValueChanges();
    fittingErrorKnob->blockValueChanges();

    std::list<KnobIPtr> animatedKnobsChanged;
    animatedKnobsChanged.push_back(translationKnob);
    animatedKnobsChanged.push_back(scaleKnob);
    animatedKnobsChanged.push_back(rotationKnob);
    animatedKnobsChanged.push_back(fittingErrorKnob);


    Curve tmpTXCurve, tmpTYCurve, tmpRotateCurve, tmpScaleCurve, tmpFittingErrorCurve;
    bool mustShowFittingWarn = false;
    for (QList<TransformData>::const_iterator itResults = validResults.begin(); itResults != validResults.end(); ++itResults) {
        const TransformData& dataAtTime = *itResults;
        {
            KeyFrame kf(dataAtTime.time, dataAtTime.rms);
            if (dataAtTime.rms >= maxFittingError) {
                mustShowFittingWarn = true;
            }
            tmpFittingErrorCurve.setOrAddKeyframe(kf);
        }
        if (!dataAtTime.hasRotationAndScale) {
            // no rotation or scale: simply extract the translation
            Point translation;
            if (smoothTJitter > 1) {
                TranslateData avgT;
                averageDataFunctor<QList<TransformData>::const_iterator, void, TranslateData>(validResults.begin(), validResults.end(), itResults, halfTJitter, 0, &avgT, 0);
                translation.x = avgT.p.x;
                translation.y = avgT.p.y;
            } else {
                translation.x = dataAtTime.translation.x;
                translation.y = dataAtTime.translation.y;
            }
            {
                KeyFrame kx(dataAtTime.time, translation.x);
                KeyFrame ky(dataAtTime.time, translation.y);
                tmpTXCurve.setOrAddKeyframe(kx);
                tmpTYCurve.setOrAddKeyframe(ky);
            }
        } else {
            double rot = 0;
            if (smoothRJitter > 1) {
                RotateData avgR;
                averageDataFunctor<QList<TransformData>::const_iterator, void, RotateData>(validResults.begin(), validResults.end(), itResults, halfRJitter, 0, &avgR, 0);
                rot = avgR.r;
            } else {
                rot = dataAtTime.rotation;
            }
            {
                KeyFrame k(dataAtTime.time, rot);
                tmpRotateCurve.setOrAddKeyframe(k);
            }
            double scale;
            if (smoothSJitter > 1) {
                ScaleData avgR;
                averageDataFunctor<QList<TransformData>::const_iterator, void, ScaleData>(validResults.begin(), validResults.end(), itResults, halfSJitter, 0, &avgR, 0);
                scale = avgR.s;
            } else {
                scale = dataAtTime.scale;
            }
            {
                KeyFrame k(dataAtTime.time, scale);
                tmpScaleCurve.setOrAddKeyframe(k);
            }
            Point translation;
            if (smoothTJitter > 1) {
                TranslateData avgT;
                averageDataFunctor<QList<TransformData>::const_iterator, void, TranslateData>(validResults.begin(), validResults.end(), itResults, halfTJitter, 0, &avgT, 0);
                translation.x = avgT.p.x;
                translation.y = avgT.p.y;
            } else {
                translation.x = dataAtTime.translation.x;
                translation.y = dataAtTime.translation.y;
            }
            {
                KeyFrame kx(dataAtTime.time, translation.x);
                KeyFrame ky(dataAtTime.time, translation.y);
                tmpTXCurve.setOrAddKeyframe(kx);
                tmpTYCurve.setOrAddKeyframe(ky);
            }
       }
    } // for all samples

    fittingWarningKnob->setSecret(!mustShowFittingWarn);
    fittingErrorKnob->cloneCurve(ViewIdx(0), DimIdx(0), tmpFittingErrorCurve, 0 /*offset*/, 0 /*range*/);
    translationKnob->cloneCurve(ViewIdx(0), DimIdx(0), tmpTXCurve, 0 /*offset*/, 0 /*range*/);
    translationKnob->cloneCurve(ViewIdx(0), DimIdx(1), tmpTYCurve, 0 /*offset*/, 0 /*range*/);
    rotationKnob->cloneCurve(ViewIdx(0), DimIdx(0), tmpRotateCurve, 0 /*offset*/, 0 /*range*/);
    scaleKnob->cloneCurve(ViewIdx(0), DimIdx(0), tmpScaleCurve, 0 /*offset*/, 0 /*range*/);
    scaleKnob->cloneCurve(ViewIdx(0), DimIdx(1), tmpScaleCurve, 0 /*offset*/, 0 /*range*/);

    for (std::list<KnobIPtr>::iterator it = animatedKnobsChanged.begin(); it != animatedKnobsChanged.end(); ++it) {
        (*it)->unblockValueChanges();
        (*it)->evaluateValueChange(DimSpec::all(), TimeValue(refTime), ViewSetSpec::all(), eValueChangedReasonUserEdited);
    }
    endSolve();
} // TrackerNodePrivate::computeTransformParamsFromTracksEnd
void
TrackerNodePrivate::exportTrackDataFromExportOptions()
{
    //bool transformLink = _imp->exportLink.lock()->getValue();
    KnobChoicePtr transformTypeKnob = transformType.lock();

    assert(transformTypeKnob);
    int transformType_i = transformTypeKnob->getValue();
    TrackerTransformNodeEnum transformType = (TrackerTransformNodeEnum)transformType_i;
    KnobChoicePtr motionTypeKnob = motionType.lock();
    if (!motionTypeKnob) {
        return;
    }
    int motionType_i = motionTypeKnob->getValue();
    TrackerMotionTypeEnum mt = (TrackerMotionTypeEnum)motionType_i;

    if (mt == eTrackerMotionTypeNone) {
        Dialogs::errorDialog( tr("Tracker Export").toStdString(), tr("Please select the export mode with the Motion Type parameter").toStdString() );

        return;
    }

    bool linked = exportLink.lock()->getValue();
    QString pluginID;
    switch (transformType) {
        case eTrackerTransformNodeCornerPin:
            pluginID = QString::fromUtf8(PLUGINID_OFX_CORNERPIN);
            break;
        case eTrackerTransformNodeTransform:
            pluginID = QString::fromUtf8(PLUGINID_OFX_TRANSFORM);
            break;
    }

    NodePtr thisNode = publicInterface->getNode();
    AppInstancePtr app = thisNode->getApp();
    CreateNodeArgsPtr args(CreateNodeArgs::create( pluginID.toStdString(), thisNode->getGroup() ));
    args->setProperty<bool>(kCreateNodeArgsPropAutoConnect, false);
    args->setProperty<bool>(kCreateNodeArgsPropSettingsOpened, false);

    NodePtr createdNode = app->createNode(args);
    if (!createdNode) {
        return;
    }

    // Move the new node
    double thisNodePos[2];
    double thisNodeSize[2];
    thisNode->getPosition(&thisNodePos[0], &thisNodePos[1]);
    thisNode->getSize(&thisNodeSize[0], &thisNodeSize[1]);
    createdNode->setPosition(thisNodePos[0] + thisNodeSize[0] * 2., thisNodePos[1]);

    TimeValue timeForFromPoints(referenceFrame.lock()->getValue());


    switch (transformType) {
        case eTrackerTransformNodeCornerPin: {
            KnobDoublePtr cornerPinToPoints[4];
            KnobDoublePtr cornerPinFromPoints[4];


            for (unsigned int i = 0; i < 4; ++i) {
                cornerPinFromPoints[i] = getCornerPinPoint(createdNode, true, i);
                assert(cornerPinFromPoints[i]);
                for (int j = 0; j < cornerPinFromPoints[i]->getNDimensions(); ++j) {
                    cornerPinFromPoints[i]->setValue(fromPoints[i].lock()->getValueAtTime(timeForFromPoints, DimIdx(j)), ViewSetSpec::all(), DimIdx(j));
                }

                cornerPinToPoints[i] = getCornerPinPoint(createdNode, false, i);
                assert(cornerPinToPoints[i]);
                if (!linked) {
                    cornerPinToPoints[i]->copyKnob( toPoints[i].lock() );
                } else {
                    bool ok = cornerPinToPoints[i]->linkTo(toPoints[i].lock());
                    (void)ok;
                    assert(ok);
                }
            }
            {
                KnobIPtr knob = createdNode->getKnobByName(kCornerPinParamMatrix);
                if (knob) {
                    KnobDoublePtr isType = toKnobDouble(knob);
                    if (isType) {
                        isType->copyKnob(cornerPinMatrix.lock() );
                    }
                }
            }
            break;
        }
        case eTrackerTransformNodeTransform: {
            KnobIPtr translateKnob = createdNode->getKnobByName(kTransformParamTranslate);
            if (translateKnob) {
                KnobDoublePtr isDbl = toKnobDouble(translateKnob);
                if (isDbl) {
                    if (!linked) {
                        isDbl->copyKnob(translate.lock() );
                    } else {
                        ignore_result(isDbl->linkTo(translate.lock()));
                    }
                }
            }

            KnobIPtr scaleKnob = createdNode->getKnobByName(kTransformParamScale);
            if (scaleKnob) {
                KnobDoublePtr isDbl = toKnobDouble(scaleKnob);
                if (isDbl) {
                    if (!linked) {
                        isDbl->copyKnob(scale.lock() );
                    } else {
                        ignore_result(isDbl->linkTo(scale.lock()));
                    }
                }
            }

            KnobIPtr rotateKnob = createdNode->getKnobByName(kTransformParamRotate);
            if (rotateKnob) {
                KnobDoublePtr isDbl = toKnobDouble(rotateKnob);
                if (isDbl) {
                    if (!linked) {
                        isDbl->copyKnob(rotate.lock());
                    } else {
                        ignore_result(isDbl->linkTo(rotate.lock()));
                    }
                }
            }
            KnobIPtr centerKnob = createdNode->getKnobByName(kTransformParamCenter);
            if (centerKnob) {
                KnobDoublePtr isDbl = toKnobDouble(centerKnob);
                if (isDbl) {
                    isDbl->copyKnob( center.lock() );
                }
            }
            break;
        }
    } // switch

    KnobIPtr cpInvertKnob = createdNode->getKnobByName(kTransformParamInvert);
    if (cpInvertKnob) {
        KnobBoolPtr isBool = toKnobBool(cpInvertKnob);
        if (isBool) {
            if (!linked) {
                isBool->copyKnob(invertTransform.lock());
            } else {
                ignore_result(isBool->linkTo(invertTransform.lock()));
            }
        }
    }

    {
        KnobIPtr knob = createdNode->getKnobByName(kTransformParamMotionBlur);
        if (knob) {
            KnobDoublePtr isType = toKnobDouble(knob);
            if (isType) {
                isType->copyKnob(motionBlur.lock());
            }
        }
    }
    {
        KnobIPtr knob = createdNode->getKnobByName(kTransformParamShutter);
        if (knob) {
            KnobDoublePtr isType = toKnobDouble(knob);
            if (isType) {
                isType->copyKnob(shutter.lock());
            }
        }
    }
    {
        KnobIPtr knob = createdNode->getKnobByName(kTransformParamShutterOffset);
        if (knob) {
            KnobChoicePtr isType = toKnobChoice(knob);
            if (isType) {
                isType->copyKnob(shutterOffset.lock());
            }
        }
    }
    {
        KnobIPtr knob = createdNode->getKnobByName(kTransformParamCustomShutterOffset);
        if (knob) {
            KnobDoublePtr isType = toKnobDouble(knob);
            if (isType) {
                isType->copyKnob(customShutterOffset.lock());
            }
        }
    }
} // exportTrackDataFromExportOptions
Exemple #27
0
bool
TrackMarkerPM::trackMarker(bool forward,
                           int refFrame,
                           int frame)
{
    KnobButtonPtr button;

    if (forward) {
        button = trackNextButton.lock();
    } else {
        button = trackPrevButton.lock();
    }
    KnobIntPtr refFrameK = refFrameKnob.lock();
    refFrameK->setValue(refFrame);

    // Unslave the center knob since the trackerNode will update it, then update the marker center
    KnobDoublePtr center = centerKnob.lock();
    center->unlink(DimSpec::all(), ViewSetSpec::all(), true);

    trackerNode->getEffectInstance()->onKnobValueChanged_public(button, eValueChangedReasonUserEdited, TimeValue(frame), ViewIdx(0));

    KnobDoublePtr markerCenter = getCenterKnob();
    // The TrackerPM plug-in has set a keyframe at the refFrame and frame, copy them
    bool ret = true;
    double centerPoint[2];
    for (int i = 0; i < center->getNDimensions(); ++i) {
        {
            int index = center->getKeyFrameIndex(ViewIdx(0), DimIdx(i), TimeValue(frame));
            if (index != -1) {
                centerPoint[i] = center->getValueAtTime(TimeValue(frame), DimIdx(i));
                markerCenter->setValueAtTime(TimeValue(frame), centerPoint[i], ViewSetSpec::all(), DimIdx(i));
            } else {
                // No keyframe at this time: tracking failed
                ret = false;
                break;
            }
        }
        {
            int index = center->getKeyFrameIndex(ViewIdx(0), DimIdx(i), TimeValue(refFrame));
            if (index != -1) {
                double value = center->getValueAtTime(TimeValue(refFrame), DimIdx(i));
                markerCenter->setValueAtTime(TimeValue(refFrame), value, ViewSetSpec::all(), DimIdx(i));
            }
        }
    }

    // Convert the correlation score of the TrackerPM to the error
    if (ret) {
        KnobDoublePtr markerError = getErrorKnob();
        KnobDoublePtr correlation = correlationScoreKnob.lock();
        {
            int index = correlation->getKeyFrameIndex(ViewIdx(0), DimIdx(0), TimeValue(frame));
            if (index != -1) {
                // The error is estimated as a percentage of the correlation across the number of pixels in the pattern window
                KnobDoublePtr  pBtmLeft = patternBtmLeftKnob.lock();
                KnobDoublePtr  pTopRight = patternTopRightKnob.lock();
                Point btmLeft, topRight;

                btmLeft.x = pBtmLeft->getValueAtTime(TimeValue(frame), DimIdx(0));
                btmLeft.y = pBtmLeft->getValueAtTime(TimeValue(frame), DimIdx(1));

                topRight.x = pTopRight->getValueAtTime(TimeValue(frame), DimIdx(0));
                topRight.y = pTopRight->getValueAtTime(TimeValue(frame), DimIdx(1));


                double areaPixels = (topRight.x - btmLeft.x) * (topRight.y - btmLeft.y);
                NodePtr trackerInput = trackerNode->getInput(0);
                if (trackerInput) {
                    ImagePlaneDesc comps, paireComps;
                    trackerInput->getEffectInstance()->getMetadataComponents(-1, &comps, &paireComps);
                    areaPixels *= comps.getNumComponents();
                }

                double value = correlation->getValueAtTime(TimeValue(frame), DimIdx(0));

                // Convert to a percentage
                if (areaPixels > 0) {
                    value /= areaPixels;
                }

                markerError->setValueAtTime(TimeValue(frame), value, ViewSetSpec::all(), DimIdx(0));
            }
        }
    }

    if ( !center->linkTo(markerCenter) ) {
        throw std::runtime_error("Could not link center");
    }

    return ret;
} // TrackMarkerPM::trackMarker
void
ViewerNodeOverlay::drawWipeControl()
{
    Point pixelScale;
    getPixelScale(pixelScale.x, pixelScale.y);

    double angle;
    QPointF center;
    double mixAmount;
    {
        angle = _imp->wipeAngle.lock()->getValue();
        KnobDoublePtr centerKnob = _imp->wipeCenter.lock();
        center.rx() = centerKnob->getValue();
        center.ry() = centerKnob->getValue(DimIdx(1));
        mixAmount = _imp->wipeAmount.lock()->getValue();
    }
    double alphaMix1, alphaMix0, alphaCurMix;

    alphaMix1 = angle + M_PI_4 / 2;
    alphaMix0 = angle + 3. * M_PI_4 / 2;
    alphaCurMix = mixAmount * (alphaMix1 - alphaMix0) + alphaMix0;
    QPointF mix0Pos, mixPos, mix1Pos;
    double mixX, mixY, rotateW, rotateH, rotateOffsetX, rotateOffsetY;

    mixX = WIPE_MIX_HANDLE_LENGTH * pixelScale.x;
    mixY = WIPE_MIX_HANDLE_LENGTH * pixelScale.y;
    rotateW = WIPE_ROTATE_HANDLE_LENGTH * pixelScale.x;
    rotateH = WIPE_ROTATE_HANDLE_LENGTH * pixelScale.y;
    rotateOffsetX = WIPE_ROTATE_OFFSET * pixelScale.x;
    rotateOffsetY = WIPE_ROTATE_OFFSET * pixelScale.y;


    mixPos.setX(center.x() + std::cos(alphaCurMix) * mixX);
    mixPos.setY(center.y() + std::sin(alphaCurMix) * mixY);
    mix0Pos.setX(center.x() + std::cos(alphaMix0) * mixX);
    mix0Pos.setY(center.y() + std::sin(alphaMix0) * mixY);
    mix1Pos.setX(center.x() + std::cos(alphaMix1) * mixX);
    mix1Pos.setY(center.y() + std::sin(alphaMix1) * mixY);

    QPointF oppositeAxisBottom, oppositeAxisTop, rotateAxisLeft, rotateAxisRight;
    rotateAxisRight.setX( center.x() + std::cos(angle) * (rotateW - rotateOffsetX) );
    rotateAxisRight.setY( center.y() + std::sin(angle) * (rotateH - rotateOffsetY) );
    rotateAxisLeft.setX(center.x() - std::cos(angle) * rotateOffsetX);
    rotateAxisLeft.setY( center.y() - (std::sin(angle) * rotateOffsetY) );

    oppositeAxisTop.setX( center.x() + std::cos(angle + M_PI_2) * (rotateW / 2.) );
    oppositeAxisTop.setY( center.y() + std::sin(angle + M_PI_2) * (rotateH / 2.) );
    oppositeAxisBottom.setX( center.x() - std::cos(angle + M_PI_2) * (rotateW / 2.) );
    oppositeAxisBottom.setY( center.y() - std::sin(angle + M_PI_2) * (rotateH / 2.) );

    {
        GLProtectAttrib<GL_GPU> a(GL_ENABLE_BIT | GL_LINE_BIT | GL_CURRENT_BIT | GL_HINT_BIT | GL_TRANSFORM_BIT | GL_COLOR_BUFFER_BIT);
        //GLProtectMatrix p(GL_PROJECTION); // useless (we do two glTranslate in opposite directions)

        // Draw everything twice
        // l = 0: shadow
        // l = 1: drawing
        double baseColor[3];
        for (int l = 0; l < 2; ++l) {
            // shadow (uses GL_PROJECTION)
            GL_GPU::MatrixMode(GL_PROJECTION);
            int direction = (l == 0) ? 1 : -1;
            // translate (1,-1) pixels
            GL_GPU::Translated(direction * pixelScale.x, -direction * pixelScale.y, 0);
            GL_GPU::MatrixMode(GL_MODELVIEW); // Modelview should be used on Nuke

            if (l == 0) {
                // Draw a shadow for the cross hair
                baseColor[0] = baseColor[1] = baseColor[2] = 0.;
            } else {
                baseColor[0] = baseColor[1] = baseColor[2] = 0.8;
            }

            GL_GPU::Enable(GL_BLEND);
            GL_GPU::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            GL_GPU::Enable(GL_LINE_SMOOTH);
            GL_GPU::Hint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
            GL_GPU::LineWidth(1.5);
            GL_GPU::Begin(GL_LINES);
            if ( (hoverState == eHoverStateWipeRotateHandle) || (uiState == eViewerNodeInteractMouseStateRotatingWipeHandle) ) {
                GL_GPU::Color4f(0., 1. * l, 0., 1.);
            }
            GL_GPU::Color4f(baseColor[0], baseColor[1], baseColor[2], 1.);
            GL_GPU::Vertex2d( rotateAxisLeft.x(), rotateAxisLeft.y() );
            GL_GPU::Vertex2d( rotateAxisRight.x(), rotateAxisRight.y() );
            GL_GPU::Vertex2d( oppositeAxisBottom.x(), oppositeAxisBottom.y() );
            GL_GPU::Vertex2d( oppositeAxisTop.x(), oppositeAxisTop.y() );
            GL_GPU::Vertex2d( center.x(), center.y() );
            GL_GPU::Vertex2d( mixPos.x(), mixPos.y() );
            GL_GPU::End();
            GL_GPU::LineWidth(1.);

            ///if hovering the rotate handle or dragging it show a small bended arrow
            if ( (hoverState == eHoverStateWipeRotateHandle) || (uiState == eViewerNodeInteractMouseStateRotatingWipeHandle) ) {
                GLProtectMatrix<GL_GPU> p(GL_MODELVIEW);

                GL_GPU::Color4f(0., 1. * l, 0., 1.);
                double arrowCenterX = WIPE_ROTATE_HANDLE_LENGTH * pixelScale.x / 2;
                ///draw an arrow slightly bended. This is an arc of circle of radius 5 in X, and 10 in Y.
                OfxPointD arrowRadius;
                arrowRadius.x = 5. * pixelScale.x;
                arrowRadius.y = 10. * pixelScale.y;

                GL_GPU::Translatef(center.x(), center.y(), 0.);
                GL_GPU::Rotatef(angle * 180.0 / M_PI, 0, 0, 1);
                //  center the oval at x_center, y_center
                GL_GPU::Translatef (arrowCenterX, 0., 0);
                //  draw the oval using line segments
                GL_GPU::Begin (GL_LINE_STRIP);
                GL_GPU::Vertex2f (0, arrowRadius.y);
                GL_GPU::Vertex2f (arrowRadius.x, 0.);
                GL_GPU::Vertex2f (0, -arrowRadius.y);
                GL_GPU::End ();


                GL_GPU::Begin(GL_LINES);
                ///draw the top head
                GL_GPU::Vertex2f(0., arrowRadius.y);
                GL_GPU::Vertex2f(0., arrowRadius.y -  arrowRadius.x );

                GL_GPU::Vertex2f(0., arrowRadius.y);
                GL_GPU::Vertex2f(4. * pixelScale.x, arrowRadius.y - 3. * pixelScale.y); // 5^2 = 3^2+4^2

                ///draw the bottom head
                GL_GPU::Vertex2f(0., -arrowRadius.y);
                GL_GPU::Vertex2f(0., -arrowRadius.y + 5. * pixelScale.y);

                GL_GPU::Vertex2f(0., -arrowRadius.y);
                GL_GPU::Vertex2f(4. * pixelScale.x, -arrowRadius.y + 3. * pixelScale.y); // 5^2 = 3^2+4^2

                GL_GPU::End();

                GL_GPU::Color4f(baseColor[0], baseColor[1], baseColor[2], 1.);
            }

            GL_GPU::PointSize(5.);
            GL_GPU::Enable(GL_POINT_SMOOTH);
            GL_GPU::Begin(GL_POINTS);
            GL_GPU::Vertex2d( center.x(), center.y() );
            if ( ( (hoverState == eHoverStateWipeMix) &&
                  (uiState != eViewerNodeInteractMouseStateRotatingWipeHandle) )
                || (uiState == eViewerNodeInteractMouseStateDraggingWipeMixHandle) ) {
                GL_GPU::Color4f(0., 1. * l, 0., 1.);
            }
            GL_GPU::Vertex2d( mixPos.x(), mixPos.y() );
            GL_GPU::End();
            GL_GPU::PointSize(1.);

            drawArcOfCircle(center, mixX, mixY, angle + M_PI_4 / 2, angle + 3. * M_PI_4 / 2);
        }
    } // GLProtectAttrib a(GL_ENABLE_BIT | GL_LINE_BIT | GL_CURRENT_BIT | GL_HINT_BIT | GL_TRANSFORM_BIT | GL_COLOR_BUFFER_BIT);
} // drawWipeControl
Exemple #29
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
ViewerNodeOverlay::onOverlayPenMotion(TimeValue /*time*/, const RenderScale & /*renderScale*/, ViewIdx /*view*/,
                               const QPointF & /*viewportPos*/, const QPointF & pos, double /*pressure*/, TimeValue /*timestamp*/)
{
    Point pixelScale;
    getPixelScale(pixelScale.x, pixelScale.y);

    bool userRoIEnabled = _imp->toggleUserRoIButtonKnob.lock()->getValue();
    RectD userRoI;
    if (userRoIEnabled) {
        if (uiState == eViewerNodeInteractMouseStateDraggingRoiBottomEdge ||
            uiState == eViewerNodeInteractMouseStateDraggingRoiTopEdge ||
            uiState == eViewerNodeInteractMouseStateDraggingRoiLeftEdge ||
            uiState == eViewerNodeInteractMouseStateDraggingRoiRightEdge ||
            uiState == eViewerNodeInteractMouseStateDraggingRoiCross ||
            uiState == eViewerNodeInteractMouseStateDraggingRoiBottomLeft ||
            uiState == eViewerNodeInteractMouseStateDraggingRoiBottomRight ||
            uiState == eViewerNodeInteractMouseStateDraggingRoiTopLeft ||
            uiState == eViewerNodeInteractMouseStateDraggingRoiTopRight) {
            userRoI = draggedUserRoI;
        } else {
            userRoI = _imp->_publicInterface->getUserRoI();
        }
    }
    bool wipeEnabled = (ViewerCompositingOperatorEnum)_imp->blendingModeChoiceKnob.lock()->getValue() != eViewerCompositingOperatorNone;
    double wipeAmount = _imp->_publicInterface->getWipeAmount();
    double wipeAngle = _imp->_publicInterface->getWipeAngle();
    QPointF wipeCenter = _imp->_publicInterface->getWipeCenter();

    bool wasHovering = hoverState != eHoverStateNothing;
    bool cursorSet = false;
    bool overlayCaught = false;
    hoverState = eHoverStateNothing;
    if ( wipeEnabled && isNearbyWipeCenter(wipeCenter, pos, pixelScale.x, pixelScale.y) ) {
        _imp->_publicInterface->setCurrentCursor(eCursorSizeAll);
        cursorSet = true;
    } else if ( wipeEnabled && isNearbyWipeMixHandle(wipeCenter, wipeAngle, wipeAmount, pos, pixelScale.x, pixelScale.y) ) {
        hoverState = eHoverStateWipeMix;
        overlayCaught = true;
    } else if ( wipeEnabled && isNearbyWipeRotateBar(wipeCenter, wipeAngle, pos, pixelScale.x, pixelScale.y) ) {
        hoverState = eHoverStateWipeRotateHandle;
        overlayCaught = true;
    } else if (userRoIEnabled) {
        if ( isNearbyUserRoIBottomEdge(userRoI, pos, pixelScale.x, pixelScale.y)
            || isNearbyUserRoITopEdge(userRoI, pos, pixelScale.x, pixelScale.y)
            || ( uiState == eViewerNodeInteractMouseStateDraggingRoiBottomEdge)
            || ( uiState == eViewerNodeInteractMouseStateDraggingRoiTopEdge) ) {
            _imp->_publicInterface->setCurrentCursor(eCursorSizeVer);
            cursorSet = true;
        } else if ( isNearbyUserRoILeftEdge(userRoI, pos, pixelScale.x, pixelScale.y)
                   || isNearbyUserRoIRightEdge(userRoI, pos, pixelScale.x, pixelScale.y)
                   || ( uiState == eViewerNodeInteractMouseStateDraggingRoiLeftEdge)
                   || ( uiState == eViewerNodeInteractMouseStateDraggingRoiRightEdge) ) {
            _imp->_publicInterface->setCurrentCursor(eCursorSizeHor);
            cursorSet = true;
        } else if ( isNearbyUserRoI( (userRoI.x1 + userRoI.x2) / 2, (userRoI.y1 + userRoI.y2) / 2, pos, pixelScale.x, pixelScale.y )
                   || ( uiState == eViewerNodeInteractMouseStateDraggingRoiCross) ) {
            _imp->_publicInterface->setCurrentCursor(eCursorSizeAll);
            cursorSet = true;
        } else if ( isNearbyUserRoI(userRoI.x2, userRoI.y1, pos, pixelScale.x, pixelScale.y) ||
                   isNearbyUserRoI(userRoI.x1, userRoI.y2, pos, pixelScale.x, pixelScale.y) ||
                   ( uiState == eViewerNodeInteractMouseStateDraggingRoiBottomRight) ||
                   ( uiState == eViewerNodeInteractMouseStateDraggingRoiTopLeft) ) {
            _imp->_publicInterface->setCurrentCursor(eCursorFDiag);
            cursorSet = true;
        } else if ( isNearbyUserRoI(userRoI.x1, userRoI.y1, pos, pixelScale.x, pixelScale.y) ||
                   isNearbyUserRoI(userRoI.x2, userRoI.y2, pos, pixelScale.x, pixelScale.y) ||
                   ( uiState == eViewerNodeInteractMouseStateDraggingRoiBottomLeft) ||
                   ( uiState == eViewerNodeInteractMouseStateDraggingRoiTopRight) ) {
            _imp->_publicInterface->setCurrentCursor(eCursorBDiag);
            cursorSet = true;
        }
    }

    if (!cursorSet) {
        _imp->_publicInterface->setCurrentCursor(eCursorDefault);
    }


    if ( (hoverState == eHoverStateNothing) && wasHovering ) {
        overlayCaught = true;
    }

    double dx = pos.x() - lastMousePos.x();
    double dy = pos.y() - lastMousePos.y();

    switch (uiState) {
        case eViewerNodeInteractMouseStateDraggingRoiBottomEdge: {
            if ( (draggedUserRoI.y1 + dy) < draggedUserRoI.y2 ) {
                draggedUserRoI.y1 += dy;
                overlayCaught = true;
            }
            break;
        }
        case eViewerNodeInteractMouseStateDraggingRoiLeftEdge: {
            if ( (draggedUserRoI.x1 + dx) < draggedUserRoI.x2 ) {
                draggedUserRoI.x1 += dx;
                overlayCaught = true;
            }
            break;
        }
        case eViewerNodeInteractMouseStateDraggingRoiRightEdge: {
            if ( (draggedUserRoI.x2 + dx) > draggedUserRoI.x1 ) {
                draggedUserRoI.x2 += dx;
                overlayCaught = true;
            }
            break;
        }
        case eViewerNodeInteractMouseStateDraggingRoiTopEdge: {
            if ( (draggedUserRoI.y2 + dy) > draggedUserRoI.y1 ) {
                draggedUserRoI.y2 += dy;
                overlayCaught = true;
            }
            break;
        }
        case eViewerNodeInteractMouseStateDraggingRoiCross: {
            draggedUserRoI.translate(dx, dy);
            overlayCaught = true;
            break;
        }
        case eViewerNodeInteractMouseStateDraggingRoiTopLeft: {
            if ( (draggedUserRoI.y2 + dy) > draggedUserRoI.y1 ) {
                draggedUserRoI.y2 += dy;
            }
            if ( (draggedUserRoI.x1 + dx) < draggedUserRoI.x2 ) {
                draggedUserRoI.x1 += dx;
            }
            overlayCaught = true;
            break;
        }
        case eViewerNodeInteractMouseStateDraggingRoiTopRight: {
            if ( (draggedUserRoI.y2 + dy) > draggedUserRoI.y1 ) {
                draggedUserRoI.y2 += dy;
            }
            if ( (draggedUserRoI.x2 + dx) > draggedUserRoI.x1 ) {
                draggedUserRoI.x2 += dx;
            }
            overlayCaught = true;
            break;
        }
        case eViewerNodeInteractMouseStateDraggingRoiBottomRight:
        case eViewerNodeInteractMouseStateBuildingUserRoI:{
            if ( (draggedUserRoI.x2 + dx) > draggedUserRoI.x1 ) {
                draggedUserRoI.x2 += dx;
            }
            if ( (draggedUserRoI.y1 + dy) < draggedUserRoI.y2 ) {
                draggedUserRoI.y1 += dy;
            }
            overlayCaught = true;
            break;
        }
        case eViewerNodeInteractMouseStateDraggingRoiBottomLeft: {
            if ( (draggedUserRoI.y1 + dy) < draggedUserRoI.y2 ) {
                draggedUserRoI.y1 += dy;
            }
            if ( (draggedUserRoI.x1 + dx) < draggedUserRoI.x2 ) {
                draggedUserRoI.x1 += dx;
            }
            overlayCaught = true;

            break;
        }
        case eViewerNodeInteractMouseStateDraggingWipeCenter: {
            KnobDoublePtr centerKnob = _imp->wipeCenter.lock();
            centerKnob->setValue(centerKnob->getValue() + dx);
            centerKnob->setValue(centerKnob->getValue(DimIdx(1)) + dy, ViewSetSpec::all(), DimIdx(1));
            overlayCaught = true;
            break;
        }
        case eViewerNodeInteractMouseStateDraggingWipeMixHandle: {
            KnobDoublePtr centerKnob = _imp->wipeCenter.lock();
            Point center;
            center.x = centerKnob->getValue();
            center.y = centerKnob->getValue(DimIdx(1));
            double angle = std::atan2( pos.y() - center.y, pos.x() - center.x );
            double prevAngle = std::atan2( lastMousePos.y() - center.y,
                                          lastMousePos.x() - center.x );
            KnobDoublePtr mixKnob = _imp->wipeAmount.lock();
            double mixAmount = mixKnob->getValue();
            mixAmount -= (angle - prevAngle);
            mixAmount = std::max( 0., std::min(mixAmount, 1.) );
            mixKnob->setValue(mixAmount);
            overlayCaught = true;
            break;
        }
        case eViewerNodeInteractMouseStateRotatingWipeHandle: {
            KnobDoublePtr centerKnob = _imp->wipeCenter.lock();
            Point center;
            center.x = centerKnob->getValue();
            center.y = centerKnob->getValue(DimIdx(1));
            double angle = std::atan2( pos.y() - center.y, pos.x() - center.x );

            KnobDoublePtr angleKnob = _imp->wipeAngle.lock();
            double closestPI2 = M_PI_2 * std::floor(angle / M_PI_2 + 0.5);
            if (std::fabs(angle - closestPI2) < 0.1) {
                // snap to closest multiple of PI / 2.
                angle = closestPI2;
            }

            angleKnob->setValue(angle);

            overlayCaught = true;
            break;
        }
        default:
            break;
    }
    lastMousePos = pos;
    return overlayCaught;

} // onOverlayPenMotion