Merge branch 'master' into blender2.8
[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_global.h"
46 #include "BKE_layer.h"
47 #include "BKE_object.h"
48 #include "BKE_report.h"
49
50 #include "DEG_depsgraph.h"
51
52 #include "WM_api.h"
53 #include "WM_types.h"
54
55 #include "ED_clip.h"
56
57 #include "RNA_access.h"
58 #include "RNA_define.h"
59
60 #include "clip_intern.h"
61
62 /********************** set origin operator *********************/
63
64 static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
65 {
66         Object *camera = scene->camera;
67
68         if (camera != NULL &&
69             BKE_object_movieclip_get(scene, camera, false) == clip)
70         {
71                 return camera;
72         }
73
74         FOREACH_SCENE_OBJECT(scene, ob)
75         {
76                 if (ob->type == OB_CAMERA) {
77                         if (BKE_object_movieclip_get(scene, ob, false) == clip) {
78                                 camera = ob;
79                                 break;
80                         }
81                 }
82         }
83         FOREACH_SCENE_OBJECT_END
84
85         return camera;
86 }
87
88 static Object *get_orientation_object(bContext *C)
89 {
90         Scene *scene = CTX_data_scene(C);
91         SceneLayer *sl = CTX_data_scene_layer(C);
92         SpaceClip *sc = CTX_wm_space_clip(C);
93         MovieClip *clip = ED_space_clip_get_clip(sc);
94         MovieTracking *tracking = &clip->tracking;
95         MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
96         Object *object = NULL;
97
98         if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
99                 object = get_camera_with_movieclip(scene, clip);
100         }
101         else {
102                 object = OBACT_NEW;
103         }
104
105         if (object != NULL && object->parent != NULL) {
106                 object = object->parent;
107         }
108
109         return object;
110 }
111
112 static int set_orientation_poll(bContext *C)
113 {
114         SpaceClip *sc = CTX_wm_space_clip(C);
115         if (sc != NULL) {
116                 SceneLayer *sl = CTX_data_scene_layer(C);
117                 MovieClip *clip = ED_space_clip_get_clip(sc);
118                 if (clip != NULL) {
119                         MovieTracking *tracking = &clip->tracking;
120                         MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
121                         if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
122                                 return true;
123                         }
124                         else {
125                                 return OBACT_NEW != NULL;
126                         }
127                 }
128         }
129         return false;
130 }
131
132 static int count_selected_bundles(bContext *C)
133 {
134         SpaceClip *sc = CTX_wm_space_clip(C);
135         MovieClip *clip = ED_space_clip_get_clip(sc);
136         ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking);
137         int tot = 0;
138         for (MovieTrackingTrack *track = tracksbase->first;
139              track != NULL;
140              track = track->next)
141         {
142                 if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_HAS_BUNDLE)) {
143                         tot++;
144                 }
145         }
146         return tot;
147 }
148
149 static void object_solver_inverted_matrix(Scene *scene,
150                                           Object *ob,
151                                           float invmat[4][4])
152 {
153         bool found = false;
154         for (bConstraint *con = ob->constraints.first;
155              con != NULL;
156              con = con->next)
157         {
158                 const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
159                 if (cti == NULL) {
160                         continue;
161                 }
162                 if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
163                         bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
164                         if (!found) {
165                                 Object *cam = data->camera ? data->camera : scene->camera;
166                                 BKE_object_where_is_calc_mat4(scene, cam, invmat);
167                         }
168                         mul_m4_m4m4(invmat, invmat, data->invmat);
169                         found = true;
170                 }
171         }
172         if (found) {
173                 invert_m4(invmat);
174         }
175         else {
176                 unit_m4(invmat);
177         }
178 }
179
180 static Object *object_solver_camera(Scene *scene, Object *ob)
181 {
182         for (bConstraint *con = ob->constraints.first;
183              con != NULL;
184              con = con->next)
185         {
186                 const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
187                 if (cti == NULL) {
188                         continue;
189                 }
190                 if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
191                         bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
192                         return (data->camera != NULL) ? data->camera : scene->camera;
193                 }
194         }
195         return NULL;
196 }
197
198 static int set_origin_exec(bContext *C, wmOperator *op)
199 {
200         SpaceClip *sc = CTX_wm_space_clip(C);
201         MovieClip *clip = ED_space_clip_get_clip(sc);
202         MovieTracking *tracking = &clip->tracking;
203         Scene *scene = CTX_data_scene(C);
204         Object *camera = get_camera_with_movieclip(scene, clip);
205         int selected_count = count_selected_bundles(C);
206
207         if (selected_count == 0) {
208                 BKE_report(op->reports,
209                            RPT_ERROR,
210                            "At least one track with bundle should be selected to "
211                            "define origin position");
212
213                 return OPERATOR_CANCELLED;
214         }
215
216         Object *object = get_orientation_object(C);
217         if (object == NULL) {
218                 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
219                 return OPERATOR_CANCELLED;
220         }
221
222         MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
223         ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
224
225         float median[3] = {0.0f, 0.0f, 0.0f};
226         zero_v3(median);
227         for (MovieTrackingTrack *track = tracksbase->first;
228              track != NULL;
229              track = track->next)
230         {
231                 if (TRACK_VIEW_SELECTED(sc, track) &&
232                     (track->flag & TRACK_HAS_BUNDLE))
233                 {
234                         add_v3_v3(median, track->bundle_pos);
235                 }
236         }
237         mul_v3_fl(median, 1.0f / selected_count);
238
239         float mat[4][4], vec[3];
240         BKE_tracking_get_camera_object_matrix(scene, camera, mat);
241         mul_v3_m4v3(vec, mat, median);
242
243         if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
244                 sub_v3_v3(object->loc, vec);
245         }
246         else {
247                 object_solver_inverted_matrix(scene, object, mat);
248                 mul_v3_m4v3(vec, mat, vec);
249                 copy_v3_v3(object->loc, vec);
250         }
251
252         DEG_id_tag_update(&clip->id, 0);
253         DEG_id_tag_update(&object->id, OB_RECALC_OB);
254
255         WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
256         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
257
258         return OPERATOR_FINISHED;
259 }
260
261 void CLIP_OT_set_origin(wmOperatorType *ot)
262 {
263         /* identifiers */
264         ot->name = "Set Origin";
265         ot->description = "Set active marker as origin by moving camera (or its parent if present) in 3D space";
266         ot->idname = "CLIP_OT_set_origin";
267
268         /* api callbacks */
269         ot->exec = set_origin_exec;
270         ot->poll = set_orientation_poll;
271
272         /* flags */
273         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
274
275         /* properties */
276         RNA_def_boolean(ot->srna, "use_median", 0, "Use Median",
277                         "Set origin to median point of selected bundles");
278 }
279
280 /********************** set floor operator *********************/
281
282 static void set_axis(Scene *scene,
283                      Object *ob,
284                      MovieClip *clip,
285                      MovieTrackingObject *tracking_object,
286                      MovieTrackingTrack *track,
287                      char axis)
288 {
289         Object *camera = get_camera_with_movieclip(scene, clip);
290         const bool is_camera = (tracking_object->flag & TRACKING_OBJECT_CAMERA) != 0;
291         bool flip = false;
292         float mat[4][4], vec[3], obmat[4][4], dvec[3];
293
294         BKE_object_to_mat4(ob, obmat);
295
296         BKE_tracking_get_camera_object_matrix(scene, camera, mat);
297         mul_v3_m4v3(vec, mat, track->bundle_pos);
298         copy_v3_v3(dvec, vec);
299
300         if (!is_camera) {
301                 float imat[4][4];
302
303                 object_solver_inverted_matrix(scene, ob, imat);
304                 mul_v3_m4v3(vec, imat, vec);
305
306                 invert_m4_m4(imat, obmat);
307                 mul_v3_m4v3(dvec, imat, vec);
308
309                 sub_v3_v3(vec, obmat[3]);
310         }
311
312         if (len_squared_v2(vec) < (1e-3f * 1e-3f)) {
313                 return;
314         }
315
316         unit_m4(mat);
317
318         if (axis == 'X') {
319                 if (fabsf(dvec[1]) < 1e-3f) {
320                         flip = true;
321
322                         mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f;
323                         mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f;
324                         mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
325                 }
326                 else {
327                         copy_v3_v3(mat[0], vec);
328
329                         if (is_camera || fabsf(vec[2]) < 1e-3f) {
330                                 mat[0][2] = 0.0f;
331                                 mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
332                                 cross_v3_v3v3(mat[1], mat[2], mat[0]);
333                         }
334                         else {
335                                 vec[2] = 0.0f;
336
337                                 cross_v3_v3v3(mat[1], mat[0], vec);
338                                 cross_v3_v3v3(mat[2], mat[0], mat[1]);
339                         }
340                 }
341         }
342         else {
343                 if (fabsf(dvec[0]) < 1e-3f) {
344                         flip = true;
345
346                         mat[0][0] = -1.0f; mat[0][1] = 0.0f; mat[0][2] = 0.0f;
347                         mat[1][0] = 0.0f; mat[1][1] = -1.0f; mat[1][2] = 0.0f;
348                         mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
349                 }
350                 else {
351                         copy_v3_v3(mat[1], vec);
352
353                         if (is_camera || fabsf(vec[2]) < 1e-3f) {
354                                 mat[1][2] = 0.0f;
355                                 mat[2][0] = 0.0f; mat[2][1] = 0.0f; mat[2][2] = 1.0f;
356                                 cross_v3_v3v3(mat[0], mat[1], mat[2]);
357                         }
358                         else {
359                                 vec[2] = 0.0f;
360
361                                 cross_v3_v3v3(mat[0], vec, mat[1]);
362                                 cross_v3_v3v3(mat[2], mat[0], mat[1]);
363                         }
364                 }
365         }
366
367         normalize_v3(mat[0]);
368         normalize_v3(mat[1]);
369         normalize_v3(mat[2]);
370
371         if (is_camera) {
372                 invert_m4(mat);
373
374                 mul_m4_m4m4(mat, mat, obmat);
375         }
376         else {
377                 if (!flip) {
378                         float lmat[4][4], ilmat[4][4], rmat[3][3];
379
380                         BKE_object_rot_to_mat3(ob, rmat, true);
381                         invert_m3(rmat);
382                         mul_m4_m4m3(mat, mat, rmat);
383
384                         unit_m4(lmat);
385                         copy_v3_v3(lmat[3], obmat[3]);
386                         invert_m4_m4(ilmat, lmat);
387
388                         mul_m4_series(mat, lmat, mat, ilmat, obmat);
389                 }
390                 else {
391                         mul_m4_m4m4(mat, obmat, mat);
392                 }
393         }
394
395         BKE_object_apply_mat4(ob, mat, 0, 0);
396 }
397
398 static int set_plane_exec(bContext *C, wmOperator *op)
399 {
400         SpaceClip *sc = CTX_wm_space_clip(C);
401         MovieClip *clip = ED_space_clip_get_clip(sc);
402         Scene *scene = CTX_data_scene(C);
403         MovieTracking *tracking = &clip->tracking;
404         MovieTrackingObject *tracking_object;
405         MovieTrackingTrack *track, *axis_track = NULL, *act_track;
406         ListBase *tracksbase;
407         Object *object;
408         Object *camera = get_camera_with_movieclip(scene, clip);
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(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 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 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 }