== Clamp-To Constraint (was Patch #4818) ==

This (new) constraint limits the location of an object/bone to the range of locations
on a given curve. It works by comparing the location of the owner on one axis, to
the extents of the curve's bounding-box on the same axis, to find the location on
the curve.

Usage Notes:
* 'Ob:' field must point to a valid curve object
* This curve should have 'Path' turned on in order for this constraint to work. You
don't really need to do this as it will be taken care of by the code.
* 'Auto' toggle automically determines which axis should be used for the distance estimations/calculations. It is the default option, but may not work that well for
some cases.
* X/Y/Z toggles can be used to select the axis to use for these calculations. Try
to choose the axis along which the curve stretches out for most.

Python Notes:
Python API access for this constraint is not included in this commit. Will be coming
soon.
This commit is contained in:
2007-04-07 03:32:57 +00:00
parent 999e405543
commit 655f9a61de
7 changed files with 227 additions and 7 deletions

View File

@@ -206,6 +206,14 @@ void relink_constraints (struct ListBase *list)
bRigidBodyJointConstraint *data;
data = con->data;
ID_NEW(data->tar);
}
break;
case CONSTRAINT_TYPE_CLAMPTO:
{
bClampToConstraint *data;
data = con->data;
ID_NEW(data->tar);
}
break;
@@ -333,6 +341,13 @@ char constraint_has_target (bConstraint *con)
return 1;
}
break;
case CONSTRAINT_TYPE_CLAMPTO:
{
bClampToConstraint *data = con->data;
if (data->tar)
return 1;
}
break;
}
// Unknown types or CONSTRAINT_TYPE_NULL or no target
return 0;
@@ -422,6 +437,13 @@ Object *get_constraint_target(bConstraint *con, char **subtarget)
return data->tar;
}
break;
case CONSTRAINT_TYPE_CLAMPTO:
{
bClampToConstraint *data = con->data;
*subtarget= NULL;
return data->tar;
}
break;
default:
*subtarget= NULL;
break;
@@ -511,6 +533,12 @@ void set_constraint_target(bConstraint *con, Object *ob, char *subtarget)
if(subtarget) BLI_strncpy(data->subtarget, subtarget, 32);
}
break;
case CONSTRAINT_TYPE_CLAMPTO:
{
bClampToConstraint *data = con->data;
data->tar= ob;
}
break;
}
}
@@ -739,6 +767,13 @@ void *new_constraint_data (short type)
result = data;
}
break;
case CONSTRAINT_TYPE_CLAMPTO:
{
bClampToConstraint *data;
data = MEM_callocN(sizeof(bClampToConstraint), "ClampToConstraint");
result = data;
}
break;
default:
result = NULL;
@@ -1255,6 +1290,24 @@ short get_constraint_target_matrix (bConstraint *con, short ownertype, void* own
Mat4One (mat);
}
break;
case CONSTRAINT_TYPE_CLAMPTO:
{
bClampToConstraint *data;
data = (bClampToConstraint*)con->data;
if (data->tar) {
Curve *cu= data->tar->data;
/* note; when creating constraints that follow path, the curve gets the CU_PATH set now,
currently for paths to work it needs to go through the bevlist/displist system (ton) */
if(cu->path==NULL || cu->path->data==NULL) /* only happens on reload file, but violates depsgraph still... fix! */
makeDispListCurveTypes(data->tar, 0);
}
Mat4One (mat);
}
break;
default:
Mat4One(mat);
@@ -1277,7 +1330,7 @@ void evaluate_constraint (bConstraint *constraint, Object *ob, short ownertype,
Mat4One (M_identity);
switch (constraint->type){
switch (constraint->type) {
case CONSTRAINT_TYPE_NULL:
case CONSTRAINT_TYPE_KINEMATIC: /* removed */
break;
@@ -1300,10 +1353,8 @@ void evaluate_constraint (bConstraint *constraint, Object *ob, short ownertype,
data = constraint->data;
if (data->flag & LOCLIKE_OFFSET) {
// for now...
if (data->flag & LOCLIKE_OFFSET)
VECCOPY(offset, ob->obmat[3]);
}
if (data->flag & LOCLIKE_X) {
ob->obmat[3][0] = targetmat[3][0];
@@ -2181,7 +2232,77 @@ void evaluate_constraint (bConstraint *constraint, Object *ob, short ownertype,
}
break;
break;
case CONSTRAINT_TYPE_CLAMPTO:
{
bClampToConstraint *data;
Curve *cu;
float obmat[4][4], targetMatrix[4][4], ownLoc[3];
float curveMin[3], curveMax[3];
data = constraint->data;
/* prevent crash if user deletes curve */
if ((data->tar == NULL) || (data->tar->type != OB_CURVE) )
return;
else
cu= data->tar->data;
Mat4CpyMat4(obmat, ob->obmat);
Mat4One(targetMatrix);
VECCOPY(ownLoc, obmat[3]);
INIT_MINMAX(curveMin, curveMax)
minmax_object(data->tar, curveMin, curveMax);
/* get targetmatrix */
if(cu->path && cu->path->data) {
float vec[4], dir[3], totmat[4][4];
float curvetime;
short clamp_axis;
/* find best position on curve */
/* 1. determine which axis to sample on? */
if (data->flag==CLAMPTO_AUTO) {
float size[3];
VecSubf(size, curveMax, curveMin);
/* find axis along which the bounding box has the greatest
* extent. Otherwise, default to the x-axis, as that is quite
* frequently used.
*/
if ((size[2]>size[0]) && (size[2]>size[1]))
clamp_axis= CLAMPTO_Z;
else if ((size[1]>size[0]) && (size[1]>size[2]))
clamp_axis= CLAMPTO_Y;
else
clamp_axis = CLAMPTO_X;
}
else
clamp_axis= data->flag;
/* 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]); // umm
/* 3. position on curve */
if(where_on_path(data->tar, curvetime, vec, dir) ) {
Mat4One(totmat);
VECCOPY(totmat[3], vec);
Mat4MulSerie(targetMatrix, data->tar->obmat, totmat, NULL, NULL, NULL, NULL, NULL, NULL);
}
}
/* obtain final object position */
VECCOPY(ob->obmat[3], targetMatrix[3]);
}
break;
default:
printf ("Error: Unknown constraint type\n");
break;

View File

@@ -1710,6 +1710,13 @@ static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist)
data->tar = newlibadr(fd, id->lib, data->tar);
};
break;
case CONSTRAINT_TYPE_CLAMPTO:
{
bClampToConstraint *data;
data= ((bClampToConstraint*)con->data);
data->tar = newlibadr(fd, id->lib, data->tar);
};
break;
case CONSTRAINT_TYPE_NULL:
break;
@@ -6852,6 +6859,12 @@ static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb)
expand_doit(fd, mainvar, data->tar);
break;
}
case CONSTRAINT_TYPE_CLAMPTO:
{
bClampToConstraint *data = (bClampToConstraint*)curcon->data;
expand_doit(fd, mainvar, data->tar);
break;
}
case CONSTRAINT_TYPE_NULL:
break;
default:

View File

@@ -744,6 +744,9 @@ static void write_constraints(WriteData *wd, ListBase *conlist)
case CONSTRAINT_TYPE_RIGIDBODYJOINT:
writestruct(wd, DATA, "bRigidBodyJointConstraint", 1, con->data);
break;
case CONSTRAINT_TYPE_CLAMPTO:
writestruct(wd, DATA, "bClampToConstraint", 1, con->data);
break;
default:
break;
}

View File

@@ -646,6 +646,7 @@ enum {
B_CONSTRAINT_ADD_RIGIDBODYJOINT,
B_CONSTRAINT_ADD_CHILDOF,
B_CONSTRAINT_ADD_PYTHON,
B_CONSTRAINT_ADD_CLAMPTO,
B_CONSTRAINT_INF
};

View File

@@ -216,6 +216,13 @@ typedef struct bRigidBodyJointConstraint{
short pad2;
} bRigidBodyJointConstraint;
/* ClampTo Constraint */
typedef struct bClampToConstraint {
Object *tar; /* 'target' must be a curve */
int flag; /* which plane to find object on */
int pad;
} bClampToConstraint;
/* bConstraint.type */
#define CONSTRAINT_TYPE_NULL 0
#define CONSTRAINT_TYPE_CHILDOF 1 /* Unimplemented */
@@ -235,6 +242,7 @@ typedef struct bRigidBodyJointConstraint{
#define CONSTRAINT_TYPE_STRETCHTO 15 /* claiming this to be mine :) is in tuhopuu bjornmose */
#define CONSTRAINT_TYPE_MINMAX 16 /* floor constraint */
#define CONSTRAINT_TYPE_RIGIDBODYJOINT 17 /* rigidbody constraint */
#define CONSTRAINT_TYPE_CLAMPTO 18 /* clampto constraint */
/* bConstraint.flag */
/* expand for UI */
@@ -310,6 +318,11 @@ typedef struct bRigidBodyJointConstraint{
#define PLANE_Y 0x01
#define PLANE_Z 0x02
#define CLAMPTO_AUTO 0
#define CLAMPTO_X 1
#define CLAMPTO_Y 2
#define CLAMPTO_Z 3
/* bKinematicConstraint->flag */
#define CONSTRAINT_IK_TIP 1
#define CONSTRAINT_IK_ROT 2

View File

@@ -371,6 +371,9 @@ void get_constraint_typestring (char *str, void *con_v)
case CONSTRAINT_TYPE_RIGIDBODYJOINT:
strcpy (str, "Rigid Body");
return;
case CONSTRAINT_TYPE_CLAMPTO:
strcpy (str, "Clamp To");
return;
default:
strcpy (str, "Unknown");
return;
@@ -1268,6 +1271,28 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
}
}
break;
case CONSTRAINT_TYPE_CLAMPTO:
{
bClampToConstraint *data = con->data;
height = 66;
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");
/* Draw XYZ toggles */
uiBlockBeginAlign(block);
uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Main Axis:", *xco, *yco-64, 90, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
uiDefButI(block, ROW, B_CONSTRAINT_TEST, "Auto", *xco+100, *yco-64, 50, 18, &data->flag, 12.0, CLAMPTO_AUTO, 0, 0, "Automatically determine main-axis of movement");
uiDefButI(block, ROW, B_CONSTRAINT_TEST, "X", *xco+150, *yco-64, 32, 18, &data->flag, 12.0, CLAMPTO_X, 0, 0, "Main axis of movement is x-axis");
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);
}
break;
case CONSTRAINT_TYPE_NULL:
{
height = 17;
@@ -1327,6 +1352,7 @@ static uiBlock *add_constraintmenu(void *arg_unused)
uiDefBut(block, BUTM, B_CONSTRAINT_ADD_MINMAX,"Floor", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
uiDefBut(block, BUTM, B_CONSTRAINT_ADD_LOCKTRACK,"Locked Track", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
uiDefBut(block, BUTM, B_CONSTRAINT_ADD_FOLLOWPATH,"Follow Path", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
uiDefBut(block, BUTM, B_CONSTRAINT_ADD_CLAMPTO,"Clamp To", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
uiDefBut(block, SEPR, 0, "", 0, yco-=6, 120, 6, NULL, 0.0, 0.0, 0, 0, "");
@@ -1515,6 +1541,15 @@ void do_constraintbuts(unsigned short event)
BIF_undo_push("Add constraint");
}
break;
case B_CONSTRAINT_ADD_CLAMPTO:
{
bConstraint *con;
con = add_new_constraint(CONSTRAINT_TYPE_CLAMPTO);
add_constraint_to_active(ob, con);
BIF_undo_push("Add constraint");
}
break;
default:
break;

View File

@@ -313,6 +313,12 @@ char *get_con_subtarget_name(bConstraint *con, Object *target)
return NULL;
}
break;
case CONSTRAINT_TYPE_CLAMPTO:
{
/* cannot have subtarget. if followpath is removed from here, remove this too... */
return NULL;
}
break;
}
return NULL;
@@ -571,6 +577,29 @@ static void test_constraints (Object *owner, const char* substring)
}
}
break;
case CONSTRAINT_TYPE_CLAMPTO:
{
bClampToConstraint *data = curcon->data;
if (!exist_object(data->tar)){
data->tar = NULL;
curcon->flag |= CONSTRAINT_DISABLE;
break;
}
if (data->tar->type != OB_CURVE){
data->tar = NULL;
curcon->flag |= CONSTRAINT_DISABLE;
break;
}
else {
Curve *cu= data->tar->data;
/* auto-set 'Path' setting on curve so this works */
cu->flag |= CU_PATH;
}
}
break;
}
}
}
@@ -661,7 +690,7 @@ void add_constraint(int only_IK)
if(pchansel)
nr= pupmenu("Add Constraint to Active Bone%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|Action%x16");
else if(obsel && obsel->type==OB_CURVE)
nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Stretch To%x7|Action%x16");
nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|Stretch To%x7|Action%x16");
else if(obsel)
nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|Action%x16");
else
@@ -669,7 +698,7 @@ void add_constraint(int only_IK)
}
else {
if(obsel && obsel->type==OB_CURVE)
nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6");
nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17");
else if(obsel)
nr= pupmenu("Add Constraint to Active Object%t|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|Track To%x3|Floor%x4|Locked Track%x5");
else
@@ -728,6 +757,11 @@ void add_constraint(int only_IK)
else if(nr==14) con = add_new_constraint(CONSTRAINT_TYPE_ROTLIMIT);
else if(nr==15) con = add_new_constraint(CONSTRAINT_TYPE_SIZELIMIT);
else if(nr==16) con = add_new_constraint(CONSTRAINT_TYPE_ACTION);
else if(nr==17) {
Curve *cu= obsel->data;
cu->flag |= CU_PATH;
con = add_new_constraint(CONSTRAINT_TYPE_CLAMPTO)
}
if(con==NULL) return; /* paranoia */