예제 #1
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);
}
예제 #2
0
QPointF
ViewerNode::getWipeCenter() const
{
    KnobDoublePtr wipeCenter = _imp->wipeCenter.lock();
    QPointF r;
    r.rx() = wipeCenter->getValue();
    r.ry() = wipeCenter->getValue(DimIdx(1));
    return r;
}
예제 #3
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;
}
예제 #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();
}
예제 #5
0
파일: BaseTest.cpp 프로젝트: Kthulhu/Natron
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);
    }
}
예제 #6
0
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
예제 #7
0
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
void
TrackerNodePrivate::solveTransformParams()
{
    setTransformOutOfDate(false);

    std::vector<TrackMarkerPtr> markers;

    knobsTable->getAllMarkers(&markers);
    if ( markers.empty() ) {
        return;
    }

    resetTransformParamsAnimation();

    KnobChoicePtr motionTypeKnob = motionType.lock();
    int motionType_i = motionTypeKnob->getValue();
    TrackerMotionTypeEnum type =  (TrackerMotionTypeEnum)motionType_i;
    TimeValue refTime(referenceFrame.lock()->getValue());
    int jitterPer = 0;
    bool jitterAdd = false;
    switch (type) {
        case eTrackerMotionTypeNone:

            return;
        case eTrackerMotionTypeMatchMove:
        case eTrackerMotionTypeStabilize:
            break;
        case eTrackerMotionTypeAddJitter:
        case eTrackerMotionTypeRemoveJitter: {
            jitterPer = jitterPeriod.lock()->getValue();
            jitterAdd = type == eTrackerMotionTypeAddJitter;
            break;
        }
    }

    setSolverParamsEnabled(false);

    std::set<TimeValue> keyframes;
    {
        for (std::size_t i = 0; i < markers.size(); ++i) {
            std::set<double> keys;
            markers[i]->getCenterKeyframes(&keys);
            for (std::set<double>::iterator it = keys.begin(); it != keys.end(); ++it) {
                keyframes.insert(TimeValue(*it));
            }
        }
    }
    KnobChoicePtr transformTypeKnob = transformType.lock();
    assert(transformTypeKnob);
    int transformType_i = transformTypeKnob->getValue();
    TrackerTransformNodeEnum transformType = (TrackerTransformNodeEnum)transformType_i;
    NodePtr node = publicInterface->getNode();

    invertTransform.lock()->setValue(type == eTrackerMotionTypeStabilize);

    KnobDoublePtr centerKnob = center.lock();

    // Set the center at the reference frame
    Point centerValue = {0, 0};
    int nSamplesAtRefTime = 0;
    for (std::size_t i = 0; i < markers.size(); ++i) {
        if ( !markers[i]->isEnabled(refTime) ) {
            continue;
        }
        KnobDoublePtr markerCenterKnob = markers[i]->getCenterKnob();

        centerValue.x += markerCenterKnob->getValueAtTime(refTime);
        centerValue.y += markerCenterKnob->getValueAtTime(refTime, DimIdx(1));
        ++nSamplesAtRefTime;
    }
    if (nSamplesAtRefTime) {
        centerValue.x /= nSamplesAtRefTime;
        centerValue.y /= nSamplesAtRefTime;
        {
            std::vector<double> values(2);
            values[0] = centerValue.x;
            values[1] = centerValue.y;
            centerKnob->setValueAcrossDimensions(values);
        }

    }

    bool robust;
    robust = robustModel.lock()->getValue();

    KnobDoublePtr maxFittingErrorKnob = fittingErrorWarnIfAbove.lock();
    const double maxFittingError = maxFittingErrorKnob->getValue();

    node->getApp()->progressStart( node, tr("Solving for transform parameters...").toStdString(), std::string() );

    lastSolveRequest.refTime = refTime;
    lastSolveRequest.jitterPeriod = jitterPer;
    lastSolveRequest.jitterAdd = jitterAdd;
    lastSolveRequest.allMarkers = markers;
    lastSolveRequest.keyframes = keyframes;
    lastSolveRequest.robustModel = robust;
    lastSolveRequest.maxFittingError = maxFittingError;

    switch (transformType) {
        case eTrackerTransformNodeTransform:
            computeTransformParamsFromTracks();
            break;
        case eTrackerTransformNodeCornerPin:
            computeCornerParamsFromTracks();
            break;
    }
} // TrackerNodePrivate::solveTransformParams