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