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); }
QPointF ViewerNode::getWipeCenter() const { KnobDoublePtr wipeCenter = _imp->wipeCenter.lock(); QPointF r; r.rx() = wipeCenter->getValue(); r.ry() = wipeCenter->getValue(DimIdx(1)); return r; }
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; }
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(); }
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); } }
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
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