Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_operators/__init__.py1
-rw-r--r--release/scripts/startup/bl_operators/fcurve_euler_filter.py78
-rw-r--r--source/blender/editors/space_graph/graph_edit.c123
-rw-r--r--source/blender/editors/space_graph/graph_intern.h1
-rw-r--r--source/blender/editors/space_graph/graph_ops.c1
5 files changed, 108 insertions, 96 deletions
diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py
index 599cd6c1889..2a42cfbacb8 100644
--- a/release/scripts/startup/bl_operators/__init__.py
+++ b/release/scripts/startup/bl_operators/__init__.py
@@ -25,7 +25,6 @@ if "bpy" in locals():
_modules = (
"add_mesh_torus",
"animsys_update",
- "fcurve_euler_filter",
"image",
"mesh",
"nla",
diff --git a/release/scripts/startup/bl_operators/fcurve_euler_filter.py b/release/scripts/startup/bl_operators/fcurve_euler_filter.py
deleted file mode 100644
index c7b249a1d0c..00000000000
--- a/release/scripts/startup/bl_operators/fcurve_euler_filter.py
+++ /dev/null
@@ -1,78 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# <pep8 compliant>
-
-import bpy
-
-
-def main(context):
- from math import pi
-
- def cleanupEulCurve(fcv):
- keys = []
-
- for k in fcv.keyframe_points:
- keys.append([k.handle_left.copy(), k.co.copy(), k.handle_right.copy()])
-
- for i in range(len(keys)):
- cur = keys[i]
- prev = keys[i - 1] if i > 0 else None
- next = keys[i + 1] if i < len(keys) - 1 else None
-
- if prev is None:
- continue
-
- th = pi
- if abs(prev[1][1] - cur[1][1]) >= th: # more than 180 degree jump
- fac = pi * 2.0
- if prev[1][1] > cur[1][1]:
- while abs(cur[1][1] - prev[1][1]) >= th: # < prev[1][1]:
- cur[0][1] += fac
- cur[1][1] += fac
- cur[2][1] += fac
- elif prev[1][1] < cur[1][1]:
- while abs(cur[1][1] - prev[1][1]) >= th:
- cur[0][1] -= fac
- cur[1][1] -= fac
- cur[2][1] -= fac
-
- for i in range(len(keys)):
- for x in range(2):
- fcv.keyframe_points[i].handle_left[x] = keys[i][0][x]
- fcv.keyframe_points[i].co[x] = keys[i][1][x]
- fcv.keyframe_points[i].handle_right[x] = keys[i][2][x]
-
- flist = bpy.context.active_object.animation_data.action.fcurves
- for f in flist:
- if f.select and f.data_path.endswith("rotation_euler"):
- cleanupEulCurve(f)
-
-
-class DiscontFilterOp(bpy.types.Operator):
- """Fixes the most common causes of gimbal lock in the fcurves of the active bone"""
- bl_idname = "graph.euler_filter"
- bl_label = "Filter out discontinuities in the active fcurves"
-
- @classmethod
- def poll(cls, context):
- return context.active_object != None
-
- def execute(self, context):
- main(context)
- return {'FINISHED'}
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index fdd43aa0566..deffc60019e 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -1501,12 +1501,13 @@ static int graphkeys_handletype_exec(bContext *C, wmOperator *op)
* of values to -180 degrees to 180 degrees.
*/
-#if 0 // XXX this is not ready for the primetime yet
-
/* set of three euler-rotation F-Curves */
typedef struct tEulerFilter {
+ struct tEulerFilter *next, *prev;
+
ID *id; /* ID-block which owns the channels */
- FCurve (*fcurves)[3]; /* 3 Pointers to F-Curves */
+ FCurve *(fcurves[3]); /* 3 Pointers to F-Curves */
+ char *rna_path; /* Pointer to one of the RNA Path's used by one of the F-Curves */
} tEulerFilter;
static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op)
@@ -1518,7 +1519,8 @@ static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op)
int filter;
ListBase eulers = {NULL, NULL};
- tEulerFilter *euf= NULL;
+ tEulerFilter *euf= NULL;
+ int groups=0, failed=0;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -1528,7 +1530,7 @@ static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op)
* 1) Sets of three related rotation curves are identified from the selected channels,
* and are stored as a single 'operation unit' for the next step
* 2) Each set of three F-Curves is processed for each keyframe, with the values being
- * processed according to one of several ways.
+ * processed as necessary
*/
/* step 1: extract only the rotation f-curves */
@@ -1542,45 +1544,134 @@ static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op)
* - only rotation curves
* - for pchan curves, make sure we're only using the euler curves
*/
- if (strstr(fcu->rna_path, "rotation_euler") == 0)
+ if (strstr(fcu->rna_path, "rotation_euler") == NULL)
continue;
+ else if (ELEM3(fcu->array_index, 0, 1, 2) == 0) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Euler Rotation F-Curve has invalid index (ID='%s', Path='%s', Index=%d)",
+ (ale->id)? ale->id->name:"<No ID>", fcu->rna_path, fcu->array_index);
+ continue;
+ }
- /* check if current set of 3-curves is suitable to add this curve to
- * - things like whether the current set of curves is 'full' should be checked later only
- * - first check if id-blocks are compatible
+ /* optimisation: assume that xyz curves will always be stored consecutively,
+ * so if the paths or the ID's don't match up, then a curve needs to be added
+ * to a new group
*/
- if ((euf) && (ale->id != euf->id)) {
- /* if the paths match, add this curve to the set of curves */
- // NOTE: simple string compare for now... could be a bit more fancy...
-
+ if ((euf) && (euf->id == ale->id) && (strcmp(euf->rna_path, fcu->rna_path)==0)) {
+ /* this should be fine to add to the existing group then */
+ euf->fcurves[fcu->array_index]= fcu;
}
else {
/* just add to a new block */
euf= MEM_callocN(sizeof(tEulerFilter), "tEulerFilter");
BLI_addtail(&eulers, euf);
+ groups++;
euf->id= ale->id;
+ euf->rna_path = fcu->rna_path; /* this should be safe, since we're only using it for a short time */
euf->fcurves[fcu->array_index]= fcu;
}
}
BLI_freelistN(&anim_data);
+ if (groups == 0) {
+ BKE_report(op->reports, RPT_WARNING, "No Euler Rotation F-Curves to fix up");
+ return OPERATOR_CANCELLED;
+ }
+
/* step 2: go through each set of curves, processing the values at each keyframe
* - it is assumed that there must be a full set of keyframes at each keyframe position
*/
for (euf= eulers.first; euf; euf= euf->next) {
+ int f;
+
+ /* sanity check: ensure that there are enough F-Curves to work on in this group */
+ // TODO: also enforce assumption that there be a full set of keyframes at each position by ensuring that totvert counts are same?
+ if (ELEM3(NULL, euf->fcurves[0], euf->fcurves[1], euf->fcurves[2])) {
+ /* report which components are missing */
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Missing %s%s%s component(s) of euler rotation for ID='%s' and RNA-Path='%s'",
+ (euf->fcurves[0]==NULL)? "X":"",
+ (euf->fcurves[1]==NULL)? "Y":"",
+ (euf->fcurves[2]==NULL)? "Z":"",
+ euf->id->name, euf->rna_path);
+
+ /* keep track of number of failed sets, and carry on to next group */
+ failed++;
+ continue;
+ }
+ /* simple method: just treat any difference between keys of greater than 180 degrees as being a flip */
+ // FIXME: there are more complicated methods that will be needed to fix more cases than just some
+ for (f = 0; f < 3; f++) {
+ FCurve *fcu = euf->fcurves[f];
+ BezTriple *bezt, *prev=NULL;
+ unsigned int i;
+
+ /* skip if not enough vets to do a decent analysis of... */
+ if (fcu->totvert <= 2)
+ continue;
+
+ /* prev follows bezt, bezt = "current" point to be fixed */
+ for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, prev=bezt, bezt++) {
+ /* our method depends on determining a "difference" from the previous vert */
+ if (prev == NULL)
+ continue;
+
+ /* > 180 degree flip? */
+ if (fabs(prev->vec[1][1] - bezt->vec[1][1]) >= M_PI) {
+ /* 360 degrees to add/subtract frame value until difference is acceptably small that there's no more flip */
+ const double fac = 2.0 * M_PI;
+
+ if (prev->vec[1][1] > bezt->vec[1][1]) {
+ while (fabs(bezt->vec[1][1] - prev->vec[1][1]) >= M_PI) {
+ bezt->vec[0][1] += fac;
+ bezt->vec[1][1] += fac;
+ bezt->vec[2][1] += fac;
+ }
+ }
+ else /* if (prev->vec[1][1] < bezt->vec[1][1]) */ {
+ while (fabs(bezt->vec[1][1] - prev->vec[1][1]) >= M_PI) {
+ bezt->vec[0][1] -= fac;
+ bezt->vec[1][1] -= fac;
+ bezt->vec[2][1] -= fac;
+ }
+ }
+ }
+ }
+ }
}
BLI_freelistN(&eulers);
- return OPERATOR_FINISHED;
+ /* updates + finishing warnings */
+ if (failed == groups) {
+ BKE_report(op->reports, RPT_ERROR,
+ "No Euler Rotations could be corrected. Ensure each rotation has keys for all components, and that F-Curves for these are in consecutive XYZ order and selected.");
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ if (failed) {
+ BKE_report(op->reports, RPT_ERROR,
+ "Some Euler Rotations couldn't be corrected due to missing/unselected/out-of-order F-Curves. Ensure each rotation has keys for all components, and that F-Curves for these are in consecutive XYZ order and selected.");
+ }
+
+ /* validate keyframes after editing */
+ ANIM_editkeyframes_refresh(&ac);
+
+ /* set notifier that keyframes have changed */
+ WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL);
+
+ /* done at last */
+ return OPERATOR_FINISHED;
+ }
}
void GRAPH_OT_euler_filter (wmOperatorType *ot)
{
/* identifiers */
- ot->name= "Euler Filter";
+ ot->name= "Euler Discontinuity Filter";
ot->idname= "GRAPH_OT_euler_filter";
+ ot->description= "Fixes the most common causes of gimbal lock in the selected Euler Rotation F-Curves";
/* api callbacks */
ot->exec= graphkeys_euler_filter_exec;
@@ -1590,8 +1681,6 @@ void GRAPH_OT_euler_filter (wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
-#endif // XXX this is not ready for the primetime yet
-
/* ***************** Jump to Selected Frames Operator *********************** */
/* snap current-frame indicator to 'average time' of selected keyframe */
diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h
index feb17827db7..2aefb7c64dd 100644
--- a/source/blender/editors/space_graph/graph_intern.h
+++ b/source/blender/editors/space_graph/graph_intern.h
@@ -111,6 +111,7 @@ void GRAPH_OT_sample(struct wmOperatorType *ot);
void GRAPH_OT_bake(struct wmOperatorType *ot);
void GRAPH_OT_sound_bake(struct wmOperatorType *ot);
void GRAPH_OT_smooth(struct wmOperatorType *ot);
+void GRAPH_OT_euler_filter(struct wmOperatorType *ot);
void GRAPH_OT_handle_type(struct wmOperatorType *ot);
void GRAPH_OT_interpolation_type(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 674d2809188..e75fbeb8efc 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -255,6 +255,7 @@ void graphedit_operatortypes(void)
WM_operatortype_append(GRAPH_OT_sound_bake);
WM_operatortype_append(GRAPH_OT_smooth);
WM_operatortype_append(GRAPH_OT_clean);
+ WM_operatortype_append(GRAPH_OT_euler_filter);
WM_operatortype_append(GRAPH_OT_delete);
WM_operatortype_append(GRAPH_OT_duplicate);