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
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
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
00315 Point3d minu, minv;
00316
00317
00318
00319
00320 Point3d cpos = model.position(c);
00321
00322
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 }
00373 }
00374 }
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
00414 Point3d cpos = model.position(c);
00415
00416
00417
00418
00419
00420 double mindis = HUGE_VAL;
00421 forall(const junction& tu2, T.S.neighbors(c))
00422 {
00423
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
00467 Point3d cpos = model.position(c);
00468
00469
00470
00471
00472
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
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
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,
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,
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,
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,
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
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
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
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
01053 double kcqw = quadsWidth.find(k)->second * cellWallWidth;
01054 double jcqw = quadsWidth.find(j)->second * cellWallWidth;
01055
01056
01057 bool ccvx;
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
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
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
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
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
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
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
01183 double kcqw = quadsWidth.find(k)->second * cellWallWidth;
01184 double jcqw = quadsWidth.find(j)->second * cellWallWidth;
01185
01186
01187 bool ccvx;
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
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
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
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
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
01320 double lsz = norm(kc ^ util::normalized(kl));
01321 if(lsz > 0)
01322 lsz = norm(kc)/lsz;
01323 double jsz = norm(kc ^ util::normalized(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