opensurgsim
Polynomial-inl.h
1 // This file is a part of the OpenSurgSim project.
2 // Copyright 2013-2016, SimQuest Solutions Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #ifndef SURGSIM_MATH_POLYNOMIAL_INL_H
17 #define SURGSIM_MATH_POLYNOMIAL_INL_H
18 
19 #include <stdlib.h>
20 #include <algorithm>
21 
22 #include "SurgSim/Math/IntervalArithmetic.h"
23 
24 namespace SurgSim
25 {
26 namespace Math
27 {
28 
29 template <typename T>
30 bool isNearZero(const T& value, const T& epsilon)
31 {
32  return (value + epsilon >= 0 && value - epsilon <= 0);
33 }
34 
35 // Polynomial of degree 0
36 
37 template <class T>
38 Polynomial<T, 0>::Polynomial() : m_a0(static_cast<T>(0))
39 {
40 }
41 
42 template <class T>
43 Polynomial<T, 0>::Polynomial(const T& a0) : m_a0(a0)
44 {
45 }
46 
47 template <class T>
48 T Polynomial<T, 0>::evaluate(const T& x) const
49 {
50  return m_a0;
51 }
52 
53 template <class T>
54 T Polynomial<T, 0>::operator()(const T& x) const
55 {
56  return evaluate(x);
57 }
58 
59 template <class T>
60 T& Polynomial<T, 0>::operator[](const size_t i)
61 {
62  return const_cast<T&>(const_cast<const Polynomial<T, 0>*>(this)->operator[](i));
63 }
64 
65 template <class T>
66 const T& Polynomial<T, 0>::operator[](const size_t i) const
67 {
68  SURGSIM_ASSERT(i <= 0) << "Attempting to set a coefficient greater than the polynomial degree";
69  return m_a0;
70 }
71 
72 template <class T>
74 {
75  return Polynomial(-m_a0);
76 }
77 
78 template <class T>
80 {
81  return Polynomial(m_a0 + rhs.m_a0);
82 }
83 
84 template <class T>
86 {
87  m_a0 += rhs.m_a0;
88  return *this;
89 }
90 
91 template <class T>
93 {
94  return Polynomial(m_a0 - rhs.m_a0);
95 }
96 
97 template <class T>
99 {
100  m_a0 -= rhs.m_a0;
101  return *this;
102 }
103 
104 template <class T>
105 bool Polynomial<T, 0>::isNearZero(const T& epsilon) const
106 {
107  return SurgSim::Math::isNearZero(m_a0, epsilon);
108 }
109 
110 template <class T>
111 bool Polynomial<T, 0>::isApprox(const Polynomial<T, 0>& p, const T& epsilon) const
112 {
113  return ((*this) - p).isNearZero(epsilon);
114 }
115 
116 template <class T>
118 {
119  switch (i)
120  {
121  case 0:
122  return m_a0;
123  default:
124  return 0;
125  }
126 }
127 
128 template <class T>
129 void Polynomial<T, 0>::setCoefficient(size_t i, const T& value)
130 {
131  SURGSIM_ASSERT(i <= 0) << "Attempting to set a coefficient greater than the polynomial degree";
132  m_a0 = value;
133 }
134 
135 // Polynomial of degree 1
136 
137 template <class T>
138 Polynomial<T, 1>::Polynomial() : m_a0(static_cast<T>(0)), m_a1(static_cast<T>(0))
139 {
140 }
141 
142 template <class T>
143 Polynomial<T, 1>::Polynomial(const T& a0, const T& a1) : m_a0(a0), m_a1(a1)
144 {
145 }
146 
147 template <class T>
148 T Polynomial<T, 1>::evaluate(const T& x) const
149 {
150  return m_a1 * x + m_a0;
151 }
152 
153 template <class T>
154 T Polynomial<T, 1>::operator()(const T& x) const
155 {
156  return evaluate(x);
157 }
158 
159 template <class T>
161 {
162  return const_cast<T&>(const_cast<const Polynomial<T, 1>*>(this)->operator[](i));
163 }
164 
165 template <class T>
166 const T& Polynomial<T, 1>::operator[](const size_t i) const
167 {
168  SURGSIM_ASSERT(i <= 1) << "Attempting to set a coefficient greater than the polynomial degree";
169  switch (i)
170  {
171  case 0:
172  {
173  return m_a0;
174  }
175  default:
176  {
177  return m_a1;
178  }
179  }
180 }
181 
182 template <class T>
184 {
185  return Polynomial(-m_a0, -m_a1);
186 }
187 
188 template <class T>
190 {
191  return Polynomial(m_a0 + rhs.m_a0, m_a1 + rhs.m_a1);
192 }
193 
194 template <class T>
196 {
197  m_a0 += rhs.m_a0;
198  m_a1 += rhs.m_a1;
199  return *this;
200 }
201 
202 template <class T>
204 {
205  return Polynomial(m_a0 - rhs.m_a0, m_a1 - rhs.m_a1);
206 }
207 
208 template <class T>
210 {
211  m_a0 -= rhs.m_a0;
212  m_a1 -= rhs.m_a1;
213  return *this;
214 }
215 
216 template <class T>
218 {
219  return Polynomial<T, 0>(m_a1);
220 }
221 
222 template <class T>
223 bool Polynomial<T, 1>::isNearZero(const T& epsilon) const
224 {
225  return SurgSim::Math::isNearZero(m_a0, epsilon) && SurgSim::Math::isNearZero(m_a1, epsilon);
226 }
227 
228 template <class T>
229 bool Polynomial<T, 1>::isApprox(const Polynomial<T, 1>& p, const T& epsilon) const
230 {
231  return ((*this) - p).isNearZero(epsilon);
232 }
233 
234 template <class T>
236 {
237  switch (i)
238  {
239  case 0:
240  {
241  return m_a0;
242  }
243  case 1:
244  {
245  return m_a1;
246  }
247  default:
248  {
249  return 0;
250  }
251  }
252 }
253 
254 template <class T>
255 void Polynomial<T, 1>::setCoefficient(size_t i, const T& value)
256 {
257  SURGSIM_ASSERT(i <= 1) << "Attempting to set a coefficient greater than the polynomial degree";
258  switch (i)
259  {
260  case 0:
261  {
262  m_a0 = value;
263  break;
264  }
265  case 1:
266  {
267  m_a1 = value;
268  break;
269  }
270  }
271 }
272 
273 // Polynomial of degree 2
274 
275 template <class T>
276 Polynomial<T, 2>::Polynomial() : m_a0(static_cast<T>(0)), m_a1(static_cast<T>(0)), m_a2(static_cast<T>(0))
277 {
278 }
279 
280 template <class T>
281 Polynomial<T, 2>::Polynomial(const T& a0, const T& a1, const T& a2) : m_a0(a0), m_a1(a1), m_a2(a2)
282 {
283 }
284 
285 template <class T>
287 {
288  return m_a1 * m_a1 - static_cast<T>(4) * m_a0 * m_a2;
289 }
290 
291 template <class T>
292 T Polynomial<T, 2>::evaluate(const T& x) const
293 {
294  return (m_a2 * x + m_a1) * x + m_a0;
295 }
296 
297 template <class T>
298 T Polynomial<T, 2>::operator()(const T& x) const
299 {
300  return evaluate(x);
301 }
302 
303 template <class T>
305 {
306  return const_cast<T&>(const_cast<const Polynomial<T, 2>*>(this)->operator[](i));
307 }
308 
309 template <class T>
310 const T& Polynomial<T, 2>::operator[](const size_t i) const
311 {
312  SURGSIM_ASSERT(i <= 2) << "Attempting to set a coefficient greater than the polynomial degree";
313  switch (i)
314  {
315  case 0:
316  {
317  return m_a0;
318  }
319  case 1:
320  {
321  return m_a1;
322  }
323  default:
324  {
325  return m_a2;
326  }
327  }
328 }
329 
330 template <class T>
332 {
333  return Polynomial(-m_a0, -m_a1, -m_a2);
334 }
335 
336 template <class T>
338 {
339  return Polynomial(m_a0 + rhs.m_a0, m_a1 + rhs.m_a1, m_a2 + rhs.m_a2);
340 }
341 
342 template <class T>
344 {
345  m_a0 += rhs.m_a0;
346  m_a1 += rhs.m_a1;
347  m_a2 += rhs.m_a2;
348  return *this;
349 }
350 
351 template <class T>
353 {
354  return Polynomial(m_a0 - rhs.m_a0, m_a1 - rhs.m_a1, m_a2 - rhs.m_a2);
355 }
356 
357 template <class T>
359 {
360  m_a0 -= rhs.m_a0;
361  m_a1 -= rhs.m_a1;
362  m_a2 -= rhs.m_a2;
363  return *this;
364 }
365 
366 template <class T>
368 {
369  return Polynomial<T, 1>(m_a1, 2 * m_a2);
370 }
371 
372 template <class T>
373 bool Polynomial<T, 2>::isNearZero(const T& epsilon) const
374 {
375  return SurgSim::Math::isNearZero(m_a0, epsilon) &&
376  SurgSim::Math::isNearZero(m_a1, epsilon) &&
377  SurgSim::Math::isNearZero(m_a2, epsilon);
378 }
379 
380 template <class T>
381 bool Polynomial<T, 2>::isApprox(const Polynomial<T, 2>& p, const T& epsilon) const
382 {
383  return ((*this) - p).isNearZero(epsilon);
384 }
385 
386 template <class T>
388 {
389  switch (i)
390  {
391  case 0:
392  {
393  return m_a0;
394  }
395  case 1:
396  {
397  return m_a1;
398  }
399  case 2:
400  {
401  return m_a2;
402  }
403  default:
404  {
405  return 0;
406  }
407  }
408 }
409 
410 template <class T>
411 void Polynomial<T, 2>::setCoefficient(size_t i, const T& value)
412 {
413  SURGSIM_ASSERT(i <= 2) << "Attempting to set a coefficient greater than the polynomial degree";
414  switch (i)
415  {
416  case 0:
417  {
418  m_a0 = value;
419  break;
420  }
421  case 1:
422  {
423  m_a1 = value;
424  break;
425  }
426  case 2:
427  {
428  m_a2 = value;
429  break;
430  }
431  }
432 }
433 
434 // Polynomial of degree 3
435 
436 template <class T>
438  m_a0(static_cast<T>(0)),
439  m_a1(static_cast<T>(0)),
440  m_a2(static_cast<T>(0)),
441  m_a3(static_cast<T>(0))
442 {
443 }
444 
445 template <class T>
446 Polynomial<T, 3>::Polynomial(const T& a0, const T& a1, const T& a2, const T& a3) :
447  m_a0(a0),
448  m_a1(a1),
449  m_a2(a2),
450  m_a3(a3)
451 {
452 }
453 
454 template <class T>
455 T Polynomial<T, 3>::evaluate(const T& x) const
456 {
457  return ((m_a3 * x + m_a2) * x + m_a1) * x + m_a0;
458 }
459 
460 template <class T>
461 T Polynomial<T, 3>::operator()(const T& x) const
462 {
463  return evaluate(x);
464 }
465 
466 template <class T>
468 {
469  return const_cast<T&>(const_cast<const Polynomial<T, 3>*>(this)->operator[](i));
470 }
471 
472 template <class T>
473 const T& Polynomial<T, 3>::operator[](const size_t i) const
474 {
475  SURGSIM_ASSERT(i <= 3) << "Attempting to set or access a coefficient greater than the polynomial degree";
476  switch (i)
477  {
478  case 0:
479  {
480  return m_a0;
481  }
482  case 1:
483  {
484  return m_a1;
485  }
486  case 2:
487  {
488  return m_a2;
489  }
490  default:
491  {
492  return m_a3;
493  }
494  }
495 }
496 
497 template <class T>
499 {
500  return Polynomial(-m_a0, -m_a1, -m_a2, -m_a3);
501 }
502 
503 template <class T>
505 {
506  return Polynomial(m_a0 + rhs.m_a0, m_a1 + rhs.m_a1, m_a2 + rhs.m_a2, m_a3 + rhs.m_a3);
507 }
508 
509 template <class T>
511 {
512  m_a0 += rhs.m_a0;
513  m_a1 += rhs.m_a1;
514  m_a2 += rhs.m_a2;
515  m_a3 += rhs.m_a3;
516  return *this;
517 }
518 
519 template <class T>
521 {
522  return Polynomial(m_a0 - rhs.m_a0, m_a1 - rhs.m_a1, m_a2 - rhs.m_a2, m_a3 - rhs.m_a3);
523 }
524 
525 template <class T>
527 {
528  m_a0 -= rhs.m_a0;
529  m_a1 -= rhs.m_a1;
530  m_a2 -= rhs.m_a2;
531  m_a3 -= rhs.m_a3;
532  return *this;
533 }
534 
535 template <class T>
537 {
538  return Polynomial<T, 2>(m_a1, 2 * m_a2, 3 * m_a3);
539 }
540 
541 template <class T>
542 bool Polynomial<T, 3>::isNearZero(const T& epsilon) const
543 {
544  return SurgSim::Math::isNearZero(m_a0, epsilon) &&
545  SurgSim::Math::isNearZero(m_a1, epsilon) &&
546  SurgSim::Math::isNearZero(m_a2, epsilon) &&
547  SurgSim::Math::isNearZero(m_a3, epsilon);
548 }
549 
550 template <class T>
551 bool Polynomial<T, 3>::isApprox(const Polynomial<T, 3>& p, const T& epsilon) const
552 {
553  return ((*this) - p).isNearZero(epsilon);
554 }
555 
556 template <class T>
558 {
559  switch (i)
560  {
561  case 0:
562  {
563  return m_a0;
564  }
565  case 1:
566  {
567  return m_a1;
568  }
569  case 2:
570  {
571  return m_a2;
572  }
573  case 3:
574  {
575  return m_a3;
576  }
577  default:
578  {
579  return 0;
580  }
581  }
582 }
583 
584 template <class T>
585 void Polynomial<T, 3>::setCoefficient(size_t i, const T& value)
586 {
587  SURGSIM_ASSERT(i <= 3) << "Attempting to set a coefficient greater than the polynomial degree";
588  switch (i)
589  {
590  case 0:
591  {
592  m_a0 = value;
593  break;
594  }
595  case 1:
596  {
597  m_a1 = value;
598  break;
599  }
600  case 2:
601  {
602  m_a2 = value;
603  break;
604  }
605  case 3:
606  {
607  m_a3 = value;
608  break;
609  }
610  }
611 }
612 
613 // Operators
614 
615 template <typename T, int N, int M>
616 Polynomial < T, N + M > operator*(const Polynomial<T, N>& p, const Polynomial<T, M>& q)
617 {
619  for (int i = 0; i <= N + M; ++i)
620  {
621  T coeff = 0;
622  int jMin = std::max(0, i - M);
623  int jMax = std::min(i, N);
624  for (int j = jMin; j <= jMax; ++j)
625  {
626  coeff += p.getCoefficient(j) * q.getCoefficient(i - j);
627  }
628  result.setCoefficient(i, coeff);
629  }
630  return result;
631 }
632 
633 template <typename T>
634 Polynomial<T, 2> operator*(const Polynomial<T, 1>& p, const Polynomial<T, 1>& q)
635 {
636  const T p0 = p.getCoefficient(0);
637  const T p1 = p.getCoefficient(1);
638  const T q0 = q.getCoefficient(0);
639  const T q1 = q.getCoefficient(1);
640  return Polynomial<T, 2>(p0 * q0, p0 * q1 + p1 * q0, p1 * q1);
641 }
642 
643 template <typename T>
644 Polynomial<T, 3> operator*(const Polynomial<T, 2>& p, const Polynomial<T, 1>& q)
645 {
646  const T p0 = p.getCoefficient(0);
647  const T p1 = p.getCoefficient(1);
648  const T p2 = p.getCoefficient(2);
649  const T q0 = q.getCoefficient(0);
650  const T q1 = q.getCoefficient(1);
651  return Polynomial<T, 3>(p0 * q0, p0 * q1 + p1 * q0, p1 * q1 + p2 * q0, p2 * q1);
652 }
653 
654 template <typename T>
655 Polynomial<T, 3> operator*(const Polynomial<T, 1>& p, const Polynomial<T, 2>& q)
656 {
657  const T p0 = p.getCoefficient(0);
658  const T p1 = p.getCoefficient(1);
659  const T q0 = q.getCoefficient(0);
660  const T q1 = q.getCoefficient(1);
661  const T q2 = q.getCoefficient(2);
662  return Polynomial<T, 3>(p0 * q0, p0 * q1 + p1 * q0, p0 * q2 + p1 * q1, p1 * q2);
663 }
664 
665 template <typename T>
666 Polynomial<T, 0> square(const Polynomial<T, 0>& p)
667 {
668  const T c = p.getCoefficient(0);
669  return Polynomial<T, 0>(c * c);
670 }
671 
672 template <typename T>
673 Polynomial<T, 2> square(const Polynomial<T, 1>& p)
674 {
675  const T p0 = p.getCoefficient(0);
676  const T p1 = p.getCoefficient(1);
677  return Polynomial<T, 2>(p0 * p0, 2 * p1 * p0, p1 * p1);
678 }
679 
680 template <typename T, int N>
681 inline std::ostream& operator<<(std::ostream& stream, const Polynomial<T, N>& p)
682 {
683  stream << "(";
684  for (int i = N; i > 1; --i)
685  {
686  stream << p.getCoefficient(i) << "*x^" << i << " + ";
687  }
688  if (N >= 1)
689  {
690  stream << p.getCoefficient(1) << "*x + ";
691  }
692  stream << p.getCoefficient(0) << ")";
693  return stream;
694 }
695 
696 }; // Math
697 }; // SurgSim
698 
699 #endif // SURGSIM_MATH_POLYNOMIAL_INL_H
Wraps glewInit() to separate the glew opengl definitions from the osg opengl definitions only imgui n...
Definition: AddRandomSphereBehavior.cpp:36
Polynomial<T, 0> specializes the Polynomial class for degree 0 (constant polynomials) ...
Definition: Polynomial.h:56
T getCoefficient(size_t i) const
Definition: Polynomial-inl.h:387
Polynomial<T, N> defines the concept of an N degree polynomial with type T coefficients and provides ...
Definition: Polynomial.h:47
#define SURGSIM_ASSERT(condition)
Assert that condition is true.
Definition: Assert.h:77
Polynomial<T, 3> specializes the Polynomial class for degree 3 (cubic polynomials) ...
Definition: Polynomial.h:255
T getCoefficient(size_t i) const
Definition: Polynomial-inl.h:235
Polynomial<T, 2> specializes the Polynomial class for degree 2 (quadratic polynomials) ...
Definition: Polynomial.h:183
T getCoefficient(size_t i) const
Definition: Polynomial-inl.h:117
Polynomial<T, 1> specializes the Polynomial class for degree 1 (linear polynomials) ...
Definition: Polynomial.h:117