Pass EvaluationContext argument everywhere
[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         EvaluationContext eval_ctx;
410         int tot = 0;
411         float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3] = {0.0f, 0.0f, 0.0f};
412         int plane = RNA_enum_get(op->ptr, "plane");
413         float rot[4][4] = {{0.0f, 0.0f, -1.0f, 0.0f},
414                            {0.0f, 1.0f, 0.0f, 0.0f},
415                            {1.0f, 0.0f, 0.0f, 0.0f},
416                            {0.0f, 0.0f, 0.0f, 1.0f}};  /* 90 degrees Y-axis rotation matrix */
417
418         if (count_selected_bundles(C) != 3) {
419                 BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");
420
421                 return OPERATOR_CANCELLED;
422         }
423
424         tracking_object = BKE_tracking_object_get_active(tracking);
425         tracksbase = BKE_tracking_object_get_tracks(tracking, tracking_object);
426         act_track = BKE_tracking_track_get_active(tracking);
427
428         object = get_orientation_object(C);
429         if (object == NULL) {
430                 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
431                 return OPERATOR_CANCELLED;
432         }
433
434         CTX_data_eval_ctx(C, &eval_ctx);
435
436         BKE_tracking_get_camera_object_matrix(scene, camera, mat);
437
438         /* Get 3 bundles to use as reference. */
439         track = tracksbase->first;
440         while (track && tot < 3) {
441                 if (track->flag & TRACK_HAS_BUNDLE && TRACK_VIEW_SELECTED(sc, track)) {
442                         mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
443                         if (tot == 0 || track == act_track) {
444                                 copy_v3_v3(orig, vec[tot]);
445                         }
446                         else {
447                                 axis_track = track;
448                         }
449                         tot++;
450                 }
451                 track = track->next;
452         }
453
454         sub_v3_v3(vec[1], vec[0]);
455         sub_v3_v3(vec[2], vec[0]);
456
457         /* Construct ortho-normal basis. */
458         unit_m4(mat);
459         if (plane == 0) { /* floor */
460                 cross_v3_v3v3(mat[0], vec[1], vec[2]);
461                 copy_v3_v3(mat[1], vec[1]);
462                 cross_v3_v3v3(mat[2], mat[0], mat[1]);
463         }
464         else if (plane == 1) { /* wall */
465                 cross_v3_v3v3(mat[2], vec[1], vec[2]);
466                 copy_v3_v3(mat[1], vec[1]);
467                 cross_v3_v3v3(mat[0], mat[1], mat[2]);
468         }
469
470         normalize_v3(mat[0]);
471         normalize_v3(mat[1]);
472         normalize_v3(mat[2]);
473
474         /* Move to origin point. */
475         mat[3][0] = orig[0];
476         mat[3][1] = orig[1];
477         mat[3][2] = orig[2];
478
479         if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
480                 invert_m4(mat);
481
482                 BKE_object_to_mat4(object, obmat);
483                 mul_m4_m4m4(mat, mat, obmat);
484                 mul_m4_m4m4(newmat, rot, mat);
485                 BKE_object_apply_mat4(object, newmat, 0, 0);
486
487                 /* Make camera have positive z-coordinate. */
488                 if (object->loc[2] < 0) {
489                         invert_m4(rot);
490                         mul_m4_m4m4(newmat, rot, mat);
491                         BKE_object_apply_mat4(object, newmat, 0, 0);
492                 }
493         }
494         else {
495                 BKE_object_apply_mat4(object, mat, 0, 0);
496         }
497
498         BKE_object_where_is_calc(&eval_ctx, scene, object);
499         set_axis(scene, object, clip, tracking_object, axis_track, 'X');
500
501         DEG_id_tag_update(&clip->id, 0);
502         DEG_id_tag_update(&object->id, OB_RECALC_OB);
503
504         WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
505         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
506
507         return OPERATOR_FINISHED;
508 }
509
510 void CLIP_OT_set_plane(wmOperatorType *ot)
511 {
512         static EnumPropertyItem plane_items[] = {
513                 {0, "FLOOR", 0, "Floor", "Set floor plane"},
514                 {1, "WALL", 0, "Wall", "Set wall plane"},
515                 {0, NULL, 0, NULL, NULL}
516         };
517
518         /* identifiers */
519         ot->name = "Set Plane";
520         ot->description = "Set plane based on 3 selected bundles by moving camera "
521                           "(or its parent if present) in 3D space";
522         ot->idname = "CLIP_OT_set_plane";
523
524         /* api callbacks */
525         ot->exec = set_plane_exec;
526         ot->poll = set_orientation_poll;
527
528         /* flags */
529         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
530
531         /* properties */
532         RNA_def_enum(ot->srna, "plane", plane_items, 0, "Plane",
533                      "Plane to be used for orientation");
534 }
535
536 /********************** set axis operator *********************/
537
538 static int set_axis_exec(bContext *C, wmOperator *op)
539 {
540         SpaceClip *sc = CTX_wm_space_clip(C);
541         MovieClip *clip = ED_space_clip_get_clip(sc);
542         MovieTracking *tracking = &clip->tracking;
543         MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
544         Scene *scene = CTX_data_scene(C);
545         Object *object;
546         int axis = RNA_enum_get(op->ptr, "axis");
547
548         if (count_selected_bundles(C) != 1) {
549                 BKE_report(op->reports,
550                            RPT_ERROR,
551                            "Single track with bundle should be selected to define axis");
552                 return OPERATOR_CANCELLED;
553         }
554
555         object = get_orientation_object(C);
556         if (object == NULL) {
557                 BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
558                 return OPERATOR_CANCELLED;
559         }
560
561         ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking,
562                                                               tracking_object);
563         MovieTrackingTrack *track = tracksbase->first;
564         while (track) {
565                 if (TRACK_VIEW_SELECTED(sc, track) &&
566                     (track->flag & TRACK_HAS_BUNDLE))
567                 {
568                         break;
569                 }
570                 track = track->next;
571         }
572
573         set_axis(scene, object, clip, tracking_object, track, axis == 0 ? 'X' : 'Y');
574
575         DEG_id_tag_update(&clip->id, 0);
576         DEG_id_tag_update(&object->id, OB_RECALC_OB);
577
578         WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
579         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
580
581         return OPERATOR_FINISHED;
582 }
583
584 void CLIP_OT_set_axis(wmOperatorType *ot)
585 {
586         static EnumPropertyItem axis_actions[] = {
587                 {0, "X", 0, "X", "Align bundle align X axis"},
588                 {1, "Y", 0, "Y", "Align bundle align Y axis"},
589                 {0, NULL, 0, NULL, NULL}
590         };
591
592         /* identifiers */
593         ot->name = "Set Axis";
594         ot->description = "Set direction of scene axis rotating camera "
595                           "(or its parent if present) and assume selected track "
596                           "lies on real axis, joining it with the origin";
597         ot->idname = "CLIP_OT_set_axis";
598
599         /* api callbacks */
600         ot->exec = set_axis_exec;
601         ot->poll = set_orientation_poll;
602
603         /* flags */
604         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
605
606         /* properties */
607         RNA_def_enum(ot->srna, "axis", axis_actions, 0, "Axis",
608                      "Axis to use to align bundle along");
609 }
610
611 /********************** set scale operator *********************/
612
613 static int do_set_scale(bContext *C,
614                         wmOperator *op,
615                         bool scale_solution,
616                         bool apply_scale)
617 {
618         SpaceClip *sc = CTX_wm_space_clip(C);
619         MovieClip *clip = ED_space_clip_get_clip(sc);
620         MovieTracking *tracking = &clip->tracking;
621         MovieTrackingObject *tracking_object = BKE_tracking_object_get_active(tracking);
622         MovieTrackingTrack *track;
623         Scene *scene = CTX_data_scene(C);
624         Object *object = NULL;
625         Object *camera = get_camera_with_movieclip(scene, clip);
626         ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
627         int tot = 0;
628         float vec[2][3], mat[4][4], scale;
629         float dist = RNA_float_get(op->ptr, "distance");
630
631         if (count_selected_bundles(C) != 2) {
632                 BKE_report(op->reports,
633                            RPT_ERROR,
634                            "Two tracks with bundles should be selected to set scale");
635                 return OPERATOR_CANCELLED;
636         }
637
638         if (!scale_solution && !apply_scale) {
639                 object = get_orientation_object(C);
640                 if (object == NULL) {
641                         BKE_report(op->reports,
642                                    RPT_ERROR,
643                                    "No object to apply orientation on");
644                         return OPERATOR_CANCELLED;
645                 }
646         }
647
648         BKE_tracking_get_camera_object_matrix(scene, camera, mat);
649
650         track = tracksbase->first;
651         while (track) {
652                 if (TRACK_VIEW_SELECTED(sc, track)) {
653                         mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
654                         tot++;
655                 }
656                 track = track->next;
657         }
658
659         sub_v3_v3(vec[0], vec[1]);
660
661         if (len_v3(vec[0]) > 1e-5f) {
662                 scale = dist / len_v3(vec[0]);
663                 if (apply_scale) {
664                         /* Apply scale on reconstructed scene itself. */
665                         MovieTrackingReconstruction *reconstruction =
666                                 BKE_tracking_get_active_reconstruction(tracking);
667                         MovieReconstructedCamera *reconstructed_cameras;
668                         int i;
669
670                         for (track = tracksbase->first; track; track = track->next) {
671                                 mul_v3_fl(track->bundle_pos, scale);
672                         }
673
674                         reconstructed_cameras = reconstruction->cameras;
675                         for (i = 0; i < reconstruction->camnr; i++) {
676                                 mul_v3_fl(reconstructed_cameras[i].mat[3], scale);
677                         }
678
679                         WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
680                         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
681                 }
682                 else {
683                         if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
684                                 mul_v3_fl(object->size, scale);
685                                 mul_v3_fl(object->loc, scale);
686                         }
687                         else if (!scale_solution) {
688                                 Object *solver_camera = object_solver_camera(scene, object);
689
690                                 object->size[0] = object->size[1] = object->size[2] = 1.0f / scale;
691
692                                 if (solver_camera) {
693                                         object->size[0] /= solver_camera->size[0];
694                                         object->size[1] /= solver_camera->size[1];
695                                         object->size[2] /= solver_camera->size[2];
696                                 }
697                         }
698                         else {
699                                 tracking_object->scale = scale;
700                         }
701
702                         DEG_id_tag_update(&clip->id, 0);
703
704                         if (object)
705                                 DEG_id_tag_update(&object->id, OB_RECALC_OB);
706
707                         WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
708                         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
709                 }
710         }
711
712         return OPERATOR_FINISHED;
713 }
714
715 static int set_scale_exec(bContext *C, wmOperator *op)
716 {
717         return do_set_scale(C, op, false, false);
718 }
719
720 static int set_scale_invoke(bContext *C,
721                             wmOperator *op,
722                             const wmEvent *UNUSED(event))
723 {
724         SpaceClip *sc = CTX_wm_space_clip(C);
725         MovieClip *clip = ED_space_clip_get_clip(sc);
726
727         if (!RNA_struct_property_is_set(op->ptr, "distance"))
728                 RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
729
730         return set_scale_exec(C, op);
731 }
732
733 void CLIP_OT_set_scale(wmOperatorType *ot)
734 {
735         /* identifiers */
736         ot->name = "Set Scale";
737         ot->description = "Set scale of scene by scaling camera (or its parent if present)";
738         ot->idname = "CLIP_OT_set_scale";
739
740         /* api callbacks */
741         ot->exec = set_scale_exec;
742         ot->invoke = set_scale_invoke;
743         ot->poll = set_orientation_poll;
744
745         /* flags */
746         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
747
748         /* properties */
749         RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
750                       "Distance", "Distance between selected tracks", -100.0f, 100.0f);
751 }
752
753 /********************** set solution scale operator *********************/
754
755 static int set_solution_scale_poll(bContext *C)
756 {
757         SpaceClip *sc = CTX_wm_space_clip(C);
758         if (sc != NULL) {
759                 MovieClip *clip = ED_space_clip_get_clip(sc);
760                 if (clip != NULL) {
761                         MovieTracking *tracking = &clip->tracking;
762                         MovieTrackingObject *tracking_object =
763                                 BKE_tracking_object_get_active(tracking);
764                         return (tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0;
765                 }
766         }
767         return false;
768 }
769
770 static int set_solution_scale_exec(bContext *C, wmOperator *op)
771 {
772         return do_set_scale(C, op, true, false);
773 }
774
775 static int set_solution_scale_invoke(bContext *C,
776                                      wmOperator *op,
777                                      const wmEvent *UNUSED(event))
778 {
779         SpaceClip *sc = CTX_wm_space_clip(C);
780         MovieClip *clip = ED_space_clip_get_clip(sc);
781
782         if (!RNA_struct_property_is_set(op->ptr, "distance")) {
783                 RNA_float_set(op->ptr,
784                               "distance",
785                               clip->tracking.settings.object_distance);
786         }
787
788         return set_solution_scale_exec(C, op);
789 }
790
791 void CLIP_OT_set_solution_scale(wmOperatorType *ot)
792 {
793         /* identifiers */
794         ot->name = "Set Solution Scale";
795         ot->description = "Set object solution scale using distance between "
796                           "two selected tracks";
797         ot->idname = "CLIP_OT_set_solution_scale";
798
799         /* api callbacks */
800         ot->exec = set_solution_scale_exec;
801         ot->invoke = set_solution_scale_invoke;
802         ot->poll = set_solution_scale_poll;
803
804         /* flags */
805         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
806
807         /* properties */
808         RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
809                       "Distance", "Distance between selected tracks",
810                       -100.0f, 100.0f);
811 }
812
813 /********************** apply solution scale operator *********************/
814
815 static int apply_solution_scale_poll(bContext *C)
816 {
817         SpaceClip *sc = CTX_wm_space_clip(C);
818         if (sc != NULL) {
819                 MovieClip *clip = ED_space_clip_get_clip(sc);
820                 if (clip != NULL) {
821                         MovieTracking *tracking = &clip->tracking;
822                         MovieTrackingObject *tracking_object =
823                                 BKE_tracking_object_get_active(tracking);
824                         return (tracking_object->flag & TRACKING_OBJECT_CAMERA) != 0;
825                 }
826         }
827         return 0;
828 }
829
830 static int apply_solution_scale_exec(bContext *C, wmOperator *op)
831 {
832         return do_set_scale(C, op, false, true);
833 }
834
835 static int apply_solution_scale_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
836 {
837         SpaceClip *sc = CTX_wm_space_clip(C);
838         MovieClip *clip = ED_space_clip_get_clip(sc);
839         if (!RNA_struct_property_is_set(op->ptr, "distance")) {
840                 RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
841         }
842         return apply_solution_scale_exec(C, op);
843 }
844
845 void CLIP_OT_apply_solution_scale(wmOperatorType *ot)
846 {
847         /* identifiers */
848         ot->name = "Apply Solution Scale";
849         ot->description = "Apply scale on solution itself to make distance between "
850                           "selected tracks equals to desired";
851         ot->idname = "CLIP_OT_apply_solution_scale";
852
853         /* api callbacks */
854         ot->exec = apply_solution_scale_exec;
855         ot->invoke = apply_solution_scale_invoke;
856         ot->poll = apply_solution_scale_poll;
857
858         /* flags */
859         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
860
861         /* properties */
862         RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
863                       "Distance", "Distance between selected tracks",
864                       -100.0f, 100.0f);
865 }