Camera tracking: wall scene orientation operator
[blender-staging.git] / source / blender / editors / space_clip / tracking_ops.c
index 6f3bd6810e5cd37f29b60b186842558aeac22cf4..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,41 +92,21 @@ 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)
 {
        MovieClip *clip= ED_space_clip(sc);
+       MovieTracking *tracking= &clip->tracking;
+       ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
        MovieTrackingTrack *track;
        int width, height;
        
        ED_space_clip_size(sc, &width, &height);
 
-       track= BKE_tracking_add_track(&clip->tracking, x, y, sc->user.framenr, width, height);
+       track= BKE_tracking_add_track(tracking, tracksbase, x, y, sc->user.framenr, width, height);
 
-       BKE_tracking_select_track(&clip->tracking, track, TRACK_AREA_ALL, 0);
+       BKE_tracking_select_track(tracksbase, track, TRACK_AREA_ALL, 0);
 
        clip->tracking.act_track= track;
 }
@@ -191,13 +173,14 @@ static int delete_track_exec(bContext *C, wmOperator *UNUSED(op))
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
-       MovieTrackingTrack *track= tracking->tracks.first, *next;
+       ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
+       MovieTrackingTrack *track= tracksbase->first, *next;
 
        while(track) {
                next= track->next;
 
                if(TRACK_VIEW_SELECTED(sc, track))
-                       clip_delete_track(C, clip, track);
+                       clip_delete_track(C, clip, tracksbase, track);
 
                track= next;
        }
@@ -230,7 +213,8 @@ static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
 {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
-       MovieTrackingTrack *track= clip->tracking.tracks.first, *next;
+       ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
+       MovieTrackingTrack *track= tracksbase->first, *next;
        int framenr= sc->user.framenr;
        int has_selection= 0;
 
@@ -243,7 +227,7 @@ static int delete_marker_exec(bContext *C, wmOperator *UNUSED(op))
                        if(marker) {
                                has_selection|= track->markersnr>1;
 
-                               clip_delete_marker(C, clip, track, marker);
+                               clip_delete_marker(C, clip, tracksbase, track, marker);
                        }
                }
 
@@ -350,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)
 {
@@ -429,6 +413,7 @@ static void *slide_marker_customdata(bContext *C, wmEvent *event)
        int width, height;
        float co[2];
        void *customdata= NULL;
+       ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
 
        ED_space_clip_size(sc, &width, &height);
 
@@ -437,7 +422,7 @@ static void *slide_marker_customdata(bContext *C, wmEvent *event)
 
        ED_clip_mouse_pos(C, event, co);
 
-       track= clip->tracking.tracks.first;
+       track= tracksbase->first;
        while(track) {
                if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_LOCKED)==0) {
                        MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
@@ -684,7 +669,7 @@ static int track_mouse_area(SpaceClip *sc, float co[2], MovieTrackingTrack *trac
        epsy= MIN4(track->pat_min[1]-track->search_min[1], track->search_max[1]-track->pat_max[1],
                   fabsf(track->pat_min[1]), fabsf(track->pat_max[1])) / 2;
 
-       epsx= MAX2(epsy, 2.0f / width);
+       epsx= MAX2(epsx, 2.0f / width);
        epsy= MAX2(epsy, 2.0f / height);
 
        if(sc->flag&SC_SHOW_MARKER_SEARCH)
@@ -721,12 +706,12 @@ static float dist_to_rect(float co[2], float pos[2], float min[2], float max[2])
        return MIN4(d1, d2, d3, d4);
 }
 
-static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, MovieClip *clip, float co[2])
+static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, ListBase *tracksbase, float co[2])
 {
        MovieTrackingTrack *track= NULL, *cur;
        float mindist= 0.0f;
 
-       cur= clip->tracking.tracks.first;
+       cur= tracksbase->first;
        while(cur) {
                MovieTrackingMarker *marker= BKE_tracking_get_marker(cur, sc->user.framenr);
 
@@ -741,7 +726,7 @@ static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, MovieClip *clip, fl
                                d2= dist_to_rect(co, marker->pos, cur->pat_min, cur->pat_max);
 
                        /* distance to search boundbox */
-                       if(sc->flag&SC_SHOW_MARKER_SEARCH)
+                       if(sc->flag&SC_SHOW_MARKER_SEARCH && TRACK_VIEW_SELECTED(sc, cur))
                                d3= dist_to_rect(co, marker->pos, cur->search_min, cur->search_max);
 
                        /* choose minimal distance. useful for cases of overlapped markers. */
@@ -764,10 +749,11 @@ static int mouse_select(bContext *C, float co[2], int extend)
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
-       MovieTrackingTrack *act_track= tracking->act_track;
+       ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
+       MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
        MovieTrackingTrack *track= NULL;        /* selected marker */
 
-       track= find_nearest_track(sc, clip, co);
+       track= find_nearest_track(sc, tracksbase, co);
 
        if(track) {
                int area= track_mouse_area(sc, co, track);
@@ -784,7 +770,7 @@ static int mouse_select(bContext *C, float co[2], int extend)
                        if(area==TRACK_AREA_POINT)
                                area= TRACK_AREA_ALL;
 
-                       BKE_tracking_select_track(tracking, track, area, extend);
+                       BKE_tracking_select_track(tracksbase, track, area, extend);
                        clip->tracking.act_track= track;
                }
        }
@@ -867,6 +853,7 @@ static int border_select_exec(bContext *C, wmOperator *op)
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTrackingTrack *track;
+       ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
        rcti rect;
        rctf rectf;
        int change= 0, mode, extend;
@@ -884,7 +871,7 @@ static int border_select_exec(bContext *C, wmOperator *op)
        extend= RNA_boolean_get(op->ptr, "extend");
 
        /* do actual selection */
-       track= clip->tracking.tracks.first;
+       track= tracksbase->first;
        while(track) {
                if((track->flag&TRACK_HIDDEN)==0) {
                        MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
@@ -952,6 +939,7 @@ static int circle_select_exec(bContext *C, wmOperator *op)
        MovieClip *clip= ED_space_clip(sc);
        ARegion *ar= CTX_wm_region(C);
        MovieTrackingTrack *track;
+       ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
        int x, y, radius, width, height, mode, change= 0;
        float zoomx, zoomy, offset[2], ellipse[2];
 
@@ -972,7 +960,7 @@ static int circle_select_exec(bContext *C, wmOperator *op)
        ED_clip_point_stable_pos(C, x, y, &offset[0], &offset[1]);
 
        /* do selection */
-       track= clip->tracking.tracks.first;
+       track= tracksbase->first;
        while(track) {
                if((track->flag&TRACK_HIDDEN)==0) {
                        MovieTrackingMarker *marker= BKE_tracking_get_marker(track, sc->user.framenr);
@@ -1026,29 +1014,35 @@ 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;
        int has_selection= 0;
 
        if(action == SEL_TOGGLE){
                action= SEL_SELECT;
-               track= clip->tracking.tracks.first;
+               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;
                }
        }
 
-       track= clip->tracking.tracks.first;
+       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;
@@ -1108,9 +1102,11 @@ static int select_groped_exec(bContext *C, wmOperator *op)
        MovieClip *clip= ED_space_clip(sc);
        MovieTrackingTrack *track;
        MovieTrackingMarker *marker;
+       MovieTracking *tracking= &clip->tracking;
+       ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
        int group= RNA_enum_get(op->ptr, "group");
 
-       track= clip->tracking.tracks.first;
+       track= tracksbase->first;
        while(track) {
                int ok= 0;
 
@@ -1132,11 +1128,13 @@ static int select_groped_exec(bContext *C, wmOperator *op)
                        ok= marker->flag&MARKER_DISABLED;
                }
                else if(group==5) { /* color */
-                       if(clip->tracking.act_track) {
-                               ok= (track->flag&TRACK_CUSTOMCOLOR) == (clip->tracking.act_track->flag&TRACK_CUSTOMCOLOR);
+                       MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
+
+                       if(act_track) {
+                               ok= (track->flag&TRACK_CUSTOMCOLOR) == (act_track->flag&TRACK_CUSTOMCOLOR);
 
                                if(ok && track->flag&TRACK_CUSTOMCOLOR)
-                                       ok= equals_v3v3(track->color, clip->tracking.act_track->color);
+                                       ok= equals_v3v3(track->color, act_track->color);
                        }
                }
                else if(group==6) { /* failed */
@@ -1145,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;
@@ -1208,12 +1206,18 @@ static int track_markers_testbreak(void)
 static int track_count_markers(SpaceClip *sc, MovieClip *clip)
 {
        int tot= 0;
+       ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
        MovieTrackingTrack *track;
+       int framenr= sc->user.framenr;
 
-       track= clip->tracking.tracks.first;
+       track= tracksbase->first;
        while(track) {
-               if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_LOCKED)==0)
-                       tot++;
+               if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_LOCKED)==0) {
+                       MovieTrackingMarker *marker= BKE_tracking_get_marker(track, framenr);
+
+                       if (!marker || (marker->flag&MARKER_DISABLED) == 0)
+                               tot++;
+               }
 
                track= track->next;
        }
@@ -1221,21 +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= clip->tracking.tracks.first;
+       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);
 
@@ -1303,11 +1327,11 @@ static int track_markers_initjob(bContext *C, TrackMarkersJob *tmj, int backward
 
        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);
@@ -1324,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;
 
@@ -1443,6 +1467,11 @@ static int track_markers_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(eve
        int backwards= RNA_boolean_get(op->ptr, "backwards");
        int sequence= RNA_boolean_get(op->ptr, "sequence");
 
+       if(WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C))) {
+               /* only one tracking is allowed at a time */
+               return OPERATOR_CANCELLED;
+       }
+
        if(clip->tracking_context)
                return OPERATOR_CANCELLED;
 
@@ -1464,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);
 
@@ -1541,9 +1570,10 @@ static int solve_camera_initjob(bContext *C, SolveCameraJob *scj, wmOperator *op
        Scene *scene= CTX_data_scene(C);
        MovieTracking *tracking= &clip->tracking;
        MovieTrackingSettings *settings= &clip->tracking.settings;
+       MovieTrackingObject *object= BKE_tracking_active_object(tracking);
        int width, height;
 
-       if(!BKE_tracking_can_reconstruct(tracking, error_msg, max_error))
+       if(!BKE_tracking_can_reconstruct(tracking, object, error_msg, max_error))
                return 0;
 
        /* could fail if footage uses images with different sizes */
@@ -1554,7 +1584,7 @@ static int solve_camera_initjob(bContext *C, SolveCameraJob *scj, wmOperator *op
        scj->reports= op->reports;
        scj->user= sc->user;
 
-       scj->context= BKE_tracking_reconstruction_context_new(tracking,
+       scj->context= BKE_tracking_reconstruction_context_new(tracking, object,
                        settings->keyframe1, settings->keyframe2, width, height);
 
        tracking->stats= MEM_callocN(sizeof(MovieTrackingStats), "solve camera stats");
@@ -1607,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;
@@ -1665,9 +1692,15 @@ static int solve_camera_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(even
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
+       MovieTrackingReconstruction *reconstruction= BKE_tracking_get_reconstruction(tracking);
        wmJob *steve;
        char error_msg[256]= "\0";
 
+       if(WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C))) {
+               /* only one solve is allowed at a time */
+               return OPERATOR_CANCELLED;
+       }
+
        scj= MEM_callocN(sizeof(SolveCameraJob), "SolveCameraJob data");
        if(!solve_camera_initjob(C, scj, op, error_msg, sizeof(error_msg))) {
                if(error_msg[0])
@@ -1681,7 +1714,7 @@ static int solve_camera_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(even
        BLI_strncpy(tracking->stats->message, "Solving camera | Preparing solve", sizeof(tracking->stats->message));
 
        /* hide reconstruction statistics from previous solve */
-       clip->tracking.reconstruction.flag&= ~TRACKING_RECONSTRUCTED;
+       reconstruction->flag&= ~TRACKING_RECONSTRUCTED;
        WM_event_add_notifier(C, NC_MOVIECLIP|NA_EVALUATED, clip);
 
        /* setup job */
@@ -1741,7 +1774,9 @@ static int clear_solution_exec(bContext *C, wmOperator *UNUSED(op))
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
-       MovieTrackingTrack *track= tracking->tracks.first;
+       ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
+       MovieTrackingReconstruction *reconstruction= BKE_tracking_get_reconstruction(tracking);
+       MovieTrackingTrack *track= tracksbase->first;
 
        while(track) {
                track->flag&= ~TRACK_HAS_BUNDLE;
@@ -1749,13 +1784,13 @@ static int clear_solution_exec(bContext *C, wmOperator *UNUSED(op))
                track= track->next;
        }
 
-       if(tracking->reconstruction.cameras)
-               MEM_freeN(tracking->reconstruction.cameras);
+       if(reconstruction->cameras)
+               MEM_freeN(reconstruction->cameras);
 
-       tracking->reconstruction.cameras= NULL;
-       tracking->reconstruction.camnr= 0;
+       reconstruction->cameras= NULL;
+       reconstruction->camnr= 0;
 
-       tracking->reconstruction.flag&= ~TRACKING_RECONSTRUCTED;
+       reconstruction->flag&= ~TRACKING_RECONSTRUCTED;
 
        DAG_id_tag_update(&clip->id, 0);
 
@@ -1787,9 +1822,10 @@ static int clear_track_path_exec(bContext *C, wmOperator *op)
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTrackingTrack *track;
+       ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
        int action= RNA_enum_get(op->ptr, "action");
 
-       track= clip->tracking.tracks.first;
+       track= tracksbase->first;
        while(track) {
                if(TRACK_VIEW_SELECTED(sc, track))
                        BKE_tracking_clear_path(track, sc->user.framenr, action);
@@ -1834,7 +1870,8 @@ static int disable_markers_exec(bContext *C, wmOperator *op)
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
-       MovieTrackingTrack *track= tracking->tracks.first;
+       ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
+       MovieTrackingTrack *track= tracksbase->first;
        int action= RNA_enum_get(op->ptr, "action");
 
        while(track) {
@@ -1883,14 +1920,80 @@ 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);
        MovieClip *clip= ED_space_clip(sc);
+       ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
        MovieTrackingTrack *track;
        int tot= 0;
 
-       track= clip->tracking.tracks.first;
+       track= tracksbase->first;
        while(track) {
                if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_HAS_BUNDLE))
                        tot++;
@@ -1901,38 +2004,115 @@ 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);
        MovieClip *clip= ED_space_clip(sc);
+       MovieTracking *tracking= &clip->tracking;
        MovieTrackingTrack *track;
+       MovieTrackingObject *tracking_object;
        Scene *scene= CTX_data_scene(C);
-       Object *parent= scene->camera;
-       float mat[4][4], vec[3];
+       Object *object;
+       Object *camera= get_camera_with_movieclip(scene, clip);
+       ListBase *tracksbase;
+       float mat[4][4], vec[3], median[3];
+       int selected_count= count_selected_bundles(C);
+
+       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;
+       }
+
+       object= get_orientation_object(C);
+       if(!object) {
+               BKE_report(op->reports, RPT_ERROR, "No object to apply orientation on");
 
-       if(count_selected_bundles(C)!=1) {
-               BKE_report(op->reports, RPT_ERROR, "Track with bundle should be selected to define origin position");
                return OPERATOR_CANCELLED;
        }
 
-       if(scene->camera->parent)
-               parent= scene->camera->parent;
+       tracking_object= BKE_tracking_active_object(tracking);
 
-       track= clip->tracking.tracks.first;
+       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);
-       mul_v3_m4v3(vec, mat, track->bundle_pos);
+       BKE_get_tracking_mat(scene, camera, mat);
 
-       sub_v3_v3(parent->loc, vec);
+       mul_v3_m4v3(vec, mat, median);
+
+       if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
+               sub_v3_v3(object->loc, vec);
+       }
+       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(&parent->id, OB_RECALC_OB);
+       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);
@@ -1949,20 +2129,42 @@ 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, MovieTrackingTrack *track, char axis)
+static void set_axis(Scene *scene,  Object *ob, MovieClip *clip, MovieTrackingObject *tracking_object,
+                       MovieTrackingTrack *track, char axis)
 {
-       float mat[4][4], vec[3], obmat[4][4];
+       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);
+
+               sub_v3_v3(vec, obmat[3]);
+       }
 
        if(len_v2(vec) < 1e-3f)
                return;
@@ -1970,26 +2172,48 @@ static void set_axis(Scene *scene,  Object *ob, MovieTrackingTrack *track, char
        unit_m4(mat);
 
        if(axis=='X') {
-               if(fabsf(vec[1])<1e-3f) {
+               if(fabsf(dvec[1])<1e-3f) {
+                       flip= 1;
+
                        mat[0][0]= -1.0f; mat[0][1]= 0.0f; mat[0][2]= 0.0f;
                        mat[1][0]= 0.0f; mat[1][1]= -1.0f; mat[1][2]= 0.0f;
                        mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
                } else {
                        copy_v3_v3(mat[0], vec);
-                       mat[0][2]= 0.0f;
-                       mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
-                       cross_v3_v3v3(mat[1], mat[2], mat[0]);
+
+                       if(is_camera || fabsf(vec[2])<1e-3f) {
+                               mat[0][2]= 0.0f;
+                               mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
+                               cross_v3_v3v3(mat[1], mat[2], mat[0]);
+                       }
+                       else {
+                               vec[2]= 0.0f;
+
+                               cross_v3_v3v3(mat[1], mat[0], vec);
+                               cross_v3_v3v3(mat[2], mat[0], mat[1]);
+                       }
                }
        } else {
-               if(fabsf(vec[0])<1e-3f) {
+               if(fabsf(dvec[0])<1e-3f) {
+                       flip= 1;
+
                        mat[0][0]= -1.0f; mat[0][1]= 0.0f; mat[0][2]= 0.0f;
                        mat[1][0]= 0.0f; mat[1][1]= -1.0f; mat[1][2]= 0.0f;
                        mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
                } else {
                        copy_v3_v3(mat[1], vec);
-                       mat[1][2]= 0.0f;
-                       mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
-                       cross_v3_v3v3(mat[0], mat[1], mat[2]);
+
+                       if(is_camera || fabsf(vec[2])<1e-3f) {
+                               mat[1][2]= 0.0f;
+                               mat[2][0]= 0.0f; mat[2][1]= 0.0f; mat[2][2]= 1.0f;
+                               cross_v3_v3v3(mat[0], mat[1], mat[2]);
+                       }
+                       else {
+                               vec[2]= 0.0f;
+
+                               cross_v3_v3v3(mat[0], vec, mat[1]);
+                               cross_v3_v3v3(mat[2], mat[0], mat[1]);
+                       }
                }
        }
 
@@ -1997,23 +2221,47 @@ static void set_axis(Scene *scene,  Object *ob, MovieTrackingTrack *track, char
        normalize_v3(mat[1]);
        normalize_v3(mat[2]);
 
-       invert_m4(mat);
+       if(is_camera) {
+               invert_m4(mat);
+
+               mult_m4_m4m4(mat, mat, obmat);
+       }
+       else {
+               if(!flip) {
+                       float lmat[4][4], ilmat[4][4], rmat[3][3];
+
+                       object_rot_to_mat3(ob, rmat);
+                       invert_m3(rmat);
+                       mul_m4_m4m3(mat, mat, rmat);
+
+                       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);
+               }
+               else {
+                       mult_m4_m4m4(mat, obmat, mat);
+               }
+       }
 
-       object_to_mat4(ob, obmat);
-       mul_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);
        Scene *scene= CTX_data_scene(C);
-       MovieTrackingTrack *track, *axis_track= NULL;
-       Object *camera= scene->camera;
-       Object *parent= camera;
+       MovieTracking *tracking= &clip->tracking;
+       MovieTrackingObject *tracking_object;
+       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},
@@ -2021,21 +2269,30 @@ static int set_floor_exec(bContext *C, wmOperator *op)
 
        if(count_selected_bundles(C)!=3) {
                BKE_report(op->reports, RPT_ERROR, "Three tracks with bundles are needed to orient the floor");
+
                return OPERATOR_CANCELLED;
        }
 
-       if(scene->camera->parent)
-               parent= scene->camera->parent;
+       tracking_object= BKE_tracking_active_object(tracking);
+       tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
+       act_track= BKE_tracking_active_track(tracking);
 
-       BKE_get_tracking_mat(scene, NULL, mat);
+       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, camera, mat);
 
        /* get 3 bundles to use as reference */
-       track= clip->tracking.tracks.first;
+       track= tracksbase->first;
        while(track && tot<3) {
                if(track->flag&TRACK_HAS_BUNDLE && TRACK_VIEW_SELECTED(sc, track)) {
                        mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
 
-                       if(tot==0 || track==clip->tracking.act_track)
+                       if(tot==0 || track==act_track)
                                copy_v3_v3(orig, vec[tot]);
                        else
                                axis_track= track;
@@ -2052,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]);
@@ -2065,25 +2329,30 @@ static int set_floor_exec(bContext *C, wmOperator *op)
        mat[3][1]= orig[1];
        mat[3][2]= orig[2];
 
-       invert_m4(mat);
+       if(tracking_object->flag&TRACKING_OBJECT_CAMERA) {
+               invert_m4(mat);
 
-       object_to_mat4(parent, obmat);
-       mul_m4_m4m4(mat, obmat, mat);
-       mul_m4_m4m4(newmat, mat, rot);
-       object_apply_mat4(parent, newmat, 0, 0);
+               object_to_mat4(object, obmat);
+               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(parent->loc[2]<0) {
-               invert_m4(rot);
-               mul_m4_m4m4(newmat, mat, rot);
-               object_apply_mat4(parent, newmat, 0, 0);
+               /* make camera have positive z-coordinate */
+               if(object->loc[2]<0) {
+                       invert_m4(rot);
+                       mult_m4_m4m4(newmat, rot, mat);
+                       object_apply_mat4(object, newmat, 0, 0);
+               }
+       }
+       else {
+               object_apply_mat4(object, mat, 0, 0);
        }
 
-       where_is_object(scene, parent);
-       set_axis(scene, parent, axis_track, 'X');
+       where_is_object(scene, object);
+       set_axis(scene, object, clip, tracking_object, axis_track, 'X');
 
        DAG_id_tag_update(&clip->id, 0);
-       DAG_id_tag_update(&parent->id, OB_RECALC_OB);
+       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);
@@ -2091,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 *********************/
@@ -2112,9 +2390,12 @@ static int set_axis_exec(bContext *C, wmOperator *op)
 {
        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;
+       Object *object;
+       ListBase *tracksbase;
        int axis= RNA_enum_get(op->ptr, "axis");
 
        if(count_selected_bundles(C)!=1) {
@@ -2123,10 +2404,16 @@ static int set_axis_exec(bContext *C, wmOperator *op)
                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");
 
-       track= clip->tracking.tracks.first;
+               return OPERATOR_CANCELLED;
+       }
+
+       tracksbase= BKE_tracking_object_tracks(tracking, tracking_object);
+
+       track=tracksbase->first;
        while(track) {
                if(TRACK_VIEW_SELECTED(sc, track))
                        break;
@@ -2134,10 +2421,10 @@ static int set_axis_exec(bContext *C, wmOperator *op)
                track= track->next;
        }
 
-       set_axis(scene, parent, 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(&parent->id, OB_RECALC_OB);
+       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);
@@ -2160,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;
@@ -2171,29 +2458,37 @@ 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;
+       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");
 
-       BKE_get_tracking_mat(scene, NULL, mat);
+               return OPERATOR_CANCELLED;
+       }
+
+       BKE_get_tracking_mat(scene, camera, mat);
 
-       track= clip->tracking.tracks.first;
+       track= tracksbase->first;
        while(track) {
                if(TRACK_VIEW_SELECTED(sc, track)) {
                        mul_v3_m4v3(vec[tot], mat, track->bundle_pos);
@@ -2208,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);
@@ -2221,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);
@@ -2243,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;
@@ -2296,11 +2665,14 @@ static int hide_tracks_exec(bContext *C, wmOperator *op)
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTrackingTrack *track;
+       MovieTracking *tracking= &clip->tracking;
+       ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
+       MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
        int unselected;
 
        unselected= RNA_boolean_get(op->ptr, "unselected");
 
-       track= clip->tracking.tracks.first;
+       track= tracksbase->first;
        while(track) {
                if(unselected==0 && TRACK_VIEW_SELECTED(sc, track)) {
                        track->flag|= TRACK_HIDDEN;
@@ -2311,7 +2683,7 @@ static int hide_tracks_exec(bContext *C, wmOperator *op)
                track= track->next;
        }
 
-       if(clip->tracking.act_track && clip->tracking.act_track->flag&TRACK_HIDDEN)
+       if(act_track && act_track->flag&TRACK_HIDDEN)
                clip->tracking.act_track= NULL;
 
        if(unselected==0) {
@@ -2348,9 +2720,10 @@ static int hide_tracks_clear_exec(bContext *C, wmOperator *UNUSED(op))
 {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
+       ListBase *tracksbase= BKE_tracking_get_tracks(&clip->tracking);
        MovieTrackingTrack *track;
 
-       track= clip->tracking.tracks.first;
+       track= tracksbase->first;
        while(track) {
                track->flag&= ~TRACK_HIDDEN;
 
@@ -2401,8 +2774,11 @@ 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);
-       MovieTrackingTrack *track= clip->tracking.tracks.first;
+       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;
        int placement= RNA_enum_get(op->ptr, "placement");
        int margin= RNA_int_get(op->ptr, "margin");
        int min_trackability= RNA_int_get(op->ptr, "min_trackability");
@@ -2424,7 +2800,8 @@ static int detect_features_exec(bContext *C, wmOperator *op)
                track= track->next;
        }
 
-       BKE_tracking_detect_fast(&clip->tracking, ibuf, sc->user.framenr, margin, min_trackability, min_distance, layer, place_outside_layer);
+       BKE_tracking_detect_fast(tracking, tracksbase, ibuf, sc->user.framenr, margin,
+                               min_trackability, min_distance, layer, place_outside_layer);
 
        IMB_freeImBuf(ibuf);
 
@@ -2473,7 +2850,7 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
        int delta;
 
        if(pos<=1) {    /* jump to path */
-               track= clip->tracking.act_track;
+               track= BKE_tracking_active_track(&clip->tracking);
 
                if(!track)
                        return OPERATOR_CANCELLED;
@@ -2493,13 +2870,16 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
                if(clip->tracking.reconstruction.flag&TRACKING_RECONSTRUCTED) {
                        int a= sc->user.framenr;
                        MovieTracking *tracking= &clip->tracking;
+                       MovieTrackingObject *object= BKE_tracking_active_object(tracking);
 
                        delta= pos == 3 ? 1 : -1;
 
                        a+= delta;
 
                        while(a+delta >= SFRA && a+delta <= EFRA) {
-                               MovieReconstructedCamera *cam= BKE_tracking_get_reconstructed_camera(tracking, a);
+                               MovieReconstructedCamera *cam;
+
+                               cam= BKE_tracking_get_reconstructed_camera(tracking, object, a);
 
                                if(!cam) {
                                        sc->user.framenr= a;
@@ -2556,16 +2936,18 @@ static int join_tracks_exec(bContext *C, wmOperator *op)
 {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
+       MovieTracking *tracking= &clip->tracking;
+       ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
        MovieTrackingTrack *act_track, *track, *next;
 
-       act_track= clip->tracking.act_track;
+       act_track= BKE_tracking_active_track(tracking);
 
        if(!act_track) {
                BKE_report(op->reports, RPT_ERROR, "No active track to join to");
                return OPERATOR_CANCELLED;
        }
 
-       track= clip->tracking.tracks.first;
+       track= tracksbase->first;
        while(track) {
                if(TRACK_VIEW_SELECTED(sc, track) && track!=act_track) {
                        if(!BKE_tracking_test_join_tracks(act_track, track)) {
@@ -2577,7 +2959,7 @@ static int join_tracks_exec(bContext *C, wmOperator *op)
                track= track->next;
        }
 
-       track= clip->tracking.tracks.first;
+       track= tracksbase->first;
        while(track) {
                next= track->next;
 
@@ -2585,7 +2967,7 @@ static int join_tracks_exec(bContext *C, wmOperator *op)
                        BKE_tracking_join_tracks(act_track, track);
 
                        BKE_tracking_free_track(track);
-                       BLI_freelinkN(&clip->tracking.tracks, track);
+                       BLI_freelinkN(tracksbase, track);
                }
 
                track= next;
@@ -2618,7 +3000,8 @@ static int lock_tracks_exec(bContext *C, wmOperator *op)
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
-       MovieTrackingTrack *track= tracking->tracks.first;
+       ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
+       MovieTrackingTrack *track= tracksbase->first;
        int action= RNA_enum_get(op->ptr, "action");
 
        while(track) {
@@ -2667,12 +3050,14 @@ static int track_copy_color_exec(bContext *C, wmOperator *UNUSED(op))
 {
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
-       MovieTrackingTrack *track, *act_track= clip->tracking.act_track;
+       MovieTracking *tracking= &clip->tracking;
+       ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
+       MovieTrackingTrack *track, *act_track= BKE_tracking_active_track(tracking);
 
        if(!act_track)
                return OPERATOR_CANCELLED;
 
-       track= clip->tracking.tracks.first;
+       track= tracksbase->first;
        while(track) {
                if(TRACK_VIEW_SELECTED(sc, track) && track!=act_track) {
                        track->flag&= ~TRACK_CUSTOMCOLOR;
@@ -2713,11 +3098,12 @@ static int stabilize_2d_add_exec(bContext *C, wmOperator *UNUSED(op))
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
+       ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
        MovieTrackingTrack *track;
        MovieTrackingStabilization *stab= &tracking->stabilization;
        int update= 0;
 
-       track= tracking->tracks.first;
+       track= tracksbase->first;
        while(track) {
                if(TRACK_VIEW_SELECTED(sc, track) && (track->flag&TRACK_USE_2D_STAB)==0) {
                        track->flag|= TRACK_USE_2D_STAB;
@@ -2762,10 +3148,11 @@ static int stabilize_2d_remove_exec(bContext *C, wmOperator *UNUSED(op))
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
        MovieTrackingStabilization *stab= &tracking->stabilization;
+       ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
        MovieTrackingTrack *track;
        int a= 0, update= 0;
 
-       track= tracking->tracks.first;
+       track= tracksbase->first;
        while(track) {
                if(track->flag&TRACK_USE_2D_STAB) {
                        if(a==stab->act_track) {
@@ -2820,10 +3207,11 @@ static int stabilize_2d_select_exec(bContext *C, wmOperator *UNUSED(op))
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
+       ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
        MovieTrackingTrack *track;
        int update= 0;
 
-       track= tracking->tracks.first;
+       track= tracksbase->first;
        while(track) {
                if(track->flag&TRACK_USE_2D_STAB) {
                        BKE_tracking_track_flag(track, TRACK_AREA_ALL, SELECT, 0);
@@ -2862,11 +3250,12 @@ static int stabilize_2d_set_rotation_exec(bContext *C, wmOperator *UNUSED(op))
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
+       MovieTrackingTrack *act_track= BKE_tracking_active_track(tracking);
 
-       if(tracking->act_track) {
+       if(act_track) {
                MovieTrackingStabilization *stab= &tracking->stabilization;
 
-               stab->rot_track= tracking->act_track;
+               stab->rot_track= act_track;
                stab->ok= 0;
 
                DAG_id_tag_update(&clip->id, 0);
@@ -2960,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;
                                }
                        }
@@ -2991,7 +3380,8 @@ static int clean_tracks_exec(bContext *C, wmOperator *op)
        SpaceClip *sc= CTX_wm_space_clip(C);
        MovieClip *clip= ED_space_clip(sc);
        MovieTracking *tracking= &clip->tracking;
-       MovieTrackingTrack *track, *next, *act_track= clip->tracking.act_track;
+       ListBase *tracksbase= BKE_tracking_get_tracks(tracking);
+       MovieTrackingTrack *track, *next, *act_track= BKE_tracking_active_track(tracking);
        int frames= RNA_int_get(op->ptr, "frames");
        int action= RNA_enum_get(op->ptr, "action");
        float error= RNA_float_get(op->ptr, "error");
@@ -2999,7 +3389,7 @@ static int clean_tracks_exec(bContext *C, wmOperator *op)
        if(error && action==TRACKING_CLEAN_DELETE_SEGMENT)
                action= TRACKING_CLEAN_DELETE_TRACK;
 
-       track= tracking->tracks.first;
+       track= tracksbase->first;
        while(track) {
                next= track->next;
 
@@ -3018,7 +3408,7 @@ static int clean_tracks_exec(bContext *C, wmOperator *op)
                                                clip->tracking.act_track= NULL;
 
                                        BKE_tracking_free_track(track);
-                                       BLI_freelinkN(&clip->tracking.tracks, track);
+                                       BLI_freelinkN(tracksbase, track);
                                        track= NULL;
                                }
 
@@ -3028,7 +3418,7 @@ static int clean_tracks_exec(bContext *C, wmOperator *op)
                                                clip->tracking.act_track= NULL;
 
                                        BKE_tracking_free_track(track);
-                                       BLI_freelinkN(&clip->tracking.tracks, track);
+                                       BLI_freelinkN(tracksbase, track);
                                }
                        }
                }
@@ -3045,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);
 }
@@ -3085,3 +3475,142 @@ void CLIP_OT_clean_tracks(wmOperatorType *ot)
        RNA_def_float(ot->srna, "error", 0.0f, 0.0f, FLT_MAX, "Reprojection Error", "Effect on tracks with have got larger reprojection error", 0.0f, 100.0f);
        RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Cleanup action to execute");
 }
+
+/********************** add tracking object *********************/
+
+static int tracking_object_new_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       SpaceClip *sc= CTX_wm_space_clip(C);
+       MovieClip *clip= ED_space_clip(sc);
+       MovieTracking *tracking= &clip->tracking;
+
+       BKE_tracking_new_object(tracking, "Object");
+
+       WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
+
+       return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_tracking_object_new(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Add Tracking Object";
+       ot->description= "Add new object for tracking";
+       ot->idname= "CLIP_OT_tracking_object_new";
+
+       /* api callbacks */
+       ot->exec= tracking_object_new_exec;
+       ot->poll= ED_space_clip_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/********************** remove tracking object *********************/
+
+static int tracking_object_remove_exec(bContext *C, wmOperator *op)
+{
+       SpaceClip *sc= CTX_wm_space_clip(C);
+       MovieClip *clip= ED_space_clip(sc);
+       MovieTracking *tracking= &clip->tracking;
+       MovieTrackingObject *object;
+
+       object= BKE_tracking_active_object(tracking);
+
+       if(object->flag&TRACKING_OBJECT_CAMERA) {
+               BKE_report(op->reports, RPT_WARNING, "Object used for camera tracking can't be deleted");
+               return OPERATOR_CANCELLED;
+       }
+
+       BKE_tracking_remove_object(tracking, object);
+
+       WM_event_add_notifier(C, NC_MOVIECLIP|NA_EDITED, clip);
+
+       return OPERATOR_FINISHED;
+}
+
+void CLIP_OT_tracking_object_remove(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Movie Tracking Object";
+       ot->description= "Remove object for tracking";
+       ot->idname= "CLIP_OT_tracking_object_remove";
+
+       /* api callbacks */
+       ot->exec= tracking_object_remove_exec;
+       ot->poll= ED_space_clip_poll;
+
+       /* 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;
+}