Camera tracking: wall scene orientation operator
[blender-staging.git] / source / blender / editors / space_clip / tracking_ops.c
index 49ea3247a554bbfc774453287cd78ffde3ac4d4d..68b98ce756cd3a68c306c372519ee62a03d00b16 100644 (file)
@@ -32,6 +32,7 @@
 #include "MEM_guardedalloc.h"
 
 #include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
 #include "DNA_gpencil_types.h"
 #include "DNA_movieclip_types.h"
 #include "DNA_object_types.h"  /* SELECT */
@@ -45,6 +46,7 @@
 
 #include "BKE_main.h"
 #include "BKE_context.h"
+#include "BKE_constraint.h"
 #include "BKE_movieclip.h"
 #include "BKE_tracking.h"
 #include "BKE_global.h"
@@ -90,28 +92,6 @@ static int space_clip_frame_poll(bContext *C)
        return 0;
 }
 
-static int space_clip_frame_camera_poll(bContext *C)
-{
-       Scene *scene= CTX_data_scene(C);
-
-       if(space_clip_frame_poll(C)) {
-               return scene->camera != NULL;
-       }
-
-       return 0;
-}
-
-static int space_clip_camera_poll(bContext *C)
-{
-       SpaceClip *sc= CTX_wm_space_clip(C);
-       Scene *scene= CTX_data_scene(C);
-
-       if(sc && sc->clip && scene->camera)
-               return 1;
-
-       return 0;
-}
-
 /********************** add marker operator *********************/
 
 static void add_marker(SpaceClip *sc, float x, float y)
@@ -354,7 +334,7 @@ static SlideMarkerData *create_slide_marker_data(SpaceClip *sc, MovieTrackingTra
 }
 
 /* corner = 0: right-bottom corner,
  corner = 1: left-top corner */
* corner = 1: left-top corner */
 static int mouse_on_corner(SpaceClip *sc, MovieTrackingTrack *track, MovieTrackingMarker *marker,
                        int area, float co[2], int corner, int width, int height)
 {
@@ -1034,6 +1014,7 @@ static int select_all_exec(bContext *C, wmOperator *op)
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTrackingTrack *track= NULL;        /* selected track */
+       MovieTrackingMarker *marker;
        ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
        int action= RNA_enum_get(op->ptr, "action");
        int framenr= sc->user.framenr;
@@ -1044,8 +1025,12 @@ static int select_all_exec(bContext *C, wmOperator *op)
                track= tracksbase->first;
                while(track) {
                        if(TRACK_VIEW_SELECTED(sc, track)) {
-                               action= SEL_DESELECT;
-                               break;
+                               marker= BKE_tracking_get_marker(track, framenr);
+
+                               if(MARKER_VISIBLE(sc, marker)) {
+                                       action= SEL_DESELECT;
+                                       break;
+                               }
                        }
 
                        track= track->next;
@@ -1055,9 +1040,9 @@ static int select_all_exec(bContext *C, wmOperator *op)
        track= tracksbase->first;
        while(track) {
                if((track->flag&TRACK_HIDDEN)==0) {
-                       MovieTrackingMarker *marker= BKE_tracking_get_marker(track, framenr);
+                       marker= BKE_tracking_get_marker(track, framenr);
 
-                       if(marker && MARKER_VISIBLE(sc, marker)) {
+                       if(MARKER_VISIBLE(sc, marker)) {
                                switch (action) {
                                        case SEL_SELECT:
                                                track->flag|= SELECT;
@@ -1158,8 +1143,8 @@ static int select_groped_exec(bContext *C, wmOperator *op)
 
                if(ok) {
                        track->flag|= SELECT;
-                       if(sc->flag&SC_SHOW_MARKER_PATTERN) track->pat_flag|= SELECT;;
-                       if(sc->flag&SC_SHOW_MARKER_SEARCH) track->search_flag|= SELECT;;
+                       if(sc->flag&SC_SHOW_MARKER_PATTERN) track->pat_flag|= SELECT;
+                       if(sc->flag&SC_SHOW_MARKER_SEARCH) track->search_flag|= SELECT;
                }
 
                track= track->next;
@@ -1228,7 +1213,7 @@ static int track_count_markers(SpaceClip *sc, MovieClip *clip)
        track= tracksbase->first;
        while(track) {
                if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_LOCKED)==0) {
-                       MovieTrackingMarker *marker= BKE_tracking_exact_marker(track, framenr);
+                       MovieTrackingMarker *marker= BKE_tracking_get_marker(track, framenr);
 
                        if (!marker || (marker->flag&MARKER_DISABLED) == 0)
                                tot++;
@@ -1240,22 +1225,41 @@ static int track_count_markers(SpaceClip *sc, MovieClip *clip)
        return tot;
 }
 
+static void clear_invisible_track_selection(SpaceClip *sc, MovieClip *clip)
+{
+       ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
+       int hidden = 0;
+
+       if ((sc->flag&SC_SHOW_MARKER_PATTERN)==0)
+               hidden |= TRACK_AREA_PAT;
+
+       if ((sc->flag&SC_SHOW_MARKER_SEARCH)==0)
+               hidden |= TRACK_AREA_SEARCH;
+
+       if (hidden) {
+               MovieTrackingTrack *track = tracksbase->first;
+
+               while(track) {
+                       if ((track->flag & TRACK_HIDDEN) == 0)
+                               BKE_tracking_track_flag(track, hidden, SELECT, 1);
+
+                       track = track->next;
+               }
+       }
+}
+
 static void track_init_markers(SpaceClip *sc, MovieClip *clip, int *frames_limit_r)
 {
        ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
        MovieTrackingTrack *track;
-       int framenr= sc->user.framenr, hidden= 0;
+       int framenr= sc->user.framenr;
        int frames_limit= 0;
 
-       if((sc->flag&SC_SHOW_MARKER_PATTERN)==0) hidden|= TRACK_AREA_PAT;
-       if((sc->flag&SC_SHOW_MARKER_SEARCH)==0) hidden|= TRACK_AREA_SEARCH;
+       clear_invisible_track_selection(sc, clip);
 
        track= tracksbase->first;
        while(track) {
-               if(hidden)
-                       BKE_tracking_track_flag(track, hidden, SELECT, 1);
-
-               if(TRACK_SELECTED(track)) {
+               if(TRACK_VIEW_SELECTED(sc, track)) {
                        if((track->flag&TRACK_HIDDEN)==0 && (track->flag&TRACK_LOCKED)==0) {
                                BKE_tracking_ensure_marker(track, framenr);
 
@@ -1317,17 +1321,17 @@ static int track_markers_initjob(bContext *C, TrackMarkersJob *tmj, int backward
                else if(settings->speed==TRACKING_SPEED_DOUBLE) tmj->delay/= 2;
        }
 
-       tmj->context= BKE_tracking_context_new(clip, &sc->user, backwards);
+       tmj->context= BKE_tracking_context_new(clip, &sc->user, backwards, 1);
 
        clip->tracking_context= tmj->context;
 
        tmj->lastfra= tmj->sfra;
 
-       /* XXX: silly to store this, but this data is needed to update scene and movieclip
-               frame numbers when tracking is finished. This introduces better feedback for artists.
-               Maybe there's another way to solve this problem, but can't think better way atm.
-               Anyway, this way isn't more unstable as animation rendering animation
-               which uses the same approach (except storing screen). */
+       /* XXX: silly to store this, but this data is needed to update scene and movie-clip
+        *      frame numbers when tracking is finished. This introduces better feedback for artists.
+        *      Maybe there's another way to solve this problem, but can't think better way atm.
+        *      Anyway, this way isn't more unstable as animation rendering animation
+        *      which uses the same approach (except storing screen). */
        tmj->scene= scene;
        tmj->main= CTX_data_main(C);
        tmj->screen= CTX_wm_screen(C);
@@ -1344,10 +1348,10 @@ static void track_markers_startjob(void *tmv, short *stop, short *do_update, flo
        while(framenr != tmj->efra) {
                if(tmj->delay>0) {
                        /* tracking should happen with fixed fps. Calculate time
-                          using current timer value before tracking frame and after.
-
-                          Small (and maybe unneeded optimization): do not calculate exec_time
-                          for "Fastest" tracking */
+                        * using current timer value before tracking frame and after.
+                        *
+                        * Small (and maybe unneeded optimization): do not calculate exec_time
+                        * for "Fastest" tracking */
 
                        double start_time= PIL_check_seconds_timer(), exec_time;
 
@@ -1428,7 +1432,7 @@ static int track_markers_exec(bContext *C, wmOperator *op)
                return OPERATOR_CANCELLED;
 
        /* do not disable tracks due to threshold when tracking frame-by-frame */
-       context= BKE_tracking_context_new(clip, &sc->user, backwards);
+       context= BKE_tracking_context_new(clip, &sc->user, backwards, sequence);
 
        while(framenr != efra) {
                if(!BKE_tracking_next(context))
@@ -1489,9 +1493,9 @@ static int track_markers_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(eve
        WM_jobs_customdata(steve, tmj, track_markers_freejob);
 
        /* if there's delay set in tracking job, tracking should happen
-          with fixed FPS. To deal with editor refresh we have to syncronize
-          tracks from job and tracks in clip. Do this in timer callback
-          to prevent threading conflicts. */
+        * with fixed FPS. To deal with editor refresh we have to syncronize
+        * tracks from job and tracks in clip. Do this in timer callback
+        * to prevent threading conflicts. */
        if(tmj->delay>0) WM_jobs_timer(steve, tmj->delay/1000.0f, NC_MOVIECLIP|NA_EVALUATED, 0);
        else WM_jobs_timer(steve, 0.2, NC_MOVIECLIP|NA_EVALUATED, 0);
 
@@ -1633,9 +1637,6 @@ static void solve_camera_freejob(void *scv)
        id_us_plus(&clip->id);
 
        /* set blender camera focal length so result would look fine there */
-       if(!scene->camera)
-               scene->camera= scene_find_camera(scene);
-
        if(scene->camera) {
                Camera *camera= (Camera*)scene->camera->data;
                int width, height;
@@ -1919,6 +1920,71 @@ void CLIP_OT_disable_markers(wmOperatorType *ot)
 
 /********************** set origin operator *********************/
 
+static Object *get_camera_with_movieclip(Scene *scene, MovieClip *clip)
+{
+       Object *camera= scene->camera;
+       Base *base;
+
+       if(camera && object_get_movieclip(scene, camera, 0)==clip)
+               return camera;
+
+       base= scene->base.first;
+       while(base) {
+               if(base->object->type == OB_CAMERA) {
+                       if(object_get_movieclip(scene, base->object, 0)==clip) {
+                               camera= base->object;
+                               break;
+                       }
+               }
+
+               base= base->next;
+       }
+
+       return camera;
+}
+
+static Object *get_orientation_object(bContext *C)
+{
+       Scene *scene= CTX_data_scene(C);
+       SpaceClip *sc= CTX_wm_space_clip(C);
+       MovieClip *clip= ED_space_clip(sc);
+       MovieTracking *tracking= &clip->tracking;
+       MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
+       Object *object= NULL;
+
+       if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
+               object= get_camera_with_movieclip(scene, clip);
+       }
+       else {
+               object= OBACT;
+       }
+
+       if(object && object->parent)
+               object= object->parent;
+
+       return object;
+}
+
+static int set_orientation_poll(bContext *C)
+{
+       if(space_clip_frame_poll(C)) {
+               Scene *scene= CTX_data_scene(C);
+               SpaceClip *sc= CTX_wm_space_clip(C);
+               MovieClip *clip= ED_space_clip(sc);
+               MovieTracking *tracking= &clip->tracking;
+               MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
+
+               if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
+                       return 1;
+               }
+               else {
+                       return OBACT != NULL;
+               }
+       }
+
+       return 0;
+}
+
 static int count_selected_bundles(bContext *C)
 {
        SpaceClip *sc= CTX_wm_space_clip(C);
@@ -1938,6 +2004,58 @@ static int count_selected_bundles(bContext *C)
        return tot;
 }
 
+static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat[4][4])
+{
+       bConstraint *con;
+       int found= 0;
+
+       for (con= ob->constraints.first; con; con=con->next) {
+               bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+
+               if(!cti)
+                       continue;
+
+               if(cti->type==CONSTRAINT_TYPE_OBJECTSOLVER) {
+                       bObjectSolverConstraint *data= (bObjectSolverConstraint *)con->data;
+
+                       if(!found) {
+                               Object *cam= data->camera ? data->camera : scene->camera;
+
+                               where_is_object_mat(scene, cam, invmat);
+                       }
+
+                       mult_m4_m4m4(invmat, invmat, data->invmat);
+
+                       found= 1;
+               }
+       }
+
+       if(found)
+               invert_m4(invmat);
+       else
+               unit_m4(invmat);
+}
+
+static Object *object_solver_camera(Scene *scene, Object *ob)
+{
+       bConstraint *con;
+
+       for (con= ob->constraints.first; con; con=con->next) {
+               bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+
+               if(!cti)
+                       continue;
+
+               if(cti->type==CONSTRAINT_TYPE_OBJECTSOLVER) {
+                       bObjectSolverConstraint *data= (bObjectSolverConstraint *)con->data;
+
+                       return data->camera ? data->camera : scene->camera;
+               }
+       }
+
+       return NULL;
+}
+
 static int set_origin_exec(bContext *C, wmOperator *op)
 {
        SpaceClip *sc= CTX_wm_space_clip(C);
@@ -1947,43 +2065,51 @@ static int set_origin_exec(bContext *C, wmOperator *op)
        MovieTrackingObject *tracking_object;
        Scene *scene= CTX_data_scene(C);
        Object *object;
+       Object *camera= get_camera_with_movieclip(scene, clip);
        ListBase *tracksbase;
-       float mat[4][4], vec[3];
+       float mat[4][4], vec[3], median[3];
+       int selected_count= count_selected_bundles(C);
 
-       if(count_selected_bundles(C)!=1) {
-               BKE_report(op->reports, RPT_ERROR, "Track with bundle should be selected to define origin position");
+       if(selected_count==0) {
+               BKE_report(op->reports, RPT_ERROR, "At least one track with bundle should be selected to define origin position");
 
                return OPERATOR_CANCELLED;
        }
 
-       tracking_object= BKE_tracking_active_object(tracking);
+       object= get_orientation_object(C);
+       if(!object) {
+               BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
 
-       if(tracking_object->flag&TRACKING_OBJECT_CAMERA)
-               object= scene->camera;
-       else
-               object= OBACT;
+               return OPERATOR_CANCELLED;
+       }
 
-       if(object->parent)
-               object= object->parent;
+       tracking_object= BKE_tracking_active_object(tracking);
 
        tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
 
        track= tracksbase->first;
+       zero_v3(median);
        while(track) {
-               if(TRACK_VIEW_SELECTED(sc, track))
-                       break;
+               if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_HAS_BUNDLE)) {
+                       add_v3_v3(median, track->bundle_pos);
+               }
 
                track= track->next;
        }
+       mul_v3_fl(median, 1.0f/selected_count);
 
-       BKE_get_tracking_mat(scene, NULL, mat);
+       BKE_get_tracking_mat(scene, camera, mat);
 
-       mul_v3_m4v3(vec, mat, track->bundle_pos);
+       mul_v3_m4v3(vec, mat, median);
 
-       if(tracking_object->flag&TRACKING_OBJECT_CAMERA)
+       if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
                sub_v3_v3(object->loc, vec);
-       else
+       }
+       else {
+               object_solver_inverted_matrix(scene, object, mat);
+               mul_v3_m4v3(vec, mat, vec);
                copy_v3_v3(object->loc, vec);
+       }
 
        DAG_id_tag_update(&clip->id, 0);
        DAG_id_tag_update(&object->id, OB_RECALC_OB);
@@ -2003,30 +2129,37 @@ void CLIP_OT_set_origin(wmOperatorType *ot)
 
        /* api callbacks */
        ot->exec= set_origin_exec;
-       ot->poll= space_clip_frame_camera_poll;
+       ot->poll= set_orientation_poll;
 
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       /* properties */
+       RNA_def_boolean(ot->srna, "use_median", 0, "Use Median", "Set origin to median point of selected bundles");
 }
 
 /********************** set floor operator *********************/
 
-static void set_axis(Scene *scene,  Object *ob, MovieTrackingObject *tracking_object,
+static void set_axis(Scene *scene,  Object *ob, MovieClip *clip, MovieTrackingObject *tracking_object,
                        MovieTrackingTrack *track, char axis)
 {
+       Object *camera= get_camera_with_movieclip(scene, clip);
        int is_camera= tracking_object->flag&TRACKING_OBJECT_CAMERA;
        int  flip= 0;
        float mat[4][4], vec[3], obmat[4][4], dvec[3];
 
        object_to_mat4(ob, obmat);
 
-       BKE_get_tracking_mat(scene, NULL, mat);
+       BKE_get_tracking_mat(scene, camera, mat);
        mul_v3_m4v3(vec, mat, track->bundle_pos);
        copy_v3_v3(dvec, vec);
 
        if(!is_camera) {
                float imat[4][4];
 
+               object_solver_inverted_matrix(scene, ob, imat);
+               mul_v3_m4v3(vec, imat, vec);
+
                invert_m4_m4(imat, obmat);
                mul_v3_m4v3(dvec, imat, vec);
 
@@ -2091,32 +2224,31 @@ static void set_axis(Scene *scene,  Object *ob, MovieTrackingObject *tracking_ob
        if(is_camera) {
                invert_m4(mat);
 
-               mul_m4_m4m4(mat, obmat, mat);
+               mult_m4_m4m4(mat, mat, obmat);
        }
        else {
-               float lmat[4][4], ilmat[4][4], m[4][4];
-
-               unit_m4(lmat);
-               copy_v3_v3(lmat[3], obmat[3]);
-               invert_m4_m4(ilmat, lmat);
-
                if(!flip) {
-                       float rmat[3][3], tmat[4][4];
+                       float lmat[4][4], ilmat[4][4], rmat[3][3];
 
                        object_rot_to_mat3(ob, rmat);
-                       copy_m4_m3(tmat, rmat);
-                       invert_m4(tmat);
+                       invert_m3(rmat);
+                       mul_m4_m4m3(mat, mat, rmat);
 
-                       mul_m4_m4m4(mat, mat, tmat);
-               }
+                       unit_m4(lmat);
+                       copy_v3_v3(lmat[3], obmat[3]);
+                       invert_m4_m4(ilmat, lmat);
 
-               mul_serie_m4(mat, lmat, mat, ilmat, obmat, NULL, NULL, NULL, NULL);
+                       mul_serie_m4(mat, lmat, mat, ilmat, obmat, NULL, NULL, NULL, NULL);
+               }
+               else {
+                       mult_m4_m4m4(mat, obmat, mat);
+               }
        }
 
        object_apply_mat4(ob, mat, 0, 0);
 }
 
-static int set_floor_exec(bContext *C, wmOperator *op)
+static int set_plane_exec(bContext *C, wmOperator *op)
 {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
@@ -2126,8 +2258,10 @@ static int set_floor_exec(bContext *C, wmOperator *op)
        MovieTrackingTrack *track, *axis_track= NULL, *act_track;
        ListBase *tracksbase;
        Object *object;
+       Object *camera= get_camera_with_movieclip(scene, clip);
        int tot= 0;
        float vec[3][3], mat[4][4], obmat[4][4], newmat[4][4], orig[3]= {0.0f, 0.0f, 0.0f};
+       int plane= RNA_enum_get(op->ptr, "plane");
        float rot[4][4]={{0.0f, 0.0f, -1.0f, 0.0f},
                         {0.0f, 1.0f, 0.0f, 0.0f},
                         {1.0f, 0.0f, 0.0f, 0.0f},
@@ -2143,15 +2277,14 @@ static int set_floor_exec(bContext *C, wmOperator *op)
        tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
        act_track= BKE_tracking_active_track(tracking);
 
-       if(tracking_object->flag&TRACKING_OBJECT_CAMERA)
-               object= scene->camera;
-       else
-               object= OBACT;
+       object= get_orientation_object(C);
+       if(!object) {
+               BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
 
-       if(object->parent)
-               object= object->parent;
+               return OPERATOR_CANCELLED;
+       }
 
-       BKE_get_tracking_mat(scene, NULL, mat);
+       BKE_get_tracking_mat(scene, camera, mat);
 
        /* get 3 bundles to use as reference */
        track= tracksbase->first;
@@ -2176,9 +2309,16 @@ static int set_floor_exec(bContext *C, wmOperator *op)
        /* construct ortho-normal basis */
        unit_m4(mat);
 
-       cross_v3_v3v3(mat[0], vec[1], vec[2]);
-       copy_v3_v3(mat[1], vec[1]);
-       cross_v3_v3v3(mat[2], mat[0], mat[1]);
+       if (plane == 0) { /* floor */
+               cross_v3_v3v3(mat[0], vec[1], vec[2]);
+               copy_v3_v3(mat[1], vec[1]);
+               cross_v3_v3v3(mat[2], mat[0], mat[1]);
+       }
+       else if (plane == 1) { /* wall */
+               cross_v3_v3v3(mat[2], vec[1], vec[2]);
+               copy_v3_v3(mat[1], vec[1]);
+               cross_v3_v3v3(mat[0], mat[1], mat[2]);
+       }
 
        normalize_v3(mat[0]);
        normalize_v3(mat[1]);
@@ -2193,15 +2333,15 @@ static int set_floor_exec(bContext *C, wmOperator *op)
                invert_m4(mat);
 
                object_to_mat4(object, obmat);
-               mul_m4_m4m4(mat, obmat, mat);
-               mul_m4_m4m4(newmat, mat, rot);
+               mult_m4_m4m4(mat, mat, obmat);
+               mult_m4_m4m4(newmat, rot, mat);
                object_apply_mat4(object, newmat, 0, 0);
 
                /* make camera have positive z-coordinate */
                if(object->loc[2]<0) {
-                 invert_m4(rot);
-                 mul_m4_m4m4(newmat, mat, rot);
-                 object_apply_mat4(object, newmat, 0, 0);
+                       invert_m4(rot);
+                       mult_m4_m4m4(newmat, rot, mat);
+                       object_apply_mat4(object, newmat, 0, 0);
                }
        }
        else {
@@ -2209,7 +2349,7 @@ static int set_floor_exec(bContext *C, wmOperator *op)
        }
 
        where_is_object(scene, object);
-       set_axis(scene, object, tracking_object, axis_track, 'X');
+       set_axis(scene, object, clip, tracking_object, axis_track, 'X');
 
        DAG_id_tag_update(&clip->id, 0);
        DAG_id_tag_update(&object->id, OB_RECALC_OB);
@@ -2220,19 +2360,28 @@ static int set_floor_exec(bContext *C, wmOperator *op)
        return OPERATOR_FINISHED;
 }
 
-void CLIP_OT_set_floor(wmOperatorType *ot)
+void CLIP_OT_set_plane(wmOperatorType *ot)
 {
+       static EnumPropertyItem plane_items[] = {
+                       {0, "FLOOR", 0, "Floor", "Set floor plane"},
+                       {1, "WALL", 0, "Wall", "Set wall plane"},
+                       {0, NULL, 0, NULL, NULL}
+       };
+
        /* identifiers */
-       ot->name= "Set Floor";
-       ot->description= "Set floor based on 3 selected bundles by moving camera (or it's parent if present) in 3D space";
-       ot->idname= "CLIP_OT_set_floor";
+       ot->name= "Set Plane";
+       ot->description= "Set plane based on 3 selected bundles by moving camera (or it's parent if present) in 3D space";
+       ot->idname= "CLIP_OT_set_plane";
 
        /* api callbacks */
-       ot->exec= set_floor_exec;
-       ot->poll= space_clip_camera_poll;
+       ot->exec= set_plane_exec;
+       ot->poll= set_orientation_poll;
 
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       /* properties */
+       RNA_def_enum(ot->srna, "plane", plane_items, 0, "Plane", "Plane to be sued for orientation");
 }
 
 /********************** set axis operator *********************/
@@ -2255,13 +2404,12 @@ static int set_axis_exec(bContext *C, wmOperator *op)
                return OPERATOR_CANCELLED;
        }
 
-       if(tracking_object->flag & TRACKING_OBJECT_CAMERA)
-               object= scene->camera;
-       else
-               object= OBACT;
+       object= get_orientation_object(C);
+       if(!object) {
+               BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
 
-       if(object->parent)
-               object= object->parent;
+               return OPERATOR_CANCELLED;
+       }
 
        tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
 
@@ -2273,7 +2421,7 @@ static int set_axis_exec(bContext *C, wmOperator *op)
                track= track->next;
        }
 
-       set_axis(scene, object, tracking_object, track, axis==0?'X':'Y');
+       set_axis(scene, object, clip, tracking_object, track, axis==0?'X':'Y');
 
        DAG_id_tag_update(&clip->id, 0);
        DAG_id_tag_update(&object->id, OB_RECALC_OB);
@@ -2299,7 +2447,7 @@ void CLIP_OT_set_axis(wmOperatorType *ot)
 
        /* api callbacks */
        ot->exec= set_axis_exec;
-       ot->poll= space_clip_frame_camera_poll;
+       ot->poll= set_orientation_poll;
 
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -2310,28 +2458,35 @@ void CLIP_OT_set_axis(wmOperatorType *ot)
 
 /********************** set scale operator *********************/
 
-static int set_scale_exec(bContext *C, wmOperator *op)
+static int do_set_scale(bContext *C, wmOperator *op, int scale_solution)
 {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
+       MovieTracking *tracking= &clip->tracking;
+       MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
        MovieTrackingTrack *track;
        Scene *scene= CTX_data_scene(C);
-       Object *parent= scene->camera;
-       ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
+       Object *object= NULL;
+       Object *camera= get_camera_with_movieclip(scene, clip);
+       ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
        int tot= 0;
        float vec[2][3], mat[4][4], scale;
        float dist= RNA_float_get(op->ptr, "distance");
 
        if(count_selected_bundles(C)!=2) {
-               BKE_report(op->reports, RPT_ERROR, "Two tracks with bundles should be selected to scale scene");
+               BKE_report(op->reports, RPT_ERROR, "Two tracks with bundles should be selected to set scale");
 
                return OPERATOR_CANCELLED;
        }
 
-       if(scene->camera->parent)
-               parent= scene->camera->parent;
+       object= get_orientation_object(C);
+       if(!object) {
+               BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
+
+               return OPERATOR_CANCELLED;
+       }
 
-       BKE_get_tracking_mat(scene, NULL, mat);
+       BKE_get_tracking_mat(scene, camera, mat);
 
        track= tracksbase->first;
        while(track) {
@@ -2348,11 +2503,29 @@ static int set_scale_exec(bContext *C, wmOperator *op)
        if(len_v3(vec[0])>1e-5f) {
                scale= dist / len_v3(vec[0]);
 
-               mul_v3_fl(parent->size, scale);
-               mul_v3_fl(parent->loc, scale);
+               if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
+                       mul_v3_fl(object->size, scale);
+                       mul_v3_fl(object->loc, scale);
+               }
+               else if(!scale_solution){
+                       Object *solver_camera= object_solver_camera(scene, object);
+
+                       object->size[0]= object->size[1]= object->size[2]= 1.0f/scale;
+
+                       if(solver_camera) {
+                               object->size[0]/= solver_camera->size[0];
+                               object->size[1]/= solver_camera->size[1];
+                               object->size[2]/= solver_camera->size[2];
+                       }
+               }
+               else {
+                       tracking_object->scale= scale;
+               }
 
                DAG_id_tag_update(&clip->id, 0);
-               DAG_id_tag_update(&parent->id, OB_RECALC_OB);
+
+               if(object)
+                       DAG_id_tag_update(&object->id, OB_RECALC_OB);
 
                WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
                WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
@@ -2361,13 +2534,17 @@ static int set_scale_exec(bContext *C, wmOperator *op)
        return OPERATOR_FINISHED;
 }
 
+static int set_scale_exec(bContext *C, wmOperator *op)
+{
+       return do_set_scale(C, op, 0);
+}
+
 static int set_scale_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
 {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
-       float dist= RNA_float_get(op->ptr, "distance");
 
-       if(dist==0.0f)
+       if(!RNA_struct_property_is_set(op->ptr, "distance"))
                RNA_float_set(op->ptr, "distance", clip->tracking.settings.dist);
 
        return set_scale_exec(C, op);
@@ -2383,7 +2560,59 @@ void CLIP_OT_set_scale(wmOperatorType *ot)
        /* api callbacks */
        ot->exec= set_scale_exec;
        ot->invoke= set_scale_invoke;
-       ot->poll= space_clip_frame_camera_poll;
+       ot->poll= set_orientation_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       /* properties */
+       RNA_def_float(ot->srna, "distance", 0.0f, -FLT_MAX, FLT_MAX,
+               "Distance", "Distance between selected tracks", -100.0f, 100.0f);
+}
+
+/********************** set solution scale operator *********************/
+
+static int set_solution_scale_poll(bContext *C)
+{
+       if(space_clip_frame_poll(C)) {
+               SpaceClip *sc= CTX_wm_space_clip(C);
+               MovieClip *clip= ED_space_clip(sc);
+               MovieTracking *tracking= &clip->tracking;
+               MovieTrackingObject *tracking_object= BKE_tracking_active_object(tracking);
+
+               return (tracking_object->flag&TRACKING_OBJECT_CAMERA) == 0;
+       }
+
+       return 0;
+}
+
+static int set_solution_scale_exec(bContext *C, wmOperator *op)
+{
+       return do_set_scale(C, op, 1);
+}
+
+static int set_solution_scale_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+{
+       SpaceClip *sc= CTX_wm_space_clip(C);
+       MovieClip *clip= ED_space_clip(sc);
+
+       if(!RNA_struct_property_is_set(op->ptr, "distance"))
+               RNA_float_set(op->ptr, "distance", clip->tracking.settings.object_distance);
+
+       return set_solution_scale_exec(C, op);
+}
+
+void CLIP_OT_set_solution_scale(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Set Solution Scale";
+       ot->description= "Set object solution scale using distance between two selected tracks";
+       ot->idname= "CLIP_OT_set_solution_scale";
+
+       /* api callbacks */
+       ot->exec= set_solution_scale_exec;
+       ot->invoke= set_solution_scale_invoke;
+       ot->poll= set_solution_scale_poll;
 
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -2545,7 +2774,8 @@ static int detect_features_exec(bContext *C, wmOperator *op)
 {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
-       ImBuf *ibuf= BKE_movieclip_get_ibuf_flag(clip, &sc->user, 0);
+       int clip_flag= clip->flag&MCLIP_TIMECODE_FLAGS;
+       ImBuf *ibuf= BKE_movieclip_get_ibuf_flag(clip, &sc->user, clip_flag, MOVIECLIP_CACHE_SKIP);
        MovieTracking *tracking= &clip->tracking;
        ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
        MovieTrackingTrack *track= tracksbase->first;
@@ -3119,7 +3349,7 @@ static int is_track_clean(MovieTrackingTrack *track, int frames, int del)
                                }
                                else if(markers[a].flag&MARKER_DISABLED) {
                                        /* current segment which would be deleted was finished by disabled marker,
-                                          so next segment should be started from disabled marker */
+                                        * so next segment should be started from disabled marker */
                                        start_disabled= 1;
                                }
                        }
@@ -3205,15 +3435,15 @@ static int clean_tracks_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(even
 {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
-       int frames= RNA_int_get(op->ptr, "frames");
-       float error= RNA_float_get(op->ptr, "error");
-       int action= RNA_enum_get(op->ptr, "action");
 
-       if(frames==0 && error==0 && action==0) {
+       if(!RNA_struct_property_is_set(op->ptr, "frames"))
                RNA_int_set(op->ptr, "frames", clip->tracking.settings.clean_frames);
+
+       if(!RNA_struct_property_is_set(op->ptr, "error"))
                RNA_float_set(op->ptr, "error", clip->tracking.settings.clean_error);
+
+       if(!RNA_struct_property_is_set(op->ptr, "action"))
                RNA_enum_set(op->ptr, "action", clip->tracking.settings.clean_action);
-       }
 
        return clean_tracks_exec(C, op);
 }
@@ -3313,3 +3543,74 @@ void CLIP_OT_tracking_object_remove(wmOperatorType *ot)
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
+
+/********************** copy tracks to clipboard operator *********************/
+
+static int copy_tracks_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       SpaceClip *sc = CTX_wm_space_clip(C);
+       MovieClip *clip = ED_space_clip(sc);
+       MovieTracking *tracking = &clip->tracking;
+       MovieTrackingObject *object = BKE_tracking_active_object(tracking);
+
+       clear_invisible_track_selection(sc, clip);
+
+       BKE_tracking_clipboard_copy_tracks(tracking, object);
+
+       return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_copy_tracks(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Copy Tracks";
+       ot->description = "Copy selected tracks to clipboard";
+       ot->idname = "CLIP_OT_copy_tracks";
+
+       /* api callbacks */
+       ot->exec = copy_tracks_exec;
+       ot->poll = ED_space_clip_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER;
+}
+
+/********************** paste tracks from clipboard operator *********************/
+
+static int paste_tracks_poll(bContext *C)
+{
+       if (ED_space_clip_poll(C)) {
+               return BKE_tracking_clipboard_has_tracks();
+       }
+
+       return 0;
+}
+
+static int paste_tracks_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       SpaceClip *sc = CTX_wm_space_clip(C);
+       MovieClip *clip = ED_space_clip(sc);
+       MovieTracking *tracking = &clip->tracking;
+       MovieTrackingObject *object = BKE_tracking_active_object(tracking);
+
+       BKE_tracking_clipboard_paste_tracks(tracking, object);
+
+       WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
+
+       return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_paste_tracks(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Paste Tracks";
+       ot->description = "Paste tracks from clipboard";
+       ot->idname = "CLIP_OT_paste_tracks";
+
+       /* api callbacks */
+       ot->exec = paste_tracks_exec;
+       ot->poll = paste_tracks_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}