Depsgraph: remove EvaluationContext, pass Depsgraph instead.
[blender.git] / source / blender / editors / space_clip / tracking_ops_orient.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2016 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation,
23  *                 Sergey Sharybin
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_clip/tracking_ops_orient.c
29  *  \ingroup spclip
30  */
31
32 #include "MEM_guardedalloc.h"
33
34 #include "DNA_constraint_types.h"
35 #include "DNA_object_types.h"   /* SELECT */
36 #include "DNA_screen_types.h"
37 #include "DNA_space_types.h"
38
39 #include "BLI_utildefines.h"
40 #include "BLI_math.h"
41
42 #include "BKE_context.h"
43 #include "BKE_constraint.h"
44 #include "BKE_tracking.h"
45 #include "BKE_layer.h"
46 #include "BKE_object.h"
47 #include "BKE_report.h"
48
49 #include "DEG_depsgraph.h"
50
51 #include "WM_api.h"
52 #include "WM_types.h"
53
54 #include "ED_clip.h"
55
56 #include "RNA_access.h"
57 #include "RNA_define.h"
58
59 #include "clip_intern.h"
60
61 /********************** set origin operator *********************/
62
63 static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
64 {
65         Object *camera = scene->camera;
66
67         if (camera != NULL &&
68             BKE_object_movieclip_get(scene, camera, false) == clip)
69         {
70                 return camera;
71         }
72
73         FOREACH_SCENE_OBJECT_BEGIN(scene, ob)
74         {
75                 if (ob->type == OB_CAMERA) {
76                         if (BKE_object_movieclip_get(scene, ob, false) == clip) {
77                                 camera = ob;
78                                 break;
79                         }
80                 }
81         }
82         FOREACH_SCENE_OBJECT_END;
83
84         return camera;
85 }
86
87 static Object *get_orientation_object(bContext *C)
88 {
89         Scene *scene = CTX_data_scene(C);
90         ViewLayer *view_layer = CTX_data_view_layer(C);
91         SpaceClip *sc = CTX_wm_space_clip(C);
92         MovieClip *clip = ED_space_clip_get_clip(sc);
93         MovieTracking *tracking = &clip->tracking;
94         MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
95         Object *object = NULL;
96
97         if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
98                 object = get_camera_with_movieclip(scene, clip);
99         }
100         else {
101                 object = OBACT(view_layer);
102         }
103
104         if (object != NULL && object->parent != NULL) {
105                 object = object->parent;
106         }
107
108         return object;
109 }
110
111 static int set_orientation_poll(bContext *C)
112 {
113         SpaceClip *sc = CTX_wm_space_clip(C);
114         if (sc != NULL) {
115                 ViewLayer *view_layer = CTX_data_view_layer(C);
116                 MovieClip *clip = ED_space_clip_get_clip(sc);
117                 if (clip != NULL) {
118                         MovieTracking *tracking = &clip->tracking;
119                         MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
120                         if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
121                                 return true;
122                         }
123                         else {
124                                 return OBACT(view_layer) != NULL;
125                         }
126                 }
127         }
128         return false;
129 }
130
131 static int count_selected_bundles(bContext *C)
132 {
133         SpaceClip *sc = CTX_wm_space_clip(C);
134         MovieClip *clip = ED_space_clip_get_clip(sc);
135         ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
136         int tot = 0;
137         for (MovieTrackingTrack *track = tracksbase->first;
138              track != NULL;
139              track = track->next)
140         {
141                 if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_HAS_BUNDLE)) {
142                         tot++;
143                 }
144         }
145         return tot;
146 }
147
148 static void object_solver_inverted_matrix(Scene *scene,
149                                           Object *ob,
150                                           float invmat[4][4])
151 {
152         bool found = false;
153         for (bConstraint *con = ob->constraints.first;
154              con != NULL;
155              con = con->next)
156         {
157                 const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
158                 if (cti == NULL) {
159                         continue;
160                 }
161                 if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
162                         bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
163                         if (!found) {
164                                 Object *cam = data->camera ? data->camera : scene->camera;
165                                 BKE_object_where_is_calc_mat4(scene, cam, invmat);
166                         }
167                         mul_m4_m4m4(invmat, invmat, data->invmat);
168                         found = true;
169                 }
170         }
171         if (found) {
172                 invert_m4(invmat);
173         }
174         else {
175                 unit_m4(invmat);
176         }
177 }
178
179 static Object *object_solver_camera(Scene *scene, Object *ob)
180 {
181         for (bConstraint *con = ob->constraints.first;
182              con != NULL;
183              con = con->next)
184         {
185                 const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
186                 if (cti == NULL) {
187                         continue;
188                 }
189                 if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
190                         bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
191                         return (data->camera != NULL) ? data->camera : scene->camera;
192                 }
193         }
194         return NULL;
195 }
196
197 static int set_origin_exec(bContext *C, wmOperator *op)
198 {
199         SpaceClip *sc = CTX_wm_space_clip(C);
200         MovieClip *clip = ED_space_clip_get_clip(sc);
201         MovieTracking *tracking = &clip->tracking;
202         Scene *scene = CTX_data_scene(C);
203         Object *camera = get_camera_with_movieclip(scene, clip);
204         int selected_count = count_selected_bundles(C);
205
206         if (selected_count == 0) {
207                 BKE_report(op->reports,
208                            RPT_ERROR,
209                            "At least one track with bundle should be selected to "
210                            "define origin position");
211
212                 return OPERATOR_CANCELLED;
213         }
214
215         Object *object = get_orientation_object(C);
216         if (object == NULL) {
217                 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
218                 return OPERATOR_CANCELLED;
219         }
220
221         MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
222         ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
223
224         float median[3] = {0.0f, 0.0f, 0.0f};
225         zero_v3(median);
226         for (MovieTrackingTrack *track = tracksbase->first;
227              track != NULL;
228              track = track->next)
229         {
230                 if (TRACK_VIEW_SELECTED(sc, track) &&
231                     (track->flag & TRACK_HAS_BUNDLE))
232                 {
233                         add_v3_v3(median, track->bundle_pos);
234                 }
235         }
236         mul_v3_fl(median, 1.0f / selected_count);
237
238         float mat[4][4], vec[3];
239         BKE_tracking_get_camera_object_matrix(scene, camera, mat);
240         mul_v3_m4v3(vec, mat, median);
241
242         if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
243                 sub_v3_v3(object->loc, vec);
244         }
245         else {
246                 object_solver_inverted_matrix(scene, object, mat);
247                 mul_v3_m4v3(vec, mat, vec);
248                 copy_v3_v3(object->loc, vec);
249         }
250
251         DEG_id_tag_update(&clip->id, 0);
252         DEG_id_tag_update(&object->id, OB_RECALC_OB);
253
254         WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
255         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
256
257         return OPERATOR_FINISHED;
258 }
259
260 void CLIP_OT_set_origin(wmOperatorType *ot)
261 {
262         /* identifiers */
263         ot->name = "Set Origin";
264         ot->description = "Set active marker as origin by moving camera (or its parent if present) in 3D space";
265         ot->idname = "CLIP_OT_set_origin";
266
267         /* api callbacks */
268         ot->exec = set_origin_exec;
269         ot->poll = set_orientation_poll;
270
271         /* flags */
272         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
273
274         /* properties */
275         RNA_def_boolean(ot->srna, "use_median", 0, "Use Median",
276                         "Set origin to median point of selected bundles");
277 }
278
279 /********************** set floor operator *********************/
280
281 static void set_axis(Scene *scene,
282                      Object *ob,
283                      MovieClip *clip,
284                      MovieTrackingObject *tracking_object,
285                      MovieTrackingTrack *track,
286                      char axis)
287 {
288         Object *camera = get_camera_with_movieclip(scene, clip);
289         const bool is_camera = (tracking_object->flag & TRACKING_OBJECT_CAMERA) != 0;
290         bool flip = false;
291         float mat[4][4], vec[3], obmat[4][4], dvec[3];
292
293         BKE_object_to_mat4(ob, obmat);
294
295         BKE_tracking_get_camera_object_matrix(scene, camera, mat);
296         mul_v3_m4v3(vec, mat, track->bundle_pos);
297         copy_v3_v3(dvec, vec);
298
299         if (!is_camera) {
300                 float imat[4][4];
301
302                 object_solver_inverted_matrix(scene, ob, imat);
303                 mul_v3_m4v3(vec, imat, vec);
304
305                 invert_m4_m4(imat, obmat);
306                 mul_v3_m4v3(dvec, imat, vec);
307
308                 sub_v3_v3(vec, obmat[3]);
309         }
310
311         if (len_squared_v2(vec) < (1e-3f * 1e-3f)) {
312                 return;
313         }
314
315         unit_m4(mat);
316
317         if (axis == 'X') {
318                 if (fabsf(dvec[1]) < 1e-3f) {
319                         flip = true;
320
321                         mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f;
322                         mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f;
323                         mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
324                 }
325                 else {
326                         copy_v3_v3(mat[0], vec);
327
328                         if (is_camera || fabsf(vec[2]) < 1e-3f) {
329                                 mat[0][2] = 0.0f;
330                                 mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
331                                 cross_v3_v3v3(mat[1], mat[2], mat[0]);
332                         }
333                         else {
334                                 vec[2] = 0.0f;
335
336                                 cross_v3_v3v3(mat[1], mat[0], vec);
337                                 cross_v3_v3v3(mat[2], mat[0], mat[1]);
338                         }
339                 }
340         }
341         else {
342                 if (fabsf(dvec[0]) < 1e-3f) {
343                         flip = true;
344
345                         mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f;
346                         mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f;
347                         mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
348                 }
349                 else {
350                         copy_v3_v3(mat[1], vec);
351
352                         if (is_camera || fabsf(vec[2]) < 1e-3f) {
353                                 mat[1][2] = 0.0f;
354                                 mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
355                                 cross_v3_v3v3(mat[0], mat[1], mat[2]);
356                         }
357                         else {
358                                 vec[2] = 0.0f;
359
360                                 cross_v3_v3v3(mat[0], vec, mat[1]);
361                                 cross_v3_v3v3(mat[2], mat[0], mat[1]);
362                         }
363                 }
364         }
365
366         normalize_v3(mat[0]);
367         normalize_v3(mat[1]);
368         normalize_v3(mat[2]);
369
370         if (is_camera) {
371                 invert_m4(mat);
372
373                 mul_m4_m4m4(mat, mat, obmat);
374         }
375         else {
376                 if (!flip) {
377                         float lmat[4][4], ilmat[4][4], rmat[3][3];
378
379                         BKE_object_rot_to_mat3(ob, rmat, true);
380                         invert_m3(rmat);
381                         mul_m4_m4m3(mat, mat, rmat);
382
383                         unit_m4(lmat);
384                         copy_v3_v3(lmat[3], obmat[3]);
385                         invert_m4_m4(ilmat, lmat);
386
387                         mul_m4_series(mat, lmat, mat, ilmat, obmat);
388                 }
389                 else {
390                         mul_m4_m4m4(mat, obmat, mat);
391                 }
392         }
393
394         BKE_object_apply_mat4(ob, mat, 0, 0);
395 }
396
397 static int set_plane_exec(bContext *C, wmOperator *op)
398 {
399         SpaceClip *sc = CTX_wm_space_clip(C);
400         MovieClip *clip = ED_space_clip_get_clip(sc);
401         Scene *scene = CTX_data_scene(C);
402         MovieTracking *tracking = &clip->tracking;
403         MovieTrackingObject *tracking_object;
404         MovieTrackingTrack *track, *axis_track = NULL, *act_track;
405         ListBase *tracksbase;
406         Object *object;
407         Object *camera = get_camera_with_movieclip(scene, clip);
408         Depsgraph *depsgraph = CTX_data_depsgraph(C);
409         int tot = 0;
410         float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3] = {0.0f, 0.0f, 0.0f};
411         int plane = RNA_enum_get(op->ptr, "plane");
412         float rot[4][4] = {{0.0f, 0.0f, -1.0f, 0.0f},
413                            {0.0f, 1.0f, 0.0f, 0.0f},
414                            {1.0f, 0.0f, 0.0f, 0.0f},
415                            {0.0f, 0.0f, 0.0f, 1.0f}};  /* 90 degrees Y-axis rotation matrix */
416
417         if (count_selected_bundles(C) != 3) {
418                 BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");
419
420                 return OPERATOR_CANCELLED;
421         }
422
423         tracking_object = BKE_tracking_object_get_active(tracking);
424         tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
425         act_track = BKE_tracking_track_get_active(tracking);
426
427         object = get_orientation_object(C);
428         if (object == NULL) {
429                 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
430                 return OPERATOR_CANCELLED;
431         }
432
433         BKE_tracking_get_camera_object_matrix(scene, camera, mat);
434
435         /* Get 3 bundles to use as reference. */
436         track = tracksbase->first;
437         while (track && tot < 3) {
438                 if (track->flag & TRACK_HAS_BUNDLE && TRACK_VIEW_SELECTED(sc, track)) {
439                         mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
440                         if (tot == 0 || track == act_track) {
441                                 copy_v3_v3(orig, vec[tot]);
442                         }
443                         else {
444                                 axis_track = track;
445                         }
446                         tot++;
447                 }
448                 track = track->next;
449         }
450
451         sub_v3_v3(vec[1], vec[0]);
452         sub_v3_v3(vec[2], vec[0]);
453
454         /* Construct ortho-normal basis. */
455         unit_m4(mat);
456         if (plane == 0) { /* floor */
457                 cross_v3_v3v3(mat[0], vec[1], vec[2]);
458                 copy_v3_v3(mat[1], vec[1]);
459                 cross_v3_v3v3(mat[2], mat[0], mat[1]);
460         }
461         else if (plane == 1) { /* wall */
462                 cross_v3_v3v3(mat[2], vec[1], vec[2]);
463                 copy_v3_v3(mat[1], vec[1]);
464                 cross_v3_v3v3(mat[0], mat[1], mat[2]);
465         }
466
467         normalize_v3(mat[0]);
468         normalize_v3(mat[1]);
469         normalize_v3(mat[2]);
470
471         /* Move to origin point. */
472         mat[3][0] = orig[0];
473         mat[3][1] = orig[1];
474         mat[3][2] = orig[2];
475
476         if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
477                 invert_m4(mat);
478
479                 BKE_object_to_mat4(object, obmat);
480                 mul_m4_m4m4(mat, mat, obmat);
481                 mul_m4_m4m4(newmat, rot, mat);
482                 BKE_object_apply_mat4(object, newmat, 0, 0);
483
484                 /* Make camera have positive z-coordinate. */
485                 if (object->loc[2] < 0) {
486                         invert_m4(rot);
487                         mul_m4_m4m4(newmat, rot, mat);
488                         BKE_object_apply_mat4(object, newmat, 0, 0);
489                 }
490         }
491         else {
492                 BKE_object_apply_mat4(object, mat, 0, 0);
493         }
494
495         BKE_object_where_is_calc(depsgraph, scene, object);
496         set_axis(scene, object, clip, tracking_object, axis_track, 'X');
497
498         DEG_id_tag_update(&clip->id, 0);
499         DEG_id_tag_update(&object->id, OB_RECALC_OB);
500
501         WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
502         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
503
504         return OPERATOR_FINISHED;
505 }
506
507 void CLIP_OT_set_plane(wmOperatorType *ot)
508 {
509         static const EnumPropertyItem plane_items[] = {
510                 {0, "FLOOR", 0, "Floor", "Set floor plane"},
511                 {1, "WALL", 0, "Wall", "Set wall plane"},
512                 {0, NULL, 0, NULL, NULL}
513         };
514
515         /* identifiers */
516         ot->name = "Set Plane";
517         ot->description = "Set plane based on 3 selected bundles by moving camera "
518                           "(or its parent if present) in 3D space";
519         ot->idname = "CLIP_OT_set_plane";
520
521         /* api callbacks */
522         ot->exec = set_plane_exec;
523         ot->poll = set_orientation_poll;
524
525         /* flags */
526         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
527
528         /* properties */
529         RNA_def_enum(ot->srna, "plane", plane_items, 0, "Plane",
530                      "Plane to be used for orientation");
531 }
532
533 /********************** set axis operator *********************/
534
535 static int set_axis_exec(bContext *C, wmOperator *op)
536 {
537         SpaceClip *sc = CTX_wm_space_clip(C);
538         MovieClip *clip = ED_space_clip_get_clip(sc);
539         MovieTracking *tracking = &clip->tracking;
540         MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
541         Scene *scene = CTX_data_scene(C);
542         Object *object;
543         int axis = RNA_enum_get(op->ptr, "axis");
544
545         if (count_selected_bundles(C) != 1) {
546                 BKE_report(op->reports,
547                            RPT_ERROR,
548                            "Single track with bundle should be selected to define axis");
549                 return OPERATOR_CANCELLED;
550         }
551
552         object = get_orientation_object(C);
553         if (object == NULL) {
554                 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
555                 return OPERATOR_CANCELLED;
556         }
557
558         ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking,
559                                                               tracking_object);
560         MovieTrackingTrack *track = tracksbase->first;
561         while (track) {
562                 if (TRACK_VIEW_SELECTED(sc, track) &&
563                     (track->flag & TRACK_HAS_BUNDLE))
564                 {
565                         break;
566                 }
567                 track = track->next;
568         }
569
570         set_axis(scene, object, clip, tracking_object, track, axis == 0 ? 'X' : 'Y');
571
572         DEG_id_tag_update(&clip->id, 0);
573         DEG_id_tag_update(&object->id, OB_RECALC_OB);
574
575         WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
576         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
577
578         return OPERATOR_FINISHED;
579 }
580
581 void CLIP_OT_set_axis(wmOperatorType *ot)
582 {
583         static const EnumPropertyItem axis_actions[] = {
584                 {0, "X", 0, "X", "Align bundle align X axis"},
585                 {1, "Y", 0, "Y", "Align bundle align Y axis"},
586                 {0, NULL, 0, NULL, NULL}
587         };
588
589         /* identifiers */
590         ot->name = "Set Axis";
591         ot->description = "Set direction of scene axis rotating camera "
592                           "(or its parent if present) and assume selected track "
593                           "lies on real axis, joining it with the origin";
594         ot->idname = "CLIP_OT_set_axis";
595
596         /* api callbacks */
597         ot->exec = set_axis_exec;
598         ot->poll = set_orientation_poll;
599
600         /* flags */
601         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
602
603         /* properties */
604         RNA_def_enum(ot->srna, "axis", axis_actions, 0, "Axis",
605                      "Axis to use to align bundle along");
606 }
607
608 /********************** set scale operator *********************/
609
610 static int do_set_scale(bContext *C,
611                         wmOperator *op,
612                         bool scale_solution,
613                         bool apply_scale)
614 {
615         SpaceClip *sc = CTX_wm_space_clip(C);
616         MovieClip *clip = ED_space_clip_get_clip(sc);
617         MovieTracking *tracking = &clip->tracking;
618         MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
619         MovieTrackingTrack *track;
620         Scene *scene = CTX_data_scene(C);
621         Object *object = NULL;
622         Object *camera = get_camera_with_movieclip(scene, clip);
623         ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
624         int tot = 0;
625         float vec[2][3], mat[4][4], scale;
626         float dist = RNA_float_get(op->ptr, "distance");
627
628         if (count_selected_bundles(C) != 2) {
629                 BKE_report(op->reports,
630                            RPT_ERROR,
631                            "Two tracks with bundles should be selected to set scale");
632                 return OPERATOR_CANCELLED;
633         }
634
635         if (!scale_solution && !apply_scale) {
636                 object = get_orientation_object(C);
637                 if (object == NULL) {
638                         BKE_report(op->reports,
639                                    RPT_ERROR,
640                                    "No object to apply orientation on");
641                         return OPERATOR_CANCELLED;
642                 }
643         }
644
645         BKE_tracking_get_camera_object_matrix(scene, camera, mat);
646
647         track = tracksbase->first;
648         while (track) {
649                 if (TRACK_VIEW_SELECTED(sc, track)) {
650                         mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
651                         tot++;
652                 }
653                 track = track->next;
654         }
655
656         sub_v3_v3(vec[0], vec[1]);
657
658         if (len_v3(vec[0]) > 1e-5f) {
659                 scale = dist / len_v3(vec[0]);
660                 if (apply_scale) {
661                         /* Apply scale on reconstructed scene itself. */
662                         MovieTrackingReconstruction *reconstruction =
663                                 BKE_tracking_get_active_reconstruction(tracking);
664                         MovieReconstructedCamera *reconstructed_cameras;
665                         int i;
666
667                         for (track = tracksbase->first; track; track = track->next) {
668                                 mul_v3_fl(track->bundle_pos, scale);
669                         }
670
671                         reconstructed_cameras = reconstruction->cameras;
672                         for (i = 0; i < reconstruction->camnr; i++) {
673                                 mul_v3_fl(reconstructed_cameras[i].mat[3], scale);
674                         }
675
676                         WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
677                         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
678                 }
679                 else {
680                         if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
681                                 mul_v3_fl(object->size, scale);
682                                 mul_v3_fl(object->loc, scale);
683                         }
684                         else if (!scale_solution) {
685                                 Object *solver_camera = object_solver_camera(scene, object);
686
687                                 object->size[0] = object->size[1] = object->size[2] = 1.0f / scale;
688
689                                 if (solver_camera) {
690                                         object->size[0] /= solver_camera->size[0];
691                                         object->size[1] /= solver_camera->size[1];
692                                         object->size[2] /= solver_camera->size[2];
693                                 }
694                         }
695                         else {
696                                 tracking_object->scale = scale;
697                         }
698
699                         DEG_id_tag_update(&clip->id, 0);
700
701                         if (object)
702                                 DEG_id_tag_update(&object->id, OB_RECALC_OB);
703
704                         WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
705                         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
706                 }
707         }
708
709         return OPERATOR_FINISHED;
710 }
711
712 static int set_scale_exec(bContext *C, wmOperator *op)
713 {
714         return do_set_scale(C, op, false, false);
715 }
716
717 static int set_scale_invoke(bContext *C,
718                             wmOperator *op,
719                             const wmEvent *UNUSED(event))
720 {
721         SpaceClip *sc = CTX_wm_space_clip(C);
722         MovieClip *clip = ED_space_clip_get_clip(sc);
723
724         if (!RNA_struct_property_is_set(op->ptr, "distance"))
725                 RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
726
727         return set_scale_exec(C, op);
728 }
729
730 void CLIP_OT_set_scale(wmOperatorType *ot)
731 {
732         /* identifiers */
733         ot->name = "Set Scale";
734         ot->description = "Set scale of scene by scaling camera (or its parent if present)";
735         ot->idname = "CLIP_OT_set_scale";
736
737         /* api callbacks */
738         ot->exec = set_scale_exec;
739         ot->invoke = set_scale_invoke;
740         ot->poll = set_orientation_poll;
741
742         /* flags */
743         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
744
745         /* properties */
746         RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
747                       "Distance", "Distance between selected tracks", -100.0f, 100.0f);
748 }
749
750 /********************** set solution scale operator *********************/
751
752 static int set_solution_scale_poll(bContext *C)
753 {
754         SpaceClip *sc = CTX_wm_space_clip(C);
755         if (sc != NULL) {
756                 MovieClip *clip = ED_space_clip_get_clip(sc);
757                 if (clip != NULL) {
758                         MovieTracking *tracking = &clip->tracking;
759                         MovieTrackingObject *tracking_object =
760                                 BKE_tracking_object_get_active(tracking);
761                         return (tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0;
762                 }
763         }
764         return false;
765 }
766
767 static int set_solution_scale_exec(bContext *C, wmOperator *op)
768 {
769         return do_set_scale(C, op, true, false);
770 }
771
772 static int set_solution_scale_invoke(bContext *C,
773                                      wmOperator *op,
774                                      const wmEvent *UNUSED(event))
775 {
776         SpaceClip *sc = CTX_wm_space_clip(C);
777         MovieClip *clip = ED_space_clip_get_clip(sc);
778
779         if (!RNA_struct_property_is_set(op->ptr, "distance")) {
780                 RNA_float_set(op->ptr,
781                               "distance",
782                               clip->tracking.settings.object_distance);
783         }
784
785         return set_solution_scale_exec(C, op);
786 }
787
788 void CLIP_OT_set_solution_scale(wmOperatorType *ot)
789 {
790         /* identifiers */
791         ot->name = "Set Solution Scale";
792         ot->description = "Set object solution scale using distance between "
793                           "two selected tracks";
794         ot->idname = "CLIP_OT_set_solution_scale";
795
796         /* api callbacks */
797         ot->exec = set_solution_scale_exec;
798         ot->invoke = set_solution_scale_invoke;
799         ot->poll = set_solution_scale_poll;
800
801         /* flags */
802         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
803
804         /* properties */
805         RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
806                       "Distance", "Distance between selected tracks",
807                       -100.0f, 100.0f);
808 }
809
810 /********************** apply solution scale operator *********************/
811
812 static int apply_solution_scale_poll(bContext *C)
813 {
814         SpaceClip *sc = CTX_wm_space_clip(C);
815         if (sc != NULL) {
816                 MovieClip *clip = ED_space_clip_get_clip(sc);
817                 if (clip != NULL) {
818                         MovieTracking *tracking = &clip->tracking;
819                         MovieTrackingObject *tracking_object =
820                                 BKE_tracking_object_get_active(tracking);
821                         return (tracking_object->flag & TRACKING_OBJECT_CAMERA) != 0;
822                 }
823         }
824         return 0;
825 }
826
827 static int apply_solution_scale_exec(bContext *C, wmOperator *op)
828 {
829         return do_set_scale(C, op, false, true);
830 }
831
832 static int apply_solution_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
833 {
834         SpaceClip *sc = CTX_wm_space_clip(C);
835         MovieClip *clip = ED_space_clip_get_clip(sc);
836         if (!RNA_struct_property_is_set(op->ptr, "distance")) {
837                 RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
838         }
839         return apply_solution_scale_exec(C, op);
840 }
841
842 void CLIP_OT_apply_solution_scale(wmOperatorType *ot)
843 {
844         /* identifiers */
845         ot->name = "Apply Solution Scale";
846         ot->description = "Apply scale on solution itself to make distance between "
847                           "selected tracks equals to desired";
848         ot->idname = "CLIP_OT_apply_solution_scale";
849
850         /* api callbacks */
851         ot->exec = apply_solution_scale_exec;
852         ot->invoke = apply_solution_scale_invoke;
853         ot->poll = apply_solution_scale_poll;
854
855         /* flags */
856         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
857
858         /* properties */
859         RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
860                       "Distance", "Distance between selected tracks",
861                       -100.0f, 100.0f);
862 }