Pole Target for IK
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 24 Oct 2007 14:58:31 +0000 (14:58 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 24 Oct 2007 14:58:31 +0000 (14:58 +0000)
==================

This adds an extra target to the IK solver constraint to define the
roll of the IK chain.

http://www.blender.org/development/current-projects/changes-since-244/inverse-kinematics/

Also fixes a crashes using ctrl+I to set an IK constraint on a bone
due to the recent constraints refactor.

17 files changed:
intern/iksolver/extern/IK_solver.h
intern/iksolver/intern/IK_QJacobian.cpp
intern/iksolver/intern/IK_QJacobian.h
intern/iksolver/intern/IK_QJacobianSolver.cpp
intern/iksolver/intern/IK_QJacobianSolver.h
intern/iksolver/intern/IK_QSegment.cpp
intern/iksolver/intern/IK_QSegment.h
intern/iksolver/intern/IK_QTask.h
intern/iksolver/intern/IK_Solver.cpp
source/blender/blenkernel/BKE_constraint.h
source/blender/blenkernel/intern/armature.c
source/blender/blenkernel/intern/constraint.c
source/blender/blenloader/intern/readfile.c
source/blender/makesdna/DNA_constraint_types.h
source/blender/src/buttons_object.c
source/blender/src/editconstraint.c
source/blender/src/editobject.c

index 8626ca22beb01cf60b35c87e624c4979d7cffc4f..bf53a9e3724e861bdc20c75aec1770ae79039d01 100644 (file)
@@ -158,6 +158,8 @@ void IK_FreeSolver(IK_Solver *solver);
 
 void IK_SolverAddGoal(IK_Solver *solver, IK_Segment *tip, float goal[3], float weight);
 void IK_SolverAddGoalOrientation(IK_Solver *solver, IK_Segment *tip, float goal[][3], float weight);
+void IK_SolverSetPoleVectorConstraint(IK_Solver *solver, IK_Segment *tip, float goal[3], float polegoal[3], float poleangle, int getangle);
+float IK_SolverGetPoleAngle(IK_Solver *solver);
 
 int IK_Solve(IK_Solver *solver, float tolerance, int max_iterations);
 
index 03c5f9500be147c60cb847951d41d0c391a5d765..1dd4d086aa84342481a65d9e59a5f38dfa3d785f 100644 (file)
@@ -42,11 +42,10 @@ IK_QJacobian::~IK_QJacobian()
 {
 }
 
-void IK_QJacobian::ArmMatrices(int dof, int task_size, int tasks)
+void IK_QJacobian::ArmMatrices(int dof, int task_size)
 {
        m_dof = dof;
        m_task_size = task_size;
-       m_tasks = tasks;
 
        m_jacobian.newsize(task_size, dof);
        m_jacobian = 0;
index b80db1d8f53aeef0a5bc534dd83c74dd5c68e1ad..3e20e4a9fd07b1be97352bd4e32d00bf8929f2f5 100644 (file)
@@ -49,7 +49,7 @@ public:
        ~IK_QJacobian();
 
        // Call once to initialize
-       void ArmMatrices(int dof, int task_size, int tasks);
+       void ArmMatrices(int dof, int task_size);
        void SetDoFWeight(int dof, MT_Scalar weight);
 
        // Iteratively called
@@ -75,7 +75,7 @@ private:
        void InvertSDLS();
        void InvertDLS();
 
-       int m_dof, m_task_size, m_tasks;
+       int m_dof, m_task_size;
        bool m_transpose;
 
        // the jacobian matrix and it's null space projector
index ea18f0b20036751017578b259983b5e60b85f1f0..f19b2a162fa224ce43b8ee1de94a4ef8be69aace 100644 (file)
 
 #include <stdio.h>
 #include "IK_QJacobianSolver.h"
+#include "MT_Quaternion.h"
+
+//#include "analyze.h"
+IK_QJacobianSolver::IK_QJacobianSolver()
+{
+       m_poleconstraint = false;
+       m_getpoleangle = false;
+       m_rootmatrix.setIdentity();
+}
 
 void IK_QJacobianSolver::AddSegmentList(IK_QSegment *seg)
 {
@@ -47,7 +56,7 @@ bool IK_QJacobianSolver::Setup(IK_QSegment *root, std::list<IK_QTask*>& tasks)
        m_segments.clear();
        AddSegmentList(root);
 
-       // assing each segment a unique id for the jacobian
+       // assign each segment a unique id for the jacobian
        std::vector<IK_QSegment*>::iterator seg;
        int num_dof = 0;
 
@@ -105,9 +114,9 @@ bool IK_QJacobianSolver::Setup(IK_QSegment *root, std::list<IK_QTask*>& tasks)
        }
 
        // set matrix sizes
-       m_jacobian.ArmMatrices(num_dof, primary_size, primary);
+       m_jacobian.ArmMatrices(num_dof, primary_size);
        if (secondary > 0)
-               m_jacobian_sub.ArmMatrices(num_dof, secondary_size, secondary);
+               m_jacobian_sub.ArmMatrices(num_dof, secondary_size);
 
        // set dof weights
        int i;
@@ -119,6 +128,109 @@ bool IK_QJacobianSolver::Setup(IK_QSegment *root, std::list<IK_QTask*>& tasks)
        return true;
 }
 
+void IK_QJacobianSolver::SetPoleVectorConstraint(IK_QSegment *tip, MT_Vector3& goal, MT_Vector3& polegoal, float poleangle, bool getangle)
+{
+       m_poleconstraint = true;
+       m_poletip = tip;
+       m_goal = goal;
+       m_polegoal = polegoal;
+       m_poleangle = (getangle)? 0.0f: poleangle;
+       m_getpoleangle = getangle;
+}
+
+static MT_Scalar safe_acos(MT_Scalar f)
+{
+       // acos that does not return NaN with rounding errors
+       if (f <= -1.0f) return MT_PI;
+       else if (f >= 1.0f) return 0.0;
+       else return acos(f);
+}
+
+static MT_Vector3 normalize(const MT_Vector3& v)
+{
+       // a sane normalize function that doesn't give (1, 0, 0) in case
+       // of a zero length vector, like MT_Vector3.normalize
+       MT_Scalar len = v.length();
+       return MT_fuzzyZero(len)?  MT_Vector3(0, 0, 0): v/len;
+}
+
+static float angle(const MT_Vector3& v1, const MT_Vector3& v2)
+{
+       return safe_acos(v1.dot(v2));
+}
+
+void IK_QJacobianSolver::ConstrainPoleVector(IK_QSegment *root, std::list<IK_QTask*>& tasks)
+{
+       // this function will be called before and after solving. calling it before
+       // solving gives predictable solutions by rotating towards the solution,
+       // and calling it afterwards ensures the solution is exact.
+
+       if(!m_poleconstraint)
+               return;
+       
+       // disable pole vector constraint in case of multiple position tasks
+       std::list<IK_QTask*>::iterator task;
+       int positiontasks = 0;
+
+       for (task = tasks.begin(); task != tasks.end(); task++)
+               if((*task)->PositionTask())
+                       positiontasks++;
+       
+       if (positiontasks >= 2) {
+               m_poleconstraint = false;
+               return;
+       }
+
+       // get positions and rotations
+       root->UpdateTransform(m_rootmatrix);
+
+       const MT_Vector3 rootpos = root->GlobalStart();
+       const MT_Vector3 endpos = m_poletip->GlobalEnd();
+       const MT_Matrix3x3& rootbasis = root->GlobalTransform().getBasis();
+
+       // construct "lookat" matrices (like gluLookAt), based on a direction and
+       // an up vector, with the direction going from the root to the end effector
+       // and the up vector going from the root to the pole constraint position.
+       MT_Vector3 dir = normalize(endpos - rootpos);
+       MT_Vector3 rootx= rootbasis.getColumn(0);
+       MT_Vector3 rootz= rootbasis.getColumn(2);
+       MT_Vector3 up = rootx*cos(m_poleangle) + rootz*sin(m_poleangle);
+
+       // in post, don't rotate towards the goal but only correct the pole up
+       MT_Vector3 poledir = (m_getpoleangle)? dir: normalize(m_goal - rootpos);
+       MT_Vector3 poleup = normalize(m_polegoal - rootpos);
+
+       MT_Matrix3x3 mat, polemat;
+
+       mat[0] = normalize(MT_cross(dir, up));
+       mat[1] = MT_cross(mat[0], dir);
+       mat[2] = -dir;
+
+       polemat[0] = normalize(MT_cross(poledir, poleup));
+       polemat[1] = MT_cross(polemat[0], poledir);
+       polemat[2] = -poledir;
+
+       if(m_getpoleangle) {
+               // we compute the pole angle that to rotate towards the target
+               m_poleangle = angle(mat[1], polemat[1]);
+
+               if(rootz.dot(mat[1]*cos(m_poleangle) + mat[0]*sin(m_poleangle)) > 0.0f)
+                       m_poleangle = -m_poleangle;
+
+               // solve again, with the pole angle we just computed
+               m_getpoleangle = false;
+               ConstrainPoleVector(root, tasks);
+       }
+       else {
+               // now we set as root matrix the difference between the current and
+               // desired rotation based on the pole vector constraint. we use
+               // transpose instead of inverse because we have orthogonal matrices
+               // anyway, and in case of a singular matrix we don't get NaN's.
+               MT_Transform trans(MT_Point3(0, 0, 0), polemat.transposed()*mat);
+               m_rootmatrix = trans*m_rootmatrix;
+       }
+}
+
 bool IK_QJacobianSolver::UpdateAngles(MT_Scalar& norm)
 {
        // assing each segment a unique id for the jacobian
@@ -181,15 +293,17 @@ bool IK_QJacobianSolver::Solve(
        const int max_iterations
 )
 {
+       bool solved = false;
        //double dt = analyze_time();
 
-       if (!Setup(root, tasks))
-               return false;
+       ConstrainPoleVector(root, tasks);
+
+       root->UpdateTransform(m_rootmatrix);
 
        // iterate
        for (int iterations = 0; iterations < max_iterations; iterations++) {
                // update transform
-               root->UpdateTransform(MT_Transform::Identity());
+               root->UpdateTransform(m_rootmatrix);
 
                std::list<IK_QTask*>::iterator task;
 
@@ -211,7 +325,7 @@ bool IK_QJacobianSolver::Solve(
                                        m_jacobian.SubTask(m_jacobian_sub);
                        }
                        catch (...) {
-                               printf("IK Exception\n");
+                               fprintf(stderr, "IK Exception\n");
                                return false;
                        }
 
@@ -230,12 +344,19 @@ bool IK_QJacobianSolver::Solve(
 
                // check for convergence
                if (norm < 1e-3) {
+                       solved = true;
+                       break;
                        //analyze_add_run(iterations, analyze_time()-dt);
+
                        return true;
                }
        }
 
+       if(m_poleconstraint)
+               root->PrependBasis(m_rootmatrix.getBasis());
+
        //analyze_add_run(max_iterations, analyze_time()-dt);
-       return false;
+
+       return solved;
 }
 
index adf95eb82dcb57af01c7e164b98060c9c56c224d..bc3d1686b59870c597325b566f0daff1f7e95500 100644 (file)
@@ -43,6 +43,7 @@
 #include <list>
 
 #include "MT_Vector3.h"
+#include "MT_Transform.h"
 #include "IK_QJacobian.h"
 #include "IK_QSegment.h"
 #include "IK_QTask.h"
 class IK_QJacobianSolver
 {
 public:
-       IK_QJacobianSolver() {};
+       IK_QJacobianSolver();
        ~IK_QJacobianSolver() {};
 
-       // returns true if converged, false if max number of iterations was used
+       // setup pole vector constraint
+       void SetPoleVectorConstraint(IK_QSegment *tip, MT_Vector3& goal,
+               MT_Vector3& polegoal, float poleangle, bool getangle);
+       float GetPoleAngle() { return m_poleangle; };
+
+       // call setup once before solving, if it fails don't solve
+       bool Setup(IK_QSegment *root, std::list<IK_QTask*>& tasks);
 
+       // returns true if converged, false if max number of iterations was used
        bool Solve(
                IK_QSegment *root,
                std::list<IK_QTask*> tasks,
@@ -64,8 +72,8 @@ public:
 
 private:
        void AddSegmentList(IK_QSegment *seg);
-       bool Setup(IK_QSegment *root, std::list<IK_QTask*>& tasks);
        bool UpdateAngles(MT_Scalar& norm);
+       void ConstrainPoleVector(IK_QSegment *root, std::list<IK_QTask*>& tasks);
 
 private:
 
@@ -75,6 +83,15 @@ private:
        bool m_secondary_enabled;
 
        std::vector<IK_QSegment*> m_segments;
+
+       MT_Transform m_rootmatrix;
+
+       bool m_poleconstraint;
+       bool m_getpoleangle;
+       MT_Vector3 m_goal;
+       MT_Vector3 m_polegoal;
+       float m_poleangle;
+       IK_QSegment *m_poletip;
 };
 
 #endif
index cf9e1615d8cd28fe429a8ce8114c91bc1794b826..1855c1e3db3b626812607f2f7f79953408495aae 100644 (file)
@@ -236,6 +236,18 @@ IK_QSegment::IK_QSegment(int num_DoF, bool translational)
        m_orig_translation = m_translation;
 }
 
+void IK_QSegment::Reset()
+{
+       m_locked[0] = m_locked[1] = m_locked[2] = false;
+
+       m_basis = m_orig_basis;
+       m_translation = m_orig_translation;
+       SetBasis(m_basis);
+
+       for (IK_QSegment *seg = m_child; seg; seg = seg->m_sibling)
+               seg->Reset();
+}
+
 void IK_QSegment::SetTransform(
        const MT_Vector3& start,
        const MT_Matrix3x3& rest_basis,
@@ -326,6 +338,11 @@ void IK_QSegment::UpdateTransform(const MT_Transform& global)
                seg->UpdateTransform(m_global_transform);
 }
 
+void IK_QSegment::PrependBasis(const MT_Matrix3x3& mat)
+{
+       m_basis = m_rest_basis.inverse() * mat * m_rest_basis * m_basis;
+}
+
 // IK_QSphericalSegment
 
 IK_QSphericalSegment::IK_QSphericalSegment()
index e406585bc8bea4b9553f981e444d3793264b679b..ca0abafb06adc8df8397332645fa30a32942024e 100644 (file)
@@ -165,6 +165,10 @@ public:
 
        virtual void SetBasis(const MT_Matrix3x3& basis) { m_basis = basis; }
 
+       // functions needed for pole vector constraint
+       void PrependBasis(const MT_Matrix3x3& mat);
+       void Reset();
+
 protected:
 
        // num_DoF: number of degrees of freedom
index 0e00925d908d5025be98b27d57e200ecce8d6fe5..26beaa386229e310f465ab4319e3c9ada0672aff 100644 (file)
@@ -75,6 +75,8 @@ public:
 
        virtual MT_Scalar Distance() const=0;
 
+       virtual bool PositionTask() const { return false; }
+
 protected:
        int m_id;
        int m_size;
@@ -97,6 +99,8 @@ public:
 
        MT_Scalar Distance() const;
 
+       bool PositionTask() const { return true; }
+
 private:
        MT_Vector3 m_goal;
        MT_Scalar m_clamp_length;
index 919eeb739ce08ef48160e82fa4959fce2be17e48..b2d75d783c6016be5383e03ad7bac9ee6993ac34 100644 (file)
@@ -318,6 +318,31 @@ void IK_SolverAddGoalOrientation(IK_Solver *solver, IK_Segment *tip, float goal[
        qsolver->tasks.push_back(orient);
 }
 
+void IK_SolverSetPoleVectorConstraint(IK_Solver *solver, IK_Segment *tip, float goal[3], float polegoal[3], float poleangle, int getangle)
+{
+       if (solver == NULL || tip == NULL)
+               return;
+
+       IK_QSolver *qsolver = (IK_QSolver*)solver;
+       IK_QSegment *qtip = (IK_QSegment*)tip;
+
+       MT_Vector3 qgoal(goal);
+       MT_Vector3 qpolegoal(polegoal);
+
+       qsolver->solver.SetPoleVectorConstraint(
+               qtip, qgoal, qpolegoal, poleangle, getangle);
+}
+
+float IK_SolverGetPoleAngle(IK_Solver *solver)
+{
+       if (solver == NULL)
+               return 0.0f;
+
+       IK_QSolver *qsolver = (IK_QSolver*)solver;
+
+       return qsolver->solver.GetPoleAngle();
+}
+
 void IK_SolverAddCenterOfMass(IK_Solver *solver, IK_Segment *root, float goal[3], float weight)
 {
        if (solver == NULL || root == NULL)
@@ -346,6 +371,9 @@ int IK_Solve(IK_Solver *solver, float tolerance, int max_iterations)
        std::list<IK_QTask*>& tasks = qsolver->tasks;
        MT_Scalar tol = tolerance;
 
+       if(!jacobian.Setup(root, tasks))
+               return 0;
+
        bool result = jacobian.Solve(root, tasks, tol, max_iterations);
 
        return ((result)? 1: 0);
index 40fd8c5ed1848c440d3bc401e8245de75ac090da..aa8e9cf18f8b3b149fa937f1aa3ae6400ea391c6 100644 (file)
@@ -126,14 +126,13 @@ void copy_constraint_channels(struct ListBase *dst, struct ListBase *src);
 void clone_constraint_channels(struct ListBase *dst, struct ListBase *src);
 void free_constraint_channels(struct ListBase *chanbase);
 
-
 /* Constraint Evaluation function prototypes */
 struct bConstraintOb *constraints_make_evalob(struct Object *ob, void *subdata, short datatype);
 void constraints_clear_evalob(struct bConstraintOb *cob);
 
 void constraint_mat_convertspace(struct Object *ob, struct bPoseChannel *pchan, float mat[][4], short from, short to);
 
-void get_constraint_target_matrix(struct bConstraint *con, short ownertype, void *ownerdata, float mat[][4], float ctime);
+void get_constraint_target_matrix(struct bConstraint *con, int n, short ownertype, void *ownerdata, float mat[][4], float ctime);
 void solve_constraints(struct ListBase *conlist, struct bConstraintOb *cob, float ctime);
 
 
index 09a7b2a8dcc309c8ce4789227a4f72fd3bfb4180..38a6a05017c54ff804e109a0157f0150e1821511 100644 (file)
@@ -1512,7 +1512,7 @@ static void execute_posetree(Object *ob, PoseTree *tree)
        IK_Segment *seg, *parent, **iktree, *iktarget;
        IK_Solver *solver;
        PoseTarget *target;
-       bKinematicConstraint *data;
+       bKinematicConstraint *data, *poleangledata=NULL;
        Bone *bone;
 
        if (tree->totchannel == 0)
@@ -1624,12 +1624,15 @@ static void execute_posetree(Object *ob, PoseTree *tree)
        Mat4Invert (goalinv, imat);
        
        for (target=tree->targets.first; target; target=target->next) {
+               float polepos[3];
+               int poleconstrain= 0;
+
                data= (bKinematicConstraint*)target->con->data;
                
                /* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though
                 * strictly speaking, it is a posechannel)
                 */
-               get_constraint_target_matrix(target->con, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
+               get_constraint_target_matrix(target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
                
                /* and set and transform goal */
                Mat4MulMat4(goal, rootmat, goalinv);
@@ -1637,6 +1640,26 @@ static void execute_posetree(Object *ob, PoseTree *tree)
                VECCOPY(goalpos, goal[3]);
                Mat3CpyMat4(goalrot, goal);
                
+               /* same for pole vector target */
+               if(data->poletar) {
+                       get_constraint_target_matrix(target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
+
+                       if(data->flag & CONSTRAINT_IK_SETANGLE) {
+                               /* don't solve IK when we are setting the pole angle */
+                               break;
+                       }
+                       else {
+                               Mat4MulMat4(goal, rootmat, goalinv);
+                               VECCOPY(polepos, goal[3]);
+                               poleconstrain= 1;
+
+                               if(data->flag & CONSTRAINT_IK_GETANGLE) {
+                                       poleangledata= data;
+                                       data->flag &= ~CONSTRAINT_IK_GETANGLE;
+                               }
+                       }
+               }
+
                /* do we need blending? */
                if (target->con->enforce!=1.0) {
                        float q1[4], q2[4], q[4];
@@ -1664,14 +1687,24 @@ static void execute_posetree(Object *ob, PoseTree *tree)
                
                iktarget= iktree[target->tip];
                
-               if(data->weight != 0.0)
+               if(data->weight != 0.0) {
+                       if(poleconstrain)
+                               IK_SolverSetPoleVectorConstraint(solver, iktarget, goalpos,
+                                       polepos, data->poleangle*M_PI/180, (poleangledata == data));
                        IK_SolverAddGoal(solver, iktarget, goalpos, data->weight);
-               if((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0) && (data->flag & CONSTRAINT_IK_AUTO)==0)
-                       IK_SolverAddGoalOrientation(solver, iktarget, goalrot, data->orientweight);
+               }
+               if((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0))
+                       if((data->flag & CONSTRAINT_IK_AUTO)==0)
+                               IK_SolverAddGoalOrientation(solver, iktarget, goalrot,
+                                       data->orientweight);
        }
 
        /* solve */
        IK_Solve(solver, 0.0f, tree->iterations);
+
+       if(poleangledata)
+               poleangledata->poleangle= IK_SolverGetPoleAngle(solver)*180/M_PI;
+
        IK_FreeSolver(solver);
 
        /* gather basis changes */
index 9dce9c3a611676745a687883d25da858c869d64a..a8305a7dec15941a2cd90bc9f1c13a34c9e68e4d 100644 (file)
@@ -804,12 +804,12 @@ static void default_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstrain
  * (Hopefully all compilers will be happy with the lines with just a space on them. Those are
  *  really just to help this code easier to read)
  */
-#define SINGLETARGET_GET_TARS(con, data, ct, list) \
+#define SINGLETARGET_GET_TARS(con, datatar, datasubtarget, ct, list) \
        { \
                ct= MEM_callocN(sizeof(bConstraintTarget), "tempConstraintTarget"); \
                 \
-               ct->tar= data->tar; \
-               strcpy(ct->subtarget, data->subtarget); \
+               ct->tar= datatar; \
+               strcpy(ct->subtarget, datasubtarget); \
                ct->space= con->tarspace; \
                ct->flag= CONSTRAINT_TAR_TEMP; \
                 \
@@ -827,11 +827,11 @@ static void default_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstrain
  * (Hopefully all compilers will be happy with the lines with just a space on them. Those are
  *  really just to help this code easier to read)
  */
-#define SINGLETARGETNS_GET_TARS(con, data, ct, list) \
+#define SINGLETARGETNS_GET_TARS(con, datatar, ct, list) \
        { \
                ct= MEM_callocN(sizeof(bConstraintTarget), "tempConstraintTarget"); \
                 \
-               ct->tar= data->tar; \
+               ct->tar= datatar; \
                ct->space= con->tarspace; \
                ct->flag= CONSTRAINT_TAR_TEMP; \
                 \
@@ -845,16 +845,16 @@ static void default_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstrain
  * (Hopefully all compilers will be happy with the lines with just a space on them. Those are
  *  really just to help this code easier to read)
  */
-#define SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy) \
+#define SINGLETARGET_FLUSH_TARS(con, datatar, datasubtarget, ct, list, nocopy) \
        { \
                if (ct) { \
                        if (nocopy == 0) { \
-                               data->tar= ct->tar; \
-                               strcpy(data->subtarget, ct->subtarget); \
+                               datatar= ct->tar; \
+                               strcpy(datasubtarget, ct->subtarget); \
                                con->tarspace= ct->space; \
                        } \
                         \
-                       BLI_freelistN(list); \
+                       BLI_freelinkN(list, ct); \
                } \
        }
        
@@ -863,15 +863,15 @@ static void default_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstrain
  * (Hopefully all compilers will be happy with the lines with just a space on them. Those are
  *  really just to help this code easier to read)
  */
-#define SINGLETARGETNS_FLUSH_TARS(con, data, ct, list, nocopy) \
+#define SINGLETARGETNS_FLUSH_TARS(con, datatar, ct, list, nocopy) \
        { \
                if (ct) { \
                        if (nocopy == 0) { \
-                               data->tar= ct->tar; \
+                               datatar= ct->tar; \
                                con->tarspace= ct->space; \
                        } \
                         \
-                       BLI_freelistN(list); \
+                       BLI_freelinkN(list, ct); \
                } \
        }
  
@@ -894,7 +894,7 @@ static void childof_get_tars (bConstraint *con, ListBase *list)
                bConstraintTarget *ct;
                
                /* standard target-getting macro for single-target constraints */
-               SINGLETARGET_GET_TARS(con, data, ct, list)
+               SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
        }
 }
 
@@ -905,7 +905,7 @@ static void childof_flush_tars (bConstraint *con, ListBase *list, short nocopy)
                bConstraintTarget *ct= list->first;
                
                /* the following macro is used for all standard single-target constraints */
-               SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy)
+               SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
        }
 }
 
@@ -992,7 +992,7 @@ static void trackto_get_tars (bConstraint *con, ListBase *list)
                bConstraintTarget *ct;
                
                /* standard target-getting macro for single-target constraints */
-               SINGLETARGET_GET_TARS(con, data, ct, list)
+               SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
        }
 }
 
@@ -1003,7 +1003,7 @@ static void trackto_flush_tars (bConstraint *con, ListBase *list, short nocopy)
                bConstraintTarget *ct= list->first;
                
                /* the following macro is used for all standard single-target constraints */
-               SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy)
+               SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
        }
 }
 
@@ -1169,7 +1169,8 @@ static void kinematic_get_tars (bConstraint *con, ListBase *list)
                bConstraintTarget *ct;
                
                /* standard target-getting macro for single-target constraints */
-               SINGLETARGET_GET_TARS(con, data, ct, list)
+               SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
+               SINGLETARGET_GET_TARS(con, data->poletar, data->polesubtarget, ct, list)
        }
 }
 
@@ -1180,7 +1181,9 @@ static void kinematic_flush_tars (bConstraint *con, ListBase *list, short nocopy
                bConstraintTarget *ct= list->first;
                
                /* the following macro is used for all standard single-target constraints */
-               SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy)
+               SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
+               ct= ct->next;
+               SINGLETARGET_FLUSH_TARS(con, data->poletar, data->polesubtarget, ct, list, nocopy)
        }
 }
 
@@ -1245,7 +1248,7 @@ static void followpath_get_tars (bConstraint *con, ListBase *list)
                bConstraintTarget *ct;
                
                /* standard target-getting macro for single-target constraints without subtargets */
-               SINGLETARGETNS_GET_TARS(con, data, ct, list)
+               SINGLETARGETNS_GET_TARS(con, data->tar, ct, list)
        }
 }
 
@@ -1256,7 +1259,7 @@ static void followpath_flush_tars (bConstraint *con, ListBase *list, short nocop
                bConstraintTarget *ct= list->first;
                
                /* the following macro is used for all standard single-target constraints */
-               SINGLETARGETNS_FLUSH_TARS(con, data, ct, list, nocopy)
+               SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, nocopy)
        }
 }
 
@@ -1283,7 +1286,7 @@ static void followpath_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstr
                
                if (cu->path && cu->path->data) {
                        curvetime= bsystem_time(ct->tar, (float)ctime, 0.0) - data->offset;
-                       
+
                        if (calc_ipo_spec(cu->ipo, CU_SPEED, &curvetime)==0) {
                                curvetime /= cu->pathlen;
                                CLAMP(curvetime, 0.0, 1.0);
@@ -1546,7 +1549,7 @@ static void loclike_get_tars (bConstraint *con, ListBase *list)
                bConstraintTarget *ct;
                
                /* standard target-getting macro for single-target constraints */
-               SINGLETARGET_GET_TARS(con, data, ct, list)
+               SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
        }
 }
 
@@ -1557,7 +1560,7 @@ static void loclike_flush_tars (bConstraint *con, ListBase *list, short nocopy)
                bConstraintTarget *ct= list->first;
                
                /* the following macro is used for all standard single-target constraints */
-               SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy)
+               SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
        }
 }
 
@@ -1661,7 +1664,7 @@ static void rotlike_get_tars (bConstraint *con, ListBase *list)
                bConstraintTarget *ct;
                
                /* standard target-getting macro for single-target constraints */
-               SINGLETARGET_GET_TARS(con, data, ct, list)
+               SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
        }
 }
 
@@ -1672,7 +1675,7 @@ static void rotlike_flush_tars (bConstraint *con, ListBase *list, short nocopy)
                bConstraintTarget *ct= list->first;
                
                /* the following macro is used for all standard single-target constraints */
-               SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy)
+               SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
        }
 }
 
@@ -1749,7 +1752,7 @@ static void sizelike_get_tars (bConstraint *con, ListBase *list)
                bConstraintTarget *ct;
                
                /* standard target-getting macro for single-target constraints */
-               SINGLETARGET_GET_TARS(con, data, ct, list)
+               SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
        }
 }
 
@@ -1760,7 +1763,7 @@ static void sizelike_flush_tars (bConstraint *con, ListBase *list, short nocopy)
                bConstraintTarget *ct= list->first;
                
                /* the following macro is used for all standard single-target constraints */
-               SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy)
+               SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
        }
 }
 
@@ -1928,7 +1931,7 @@ static void actcon_get_tars (bConstraint *con, ListBase *list)
                bConstraintTarget *ct;
                
                /* standard target-getting macro for single-target constraints */
-               SINGLETARGET_GET_TARS(con, data, ct, list)
+               SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
        }
 }
 
@@ -1939,7 +1942,7 @@ static void actcon_flush_tars (bConstraint *con, ListBase *list, short nocopy)
                bConstraintTarget *ct= list->first;
                
                /* the following macro is used for all standard single-target constraints */
-               SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy)
+               SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
        }
 }
 
@@ -2068,7 +2071,7 @@ static void locktrack_get_tars (bConstraint *con, ListBase *list)
                bConstraintTarget *ct;
                
                /* the following macro is used for all standard single-target constraints */
-               SINGLETARGET_GET_TARS(con, data, ct, list)
+               SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
        }
 }
 
@@ -2079,7 +2082,7 @@ static void locktrack_flush_tars (bConstraint *con, ListBase *list, short nocopy
                bConstraintTarget *ct= list->first;
                
                /* the following macro is used for all standard single-target constraints */
-               SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy)
+               SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
        }
 }
 
@@ -2419,7 +2422,7 @@ static void stretchto_get_tars (bConstraint *con, ListBase *list)
                bConstraintTarget *ct;
                
                /* standard target-getting macro for single-target constraints */
-               SINGLETARGET_GET_TARS(con, data, ct, list)
+               SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
        }
 }
 
@@ -2430,7 +2433,7 @@ static void stretchto_flush_tars (bConstraint *con, ListBase *list, short nocopy
                bConstraintTarget *ct= list->first;
                
                /* the following macro is used for all standard single-target constraints */
-               SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy)
+               SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
        }
 }
 
@@ -2595,7 +2598,7 @@ static void minmax_get_tars (bConstraint *con, ListBase *list)
                bConstraintTarget *ct;
                
                /* standard target-getting macro for single-target constraints */
-               SINGLETARGET_GET_TARS(con, data, ct, list)
+               SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
        }
 }
 
@@ -2606,7 +2609,7 @@ static void minmax_flush_tars (bConstraint *con, ListBase *list, short nocopy)
                bConstraintTarget *ct= list->first;
                
                /* the following macro is used for all standard single-target constraints */
-               SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy)
+               SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
        }
 }
 
@@ -2725,7 +2728,7 @@ static void rbj_get_tars (bConstraint *con, ListBase *list)
                bConstraintTarget *ct;
                
                /* standard target-getting macro for single-target constraints without subtargets */
-               SINGLETARGETNS_GET_TARS(con, data, ct, list)
+               SINGLETARGETNS_GET_TARS(con, data->tar, ct, list)
        }
 }
 
@@ -2736,7 +2739,7 @@ static void rbj_flush_tars (bConstraint *con, ListBase *list, short nocopy)
                bConstraintTarget *ct= list->first;
                
                /* the following macro is used for all standard single-target constraints */
-               SINGLETARGETNS_FLUSH_TARS(con, data, ct, list, nocopy)
+               SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, nocopy)
        }
 }
 
@@ -2764,7 +2767,7 @@ static void clampto_get_tars (bConstraint *con, ListBase *list)
                bConstraintTarget *ct;
                
                /* standard target-getting macro for single-target constraints without subtargets */
-               SINGLETARGETNS_GET_TARS(con, data, ct, list)
+               SINGLETARGETNS_GET_TARS(con, data->tar, ct, list)
        }
 }
 
@@ -2775,7 +2778,7 @@ static void clampto_flush_tars (bConstraint *con, ListBase *list, short nocopy)
                bConstraintTarget *ct= list->first;
                
                /* the following macro is used for all standard single-target constraints */
-               SINGLETARGETNS_FLUSH_TARS(con, data, ct, list, nocopy)
+               SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, nocopy)
        }
 }
 
@@ -2937,7 +2940,7 @@ static void transform_get_tars (bConstraint *con, ListBase *list)
                bConstraintTarget *ct;
                
                /* standard target-getting macro for single-target constraints */
-               SINGLETARGET_GET_TARS(con, data, ct, list)
+               SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
        }
 }
 
@@ -2948,7 +2951,7 @@ static void transform_flush_tars (bConstraint *con, ListBase *list, short nocopy
                bConstraintTarget *ct= list->first;
                
                /* the following macro is used for all standard single-target constraints */
-               SINGLETARGET_FLUSH_TARS(con, data, ct, list, nocopy)
+               SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
        }
 }
 
@@ -3225,7 +3228,7 @@ void copy_constraints (ListBase *dst, ListBase *src)
  * None of the actual calculations of the matricies should be done here! Also, this function is 
  * not to be used by any new constraints, particularly any that have multiple targets.
  */
-void get_constraint_target_matrix (bConstraint *con, short ownertype, void *ownerdata, float mat[][4], float ctime)
+void get_constraint_target_matrix (bConstraint *con, int n, short ownertype, void *ownerdata, float mat[][4], float ctime)
 {
        bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
        ListBase targets = {NULL, NULL};
@@ -3272,6 +3275,9 @@ void get_constraint_target_matrix (bConstraint *con, short ownertype, void *owne
                
                /* only calculate the target matrix on the first target */
                ct= (bConstraintTarget *)targets.first;
+               while(ct && n-- > 0)
+                       ct= ct->next;
+
                if (ct) {
                        if (cti->get_target_matrix)
                                cti->get_target_matrix(con, cob, ct, ctime);
index e1d538a54dad9e94b4a58bbc4b22dda2aaeeb03d..2293fbef0b5e09dd481a6fad277872361e5e8d19 100644 (file)
@@ -1664,6 +1664,7 @@ static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist)
                                bKinematicConstraint *data;
                                data = ((bKinematicConstraint*)con->data);
                                data->tar = newlibadr(fd, id->lib, data->tar);
+                               data->poletar = newlibadr(fd, id->lib, data->poletar);
                        }
                        break;
                case CONSTRAINT_TYPE_TRACKTO:
@@ -7289,6 +7290,7 @@ static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb)
                        {
                                bKinematicConstraint *data = (bKinematicConstraint*)curcon->data;
                                expand_doit(fd, mainvar, data->tar);
+                               expand_doit(fd, mainvar, data->poletar);
                        }
                        break;
                case CONSTRAINT_TYPE_TRACKTO:
index e06063a11a15093de37ce5303f8502464065a038..431ef56e1c4e05ed78314a2da64577f14ff2de11 100644 (file)
@@ -125,10 +125,13 @@ typedef struct bKinematicConstraint {
        int                     rootbone;       /* index to rootbone, if zero go all the way to mother bone */
        char            subtarget[32];  /* String to specify sub-object target */
 
+       Object          *poletar;                       /* Pole vector target */
+       char            polesubtarget[32];      /* Pole vector sub-object target */
+       float           poleangle;                      /* Pole vector rest angle */
+
        float           weight;                 /* Weight of goal in IK tree */
        float           orientweight;   /* Amount of rotation a target applies on chain */
        float           grabtarget[3];  /* for target-less IK */
-       int                     pad;
 } bKinematicConstraint;
 
 /* Track To Constraint */
@@ -439,6 +442,8 @@ typedef enum B_CONSTRAINTCHANNEL_FLAG {
 #define CONSTRAINT_IK_TEMP             8
 #define CONSTRAINT_IK_STRETCH  16
 #define CONSTRAINT_IK_POS              32
+#define CONSTRAINT_IK_SETANGLE 64
+#define CONSTRAINT_IK_GETANGLE 128
 
 /* MinMax (floor) flags */
 #define MINMAX_STICKY  0x01
index 94a40a7ebb61ae2fbed813d24ff1a55079c64658..35db9294af1fdc2100e29d78a8234d30d9fc7f85 100644 (file)
@@ -410,6 +410,24 @@ void autocomplete_vgroup(char *str, void *arg_v)
        }
 }
 
+/* pole angle callback */
+void con_kinematic_set_pole_angle(void *ob_v, void *con_v)
+{
+       bConstraint *con= con_v;
+       bKinematicConstraint *data = con->data;
+
+       if(data->poletar) {
+               if(data->flag & CONSTRAINT_IK_SETANGLE) {
+                       data->flag |= CONSTRAINT_IK_GETANGLE;
+                       data->flag &= ~CONSTRAINT_IK_SETANGLE;
+               }
+               else {
+                       data->flag &= ~CONSTRAINT_IK_GETANGLE;
+                       data->flag |= CONSTRAINT_IK_SETANGLE;
+               }
+       }
+}
+
 /* some commonly used macros in the constraints drawing code */
 #define is_armature_target(target) (target && target->type==OB_ARMATURE)
 #define is_armature_owner(ob) ((ob->type == OB_ARMATURE) && (ob->flag & OB_POSEMODE))
@@ -878,47 +896,76 @@ static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, s
                        {
                                bKinematicConstraint *data = con->data;
                                
-                               height = 111;
+                               height = 146;
+                               if(data->poletar) 
+                                       height += 30;
+
                                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, ""); 
+                               /* IK Target */
+                               uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
                                
                                /* Draw target parameters */
-                               uiDefButBitS(block, TOG, CONSTRAINT_IK_ROT, B_CONSTRAINT_TEST, "Rot", *xco, *yco-24,60,19, &data->flag, 0, 0, 0, 0, "Chain follows rotation of target");
-                               
                                uiBlockBeginAlign(block);
-                                       uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 19, &data->tar, "Target Object"); 
-                                       
-                                       if (is_armature_target(data->tar)) {
-                                               but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,19, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone");
-                                               uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar);
-                                       }
-                                       else if (is_geom_target(data->tar)) {
-                                               but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points");
-                                               uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar);
-                                       }
-                                       else {
-                                               strcpy(data->subtarget, "");
-                                       }
+                               uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco, *yco-44, 137, 19, &data->tar, "Target Object"); 
+
+                               if (is_armature_target(data->tar)) {
+                                       but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco, *yco-62,137,19, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone");
+                                       uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar);
+                               }
+                               else if (is_geom_target(data->tar)) {
+                                       but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco, *yco-62,137,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points");
+                                       uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar);
+                               }
+                               else {
+                                       strcpy (data->subtarget, "");
+                               }
+
                                uiBlockEndAlign(block);
-                               
+
+                               /* Settings */
                                uiBlockBeginAlign(block);
-                                       uiDefButBitS(block, TOG, CONSTRAINT_IK_TIP, B_CONSTRAINT_TEST, "Use Tail", *xco, *yco-64, 137, 19, &data->flag, 0, 0, 0, 0, "Include Bone's tail as last element in Chain");
-                                       uiDefButI(block, NUM, B_CONSTRAINT_TEST, "ChainLen:", *xco, *yco-84,137,19, &data->rootbone, 0, 255, 0, 0, "If not zero, the amount of bones in this chain");
-                               uiBlockEndAlign(block);
-                               
+                               uiDefButBitS(block, TOG, CONSTRAINT_IK_TIP, B_CONSTRAINT_TEST, "Use Tail", *xco, *yco-92, 137, 19, &data->flag, 0, 0, 0, 0, "Include Bone's tail als last element in Chain");
+                               uiDefButI(block, NUM, B_CONSTRAINT_TEST, "ChainLen:", *xco, *yco-112,137,19, &data->rootbone, 0, 255, 0, 0, "If not zero, the amount of bones in this chain");
+
                                uiBlockBeginAlign(block);
-                                       uiDefButF(block, NUMSLI, B_CONSTRAINT_TEST, "PosW ", *xco+147, *yco-64, 137, 19, &data->weight, 0.01, 1.0, 2, 2, "For Tree-IK: weight of position control for this target");
-                                       uiDefButF(block, NUMSLI, B_CONSTRAINT_TEST, "RotW ", *xco+147, *yco-84, 137, 19, &data->orientweight, 0.01, 1.0, 2, 2, "For Tree-IK: Weight of orientation control for this target");
-                               uiBlockEndAlign(block);
-                               
+                               uiDefButF(block, NUMSLI, B_CONSTRAINT_TEST, "PosW ", *xco+147, *yco-92, 137, 19, &data->weight, 0.01, 1.0, 2, 2, "For Tree-IK: weight of position control for this target");
+                               uiDefButBitS(block, TOG, CONSTRAINT_IK_ROT, B_CONSTRAINT_TEST, "Rot", *xco+147, *yco-112, 40,19, &data->flag, 0, 0, 0, 0, "Chain follows rotation of target");
+                               uiDefButF(block, NUMSLI, B_CONSTRAINT_TEST, "W ", *xco+187, *yco-112, 97, 19, &data->orientweight, 0.01, 1.0, 2, 2, "For Tree-IK: Weight of orientation control for this target");
+
                                uiBlockBeginAlign(block);
-                                       uiDefButS(block, NUM, B_CONSTRAINT_TEST, "Iterations:", *xco, *yco-109, 137, 19, &data->iterations, 1, 10000, 0, 0, "Maximum number of solving iterations"); 
-                               uiBlockEndAlign(block);
-                               
+
+                               uiDefButBitS(block, TOG, CONSTRAINT_IK_STRETCH, B_CONSTRAINT_TEST, "Stretch", *xco, *yco-137,137,19, &data->flag, 0, 0, 0, 0, "Enable IK stretching");
                                uiBlockBeginAlign(block);
-                                       uiDefButBitS(block, TOG, CONSTRAINT_IK_STRETCH, B_CONSTRAINT_TEST, "Stretch", *xco+147, *yco-109,137,19, &data->flag, 0, 0, 0, 0, "Enable IK stretching");
+                               uiDefButS(block, NUM, B_CONSTRAINT_TEST, "Iterations:", *xco+147, *yco-137, 137, 19, &data->iterations, 1, 10000, 0, 0, "Maximum number of solving iterations"); 
                                uiBlockEndAlign(block);
+
+                               /* Pole Vector */
+                               uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Pole Target:", *xco+147, *yco-24, 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, ""); 
+
+                               uiBlockBeginAlign(block);
+                               uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+147, *yco-44, 137, 19, &data->poletar, "Pole Target Object"); 
+                               if (is_armature_target(data->poletar)) {
+                                       but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+147, *yco-62,137,19, &data->polesubtarget, 0, 24, 0, 0, "Pole Subtarget Bone");
+                                       uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->poletar);
+                               }
+                               else if (is_geom_target(data->poletar)) {
+                                       but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+147, *yco-62,137,18, &data->polesubtarget, 0, 24, 0, 0, "Name of Vertex Group defining pole 'target' points");
+                                       uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->poletar);
+                               }
+                               else {
+                                       strcpy (data->polesubtarget, "");
+                               }
+       
+                               if(data->poletar) {
+                                       uiBlockBeginAlign(block);
+#if 0
+                                       but = uiDefBut(block, BUT, B_CONSTRAINT_TEST, (data->flag & CONSTRAINT_IK_SETANGLE)? "Set Pole Offset": "Clear Pole Offset", *xco, *yco-167, 137, 19, 0, 0.0, 1.0, 0.0, 0.0, "Set the pole rotation offset from the current pose");
+                                       uiButSetFunc(but, con_kinematic_set_pole_angle, ob, con);
+                                       if(!(data->flag & CONSTRAINT_IK_SETANGLE))
+#endif
+                                               uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Pole Offset ", *xco, *yco-167, 137, 19, &data->poleangle, -180.0, 180.0, 0, 0, "Pole rotation offset");
+                               }
                        }
                        break;
                case CONSTRAINT_TYPE_TRACKTO:
index 0360c4add1875555a4a514492291a00455e80129..e0588b4c2a0493dff946dde585672bec75ccaa3c 100644 (file)
@@ -417,18 +417,26 @@ static void test_constraints (Object *owner, const char substring[])
                                case CONSTRAINT_TYPE_KINEMATIC:
                                {
                                        bKinematicConstraint *data = curcon->data;
+
                                        if (!exist_object(data->tar)) {
                                                data->tar = NULL;
                                                curcon->flag |= CONSTRAINT_DISABLE;
-                                               break;
                                        }
-                                       
-                                       if ( (data->tar == owner) &&
+                                       else if ( (data->tar == owner) &&
                                                 (!get_named_bone(get_armature(owner), 
                                                                                  data->subtarget))) {
                                                curcon->flag |= CONSTRAINT_DISABLE;
-                                               break;
                                        }
+
+                                       if (data->poletar && !exist_object(data->poletar)) {
+                                               data->poletar = NULL;
+                                       }
+                                       else if ( (data->poletar == owner) &&
+                                                (!get_named_bone(get_armature(owner), 
+                                                                                 data->polesubtarget))) {
+                                               curcon->flag |= CONSTRAINT_DISABLE;
+                                       }
+
                                }
                                        break;
                                case CONSTRAINT_TYPE_TRACKTO:
@@ -816,7 +824,7 @@ void add_constraint(int only_IK)
                set_constraint_nth_target(con, ob, pchansel->name, 0);
        }
        else if(obsel) {
-               set_constraint_nth_target(con, obsel, NULL, 0);
+               set_constraint_nth_target(con, obsel, "", 0);
        }
        else if (ELEM4(nr, 11, 13, 14, 15)==0) {        /* add new empty as target */
                Base *base= BASACT, *newbase;
@@ -838,7 +846,7 @@ void add_constraint(int only_IK)
                else
                        VECCOPY(obt->loc, ob->obmat[3]);
                
-               set_constraint_nth_target(con, obt, NULL, 0);
+               set_constraint_nth_target(con, obt, "", 0);
                
                /* restore, add_object sets active */
                BASACT= base;
index 1c9cf15bc7e84a52ae7bb79439b5880f36e5a7d7..997593b30b1ee515f4262fd83603b3e0223286f4 100644 (file)
@@ -1416,7 +1416,7 @@ void make_parent(void)
                                                
                                                add_constraint_to_object(con, base->object);
                                                
-                                               get_constraint_target_matrix(con, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, G.scene->r.cfra - base->object->sf);
+                                               get_constraint_target_matrix(con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, G.scene->r.cfra - base->object->sf);
                                                VecSubf(vec, base->object->obmat[3], cmat[3]);
                                                
                                                base->object->loc[0] = vec[0];