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
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); } }
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(¢erKeys); for (std::set<double>::iterator it2 = centerKeys.begin(); it2 != centerKeys.end(); ++it2) { if ( userKeys.find(*it2) != userKeys.end() ) { continue; } // Add the marker to the markers ordered only if it can contribute to predicting its next position if ( ( ( (frameStep > 0) && (*it2 < start) ) || ( (frameStep < 0) && (*it2 > start) ) ) ) { previousFramesOrdered.insert( PreviouslyComputedTrackFrame(TimeValue(*it2), false) ); } } // Taken from libmv, only initialize the filter to this amount of frames (max) const int max_frames_to_predict_from = 20; std::list<mv::Marker> previouslyComputedMarkersOrdered; // Find the first keyframe that's not considered to go before start or end PreviouslyTrackedFrameSet::iterator prevFramesIt = previousFramesOrdered.lower_bound(PreviouslyComputedTrackFrame(start, false)); if (frameStep < 0) { if (prevFramesIt != previousFramesOrdered.end()) { while (prevFramesIt != previousFramesOrdered.end() && (int)previouslyComputedMarkersOrdered.size() != max_frames_to_predict_from) { mv::Marker mvMarker; TrackerHelperPrivate::natronTrackerToLibMVTracker(true, enabledChannels, *t->natronMarker, trackIndex, TimeValue(prevFramesIt->frame), frameStep, formatHeight, &mvMarker); trackContext->AddMarker(mvMarker); // insert in the front of the list so that the order is reversed previouslyComputedMarkersOrdered.push_front(mvMarker); ++prevFramesIt; } } // previouslyComputedMarkersOrdered is now ordererd by decreasing order } else { if (prevFramesIt != previousFramesOrdered.end()) { while (prevFramesIt != previousFramesOrdered.begin() && (int)previouslyComputedMarkersOrdered.size() != max_frames_to_predict_from) { mv::Marker mvMarker; TrackerHelperPrivate::natronTrackerToLibMVTracker(true, enabledChannels, *t->natronMarker, trackIndex, TimeValue(prevFramesIt->frame), frameStep, formatHeight, &mvMarker); trackContext->AddMarker(mvMarker); // insert in the front of the list so that the order is reversed previouslyComputedMarkersOrdered.push_front(mvMarker); --prevFramesIt; } if (prevFramesIt == previousFramesOrdered.begin() && (int)previouslyComputedMarkersOrdered.size() != max_frames_to_predict_from) { mv::Marker mvMarker; TrackerHelperPrivate::natronTrackerToLibMVTracker(true, enabledChannels, *t->natronMarker, trackIndex, TimeValue(prevFramesIt->frame), frameStep, formatHeight, &mvMarker); trackContext->AddMarker(mvMarker); // insert in the front of the list so that the order is reversed previouslyComputedMarkersOrdered.push_front(mvMarker); } } // previouslyComputedMarkersOrdered is now ordererd by increasing order } // There must be at least 1 marker at the start time assert( !previouslyComputedMarkersOrdered.empty() ); // Initialise the kalman state with the marker at the position std::list<mv::Marker>::iterator mIt = previouslyComputedMarkersOrdered.begin(); t->mvState.Init(*mIt, frameStep); ++mIt; for (; mIt != previouslyComputedMarkersOrdered.end(); ++mIt) { mv::Marker predictedMarker; if ( !t->mvState.PredictForward(mIt->frame, &predictedMarker) ) { break; } else { t->mvState.Update(*mIt); } } t->mvOptions = mvOptions; trackAndOptions.push_back(t); } /* Launch tracking in the scheduler thread. */ boost::shared_ptr<TrackArgs> args( new TrackArgs(start, end, frameStep, trackerNode->getApp()->getTimeLine(), viewer, trackContext, accessor, trackAndOptions, formatWidth, formatHeight, autoKeyingOnEnabledParamEnabled) ); _imp->scheduler->track(args); } // TrackerHelper::trackMarkers
bool CornerPinOverlayInteract::onOverlayPenMotion(TimeValue time, const RenderScale & /*renderScale*/, ViewIdx view, const QPointF & /*viewportPos*/, const QPointF & penPos, double /*pressure*/, TimeValue /*timestamp*/) { // do not show interact if knob is secret or not enabled // see https://github.com/MrKepzie/Natron/issues/932 KnobDoublePtr from1Knob = _imp->from[0].lock(); if ( !from1Knob || !from1Knob->shouldDrawOverlayInteract() ) { return false; } RenderScale pscale; getPixelScale(pscale.x, pscale.y); OfxPointD to[4]; OfxPointD from[4]; bool enable[4]; bool useFrom; if (_imp->dragging == -1) { for (int i = 0; i < 4; ++i) { _imp->getFrom(time, i, &from[i].x, &from[i].y); _imp->getTo(time, i, &to[i].x, &to[i].y); enable[i] = _imp->getEnabled(time, i); } useFrom = _imp->getUseFromPoints(time); } else { for (int i = 0; i < 4; ++i) { to[i] = _imp->toDrag[i]; from[i] = _imp->fromDrag[i]; enable[i] = _imp->enableDrag[i]; } useFrom = _imp->useFromDrag; } if (!useFrom && !_imp->areToPointsAnimated()) { return false; } OfxPointD p[4]; OfxPointD q[4]; int enableBegin = 4; int enableEnd = 0; for (int i = 0; i < 4; ++i) { if (enable[i]) { if (useFrom) { p[i] = from[i]; q[i] = to[i]; } else { q[i] = from[i]; p[i] = to[i]; } if (i < enableBegin) { enableBegin = i; } if (i + 1 > enableEnd) { enableEnd = i + 1; } } } bool didSomething = false; bool valuesChanged = false; OfxPointD delta; delta.x = penPos.x() - _imp->lastPenPos.x(); delta.y = penPos.y() - _imp->lastPenPos.y(); _imp->hovering = -1; for (int i = enableBegin; i < enableEnd; ++i) { if (enable[i]) { if (_imp->dragging == i) { if (useFrom) { from[i].x += delta.x; from[i].y += delta.y; _imp->fromDrag[i] = from[i]; } else { to[i].x += delta.x; to[i].y += delta.y; _imp->toDrag[i] = to[i]; } valuesChanged = true; } else if ( CornerPinOverlayInteractPrivate::isNearby(penPos, p[i].x, p[i].y, CornerPinOverlayInteractPrivate::pointTolerance(), pscale) ) { _imp->hovering = i; didSomething = true; } } } if ( (_imp->dragging != -1) && _imp->interactiveDrag && valuesChanged ) { // no need to redraw overlay since it is slave to the paramaters if (_imp->useFromDrag) { KnobDoublePtr knob = _imp->from[_imp->dragging].lock(); assert(knob); std::vector<double> val(2); val[0] = from[_imp->dragging].x; val[1] = from[_imp->dragging].y; knob->setValueAcrossDimensions(val, DimIdx(0), view, eValueChangedReasonUserEdited); } else { KnobDoublePtr knob = _imp->to[_imp->dragging].lock(); assert(knob); std::vector<double> val(2); val[0] = to[_imp->dragging].x; val[1] = to[_imp->dragging].y; if (_imp->toPointsAutoKeyingEnabled) { knob->setValueAtTimeAcrossDimensions(time, val, DimIdx(0), view, eValueChangedReasonUserEdited); // Also set a keyframe on other points for (int i = 0; i < 4; ++i) { if (i == _imp->dragging) { continue; } std::vector<double> values(2); KnobDoublePtr toPoint = _imp->to[i].lock(); values[0] = toPoint->getValueAtTime(time, DimIdx(0)); values[1] = toPoint->getValueAtTime(time, DimIdx(1)); toPoint->setValueAtTimeAcrossDimensions(time, values, DimIdx(0), view, eValueChangedReasonUserEdited); } } else { knob->setValueAcrossDimensions(val, DimIdx(0), view, eValueChangedReasonUserEdited); } } } _imp->lastPenPos = penPos; return didSomething || valuesChanged; } // onOverlayPenMotion