Field3D
FieldMapping.cpp
Go to the documentation of this file.
00001 //----------------------------------------------------------------------------//
00002 
00003 /*
00004  * Copyright (c) 2009 Sony Pictures Imageworks Inc
00005  *
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  *
00012  * Redistributions of source code must retain the above copyright
00013  * notice, this list of conditions and the following disclaimer.
00014  * Redistributions in binary form must reproduce the above copyright
00015  * notice, this list of conditions and the following disclaimer in the
00016  * documentation and/or other materials provided with the
00017  * distribution.  Neither the name of Sony Pictures Imageworks nor the
00018  * names of its contributors may be used to endorse or promote
00019  * products derived from this software without specific prior written
00020  * permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
00026  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00028  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00029  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00031  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
00033  * OF THE POSSIBILITY OF SUCH DAMAGE.
00034  */
00035 
00036 //----------------------------------------------------------------------------//
00037 
00043 //----------------------------------------------------------------------------//
00044 
00045 #include <iostream>
00046 #include <vector>
00047 
00048 #include "Field.h"
00049 #include "FieldMapping.h"
00050 #include "Types.h"
00051 
00052 //----------------------------------------------------------------------------//
00053 
00054 using namespace boost;
00055 using namespace std;
00056 
00057 //----------------------------------------------------------------------------//
00058 
00059 FIELD3D_NAMESPACE_OPEN
00060 
00061 //----------------------------------------------------------------------------//
00062 // Field3D namespaces
00063 //----------------------------------------------------------------------------//
00064 
00065 
00066 //----------------------------------------------------------------------------//
00067 // Local namespace
00068 //----------------------------------------------------------------------------//
00069 
00070 namespace {
00071   
00072   // Strings ---
00073 
00074   const string k_mappingName("FieldMapping");
00075   const string k_nullMappingName("NullFieldMapping");
00076   const string k_matrixMappingName("MatrixFieldMapping");
00077   const string k_frustumMappingName("FrustumFieldMapping");
00078 
00079   // Functions ---
00080 
00081   template <class Matrix_T>
00082   bool checkMatricesIdentical(const Matrix_T &m1, const Matrix_T &m2,
00083                               double tolerance)
00084   {
00085     if (m1.equalWithRelError(m2, tolerance)) {
00086       return true;
00087     }
00088     V3d s1, r1, t1, sh1, s2, r2, t2, sh2;
00089     if (!FIELD3D_EXTRACT_SHRT(m1, s1, sh1, r1, t1, false)) {
00090       return false;
00091     }
00092     if (!FIELD3D_EXTRACT_SHRT(m2, s2, sh2, r2, t2, false)) {
00093       return false;
00094     }
00095     if (!s1.equalWithRelError(s2, tolerance) ||
00096         !r1.equalWithAbsError(r2, tolerance) ||
00097         !t1.equalWithRelError(t2, tolerance)) {
00098       return false;
00099     }
00100     return true;
00101   }
00102 
00103 }
00104 
00105 //----------------------------------------------------------------------------//
00106 // FieldMapping
00107 //----------------------------------------------------------------------------//
00108 
00109 FieldMapping::FieldMapping()
00110   : RefBase(), 
00111     m_origin(V3i(0)),
00112     m_res(V3i(1))
00113 { 
00114   /* Empty */ 
00115 }
00116 
00117 //----------------------------------------------------------------------------//
00118 
00119 FieldMapping::FieldMapping(const Box3i &extents)
00120   : RefBase()
00121 { 
00122   setExtents(extents);
00123 }
00124 
00125 //----------------------------------------------------------------------------//
00126 
00127 FieldMapping::~FieldMapping()
00128 { 
00129   /* Empty */ 
00130 }
00131 
00132 //----------------------------------------------------------------------------//
00133 
00134 
00135 std::string FieldMapping::className() const
00136 {
00137   return  std::string(classType());
00138 }
00139 
00140 //----------------------------------------------------------------------------//
00141 
00142 void FieldMapping::setExtents(const Box3i &extents)
00143 { 
00144   m_origin = extents.min;
00145   m_res = extents.max - extents.min + V3i(1);
00146   extentsChanged();
00147 }
00148 
00149 //----------------------------------------------------------------------------//
00150 
00151 void FieldMapping::localToVoxel(const V3d &lsP, V3d &vsP) const
00152 { 
00153   vsP = m_origin + lsP * m_res;
00154 }
00155 
00156 //----------------------------------------------------------------------------//
00157 
00158 void FieldMapping::voxelToLocal(const V3d &vsP, V3d &lsP) const
00159 { 
00160   lsP.x = FIELD3D_LERPFACTOR(vsP.x, m_origin.x, m_origin.x + m_res.x);
00161   lsP.y = FIELD3D_LERPFACTOR(vsP.y, m_origin.y, m_origin.y + m_res.y);
00162   lsP.z = FIELD3D_LERPFACTOR(vsP.z, m_origin.z, m_origin.z + m_res.z);
00163 }
00164 
00165 //----------------------------------------------------------------------------//
00166 // NullFieldMapping
00167 //----------------------------------------------------------------------------//
00168 
00169 std::string NullFieldMapping::className() const
00170 {
00171   return std::string(classType());
00172 }
00173 
00174 //----------------------------------------------------------------------------//
00175 
00176 bool NullFieldMapping::isIdentical(FieldMapping::Ptr other, 
00177                                    double tolerance) const
00178 {
00179   // For null mappings it's simple - if the other one is also a null mapping
00180   // then true, otherwise it's false.
00181   
00182   return other->className() == k_nullMappingName;
00183 }
00184 
00185 //----------------------------------------------------------------------------//
00186 
00187 FieldMapping::Ptr NullFieldMapping::clone() const
00188 {
00189   return Ptr(new NullFieldMapping(*this));
00190 }
00191 
00192 //----------------------------------------------------------------------------//
00193 // MatrixFieldMapping
00194 //----------------------------------------------------------------------------//
00195 
00196 MatrixFieldMapping::MatrixFieldMapping()
00197   : FieldMapping()
00198 { 
00199   makeIdentity();
00200 }
00201 
00202 //----------------------------------------------------------------------------//
00203 
00204 MatrixFieldMapping::MatrixFieldMapping(const Box3i &extents)
00205   : FieldMapping(extents)
00206 { 
00207   makeIdentity();
00208 }
00209 
00210 //----------------------------------------------------------------------------//
00211 
00212 void MatrixFieldMapping::setLocalToWorld(const M44d &lsToWs)
00213 {
00214   if (m_lsToWsCurve.numSamples() > 0) {
00215     makeIdentity();
00216   }
00217   setLocalToWorld(0.0f, lsToWs);
00218 }
00219 
00220 //----------------------------------------------------------------------------//
00221 
00222 void MatrixFieldMapping::setLocalToWorld(float t, const M44d &lsToWs)
00223 {
00224   m_lsToWsCurve.addSample(t, lsToWs);
00225   updateTransform();
00226 }
00227 
00228 //----------------------------------------------------------------------------//
00229 
00230 void MatrixFieldMapping::makeIdentity()
00231 {
00232   m_lsToWsCurve.clear();
00233   updateTransform();
00234 }
00235 
00236 //----------------------------------------------------------------------------//
00237 
00238 void MatrixFieldMapping::extentsChanged()
00239 { 
00240   updateTransform();
00241 }
00242 
00243 //----------------------------------------------------------------------------//
00244 
00245 std::string MatrixFieldMapping::className() const
00246 {
00247   return std::string(classType());
00248 }
00249 
00250 //----------------------------------------------------------------------------//
00251 
00252 bool MatrixFieldMapping::isIdentical(FieldMapping::Ptr other, 
00253                                      double tolerance) const
00254 {
00255   typedef MatrixFieldMapping::MatrixCurve::SampleVec SampleVec;
00256 
00257   if (other->className() != k_matrixMappingName) {
00258     return false;
00259   } else {
00260 
00261     MatrixFieldMapping::Ptr mm = 
00262       FIELD_DYNAMIC_CAST<MatrixFieldMapping>(other);
00263 
00264     if (mm) {
00265 
00266       const SampleVec lsToWs1 = m_lsToWsCurve.samples();
00267       const SampleVec lsToWs2 = mm->m_lsToWsCurve.samples();
00268       const SampleVec vsToWs1 = m_vsToWsCurve.samples();
00269       const SampleVec vsToWs2 = mm->m_vsToWsCurve.samples();
00270 
00271       size_t numSamples = lsToWs1.size();
00272       
00273       // First check if time sample counts differ
00274       // lsToWs and vsToWs are guaranteed to have same sample count.
00275       if (lsToWs1.size() != lsToWs2.size()) {
00276         return false;
00277       }
00278       
00279       // Then check if all time samples match, then check localToWorld 
00280       // and voxelToWorld matrices
00281       for (size_t i = 0; i < numSamples; ++i) {
00282         if (lsToWs1[i].first != lsToWs2[i].first) {
00283           return false;
00284         }
00285         if (!checkMatricesIdentical(lsToWs1[i].second, lsToWs2[i].second,
00286                                     tolerance)) {
00287           return false;
00288         }
00289         if (!checkMatricesIdentical(vsToWs1[i].second, vsToWs2[i].second,
00290                                     tolerance)) {
00291           return false;        
00292         }
00293       }
00294 
00295       return true;
00296 
00297     } else {
00298       return false;
00299     }
00300   }
00301   return false;
00302 }
00303 
00304 //----------------------------------------------------------------------------//
00305 
00306 void MatrixFieldMapping::updateTransform() 
00307 {
00308   typedef MatrixCurve::SampleVec::const_iterator SampleIter;
00309 
00310   // Build the voxel to world space transforms ---
00311   M44d lsToVs;
00312   getLocalToVoxelMatrix(lsToVs);
00313   M44d vsToLs = lsToVs.inverse();
00314   // Loop over all samples in lsToWs, append vsToLs and create new curve
00315   // Also handle the special case where lsToWs has no samples. In that
00316   // case m_vsToWsCurve still has to have one sample.
00317   const MatrixCurve::SampleVec &lsToWs = m_lsToWsCurve.samples();
00318   m_vsToWsCurve.clear();
00319   for (SampleIter i = lsToWs.begin(), end = lsToWs.end(); i != end; i++) {
00320     m_vsToWsCurve.addSample(i->first, vsToLs * i->second);
00321   }
00322 
00323   // See if the curve has more than just a single sample
00324   m_isTimeVarying = m_lsToWsCurve.numSamples() > 1;
00325 
00326   // Sample the time-varying transforms at time=0.0
00327   m_lsToWs = m_lsToWsCurve.linear(0.0);
00328   m_wsToLs = m_lsToWs.inverse();
00329   m_vsToWs = vsToLs * m_lsToWs;
00330   m_wsToVs = m_vsToWs.inverse();
00331 
00332   // Precompute the voxel size
00333   V3d voxelOrigin, nextVoxel;
00334   m_vsToWs.multVecMatrix(V3d(0, 0, 0), voxelOrigin);
00335   m_vsToWs.multVecMatrix(V3d(1, 0, 0), nextVoxel);
00336   m_wsVoxelSize.x = (nextVoxel - voxelOrigin).length();
00337   m_vsToWs.multVecMatrix(V3d(0, 1, 0), nextVoxel);
00338   m_wsVoxelSize.y = (nextVoxel - voxelOrigin).length();
00339   m_vsToWs.multVecMatrix(V3d(0, 0, 1), nextVoxel);
00340   m_wsVoxelSize.z = (nextVoxel - voxelOrigin).length();
00341 }
00342 
00343 //----------------------------------------------------------------------------//
00344 
00345 void MatrixFieldMapping::getLocalToVoxelMatrix(M44d &result)
00346 {
00347   // Local to voxel is a scale by the resolution of the field, offset
00348   // to the origin of the extents
00349   M44d scaling, translation;
00350   scaling.setScale(m_res);
00351   translation.setTranslation(m_origin);
00352   result = scaling * translation;
00353 }
00354 
00355 //----------------------------------------------------------------------------//
00356 
00357 FieldMapping::Ptr MatrixFieldMapping::clone() const
00358 {
00359   return Ptr(new MatrixFieldMapping(*this));
00360 }
00361 
00362 //----------------------------------------------------------------------------//
00363 // FrustumFieldMapping
00364 //----------------------------------------------------------------------------//
00365 
00366 FrustumFieldMapping::FrustumFieldMapping()
00367   : FieldMapping(),
00368     m_zDistribution(PerspectiveDistribution),
00369     m_defaultState(true)
00370 { 
00371   reset();
00372 }
00373 
00374 //----------------------------------------------------------------------------//
00375 
00376 FrustumFieldMapping::FrustumFieldMapping(const Box3i &extents)
00377   : FieldMapping(extents)
00378 { 
00379   reset();
00380 }
00381 
00382 //----------------------------------------------------------------------------//
00383 
00384 void FrustumFieldMapping::setTransforms(const M44d &ssToWs, const M44d &csToWs)
00385 {
00386   setTransforms(0.0, ssToWs, csToWs);
00387 }
00388 
00389 //----------------------------------------------------------------------------//
00390 
00391 void FrustumFieldMapping::setTransforms(float t, 
00392                                         const M44d &ssToWs, const M44d &csToWs)
00393 {
00394   if (m_defaultState) {
00395     clearCurves();
00396     m_defaultState = false;
00397   }
00398 
00399   // Construct local-to-world transform from ssToWs
00400   M44d lsToSs, scale, translation;
00401   scale.setScale(V3d(2.0, 2.0, 1.0));
00402   translation.setTranslation(V3d(-1.0, -1.0, 0.0));
00403   lsToSs = scale * translation;
00404   M44d lpsToWs = lsToSs * ssToWs;
00405 
00406   // Add samples to Curves
00407   m_ssToWsCurve.addSample(t, ssToWs);
00408   m_lpsToWsCurve.addSample(t, lpsToWs);
00409   m_csToWsCurve.addSample(t, csToWs);
00410 
00411   // Compute near and far planes ---
00412 
00413   // Because the frustum may be skewed we can't just measure distance from
00414   // the apex of the frustum to the world-space center point of the frustum.
00415   // Instead, we transform into camera space and measure z depth there.
00416 
00417   V3d lsNearP(0.5, 0.5, 0.0), lsFarP(0.5, 0.5, 1.0);
00418   V3d wsNearP, wsFarP, csNearP, csFarP;
00419 
00420   lpsToWs.multVecMatrix(lsNearP, wsNearP);
00421   lpsToWs.multVecMatrix(lsFarP, wsFarP);
00422 
00423   M44d wsToCs = csToWs.inverse();
00424   wsToCs.multVecMatrix(wsNearP, csNearP);
00425   wsToCs.multVecMatrix(wsFarP, csFarP);
00426 
00427   double near = -csNearP.z;
00428   double far = -csFarP.z;
00429 
00430   // Catch NaN here
00431   if (isnan(near) || isnan(far)) {
00432     throw BadPerspectiveMatrix("FrustumFieldMapping::setTransforms "
00433                                "received bad screen-to-world matrix");
00434   }
00435 
00436   m_nearCurve.addSample(t, near);
00437   m_farCurve.addSample(t, far);
00438 
00439   computeVoxelSize();
00440 }
00441 
00442 //----------------------------------------------------------------------------//
00443 
00444 void FrustumFieldMapping::reset()
00445 {
00446   // Default camera to world ---
00447 
00448   M44d csToWs;
00449   csToWs.makeIdentity();
00450 
00451   // Default screen to world ---
00452 
00453   double near = 1;
00454   double far = 2;
00455   double fovRadians = 45.0 * M_PI / 180.0;
00456   double invTan = 1.0 / std::tan(fovRadians / 2.0);
00457   double imageAspectRatio = 1.0;
00458 
00459   M44d perspective(1, 0, 0, 0,
00460                    0, 1, 0, 0,
00461                    0, 0, (far) / (far - near),          1,
00462                    0, 0, (- far * near) / (far - near), 0);
00463 
00464   M44d fov;
00465   fov.setScale(V3d(invTan / imageAspectRatio, invTan, 1.0));
00466   
00467   M44d flipZ;
00468   flipZ.setScale(V3d(1.0, 1.0, -1.0));
00469   
00470   M44d csToSs = flipZ * perspective * fov;
00471 
00472   M44d standardSsToWs = csToSs.inverse() * csToWs;
00473 
00474   // Set default state ---
00475 
00476   clearCurves();
00477   setTransforms(standardSsToWs, csToWs);
00478 
00479   m_defaultState = true;
00480 
00481   computeVoxelSize();
00482 }
00483 
00484 //----------------------------------------------------------------------------//
00485 
00486 void FrustumFieldMapping::extentsChanged()
00487 { 
00488   computeVoxelSize();
00489 }
00490 
00491 //----------------------------------------------------------------------------//
00492 
00493 void FrustumFieldMapping::worldToVoxel(const V3d &wsP, V3d &vsP) const
00494 {
00495   worldToVoxel(wsP, vsP, 0.0);
00496 }
00497 
00498 //----------------------------------------------------------------------------//
00499 
00500 void FrustumFieldMapping::worldToVoxel(const V3d &wsP, V3d &vsP, float time) const
00501 {
00502   V3d lsP;
00503   worldToLocal(wsP, lsP, time);
00504   localToVoxel(lsP, vsP);
00505 }
00506 
00507 //----------------------------------------------------------------------------//
00508 
00509 void FrustumFieldMapping::voxelToWorld(const V3d &vsP, V3d &wsP) const
00510 {
00511   voxelToWorld(vsP, wsP, 0.0);
00512 }
00513 
00514 //----------------------------------------------------------------------------//
00515 
00516 void FrustumFieldMapping::voxelToWorld(const V3d &vsP, V3d &wsP, float time) const
00517 {
00518   V3d lsP;
00519   voxelToLocal(vsP, lsP);
00520   localToWorld(lsP, wsP, time);
00521 }
00522 
00523 //----------------------------------------------------------------------------//
00524 
00525 void FrustumFieldMapping::worldToLocal(const V3d &wsP, V3d &lsP) const
00526 {
00527   worldToLocal(wsP, lsP, 0.0);
00528 }
00529 
00530 //----------------------------------------------------------------------------//
00531 
00532 void FrustumFieldMapping::worldToLocal(const V3d &wsP, V3d &lsP, float time) const
00533 {
00534   switch (m_zDistribution) {
00535   case UniformDistribution:
00536     {
00537       // First transform to local perspective space
00538       V3d lpsP;
00539       m_lpsToWsCurve.linear(time).inverse().multVecMatrix(wsP, lpsP);
00540       // Also transform to camera space
00541       V3d csP;
00542       m_csToWsCurve.linear(time).inverse().multVecMatrix(wsP, csP);
00543       // Interpolate near and far plane at current time
00544       double near = m_nearCurve.linear(time);
00545       double far = m_farCurve.linear(time);
00546       // Use perspective-space X/Y and normalized depth for Z.
00547       lsP = V3d(lpsP.x, lpsP.y, FIELD3D_LERPFACTOR(-csP.z, near, far));
00548       break;
00549     }
00550   case PerspectiveDistribution:
00551   default:
00552     {
00553       m_lpsToWsCurve.linear(time).inverse().multVecMatrix(wsP, lsP);
00554       break;
00555     }
00556   }
00557 }
00558 
00559 //----------------------------------------------------------------------------//
00560 
00561 void FrustumFieldMapping::localToWorld(const V3d &lsP, V3d &wsP) const
00562 {
00563   localToWorld(lsP, wsP, 0.0);
00564 }
00565 
00566 //----------------------------------------------------------------------------//
00567 
00568 void FrustumFieldMapping::localToWorld(const V3d &lsP, V3d &wsP, float time) const
00569 {
00570   switch (m_zDistribution) {
00571   case UniformDistribution:
00572     {
00573       // Interpolate near and far plane at current time
00574       double near = m_nearCurve.linear(time);
00575       double far = m_farCurve.linear(time);
00576       // In this case, local space is -not- equal to local perspective space
00577       // Determine distance from camera
00578       double wsDepthFromCam = FIELD3D_LERP(near, far, lsP.z);
00579       // Transform point right in front of camera, X units away into world space
00580       V3d lpsCenterP, wsCenterP, csCenterP(0.0, 0.0, -wsDepthFromCam);
00581       m_csToWsCurve.linear(time).multVecMatrix(csCenterP, wsCenterP);
00582       // Transform center point into screen space so we know what depth 
00583       // (in screen space) the voxel would live at -if- it were in local
00584       // perspective space.
00585       m_lpsToWsCurve.linear(time).inverse().multVecMatrix(wsCenterP, lpsCenterP);
00586       // Now we create a local perspective coordinate that can be transformed
00587       // using m_lpsToWsCurve
00588       V3d lpsP(lsP.x, lsP.y, lpsCenterP.z);
00589       // Now we can use m_lpsToWsCurve to transform the actual voxel location
00590       m_lpsToWsCurve.linear(time).multVecMatrix(lpsP, wsP);
00591       break;
00592     }
00593   case PerspectiveDistribution:
00594   default:
00595     {
00596       // In this case, local space and local perspective space are the same.
00597       m_lpsToWsCurve.linear(time).multVecMatrix(lsP, wsP);
00598       break;
00599     }
00600   }
00601 }
00602 
00603 //----------------------------------------------------------------------------//
00604 
00605 std::string FrustumFieldMapping::className() const
00606 {
00607   return std::string(classType());
00608 }
00609 
00610 //----------------------------------------------------------------------------//
00611 
00612 bool FrustumFieldMapping::isIdentical(FieldMapping::Ptr other, 
00613                                      double tolerance) const
00614 {
00615   typedef MatrixFieldMapping::MatrixCurve::SampleVec SampleVec;
00616 
00617   if (other->className() != k_frustumMappingName) {
00618     return false;
00619   } else {
00620 
00621     FrustumFieldMapping::Ptr fm = 
00622       FIELD_DYNAMIC_CAST<FrustumFieldMapping>(other);
00623 
00624     if (fm) {
00625 
00626       const SampleVec lpsToWs1 = m_lpsToWsCurve.samples();
00627       const SampleVec lpsToWs2 = fm->m_lpsToWsCurve.samples();
00628       const SampleVec csToWs1 = m_csToWsCurve.samples();
00629       const SampleVec csToWs2 = fm->m_csToWsCurve.samples();
00630 
00631       size_t numSamples = lpsToWs1.size();
00632       
00633       // Check that slice distributions match
00634       if (m_zDistribution != fm->m_zDistribution) {
00635         return false;
00636       }
00637 
00638       // First check if time sample counts differ
00639       // lpsToWs and csToWs are guaranteed to have same sample count.
00640       if (lpsToWs1.size() != lpsToWs2.size()) {
00641         return false;
00642       }
00643       
00644       // Then check if all time samples match, then check localToWorld 
00645       // and voxelToWorld matrices
00646       for (size_t i = 0; i < numSamples; ++i) {
00647         if (lpsToWs1[i].first != lpsToWs2[i].first) {
00648           return false;
00649         }
00650         if (!checkMatricesIdentical(lpsToWs1[i].second, lpsToWs2[i].second,
00651                                     tolerance)) {
00652           return false;
00653         }
00654         if (!checkMatricesIdentical(csToWs1[i].second, csToWs2[i].second,
00655                                     tolerance)) {
00656           return false;        
00657         }
00658       }
00659       
00660       return true;
00661 
00662     } else {
00663       return false;
00664     }
00665   }
00666   return false;
00667 }
00668 
00669 //----------------------------------------------------------------------------//
00670 
00671 V3d FrustumFieldMapping::wsVoxelSize(int /*i*/, int /*j*/, int k) const
00672 {
00673   k = std::min(std::max(k, static_cast<int>(m_origin.z)), 
00674                static_cast<int>(m_origin.z + m_res.z - 1));
00675   return m_wsVoxelSize[k - static_cast<int>(m_origin.z)];
00676 }
00677 
00678 //----------------------------------------------------------------------------//
00679 
00680 void FrustumFieldMapping::computeVoxelSize() 
00681 {
00682   // Precompute the voxel size ---
00683 
00684   m_wsVoxelSize.resize(static_cast<int>(m_res.z),V3d(0.0));
00685 
00686   int i = m_origin.x + m_res.x / 2;
00687   int j = m_origin.y + m_res.y / 2;
00688 
00689   // Do all z slices except last
00690   int zMin = static_cast<int>(m_origin.z);
00691   int zMax = static_cast<int>(m_origin.z + m_res.z - 1);
00692 
00693   for (int k = zMin, idx = 0; k < zMax; ++k, ++idx) {
00694     V3d wsP, wsPx, wsPy, wsPz;
00695     V3d vsP = discToCont(V3i(i, j, k));
00696     V3d vsPx = discToCont(V3i(i + 1, j, k));
00697     V3d vsPy = discToCont(V3i(i, j + 1, k));
00698     V3d vsPz = discToCont(V3i(i, j, k + 1));
00699     voxelToWorld(vsP, wsP);
00700     voxelToWorld(vsPx, wsPx);
00701     voxelToWorld(vsPy, wsPy);
00702     voxelToWorld(vsPz, wsPz);
00703     m_wsVoxelSize[idx] = V3d((wsPx - wsP).length(), 
00704                              (wsPy - wsP).length(),
00705                              (wsPz - wsP).length());
00706   }
00707 
00708   // Duplicate last value since there are no further slices to differentiate
00709   // against
00710   if (m_res.z >= 2) {
00711     m_wsVoxelSize[m_res.z - 1] = m_wsVoxelSize[m_res.z - 2];
00712   }
00713 
00714 }
00715 
00716 //----------------------------------------------------------------------------//
00717 
00718 void FrustumFieldMapping::getLocalToVoxelMatrix(M44d &result)
00719 {
00720   // Local to voxel is a scale by the resolution of the field, offset
00721   // to the origin of the extents
00722   M44d scaling, translation;
00723   scaling.setScale(m_res);
00724   translation.setTranslation(m_origin);
00725   result = scaling * translation;
00726 }
00727 
00728 //----------------------------------------------------------------------------//
00729 
00730 void FrustumFieldMapping::clearCurves()
00731 {
00732   m_lpsToWsCurve.clear();
00733   m_csToWsCurve.clear();
00734   m_nearCurve.clear();
00735   m_farCurve.clear();
00736 }
00737 
00738 //----------------------------------------------------------------------------//
00739 
00740 FieldMapping::Ptr FrustumFieldMapping::clone() const
00741 {
00742   return Ptr(new FrustumFieldMapping(*this));
00743 }
00744 
00745 //----------------------------------------------------------------------------//
00746 
00747 FIELD3D_NAMESPACE_SOURCE_CLOSE
00748 
00749 //----------------------------------------------------------------------------//