transform2D.cpp

Go to the documentation of this file.
00001 
00015 #include <dlrNumeric/transform2D.h>
00016 
00017 namespace dlr {
00018 
00019   namespace numeric {
00020     
00021     // Build a Transform2D from a homogeneous 3x3 matrix.
00022     Transform2D::
00023     Transform2D(const Array2D<double>& source)
00024     {
00025       if((source.rows() != 3) || (source.columns() != 3)) {
00026         std::ostringstream message;
00027         message << "Can't create a Transform2D from a " << source.rows()
00028                 << " x " << source.columns() << "Array2D<double> instance.";
00029         DLR_THROW(ValueException, "Transform2D::Transform2D()",
00030                   message.str().c_str());
00031       }
00032       m_00 = source(0); m_01 = source(1); m_02 = source(2);
00033       m_10 = source(3); m_11 = source(4); m_12 = source(5);
00034       m_20 = source(6); m_21 = source(7);
00035       this->normalize(source(8));
00036     }
00037 
00038 
00039     // This member function returns a functor which makes it easier to
00040     // transform arrays of points using algorithms such as
00041     // std::transform().
00042     Transform2DFunctor
00043     Transform2D::
00044     getFunctor() const {
00045       return Transform2DFunctor(*this);
00046     }    
00047   
00048   
00049     // This member function returns the inverse of *this.
00050     Transform2D
00051     Transform2D::
00052     invert() const
00053     {
00054       // We use the cofactor method for now, since it's easier to code
00055       // than Gauss-Jordan elimination.  We suspect that it's less
00056       // efficient, however.
00057     
00058       // Notation for determinant values is detRRCC, where the
00059       // Rs indicate the involved rows, from top to bottom, and the Cs
00060       // indicate the involved columns, from left to right.
00061 
00062       double det0101 = m_00 * m_11 - m_01 * m_10;
00063       double det0102 = m_00 * m_12 - m_02 * m_10;
00064       double det0112 = m_01 * m_12 - m_02 * m_11;
00065 
00066       double det0201 = m_00 * m_21 - m_01 * m_20;
00067       double det0202 = m_00 - m_02 * m_20;
00068       double det0212 = m_01 - m_02 * m_21;
00069 
00070       double det1201 = m_10 * m_21 - m_11 * m_20;
00071       double det1202 = m_10 - m_12 * m_20;
00072       double det1212 = m_11 - m_12 * m_21;
00073 
00074       double det012012 = (
00075         m_00 * det1212 - m_01 * det1202 + m_02 * det1201
00076         - m_10 * det0212 + m_11 * det0202 - m_12 * det0201
00077         + m_20 * det0112 - m_21 * det0102 + det0101);
00078     
00079       // Note that in general, roundoff error will make us pass these
00080       // tests, even for singular matrices.
00081       if(det012012 == 0.0) {
00082         DLR_THROW(ValueException, "Transform2D::invert()",
00083                   "Transform is not invertible.");
00084       }
00085       if(det0101 == 0.0) {
00086         DLR_THROW(LogicException, "Transform2D::invert()",
00087                   "Illegal value for projective scale.");
00088       }
00089     
00090       return Transform2D(
00091         det1212 / det012012, -det0212 / det012012, det0112 / det012012,
00092         -det1202 / det012012, det0202 / det012012, -det0102 / det012012,
00093         det1201 / det012012, -det0201 / det012012, det0101 / det012012);
00094     }
00095 
00096   
00097     // Change the Transform2D value by explicitly setting element values
00098     // as if setting the elements of a 3x3 transformation matrix:
00099     //    [[a00, a01, a02],
00100     //     [a10, a11, a12],
00101     //     [a20, a21, a22]]
00102     void
00103     Transform2D::
00104     setTransform(double a00, double a01, double a02,
00105                  double a10, double a11, double a12,
00106                  double a20, double a21, double a22)
00107     {
00108       m_00 = a00; m_01 = a01; m_02 = a02;
00109       m_10 = a10; m_11 = a11; m_12 = a12;
00110       m_20 = a20; m_21 = a21;
00111       this->normalize(a22);
00112     }
00113 
00114 
00115     // This member function sets one element from the matrix
00116     // representation of the coordinate transform to the specified
00117     // value.
00118     void
00119     Transform2D::
00120     setValue(size_t row, size_t column, double value)
00121     {
00122       switch(row) {
00123       case 0:
00124         switch(column) {
00125         case 0: m_00 = value; return; break;
00126         case 1: m_01 = value; return; break;
00127         case 2: m_02 = value; return; break;
00128         default: break;
00129         }
00130         break;
00131       case 1:
00132         switch(column) {
00133         case 0: m_10 = value; return; break;
00134         case 1: m_11 = value; return; break;
00135         case 2: m_12 = value; return; break;
00136         default: break;
00137         }
00138         break;
00139       case 2:
00140         switch(column) {
00141         case 0: m_20 = value; return; break;
00142         case 1: m_21 = value; return; break;
00143         default: break;
00144         }
00145         break;
00146       default:
00147         break;
00148       }
00149       std::ostringstream message;
00150       message << "Indices (" << row << ", " << column << ") are out of bounds.";
00151       DLR_THROW(IndexException, "Transform2D::operator()(size_t, size_t)",
00152                 message.str().c_str());
00153     }
00154 
00155   
00156     // This operator returns one element from the matrix
00157     // representation of the coordinate transform by value.
00158     double
00159     Transform2D::
00160     operator()(size_t row, size_t column) const
00161     {
00162       // // Avoid ugly duplication of code using ugly const_cast.
00163       // return const_cast<Transform2D*>(this)->operator()(row, column);
00164       switch(row) {
00165       case 0:
00166         switch(column) {
00167         case 0: return m_00; break;
00168         case 1: return m_01; break;
00169         case 2: return m_02; break;
00170         default: break;
00171         }
00172         break;
00173       case 1:
00174         switch(column) {
00175         case 0: return m_10; break;
00176         case 1: return m_11; break;
00177         case 2: return m_12; break;
00178         default: break;
00179         }
00180         break;
00181       case 2:
00182         switch(column) {
00183         case 0: return this->value<2, 0>(); break;
00184         case 1: return m_21; break;
00185         case 2: return 1.0; break;
00186         default: break;
00187         }
00188         break;
00189       default:
00190         break;
00191       }
00192       std::ostringstream message;
00193       message << "Index (" << row << ", " << column << ") out of bounds.";
00194       DLR_THROW3(IndexException, "Transform2D::value()",
00195                  message.str().c_str());
00196       return 0.0; // Dummy return to keep the compiler happy.
00197     }
00198   
00199     // This operator takes a point and applies the coordinate
00200     // transform, returning the result.
00201     Vector2D
00202     Transform2D::
00203     operator*(const Vector2D& vector0) const
00204     {
00205       return Vector2D(
00206         m_00 * vector0.x() + m_01 * vector0.y() + m_02,
00207         m_10 * vector0.x() + m_11 * vector0.y() + m_12,
00208         m_20 * vector0.x() + m_21 * vector0.y() + 1.0);
00209     }
00210 
00211     // The assignment operator simply duplicates its argument.
00212     Transform2D&
00213     Transform2D::
00214     operator=(const Transform2D& source)
00215     {
00216       m_00 = source.m_00; m_01 = source.m_01; m_02 = source.m_02;
00217       m_10 = source.m_10; m_11 = source.m_11; m_12 = source.m_12;
00218       m_20 = source.m_20; m_21 = source.m_21;
00219       return *this;
00220     }
00221 
00222     void
00223     Transform2D::
00224     normalize(double scaleFactor)
00225     {
00226       if(scaleFactor == 0.0) {
00227         DLR_THROW3(ValueException, "Trahnsform2D::normalize(double)",
00228                    "Invalid normalization constant. "
00229                    "The bottom right element of a homogeneous transformation "
00230                    "cannot be equal to 0.0.");
00231       }
00232       if(scaleFactor != 1.0) {
00233         m_00 /= scaleFactor;
00234         m_01 /= scaleFactor;
00235         m_02 /= scaleFactor;
00236         m_10 /= scaleFactor;
00237         m_11 /= scaleFactor;
00238         m_12 /= scaleFactor;
00239         m_20 /= scaleFactor;
00240         m_21 /= scaleFactor;
00241       }
00242     }
00243 
00244     /* ============== Non-member functions which should ============== */
00245     /* ============== probably live in a different file ============== */
00246   
00247   
00248     // This operator composes two Transform2D instances.  The resulting
00249     // transform satisfies the equation:
00250     //   (transform0 * transform1) * v0 = transform0 * (transform1 * v0),
00251     // where v0 is a Vector2D instance.
00252     Transform2D
00253     operator*(const Transform2D& transform0, const Transform2D& transform1)
00254     {
00255       double a00 = (transform0.value<0, 0>() * transform1.value<0, 0>()
00256                     + transform0.value<0, 1>() * transform1.value<1, 0>()
00257                     + transform0.value<0, 2>() * transform1.value<2, 0>());
00258       double a01 = (transform0.value<0, 0>() * transform1.value<0, 1>()
00259                     + transform0.value<0, 1>() * transform1.value<1, 1>()
00260                     + transform0.value<0, 2>() * transform1.value<2, 1>());
00261       double a02 = (transform0.value<0, 0>() * transform1.value<0, 2>()
00262                     + transform0.value<0, 1>() * transform1.value<1, 2>()
00263                     + transform0.value<0, 2>() * transform1.value<2, 2>());
00264       double a10 = (transform0.value<1, 0>() * transform1.value<0, 0>()
00265                     + transform0.value<1, 1>() * transform1.value<1, 0>()
00266                     + transform0.value<1, 2>() * transform1.value<2, 0>());
00267       double a11 = (transform0.value<1, 0>() * transform1.value<0, 1>()
00268                     + transform0.value<1, 1>() * transform1.value<1, 1>()
00269                     + transform0.value<1, 2>() * transform1.value<2, 1>());
00270       double a12 = (transform0.value<1, 0>() * transform1.value<0, 2>()
00271                     + transform0.value<1, 1>() * transform1.value<1, 2>()
00272                     + transform0.value<1, 2>() * transform1.value<2, 2>());
00273       double a20 = (transform0.value<2, 0>() * transform1.value<0, 0>()
00274                     + transform0.value<2, 1>() * transform1.value<1, 0>()
00275                     + transform0.value<2, 2>() * transform1.value<2, 0>());
00276       double a21 = (transform0.value<2, 0>() * transform1.value<0, 1>()
00277                     + transform0.value<2, 1>() * transform1.value<1, 1>()
00278                     + transform0.value<2, 2>() * transform1.value<2, 1>());
00279       double a22 = (transform0.value<2, 0>() * transform1.value<0, 2>()
00280                     + transform0.value<2, 1>() * transform1.value<1, 2>()
00281                     + transform0.value<2, 2>() * transform1.value<2, 2>());
00282       return Transform2D(a00, a01, a02,
00283                          a10, a11, a12,
00284                          a20, a21, a22);
00285     }
00286 
00287 
00288     std::ostream&
00289     operator<<(std::ostream& stream, const Transform2D& transform0)
00290     {
00291       stream << "Transform2D("
00292              << transform0.value<0, 0>() << ", "
00293              << transform0.value<0, 1>() << ", "
00294              << transform0.value<0, 2>() << ", "
00295              << transform0.value<1, 0>() << ", "
00296              << transform0.value<1, 1>() << ", "
00297              << transform0.value<1, 2>() << ", "
00298              << transform0.value<2, 0>() << ", "
00299              << transform0.value<2, 1>() << ", "
00300              << transform0.value<2, 2>() << ")";
00301       return stream;
00302     }
00303 
00304   
00305     std::istream&
00306     operator>>(std::istream& stream, Transform2D& transform0)
00307     {
00308       // If stream is in a bad state, we can't read from it.
00309       if (!stream){
00310         return stream;
00311       }
00312     
00313       // It's a lot easier to use a try block than to be constantly
00314       // testing whether the IO has succeeded, so we tell stream to
00315       // complain if anything goes wrong.
00316       std::ios_base::iostate oldExceptionState = stream.exceptions();
00317       stream.exceptions(
00318         std::ios_base::badbit | std::ios_base::failbit | std::ios_base::eofbit);
00319 
00320       // Now on with the show.
00321       try{
00322         // Construct an InputStream instance so we can use our
00323         // convenience functions.
00324         InputStream inputStream(stream);
00325 
00326         // Advance to the next relevant character.
00327         inputStream.skipWhiteSpace();
00328       
00329         // Read the "Transform2D(" part.
00330         inputStream.expect("Transform2D(");
00331 
00332         // Read all the data except the last element.
00333         std::vector<double> inputValues(9);
00334         for(size_t index = 0; index < (inputValues.size() - 1); ++index) {
00335           // Read the value.
00336           inputStream >> inputValues[index];
00337 
00338           // Read punctuation before the next value.
00339           inputStream.expect(",");
00340         }
00341 
00342         // Read the final value.
00343         inputStream >> inputValues[inputValues.size() - 1];
00344 
00345         // Read the closing parenthesis.
00346         inputStream.expect(")");
00347 
00348         // And update the transform.
00349         transform0.setTransform(
00350           inputValues[0], inputValues[1], inputValues[2],
00351           inputValues[3], inputValues[4], inputValues[5],
00352           inputValues[6], inputValues[7], inputValues[8]);
00353 
00354       } catch(std::ios_base::failure) {
00355         // Empty
00356       }
00357       stream.exceptions(oldExceptionState);
00358       return stream;
00359     }
00360   
00361   } // namespace numeric
00362 
00363 } // namespace dlr

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