tissue.h

Go to the documentation of this file.
00001 
00007 #ifndef VVELIB_ALGORITHMS_TISSUE_H
00008 #define VVELIB_ALGORITHMS_TISSUE_H
00009 
00010 #include <config.h>
00011 #include <algorithms/complex.h>
00012 #include <geometry/geometry.h>
00013 
00024 namespace tissue
00025 {
00026   using util::norm;
00027   using util::normsq;
00028   using util::normalized;
00029 
00030   using vvcomplex::DivisionData;
00031   using vvcomplex::InModelDivisionParam;
00032   using vvcomplex::FindWallMin;
00033   using vvcomplex::FindOppositeWall;
00034   using vvcomplex::FindCenter;
00035 
00036 #ifndef max
00037   using std::max;
00038 #endif
00039 
00043   using geometry::Point3d;
00044 
00048   enum CELL_DIVISION_ALGORITHM
00049   {
00050     CLOSEST_MID,
00051     SHORT_WALL,
00052     CLOSEST_WALL
00053   };
00054 
00055 #ifdef JUST_FOR_DOXYGEN
00056 
00059   typedef Tissue::vertex vertex;
00063   typedef Tissue::cell_graph cell_graph;
00067   typedef Tissue::tissue_graph tissue_graph;
00068 #endif
00069 
00073   struct CellPinchingParams
00074   {
00078     CellPinchingParams(double cp = 0, double cmp = 0)
00079       : cellPinch(cp)
00080       , cellMaxPinch(cmp)
00081     { }
00082 
00086     CellPinchingParams(const CellPinchingParams& copy)
00087       : cellPinch(copy.cellPinch)
00088       , cellMaxPinch(copy.cellMaxPinch)
00089     { }
00090 
00094     double cellPinch;
00098     double cellMaxPinch;
00099   };
00100 
00116   template <class Complex>
00117     void cellPinching(const typename Complex::cell& c,
00118                       Complex& T,
00119                       DivisionData<typename Complex::junction_content>& data,
00120                       const CellPinchingParams& params)
00121   {
00122     typedef typename Complex::cell cell;
00123     typedef typename Complex::junction junction;
00124     typename Complex::model_t& model = *T.model;
00125     // Calculate cell pinch
00126     double mind = 0.0;
00127     double pinch = 0.0;
00128 
00129     junction p_u1 = data.u1;
00130     junction p_u2 = T.S.nextTo(c, p_u1);
00131 
00132     junction p_v1 = data.v1;
00133     junction p_v2 = T.S.nextTo(c, p_v1);
00134 
00135     Point3d u1 = model.position(p_u1);
00136     Point3d u2 = model.position(p_u2);
00137 
00138     // If on edge, don't pinch
00139     if(!T.border(p_u1, p_u2))
00140     {
00141       Point3d uc = (data.pv - data.pu);
00142       double ucl = norm(uc);
00143       uc /= ucl;
00144       double uu1 = norm(data.pu-u1);
00145       double uu2 = norm(data.pu-u2);
00146       if(uu1 > uu2)
00147         mind = uu2;
00148       else
00149         mind = uu1;
00150       pinch = mind * ucl * params.cellPinch;
00151       if(pinch > params.cellMaxPinch)
00152         pinch = params.cellMaxPinch;
00153       data.pu += uc * pinch;
00154     }
00155 
00156     Point3d v1 = model.position(p_v1);
00157     Point3d v2 = model.position(p_v2);
00158 
00159     if(!T.border(p_v1, p_v2))
00160     {
00161       Point3d vc = (data.pu - data.pv);
00162       double vcl = norm(vc);
00163       vc /= vcl;
00164       double vv1 = norm(data.pv-v1);
00165       double vv2 = norm(data.pv-v2);
00166       if(vv1 > vv2)
00167         mind = vv2;
00168       else
00169         mind = vv1;
00170       pinch = mind * vcl * params.cellPinch;
00171       if(pinch > params.cellMaxPinch)
00172         pinch = params.cellMaxPinch;
00173       data.pv += vc * pinch;
00174     }
00175   }
00176 
00180   struct ShortWallAlgoParams : public CellPinchingParams
00181   {
00185     ShortWallAlgoParams(double cwm = 0, bool scwm = true, double cws = 0.1, double d = 0.1)
00186       : CellPinchingParams()
00187       , cellWallMin(cwm)
00188       , strictCellWallMin(scwm)
00189       , cellWallSample(cws)
00190       , dx(d)
00191       { }
00192 
00196     ShortWallAlgoParams(const ShortWallAlgoParams& copy)
00197       : CellPinchingParams(copy)
00198       , cellWallMin(copy.cellWallMin)
00199       , strictCellWallMin(copy.strictCellWallMin)
00200       , cellWallSample(copy.cellWallSample)
00201       , dx(copy.dx)
00202       { }
00203 
00207     double cellWallMin;
00212     bool strictCellWallMin;
00216     double cellWallSample;
00220     double dx;
00221   };
00222 
00226   struct ClosestMidAlgoParams : public CellPinchingParams
00227   {
00231     ClosestMidAlgoParams(double cwm = 0, bool scwm = true)
00232       : CellPinchingParams()
00233       , cellWallMin(cwm)
00234       , strictCellWallMin(scwm)
00235       { }
00236 
00240     ClosestMidAlgoParams(const ClosestMidAlgoParams& copy)
00241       : CellPinchingParams(copy)
00242       , cellWallMin(copy.cellWallMin)
00243       , strictCellWallMin(copy.strictCellWallMin)
00244       { }
00245 
00249     double cellWallMin;
00254     bool strictCellWallMin;
00255   };
00256 
00260   struct ClosestWallAlgoParams : public CellPinchingParams
00261   {
00265     ClosestWallAlgoParams(double cwm = 0, bool scwm = true)
00266       : CellPinchingParams()
00267       , cellWallMin(cwm)
00268       , strictCellWallMin(scwm)
00269       { }
00270 
00274     ClosestWallAlgoParams(const ClosestWallAlgoParams& copy)
00275       : CellPinchingParams(copy)
00276       , cellWallMin(copy.cellWallMin)
00277       , strictCellWallMin(copy.strictCellWallMin)
00278       { }
00279 
00283     double cellWallMin;
00288     bool strictCellWallMin;
00289   };
00290 
00306   template <class Complex>
00307   DivisionData<typename Complex::junction_content> findDivisionPoints(const typename Complex::cell& c,
00308                                                                       Complex& T,
00309                                                                       const ShortWallAlgoParams& params)
00310   {
00311     IMPORT_COMPLEX_VERTICES(Complex);
00312     IMPORT_COMPLEX_MODEL(Complex, T);
00313     DivisionData<typename Complex::junction_content> result;
00314     // p_u1-u2, first edge, p_v1-v2 opposite edge
00315     Point3d minu, minv;
00316 
00317     // Find center (in case growth has changed it)
00318     //FindCenter(c, S, model);
00319 
00320     Point3d cpos = model.position(c);
00321 
00322     // Find shortest line through center
00323     double mindis = HUGE_VAL;
00324     Point3d n;
00325     n = model.normal(c);
00326     double epsilon = 0;
00327     forall(const junction& tu1, T.S.neighbors(c))
00328     {
00329       const junction& tu2 = T.S.nextTo(c, tu1);
00330       Point3d u1 = model.position(tu1);
00331       Point3d u2 = model.position(tu2);
00332       Point3d u1u2 = u2 - u1;
00333       double u1u2l = norm(u1u2);
00334       u1u2 /= u1u2l;
00335       epsilon = max(epsilon, VVE_REL_EPSILON*u1u2l);
00336       forall(const junction& tv1, T.S.neighbors(c))
00337       {
00338         if(tv1 == tu1)
00339         {
00340           continue;
00341         }
00342         const junction& tv2 = T.S.nextTo(c, tv1);
00343         const Point3d& v1 = model.position(tv1);
00344         const Point3d& v2 = model.position(tv2);
00345 
00346         double ule = u1u2l - params.cellWallMin;
00347         for(double ul = params.cellWallMin; ul < ule; ul += params.cellWallSample) 
00348         {
00349           Point3d u = u1 + ul * u1u2;
00350           Point3d uc = cpos - u;
00351           Point3d nu = n^uc;
00352           Point3d v;
00353           double s;
00354           if(geometry::planeLineIntersection(v, s, u, nu, v1, v2))
00355           {
00356             if(s >= -params.dx  && s <= (1.0 + params.dx))
00357             {
00358               if(FindWallMin(v, v1, v2, params.cellWallMin) or not params.strictCellWallMin)
00359               {
00360                 double dis = norm(u-v);
00361                 if(dis < mindis and (u-cpos)*(v-cpos) < 0)
00362                 {
00363                   mindis = dis;
00364                   minu = u;
00365                   minv = v;
00366                   result.u1 = tu1;
00367                   result.v1 = tv1;
00368                 }
00369               }
00370             }
00371           }
00372         } // Samples
00373       } // v1v2
00374     } // u1u2
00375     if(mindis == HUGE_VAL)
00376     {
00377       util::out << "findDivisionPoints::Error:Failed to find divide line" << endl;
00378       return DivisionData<typename Complex::junction_content>();
00379     }
00380     result.pu = minu;
00381     result.pv = minv;
00382 
00383     if(params.cellWallMin == 0)
00384       testDivisionOnVertices(c, result, T, epsilon);
00385 
00386     cellPinching(c, T, result, params);
00387     return result;
00388   }
00389 
00405   template <class Complex>
00406   DivisionData<typename Complex::junction_content> findDivisionPoints(const typename Complex::cell& c,
00407                                                                       Complex& T,
00408                                                                       const ClosestMidAlgoParams& params)
00409   {
00410     IMPORT_COMPLEX_VERTICES(Complex);
00411     IMPORT_COMPLEX_MODEL(Complex, T);
00412     DivisionData<typename Complex::junction_content> result;
00413     // p_u1-u2, first edge, p_v1-v2 opposite edge
00414     Point3d cpos = model.position(c);
00415 
00416     // Find center (in case growth has changed it)
00417     //FindCenter(c, S, model);
00418 
00419     // Find closest midpoint on wall
00420     double mindis = HUGE_VAL;
00421     forall(const junction& tu2, T.S.neighbors(c))
00422     {
00423       // other end of wall
00424       const junction& tu1 = T.S.prevTo(c, tu2);
00425       Point3d u1 = model.position(tu1);
00426       Point3d u2 = model.position(tu2);
00427       Point3d u = (u1 + u2)/2.0;
00428       double dis = norm(u-cpos);
00429       if(dis < mindis)
00430       {
00431         mindis = dis;
00432         result.pu = u;
00433         result.u1 = tu1;
00434       }
00435     }
00436 
00437     FindOppositeWall(c, result, T, params.cellWallMin, params.strictCellWallMin);
00438 
00439     cellPinching(c, T, result, params);
00440     return result;
00441   }
00442 
00458   template <class Complex>
00459   DivisionData<typename Complex::junction_content> findDivisionPoints(const typename Complex::cell& c,
00460                                                                       Complex& T,
00461                                                                       const ClosestWallAlgoParams& params)
00462   {
00463     IMPORT_COMPLEX_VERTICES(Complex);
00464     IMPORT_COMPLEX_MODEL(Complex, T);
00465     DivisionData<typename Complex::junction_content> result;
00466     // p_u1-u2, first edge, p_v1-v2 opposite edge
00467     Point3d cpos = model.position(c);
00468 
00469     // Find center (in case growth has changed it)
00470     //FindCenter(c, S, model);
00471 
00472     // Find closest point on wall
00473     double mindis = 1000000;
00474     double epsilon = 0;
00475     forall( const junction& tu2, T.S.neighbors(c))
00476     {
00477       const junction& tu1 = T.S.prevTo(c, tu2);
00478       Point3d u1 = model.position(tu1);
00479       Point3d u2 = model.position(tu2);
00480       Point3d u1u2 = u2 - u1;
00481       double u1u2l = norm(u1u2);
00482       u1u2 /= u1u2l;
00483       epsilon = max(epsilon, VVE_REL_EPSILON*u1u2l);
00484       Point3d u = u1 + ((cpos - u1) * u1u2) * u1u2;
00485       if(FindWallMin(u, u1, u2, params.cellWallMin) or not params.strictCellWallMin)
00486       {
00487         double dis = norm(u-cpos);
00488         if(dis < mindis)
00489         {
00490           mindis = dis;
00491           result.pu = u;
00492           result.u1 = tu1;
00493         }
00494       }
00495     }
00496 
00497     FindOppositeWall(c, result, T, params.cellWallMin, params.strictCellWallMin);
00498 
00499     if(params.cellWallMin == 0)
00500       testDivisionOnVertices(c, result, T, epsilon);
00501 
00502     cellPinching(c, T, result, params);
00503     return result;
00504   }
00505 
00517   template <typename Model,
00518            typename CellContent, typename JunctionContent,
00519            typename WallContent = graph::_EmptyEdgeContent, typename CellEdgeContent = graph::_EmptyEdgeContent,
00520            typename CellJunctionContent = graph::_EmptyEdgeContent, typename JunctionCellContent = graph::_EmptyEdgeContent,
00521            bool compact = false,
00522 #ifdef USE_ALLOCATOR
00523            typename Alloc = DEFAULT_ALLOC(CellContent),
00524 #endif
00525            typename LeafClass = template_utils::this_class
00526              >
00527   struct Tissue : public vvcomplex::VVComplex<MANDATORY_COMPLEX_TEMPLATE_ARGS,
00528                                               RESOLVE_LEAF_CLASS(LeafClass,Tissue<ALL_COMPLEX_TEMPLATE_ARGS>)>
00529   {
00530     typedef RESOLVE_LEAF_CLASS(LeafClass,Tissue) leaf_class;
00531     typedef vvcomplex::VVComplex<MANDATORY_COMPLEX_TEMPLATE_ARGS,leaf_class> VVComplex;
00532     IMPORT_COMPLEX_TYPES(VVComplex);
00533     typedef typename VVComplex::division_result_t division_result_t;
00534     typedef typename VVComplex::division_data division_data;
00535 
00536     typedef Model model_t;
00537 
00538     // Algorithm parameters
00542     CELL_DIVISION_ALGORITHM cellDivAlg;
00546     double cellPinch;
00550     double cellMaxPinch;
00554     double cellWallMin;
00559     bool strictCellWallMin;
00563     double cellWallSample;
00567     double sampleDx;
00568 
00569     // Drawing parameters
00573     const util::Palette* palette;
00577     int colorBegin;
00581     int colorEnd;
00585     double colorCenter;
00589     int contourColor;
00593     double cellWallCorner;
00598     bool drawInsides;
00603     bool drawBorders;
00609     double blending;
00615     double center_blending;
00619     double cellWallWidth;
00620 
00624     Tissue( Model* mod )
00625       : VVComplex(mod)
00626       , cellDivAlg(SHORT_WALL)
00627       , cellPinch(0)
00628       , cellMaxPinch(0)
00629       , cellWallMin(0)
00630       , strictCellWallMin(true)
00631       , cellWallSample(100)
00632       , sampleDx(0.1)
00633       , palette(NULL)
00634       , colorBegin(0)
00635       , colorEnd(1)
00636       , colorCenter(0.2)
00637       , contourColor(3)
00638       , cellWallCorner(0.15)
00639       , drawInsides(true)
00640       , drawBorders(true)
00641       , blending(1)
00642       , center_blending(1)
00643       , cellWallWidth(0.2)
00644       { }
00645 
00649     Tissue( const util::Palette& pal, Model* mod )
00650       : VVComplex(mod)
00651       , cellDivAlg(SHORT_WALL)
00652       , cellPinch(0)
00653       , cellMaxPinch(0)
00654       , cellWallMin(0)
00655       , strictCellWallMin(true)
00656       , cellWallSample(100)
00657       , sampleDx(0.1)
00658       , palette(&pal)
00659       , colorBegin(0)
00660       , colorEnd(1)
00661       , colorCenter(0.2)
00662       , contourColor(3)
00663       , cellWallCorner(0.15)
00664       , drawInsides(true)
00665       , drawBorders(true)
00666       , blending(1)
00667       , center_blending(1)
00668       , cellWallWidth(0.2)
00669       { }
00670 
00674     Tissue( const Tissue& copy )
00675       : VVComplex(copy)
00676       , cellDivAlg(copy.cellDivAlg)
00677       , cellPinch(copy.cellPinch)
00678       , cellMaxPinch(copy.cellMaxPinch)
00679       , cellWallMin(copy.cellWallMin)
00680       , strictCellWallMin(copy.strictCellWallMin)
00681       , cellWallSample(copy.cellWallSample)
00682       , sampleDx(copy.sampleDx)
00683       , palette(copy.palette)
00684       , colorBegin(copy.colorBegin)
00685       , colorEnd(copy.colorEnd)
00686       , colorCenter(copy.colorCenter)
00687       , contourColor(copy.contourColor)
00688       , cellWallCorner(copy.cellWallCorner)
00689       , drawInsides(copy.drawInsides)
00690       , drawBorders(copy.drawBorders)
00691       , blending(copy.blending)
00692       , center_blending(copy.center_blending)
00693       , cellWallWidth(copy.cellWallWidth)
00694       { }
00695 
00702     void readParms( util::Parms& parms, const QString& section )
00703     {
00704       QString algo;
00705       parms(section, "DivisionAlgorithm", algo);
00706       algo = algo.toLower();
00707       if( algo == "closestmid" )
00708         cellDivAlg = CLOSEST_MID;
00709       else if(algo == "shortwall")
00710         cellDivAlg = SHORT_WALL;
00711       else if(algo == "closestwall")
00712         cellDivAlg = CLOSEST_WALL;
00713       else
00714       {
00715         util::err << "Invalid division algorithm, should be ClosestMid, ShortWall or ClosestWall. Choosing ShortWall by default." << endl;
00716         cellDivAlg = SHORT_WALL;
00717       }
00718       parms(section, "CellPinch", cellPinch);
00719       parms(section, "CellMaxPinch", cellMaxPinch);
00720       parms(section, "CellWallMin", cellWallMin);
00721       parms(section, "StrictCellWallMin", strictCellWallMin);
00722       parms(section, "CellWallSample", cellWallSample);
00723       parms(section, "CellSampleDx", sampleDx);
00724     }
00725 
00732     void readViewParms( util::Parms& parms, const QString& section )
00733     {
00734       parms(section, "CellColorBegin", colorBegin);
00735       parms(section, "CellColorEnd", colorEnd);
00736       parms(section, "CellColorCenter", colorCenter);
00737       parms(section, "CellContourColor", contourColor);
00738       parms(section, "CellWallCorner", cellWallCorner);
00739       parms(section, "DrawInsideCells", drawInsides);
00740       parms(section, "DrawCellBorders", drawBorders);
00741       parms(section, "CellBlending", blending);
00742       parms(section, "CellCenterBlending", center_blending);
00743       parms(section, "CellWallWidth", cellWallWidth);
00744     }
00745 
00751     void setCellPinchingParams(CellPinchingParams& params)
00752     {
00753       params.cellPinch = cellPinch;
00754       params.cellMaxPinch = cellMaxPinch;
00755     }
00756 
00760     CellPinchingParams getCellPinchingParams()
00761     {
00762       return CellPinchingParams(cellPinch, cellMaxPinch);
00763     }
00764 
00768     ShortWallAlgoParams getShortWallAlgoParams()
00769     {
00770       ShortWallAlgoParams p(cellWallMin, strictCellWallMin, cellWallSample, sampleDx);
00771       setCellPinchingParams(p);
00772       return p;
00773     }
00774 
00778     ClosestMidAlgoParams getClosestMidAlgoParams()
00779     {
00780       ClosestMidAlgoParams p(cellWallMin, strictCellWallMin);
00781       setCellPinchingParams(p);
00782       return p;
00783     }
00784 
00788     ClosestWallAlgoParams getCloseWallAlgoParams()
00789     {
00790       ClosestWallAlgoParams p(cellWallMin, strictCellWallMin);
00791       setCellPinchingParams(p);
00792       return p;
00793     }
00794 
00795     division_result_t divideCell( const cell& c,
00796                                   const division_data& ddata )
00797     {
00798       division_result_t res = VVComplex::divideCell(c, ddata, std::vector<cell>());
00799       if(res)
00800       {
00801         FindCenter(res.cl, static_cast<leaf_class&>(*this));
00802         FindCenter(res.cr, static_cast<leaf_class&>(*this));
00803       }
00804       return res;
00805     }
00806 
00810     template <typename CellContainer>
00811       division_result_t divideCell( const cell& c,
00812                                     const division_data& ddata,
00813                                     const CellContainer& to_keep)
00814       {
00815         division_result_t res = VVComplex::divideCell(c, ddata, to_keep);
00816         if(res)
00817         {
00818           FindCenter(res.cl, static_cast<leaf_class&>(*this));
00819           FindCenter(res.cr, static_cast<leaf_class&>(*this));
00820         }
00821         return res;
00822       }
00823 
00827     division_result_t divideCell( const cell& c,
00828                                   const division_data& ddata,
00829                                   const cell& to_keep)
00830     {
00831       division_result_t res = VVComplex::divideCell(c, ddata, to_keep);
00832       if(res)
00833       {
00834         FindCenter(res.cl, static_cast<leaf_class&>(*this));
00835         FindCenter(res.cr, static_cast<leaf_class&>(*this));
00836       }
00837       return res;
00838     }
00839 
00840 
00851     template <typename AlgoParameter, typename CellContainer>
00852       division_result_t divideCell( const cell& c, // cell to divide
00853                                     const AlgoParameter& params,
00854                                     const CellContainer& to_keep)
00855     {
00856       division_result_t res = VVComplex::divideCell(c, params, to_keep);
00857       if(res)
00858       {
00859         FindCenter(res.cl, static_cast<leaf_class&>(*this));
00860         FindCenter(res.cr, static_cast<leaf_class&>(*this));
00861       }
00862       return res;
00863     }
00864 
00870     template <typename AlgoParameter>
00871       division_result_t divideCell( const cell& to_divide, // cell to divide
00872                                     const AlgoParameter& params,
00873                                     const cell& cell_kept )
00874     {
00875       division_result_t res = VVComplex::divideCell(to_divide, params, cell_kept);
00876       if(res)
00877       {
00878         FindCenter(res.cl, static_cast<leaf_class&>(*this));
00879         FindCenter(res.cr, static_cast<leaf_class&>(*this));
00880       }
00881       return res;
00882     }
00883 
00889     template <typename CellContainer>
00890       division_result_t divideCell( const cell& to_divide, // cell to divide
00891                                     const CellContainer& kept_cells )
00892     {
00893       switch(cellDivAlg)
00894       {
00895         case CLOSEST_MID:
00896           return divideCell(to_divide, getClosestMidAlgoParams(), kept_cells);
00897         case SHORT_WALL:
00898           return divideCell(to_divide, getShortWallAlgoParams(), kept_cells);
00899         case CLOSEST_WALL:
00900           return divideCell(to_divide, getCloseWallAlgoParams(), kept_cells);
00901         default:
00902           util::err << "Error, unknown algorithm specified ... doing nothing." << endl;
00903       }
00904       return division_result_t();
00905     }
00906 
00913     division_result_t divideCell( const cell& to_divide)
00914     {
00915       std::vector<cell> k;
00916       division_result_t res = this->divideCell(to_divide, k);
00917       if(res)
00918       {
00919         FindCenter(res.cl, static_cast<leaf_class&>(*this));
00920         FindCenter(res.cr, static_cast<leaf_class&>(*this));
00921       }
00922       return res;
00923     }
00924 
00931     division_result_t divideCell( const cell& to_divide, // cell to divide
00932                                   const cell& cell_kept )
00933     {
00934       std::vector<cell> k;
00935       k.push_back(cell_kept);
00936       division_result_t res = this->divideCell(to_divide, k);
00937       if(res)
00938       {
00939         FindCenter(res.cl, static_cast<leaf_class&>(*this));
00940         FindCenter(res.cr, static_cast<leaf_class&>(*this));
00941       }
00942       return res;
00943     }
00944 
00948     void preDraw()
00949     {
00950       glEnable(GL_POLYGON_OFFSET_FILL);
00951       glEnable(GL_POLYGON_OFFSET_LINE);
00952       glLineWidth(1.0);
00953     }
00954 
00958     void postDraw()
00959     {
00960       glDisable(GL_POLYGON_OFFSET_FILL);
00961       glDisable(GL_POLYGON_OFFSET_LINE);
00962     }
00963 
00983     void drawWalledCell(const cell& c,
00984                         util::Palette::Color cell_color,
00985                         util::Palette::Color center_color)
00986     {
00987       Point3d cpos = this->model->position(c);
00988 
00989       if(!drawInsides)
00990       {
00991         cell_color = palette->getColor(colorEnd, blending);
00992         center_color = palette->getColor(colorEnd, center_blending);
00993       }
00994 
00995       // Draw cell faces
00996       glNormal3dv(this->model->normal(c).c_data());
00997 
00998       glPolygonMode(GL_FRONT, GL_FILL);
00999       glPolygonOffset(3.0, 1.0);
01000       glBegin(GL_TRIANGLE_FAN);
01001       glColor4fv(center_color.c_data());
01002       glVertex3dv(cpos.c_data());
01003       glColor4fv(cell_color.c_data());
01004       junction fv(0);
01005       forall(const junction& k, this->S.neighbors(c))
01006       {
01007         if(fv.isNull())
01008           fv = k;
01009         glVertex3dv(this->model->position(k).c_data());
01010       }
01011       glVertex3dv(this->model->position(fv).c_data());
01012       glEnd();
01013 
01014       const std::map<junction,double>& quadsWidth = calcQuads(c);
01015 
01016       glPolygonOffset(-1.0, -1.0);
01017       forall(const junction& k, this->S.neighbors(c))
01018       {
01019         const junction& l = this->S.nextTo(c, k);
01020         const junction& j = this->S.prevTo(c, k);
01021         // Get vectors towards neighbors and normalize
01022         Point3d jpos = this->model->position(j);
01023         Point3d kpos = this->model->position(k);
01024 
01025         if(drawBorders)
01026         {
01027           util::Palette::Color col = this->model->cellWallColor(c, j);
01028           double j_order = 2*this->model->cellWallOrder(c, j);
01029           double l_order = 2*this->model->cellWallOrder(c, l);
01030           double order = std::min(j_order, l_order);
01031           Point3d lpos = this->model->position(l);
01032           Point3d kj = jpos - kpos;
01033           Point3d kl = lpos - kpos;
01034           Point3d kc = cpos - kpos;
01035           Point3d jc = cpos - jpos;
01036           Point3d kjn = kj, kln =kl, kcn = kc, jcn = jc;
01037           kjn /= norm(kjn);
01038           kln /= norm(kln);
01039           kcn /= norm(kcn);
01040           jcn /= norm(jcn);
01041 
01042           // Corner size along cell wall, clip to wall length
01043           double kjl = norm(kj);
01044           if(kjl > cellWallCorner)
01045             kjl = cellWallCorner;
01046           double kll = norm(kl);
01047           if(kll > cellWallCorner)
01048             kll = cellWallCorner;
01049 
01050           double kcl = .75 * cellWallCorner * exp((kjn * kcn + kln * kcn)/2.0);
01051 
01052           // Width of quads for walls
01053           double kcqw = quadsWidth.find(k)->second * cellWallWidth;
01054           double jcqw = quadsWidth.find(j)->second * cellWallWidth;
01055 
01056           // Adjust corner centers if required
01057           bool ccvx; // convex
01058           ccvx = ((kll*kln - kcl*kcn)^(kjl*kjn - kcl*kcn)) * this->model->normal(k) > 0;
01059           if(!ccvx || kcl < kcqw)
01060             kcl = kcqw;
01061 
01062           Point3d p;
01063 
01064           // Draw corners
01065           glPolygonOffset((1.0-order)+1, -3.0);
01066           glColor4fv(col.c_data());
01067           glBegin(GL_TRIANGLE_FAN);
01068           glVertex3dv(kpos.c_data());
01069           p = kpos + kll * kln;
01070           glVertex3dv(p.c_data());
01071           p = kpos + kcl * kcn;
01072           glVertex3dv(p.c_data());
01073           p = kpos + kjl * kjn;
01074           glVertex3dv(p.c_data());
01075           glEnd();
01076 
01077           // Draw cell walls
01078           glPolygonOffset((1.0-j_order)+1, -3.0);
01079           glBegin(GL_QUADS);
01080           glVertex3dv(jpos.c_data());
01081           glVertex3dv(kpos.c_data());
01082           p = kpos + kcqw * kcn;
01083           glVertex3dv(p.c_data());
01084           p = jpos + jcqw * jcn;
01085           glVertex3dv(p.c_data());
01086           glEnd();
01087         }
01088       }
01089     }
01090 
01094     void drawWalledCell(const cell& c,
01095                         double value)
01096     {
01097       Point3d cpos = this->model->position(c);
01098 
01099       if(!drawInsides)
01100       {
01101         value = 0;
01102       }
01103 
01104       // Draw cell faces
01105       glNormal3dv(this->model->normal(c).c_data());
01106 
01107       drawWalledCell(c, valueColor(value), valueCenterColor(value));
01108     }
01109 
01116     void drawCell(const cell& c, util::Palette::Color cell_color,
01117                   util::Palette::Color center_color)
01118     {
01119       Point3d cpos = this->model->position(c);
01120 
01121       if(!drawInsides)
01122       {
01123         cell_color = palette->getColor(colorEnd, blending);
01124         center_color = palette->getColor(colorEnd, center_blending);
01125       }
01126 
01127       // Draw cell faces
01128       glNormal3dv(this->model->normal(c).c_data());
01129 
01130       glPolygonMode(GL_FRONT, GL_FILL);
01131       glPolygonOffset(3.0, 1.0);
01132       glBegin(GL_TRIANGLE_FAN);
01133       glColor4fv(center_color.c_data());
01134       glVertex3dv(cpos.c_data());
01135       glColor4fv(cell_color.c_data());
01136       junction fv(0);
01137       forall(const junction& k, this->S.neighbors(c))
01138       {
01139         if(fv.isNull())
01140           fv = k;
01141         glVertex3dv(this->model->position(k).c_data());
01142       }
01143       glVertex3dv(this->model->position(fv).c_data());
01144       glEnd();
01145 
01146       const std::map<junction,double>& quadsWidth = calcQuads(c);
01147 
01148       if(drawBorders)
01149       {
01150         palette->useColor(contourColor);
01151         glPolygonOffset(-1.0, -1.0);
01152         forall(const junction& k, this->S.neighbors(c))
01153         {
01154           // Get vectors towards neighbors and normalize
01155           const junction& j = this->S.prevTo(c, k);
01156           const junction& l = this->S.nextTo(c, k);
01157 
01158           const Point3d& jpos = this->model->position(j);
01159           const Point3d& kpos = this->model->position(k);
01160           const Point3d& lpos = this->model->position(l);
01161 
01162           Point3d kj = jpos - kpos;
01163           Point3d kl = lpos - kpos;
01164           Point3d kc = cpos - kpos;
01165           Point3d jc = cpos - jpos;
01166           Point3d kjn = kj, kln =kl, kcn = kc, jcn = jc;
01167           kjn /= norm(kjn);
01168           kln /= norm(kln);
01169           kcn /= norm(kcn);
01170           jcn /= norm(jcn);
01171 
01172           // Corner size along cell wall, clip to wall length
01173           double kjl = norm(kj);
01174           if(kjl > cellWallCorner)
01175             kjl = cellWallCorner;
01176           double kll = norm(kl);
01177           if(kll > cellWallCorner)
01178             kll = cellWallCorner;
01179 
01180           double kcl = .75 * cellWallCorner * (kjn * kcn + kln * kcn)/2.0;
01181 
01182           // Width of quads for walls
01183           double kcqw = quadsWidth.find(k)->second * cellWallWidth;
01184           double jcqw = quadsWidth.find(j)->second * cellWallWidth;
01185 
01186           // Adjust corner centers if required
01187           bool ccvx; // convex
01188           ccvx = ((kll*kln - kcl*kcn)^(kjl*kjn - kcl*kcn)) * this->model->normal(k) > 0;
01189           if(!ccvx || kcl < kcqw)
01190             kcl = kcqw;
01191 
01192           Point3d p;
01193 
01194           // Draw corners
01195           glBegin(GL_TRIANGLE_FAN);
01196           glVertex3dv(kpos.c_data());
01197           p = kpos + kll * kln;
01198           glVertex3dv(p.c_data());
01199           p = kpos + kcl * kcn;
01200           glVertex3dv(p.c_data());
01201           p = kpos + kjl * kjn;
01202           glVertex3dv(p.c_data());
01203           glEnd();
01204 
01205           // Draw cell walls
01206           glBegin(GL_QUADS);
01207           glVertex3dv(jpos.c_data());
01208           glVertex3dv(kpos.c_data());
01209           p = kpos + kcqw * kcn;
01210           glVertex3dv(p.c_data());
01211           p = jpos + jcqw * jcn;
01212           glVertex3dv(p.c_data());
01213           glEnd();
01214         }
01215       }
01216     }
01217 
01225     void drawCellContour(const cell& c)
01226     {
01227       palette->useColor(contourColor);
01228       glPolygonMode(GL_FRONT, GL_LINE);
01229       glPolygonOffset(1.0, 5.0);
01230       glBegin(GL_POLYGON);
01231       forall(const junction& n, this->S.neighbors(c))
01232       {
01233         glVertex3dv(this->model->position(n).c_data());
01234       }
01235       glEnd();
01236     }
01237 
01243     void drawSimplifiedCell(const cell& c)
01244     {
01245       glBegin(GL_POLYGON);
01246       forall(const junction& n, this->S.neighbors(c))
01247       {
01248         glVertex3dv(this->model->position(n).c_data());
01249       }
01250       glEnd();
01251     }
01252 
01260     void drawCell(const cell& c, double value)
01261     {
01262       Point3d cpos = this->model->position(c);
01263 
01264       if(!drawInsides)
01265       {
01266         value = 0;
01267       }
01268 
01269       // Draw cell faces
01270       glNormal3dv(this->model->normal(c).c_data());
01271 
01272       drawCell(c, valueColor(value), valueCenterColor(value));
01273     }
01274 
01278     util::Palette::Color valueColor(double value)
01279     {
01280       if(value > 1.0)
01281         value = 1.0;
01282       value *= (1.0 - colorCenter);
01283       return palette->selectColor(colorBegin, colorEnd, value, blending);
01284     }
01285 
01289     util::Palette::Color valueCenterColor(double value)
01290     {
01291       if(value > 1.0)
01292         value = 1.0;
01293       value *= (1.0 - colorCenter);
01294       double value_center = value + colorCenter;
01295       return palette->selectColor(colorBegin, colorEnd, value_center, blending);
01296     }
01297 
01298   protected:
01304     std::map<junction,double>
01305     calcQuads( const cell& c )
01306     {
01307       std::map<junction,double> quadsWidth;
01308       forall(const junction& k, this->S.neighbors(c))
01309       {
01310         const junction& l = this->S.nextTo(c, k);
01311         const junction& j = this->S.prevTo(c, k);
01312 
01313         // Get vectors towards neighbors
01314         Point3d kpos = this->model->position(k);
01315         Point3d kj = this->model->position(j) - kpos;
01316         Point3d kl = this->model->position(l) - kpos;
01317         Point3d kc = this->model->position(c) - kpos;
01318 
01319         // Info for quads
01320         double lsz = norm(kc ^ util::normalized(kl)); // norm(kc - kl * (kc * kl));
01321         if(lsz > 0)
01322           lsz = norm(kc)/lsz;
01323         double jsz = norm(kc ^ util::normalized(kj)); // norm(kc - kj * (kc * kj));
01324         if(jsz > 0)
01325           jsz = norm(kc)/jsz;
01326 
01327         quadsWidth[k] = max(lsz, jsz);
01328       }
01329       return quadsWidth;
01330     }
01331 
01332   };
01333 #undef CELL_MESH
01334 #undef TISSUE_MESH
01335 #undef VERTEX
01336 }
01337 #endif // VVELIB_ALGORITHMS_TISSUE_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Generated on Fri May 31 15:37:50 2013 for VVE by  doxygen 1.6.3