Blender  V2.93
IK_QJacobianSolver.cpp
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
24 #include <stdio.h>
25 
26 #include "IK_QJacobianSolver.h"
27 
28 //#include "analyze.h"
30 {
31  m_poleconstraint = false;
32  m_getpoleangle = false;
33  m_rootmatrix.setIdentity();
34 }
35 
36 double IK_QJacobianSolver::ComputeScale()
37 {
38  std::vector<IK_QSegment *>::iterator seg;
39  double length = 0.0f;
40 
41  for (seg = m_segments.begin(); seg != m_segments.end(); seg++)
42  length += (*seg)->MaxExtension();
43 
44  if (length == 0.0)
45  return 1.0;
46  else
47  return 1.0 / length;
48 }
49 
50 void IK_QJacobianSolver::Scale(double scale, std::list<IK_QTask *> &tasks)
51 {
52  std::list<IK_QTask *>::iterator task;
53  std::vector<IK_QSegment *>::iterator seg;
54 
55  for (task = tasks.begin(); task != tasks.end(); task++)
56  (*task)->Scale(scale);
57 
58  for (seg = m_segments.begin(); seg != m_segments.end(); seg++)
59  (*seg)->Scale(scale);
60 
61  m_rootmatrix.translation() *= scale;
62  m_goal *= scale;
63  m_polegoal *= scale;
64 }
65 
66 void IK_QJacobianSolver::AddSegmentList(IK_QSegment *seg)
67 {
68  m_segments.push_back(seg);
69 
70  IK_QSegment *child;
71  for (child = seg->Child(); child; child = child->Sibling())
72  AddSegmentList(child);
73 }
74 
75 bool IK_QJacobianSolver::Setup(IK_QSegment *root, std::list<IK_QTask *> &tasks)
76 {
77  m_segments.clear();
78  AddSegmentList(root);
79 
80  // assign each segment a unique id for the jacobian
81  std::vector<IK_QSegment *>::iterator seg;
82  int num_dof = 0;
83 
84  for (seg = m_segments.begin(); seg != m_segments.end(); seg++) {
85  (*seg)->SetDoFId(num_dof);
86  num_dof += (*seg)->NumberOfDoF();
87  }
88 
89  if (num_dof == 0)
90  return false;
91 
92  // compute task id's and assing weights to task
93  int primary_size = 0, primary = 0;
94  int secondary_size = 0, secondary = 0;
95  double primary_weight = 0.0, secondary_weight = 0.0;
96  std::list<IK_QTask *>::iterator task;
97 
98  for (task = tasks.begin(); task != tasks.end(); task++) {
99  IK_QTask *qtask = *task;
100 
101  if (qtask->Primary()) {
102  qtask->SetId(primary_size);
103  primary_size += qtask->Size();
104  primary_weight += qtask->Weight();
105  primary++;
106  }
107  else {
108  qtask->SetId(secondary_size);
109  secondary_size += qtask->Size();
110  secondary_weight += qtask->Weight();
111  secondary++;
112  }
113  }
114 
115  if (primary_size == 0 || FuzzyZero(primary_weight))
116  return false;
117 
118  m_secondary_enabled = (secondary > 0);
119 
120  // rescale weights of tasks to sum up to 1
121  double primary_rescale = 1.0 / primary_weight;
122  double secondary_rescale;
123  if (FuzzyZero(secondary_weight))
124  secondary_rescale = 0.0;
125  else
126  secondary_rescale = 1.0 / secondary_weight;
127 
128  for (task = tasks.begin(); task != tasks.end(); task++) {
129  IK_QTask *qtask = *task;
130 
131  if (qtask->Primary())
132  qtask->SetWeight(qtask->Weight() * primary_rescale);
133  else
134  qtask->SetWeight(qtask->Weight() * secondary_rescale);
135  }
136 
137  // set matrix sizes
138  m_jacobian.ArmMatrices(num_dof, primary_size);
139  if (secondary > 0)
140  m_jacobian_sub.ArmMatrices(num_dof, secondary_size);
141 
142  // set dof weights
143  int i;
144 
145  for (seg = m_segments.begin(); seg != m_segments.end(); seg++)
146  for (i = 0; i < (*seg)->NumberOfDoF(); i++)
147  m_jacobian.SetDoFWeight((*seg)->DoFId() + i, (*seg)->Weight(i));
148 
149  return true;
150 }
151 
153  IK_QSegment *tip, Vector3d &goal, Vector3d &polegoal, float poleangle, bool getangle)
154 {
155  m_poleconstraint = true;
156  m_poletip = tip;
157  m_goal = goal;
158  m_polegoal = polegoal;
159  m_poleangle = (getangle) ? 0.0f : poleangle;
160  m_getpoleangle = getangle;
161 }
162 
163 void IK_QJacobianSolver::ConstrainPoleVector(IK_QSegment *root, std::list<IK_QTask *> &tasks)
164 {
165  // this function will be called before and after solving. calling it before
166  // solving gives predictable solutions by rotating towards the solution,
167  // and calling it afterwards ensures the solution is exact.
168 
169  if (!m_poleconstraint)
170  return;
171 
172  // disable pole vector constraint in case of multiple position tasks
173  std::list<IK_QTask *>::iterator task;
174  int positiontasks = 0;
175 
176  for (task = tasks.begin(); task != tasks.end(); task++)
177  if ((*task)->PositionTask())
178  positiontasks++;
179 
180  if (positiontasks >= 2) {
181  m_poleconstraint = false;
182  return;
183  }
184 
185  // get positions and rotations
186  root->UpdateTransform(m_rootmatrix);
187 
188  const Vector3d rootpos = root->GlobalStart();
189  const Vector3d endpos = m_poletip->GlobalEnd();
190  const Matrix3d &rootbasis = root->GlobalTransform().linear();
191 
192  // construct "lookat" matrices (like gluLookAt), based on a direction and
193  // an up vector, with the direction going from the root to the end effector
194  // and the up vector going from the root to the pole constraint position.
195  Vector3d dir = normalize(endpos - rootpos);
196  Vector3d rootx = rootbasis.col(0);
197  Vector3d rootz = rootbasis.col(2);
198  Vector3d up = rootx * cos(m_poleangle) + rootz * sin(m_poleangle);
199 
200  // in post, don't rotate towards the goal but only correct the pole up
201  Vector3d poledir = (m_getpoleangle) ? dir : normalize(m_goal - rootpos);
202  Vector3d poleup = normalize(m_polegoal - rootpos);
203 
204  Matrix3d mat, polemat;
205 
206  mat.row(0) = normalize(dir.cross(up));
207  mat.row(1) = mat.row(0).cross(dir);
208  mat.row(2) = -dir;
209 
210  polemat.row(0) = normalize(poledir.cross(poleup));
211  polemat.row(1) = polemat.row(0).cross(poledir);
212  polemat.row(2) = -poledir;
213 
214  if (m_getpoleangle) {
215  // we compute the pole angle that to rotate towards the target
216  m_poleangle = angle(mat.row(1), polemat.row(1));
217 
218  double dt = rootz.dot(mat.row(1) * cos(m_poleangle) + mat.row(0) * sin(m_poleangle));
219  if (dt > 0.0)
220  m_poleangle = -m_poleangle;
221 
222  // solve again, with the pole angle we just computed
223  m_getpoleangle = false;
224  ConstrainPoleVector(root, tasks);
225  }
226  else {
227  // now we set as root matrix the difference between the current and
228  // desired rotation based on the pole vector constraint. we use
229  // transpose instead of inverse because we have orthogonal matrices
230  // anyway, and in case of a singular matrix we don't get NaN's.
231  Affine3d trans;
232  trans.linear() = polemat.transpose() * mat;
233  trans.translation() = Vector3d(0, 0, 0);
234  m_rootmatrix = trans * m_rootmatrix;
235  }
236 }
237 
238 bool IK_QJacobianSolver::UpdateAngles(double &norm)
239 {
240  // assing each segment a unique id for the jacobian
241  std::vector<IK_QSegment *>::iterator seg;
242  IK_QSegment *qseg, *minseg = NULL;
243  double minabsdelta = 1e10, absdelta;
244  Vector3d delta, mindelta;
245  bool locked = false, clamp[3];
246  int i, mindof = 0;
247 
248  // here we check if any angle limits were violated. angles whose clamped
249  // position is the same as it was before, are locked immediate. of the
250  // other violation angles the most violating angle is rememberd
251  for (seg = m_segments.begin(); seg != m_segments.end(); seg++) {
252  qseg = *seg;
253  if (qseg->UpdateAngle(m_jacobian, delta, clamp)) {
254  for (i = 0; i < qseg->NumberOfDoF(); i++) {
255  if (clamp[i] && !qseg->Locked(i)) {
256  absdelta = fabs(delta[i]);
257 
258  if (absdelta < IK_EPSILON) {
259  qseg->Lock(i, m_jacobian, delta);
260  locked = true;
261  }
262  else if (absdelta < minabsdelta) {
263  minabsdelta = absdelta;
264  mindelta = delta;
265  minseg = qseg;
266  mindof = i;
267  }
268  }
269  }
270  }
271  }
272 
273  // lock most violating angle
274  if (minseg) {
275  minseg->Lock(mindof, m_jacobian, mindelta);
276  locked = true;
277 
278  if (minabsdelta > norm)
279  norm = minabsdelta;
280  }
281 
282  if (locked == false)
283  // no locking done, last inner iteration, apply the angles
284  for (seg = m_segments.begin(); seg != m_segments.end(); seg++) {
285  (*seg)->UnLock();
286  (*seg)->UpdateAngleApply();
287  }
288 
289  // signal if another inner iteration is needed
290  return locked;
291 }
292 
294  std::list<IK_QTask *> tasks,
295  const double,
296  const int max_iterations)
297 {
298  float scale = ComputeScale();
299  bool solved = false;
300  // double dt = analyze_time();
301 
302  Scale(scale, tasks);
303 
304  ConstrainPoleVector(root, tasks);
305 
306  root->UpdateTransform(m_rootmatrix);
307 
308  // iterate
309  for (int iterations = 0; iterations < max_iterations; iterations++) {
310  // update transform
311  root->UpdateTransform(m_rootmatrix);
312 
313  std::list<IK_QTask *>::iterator task;
314 
315  // compute jacobian
316  for (task = tasks.begin(); task != tasks.end(); task++) {
317  if ((*task)->Primary())
318  (*task)->ComputeJacobian(m_jacobian);
319  else
320  (*task)->ComputeJacobian(m_jacobian_sub);
321  }
322 
323  double norm = 0.0;
324 
325  do {
326  // invert jacobian
327  try {
328  m_jacobian.Invert();
329  if (m_secondary_enabled)
330  m_jacobian.SubTask(m_jacobian_sub);
331  }
332  catch (...) {
333  fprintf(stderr, "IK Exception\n");
334  return false;
335  }
336 
337  // update angles and check limits
338  } while (UpdateAngles(norm));
339 
340  // unlock segments again after locking in clamping loop
341  std::vector<IK_QSegment *>::iterator seg;
342  for (seg = m_segments.begin(); seg != m_segments.end(); seg++)
343  (*seg)->UnLock();
344 
345  // compute angle update norm
346  double maxnorm = m_jacobian.AngleUpdateNorm();
347  if (maxnorm > norm)
348  norm = maxnorm;
349 
350  // check for convergence
351  if (norm < 1e-3 && iterations > 10) {
352  solved = true;
353  break;
354  }
355  }
356 
357  if (m_poleconstraint)
358  root->PrependBasis(m_rootmatrix.linear());
359 
360  Scale(1.0f / scale, tasks);
361 
362  // analyze_add_run(max_iterations, analyze_time()-dt);
363 
364  return solved;
365 }
static const double IK_EPSILON
Definition: IK_Math.h:34
static bool FuzzyZero(double x)
Definition: IK_Math.h:36
SIMD_FORCE_INLINE btScalar length(const btQuaternion &q)
Return the length of a quaternion.
Definition: btQuaternion.h:895
SIMD_FORCE_INLINE btScalar norm() const
Return the norm (length) of the vector.
Definition: btVector3.h:263
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
void SetPoleVectorConstraint(IK_QSegment *tip, Vector3d &goal, Vector3d &polegoal, float poleangle, bool getangle)
bool Solve(IK_QSegment *root, std::list< IK_QTask * > tasks, const double tolerance, const int max_iterations)
bool Setup(IK_QSegment *root, std::list< IK_QTask * > &tasks)
void SetDoFWeight(int dof, double weight)
void SubTask(IK_QJacobian &jacobian)
double AngleUpdateNorm() const
void ArmMatrices(int dof, int task_size)
int NumberOfDoF() const
Definition: IK_QSegment.h:94
const Vector3d GlobalStart() const
Definition: IK_QSegment.h:121
const Affine3d & GlobalTransform() const
Definition: IK_QSegment.h:132
const Vector3d GlobalEnd() const
Definition: IK_QSegment.h:126
virtual void Lock(int, IK_QJacobian &, Vector3d &)
Definition: IK_QSegment.h:174
virtual bool UpdateAngle(const IK_QJacobian &, Vector3d &, bool *)=0
IK_QSegment * Child() const
Definition: IK_QSegment.h:70
IK_QSegment * Sibling() const
Definition: IK_QSegment.h:75
bool Locked(int dof) const
Definition: IK_QSegment.h:144
void UpdateTransform(const Affine3d &global)
void PrependBasis(const Matrix3d &mat)
void SetDoFId(int dof_id)
Definition: IK_QSegment.h:105
void SetId(int id)
Definition: IK_QTask.h:43
void SetWeight(double weight)
Definition: IK_QTask.h:68
double Weight() const
Definition: IK_QTask.h:63
bool Primary() const
Definition: IK_QTask.h:53
int Size() const
Definition: IK_QTask.h:48
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:319
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:311
struct blender::compositor::@172::@174 task
ccl_device_inline int clamp(int a, int mn, int mx)
Definition: util_math.h:283
ccl_device_inline float2 normalize(const float2 &a)
ccl_device_inline float2 fabs(const float2 &a)