== Clamp To Constraint ==
authorJoshua Leung <aligorith@gmail.com>
Wed, 26 Sep 2007 07:33:31 +0000 (07:33 +0000)
committerJoshua Leung <aligorith@gmail.com>
Wed, 26 Sep 2007 07:33:31 +0000 (07:33 +0000)
Now there's an option for the owner to follow the path of the target cyclically. Previously, if the owner moved past the extents of the side of the bounding-box used for the calculations, the object was placed on the curve at the nearest extent.

This option is only really useful if the curve itself is cyclic, although you can still use it otherwise. To enable, just turn on the cyclic option.

source/blender/blenkernel/intern/constraint.c
source/blender/makesdna/DNA_constraint_types.h
source/blender/python/api2_2x/Constraint.c
source/blender/python/api2_2x/doc/Constraint.py
source/blender/src/buttons_object.c

index 4f79e6867b96f1830a8b2090add1b14f570454dd..8445fe887972f392111b50cc9cd0402caa2e95f6 100644 (file)
@@ -2599,7 +2599,7 @@ static void evaluate_constraint (bConstraint *constraint, float ownermat[][4], f
                                
                                /* find best position on curve */
                                /* 1. determine which axis to sample on? */
-                               if (data->flag==CLAMPTO_AUTO) {
+                               if (data->flag == CLAMPTO_AUTO) {
                                        float size[3];
                                        VecSubf(size, curveMax, curveMin);
                                        
@@ -2608,23 +2608,60 @@ static void evaluate_constraint (bConstraint *constraint, float ownermat[][4], f
                                         * frequently used.
                                         */
                                        if ((size[2]>size[0]) && (size[2]>size[1]))
-                                               clamp_axis= CLAMPTO_Z;
+                                               clamp_axis= CLAMPTO_Z - 1;
                                        else if ((size[1]>size[0]) && (size[1]>size[2]))
-                                               clamp_axis= CLAMPTO_Y;
+                                               clamp_axis= CLAMPTO_Y - 1;
                                        else
-                                               clamp_axis = CLAMPTO_X;
+                                               clamp_axis = CLAMPTO_X - 1;
                                }
                                else 
-                                       clamp_axis= data->flag;
+                                       clamp_axis= data->flag - 1;
                                        
-                               /* 2. determine position relative to curve on a 0-1 scale */
-                               if (clamp_axis > 0) clamp_axis--;
-                               if (ownLoc[clamp_axis] <= curveMin[clamp_axis])
-                                       curvetime = 0.0;
-                               else if (ownLoc[clamp_axis] >= curveMax[clamp_axis])
-                                       curvetime = 1.0;
-                               else
-                                       curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (curveMax[clamp_axis] - curveMin[clamp_axis]);
+                               /* 2. determine position relative to curve on a 0-1 scale based on bounding box */
+                               if (data->flag2 & CLAMPTO_CYCLIC) {
+                                       /* cyclic, so offset within relative bounding box is used */
+                                       float len= (curveMax[clamp_axis] - curveMin[clamp_axis]);
+                                       float offset;
+                                       
+                                       /* find bounding-box range where target is located */
+                                       if (ownLoc[clamp_axis] < curveMin[clamp_axis]) {
+                                               /* bounding-box range is before */
+                                               offset= curveMin[clamp_axis];
+                                               
+                                               while (ownLoc[clamp_axis] < offset)
+                                                       offset -= len;
+                                               
+                                               /* now, we calculate as per normal, except using offset instead of curveMin[clamp_axis] */
+                                               curvetime = (ownLoc[clamp_axis] - offset) / (len);
+                                       }
+                                       else if (ownLoc[clamp_axis] > curveMax[clamp_axis]) {
+                                               /* bounding-box range is after */
+                                               offset= curveMax[clamp_axis];
+                                               
+                                               while (ownLoc[clamp_axis] > offset) {
+                                                       if ((offset + len) > ownLoc[clamp_axis])
+                                                               break;
+                                                       else
+                                                               offset += len;
+                                               }
+                                               
+                                               /* now, we calculate as per normal, except using offset instead of curveMax[clamp_axis] */
+                                               curvetime = (ownLoc[clamp_axis] - offset) / (len);
+                                       }
+                                       else {
+                                               /* as the location falls within bounds, just calculate */
+                                               curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (len);
+                                       }
+                               }
+                               else {
+                                       /* no cyclic, so position is clamped to within the bounding box */
+                                       if (ownLoc[clamp_axis] <= curveMin[clamp_axis])
+                                               curvetime = 0.0;
+                                       else if (ownLoc[clamp_axis] >= curveMax[clamp_axis])
+                                               curvetime = 1.0;
+                                       else
+                                               curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (curveMax[clamp_axis] - curveMin[clamp_axis]);
+                               }
                                
                                /* 3. position on curve */
                                if(where_on_path(data->tar, curvetime, vec, dir) ) {
index 9a0d5a095e5b3ff3c5a9361add8bcdf4e0e52830..fcde95371acfbc252c461fcb06513a9d07d82c84 100644 (file)
@@ -205,7 +205,7 @@ typedef struct bRigidBodyJointConstraint {
 typedef struct bClampToConstraint {
        Object          *tar;                   /* 'target' must be a curve */
        int                     flag;                   /* which axis/plane to compare owner's location on  */
-       int                     pad;
+       int                     flag2;                  /* for legacy reasons, this is flag2. used for any extra settings */
 } bClampToConstraint;
 
 /* Child Of Constraint */
@@ -373,6 +373,9 @@ typedef struct bSizeLimitConstraint {
 #define        CLAMPTO_Y               2
 #define CLAMPTO_Z              3
 
+/* ClampTo Constraint ->flag2 */
+#define CLAMPTO_CYCLIC 1
+
 /* bKinematicConstraint->flag */
 #define CONSTRAINT_IK_TIP              1
 #define CONSTRAINT_IK_ROT              2
index 0e235082c61093a9c19b57aabed871d7a2ec2e77..4dddd274a0ef37e72785dfc43b7f35988e07f27b 100644 (file)
@@ -125,6 +125,8 @@ enum constraint_constants {
        EXPP_CONSTR_LIMYROT = LIMIT_YROT,
        EXPP_CONSTR_LIMZROT = LIMIT_ZROT,
        
+       EXPP_CONSTR_CLAMPCYCLIC,
+       
        EXPP_CONSTR_XMIN,
        EXPP_CONSTR_XMAX,
        EXPP_CONSTR_YMIN,
@@ -887,6 +889,8 @@ static PyObject *clampto_getter( BPy_Constraint * self, int type )
                return Object_CreatePyObject( con->tar );
        case EXPP_CONSTR_CLAMP:
                return PyInt_FromLong( (long)con->flag );
+       case EXPP_CONSTR_CLAMPCYCLIC:
+               return PyBool_FromLong( (long)(con->flag2 & CLAMPTO_CYCLIC) );
        default:
                return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
        }
@@ -908,6 +912,8 @@ static int clampto_setter( BPy_Constraint *self, int type, PyObject *value )
        case EXPP_CONSTR_CLAMP:
                return EXPP_setIValueRange( value, &con->flag,
                                CLAMPTO_AUTO, CLAMPTO_Z, 'i' );
+       case EXPP_CONSTR_CLAMPCYCLIC:
+               return EXPP_setBitfield( value, &con->flag2, CLAMPTO_CYCLIC, 'i' );
        default:
                return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
        }
@@ -2418,6 +2424,8 @@ static PyObject *M_Constraint_SettingsDict( void )
                                PyInt_FromLong( CLAMPTO_Y ) );
                PyConstant_Insert( d, "CLAMPZ",
                                PyInt_FromLong( CLAMPTO_Z ) );
+               PyConstant_Insert( d, "CLAMPCYCLIC",
+                               PyInt_FromLong( EXPP_CONSTR_CLAMPCYCLIC ));
 
                PyConstant_Insert( d, "TARGET",
                                PyInt_FromLong( EXPP_CONSTR_TARGET ) );
index bb81d2cba7a572b6ba8de59ddadffa70a30d7006..4c1981c523845ca69161b4be150c0c5098ced9a2 100644 (file)
@@ -86,6 +86,7 @@ Or to print all the constraints attached to each bone in a pose::
                - LOCK (int): values are LOCKX, LOCKY, LOCKZ
        - Used by Clamp To (CLAMPTO) constraint:
                - CLAMP (int): values are CLAMPAUTO, CLAMPX, CLAMPY, CLAMPZ
+               - CLAMPCYCLIC (bool)
        - Used by Floor (FLOOR) constraint:
                - MINMAX (int): values are MINX, MINY, MINZ, MAXX, MAXY, MAXZ
                - OFFSET (float): clamped to [-100.0,100.0]
index 033a7dc18cc142f43419e69e0082f3c5a88e2561..cd3246fcd8d6065d5133512fadd797eba67a9fc3 100644 (file)
@@ -1409,11 +1409,11 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
                        {
                                bClampToConstraint *data = con->data;
                                
-                               height = 66;
+                               height = 90;
                                uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, ""); 
                                
                                uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
-
+                               
                                /* Draw target parameters */
                                uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object"); 
                                
@@ -1425,6 +1425,12 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
                                uiDefButI(block, ROW, B_CONSTRAINT_TEST, "Y", *xco+182, *yco-64, 32, 18, &data->flag, 12.0, CLAMPTO_Y, 0, 0, "Main axis of movement is y-axis");
                                uiDefButI(block, ROW, B_CONSTRAINT_TEST, "Z", *xco+214, *yco-64, 32, 18, &data->flag, 12.0, CLAMPTO_Z, 0, 0, "Main axis of movement is z-axis");
                                uiBlockEndAlign(block);
+                               
+                               /* Extra Options Controlling Behaviour */
+                               uiBlockBeginAlign(block);
+                               uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Options:", *xco, *yco-86, 90, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
+                               uiDefButBitI(block, TOG, CLAMPTO_CYCLIC, B_CONSTRAINT_TEST, "Cyclic", *xco+((width/2)), *yco-86,60,19, &data->flag2, 0, 0, 0, 0, "Treat curve as cyclic curve (no clamping to curve bounding box)");
+                               uiBlockEndAlign(block);
                        }
                        break;
                case CONSTRAINT_TYPE_TRANSFORM: