Rotation support for motion tracking markers

Implemented general transformation tool Rotation for motion tracking data.
Mainly used to rotate pattern of markers.

To achieve most of usability, added configurable pivot point which is in fact
was median point before, but now can be chosen from boundbox center, median point
or individual centers. Individual centers means transformation would be performed
around marker's position, which is useful for rotation and scale.

Also implemented alternative scaling transformation -- hit S, S leads to
scaling of pattern area only.

TODO:
- clamping in some cases isn't working well, but that's easier to be resolved
  after moving search are to marker.
- Update startup.blend so clip editor in Motion Tracking screen would be set to
  Individual Centers by default.
This commit is contained in:
2012-05-18 09:33:50 +00:00
parent f21cd531d6
commit 2da49c4a8f
10 changed files with 190 additions and 70 deletions

View File

@@ -54,7 +54,8 @@ class CLIP_HT_header(Header):
if clip:
if sc.view == 'CLIP':
layout.prop(sc, "mode", text="")
if sc.view == 'GRAPH':
layout.prop(sc, "pivot_point", text="", icon_only=True)
elif sc.view == 'GRAPH':
row = layout.row(align=True)
if sc.show_filters:

View File

@@ -7612,6 +7612,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
{
MovieClip *clip;
bScreen *sc;
for (clip = main->movieclip.first; clip; clip = clip->id.next) {
MovieTrackingTrack *track;
@@ -7643,6 +7644,24 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
track = track->next;
}
}
for (sc = main->screen.first; sc; sc = sc->id.next) {
ScrArea *sa;
for (sa = sc->areabase.first; sa; sa = sa->next) {
SpaceLink *sl;
for (sl = sa->spacedata.first; sl; sl = sl->next) {
if (sl->spacetype == SPACE_CLIP) {
SpaceClip *sclip = (SpaceClip *)sl;
if (sclip->around == 0) {
sclip->around = V3D_CENTROID;
}
}
}
}
}
}
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */

View File

@@ -58,6 +58,7 @@ struct Mask *ED_space_clip_mask(struct SpaceClip *sc);
void ED_space_clip_size(struct SpaceClip *sc, int *width, int *height);
void ED_space_clip_zoom(struct SpaceClip *sc, ARegion *ar, float *zoomx, float *zoomy);
void ED_space_clip_aspect(struct SpaceClip *sc, float *aspx, float *aspy);
void ED_space_clip_aspect_dimension_aware(struct SpaceClip *sc, float *aspx, float *aspy);
void ED_space_clip_mask_size(struct SpaceClip *sc, int *width, int *height);
void ED_space_clip_mask_aspect(struct SpaceClip *sc, float *aspx, float *aspy);

View File

@@ -249,9 +249,15 @@ void ED_space_clip_size(SpaceClip *sc, int *width, int *height)
void ED_space_clip_mask_size(SpaceClip *sc, int *width, int *height)
{
if(!sc->mask) {
*width= 0;
*height= 0;
/* quite the same as ED_space_clip_size, but it also runs aspect correction on output resolution
* this is needed because mask should be rasterized with exactly the same resolution as
* currently displaying frame and it doesn't have access to aspect correction currently
* used for display. (sergey)
*/
if (!sc->mask) {
*width = 0;
*height = 0;
} else {
float aspx, aspy;
@@ -306,6 +312,33 @@ void ED_space_clip_aspect(SpaceClip *sc, float *aspx, float *aspy)
*aspx = *aspy = 1.0f;
}
void ED_space_clip_aspect_dimension_aware(SpaceClip *sc, float *aspx, float *aspy)
{
int w, h;
/* most of tools does not require aspect to be returned with dimensions correction
* due to they're invariant to this stuff, but some transformation tools like rotation
* should be aware of aspect correction caused by different resolution in different
* directions.
* mainly this is sued for transformation stuff
*/
ED_space_clip_aspect(sc, aspx, aspy);
ED_space_clip_size(sc, &w, &h);
*aspx *= (float)w;
*aspy *= (float)h;
if(*aspx < *aspy) {
*aspy= *aspy / *aspx;
*aspx= 1.0f;
}
else {
*aspx= *aspx / *aspy;
*aspy= 1.0f;
}
}
void ED_clip_update_frame(const Main *mainp, int cfra)
{
wmWindowManager *wm;

View File

@@ -35,6 +35,7 @@
#include "DNA_scene_types.h"
#include "DNA_mask_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_view3d_types.h" /* for pivot point */
#include "MEM_guardedalloc.h"
@@ -239,6 +240,7 @@ static SpaceLink *clip_new(const bContext *C)
sc->zoom = 1.0f;
sc->path_length = 20;
sc->scopes.track_preview_height = 120;
sc->around = V3D_LOCAL;
/* header */
ar = MEM_callocN(sizeof(ARegion), "header for clip");

View File

@@ -244,21 +244,17 @@ void projectIntView(TransInfo *t, const float vec[3], int adr[2])
}
else if (t->spacetype==SPACE_CLIP) {
float v[2];
float aspx = 1.0f, aspy = 1.0f;
copy_v2_v2(v, vec);
if (t->options & CTX_MOVIECLIP) {
float aspx, aspy;
ED_space_clip_aspect(t->sa->spacedata.first, &aspx, &aspy);
v[0] /= aspx;
v[1] /= aspy;
}
else if (t->options & CTX_MASK) {
float aspx, aspy;
if (t->options & CTX_MOVIECLIP)
ED_space_clip_aspect_dimension_aware(t->sa->spacedata.first, &aspx, &aspy);
else if (t->options & CTX_MASK)
ED_space_clip_mask_aspect(t->sa->spacedata.first, &aspx, &aspy);
v[0] /= aspx;
v[1] /= aspy;
}
v[0] /= aspx;
v[1] /= aspy;
UI_view2d_to_region_no_clip(t->view, v[0], v[1], adr, adr+1);
}
@@ -316,12 +312,10 @@ void applyAspectRatio(TransInfo *t, float vec[2])
if (t->options & CTX_MOVIECLIP) {
int width, height;
ED_space_clip_size(sc, &width, &height);
ED_space_clip_aspect(sc, &aspx, &aspy);
ED_space_clip_aspect_dimension_aware(sc, &aspx, &aspy);
vec[0] *= width / aspx;
vec[1] *= height / aspy;
vec[0] /= aspx;
vec[1] /= aspy;
}
else if (t->options & CTX_MASK) {
ED_space_clip_mask_aspect(sc, &aspx, &aspy);
@@ -357,12 +351,10 @@ void removeAspectRatio(TransInfo *t, float vec[2])
float aspx, aspy;
if (t->options & CTX_MOVIECLIP) {
int width, height;
ED_space_clip_size(sc, &width, &height);
ED_space_clip_aspect(sc, &aspx, &aspy);
ED_space_clip_aspect_dimension_aware(sc, &aspx, &aspy);
vec[0] *= aspx / width;
vec[1] *= aspy / height;
vec[0] *= aspx;
vec[1] *= aspy;
}
else if (t->options & CTX_MASK) {
ED_space_clip_aspect(sc, &aspx, &aspy);
@@ -711,7 +703,7 @@ int transformEvent(TransInfo *t, wmEvent *event)
t->redraw |= TREDRAW_HARD;
}
else if (t->mode == TFM_TRANSLATION) {
if(t->options & (CTX_MOVIECLIP | CTX_MASK)) {
if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
restoreTransObjects(t);
t->flag ^= T_ALT_TRANSFORM;
@@ -721,7 +713,7 @@ int transformEvent(TransInfo *t, wmEvent *event)
break;
case TFM_MODAL_ROTATE:
/* only switch when... */
if (!(t->options & CTX_TEXTURE) && !(t->options & CTX_MOVIECLIP)) {
if (!(t->options & CTX_TEXTURE) && !(t->options & (CTX_MOVIECLIP | CTX_MASK))) {
if ( ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) {
resetTransRestrictions(t);
@@ -748,6 +740,14 @@ int transformEvent(TransInfo *t, wmEvent *event)
initSnapping(t, NULL); // need to reinit after mode change
t->redraw |= TREDRAW_HARD;
}
else if (t->mode == TFM_RESIZE) {
if (t->options & CTX_MOVIECLIP) {
restoreTransObjects(t);
t->flag ^= T_ALT_TRANSFORM;
t->redraw |= TREDRAW_HARD;
}
}
break;
case TFM_MODAL_SNAP_INV_ON:
@@ -976,7 +976,7 @@ int transformEvent(TransInfo *t, wmEvent *event)
break;
case RKEY:
/* only switch when... */
if (!(t->options & CTX_TEXTURE) && !(t->options & CTX_MOVIECLIP)) {
if (!(t->options & CTX_TEXTURE)) {
if ( ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) {
resetTransRestrictions(t);
@@ -2737,6 +2737,9 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
{
copy_v3_v3(center, td->center);
}
else if (t->options & CTX_MOVIECLIP) {
copy_v3_v3(center, td->center);
}
else {
copy_v3_v3(center, t->center);
}
@@ -3020,6 +3023,10 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
{
center = td->center;
}
if (t->options & CTX_MOVIECLIP) {
center = td->center;
}
}
if (t->flag & T_POINTS) {

View File

@@ -5388,23 +5388,24 @@ typedef struct TransDataTracking {
short coord;
} TransDataTracking;
static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt, MovieTrackingTrack *track,
int area, float *loc, float *rel, float *off)
static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTracking *tdt,
MovieTrackingTrack *track, MovieTrackingMarker *marker,
int area, float *loc, float *rel, float *off, float aspx, float aspy)
{
int anchor = area == TRACK_AREA_POINT && off;
tdt->mode = transDataTracking_ModeTracks;
if (anchor) {
td2d->loc[0] = rel[0]; /* hold original location */
td2d->loc[1] = rel[1];
td2d->loc[0] = rel[0] * aspx; /* hold original location */
td2d->loc[1] = rel[1] * aspy;
tdt->loc= loc;
td2d->loc2d = loc; /* current location */
}
else {
td2d->loc[0] = loc[0]; /* hold original location */
td2d->loc[1] = loc[1];
td2d->loc[0] = loc[0] * aspx; /* hold original location */
td2d->loc[1] = loc[1] * aspy;
td2d->loc2d = loc; /* current location */
}
@@ -5418,8 +5419,8 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra
if (rel) {
if (!anchor) {
td2d->loc[0] += rel[0];
td2d->loc[1] += rel[1];
td2d->loc[0] += rel[0] * aspx;
td2d->loc[1] += rel[1] * aspy;
}
copy_v2_v2(tdt->srelative, rel);
@@ -5430,9 +5431,12 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra
td->flag = 0;
td->loc = td2d->loc;
copy_v3_v3(td->center, td->loc);
copy_v3_v3(td->iloc, td->loc);
//copy_v3_v3(td->center, td->loc);
td->center[0] = marker->pos[0] * aspx;
td->center[1] = marker->pos[1] * aspy;
memset(td->axismtx, 0, sizeof(td->axismtx));
td->axismtx[2][2] = 1.0f;
@@ -5447,28 +5451,36 @@ static void markerToTransDataInit(TransData *td, TransData2D *td2d, TransDataTra
}
static void trackToTransData(SpaceClip *sc, TransData *td, TransData2D *td2d,
TransDataTracking *tdt, MovieTrackingTrack *track)
TransDataTracking *tdt, MovieTrackingTrack *track, float aspx, float aspy)
{
MovieTrackingMarker *marker = BKE_tracking_ensure_marker(track, sc->user.framenr);
tdt->flag = marker->flag;
marker->flag &= ~(MARKER_DISABLED|MARKER_TRACKED);
markerToTransDataInit(td++, td2d++, tdt++, track, TRACK_AREA_POINT, track->offset, marker->pos, track->offset);
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_POINT,
track->offset, marker->pos, track->offset, aspx, aspy);
if (track->flag & SELECT)
markerToTransDataInit(td++, td2d++, tdt++, track, TRACK_AREA_POINT, marker->pos, NULL, NULL);
if (track->flag & SELECT) {
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_POINT,
marker->pos, NULL, NULL, aspx, aspy);
}
if (track->pat_flag & SELECT) {
markerToTransDataInit(td++, td2d++, tdt++, track, TRACK_AREA_PAT, marker->pattern_corners[0], marker->pos, NULL);
markerToTransDataInit(td++, td2d++, tdt++, track, TRACK_AREA_PAT, marker->pattern_corners[1], marker->pos, NULL);
markerToTransDataInit(td++, td2d++, tdt++, track, TRACK_AREA_PAT, marker->pattern_corners[2], marker->pos, NULL);
markerToTransDataInit(td++, td2d++, tdt++, track, TRACK_AREA_PAT, marker->pattern_corners[3], marker->pos, NULL);
int a;
for (a = 0; a < 4; a++) {
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_PAT,
marker->pattern_corners[a], marker->pos, NULL, aspx, aspy);
}
}
if (track->search_flag & SELECT) {
markerToTransDataInit(td++, td2d++, tdt++, track, TRACK_AREA_SEARCH, track->search_min, marker->pos, NULL);
markerToTransDataInit(td++, td2d++, tdt++, track, TRACK_AREA_SEARCH, track->search_max, marker->pos, NULL);
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_SEARCH,
track->search_min, marker->pos, NULL, aspx, aspy);
markerToTransDataInit(td++, td2d++, tdt++, track, marker, TRACK_AREA_SEARCH,
track->search_max, marker->pos, NULL, aspx, aspy);
}
}
@@ -5495,6 +5507,7 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
MovieTrackingMarker *marker;
TransDataTracking *tdt;
int framenr = sc->user.framenr;
float aspx, aspy;
/* count */
t->total = 0;
@@ -5522,6 +5535,8 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
if (t->total == 0)
return;
ED_space_clip_aspect_dimension_aware(sc, &aspx, &aspy);
td = t->data = MEM_callocN(t->total*sizeof(TransData), "TransTracking TransData");
td2d = t->data2d = MEM_callocN(t->total*sizeof(TransData2D), "TransTracking TransData2D");
tdt = t->customData = MEM_callocN(t->total*sizeof(TransDataTracking), "TransTracking TransDataTracking");
@@ -5534,7 +5549,7 @@ static void createTransTrackingTracksData(bContext *C, TransInfo *t)
if (TRACK_VIEW_SELECTED(sc, track) && (track->flag & TRACK_LOCKED) == 0) {
marker = BKE_tracking_get_marker(track, framenr);
trackToTransData(sc, td, td2d, tdt, track);
trackToTransData(sc, td, td2d, tdt, track, aspx, aspy);
/* offset */
td++;
@@ -5704,9 +5719,6 @@ static void createTransTrackingData(bContext *C, TransInfo *t)
if (!clip || width == 0 || height == 0)
return;
if (!ELEM(t->mode, TFM_RESIZE, TFM_TRANSLATION))
return;
if (ar->regiontype == RGN_TYPE_PREVIEW) {
/* transformation was called from graph editor */
createTransTrackingCurvesData(C, t);
@@ -5774,10 +5786,14 @@ static void cancelTransTracking(TransInfo *t)
void flushTransTracking(TransInfo *t)
{
SpaceClip *sc = t->sa->spacedata.first;
TransData *td;
TransData2D *td2d;
TransDataTracking *tdt;
int a;
float aspx, aspy;
ED_space_clip_aspect_dimension_aware(sc, &aspx, &aspy);
if (t->state == TRANS_CANCEL)
cancelTransTracking(t);
@@ -5785,31 +5801,46 @@ void flushTransTracking(TransInfo *t)
/* flush to 2d vector from internally used 3d vector */
for (a=0, td= t->data, td2d= t->data2d, tdt= t->customData; a<t->total; a++, td2d++, td++, tdt++) {
if (tdt->mode == transDataTracking_ModeTracks) {
float loc2d[2];
if (t->mode == TFM_ROTATION && tdt->area == TRACK_AREA_SEARCH) {
continue;
}
loc2d[0] = td2d->loc[0] / aspx;
loc2d[1] = td2d->loc[1] / aspy;
if (t->flag & T_ALT_TRANSFORM) {
if (tdt->area == TRACK_AREA_POINT && tdt->relative) {
float d[2], d2[2];
if (t->mode == TFM_RESIZE) {
if (tdt->area != TRACK_AREA_PAT)
continue;
}
else if (t->mode == TFM_TRANSLATION) {
if (tdt->area == TRACK_AREA_POINT && tdt->relative) {
float d[2], d2[2];
if (!tdt->smarkers) {
tdt->smarkers = MEM_callocN(sizeof(*tdt->smarkers)*tdt->markersnr, "flushTransTracking markers");
for (a = 0; a < tdt->markersnr; a++)
copy_v2_v2(tdt->smarkers[a], tdt->markers[a].pos);
if (!tdt->smarkers) {
tdt->smarkers = MEM_callocN(sizeof(*tdt->smarkers)*tdt->markersnr, "flushTransTracking markers");
for (a = 0; a < tdt->markersnr; a++)
copy_v2_v2(tdt->smarkers[a], tdt->markers[a].pos);
}
sub_v2_v2v2(d, loc2d, tdt->soffset);
sub_v2_v2(d, tdt->srelative);
sub_v2_v2v2(d2, loc2d, tdt->srelative);
for (a= 0; a<tdt->markersnr; a++)
add_v2_v2v2(tdt->markers[a].pos, tdt->smarkers[a], d2);
negate_v2_v2(td2d->loc2d, d);
}
sub_v2_v2v2(d, td2d->loc, tdt->soffset);
sub_v2_v2(d, tdt->srelative);
sub_v2_v2v2(d2, td2d->loc, tdt->srelative);
for (a= 0; a<tdt->markersnr; a++)
add_v2_v2v2(tdt->markers[a].pos, tdt->smarkers[a], d2);
negate_v2_v2(td2d->loc2d, d);
}
}
if (tdt->area!=TRACK_AREA_POINT || tdt->relative==0) {
td2d->loc2d[0] = td2d->loc[0];
td2d->loc2d[1] = td2d->loc[1];
td2d->loc2d[0] = loc2d[0];
td2d->loc2d[1] = loc2d[1];
if (tdt->relative)
sub_v2_v2(td2d->loc2d, tdt->relative);

View File

@@ -660,6 +660,10 @@ static void recalcData_spaceclip(TransInfo *t)
if (TRACK_AREA_SELECTED(track, TRACK_AREA_SEARCH))
BKE_tracking_clamp_track(track, CLAMP_SEARCH_DIM);
}
else if (t->mode == TFM_ROTATION) {
if (TRACK_AREA_SELECTED(track, TRACK_AREA_PAT))
BKE_tracking_clamp_track(track, CLAMP_PAT_DIM);
}
}
track = track->next;
@@ -1114,6 +1118,11 @@ int initTransInfo(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event)
t->view = &ar->v2d;
t->around = sipo->around;
}
else if (t->spacetype==SPACE_CLIP) {
SpaceClip *sclip = sa->spacedata.first;
t->view = &ar->v2d;
t->around = sclip->around;
}
else {
if (ar) {
// XXX for now, get View2D from the active region

View File

@@ -532,7 +532,7 @@ typedef struct SpaceClip {
short dope_sort; /* sort order in dopesheet view */
short dope_flag; /* dopsheet view flags */
int pad3;
int around; /* pivot point for transforms */
/* **** mask editing **** */
struct Mask *mask;

View File

@@ -2989,6 +2989,16 @@ static void rna_def_space_clip(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem pivot_items[] = {
{V3D_CENTER, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center",
"Pivot around bounding box center of selected object(s)"},
{V3D_LOCAL, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION,
"Individual Origins", "Pivot around each object's own origin"},
{V3D_CENTROID, "MEDIAN_POINT", ICON_ROTATECENTER, "Median Point",
"Pivot around the median point of selected objects"},
{0, NULL, 0, NULL, NULL}
};
srna = RNA_def_struct(brna, "SpaceClipEditor", "Space");
RNA_def_struct_sdna(srna, "SpaceClip");
RNA_def_struct_ui_text(srna, "Space Clip Editor", "Clip editor space data");
@@ -3182,6 +3192,13 @@ static void rna_def_space_clip(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Grease Pencil Source", "Where the grease pencil comes from");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
/* pivot point */
prop = RNA_def_property(srna, "pivot_point", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "around");
RNA_def_property_enum_items(prop, pivot_items);
RNA_def_property_ui_text(prop, "Pivot Point", "Pivot center for rotation/scaling");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL);
/* ** dopesheet ** */
/* dopesheet sort */