transform3D.cpp

Go to the documentation of this file.
00001 
00015 #include <dlrNumeric/transform3D.h>
00016 
00017 namespace dlr {
00018 
00019   namespace numeric {
00020     
00021     // Build a Transform3D from a homogeneous 4x4 matrix.
00022     Transform3D::
00023     Transform3D(const Array2D<double>& source)
00024     {
00025       if((source.rows() != 4) || (source.columns() != 4)) {
00026         std::ostringstream message;
00027         message << "Can't create a Transform3D from a " << source.rows()
00028                 << " x " << source.columns() << "Array2D<double> instance.";
00029         DLR_THROW(ValueException, "Transform3D::Transform3D()",
00030                   message.str().c_str());
00031       }
00032       m_00 = source(0); m_01 = source(1); m_02 = source(2); m_03 = source(3);
00033       m_10 = source(4); m_11 = source(5); m_12 = source(6); m_13 = source(7);
00034       m_20 = source(8); m_21 = source(9); m_22 = source(10); m_23 = source(11);
00035       m_30 = source(12); m_31 = source(13); m_32 = source(14);
00036       this->normalize(source(15));
00037     }
00038 
00039 
00040     // This member function returns a functor which makes it easier to
00041     // transform arrays of points using algorithms such as
00042     // std::transform().
00043     Transform3DFunctor
00044     Transform3D::
00045     getFunctor() const {
00046       return Transform3DFunctor(*this);
00047     }    
00048     
00049   
00050     // This member function returns the inverse of *this.
00051     Transform3D
00052     Transform3D::
00053     invert() const
00054     {
00055       // We use the cofactor method for now, since it's easier to code
00056       // than Gauss-Jordan elimination.  We suspect that it's less
00057       // efficient, however.
00058     
00059       // Notation for determinant values is detRRRCCC, where the
00060       // Rs indicate the involved rows, from top to bottom, and the Cs
00061       // indicate the involved columns, from left to right.
00062 
00063       double det1201 = m_10 * m_21 - m_11 * m_20;
00064       double det1202 = m_10 * m_22 - m_12 * m_20;
00065       double det1203 = m_10 * m_23 - m_13 * m_20;
00066       double det1212 = m_11 * m_22 - m_12 * m_21;
00067       double det1213 = m_11 * m_23 - m_13 * m_21;
00068       double det1223 = m_12 * m_23 - m_13 * m_22;
00069 
00070       double det1301 = m_10 * m_31 - m_11 * m_30;
00071       double det1302 = m_10 * m_32 - m_12 * m_30;
00072       double det1303 = m_10 - m_13 * m_30;
00073       double det1312 = m_11 * m_32 - m_12 * m_31;
00074       double det1313 = m_11 - m_13 * m_31;
00075       double det1323 = m_12 - m_13 * m_32;
00076 
00077       double det2301 = m_20 * m_31 - m_21 * m_30;
00078       double det2302 = m_20 * m_32 - m_22 * m_30;
00079       double det2303 = m_20 - m_23 * m_30;
00080       double det2312 = m_21 * m_32 - m_22 * m_31;
00081       double det2313 = m_21 - m_23 * m_31;
00082       double det2323 = m_22 - m_23 * m_32;
00083     
00084       double det012012 = (m_00 * det1212 - m_01 * det1202 + m_02 * det1201);
00085       double det012013 = (m_00 * det1213 - m_01 * det1203 + m_03 * det1201);
00086       double det012023 = (m_00 * det1223 - m_02 * det1203 + m_03 * det1202);
00087       double det012123 = (m_01 * det1223 - m_02 * det1213 + m_03 * det1212);
00088 
00089       double det013012 = (m_00 * det1312 - m_01 * det1302 + m_02 * det1301);
00090       double det013013 = (m_00 * det1313 - m_01 * det1303 + m_03 * det1301);
00091       double det013023 = (m_00 * det1323 - m_02 * det1303 + m_03 * det1302);
00092       double det013123 = (m_01 * det1323 - m_02 * det1313 + m_03 * det1312);
00093 
00094       double det023012 = (m_00 * det2312 - m_01 * det2302 + m_02 * det2301);
00095       double det023013 = (m_00 * det2313 - m_01 * det2303 + m_03 * det2301);
00096       double det023023 = (m_00 * det2323 - m_02 * det2303 + m_03 * det2302);
00097       double det023123 = (m_01 * det2323 - m_02 * det2313 + m_03 * det2312);
00098     
00099       double det123012 = (m_10 * det2312 - m_11 * det2302 + m_12 * det2301);
00100       double det123013 = (m_10 * det2313 - m_11 * det2303 + m_13 * det2301);
00101       double det123023 = (m_10 * det2323 - m_12 * det2303 + m_13 * det2302);
00102       double det123123 = (m_11 * det2323 - m_12 * det2313 + m_13 * det2312);
00103 
00104       double det01230123 = (
00105         m_00 * det123123 - m_01 * det123023
00106         + m_02 * det123013 - m_03 * det123012
00107         - m_10 * det023123 + m_11 * det023023
00108         - m_12 * det023013 + m_13 * det023012
00109         + m_20 * det013123 - m_21 * det013023
00110         + m_22 * det013013 - m_23 * det013012
00111         - m_30 * det012123 + m_31 * det012023
00112         - m_32 * det012013 + det012012);
00113 
00114       // Note that in general, roundoff error will make us pass these
00115       // tests, even for singular matrices.
00116       if(det01230123 == 0.0) {
00117         DLR_THROW(ValueException, "Transform3D::invert()",
00118                   "Transform is not invertible.");
00119       }
00120       if(det012012 == 0.0) {
00121         DLR_THROW(LogicException, "Transform3D::invert()",
00122                   "Illegal value for projective scale.");
00123       }
00124     
00125       return Transform3D(
00126         det123123 / det01230123, -det023123 / det01230123,
00127         det013123 / det01230123, -det012123 / det01230123,
00128         -det123023 / det01230123, det023023 / det01230123,
00129         -det013023 / det01230123, det012023 / det01230123,
00130         det123013 / det01230123, -det023013 / det01230123,
00131         det013013 / det01230123, -det012013 / det01230123,
00132         -det123012 / det01230123, det023012 / det01230123,
00133         -det013012 / det01230123, det012012 / det01230123);
00134     }
00135 
00136   
00137     // Change the Transform3D value by explicitly setting element values
00138     // as if setting the elements of a 4x4 transformation matrix:
00139     //    [[a00, a01, a02, a03],
00140     //     [a10, a11, a12, a13],
00141     //     [a20, a21, a22, a23],
00142     //     [a30, a31, a32, a33]]
00143     void
00144     Transform3D::
00145     setTransform(double a00, double a01, double a02, double a03,
00146                  double a10, double a11, double a12, double a13,
00147                  double a20, double a21, double a22, double a23,
00148                  double a30, double a31, double a32, double a33)
00149     {
00150       m_00 = a00; m_01 = a01; m_02 = a02; m_03 = a03;
00151       m_10 = a10; m_11 = a11; m_12 = a12; m_13 = a13;
00152       m_20 = a20; m_21 = a21; m_22 = a22; m_23 = a23;
00153       m_30 = a30; m_31 = a31; m_32 = a32;
00154       this->normalize(a33);
00155     }
00156 
00157 
00158     // This member function sets one element from the matrix
00159     // representation of the coordinate transform to the specified
00160     // value.
00161     void
00162     Transform3D::
00163     setValue(size_t row, size_t column, double value)
00164     {
00165       switch(row) {
00166       case 0:
00167         switch(column) {
00168         case 0: m_00 = value; return; break;
00169         case 1: m_01 = value; return; break;
00170         case 2: m_02 = value; return; break;
00171         case 3: m_03 = value; return; break;
00172         default: break;
00173         }
00174         break;
00175       case 1:
00176         switch(column) {
00177         case 0: m_10 = value; return; break;
00178         case 1: m_11 = value; return; break;
00179         case 2: m_12 = value; return; break;
00180         case 3: m_13 = value; return; break;
00181         default: break;
00182         }
00183         break;
00184       case 2:
00185         switch(column) {
00186         case 0: m_20 = value; return; break;
00187         case 1: m_21 = value; return; break;
00188         case 2: m_22 = value; return; break;
00189         case 3: m_23 = value; return; break;
00190         default: break;
00191         }
00192         break;
00193       case 3:
00194         switch(column) {
00195         case 0: m_30 = value; return; break;
00196         case 1: m_31 = value; return; break;
00197         case 2: m_32 = value; return; break;
00198         default: break;
00199         }
00200         break;
00201       default:
00202         break;
00203       }
00204       std::ostringstream message;
00205       message << "Indices (" << row << ", " << column << ") are out of bounds.";
00206       DLR_THROW(IndexException, "Transform3D::operator()(size_t, size_t)",
00207                 message.str().c_str());
00208     }
00209 
00210       
00211     // This operator returns one element from the matrix
00212     // representation of the coordinate transform by value.
00213     double
00214     Transform3D::
00215     operator()(size_t row, size_t column) const
00216     {
00217       // // Avoid ugly duplication of code using ugly const_cast.
00218       // return const_cast<Transform3D*>(this)->operator()(row, column);
00219       switch(row) {
00220       case 0:
00221         switch(column) {
00222         case 0: return m_00; break;
00223         case 1: return m_01; break;
00224         case 2: return m_02; break;
00225         case 3: return m_03; break;
00226         default: break;
00227         }
00228         break;
00229       case 1:
00230         switch(column) {
00231         case 0: return m_10; break;
00232         case 1: return m_11; break;
00233         case 2: return m_12; break;
00234         case 3: return m_13; break;
00235         default: break;
00236         }
00237         break;
00238       case 2:
00239         switch(column) {
00240         case 0: return m_20; break;
00241         case 1: return m_21; break;
00242         case 2: return m_22; break;
00243         case 3: return m_23; break;
00244         default: break;
00245         }
00246         break;
00247       case 3:
00248         switch(column) {
00249         case 0: return m_30; break;
00250         case 1: return m_31; break;
00251         case 2: return m_32; break;
00252         case 3: return 1.0; break;
00253         default: break;
00254         }
00255         break;
00256       default:
00257         break;
00258       }
00259       std::ostringstream message;
00260       message << "Indices (" << row << ", " << column << ") are out of bounds.";
00261       DLR_THROW(IndexException, "Transform3D::operator()(size_t, size_t)",
00262                 message.str().c_str());
00263       return 0.0; // Dummy return to keep the compiler happy.
00264     }
00265   
00266   
00267     // This operator takes a point and applies the coordinate
00268     // transform, returning the result.
00269     Vector3D
00270     Transform3D::
00271     operator*(const Vector3D& vector0) const
00272     {
00273       return Vector3D(
00274         m_00 * vector0.x() + m_01 * vector0.y() + m_02 * vector0.z() + m_03,
00275         m_10 * vector0.x() + m_11 * vector0.y() + m_12 * vector0.z() + m_13,
00276         m_20 * vector0.x() + m_21 * vector0.y() + m_22 * vector0.z() + m_23,
00277         m_30 * vector0.x() + m_31 * vector0.y() + m_32 * vector0.z() + 1.0);
00278     }
00279 
00280   
00281     // The assignment operator simply duplicates its argument.
00282     Transform3D&
00283     Transform3D::
00284     operator=(const Transform3D& source)
00285     {
00286       m_00 = source.m_00; m_01 = source.m_01;
00287       m_02 = source.m_02; m_03 = source.m_03;
00288       m_10 = source.m_10; m_11 = source.m_11;
00289       m_12 = source.m_12; m_13 = source.m_13;
00290       m_20 = source.m_20; m_21 = source.m_21;
00291       m_22 = source.m_22; m_23 = source.m_23;
00292       m_30 = source.m_30; m_31 = source.m_31;
00293       m_32 = source.m_32;
00294       return *this;
00295     }
00296 
00297   
00298     void
00299     Transform3D::
00300     normalize(double scaleFactor)
00301     {
00302       if(scaleFactor == 0.0) {
00303         DLR_THROW(ValueException, "Transform3D::normalize()",
00304                   "Invalid normalization constant. "
00305                   "The bottom right element of a homogeneous transformation "
00306                   "cannot be equal to 0.0.");
00307       }
00308       if(scaleFactor != 1.0) {
00309         m_00 /= scaleFactor;
00310         m_01 /= scaleFactor;
00311         m_02 /= scaleFactor;
00312         m_03 /= scaleFactor;
00313         m_10 /= scaleFactor;
00314         m_11 /= scaleFactor;
00315         m_12 /= scaleFactor;
00316         m_13 /= scaleFactor;
00317         m_20 /= scaleFactor;
00318         m_21 /= scaleFactor;
00319         m_22 /= scaleFactor;
00320         m_23 /= scaleFactor;
00321         m_30 /= scaleFactor;
00322         m_31 /= scaleFactor;
00323         m_32 /= scaleFactor;
00324       }
00325     }
00326 
00327     /* ============== Non-member functions which should ============== */
00328     /* ============== probably live in a different file ============== */
00329   
00330   
00331     // This operator composes two Transform3D instances.  The resulting
00332     // transform satisfies the equation:
00333     //   (transform0 * transform1) * v0 = transform0 * (transform1 * v0),
00334     // where v0 is a Vector3D instance.
00335     Transform3D
00336     operator*(const Transform3D& transform0, const Transform3D& transform1)
00337     {
00338       double a00 = (transform0.value<0, 0>() * transform1.value<0, 0>()
00339                     + transform0.value<0, 1>() * transform1.value<1, 0>()
00340                     + transform0.value<0, 2>() * transform1.value<2, 0>()
00341                     + transform0.value<0, 3>() * transform1.value<3, 0>());
00342       double a01 = (transform0.value<0, 0>() * transform1.value<0, 1>()
00343                     + transform0.value<0, 1>() * transform1.value<1, 1>()
00344                     + transform0.value<0, 2>() * transform1.value<2, 1>()
00345                     + transform0.value<0, 3>() * transform1.value<3, 1>());
00346       double a02 = (transform0.value<0, 0>() * transform1.value<0, 2>()
00347                     + transform0.value<0, 1>() * transform1.value<1, 2>()
00348                     + transform0.value<0, 2>() * transform1.value<2, 2>()
00349                     + transform0.value<0, 3>() * transform1.value<3, 2>());
00350       double a03 = (transform0.value<0, 0>() * transform1.value<0, 3>()
00351                     + transform0.value<0, 1>() * transform1.value<1, 3>()
00352                     + transform0.value<0, 2>() * transform1.value<2, 3>()
00353                     + transform0.value<0, 3>() * transform1.value<3, 3>());
00354       double a10 = (transform0.value<1, 0>() * transform1.value<0, 0>()
00355                     + transform0.value<1, 1>() * transform1.value<1, 0>()
00356                     + transform0.value<1, 2>() * transform1.value<2, 0>()
00357                     + transform0.value<1, 3>() * transform1.value<3, 0>());
00358       double a11 = (transform0.value<1, 0>() * transform1.value<0, 1>()
00359                     + transform0.value<1, 1>() * transform1.value<1, 1>()
00360                     + transform0.value<1, 2>() * transform1.value<2, 1>()
00361                     + transform0.value<1, 3>() * transform1.value<3, 1>());
00362       double a12 = (transform0.value<1, 0>() * transform1.value<0, 2>()
00363                     + transform0.value<1, 1>() * transform1.value<1, 2>()
00364                     + transform0.value<1, 2>() * transform1.value<2, 2>()
00365                     + transform0.value<1, 3>() * transform1.value<3, 2>());
00366       double a13 = (transform0.value<1, 0>() * transform1.value<0, 3>()
00367                     + transform0.value<1, 1>() * transform1.value<1, 3>()
00368                     + transform0.value<1, 2>() * transform1.value<2, 3>()
00369                     + transform0.value<1, 3>() * transform1.value<3, 3>());
00370       double a20 = (transform0.value<2, 0>() * transform1.value<0, 0>()
00371                     + transform0.value<2, 1>() * transform1.value<1, 0>()
00372                     + transform0.value<2, 2>() * transform1.value<2, 0>()
00373                     + transform0.value<2, 3>() * transform1.value<3, 0>());
00374       double a21 = (transform0.value<2, 0>() * transform1.value<0, 1>()
00375                     + transform0.value<2, 1>() * transform1.value<1, 1>()
00376                     + transform0.value<2, 2>() * transform1.value<2, 1>()
00377                     + transform0.value<2, 3>() * transform1.value<3, 1>());
00378       double a22 = (transform0.value<2, 0>() * transform1.value<0, 2>()
00379                     + transform0.value<2, 1>() * transform1.value<1, 2>()
00380                     + transform0.value<2, 2>() * transform1.value<2, 2>()
00381                     + transform0.value<2, 3>() * transform1.value<3, 2>());
00382       double a23 = (transform0.value<2, 0>() * transform1.value<0, 3>()
00383                     + transform0.value<2, 1>() * transform1.value<1, 3>()
00384                     + transform0.value<2, 2>() * transform1.value<2, 3>()
00385                     + transform0.value<2, 3>() * transform1.value<3, 3>());
00386       double a30 = (transform0.value<3, 0>() * transform1.value<0, 0>()
00387                     + transform0.value<3, 1>() * transform1.value<1, 0>()
00388                     + transform0.value<3, 2>() * transform1.value<2, 0>()
00389                     + transform0.value<3, 3>() * transform1.value<3, 0>());
00390       double a31 = (transform0.value<3, 0>() * transform1.value<0, 1>()
00391                     + transform0.value<3, 1>() * transform1.value<1, 1>()
00392                     + transform0.value<3, 2>() * transform1.value<2, 1>()
00393                     + transform0.value<3, 3>() * transform1.value<3, 1>());
00394       double a32 = (transform0.value<3, 0>() * transform1.value<0, 2>()
00395                     + transform0.value<3, 1>() * transform1.value<1, 2>()
00396                     + transform0.value<3, 2>() * transform1.value<2, 2>()
00397                     + transform0.value<3, 3>() * transform1.value<3, 2>());
00398       double a33 = (transform0.value<3, 0>() * transform1.value<0, 3>()
00399                     + transform0.value<3, 1>() * transform1.value<1, 3>()
00400                     + transform0.value<3, 2>() * transform1.value<2, 3>()
00401                     + transform0.value<3, 3>() * transform1.value<3, 3>());
00402       return Transform3D(a00, a01, a02, a03,
00403                          a10, a11, a12, a13,
00404                          a20, a21, a22, a23,
00405                          a30, a31, a32, a33);
00406     }
00407 
00408 
00409     std::ostream&
00410     operator<<(std::ostream& stream, const Transform3D& transform0)
00411     {
00412       stream << "Transform3D("
00413              << transform0.value<0, 0>() << ", "
00414              << transform0.value<0, 1>() << ", "
00415              << transform0.value<0, 2>() << ", "
00416              << transform0.value<0, 3>() << ",\n"
00417              << transform0.value<1, 0>() << ", "
00418              << transform0.value<1, 1>() << ", "
00419              << transform0.value<1, 2>() << ", "
00420              << transform0.value<1, 3>() << ",\n"
00421              << transform0.value<2, 0>() << ", "
00422              << transform0.value<2, 1>() << ", "
00423              << transform0.value<2, 2>() << ", "
00424              << transform0.value<2, 3>() << ",\n"
00425              << transform0.value<3, 0>() << ", "
00426              << transform0.value<3, 1>() << ", "
00427              << transform0.value<3, 2>() << ", "
00428              << transform0.value<3, 3>() << ")";
00429       return stream;
00430     }
00431 
00432     std::istream&
00433     operator>>(std::istream& stream, Transform3D& transform0)
00434     {
00435       // If stream is in a bad state, we can't read from it.
00436       if (!stream){
00437         return stream;
00438       }
00439     
00440       // It's a lot easier to use a try block than to be constantly
00441       // testing whether the IO has succeeded, so we tell stream to
00442       // complain if anything goes wrong.
00443       std::ios_base::iostate oldExceptionState = stream.exceptions();
00444       stream.exceptions(
00445         std::ios_base::badbit | std::ios_base::failbit | std::ios_base::eofbit);
00446 
00447       // Now on with the show.
00448       try{
00449         // Construct an InputStream instance so we can use our
00450         // convenience functions.
00451         InputStream inputStream(stream);
00452 
00453         // Advance to the next relevant character.
00454         inputStream.skipWhiteSpace();
00455       
00456         // Read the "Transform3D(" part.
00457         inputStream.expect("Transform3D(");
00458 
00459         // Read all the data except the last element.
00460         std::vector<double> inputValues(16);
00461         for(size_t index = 0; index < (inputValues.size() - 1); ++index) {
00462           // Read the value.
00463           inputStream >> inputValues[index];
00464 
00465           // Read punctuation before the next value.
00466           inputStream.expect(",");
00467         }
00468 
00469         // Read the final value.
00470         inputStream >> inputValues[inputValues.size() - 1];
00471 
00472         // Read the closing parenthesis.
00473         inputStream.expect(")");
00474 
00475         // And update the transform.
00476         transform0.setTransform(inputValues[0], inputValues[1],
00477                                 inputValues[2], inputValues[3], 
00478                                 inputValues[4], inputValues[5], 
00479                                 inputValues[6], inputValues[7], 
00480                                 inputValues[8], inputValues[9], 
00481                                 inputValues[10], inputValues[11], 
00482                                 inputValues[12], inputValues[13], 
00483                                 inputValues[14], inputValues[15]);
00484       } catch(std::ios_base::failure) {
00485         // Empty
00486       }
00487       stream.exceptions(oldExceptionState);
00488       return stream;
00489     }
00490 
00491   } // namespace numeric
00492 
00493 } // namespace dlr

Generated on Mon Jul 9 20:34:03 2007 for dlrLibs Utility Libraries by  doxygen 1.5.2