00001
00006 #ifdef HAVE_CONFIG_H
00007 #include <tumble-conf.h>
00008 #endif
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
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
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
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
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 ¢er, 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
00141 v0->set_cp(gps[0]);
00142
00143
00144
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 ¢er,
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
00179 v0->set_cp(gps[0]);
00180 v1->set_cp(gps[segments]);
00181
00182
00183
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 ¢er,
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
00223 v0->set_cp(gps[0]);
00224 v1->set_cp(gps[segments]);
00225
00226
00227
00228
00229
00230
00231
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
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
00245 initial.coords[0] = -(y0 - y1 + m1*x1 - m0*x0) / (m0 - m1);
00246 initial.coords[1] = y0 + m0*(initial.x() - x0);
00247
00248 return create_edge(v0, v1, gps, initial);
00249 }
00250
00251
00252
00253
00254
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
00314 mesher->mesh();
00315
00316
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> ¢ers)
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
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> ¢ers)
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
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> ¢ers)
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
00405
00406
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
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 }