Blender V4.3
tracking_select.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "MEM_guardedalloc.h"
10
11#include "DNA_movieclip_types.h"
12#include "DNA_scene_types.h"
13
14#include "BLI_lasso_2d.hh"
15#include "BLI_listbase.h"
16#include "BLI_math_base.hh"
17#include "BLI_math_geom.h"
18#include "BLI_math_vector.h"
20#include "BLI_rect.h"
21#include "BLI_utildefines.h"
22
23#include "BKE_context.hh"
24#include "BKE_tracking.h"
25
26#include "WM_api.hh"
27#include "WM_types.hh"
28
29#include "ED_clip.hh"
30#include "ED_select_utils.hh"
31
32#include "RNA_access.hh"
33#include "RNA_define.hh"
34
35#include "UI_view2d.hh"
36
37#include "DEG_depsgraph.hh"
38
39#include "clip_intern.hh" /* own include */
40#include "tracking_ops_intern.hh" /* own include */
41
42using blender::Array;
43using blender::int2;
44using blender::Span;
45
46namespace math = blender::math;
47
48/* -------------------------------------------------------------------- */
51
53{
54 PointTrackPick pick = {nullptr};
55
56 pick.area = TRACK_AREA_NONE;
58 pick.corner_index = -1;
60
61 return pick;
62}
63
64static void slide_marker_tilt_slider_relative(const float pattern_corners[4][2], float r_slider[2])
65{
66 add_v2_v2v2(r_slider, pattern_corners[1], pattern_corners[2]);
67}
68
69static void slide_marker_tilt_slider(const float marker_pos[2],
70 const float pattern_corners[4][2],
71 float r_slider[2])
72{
73 slide_marker_tilt_slider_relative(pattern_corners, r_slider);
74 add_v2_v2(r_slider, marker_pos);
75}
76
77static float mouse_to_slide_zone_distance_squared(const float co[2],
78 const float slide_zone[2],
79 int width,
80 int height)
81{
82 const float pixel_co[2] = {co[0] * width, co[1] * height},
83 pixel_slide_zone[2] = {slide_zone[0] * width, slide_zone[1] * height};
84 return square_f(pixel_co[0] - pixel_slide_zone[0]) + square_f(pixel_co[1] - pixel_slide_zone[1]);
85}
86
88 const MovieTrackingMarker *marker, const float co[2], int corner, int width, int height)
89{
90 float side_zone[2];
91 if (corner == 0) {
92 side_zone[0] = marker->pos[0] + marker->search_max[0];
93 side_zone[1] = marker->pos[1] + marker->search_min[1];
94 }
95 else {
96 side_zone[0] = marker->pos[0] + marker->search_min[0];
97 side_zone[1] = marker->pos[1] + marker->search_max[1];
98 }
99 return mouse_to_slide_zone_distance_squared(co, side_zone, width, height);
100}
101
103 const MovieTrackingMarker *marker, const float co[2], int width, int height, int *r_corner)
104{
105 float min_distance_squared = FLT_MAX;
106 for (int i = 0; i < 4; i++) {
107 float corner_co[2];
108 add_v2_v2v2(corner_co, marker->pattern_corners[i], marker->pos);
109 float distance_squared = mouse_to_slide_zone_distance_squared(co, corner_co, width, height);
110 if (distance_squared < min_distance_squared) {
111 min_distance_squared = distance_squared;
112 *r_corner = i;
113 }
114 }
115 return min_distance_squared;
116}
117
119 const MovieTrackingMarker *marker,
120 const float co[2],
121 int width,
122 int height)
123{
124 float pos[2];
125 add_v2_v2v2(pos, marker->pos, track->offset);
126 return mouse_to_slide_zone_distance_squared(co, pos, width, height);
127}
128
130 const float co[2],
131 int width,
132 int height)
133{
134 float slider[2];
135 slide_marker_tilt_slider(marker->pos, marker->pattern_corners, slider);
136 return mouse_to_slide_zone_distance_squared(co, slider, width, height);
137}
138
140 const float corners_offset[2],
141 const float corners[4][2],
142 int width,
143 int height)
144{
145 const float co_px[2] = {co[0] * width, co[1] * height};
146
147 float prev_corner_co_px[2];
148 add_v2_v2v2(prev_corner_co_px, corners_offset, corners[3]);
149 prev_corner_co_px[0] *= width;
150 prev_corner_co_px[1] *= height;
151
152 float min_distance_squared = FLT_MAX;
153
154 for (int i = 0; i < 4; ++i) {
155 float corner_co_px[2];
156 add_v2_v2v2(corner_co_px, corners_offset, corners[i]);
157 corner_co_px[0] *= width;
158 corner_co_px[1] *= height;
159
160 const float distance_squared = dist_squared_to_line_segment_v2(
161 co_px, corner_co_px, prev_corner_co_px);
162
163 if (distance_squared < min_distance_squared) {
164 min_distance_squared = distance_squared;
165 }
166
167 copy_v2_v2(prev_corner_co_px, corner_co_px);
168 }
169
170 return min_distance_squared;
171}
172
174 const float co[2],
175 int width,
176 int height)
177{
179 co, marker->pos, marker->pattern_corners, width, height);
180}
181
183 const float co[2],
184 int width,
185 int height)
186{
187 const float corners[4][2] = {
188 {marker->search_min[0], marker->search_min[1]},
189 {marker->search_max[0], marker->search_min[1]},
190 {marker->search_max[0], marker->search_max[1]},
191 {marker->search_min[0], marker->search_max[1]},
192 };
193
194 return mouse_to_closest_corners_edge_distance_squared(co, marker->pos, corners, width, height);
195}
196
198 bContext *C,
199 const float co[2])
200{
201 SpaceClip *space_clip = CTX_wm_space_clip(C);
202
203 int width, height;
204 ED_space_clip_get_size(space_clip, &width, &height);
205 if (width == 0 || height == 0) {
207 }
208
209 MovieClip *clip = ED_space_clip_get_clip(space_clip);
211
212 const float distance_tolerance_px_squared = math::square(12.0f / space_clip->zoom *
214 const bool are_disabled_markers_visible = (space_clip->flag & SC_HIDE_DISABLED) == 0;
215 const int framenr = ED_space_clip_get_clip_frame_number(space_clip);
216
218
219 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
220 const bool is_track_selected = TRACK_VIEW_SELECTED(space_clip, track);
221
222 if (options->selected_only && !is_track_selected) {
223 continue;
224 }
225 if (options->unlocked_only && (track->flag & TRACK_LOCKED)) {
226 continue;
227 }
228
229 MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
230 const bool is_marker_enabled = ((marker->flag & MARKER_DISABLED) == 0);
231
232 if (!is_marker_enabled) {
233 if (options->enabled_only) {
234 /* Disabled marker is requested to not be in the pick result, so skip it. */
235 continue;
236 }
237
238 /* See whether the disabled marker is visible.
239 *
240 * If the clip editor is not hiding disabled markers, then all disabled markers are visible.
241 * Otherwise only disabled marker of the active track is visible. */
242 if (!are_disabled_markers_visible && track != tracking_object->active_track) {
243 continue;
244 }
245 }
246
247 float distance_squared;
248
249 /* Initialize the current pick with the offset point of the track. */
251 current_pick.track = track;
252 current_pick.marker = marker;
253 current_pick.area = TRACK_AREA_POINT;
255 track, marker, co, width, height);
256
257 /* If search area is visible, check how close to its sliding zones mouse is.
258 * NOTE: The search area is only visible for selected tracks. */
259 if (is_track_selected && (space_clip->flag & SC_SHOW_MARKER_SEARCH)) {
260 distance_squared = mouse_to_search_corner_distance_squared(marker, co, 1, width, height);
261 if (distance_squared < current_pick.distance_px_squared) {
262 current_pick.area = TRACK_AREA_SEARCH;
264 current_pick.distance_px_squared = distance_squared;
265 }
266
267 distance_squared = mouse_to_search_corner_distance_squared(marker, co, 0, width, height);
268 if (distance_squared < current_pick.distance_px_squared) {
269 current_pick.area = TRACK_AREA_SEARCH;
271 current_pick.distance_px_squared = distance_squared;
272 }
273 }
274
275 /* If pattern area is visible, check which corner is closest to the mouse. */
276 if (space_clip->flag & SC_SHOW_MARKER_PATTERN) {
277 int current_corner = -1;
279 marker, co, width, height, &current_corner);
280 if (distance_squared < current_pick.distance_px_squared) {
281 current_pick.area = TRACK_AREA_PAT;
283 current_pick.corner_index = current_corner;
284 current_pick.distance_px_squared = distance_squared;
285 }
286
287 /* Here we also check whether the mouse is actually closer to the widget which controls scale
288 * and tilt.
289 * NOTE: The tilt control is only visible for selected tracks. */
290 if (is_track_selected) {
291 distance_squared = mouse_to_tilt_distance_squared(marker, co, width, height);
292 if (distance_squared < current_pick.distance_px_squared) {
293 current_pick.area = TRACK_AREA_PAT;
295 current_pick.distance_px_squared = distance_squared;
296 }
297 }
298 }
299
300 /* Whenever a manipulation "widgets" are not within distance tolerance test the edges as well.
301 * This allows to pick tracks by clicking on the pattern/search areas edges but prefer to use
302 * more actionable "widget" for sliding. */
303 if (current_pick.distance_px_squared > distance_tolerance_px_squared) {
304 if (is_track_selected && (space_clip->flag & SC_SHOW_MARKER_SEARCH)) {
306 marker, co, width, height);
307 if (distance_squared < current_pick.distance_px_squared) {
308 current_pick.area = TRACK_AREA_SEARCH;
310 current_pick.distance_px_squared = distance_squared;
311 }
312 }
313
314 if (space_clip->flag & SC_SHOW_MARKER_PATTERN) {
316 marker, co, width, height);
317 if (distance_squared < current_pick.distance_px_squared) {
318 current_pick.area = TRACK_AREA_PAT;
320 current_pick.distance_px_squared = distance_squared;
321 }
322 }
323 }
324
325 if (current_pick.distance_px_squared < pick.distance_px_squared) {
326 pick = current_pick;
327 }
328 }
329
330 if (pick.distance_px_squared > distance_tolerance_px_squared) {
332 }
333
334 return pick;
335}
336
338 const PointTrackPick *pick)
339{
340 if (pick->track == nullptr) {
341 return false;
342 }
343
344 BLI_assert(pick->marker != nullptr);
345
346 if (!TRACK_VIEW_SELECTED(space_clip, pick->track)) {
347 return false;
348 }
349
350 if (pick->track->flag & TRACK_LOCKED) {
351 return false;
352 }
353 if (pick->marker->flag & MARKER_DISABLED) {
354 return false;
355 }
356
358}
359
361
362/* -------------------------------------------------------------------- */
365
367{
368 PlaneTrackPick result = {nullptr};
369
370 result.corner_index = -1;
371 result.distance_px_squared = FLT_MAX;
372
373 return result;
374}
375
376static float mouse_to_plane_slide_zone_distance_squared(const float co[2],
377 const float slide_zone[2],
378 int width,
379 int height)
380{
381 const float pixel_co[2] = {co[0] * width, co[1] * height};
382 const float pixel_slide_zone[2] = {slide_zone[0] * width, slide_zone[1] * height};
383 return square_f(pixel_co[0] - pixel_slide_zone[0]) + square_f(pixel_co[1] - pixel_slide_zone[1]);
384}
385
387 bContext *C,
388 const float co[2])
389{
390 SpaceClip *space_clip = CTX_wm_space_clip(C);
391
392 int width, height;
393 ED_space_clip_get_size(space_clip, &width, &height);
394 if (width == 0 || height == 0) {
396 }
397
398 MovieClip *clip = ED_space_clip_get_clip(space_clip);
400 const int framenr = ED_space_clip_get_clip_frame_number(space_clip);
401
402 const float distance_tolerance_px_squared = math::square(12.0f / space_clip->zoom *
405
406 LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, &tracking_object->plane_tracks) {
407 if (options->selected_only && !PLANE_TRACK_VIEW_SELECTED(plane_track)) {
408 continue;
409 }
410
411 MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track, framenr);
412
414 current_pick.plane_track = plane_track;
415 current_pick.plane_marker = plane_marker;
416
417 for (int i = 0; i < 4; i++) {
418 const float distance_squared = mouse_to_plane_slide_zone_distance_squared(
419 co, plane_marker->corners[i], width, height);
420
421 if (distance_squared < current_pick.distance_px_squared) {
422 current_pick.corner_index = i;
423 current_pick.distance_px_squared = distance_squared;
424 }
425 }
426
427 if (current_pick.distance_px_squared > distance_tolerance_px_squared) {
428 const float zero_offset[2] = {0.0f, 0.0f};
429 const float distance_squared = mouse_to_closest_corners_edge_distance_squared(
430 co, zero_offset, plane_marker->corners, width, height);
431 if (distance_squared < current_pick.distance_px_squared) {
432 current_pick.corner_index = -1;
433 current_pick.distance_px_squared = distance_squared;
434 }
435 }
436
437 if (current_pick.distance_px_squared < pick.distance_px_squared) {
438 pick = current_pick;
439 }
440 }
441
442 if (pick.distance_px_squared > distance_tolerance_px_squared) {
444 }
445
446 return pick;
447}
448
450{
451 if (pick->plane_track == nullptr) {
452 return false;
453 }
454
455 BLI_assert(pick->plane_marker != nullptr);
456
458 return false;
459 }
460
461 return pick->corner_index != -1;
462}
463
465
466/* -------------------------------------------------------------------- */
469
471{
473
474 result.point_track_pick = point_track_pick_make_null();
475 result.plane_track_pick = plane_track_pick_make_null();
476
477 return result;
478}
479
481 const PointTrackPick *point_track_pick,
482 const PlaneTrackPick *plane_track_pick)
483{
484 /* Simple case: one of the pick results is empty, so prefer the other one. */
485 if (point_track_pick->track == nullptr) {
486 return false;
487 }
488 if (plane_track_pick->plane_track == nullptr) {
489 return true;
490 }
491
492 SpaceClip *space_clip = CTX_wm_space_clip(C);
493
494 /* If one of the picks can be slid prefer it. */
495 const bool can_slide_point_track = ed_tracking_point_track_pick_can_slide(space_clip,
496 point_track_pick);
497 const bool can_slide_plane_track = ed_tracking_plane_track_pick_can_slide(plane_track_pick);
498 if (can_slide_point_track && !can_slide_plane_track) {
499 return true;
500 }
501 else if (!can_slide_point_track && can_slide_plane_track) {
502 return false;
503 }
504
505 /* Prefer the closest pick. */
506 if (point_track_pick->distance_px_squared > plane_track_pick->distance_px_squared) {
507 return false;
508 }
509 return true;
510}
511
530
532
533/********************** mouse select operator *********************/
534
536{
537 LISTBASE_FOREACH (MovieTrackingTrack *, track, tracks_base) {
539 }
540}
541
543{
544 LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, plane_tracks_base) {
545 plane_track->flag &= ~SELECT;
546 }
547}
548
549static bool select_poll(bContext *C)
550{
552
553 if (sc) {
554 return sc->clip && sc->view == SC_VIEW_CLIP;
555 }
556
557 return false;
558}
559
561{
564 MovieTracking *tracking = &clip->tracking;
565 MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
566 const bool extend = RNA_boolean_get(op->ptr, "extend");
567 const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
568
569 float co[2];
570 RNA_float_get_array(op->ptr, "location", co);
571
574
575 /* Special code which allows to slide a marker which belongs to currently selected but not yet
576 * active track. If such track is found activate it and return pass-though so that marker slide
577 * operator can be used immediately after.
578 * This logic makes it convenient to slide markers when left mouse selection is used. Without it
579 * selection will be lost which causes inconvenience for the VFX artist. */
580 if (!extend && ed_tracking_pick_can_slide(sc, &pick)) {
581 if (pick.point_track_pick.track != nullptr) {
582 tracking_object->active_track = pick.point_track_pick.track;
583 tracking_object->active_plane_track = nullptr;
584 }
585 else {
586 tracking_object->active_track = nullptr;
587 tracking_object->active_plane_track = pick.plane_track_pick.plane_track;
588 }
589
592
594 }
595
596 ClipViewLockState lock_state;
597 ED_clip_view_lock_state_store(C, &lock_state);
598
599 if (pick.point_track_pick.track != nullptr) {
600 if (!extend) {
602 }
603
605 int area = pick.point_track_pick.area;
606
607 if (!extend || !TRACK_VIEW_SELECTED(sc, track)) {
608 area = TRACK_AREA_ALL;
609 }
610
611 if (extend && TRACK_AREA_SELECTED(track, area)) {
612 if (track == tracking_object->active_track) {
613 BKE_tracking_track_deselect(track, area);
614 }
615 else {
616 tracking_object->active_track = track;
617 tracking_object->active_plane_track = nullptr;
618 }
619 }
620 else {
621 if (area == TRACK_AREA_POINT) {
622 area = TRACK_AREA_ALL;
623 }
624
625 BKE_tracking_track_select(&tracking_object->tracks, track, area, extend);
626 tracking_object->active_track = track;
627 tracking_object->active_plane_track = nullptr;
628 }
629 }
630 else if (pick.plane_track_pick.plane_track != nullptr) {
631 if (!extend) {
632 ed_tracking_deselect_all_tracks(&tracking_object->tracks);
633 }
634
636
637 if (PLANE_TRACK_VIEW_SELECTED(plane_track)) {
638 if (extend) {
639 plane_track->flag &= ~SELECT;
640 }
641 }
642 else {
643 plane_track->flag |= SELECT;
644 }
645
646 tracking_object->active_track = nullptr;
647 tracking_object->active_plane_track = plane_track;
648 }
649 else if (deselect_all) {
650 ed_tracking_deselect_all_tracks(&tracking_object->tracks);
652 }
653
655
657
660
661 /* Pass-through + finished to allow tweak to transform. */
663}
664
665static int select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
666{
668 ARegion *region = CTX_wm_region(C);
669
670 float co[2];
671 ED_clip_mouse_pos(sc, region, event->mval, co);
672 RNA_float_set_array(op->ptr, "location", co);
673
674 return select_exec(C, op);
675}
676
678{
679 /* identifiers */
680 ot->name = "Select";
681 ot->description = "Select tracking markers";
682 ot->idname = "CLIP_OT_select";
683
684 /* api callbacks */
685 ot->exec = select_exec;
686 ot->invoke = select_invoke;
687 ot->poll = select_poll;
688
689 /* flags */
690 ot->flag = OPTYPE_UNDO;
691
692 /* properties */
693 PropertyRNA *prop;
694 prop = RNA_def_boolean(ot->srna,
695 "extend",
696 false,
697 "Extend",
698 "Extend selection rather than clearing the existing selection");
700 prop = RNA_def_boolean(ot->srna,
701 "deselect_all",
702 false,
703 "Deselect On Nothing",
704 "Deselect all when nothing under the cursor");
706
708 ot->srna,
709 "location",
710 2,
711 nullptr,
712 -FLT_MAX,
713 FLT_MAX,
714 "Location",
715 "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds",
716 -100.0f,
717 100.0f);
718}
719
721{
722 /* To avoid conflicts with mask select deselect all in empty space. */
723 return select_poll(C);
724}
725
726/********************** box select operator *********************/
727
729{
731 ARegion *region = CTX_wm_region(C);
732
734 const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(&clip->tracking);
735 rcti rect;
736 rctf rectf;
737 bool changed = false;
738 int framenr = ED_space_clip_get_clip_frame_number(sc);
739
740 /* get rectangle from operator */
742
743 ED_clip_point_stable_pos(sc, region, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
744 ED_clip_point_stable_pos(sc, region, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
745
746 const eSelectOp sel_op = eSelectOp(RNA_enum_get(op->ptr, "mode"));
747 const bool select = (sel_op != SEL_OP_SUB);
748 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
749 ED_clip_select_all(sc, SEL_DESELECT, nullptr);
750 changed = true;
751 }
752
753 /* do actual selection */
754 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
755 if (track->flag & TRACK_HIDDEN) {
756 continue;
757 }
758
759 const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
760
761 if (ED_space_clip_marker_is_visible(sc, tracking_object, track, marker)) {
762 if (BLI_rctf_isect_pt_v(&rectf, marker->pos)) {
763 if (select) {
765 }
766 else {
768 }
769 }
770 changed = true;
771 }
772 }
773
774 LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, &tracking_object->plane_tracks) {
775 if (plane_track->flag & PLANE_TRACK_HIDDEN) {
776 continue;
777 }
778
779 const MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track,
780 framenr);
781
782 for (int i = 0; i < 4; i++) {
783 if (BLI_rctf_isect_pt_v(&rectf, plane_marker->corners[i])) {
784 if (select) {
785 plane_track->flag |= SELECT;
786 }
787 else {
788 plane_track->flag &= ~SELECT;
789 }
790 }
791 }
792 changed = true;
793 }
794
795 if (changed) {
797
800
801 return OPERATOR_FINISHED;
802 }
803
804 return OPERATOR_CANCELLED;
805}
806
808{
809 /* identifiers */
810 ot->name = "Box Select";
811 ot->description = "Select markers using box selection";
812 ot->idname = "CLIP_OT_select_box";
813
814 /* api callbacks */
815 ot->invoke = WM_gesture_box_invoke;
816 ot->exec = box_select_exec;
817 ot->modal = WM_gesture_box_modal;
819
820 /* flags */
821 ot->flag = OPTYPE_UNDO;
822
823 /* properties */
826}
827
828/********************** lasso select operator *********************/
829
830static int do_lasso_select_marker(bContext *C, const Span<int2> mcoords, bool select)
831{
833 ARegion *region = CTX_wm_region(C);
834
836 const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(&clip->tracking);
837 rcti rect;
838 bool changed = false;
839 const int framenr = ED_space_clip_get_clip_frame_number(sc);
840
841 /* get rectangle from operator */
842 BLI_lasso_boundbox(&rect, mcoords);
843
844 /* do actual selection */
845 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
846 if (track->flag & TRACK_HIDDEN) {
847 continue;
848 }
849
850 const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
851
852 if (ED_space_clip_marker_is_visible(sc, tracking_object, track, marker)) {
853 float screen_co[2];
854
855 /* marker in screen coords */
856 ED_clip_point_stable_pos__reverse(sc, region, marker->pos, screen_co);
857
858 if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) &&
859 BLI_lasso_is_point_inside(mcoords, screen_co[0], screen_co[1], V2D_IS_CLIPPED))
860 {
861 if (select) {
863 }
864 else {
866 }
867 }
868
869 changed = true;
870 }
871 }
872
873 LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, &tracking_object->plane_tracks) {
874 if (plane_track->flag & PLANE_TRACK_HIDDEN) {
875 continue;
876 }
877
878 const MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track,
879 framenr);
880
881 for (int i = 0; i < 4; i++) {
882 float screen_co[2];
883
884 /* marker in screen coords */
885 ED_clip_point_stable_pos__reverse(sc, region, plane_marker->corners[i], screen_co);
886
887 if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) &&
888 BLI_lasso_is_point_inside(mcoords, screen_co[0], screen_co[1], V2D_IS_CLIPPED))
889 {
890 if (select) {
891 plane_track->flag |= SELECT;
892 }
893 else {
894 plane_track->flag &= ~SELECT;
895 }
896 }
897 }
898
899 changed = true;
900 }
901
902 if (changed) {
904
907 }
908
909 return changed;
910}
911
913{
914 const Array<int2> mcoords = WM_gesture_lasso_path_to_array(C, op);
915
916 if (mcoords.is_empty()) {
918 }
919
920 const eSelectOp sel_op = eSelectOp(RNA_enum_get(op->ptr, "mode"));
921 const bool select = (sel_op != SEL_OP_SUB);
922 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
924 ED_clip_select_all(sc, SEL_DESELECT, nullptr);
925 }
926
928
929 return OPERATOR_FINISHED;
930}
931
933{
934 /* identifiers */
935 ot->name = "Lasso Select";
936 ot->description = "Select markers using lasso selection";
937 ot->idname = "CLIP_OT_select_lasso";
938
939 /* api callbacks */
940 ot->invoke = WM_gesture_lasso_invoke;
941 ot->modal = WM_gesture_lasso_modal;
944 ot->cancel = WM_gesture_lasso_cancel;
945
946 /* flags */
948
949 /* properties */
952}
953
954/********************** circle select operator *********************/
955
956static int point_inside_ellipse(const float point[2],
957 const float offset[2],
958 const float ellipse[2])
959{
960 /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
961 float x, y;
962
963 x = (point[0] - offset[0]) * ellipse[0];
964 y = (point[1] - offset[1]) * ellipse[1];
965
966 return x * x + y * y < 1.0f;
967}
968
970 const float offset[2],
971 const float ellipse[2])
972{
973 return point_inside_ellipse(marker->pos, offset, ellipse);
974}
975
977{
979 ARegion *region = CTX_wm_region(C);
980
982 const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(&clip->tracking);
983 int width, height;
984 bool changed = false;
985 float zoomx, zoomy, offset[2], ellipse[2];
986 int framenr = ED_space_clip_get_clip_frame_number(sc);
987
988 /* get operator properties */
989 const int x = RNA_int_get(op->ptr, "x");
990 const int y = RNA_int_get(op->ptr, "y");
991 const int radius = RNA_int_get(op->ptr, "radius");
992
993 const eSelectOp sel_op = ED_select_op_modal(
994 eSelectOp(RNA_enum_get(op->ptr, "mode")),
995 WM_gesture_is_modal_first(static_cast<wmGesture *>(op->customdata)));
996 const bool select = (sel_op != SEL_OP_SUB);
997 if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
998 ED_clip_select_all(sc, SEL_DESELECT, nullptr);
999 changed = true;
1000 }
1001
1002 /* compute ellipse and position in unified coordinates */
1003 ED_space_clip_get_size(sc, &width, &height);
1004 ED_space_clip_get_zoom(sc, region, &zoomx, &zoomy);
1005
1006 ellipse[0] = width * zoomx / radius;
1007 ellipse[1] = height * zoomy / radius;
1008
1009 ED_clip_point_stable_pos(sc, region, x, y, &offset[0], &offset[1]);
1010
1011 /* do selection */
1012 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
1013 if (track->flag & TRACK_HIDDEN) {
1014 continue;
1015 }
1016
1017 const MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
1018
1019 if (ED_space_clip_marker_is_visible(sc, tracking_object, track, marker) &&
1020 marker_inside_ellipse(marker, offset, ellipse))
1021 {
1022 if (select) {
1024 }
1025 else {
1027 }
1028 changed = true;
1029 }
1030 }
1031
1032 LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, &tracking_object->plane_tracks) {
1033 if (plane_track->flag & PLANE_TRACK_HIDDEN) {
1034 continue;
1035 }
1036
1037 const MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track,
1038 framenr);
1039
1040 for (int i = 0; i < 4; i++) {
1041 if (point_inside_ellipse(plane_marker->corners[i], offset, ellipse)) {
1042 if (select) {
1043 plane_track->flag |= SELECT;
1044 }
1045 else {
1046 plane_track->flag &= ~SELECT;
1047 }
1048 }
1049 }
1050
1051 changed = true;
1052 }
1053
1054 if (changed) {
1056
1059
1060 return OPERATOR_FINISHED;
1061 }
1062
1063 return OPERATOR_CANCELLED;
1064}
1065
1067{
1068 /* identifiers */
1069 ot->name = "Circle Select";
1070 ot->description = "Select markers using circle selection";
1071 ot->idname = "CLIP_OT_select_circle";
1072
1073 /* api callbacks */
1074 ot->invoke = WM_gesture_circle_invoke;
1075 ot->modal = WM_gesture_circle_modal;
1076 ot->exec = circle_select_exec;
1078 ot->get_name = ED_select_circle_get_name;
1079
1080 /* flags */
1081 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1082
1083 /* properties */
1086}
1087
1088/********************** select all operator *********************/
1089
1091{
1094 MovieTracking *tracking = &clip->tracking;
1095
1096 const int action = RNA_enum_get(op->ptr, "action");
1097
1098 ClipViewLockState lock_state;
1099 ED_clip_view_lock_state_store(C, &lock_state);
1100
1101 bool has_selection = false;
1102 ED_clip_select_all(sc, action, &has_selection);
1103
1104 if (has_selection) {
1106 }
1107
1109
1112
1113 return OPERATOR_FINISHED;
1114}
1115
1117{
1118 /* identifiers */
1119 ot->name = "(De)select All";
1120 ot->description = "Change selection of all tracking markers";
1121 ot->idname = "CLIP_OT_select_all";
1122
1123 /* api callbacks */
1124 ot->exec = select_all_exec;
1126
1127 /* flags */
1128 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1129
1131}
1132
1133/********************** select grouped operator *********************/
1134
1136{
1139 const MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(&clip->tracking);
1140 const int group = RNA_enum_get(op->ptr, "group");
1141 const int framenr = ED_space_clip_get_clip_frame_number(sc);
1142
1143 LISTBASE_FOREACH (MovieTrackingTrack *, track, &tracking_object->tracks) {
1144 bool ok = false;
1145
1146 MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
1147
1148 if (group == 0) { /* Keyframed */
1149 ok = marker->framenr == framenr && (marker->flag & MARKER_TRACKED) == 0;
1150 }
1151 else if (group == 1) { /* Estimated */
1152 ok = marker->framenr != framenr;
1153 }
1154 else if (group == 2) { /* tracked */
1155 ok = marker->framenr == framenr && (marker->flag & MARKER_TRACKED);
1156 }
1157 else if (group == 3) { /* locked */
1158 ok = track->flag & TRACK_LOCKED;
1159 }
1160 else if (group == 4) { /* disabled */
1161 ok = marker->flag & MARKER_DISABLED;
1162 }
1163 else if (group == 5) { /* color */
1164 const MovieTrackingTrack *act_track = tracking_object->active_track;
1165
1166 if (act_track) {
1167 ok = (track->flag & TRACK_CUSTOMCOLOR) == (act_track->flag & TRACK_CUSTOMCOLOR);
1168
1169 if (ok && track->flag & TRACK_CUSTOMCOLOR) {
1170 ok = equals_v3v3(track->color, act_track->color);
1171 }
1172 }
1173 }
1174 else if (group == 6) { /* failed */
1175 ok = (track->flag & TRACK_HAS_BUNDLE) == 0;
1176 }
1177
1178 if (ok) {
1179 track->flag |= SELECT;
1180 if (sc->flag & SC_SHOW_MARKER_PATTERN) {
1181 track->pat_flag |= SELECT;
1182 }
1183 if (sc->flag & SC_SHOW_MARKER_SEARCH) {
1184 track->search_flag |= SELECT;
1185 }
1186 }
1187 }
1188
1190
1193
1194 return OPERATOR_FINISHED;
1195}
1196
1198{
1199 static const EnumPropertyItem select_group_items[] = {
1200 {0, "KEYFRAMED", 0, "Keyframed Tracks", "Select all keyframed tracks"},
1201 {1, "ESTIMATED", 0, "Estimated Tracks", "Select all estimated tracks"},
1202 {2, "TRACKED", 0, "Tracked Tracks", "Select all tracked tracks"},
1203 {3, "LOCKED", 0, "Locked Tracks", "Select all locked tracks"},
1204 {4, "DISABLED", 0, "Disabled Tracks", "Select all disabled tracks"},
1205 {5,
1206 "COLOR",
1207 0,
1208 "Tracks with Same Color",
1209 "Select all tracks with same color as active track"},
1210 {6, "FAILED", 0, "Failed Tracks", "Select all tracks which failed to be reconstructed"},
1211 {0, nullptr, 0, nullptr, nullptr},
1212 };
1213
1214 /* identifiers */
1215 ot->name = "Select Grouped";
1216 ot->description = "Select all tracks from specified group";
1217 ot->idname = "CLIP_OT_select_grouped";
1218
1219 /* api callbacks */
1220 ot->exec = select_grouped_exec;
1222
1223 /* flags */
1224 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1225
1226 /* properties */
1227 RNA_def_enum(ot->srna,
1228 "group",
1229 select_group_items,
1231 "Action",
1232 "Clear action to execute");
1233}
SpaceClip * CTX_wm_space_clip(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
void BKE_tracking_track_deselect(struct MovieTrackingTrack *track, int area)
Definition tracking.cc:1217
void BKE_tracking_track_flag_clear(struct MovieTrackingTrack *track, int area, int flag)
Definition tracking.cc:692
#define PLANE_TRACK_VIEW_SELECTED(plane_track)
@ TRACK_AREA_POINT
@ TRACK_AREA_ALL
@ TRACK_AREA_PAT
@ TRACK_AREA_SEARCH
@ TRACK_AREA_NONE
void BKE_tracking_track_flag_set(struct MovieTrackingTrack *track, int area, int flag)
Definition tracking.cc:675
struct MovieTrackingMarker * BKE_tracking_marker_get(struct MovieTrackingTrack *track, int framenr)
Definition tracking.cc:1358
struct MovieTrackingObject * BKE_tracking_object_get_active(const struct MovieTracking *tracking)
void BKE_tracking_dopesheet_tag_update(struct MovieTracking *tracking)
Definition tracking.cc:3411
void BKE_tracking_track_select(struct ListBase *tracksbase, struct MovieTrackingTrack *track, int area, bool extend)
Definition tracking.cc:1190
@ TRACK_CLEAR_REMAINED
#define TRACK_VIEW_SELECTED(sc, track)
struct MovieTrackingPlaneMarker * BKE_tracking_plane_marker_get(struct MovieTrackingPlaneTrack *plane_track, int framenr)
Definition tracking.cc:1791
#define TRACK_AREA_SELECTED(track, area)
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_INLINE
bool BLI_lasso_is_point_inside(blender::Span< blender::int2 > mcoords, int sx, int sy, int error_value)
void BLI_lasso_boundbox(rcti *rect, blender::Span< blender::int2 > mcoords)
#define LISTBASE_FOREACH(type, var, list)
MINLINE float square_f(float a)
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
Definition math_geom.cc:289
MINLINE bool equals_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void add_v2_v2(float r[2], const float a[2])
MINLINE void add_v2_v2v2(float r[2], const float a[2], const float b[2])
bool BLI_rctf_isect_pt_v(const struct rctf *rect, const float xy[2])
bool BLI_rcti_isect_pt(const struct rcti *rect, int x, int y)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_SELECT
Definition DNA_ID.h:1068
@ SC_VIEW_CLIP
@ SC_HIDE_DISABLED
@ SC_SHOW_MARKER_SEARCH
@ SC_SHOW_MARKER_PATTERN
@ PLANE_TRACK_HIDDEN
@ TRACK_CUSTOMCOLOR
@ TRACK_HIDDEN
@ TRACK_LOCKED
@ TRACK_HAS_BUNDLE
@ MARKER_TRACKED
@ MARKER_DISABLED
#define UI_SCALE_FAC
@ OPERATOR_PASS_THROUGH
void ED_clip_view_lock_state_restore_no_jump(const bContext *C, const ClipViewLockState *state)
void ED_clip_point_stable_pos(const SpaceClip *sc, const ARegion *region, float x, float y, float *xr, float *yr)
MovieClip * ED_space_clip_get_clip(const SpaceClip *sc)
void ED_clip_mouse_pos(const SpaceClip *sc, const ARegion *region, const int mval[2], float r_co[2])
void ED_space_clip_get_size(const SpaceClip *sc, int *r_width, int *r_height)
void ED_space_clip_get_zoom(const SpaceClip *sc, const ARegion *region, float *r_zoomx, float *r_zoomy)
int ED_space_clip_get_clip_frame_number(const SpaceClip *sc)
void ED_clip_view_lock_state_store(const bContext *C, ClipViewLockState *state)
void ED_clip_select_all(const SpaceClip *sc, int action, bool *r_has_selection)
bool ED_space_clip_tracking_poll(bContext *C)
void ED_clip_point_stable_pos__reverse(const SpaceClip *sc, const ARegion *region, const float co[2], float r_co[2])
the reverse of ED_clip_point_stable_pos(), gets the marker region coords. better name here?...
eSelectOp ED_select_op_modal(eSelectOp sel_op, bool is_first)
#define SEL_OP_USE_PRE_DESELECT(sel_op)
std::string ED_select_circle_get_name(wmOperatorType *ot, PointerRNA *ptr)
@ SEL_DESELECT
eSelectOp
@ SEL_OP_SUB
Read Guarded memory(de)allocation.
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
#define C
Definition RandGen.cpp:29
#define V2D_IS_CLIPPED
Definition UI_view2d.hh:21
#define NC_GEOM
Definition WM_types.hh:360
@ OPTYPE_DEPENDS_ON_CURSOR
Definition WM_types.hh:198
@ OPTYPE_UNDO
Definition WM_types.hh:162
@ OPTYPE_REGISTER
Definition WM_types.hh:160
#define ND_DISPLAY
Definition WM_types.hh:458
#define NC_MOVIECLIP
Definition WM_types.hh:364
#define ND_SELECT
Definition WM_types.hh:474
bool is_empty() const
Definition BLI_array.hh:253
BLI_INLINE bool ED_space_clip_marker_is_visible(const SpaceClip *space_clip, const MovieTrackingObject *tracking_object, const MovieTrackingTrack *track, const MovieTrackingMarker *marker)
#define SELECT
CCL_NAMESPACE_BEGIN struct Options options
static int select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int select_exec(bContext *C, wmOperator *op)
static int select_all_exec(bContext *C, wmOperator *op)
static int box_select_exec(bContext *C, wmOperator *op)
static int clip_lasso_select_exec(bContext *C, wmOperator *op)
static int circle_select_exec(bContext *C, wmOperator *op)
ccl_device_inline float4 select(const int4 mask, const float4 a, const float4 b)
T square(const T &a)
VecBase< int32_t, 2 > int2
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
int RNA_int_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float_vector(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
#define FLT_MAX
Definition stdcycles.h:14
struct MovieTracking tracking
MovieTrackingPlaneTrack * active_plane_track
MovieTrackingTrack * active_track
MovieTrackingPlaneTrack * plane_track
MovieTrackingPlaneMarker * plane_marker
MovieTrackingMarker * marker
eTrackPickAreaDetail area_detail
MovieTrackingTrack * track
struct MovieClip * clip
PlaneTrackPick plane_track_pick
PointTrackPick point_track_pick
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
int mval[2]
Definition WM_types.hh:728
struct PointerRNA * ptr
@ TRACK_PICK_AREA_DETAIL_EDGE
@ TRACK_PICK_AREA_DETAIL_POSITION
@ TRACK_PICK_AREA_DETAIL_TILT_SIZE
@ TRACK_PICK_AREA_DETAIL_NONE
@ TRACK_PICK_AREA_DETAIL_SIZE
@ TRACK_PICK_AREA_DETAIL_OFFSET
BLI_INLINE bool ed_tracking_pick_can_slide(const SpaceClip *space_clip, const TrackingPick *pick)
BLI_INLINE TrackPickOptions ed_tracking_pick_options_defaults()
static int select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static float mouse_to_offset_distance_squared(const MovieTrackingTrack *track, const MovieTrackingMarker *marker, const float co[2], int width, int height)
static float mouse_to_closest_search_edge_distance_squared(const MovieTrackingMarker *marker, const float co[2], int width, int height)
static int select_exec(bContext *C, wmOperator *op)
static float mouse_to_slide_zone_distance_squared(const float co[2], const float slide_zone[2], int width, int height)
BLI_INLINE PlaneTrackPick plane_track_pick_make_null()
TrackingPick ed_tracking_pick_closest(const TrackPickOptions *options, bContext *C, const float co[2])
static float mouse_to_closest_pattern_edge_distance_squared(const MovieTrackingMarker *marker, const float co[2], int width, int height)
static float mouse_to_plane_slide_zone_distance_squared(const float co[2], const float slide_zone[2], int width, int height)
static int select_all_exec(bContext *C, wmOperator *op)
static float mouse_to_closest_pattern_corner_distance_squared(const MovieTrackingMarker *marker, const float co[2], int width, int height, int *r_corner)
void CLIP_OT_select_circle(wmOperatorType *ot)
void ed_tracking_deselect_all_tracks(ListBase *tracks_base)
static int box_select_exec(bContext *C, wmOperator *op)
static float mouse_to_search_corner_distance_squared(const MovieTrackingMarker *marker, const float co[2], int corner, int width, int height)
static int clip_lasso_select_exec(bContext *C, wmOperator *op)
static float mouse_to_closest_corners_edge_distance_squared(const float co[2], const float corners_offset[2], const float corners[4][2], int width, int height)
static int do_lasso_select_marker(bContext *C, const Span< int2 > mcoords, bool select)
void CLIP_OT_select_lasso(wmOperatorType *ot)
void CLIP_OT_select_all(wmOperatorType *ot)
static int circle_select_exec(bContext *C, wmOperator *op)
bool ED_clip_can_select(bContext *C)
static bool tracking_should_prefer_point_track(bContext *C, const PointTrackPick *point_track_pick, const PlaneTrackPick *plane_track_pick)
void CLIP_OT_select_box(wmOperatorType *ot)
BLI_INLINE TrackingPick tracking_pick_make_null()
static int point_inside_ellipse(const float point[2], const float offset[2], const float ellipse[2])
static int marker_inside_ellipse(const MovieTrackingMarker *marker, const float offset[2], const float ellipse[2])
bool ed_tracking_plane_track_pick_can_slide(const PlaneTrackPick *pick)
static float mouse_to_tilt_distance_squared(const MovieTrackingMarker *marker, const float co[2], int width, int height)
void CLIP_OT_select_grouped(wmOperatorType *ot)
PlaneTrackPick ed_tracking_pick_plane_track(const TrackPickOptions *options, bContext *C, const float co[2])
BLI_INLINE PointTrackPick point_track_pick_make_null()
static int select_grouped_exec(bContext *C, wmOperator *op)
void CLIP_OT_select(wmOperatorType *ot)
void ed_tracking_deselect_all_plane_tracks(ListBase *plane_tracks_base)
static void slide_marker_tilt_slider(const float marker_pos[2], const float pattern_corners[4][2], float r_slider[2])
PointTrackPick ed_tracking_pick_point_track(const TrackPickOptions *options, bContext *C, const float co[2])
bool ed_tracking_point_track_pick_can_slide(const SpaceClip *space_clip, const PointTrackPick *pick)
static void slide_marker_tilt_slider_relative(const float pattern_corners[4][2], float r_slider[2])
static bool select_poll(bContext *C)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4125
bool WM_gesture_is_modal_first(const wmGesture *gesture)
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_circle_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Array< int2 > WM_gesture_lasso_path_to_array(bContext *, wmOperator *op)
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
void WM_gesture_lasso_cancel(bContext *C, wmOperator *op)
int WM_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void WM_operator_properties_border_to_rcti(wmOperator *op, rcti *r_rect)
void WM_operator_properties_gesture_box(wmOperatorType *ot)
void WM_operator_properties_select_operation_simple(wmOperatorType *ot)
void WM_operator_properties_gesture_lasso(wmOperatorType *ot)
void WM_operator_properties_gesture_circle(wmOperatorType *ot)
void WM_operator_properties_select_all(wmOperatorType *ot)