meshconstructor.C

Go to the documentation of this file.
00001 
00006 #ifdef HAVE_CONFIG_H
00007 #include <tumble-conf.h>
00008 #endif /* HAVE_CONFIG_H */
00009 
00010 #include "meshconstructor.h"
00011 
00012 #include <algorithm>
00013 #include <cstdio>
00014 #include <cstdlib>
00015 #include <iostream>
00016 #include <sys/time.h>
00017 
00018 #include "boundarymesh.h"
00019 #include "beziermesh.h"
00020 #include "conformalmesher.h"
00021 #include "globals.h"
00022 #include "cleaner.h"
00023 #include "spline.h"
00024 
00025 using namespace std;
00026 using namespace hashers;
00027 
00028 MeshConstructor::MeshConstructor(BezierMesh* _bezier_mesh, BoundaryMesh* _bdry_mesh)
00029 {
00030   bezier = _bezier_mesh;
00031   bdry = _bdry_mesh;
00032   mesher = new ConformalMesher(bezier, bdry);
00033 }
00034 
00035 MeshConstructor::~MeshConstructor()
00036 {
00037   delete mesher;
00038 }
00039 
00040 BoundaryVertex* MeshConstructor::add_vertex(const Point2D &p)
00041 {
00042     return bdry->add_boundary_vertex(p);
00043 }
00044 
00045 BoundaryVertex* MeshConstructor::add_vertex()
00046 {
00047     Point2D p;
00048     return bdry->add_boundary_vertex(p);
00049 }
00050 
00051 BoundaryFace* MeshConstructor::add_face(const vector<BoundaryEdge*> &edges,
00052                                         const Point2D &point)
00053 {
00054   /* refine angle is set to zero by default */
00055     BoundaryFace *face;
00056     face=bdry->add_boundary_face( edges, 0.0, 0);
00057     mesher->add_face_point(face, point);
00058     return face;
00059 }
00060 
00061 BoundaryEdge* MeshConstructor::create_edge(BoundaryVertex *v0, BoundaryVertex *v1,
00062                                            const vector<Point2D> &gps, const Point2D &initial)
00063 {
00064     if(!v0 || !v1 || gps.size() < 2) return NULL;
00065 
00066     vector<Point2D> d;
00067     vector<double> k;
00068     unsigned j;
00069 
00070     /* compute deboor points */
00071     d.push_back( gps.front() );
00072     d.push_back( initial );
00073     for(j=1; j < gps.size() - 1; j++ ) d.push_back( gps[j]*2.0 - d[j]);
00074     d.push_back( gps.back() );
00075 
00076     /* compute knot vector */
00077     double temp = 0.0;
00078     double inc = 1.0/(gps.size()-1);
00079     for(j=0; j < gps.size(); j++){
00080         k.push_back( temp );
00081         temp += inc;
00082     }
00083 
00084     /* create new edge */
00085     BoundaryEdge *e = bdry->add_boundary_edge(v0, v1, d, k);
00086     if( !e ) cout<<"MeshConstructor::create_edge -- Error creating edge!"<<endl;
00087     return e;
00088 }
00089 
00090 
00091 BoundaryEdge*
00092 MeshConstructor::add_line(BoundaryVertex* v0, BoundaryVertex* v1, int segments)
00093 {
00094     return add_line(v0, v1, v0->get_cp(), v1->get_cp(), segments);
00095 }
00096 
00097 BoundaryEdge*
00098 MeshConstructor::add_line(BoundaryVertex* v0, BoundaryVertex* v1, const Point2D &p1, int segments)
00099 {
00100     return add_line(v0, v1, v0->get_cp(), p1, segments);
00101 }
00102 
00103 BoundaryEdge*
00104 MeshConstructor::add_line(BoundaryVertex* v0, BoundaryVertex* v1, const Point2D &p0, const Point2D &p1, int segments)
00105 {
00106     vector<Point2D>  gps;
00107     Point2D inc = (p1 - p0)/segments;
00108     unsigned ngps = segments + 1;
00109 
00110     v0->set_cp(p0);
00111     v1->set_cp(p1);
00112 
00113     Point2D temp = p0;
00114     for(unsigned i=0; i<ngps; i++){
00115         gps.push_back( temp );
00116         temp += inc;
00117     }
00118 
00119     Point2D initial = (gps[0] + gps[1]) * 0.5;
00120 
00121     return create_edge(v0, v1, gps, initial);
00122 }
00123 
00124 BoundaryEdge* MeshConstructor::add_circle(BoundaryVertex *v0, const Point2D &center, double radius, Radians start, int segments)
00125 {
00126     if(!v0 || radius<=0.0 || segments < 4) return NULL;
00127     vector<Point2D>  gps;
00128     Radians inc = TWOPI / (double) segments;
00129     unsigned ngps = segments + 1;
00130 
00131 
00132     double theta = start;
00133     Point2D diff;
00134     for(unsigned i=0; i<ngps; i++){
00135         diff.assign(cos(theta), sin(theta));
00136         gps.push_back( center + diff*radius );
00137         theta += inc;
00138     }
00139 
00140     /* override v0 control point */
00141     v0->set_cp(gps[0]);
00142 
00143     /* compute initial deboor */
00144     /* where tangents to circle at gps[0] and gps[1] intersect */
00145     Point2D initial;
00146     double r;
00147     theta = start + inc/2.0;
00148     initial.assign(cos(theta), sin(theta));
00149     r = radius * sqrt(1.0 + sin(inc/2.0)*sin(inc/2.0) );
00150     initial = center + initial * r;
00151 
00152     return create_edge(v0, v0, gps, initial);
00153 }
00154 
00155 BoundaryEdge* MeshConstructor::add_arc(BoundaryVertex *v0,
00156                                        BoundaryVertex *v1,
00157                                        const Point2D &center,
00158                                        double radius,
00159                                        Radians start,
00160                                        Radians stop,
00161                                        int segments)
00162 {
00163     Radians span = fabs(stop - start);
00164     if(!v0 || !v1 || radius<=0.0 || segments < (int)(2.0*span/PI) ) return NULL;
00165     vector<Point2D>  gps;
00166     Radians inc = span / (double) segments;
00167     unsigned ngps = segments + 1;
00168 
00169 
00170     double theta = start;
00171     Point2D diff;
00172     for(unsigned i=0; i<ngps; i++){
00173         diff.assign(cos(theta), sin(theta));
00174         gps.push_back( center + diff*radius );
00175         theta += inc;
00176     }
00177 
00178     /* override v0 and v1 control point */
00179     v0->set_cp(gps[0]);
00180     v1->set_cp(gps[segments]);
00181 
00182     /* compute initial deboor */
00183     /* where tangents to circle at gps[0] and gps[1] intersect */
00184     Point2D initial;
00185     double r;
00186     theta = start + inc/2.0;
00187     initial.assign(cos(theta), sin(theta));
00188     r = radius * sqrt(1.0 + sin(inc/2.0)*sin(inc/2.0) );
00189     initial = center + initial * r;
00190 
00191     return create_edge(v0, v1, gps, initial);
00192 }
00193 
00194 BoundaryEdge* MeshConstructor::add_spiral( BoundaryVertex *v0,
00195                                            BoundaryVertex *v1,
00196                                            const Point2D &center,
00197                                            double divergence,
00198                                            double radius,
00199                                            Radians start,
00200                                            Radians stop,
00201                                            int segments)
00202 {
00203     Radians span = fabs(stop - start);
00204     if(!v0 || !v1 || stop<start || divergence<=0.0 ||
00205        radius<=0.0 || segments < (int)(2.0*span/PI) ) return NULL;
00206 
00207     vector<Point2D>  gps;
00208     Radians inc = span / (double) segments;
00209     unsigned ngps = segments + 1;
00210 
00211 
00212     double theta = start;
00213     double r = radius;
00214     Point2D diff;
00215     for(unsigned i=0; i<ngps; i++){
00216         diff.assign(cos(theta), sin(theta));
00217         gps.push_back( center + diff * r );
00218         theta += inc;
00219         r += divergence * (inc/TWOPI);
00220     }
00221 
00222     /* override v0 and v1 control point */
00223     v0->set_cp(gps[0]);
00224     v1->set_cp(gps[segments]);
00225 
00226     /* compute initial deboor */
00227     /* use parametric representation of sprial where
00228      * x(phi) = (radius + divergence*phi) cos(phi)
00229      * y(phi) = (radius + divergence*phi) sin(phi)
00230      * m0 = dx/dy(phi0)
00231      * m1 = dx/dy(phi1)
00232      */
00233     Point2D initial;
00234     double phi0 = start;
00235     double phi1 = start+inc;
00236 
00237     double m0 = spiral_derivative(phi0, radius, divergence, start);
00238     double x0 = (radius + divergence * (phi0 - start) / TWOPI)*cos(phi0);
00239     double y0 = (radius + divergence * (phi0 - start) / TWOPI)*sin(phi0);
00240     //cout<<"phi0: "<<phi0<<" x0: "<<x0<<" y0: "<<y0<<" m0: "<<m0<<endl;
00241     double m1 = spiral_derivative(phi1, radius, divergence, start);
00242     double x1 = (radius + divergence * (phi1 - start) / TWOPI)*cos(phi1);
00243     double y1 = (radius + divergence * (phi1 - start) / TWOPI)*sin(phi1);
00244     //cout<<"phi1: "<<phi1<<" x1: "<<x1<<" y1: "<<y1<<" m1: "<<m1<<endl;
00245     initial.coords[0] = -(y0 - y1 + m1*x1 - m0*x0) / (m0 - m1);
00246     initial.coords[1] = y0 + m0*(initial.x() - x0);
00247     //cout<<"initial: "<<initial<<endl;
00248     return create_edge(v0, v1, gps, initial);
00249 }
00250 
00251 /* phi is angular parameter to parametric equations */
00252 /* r0 is initial radius (at phi=0.0) */
00253 /* delta is divergence of spiral in distance/radian */
00254 /* start is starting radians */
00255 double MeshConstructor::spiral_derivative(Radians phi, double r0, Radians delta, Radians start)
00256 {
00257     double cosphi = cos(phi);
00258     double sinphi = sin(phi);
00259     delta /= TWOPI;
00260     double alpha = r0 + (phi-start) * delta;
00261     return (alpha*cosphi + delta * sinphi)/ (delta*cosphi - alpha * sinphi);
00262 }
00263 
00264 
00265 BoundaryEdge* MeshConstructor::add_bezier(BoundaryVertex *v0,
00266                                           BoundaryVertex *v1,
00267                                           const Point2D &p0,
00268                                           const Point2D &p1,
00269                                           const Point2D &p2 )
00270 {
00271     vector<Point2D>  gps;
00272     v0->set_cp(p0);
00273     v1->set_cp(p2);
00274     gps.push_back( p0 );
00275     gps.push_back( p2 );
00276     return create_edge(v0, v1, gps, p1);
00277 }
00278 
00279 void
00280 MeshConstructor::add_box_void(const Point2D &p0, const Point2D &p1, const Point2D &p2, const Point2D &p3, int segments)
00281 {
00282   add_box(p0,p1,p2,p3,segments);
00283   return;
00284 }
00285 
00286 vector<BoundaryEdge*>
00287 MeshConstructor::add_box(const Point2D &p0, const Point2D &p1, const Point2D &p2, const Point2D &p3, int segments)
00288 {
00289     BoundaryVertex *v0, *v1, *v2, *v3;
00290     vector<BoundaryEdge*> es;
00291 
00292     v0 = add_vertex(p0);
00293     v1 = add_vertex(p1);
00294     v2 = add_vertex(p2);
00295     v3 = add_vertex(p3);
00296 
00297     es.push_back( add_line(v0, v1, segments) );
00298     es.push_back( add_line(v1, v2, segments) );
00299     es.push_back( add_line(v2, v3, segments) );
00300     es.push_back( add_line(v3, v0, segments) );
00301 
00302     return es;
00303 }
00304 
00305 void MeshConstructor::add_remove_point(const Point2D &p)
00306 {
00307   mesher->add_hole(p);
00308 }
00309 
00310 
00311 int MeshConstructor::mesh(bool refine)
00312 {
00313   /* create a conformal mesh */
00314   mesher->mesh();
00315 
00316   /* angle should already have bet set in degrees on the boundary facets*/
00317   if (refine) {
00318     remove_small_angles();
00319   }
00320 
00321   return 0;
00322 }
00323 
00324 void MeshConstructor::remove_small_angles()
00325 {
00326     cout << "Begin small angle removal!  Initial size: "
00327       << bezier->get_num_faces() << endl;
00328     bezier->set_linear_flips(true);
00329     bezier->make_delaunay();
00330     bezier->remove_small_angles();
00331     bezier->set_linear_flips(false);
00332     cout << "End small angle removal!  Final size: "
00333       << bezier->get_num_faces() << endl;
00334 }
00335 
00336 
00337 void MeshConstructor::add_red_blood_cells_box(int num, const Point2D &box_top, const Point2D &box_bot,
00338                                               int cell_type, double cell_size, vector<BoundaryVertex*> &verts,
00339                                               vector<BoundaryEdge*> &cells, vector<Point2D> &centers)
00340 {
00341     vector<Point2D> initial_cells;
00342     Point2D p;
00343 
00344     double x_begin = box_bot.x();
00345     double x_span = box_top.x() - box_bot.x();
00346     double y_begin = box_bot.y();
00347     double y_span = box_top.y() - box_bot.y();
00348 
00349     /* generate 30*n initial_cell locations */
00350     timeval tv;
00351     gettimeofday(&tv, NULL);
00352     srand48(tv.tv_sec);
00353     for(int i=0; i < 30*num; ++i){
00354         p.assign(x_begin + x_span * drand48(), y_begin + y_span * drand48());
00355         initial_cells.push_back(p);
00356     }
00357 
00358     insert_cells(num, initial_cells, cell_type, cell_size, verts, cells, centers);
00359 }
00360 
00361 void MeshConstructor::add_red_blood_cells_triangle(int num,
00362                                                    const Point2D &p1, const Point2D &p2, const Point2D &p3,
00363                                                    int cell_type, double cell_size,
00364                                                    vector<BoundaryVertex*> &verts,
00365                                                    vector<BoundaryEdge*> &cells,
00366                                                    vector<Point2D> &centers)
00367 {
00368     vector<Point2D> initial_cells;
00369     Point2D p;
00370     double x_begin = min(p1.x(), min(p2.x(), p3.x()));
00371     double x_end   = max(p1.x(), max(p2.x(), p3.x()));
00372     double x_span  = x_end - x_begin;
00373     double y_begin = min(p1.y(), min(p2.y(), p3.y()));
00374     double y_end   = max(p1.y(), max(p2.y(), p3.y()));
00375     double y_span  = y_end - y_begin;
00376 
00377     /* generate 30*n initial_cell locations */
00378     timeval tv;
00379     gettimeofday(&tv, NULL);
00380     srand48(tv.tv_sec);
00381     for(int i=0;;){
00382         p.assign(x_begin + x_span * drand48(), y_begin + y_span * drand48());
00383         if(p.line_side_test(p1, p2) > 0.0 && p.line_side_test(p2, p3) > 0.0 && p.line_side_test(p3, p1) > 0.0){
00384             i++;
00385             initial_cells.push_back(p);
00386         }
00387         if(i >= 30*num -1) break;
00388     }
00389 
00390     insert_cells(num, initial_cells, cell_type, cell_size, verts, cells, centers);
00391 }
00392 
00393 void MeshConstructor::insert_cells(int num, vector<Point2D> initial_cells,
00394                                    int cell_type, double cell_size, vector<BoundaryVertex*> &verts,
00395                                    vector<BoundaryEdge*> &cells, vector<Point2D> &centers)
00396 {
00397     double safe_dist = cell_size*1.1;
00398     hash_set<int> keep;
00399     int i;
00400     hash_set<int>::iterator j;
00401     bool should_keep;
00402     Point2D p;
00403     if(cell_type < 0) return;
00404     /* find a maximal independant set of centers
00405     * This is O(n^2) for number of cells, but it is
00406     * an 'offline' calculation
00407     */
00408     for(i=0; i < (int) initial_cells.size(); ++i){
00409         if(keep.find(i) != keep.end()) continue;
00410         should_keep = true;
00411         for(j=keep.begin(); j != keep.end(); ++j){
00412             if((i != *j) && ( (initial_cells[i] - initial_cells[*j]).mag() < safe_dist) ){
00413                 should_keep=false;
00414                 break;
00415             }
00416         }
00417         if(should_keep) keep.insert(i);
00418         if((int)keep.size() >= num) break;
00419         if(i%1000==0 && i!=0) cout<<"created "<<i<<" cells..."<<endl;
00420     }
00421 
00422 
00423     /* add no more than n cells, record Edges and centers */
00424     BoundaryVertex *v;
00425     for(i=0, j = keep.begin(); (i < num) && (j != keep.end()); ++i, ++j){
00426         v=add_vertex(p);
00427         verts.push_back(v);
00428         centers.push_back( initial_cells[ *j ] );
00429         cells.push_back( add_circle(v, centers.back(), cell_size*0.5, 0.0, 12) );
00430     }
00431 }

Generated on Mon May 24 09:53:30 2010 for TUMBLE by  doxygen 1.5.2