static mesh_s *make_player_mesh() { mesh_s *mesh = mesh_new(); // shader GLuint shaders[2]; shaders[0] = graphics_create_shader_from_file( GL_VERTEX_SHADER, "ship.v.glsl"); shaders[1] = graphics_create_shader_from_file( GL_FRAGMENT_SHADER, "ship.f.glsl"); mesh_set_program(mesh, graphics_create_program(2, shaders)); // geometry obj_s *obj = obj_load("ship.obj"); mesh_set_attribute(mesh, "position", 3, obj_get_vertex_count(obj) * 3 * sizeof(float), obj_get_vertices(obj)); mesh_set_elements(mesh, obj_get_triangle_count(obj) * 3 * sizeof(unsigned), obj_get_triangles(obj)); obj_release(obj); return mesh; }
int main (int argc, char *argv[]) { if (argc != 10) { fprintf(stderr, "Format: ./mpg num0 num1 ... num8\n"); exit(1); } /* select seed for rand() */ srand(time(NULL)); int num[9]; /* number of positions in each subrectangular */ int i; for (i = 0; i < 9; i++) { num[i] = atoi(argv[i+1]); } Mesh mesh; double xp[4] = {0, 167, 333, 500}; double yp[4] = {0, 167, 333, 500}; mesh_new(&mesh, 4, xp, 4, yp); int id = 0; for (i = 0; i < 9; i++) { rand_pos_n_id_in_rect(id, num[i], &mesh.rect[i], 1000, NULL, 1); id += num[i]; } mesh_free(&mesh); return 0; }
int test_element( int argc, char *argv[] ) { Element *e = element_new(); g_return_val_if_fail( e->adjacent_halfedge == NULL , 1 ); element_free( e ); Point2 p1, p2, p3; point2_set( &p1, 0.0, 1.0 ); point2_set( &p2, 0.0, 0.0 ); point2_set( &p3, sqrt( 3.0 ), 0.0 ); gdouble a1, a2, a3; triangle_angles( &p1, &p2, &p3, &a1, &a2, &a3 ); g_return_val_if_fail( fabs( a1 - G_PI/3.0) < SMALL_NUMBER, 1 ); g_return_val_if_fail( fabs( a2 - G_PI/2.0) < SMALL_NUMBER, 1 ); g_return_val_if_fail( fabs( a3 - G_PI/6.0) < SMALL_NUMBER, 1 ); a1 = triangle_circumcircle_radius( &p1, &p2, &p3 ); g_return_val_if_fail( fabs( a1 - 1.0 ) < SMALL_NUMBER, 1 ); a1 = triangle_circumcircle_radius_edge_length( 1.0, sqrt( 3.0 ), 2.0 ); g_return_val_if_fail( fabs( a1 - 1.0 ) < SMALL_NUMBER, 1 ); Point2 p; triangle_circumcenter_coordinates( &p1, &p2, &p3, &p ); g_return_val_if_fail( fabs( p.x - sqrt( 3.0 )/2.0 ) < SMALL_NUMBER, 1 ); g_return_val_if_fail( fabs( p.y - 1.0/2.0 ) < SMALL_NUMBER, 1 ); a1 = triangle_area( &p1, &p2, &p3 ); g_return_val_if_fail( fabs( a1 - sqrt( 3.0 )/2.0 ) < SMALL_NUMBER, 1 ); Mesh *mesh = mesh_new(); Node *n1 = mesh_add_node( mesh, 0.0, 1.0 ); Node *n2 = mesh_add_node( mesh, 0.0, 0.0 ); Node *n3 = mesh_add_node( mesh, sqrt(3.0), 0.0 ); Edge *e1 = mesh_add_edge( mesh, n1, n2 ); Edge *e2 = mesh_add_edge( mesh, n2, n3 ); Edge *e3 = mesh_add_edge( mesh, n3, n1 ); Element *el = mesh_add_element( mesh, &e1->he[0], &e2->he[0], &e3->he[0] ); gdouble l1, l2, l3; element_edge_lengths( el, &l1, &l2, &l3 ); g_return_val_if_fail( fabs( l1 - 1.0) < SMALL_NUMBER, 1); g_return_val_if_fail( fabs( l2 - sqrt(3.0)) < SMALL_NUMBER, 1); g_return_val_if_fail( fabs( l3 - 2.0) < SMALL_NUMBER, 1); HalfEdge *he = element_min_edge( el, &l1 ); g_return_val_if_fail( he->edge == e1, 1 ); g_return_val_if_fail( fabs( l1 - 1.0) < SMALL_NUMBER, 1); l1 = element_min_edge_length( el ); g_return_val_if_fail( fabs( l1 - 1.0) < SMALL_NUMBER, 1); he = element_max_edge( el, &l1 ); g_return_val_if_fail( he->edge == e3, 1 ); g_return_val_if_fail( fabs( l1 - 2.0) < SMALL_NUMBER, 1); l1 = element_max_edge_length( el ); g_return_val_if_fail( fabs( l1 - 2.0) < SMALL_NUMBER, 1); element_angles( el, &a1, &a2, &a3 ); g_return_val_if_fail( fabs( a1 - G_PI/3.0) < SMALL_NUMBER, 1); g_return_val_if_fail( fabs( a2 - G_PI/2.0) < SMALL_NUMBER, 1); g_return_val_if_fail( fabs( a3 - G_PI/6.0) < SMALL_NUMBER, 1); a1 = element_maximum_angle( el ); g_return_val_if_fail( fabs( a1 - G_PI/2.0) < SMALL_NUMBER, 1); a1 = element_minimum_angle( el ); g_return_val_if_fail( fabs( a1 - G_PI/6.0) < SMALL_NUMBER, 1); element_circumcenter_coordinates( el, &p ); g_return_val_if_fail( fabs( p.x - sqrt( 3.0 )/2.0 ) < SMALL_NUMBER, 1); g_return_val_if_fail( fabs( p.y - 1.0/2.0 ) < SMALL_NUMBER, 1); point2_set( NODE_POSITION( n3 ), 3.0, 0.0 ); a1 = element_area( el ); g_return_val_if_fail( fabs( a1 - 3.0/2.0) < SMALL_NUMBER, 1); return 0; }
int main(int argc, char **argv) { fail_unless(!e3x_init(NULL)); // random seed mesh_t meshA = mesh_new(); fail_unless(meshA); lob_t keyA = lob_new(); lob_set(keyA,"1a",A_KEY); lob_t secA = lob_new(); lob_set(secA,"1a",A_SEC); fail_unless(!mesh_load(meshA,secA,keyA)); mesh_on_discover(meshA,"auto",mesh_add); lob_t keyB = lob_new(); lob_set(keyB,"1a",B_KEY); hashname_t hnB = hashname_vkeys(keyB); fail_unless(hnB); link_t linkAB = link_get(meshA,hnB); fail_unless(linkAB); netA = tmesh_new(meshA, "test", NULL); fail_unless(netA); netA->sort = driver_sort; netA->schedule = driver_schedule; netA->advance = driver_advance; netA->medium = driver_medium; netA->free = driver_free; fail_unless(netA->knock); fail_unless(strcmp(netA->community,"test") == 0); // create outgoing beacon fail_unless(tmesh_schedule(netA,1)); fail_unless(netA->beacon); fail_unless(!netA->beacon->frames); fail_unless(!netA->beacon->mote); fail_unless(netA->beacon->medium == 1); // should have schedule a beacon rx fail_unless(scheduled == 1); fail_unless(netA->knock->is_active); fail_unless(netA->knock->tempo == netA->beacon); fail_unless(netA->knock->tempo->at == 2); fail_unless(netA->knock->tempo->chan == 1); mote_t moteB = tmesh_mote(netA, linkAB); fail_unless(moteB); fail_unless(moteB->link == linkAB); fail_unless(moteB->signal); fail_unless(moteB->signal->medium == 1); fail_unless(moteB->signal->driver == (void*)1); /* cmnty_t c = tmesh_join(netA,"qzjb5f4t","foo"); fail_unless(c); fail_unless(c->medium->bin[0] == 134); fail_unless(c->medium->radio == devA->id); fail_unless(c->beacons == NULL); fail_unless(c->pipe->path); LOG("netA %.*s",c->pipe->path->head_len,c->pipe->path->head); fail_unless(tmesh_leave(netA,c)); char hex[256]; netA->last = 1; fail_unless(!tmesh_join(netA, "azdhpa5r", NULL)); fail_unless((c = tmesh_join(netA, "azdhpa5n", "Public"))); fail_unless(c->beacons); fail_unless(c->beacons->public); mote_t m = c->beacons; mote_t mpub = m; memset(m->nonce,42,8); // nonce is random, force stable for fixture testing LOG("nonce %s",util_hex(m->nonce,8,hex)); fail_unless(util_cmp(hex,"2a2a2a2a2a2a2a2a") == 0); LOG("public at is now %lu",c->beacons->at); m = tmesh_link(netA, c, link); fail_unless(m); fail_unless(m->link == link); fail_unless(m == tmesh_link(netA, c, link)); fail_unless(m->order == 0); memset(m->nonce,3,8); // nonce is random, force stable for fixture testing LOG("secret %s",util_hex(m->secret,32,hex)); fail_unless(util_cmp(hex,"b7bc9e4f1f128f49a3bcef321450b996600987b129723cc7ae752d6500883c65") == 0); LOG("public at is now %lu",mpub->at); fail_unless(mote_reset(m)); memset(m->nonce,0,8); // nonce is random, force stable for fixture testing knock_t knock = devA->knock; fail_unless(mote_advance(m)); LOG("next is %lld",m->at); fail_unless(m->at == 8369); fail_unless(mote_knock(m,knock)); fail_unless(!knock->tx); fail_unless(mote_advance(m)); fail_unless(mote_advance(m)); fail_unless(mote_advance(m)); fail_unless(mote_advance(m)); fail_unless(mote_knock(m,knock)); fail_unless(knock->tx); LOG("next is %lld",knock->start); fail_unless(knock->start == 29905); LOG("public at is now %lu",mpub->at); fail_unless(mpub->at == 1); mpub->at = 5; mote_t bm = tmesh_seek(netA,c,link->id); memset(bm->nonce,2,8); // nonce is random, force stable for fixture testing mote_reset(m); memset(m->nonce,2,8); // nonce is random, force stable for fixture testing m->at = 10; fail_unless(tmesh_process(netA,1,1)); fail_unless(m->at == 9); fail_unless(knock->mote == mpub); LOG("tx %d start %lld stop %lld chan %d at %lld",knock->tx,knock->start,knock->stop,knock->chan,m->at); fail_unless(!knock->tx); fail_unless(knock->start == 4); fail_unless(knock->stop == 4+1000); fail_unless(knock->chan == 27); // fail_unless(tmesh_knocked(netA,knock)); LOG("public at is now %lu",c->beacons->at); fail_unless(mote_advance(m)); LOG("seek %s",util_hex(m->nonce,8,hex)); fail_unless(util_cmp(hex,"dc09a8ca7f5cb75e") == 0); fail_unless(mote_advance(m)); LOG("at is %lu",m->at); fail_unless(m->at >= 6037); // public ping now // m->at = 0xffffffff; memset(knock,0,sizeof(struct knock_struct)); fail_unless(tmesh_process(netA,8050,0)); LOG("beacon at is now %lu",bm->at); fail_unless(knock->mote == bm); LOG("tx %d start %lld stop %lld chan %d",knock->tx,knock->start,knock->stop,knock->chan); fail_unless(!knock->tx); fail_unless(knock->start == 9040); fail_unless(knock->stop == 9040+1000); fail_unless(knock->chan == 19); // TEMP DISABLED return 0; // public ping tx memset(m->nonce,4,8); // fixture for testing m->order = 1; memset(knock,0,sizeof(struct knock_struct)); LOG("public at is now %lu",m->at); fail_unless(tmesh_process(netA,20000,0)); fail_unless(knock->mote == bm); LOG("tx %d start %lld stop %lld chan %d",knock->tx,knock->start,knock->stop,knock->chan); fail_unless(knock->ready); fail_unless(knock->tx); fail_unless(knock->start == 21128); fail_unless(knock->chan == 19); // frame would be random ciphered, but we fixed it to test LOG("frame %s",util_hex(knock->frame,32+8,hex)); // just the stable part fail_unless(util_cmp(hex,"6c265ac8d9a533a1bc7c7f49ed83ae5d32d31b4b9b76c485b182d649c91deb08a160aab63ee8212c") == 0); // let's preted it's an rx now knock->tx = 0; knock->stopped = knock->stop; // fake rx good LOG("faking rx in"); fail_unless(!tmesh_knocked(netA,knock)); // identity crisis fail_unless(tmesh_process(netA,42424,0)); LOG("tx %d start %lld stop %lld chan %d",knock->tx,knock->start,knock->stop,knock->chan); fail_unless(knock->stopped); fail_unless(knock->start == 43444); // leave public community fail_unless(tmesh_leave(netA,c)); // two motes meshing mesh_t meshB = mesh_new(); fail_unless(meshB); lob_t secB = lob_new(); lob_set(secB,"1a",B_SEC); fail_unless(!mesh_load(meshB,secB,keyB)); mesh_on_discover(meshB,"auto",mesh_add); hashname_t hnA = hashname_vkeys(keyA); fail_unless(hnA); link_t linkBA = link_get(meshB,hnA); fail_unless(linkBA); netB = tmesh_new(meshB, NULL); fail_unless(netB); cmnty_t cB = tmesh_join(netB,"qzjb5f4t","test"); fail_unless(cB); fail_unless(cB->pipe->path); LOG("netB %s",lob_json(cB->pipe->path)); cmnty_t cA = tmesh_join(netA,"qzjb5f4t","test"); fail_unless(cA); fail_unless(cA->pipe->path); LOG("netA %s",lob_json(cA->pipe->path)); mote_t bmBA = tmesh_seek(netB, cB, linkBA->id); fail_unless(bmBA); fail_unless(bmBA->order == 1); LOG("bmBA %s secret %s",hashname_short(bmBA->beacon),util_hex(bmBA->secret,32,hex)); fail_unless(util_cmp(hex,"9a972d28dcc211d43eafdca7877bed1bbeaec30fd3740f4b787355d10423ad12") == 0); mote_t mBA = tmesh_link(netB, cB, linkBA); fail_unless(mBA); fail_unless(mBA->order == 1); LOG("mBA %s secret %s",hashname_short(mBA->link->id),util_hex(mBA->secret,32,hex)); fail_unless(util_cmp(hex,"9a972d28dcc211d43eafdca7877bed1bbeaec30fd3740f4b787355d10423ad12") == 0); mote_t bmAB = tmesh_seek(netA, cA, link->id); fail_unless(bmAB); fail_unless(bmAB->order == 0); LOG("bmBA %s secret %s",hashname_short(bmAB->beacon),util_hex(bmAB->secret,32,hex)); fail_unless(util_cmp(hex,"9a972d28dcc211d43eafdca7877bed1bbeaec30fd3740f4b787355d10423ad12") == 0); mote_t mAB = tmesh_link(netA, cA, link); fail_unless(mAB); fail_unless(mAB->order == 0); LOG("mAB %s secret %s",hashname_short(mAB->link->id),util_hex(mAB->secret,32,hex)); fail_unless(util_cmp(hex,"9a972d28dcc211d43eafdca7877bed1bbeaec30fd3740f4b787355d10423ad12") == 0); knock_t knBA = devB->knock; knBA->ready = 0; memset(mBA->nonce,0,8); memset(bmBA->nonce,2,8); fail_unless(tmesh_process(netB,10,0)); fail_unless(knBA->mote == bmBA); LOG("BA tx is %d chan %d at %lu",knBA->tx,knBA->chan,knBA->start); fail_unless(knBA->chan == 35); fail_unless(knBA->tx == 0); knock_t knAB = devA->knock; knAB->ready = 0; memset(mAB->nonce,10,8); memset(bmAB->nonce,15,8); fail_unless(tmesh_process(netA,44444,0)); fail_unless(knAB->mote == bmAB); LOG("AB tx is %d chan %d at %lu nonce %s",knAB->tx,knAB->chan,knAB->start,util_hex(mAB->nonce,8,NULL)); fail_unless(knAB->chan == 35); fail_unless(knAB->tx == 1); // fake reception, with fake cake LOG("process netA"); RXTX(knAB,knBA); fail_unless(tmesh_knocked(netA,knAB)); fail_unless(tmesh_process(netA,67689,0)); fail_unless(knAB->mote == bmAB); fail_unless(!bmAB->chunks); LOG("process netB"); RXTX(knAB,knBA); fail_unless(tmesh_knocked(netB,knBA)); fail_unless(tmesh_process(netB,22000,0)); // dummy data for sync send netA->pubim = hashname_im(netA->mesh->keys, hashname_id(netA->mesh->keys,netA->mesh->keys)); netB->pubim = hashname_im(netB->mesh->keys, hashname_id(netB->mesh->keys,netB->mesh->keys)); // back to the future RXTX(knAB,knBA); fail_unless(tmesh_knocked(netA,knAB)); LOG("mAB %lu mBA %lu",mAB->at,mBA->at); while(knBA->mote != bmBA) { knBA->ready = 0; fail_unless(tmesh_process(netB,knBA->stop,0)); } LOG("BA tx is %d chan %d at %lu nonce %s",knBA->tx,knBA->chan,knAB->start,util_hex(mBA->nonce,8,NULL)); // fail_unless(knBA->tx == 1); RXTX(knAB,knBA); LOG("mAB %lu mBA %lu",mAB->at,mBA->at); fail_unless(tmesh_knocked(netB,knBA)); while(knAB->mote != bmAB) { knAB->ready = 0; fail_unless(tmesh_process(netA,knAB->stop,0)); } LOG("AB tx is %d chan %d at %lu nonce %s",knAB->tx,knAB->chan,knAB->start,util_hex(mAB->nonce,8,NULL)); // fail_unless(knAB->tx == 0); // in sync! fail_unless(!mBA->chunks); fail_unless(!mAB->chunks); mAB->at = mBA->at; LOG("mAB %lu mBA %lu",mAB->at,mBA->at); fail_unless(mAB->at == mBA->at); // continue establishing link printf("\n\n"); int max = 40; mote_reset(mAB); mote_reset(mBA); mote_reset(bmAB); mote_reset(bmBA); mAB->at = mBA->at; bmAB->at = bmBA->at; uint32_t step = mAB->at; while(--max > 0 && !link_up(mBA->link) && !link_up(mAB->link)) { printf("\n\n%d %u\n",max,step); tmesh_process(netA,step,0); tmesh_process(netB,step,0); LOG("AB %d %d/%d BA %d %d/%d",knAB->tx,knAB->start,knAB->stop,knBA->tx,knBA->start,knBA->stop); if(knAB->stop > step) step = knAB->stop; if(knBA->stop > step) step = knBA->stop; if(knAB->chan == knBA->chan) { printf("~~~~RXTX %u\n",step); RXTX(knAB,knBA); knAB->stopped = knAB->stop; knBA->stopped = knBA->stop; }else{ knAB->err = knBA->err = 1; } tmesh_knocked(netA,knAB); tmesh_knocked(netB,knBA); } LOG("TODO linked by %d",max); // fail_unless(max); */ return 0; }
static mesh_t* create_dual_mesh_from_tet_mesh(MPI_Comm comm, mesh_t* tet_mesh, char** external_model_face_tags, int num_external_model_face_tags, char** internal_model_face_tags, int num_internal_model_face_tags, char** model_edge_tags, int num_model_edge_tags, char** model_vertex_tags, int num_model_vertex_tags) { // Build sets containing the indices of mesh elements identifying // geometric structure (for ease of querying). // External model faces, their edges, and attached tetrahedra. int_unordered_set_t* external_boundary_tets = int_unordered_set_new(); int_unordered_set_t* external_model_faces = int_unordered_set_new(); int_unordered_set_t* external_model_face_edges = int_unordered_set_new(); int_unordered_set_t* model_face_nodes = int_unordered_set_new(); for (int i = 0; i < num_external_model_face_tags; ++i) { int num_faces; int* tag = mesh_tag(tet_mesh->face_tags, external_model_face_tags[i], &num_faces); for (int f = 0; f < num_faces; ++f) { int face = tag[f]; int_unordered_set_insert(external_model_faces, face); int btet1 = tet_mesh->face_cells[2*face]; int_unordered_set_insert(external_boundary_tets, btet1); int btet2 = tet_mesh->face_cells[2*face+1]; if (btet2 != -1) int_unordered_set_insert(external_boundary_tets, btet2); int pos = 0, edge, node; while (mesh_face_next_edge(tet_mesh, face, &pos, &edge)) int_unordered_set_insert(external_model_face_edges, edge); pos = 0; while (mesh_face_next_node(tet_mesh, face, &pos, &node)) int_unordered_set_insert(model_face_nodes, node); } } // Internal model faces, their edges, and attached tetrahedra. int_unordered_set_t* internal_boundary_tets = int_unordered_set_new(); int_unordered_set_t* internal_model_faces = int_unordered_set_new(); int_unordered_set_t* internal_model_face_edges = int_unordered_set_new(); for (int i = 0; i < num_internal_model_face_tags; ++i) { int num_faces; int* tag = mesh_tag(tet_mesh->face_tags, internal_model_face_tags[i], &num_faces); for (int f = 0; f < num_faces; ++f) { int face = tag[f]; int_unordered_set_insert(internal_model_faces, face); int btet1 = tet_mesh->face_cells[2*face]; int_unordered_set_insert(internal_boundary_tets, btet1); int btet2 = tet_mesh->face_cells[2*face+1]; if (btet2 != -1) int_unordered_set_insert(internal_boundary_tets, btet2); int pos = 0, edge, node; while (mesh_face_next_edge(tet_mesh, face, &pos, &edge)) int_unordered_set_insert(internal_model_face_edges, edge); pos = 0; while (mesh_face_next_node(tet_mesh, face, &pos, &node)) int_unordered_set_insert(model_face_nodes, node); } } // Model edges and nodes belonging to them. int_unordered_set_t* model_edges = int_unordered_set_new(); int_unordered_set_t* model_edge_nodes = int_unordered_set_new(); for (int i = 0; i < num_model_edge_tags; ++i) { int num_edges; int* tag = mesh_tag(tet_mesh->edge_tags, model_edge_tags[i], &num_edges); for (int e = 0; e < num_edges; ++e) { int edge = tag[e]; int_unordered_set_insert(model_edges, edge); int_unordered_set_insert(model_edge_nodes, tet_mesh->edge_nodes[2*edge]); int_unordered_set_insert(model_edge_nodes, tet_mesh->edge_nodes[2*edge+1]); } } int_unordered_set_t* model_vertices = int_unordered_set_new(); for (int i = 0; i < num_model_vertex_tags; ++i) { int num_vertices; int* tag = mesh_tag(tet_mesh->node_tags, model_vertex_tags[i], &num_vertices); for (int v = 0; v < num_vertices; ++v) { int vertex = tag[v]; int_unordered_set_insert(model_vertices, vertex); // A model vertex should not obey the same rules as a vertex that is // attached to a model edge/face, so remove this vertex from those sets. int_unordered_set_delete(model_edge_nodes, vertex); int_unordered_set_delete(model_face_nodes, vertex); } } // Each primal edge is surrounded by primal cells and faces, // so we build lists of these cells/faces with which the edges are // associated. int_unordered_set_t** primal_cells_for_edge = polymec_malloc(sizeof(int_unordered_set_t*) * tet_mesh->num_edges); int_unordered_set_t** primal_faces_for_edge = polymec_malloc(sizeof(int_unordered_set_t*) * tet_mesh->num_edges); int_unordered_set_t** primal_boundary_faces_for_node = polymec_malloc(sizeof(int_unordered_set_t*) * tet_mesh->num_nodes); memset(primal_cells_for_edge, 0, sizeof(int_unordered_set_t*) * tet_mesh->num_edges); memset(primal_faces_for_edge, 0, sizeof(int_unordered_set_t*) * tet_mesh->num_edges); memset(primal_boundary_faces_for_node, 0, sizeof(int_unordered_set_t*) * tet_mesh->num_nodes); for (int cell = 0; cell < tet_mesh->num_cells; ++cell) { int pos = 0, face; while (mesh_cell_next_face(tet_mesh, cell, &pos, &face)) { int pos1 = 0, edge; while (mesh_face_next_edge(tet_mesh, face, &pos1, &edge)) { // Associate the cell with this edge. int_unordered_set_t* cells_for_edge = primal_cells_for_edge[edge]; if (cells_for_edge == NULL) { cells_for_edge = int_unordered_set_new(); primal_cells_for_edge[edge] = cells_for_edge; } int_unordered_set_insert(cells_for_edge, cell); // Associate the face with this edge. int_unordered_set_t* faces_for_edge = primal_faces_for_edge[edge]; if (faces_for_edge == NULL) { faces_for_edge = int_unordered_set_new(); primal_faces_for_edge[edge] = faces_for_edge; } int_unordered_set_insert(faces_for_edge, face); } // If the face is on an internal or external boundary, // associate it with each of the edge's nodes. if (int_unordered_set_contains(external_model_faces, face) || int_unordered_set_contains(internal_model_faces, face)) { int pos1 = 0, node; while (mesh_face_next_node(tet_mesh, face, &pos1, &node)) { int_unordered_set_t* faces_for_node = primal_boundary_faces_for_node[node]; if (faces_for_node == NULL) { faces_for_node = int_unordered_set_new(); primal_boundary_faces_for_node[node] = faces_for_node; } int_unordered_set_insert(faces_for_node, face); } } } } // Count up the dual mesh entities. int num_dual_nodes = external_model_faces->size + internal_model_faces->size + tet_mesh->num_cells + model_edges->size + model_vertices->size; int num_dual_faces_from_boundary_vertices = 0; // Dual faces for boundary faces attached to primal nodes. for (int n = 0; n < tet_mesh->num_nodes; ++n) { int_unordered_set_t* boundary_faces_for_node = primal_boundary_faces_for_node[n]; if (boundary_faces_for_node != NULL) num_dual_faces_from_boundary_vertices += boundary_faces_for_node->size; } { // Dual faces for model edges attached to primal nodes. int pos = 0, edge; while (int_unordered_set_next(model_edges, &pos, &edge)) { int_unordered_set_t* faces_for_edge = primal_faces_for_edge[edge]; int pos1 = 0, face; while (int_unordered_set_next(faces_for_edge, &pos1, &face)) { if (int_unordered_set_contains(external_model_faces, face) || int_unordered_set_contains(internal_model_faces, face)) ++num_dual_faces_from_boundary_vertices; } } // Dual faces for primal nodes that are model vertices. int node; pos = 0; while (int_unordered_set_next(model_vertices, &pos, &node)) { int_unordered_set_t* boundary_faces_for_node = primal_boundary_faces_for_node[node]; ASSERT(boundary_faces_for_node != NULL); num_dual_faces_from_boundary_vertices += boundary_faces_for_node->size; } } int num_dual_faces = tet_mesh->num_edges + external_model_face_edges->size + num_dual_faces_from_boundary_vertices; int num_dual_cells = tet_mesh->num_nodes; int num_dual_ghost_cells = 0; // FIXME: Figuring out ghost dual cells probably requires parallel communication. // Now that we know the various populations, build the dual mesh. mesh_t* dual_mesh = mesh_new(comm, num_dual_cells, num_dual_ghost_cells, num_dual_faces, num_dual_nodes); // Generate dual vertices for each of the interior tetrahedra. tetrahedron_t* tet = tetrahedron_new(); int dv_offset = 0; for (int c = 0; c < tet_mesh->num_cells; ++c, ++dv_offset) { // The dual vertex is located at the circumcenter of the tetrahedral // cell, or the point in the cell closest to it. point_t xc; tetrahedron_compute_circumcenter(tet, &xc); tetrahedron_compute_nearest_point(tet, &xc, &dual_mesh->nodes[dv_offset]); } // Generate dual vertices for each of the model faces. Keep track of which // faces generated which vertices. int_int_unordered_map_t* dual_node_for_model_face = int_int_unordered_map_new(); for (int i = 0; i < num_external_model_face_tags; ++i) { int num_faces; int* tag = mesh_tag(tet_mesh->face_tags, external_model_face_tags[i], &num_faces); for (int f = 0; f < num_faces; ++f, ++dv_offset) { int face = tag[f]; dual_mesh->nodes[dv_offset] = tet_mesh->face_centers[face]; int_int_unordered_map_insert(dual_node_for_model_face, face, dv_offset); } } for (int i = 0; i < num_internal_model_face_tags; ++i) { int num_faces; int* tag = mesh_tag(tet_mesh->face_tags, internal_model_face_tags[i], &num_faces); for (int f = 0; f < num_faces; ++f, ++dv_offset) { int face = tag[f]; dual_mesh->nodes[dv_offset] = tet_mesh->face_centers[face]; int_int_unordered_map_insert(dual_node_for_model_face, face, dv_offset); } } // Generate a dual vertex at the midpoint of each model edge. int_int_unordered_map_t* dual_node_for_edge = int_int_unordered_map_new(); for (int i = 0; i < num_model_edge_tags; ++i) { int num_edges; int* tag = mesh_tag(tet_mesh->edge_tags, model_edge_tags[i], &num_edges); for (int e = 0; e < num_edges; ++e, ++dv_offset) { int edge = tag[e]; point_t* x1 = &tet_mesh->nodes[tet_mesh->edge_nodes[2*edge]]; point_t* x2 = &tet_mesh->nodes[tet_mesh->edge_nodes[2*edge+1]]; point_t* n = &dual_mesh->nodes[dv_offset]; n->x = 0.5 * (x1->x + x2->x); n->y = 0.5 * (x1->y + x2->y); n->z = 0.5 * (x1->z + x2->z); int_int_unordered_map_insert(dual_node_for_edge, e, dv_offset); } } // Generate a dual vertex for each model vertex. for (int i = 0; i < num_model_vertex_tags; ++i) { int num_vertices; int* tag = mesh_tag(tet_mesh->node_tags, model_vertex_tags[i], &num_vertices); for (int v = 0; v < num_vertices; ++v, ++dv_offset) { int vertex = tag[v]; dual_mesh->nodes[dv_offset] = tet_mesh->nodes[vertex]; } } ASSERT(dv_offset == num_dual_nodes); // Now generate dual faces corresponding to primal edges. int df_offset = 0; dual_mesh->face_node_offsets[0] = 0; int_array_t** nodes_for_dual_face = polymec_malloc(sizeof(int_array_t*) * num_dual_faces); memset(nodes_for_dual_face, 0, sizeof(int_array_t*) * num_dual_faces); for (int edge = 0; edge < tet_mesh->num_edges; ++edge) { int_unordered_set_t* cells_for_edge = primal_cells_for_edge[edge]; ASSERT(cells_for_edge != NULL); // Is this edge a model edge? bool is_external_face_edge = int_unordered_set_contains(external_model_face_edges, edge); bool is_internal_face_edge = int_unordered_set_contains(internal_model_face_edges, edge); bool is_model_edge = int_unordered_set_contains(model_edges, edge); if (is_external_face_edge) { // This primal edge belongs to an external model face, // so it lies on the outside of the domain. The corresponding dual // face is bounded by dual nodes created from the primal cells // bounding the edge. We want to order these dual nodes starting at // one boundary cell and finishing at the other. So we extract the // indices of the dual nodes and then pick out the endpoints. int num_nodes = cells_for_edge->size; int pos = 0, cell, c = 0; point_t dual_nodes[num_nodes]; int dual_node_indices[num_nodes]; int endpoint_indices[] = {-1, -1}; while (int_unordered_set_next(cells_for_edge, &pos, &cell)) { dual_nodes[c] = tet_mesh->cell_centers[cell]; dual_node_indices[c] = cell; if (int_unordered_set_contains(external_boundary_tets, cell)) { if (endpoint_indices[0] == -1) endpoint_indices[0] = c; else endpoint_indices[1] = c; } ++c; } // Find a vector connecting the nodes of this edge. This orients // the face. vector_t edge_vector; point_t* x1 = &tet_mesh->nodes[tet_mesh->edge_nodes[2*edge]]; point_t* x2 = &tet_mesh->nodes[tet_mesh->edge_nodes[2*edge+1]]; point_displacement(x1, x2, &edge_vector); // Order the nodes of this dual face. sp_func_t* edge_plane = plane_sp_func_new(&edge_vector, x1); order_nodes_of_dual_face(edge_plane, endpoint_indices, dual_nodes, num_nodes, dual_node_indices); // Update the dual mesh's face->node connectivity metadata. int num_face_nodes = (is_model_edge) ? num_nodes + 1 : num_nodes; ASSERT(num_face_nodes >= 3); dual_mesh->face_node_offsets[df_offset+1] = dual_mesh->face_node_offsets[df_offset] + num_face_nodes; int_array_t* face_nodes = int_array_new(); nodes_for_dual_face[df_offset] = face_nodes; int_array_resize(face_nodes, num_face_nodes); memcpy(face_nodes->data, dual_node_indices, sizeof(int)*num_nodes); // If the edge is a model edge, stick the primal edge's node at the end // of the list of dual face nodes. if (is_model_edge) { int* dual_node_from_edge_p = int_int_unordered_map_get(dual_node_for_edge, edge); ASSERT(dual_node_from_edge_p != NULL); int dual_node_from_edge = *dual_node_from_edge_p; face_nodes->data[num_nodes] = dual_node_from_edge; } ++df_offset; } else if (is_internal_face_edge) { // This primal edge belongs to an internal model face, // so it lies on an interface between two regions within the domain. // We create two dual faces for this edge (one for each region), // using a procedure very similar to the one we used for external // edges above. // Dump the IDs of the cells attached to the edge into a single array. int num_cells = cells_for_edge->size; int pos = 0, cell, c = 0; point_t dual_nodes[num_cells]; int dual_node_indices[num_cells]; while (int_unordered_set_next(cells_for_edge, &pos, &cell)) { dual_nodes[c] = tet_mesh->cell_centers[cell]; dual_node_indices[c] = cell; ++c; } // Since this is an internal interface edge, the dual nodes // corresponding to these cells form a polygon around the edge. We can // arrange the nodes for the two faces (stuck together) into a polygon // using the "star" algorithm and then retrieve them (in order) from // the polygon. polygon_t* dual_polygon = polygon_giftwrap(dual_nodes, num_cells); // polygon_t* dual_polygon = polygon_star(x0, dual_nodes, num_cells); int* ordering = polygon_ordering(dual_polygon); // Now we just need to apportion the right nodes to the right faces. int start_index1 = -1, start_index2 = -1, stop_index1 = -1, stop_index2 = -1; for (int i = 0; i < num_cells; ++i) { // Follow the cells around the face. int this_cell = dual_node_indices[ordering[i]]; int next_cell = dual_node_indices[ordering[(i+1)%num_cells]]; if (int_unordered_set_contains(internal_boundary_tets, this_cell) && int_unordered_set_contains(internal_boundary_tets, next_cell)) { // If this_cell and next_cell share a face that is an internal // model face, they are on the opposite side of the interface. int shared_face = mesh_cell_face_for_neighbor(tet_mesh, this_cell, next_cell); if ((shared_face != -1) && int_unordered_set_contains(internal_model_faces, shared_face)) { if (start_index1 == -1) { // Face 1 starts on the "next cell," and face 2 ends on // "this cell." start_index1 = next_cell; stop_index2 = this_cell; } else { // Face 2 starts on the "next cell," and face 1 ends on // "this cell." start_index2 = next_cell; stop_index1 = this_cell; } } } } // Update the dual mesh's face->node connectivity metadata for // both faces. int num_nodes1 = stop_index1 - start_index1 + 1; int num_face1_nodes = (is_model_edge) ? num_nodes1 + 1 : num_nodes1; ASSERT(num_face1_nodes >= 3); dual_mesh->face_node_offsets[df_offset+1] = dual_mesh->face_node_offsets[df_offset] + num_face1_nodes; int_array_t* face1_nodes = int_array_new(); nodes_for_dual_face[df_offset] = face1_nodes; int_array_resize(face1_nodes, num_nodes1); for (int i = start_index1; i <= stop_index1; ++i) { int j = (start_index1 + i) % num_cells; face1_nodes->data[i] = dual_node_indices[ordering[j]]; } int num_nodes2 = stop_index2 - start_index2 + 1; int num_face2_nodes = (is_model_edge) ? num_nodes2 + 1 : num_nodes2; ASSERT(num_face2_nodes >= 3); dual_mesh->face_node_offsets[df_offset+2] = dual_mesh->face_node_offsets[df_offset+1] + num_face2_nodes; int_array_t* face2_nodes = int_array_new(); nodes_for_dual_face[df_offset+1] = face2_nodes; int_array_resize(face2_nodes, num_nodes2); for (int i = 0; i <= num_nodes2; ++i) { int j = (start_index2 + i) % num_cells; face1_nodes->data[i] = dual_node_indices[ordering[j]]; } // If the edge is a model edge, stick the primal edge's node at the end // of each of the lists of dual face nodes. if (is_model_edge) { int* dual_node_from_edge_p = int_int_unordered_map_get(dual_node_for_edge, edge); ASSERT(dual_node_from_edge_p != NULL); int dual_node_from_edge = *dual_node_from_edge_p; face1_nodes->data[num_nodes1] = dual_node_from_edge; face2_nodes->data[num_nodes2] = dual_node_from_edge; } df_offset += 2; } else { // This edge is on the interior of the domain, so it is only bounded // by cells. // Dump the cell centers into an array. int num_cells = cells_for_edge->size; int pos = 0, cell, c = 0; point_t dual_nodes[num_cells]; while (int_unordered_set_next(cells_for_edge, &pos, &cell)) dual_nodes[c++] = tet_mesh->cell_centers[cell]; // Update the dual mesh's connectivity metadata. dual_mesh->face_node_offsets[df_offset+1] = dual_mesh->face_node_offsets[df_offset] + num_cells; // Since this is an interior edge, the dual nodes corresponding to // these cells form a convex polygon around the edge. We can arrange // the nodes into a convex polygon using the gift-wrapping algorithm. polygon_t* dual_polygon = polygon_giftwrap(dual_nodes, num_cells); int_array_t* face_nodes = int_array_new(); int_array_resize(face_nodes, num_cells); memcpy(face_nodes->data, polygon_ordering(dual_polygon), sizeof(int)*num_cells); nodes_for_dual_face[df_offset] = face_nodes; dual_polygon = NULL; ++df_offset; } } ASSERT(df_offset == num_dual_faces); // Create dual faces corresponding to model vertices. { // Add dual faces for primal nodes attached to model faces. int pos = 0, node; while (int_unordered_set_next(model_face_nodes, &pos, &node)) { // This rule does not apply to nodes on model edges. if (!int_unordered_set_contains(model_edge_nodes, node)) { // Traverse the model faces attached to this node and hook up their // corresponding dual vertices to a new dual face. int_unordered_set_t* boundary_faces_for_node = primal_boundary_faces_for_node[node]; ASSERT(boundary_faces_for_node != NULL); int num_dual_nodes = boundary_faces_for_node->size; point_t dual_nodes[num_dual_nodes]; int pos1 = 0, bface, i = 0; while (int_unordered_set_next(boundary_faces_for_node, &pos1, &bface)) { // Retrieve the dual node index for this boundary face. int* dual_node_p = int_int_unordered_map_get(dual_node_for_model_face, bface); ASSERT(dual_node_p != NULL); dual_nodes[i] = dual_mesh->nodes[*dual_node_p]; ++i; } // Order the dual nodes by constructing a polygonal face. polygon_t* dual_polygon = polygon_giftwrap(dual_nodes, num_dual_nodes); int_array_t* face_nodes = int_array_new(); int_array_resize(face_nodes, num_dual_nodes); memcpy(face_nodes->data, polygon_ordering(dual_polygon), sizeof(int)*num_dual_nodes); nodes_for_dual_face[df_offset] = face_nodes; dual_polygon = NULL; ++df_offset; } } // Add dual faces for primal nodes attached to model edges. // This can be gross, since some edges may be non-manifold. int edge; pos = 0; while (int_unordered_set_next(model_edges, &pos, &edge)) { // Traverse the boundary faces attached to this edge. int_unordered_set_t* faces_for_edge = primal_faces_for_edge[edge]; int pos1 = 0, face; while (int_unordered_set_next(faces_for_edge, &pos1, &face)) { if (int_unordered_set_contains(external_model_faces, face) || int_unordered_set_contains(internal_model_faces, face)) { // FIXME } } } // Add dual faces for primal nodes which are model vertices. pos = 0; while (int_unordered_set_next(model_vertices, &pos, &node)) { // Traverse the boundary faces attached to this node. int_unordered_set_t* boundary_faces_for_node = primal_boundary_faces_for_node[node]; int pos1 = 0, face; while (int_unordered_set_next(boundary_faces_for_node, &pos1, &face)) { // FIXME } } } // Create dual cells. int dc_offset = 0; int_array_t** faces_for_dual_cell = polymec_malloc(sizeof(int_array_t*) * num_dual_cells); memset(faces_for_dual_cell, 0, sizeof(int_array_t*) * num_dual_cells); // FIXME ASSERT(dc_offset == num_dual_cells); // Allocate mesh connectivity storage and move all the data into place. mesh_reserve_connectivity_storage(dual_mesh); for (int c = 0; c < num_dual_cells; ++c) { int_array_t* cell_faces = faces_for_dual_cell[c]; memcpy(&dual_mesh->cell_faces[dual_mesh->cell_face_offsets[c]], cell_faces->data, sizeof(int)*cell_faces->size); for (int f = 0; f < cell_faces->size; ++f) { int face = cell_faces->data[f]; if (dual_mesh->face_cells[2*face] == -1) dual_mesh->face_cells[2*face] = c; else dual_mesh->face_cells[2*face+1] = c; } } for (int f = 0; f < num_dual_faces; ++f) { int_array_t* face_nodes = nodes_for_dual_face[f]; memcpy(&dual_mesh->face_nodes[dual_mesh->face_node_offsets[f]], face_nodes->data, sizeof(int)*face_nodes->size); } // Clean up. for (int c = 0; c < num_dual_cells; ++c) int_array_free(faces_for_dual_cell[c]); polymec_free(faces_for_dual_cell); for (int f = 0; f < num_dual_faces; ++f) int_array_free(nodes_for_dual_face[f]); polymec_free(nodes_for_dual_face); for (int e = 0; e < tet_mesh->num_edges; ++e) { int_unordered_set_free(primal_cells_for_edge[e]); int_unordered_set_free(primal_faces_for_edge[e]); } polymec_free(primal_cells_for_edge); polymec_free(primal_faces_for_edge); for (int n = 0; n < tet_mesh->num_nodes; ++n) { if (primal_boundary_faces_for_node[n] != NULL) int_unordered_set_free(primal_boundary_faces_for_node[n]); } polymec_free(primal_boundary_faces_for_node); int_int_unordered_map_free(dual_node_for_edge); int_int_unordered_map_free(dual_node_for_model_face); int_unordered_set_free(model_vertices); int_unordered_set_free(model_edges); int_unordered_set_free(model_edge_nodes); int_unordered_set_free(external_boundary_tets); int_unordered_set_free(external_model_faces); int_unordered_set_free(external_model_face_edges); int_unordered_set_free(model_face_nodes); int_unordered_set_free(internal_boundary_tets); int_unordered_set_free(internal_model_faces); int_unordered_set_free(internal_model_face_edges); // Compute mesh geometry. mesh_compute_geometry(dual_mesh); return dual_mesh; }
int main(int argc, char *argv[]) { lob_t id, options, json; mesh_t mesh; net_udp4_t udp4; net_tcp4_t tcp4; int port = 0; if(argc==2) { port = atoi(argv[1]); } id = util_fjson("id.json"); if(!id) return -1; mesh = mesh_new(0); mesh_load(mesh,lob_get_json(id,"secrets"),lob_get_json(id,"keys")); mesh_on_discover(mesh,"auto",mesh_add); // auto-link anyone mesh_on_open(mesh,"path",path_on_open); // add path support options = lob_new(); lob_set_int(options,"port",port); udp4 = net_udp4_new(mesh, options); util_sock_timeout(udp4->server,100); tcp4 = net_tcp4_new(mesh, options); json = mesh_json(mesh); printf("%s\n",lob_json(json)); printf("%s\n",mesh_uri(mesh, NULL)); while(net_udp4_receive(udp4) && net_tcp4_loop(tcp4)); /* if(util_loadjson(s) != 0 || (sock = util_server(0,1000)) <= 0) { printf("failed to startup %s or %s\n", strerror(errno), crypt_err()); return -1; } printf("loaded hashname %s\n",s->id->hexname); // create/send a ping packet c = chan_new(s, bucket_get(s->seeds, 0), "link", 0); p = chan_packet(c); chan_send(c, p); util_sendall(s,sock); in = path_new("ipv4"); while(util_readone(s, sock, in) == 0) { switch_loop(s); while((c = switch_pop(s))) { printf("channel active %d %s %s\n",c->ended,c->hexid,c->to->hexname); if(util_cmp(c->type,"connect") == 0) ext_connect(c); if(util_cmp(c->type,"link") == 0) ext_link(c); if(util_cmp(c->type,"path") == 0) ext_path(c); while((p = chan_pop(c))) { printf("unhandled channel packet %.*s\n", p->json_len, p->json); lob_free(p); } } util_sendall(s,sock); } */ perror("exiting"); return 0; }
Mesh * mesh_triangulate_polygon( const Polygon *poly ) { g_return_val_if_fail( poly != NULL, NULL ); g_return_val_if_fail( poly->vertices != NULL, NULL ); g_return_val_if_fail( g_list_length( poly->vertices ) >= 3, NULL ); reflex_vertices = g_hash_table_new( NULL, NULL ); convex_vertices = g_hash_table_new( NULL, NULL ); ears = g_hash_table_new( NULL, NULL ); /* create a new mesh */ Mesh *mesh = mesh_new(); /* add polygon's nodes and edges to the mesh */ add_polygon_to_mesh( mesh, poly ); /* take the first half-edge of the first edge as the starting half-edge */ HalfEdge *he_start = &EDGE(mesh->edges->data)->he[0]; HalfEdge *he_iter = he_start; /* iterate over half-edges lying on the inner side of the boundary */ do { /* classify half-edge's origin according to its convexity */ if ( halfedge_origin_is_convex( he_iter ) ) g_hash_table_insert( convex_vertices, he_iter->origin, he_iter ); else g_hash_table_insert( reflex_vertices, he_iter->origin, he_iter ); he_iter = he_iter->next; } while ( he_iter != he_start ); /* iterate over convex vertices */ GHashTableIter convex_vert_iter; g_hash_table_iter_init( &convex_vert_iter, convex_vertices ); gpointer key, value; while ( g_hash_table_iter_next( &convex_vert_iter, &key, &value ) ) { HalfEdge *conv_he = HALFEDGE(value); /* check if the convex vertex is an ear */ if ( halfedge_origin_is_ear( conv_he ) ) g_hash_table_insert( ears, conv_he->origin, conv_he ); } /* iterate over ears */ GHashTableIter ears_iter; g_hash_table_iter_init( &ears_iter, ears ); while ( g_hash_table_iter_next( &ears_iter, &key, &value) ) { /* since we will cut it off, remove the ear from ears and convex vertex * hash table */ g_hash_table_remove( ears, key ); g_hash_table_remove( convex_vertices, key ); HalfEdge *he2 = HALFEDGE(value); HalfEdge *he1 = he2->previous; Node *n1 = he1->origin; Node *n3 = he2->pair->origin; /* cut off the ear: */ /* add an edge connecting the ear's neighbours */ Edge *e = mesh_add_edge( mesh, n3, n1 ); HalfEdge *he3 = &e->he[0]; /* add ear's triangle to the mesh */ mesh_add_element( mesh, he1, he2, he3 ); he1 = &e->he[1]; he2 = he1->next; gboolean was_reflex_1 = FALSE; gboolean was_reflex_became_convex_1 = FALSE; gboolean was_reflex_2 = FALSE; gboolean was_reflex_became_convex_2 = FALSE; /* update the status of the ear's neighbours */ /* first, we need to update the reflex status of both neighbours, as * we need up-to-date info about reflex vertices in the "ear-ness" test */ if ( g_hash_table_lookup( reflex_vertices, n1 ) ) { was_reflex_1 = TRUE; /* reflex vertex can become convex */ if ( halfedge_origin_is_convex( he1 ) ) { was_reflex_became_convex_1 = TRUE; /* is now convex, remove from reflex vertices */ g_hash_table_remove( reflex_vertices, n1 ); } } if ( g_hash_table_lookup( reflex_vertices, n3 ) ) { was_reflex_2 = TRUE; if ( halfedge_origin_is_convex( he2 ) ) { was_reflex_became_convex_2 = TRUE; g_hash_table_remove( reflex_vertices, n3 ); } } /* now we can proceed with the other tests */ if ( was_reflex_1 ) { if ( was_reflex_became_convex_1 ) { /* add to convex vertices */ g_hash_table_insert( convex_vertices, n1, he1 ); /* if was reflex and became convex and even an ear, add it to * ears */ if ( halfedge_origin_is_ear( he1 ) ) g_hash_table_insert( ears, n1, he1 ); } else /* if it stayed reflex, just update it with a new half-edge */ g_hash_table_insert( reflex_vertices, n1, he1 ); } else if ( g_hash_table_lookup( ears, n1 ) ) { /* if it was an ear and now is not, remove it from ears (but it * stays convex) */ if ( ! halfedge_origin_is_ear( he1 ) ) g_hash_table_remove( ears, n1 ); else /* if it stayed an ear, just update it with a new half-edge */ g_hash_table_insert( ears, n1, he1 ); } else if ( g_hash_table_lookup( convex_vertices, n1 ) ) { /* if it was convex and now became an ear, insert it into ears */ if ( halfedge_origin_is_ear( he1 ) ) g_hash_table_insert( ears, n1, he1 ); else /* otherwise just update it with a new half-edge */ g_hash_table_insert( convex_vertices, n1, he1 ); } /* the same process with the other neighbour */ if ( was_reflex_2 ) { if ( was_reflex_became_convex_2 ) { g_hash_table_insert( convex_vertices, n3, he2 ); if ( halfedge_origin_is_ear( he2 ) ) g_hash_table_insert( ears, n3, he2 ); } } else if ( g_hash_table_lookup( ears, n3 ) ) { if ( ! halfedge_origin_is_ear( he2 ) ) g_hash_table_remove( ears, n3 ); } else if ( g_hash_table_lookup( convex_vertices, n3 ) ) { if ( halfedge_origin_is_ear( he2 ) ) g_hash_table_insert( ears, n3, he2 ); } /* we changed the ears, so update the iterator */ g_hash_table_iter_init( &ears_iter, ears ); he3 = he2->next; /* check if there are only three edges left */ if ( he3->next == he1 ) { /* if there are, so just add this last element and break out from * the loop */ mesh_add_element( mesh, he1, he2, he3 ); break; } } /* clean up */ g_hash_table_destroy( reflex_vertices ); g_hash_table_destroy( convex_vertices ); g_hash_table_destroy( ears ); /* return the resulting mesh */ return mesh; }
mesh_t* create_pebi_mesh(MPI_Comm comm, point_t* cell_centers, real_t* cell_volumes, int num_cells, int* faces, real_t* face_areas, point_t* face_centers, int num_faces) { // Check input. ASSERT(cell_centers != NULL); ASSERT(cell_volumes != NULL); ASSERT(num_cells > 0); ASSERT(faces != NULL); ASSERT(face_areas != NULL); ASSERT(num_faces >= 0); #ifndef NDEBUG for (int f = 0; f < num_faces; ++f) { ASSERT(faces[2*f] >= 0); ASSERT((faces[2*f+1] >= 0) || (faces[2*f+1] == -1)); } #endif mesh_t* mesh = mesh_new(comm, num_cells, 0, num_faces, 0); // Transcribe the mesh cell centers, which are the only connection to // spatial geometry. memcpy(mesh->cell_centers, cell_centers, sizeof(point_t)*num_cells); // Copy over the face-cell connectivity directly. memcpy(mesh->face_cells, faces, 2*sizeof(int)*num_faces); // Copy over the face areas directly. memcpy(mesh->face_areas, face_areas, sizeof(real_t)*num_faces); // Go through the list of faces and count the faces attached to each cell, // storing the tally in the set of cell face offsets. for (int f = 0; f < num_faces; ++f) { mesh->cell_face_offsets[faces[2*f]] += 1; if (faces[2*f+1] != -1) mesh->cell_face_offsets[faces[2*f]] += 1; } // Convert these face offsets to compressed row storage format. for (int c = 1; c <= num_cells; ++c) mesh->cell_face_offsets[c] += mesh->cell_face_offsets[c-1]; // Now fill the mesh's cell_faces array. int* cell_face_count = polymec_malloc(sizeof(int) * num_cells); memset(cell_face_count, 0, sizeof(int) * num_cells); mesh->cell_faces = polymec_realloc(mesh->cell_faces, sizeof(int) * mesh->cell_face_offsets[num_cells]); for (int f = 0; f < num_faces; ++f) { int c1 = faces[2*f]; mesh->cell_faces[mesh->cell_face_offsets[c1] + cell_face_count[c1]] = f; ++cell_face_count[c1]; int c2 = faces[2*f+1]; if (c2 != -1) { mesh->cell_faces[mesh->cell_face_offsets[c2] + cell_face_count[c2]] = f; ++cell_face_count[c2]; } } polymec_free(cell_face_count); // Set the cell volumes. memcpy(mesh->cell_volumes, cell_volumes, sizeof(real_t)*num_cells); // Set or compute face centers. // We compute information for interior faces first. for (int f = 0; f < num_faces; ++f) { point_t* xf = &mesh->face_centers[f]; vector_t* nf = &mesh->face_normals[f]; int c1 = mesh->face_cells[2*f]; int c2 = mesh->face_cells[2*f]; if (c2 != -1) // Interior face { point_t* xc1 = &mesh->cell_centers[c1]; point_t* xc2 = &mesh->cell_centers[c2]; if (face_centers == NULL) { // Assume each face center lies at the midpoint between its cells. xf->x = 0.5 * (xc1->x + xc2->x); xf->y = 0.5 * (xc1->y + xc2->y); xf->z = 0.5 * (xc1->z + xc2->z); } else { xf->x = face_centers[f].x; xf->y = face_centers[f].y; xf->z = face_centers[f].z; } // The face normal should connect xc1 and xc2. point_displacement(xc1, xc2, nf); vector_normalize(nf); } // Now use the existing information to compute information for // boundary faces. for (int f = 0; f < num_faces; ++f) { int c1 = mesh->face_cells[2*f]; int c2 = mesh->face_cells[2*f]; if (c2 == -1) { // Estimate the cell-face distance by assuming an isotropic cell. real_t V = mesh->cell_volumes[c1]; real_t d = pow(V, 1.0/3.0); // Form the normal vector for the face by assuming that all face // normals sum to zero. vector_t* nf = &mesh->face_normals[f]; nf->x = nf->y = nf->z = 0.0; for (int ff = mesh->cell_face_offsets[c1]; ff < mesh->cell_face_offsets[c1+1]; ++ff) { vector_t* nff = &mesh->face_normals[ff]; nf->x -= nff->x; nf->y -= nff->y; nf->z -= nff->z; } // Compute the face center. if (face_centers == NULL) { point_t* xc = &mesh->cell_centers[c1]; point_t* xf = &mesh->face_centers[f]; xf->x = xc->x + d*nf->x; xf->y = xc->y + d*nf->y; xf->z = xc->z + d*nf->z; } else { xf->x = face_centers[f].x; xf->y = face_centers[f].y; xf->z = face_centers[f].z; } } } } mesh_add_feature(mesh, PEBI); return mesh; }
mesh_t* mesh_from_fe_mesh(fe_mesh_t* fe_mesh) { // Feel out the faces for the finite element mesh. Do we need to create // them ourselves, or are they already all there? int num_cells = fe_mesh_num_elements(fe_mesh); int num_faces = fe_mesh_num_faces(fe_mesh); int* cell_face_offsets = polymec_malloc(sizeof(int) * (num_cells + 1)); cell_face_offsets[0] = 0; int* cell_faces = NULL; int* face_node_offsets = NULL; int* face_nodes = NULL; if (num_faces == 0) { // Traverse the element blocks and figure out the number of faces per cell. int pos = 0, elem_offset = 0; char* block_name; fe_block_t* block; while (fe_mesh_next_block(fe_mesh, &pos, &block_name, &block)) { int num_block_elem = fe_block_num_elements(block); fe_mesh_element_t elem_type = fe_block_element_type(block); int num_elem_faces = get_num_cell_faces(elem_type); for (int i = 0; i < num_block_elem; ++i) cell_face_offsets[elem_offset+i+1] = cell_face_offsets[elem_offset+i] + num_elem_faces; elem_offset += num_block_elem; } // Now assemble the faces for each cell. int_tuple_int_unordered_map_t* node_face_map = int_tuple_int_unordered_map_new(); cell_faces = polymec_malloc(sizeof(int) * cell_face_offsets[num_cells]); // We build the face->node connectivity data on-the-fly. int_array_t* face_node_offsets_array = int_array_new(); int_array_append(face_node_offsets_array, 0); int_array_t* face_nodes_array = int_array_new(); pos = 0, elem_offset = 0; while (fe_mesh_next_block(fe_mesh, &pos, &block_name, &block)) { int num_block_elem = fe_block_num_elements(block); fe_mesh_element_t elem_type = fe_block_element_type(block); int num_elem_nodes = fe_block_num_element_nodes(block, 0); int elem_nodes[num_elem_nodes]; for (int i = 0; i < num_block_elem; ++i) { fe_block_get_element_nodes(block, i, elem_nodes); int offset = cell_face_offsets[elem_offset+i]; get_cell_faces(elem_type, elem_nodes, node_face_map, &cell_faces[offset], face_node_offsets_array, face_nodes_array); } elem_offset += num_block_elem; } // Record the total number of faces and discard the map. num_faces = node_face_map->size; int_tuple_int_unordered_map_free(node_face_map); // Gift the contents of the arrays to our pointers. face_node_offsets = face_node_offsets_array->data; int_array_release_data_and_free(face_node_offsets_array); face_nodes = face_nodes_array->data; int_array_release_data_and_free(face_nodes_array); } else { // Fill in these arrays block by block. int pos = 0; char* block_name; fe_block_t* block; int block_cell_offset = 0; while (fe_mesh_next_block(fe_mesh, &pos, &block_name, &block)) { int num_block_elem = fe_block_num_elements(block); for (int i = 0; i < num_block_elem; ++i) cell_face_offsets[block_cell_offset+i] = cell_face_offsets[block_cell_offset+i-1] + block->elem_face_offsets[i]; block_cell_offset += num_block_elem; } cell_faces = polymec_malloc(sizeof(int) * cell_face_offsets[num_cells]); pos = 0, block_cell_offset = 0; while (fe_mesh_next_block(fe_mesh, &pos, &block_name, &block)) { int num_block_elem = fe_block_num_elements(block); memcpy(&cell_faces[cell_face_offsets[block_cell_offset]], block->elem_faces, sizeof(int) * block->elem_face_offsets[num_block_elem]); block_cell_offset += num_block_elem; } // We just borrow these from the mesh. Theeenks! face_node_offsets = fe_mesh->face_node_offsets; face_nodes = fe_mesh->face_nodes; } ASSERT(cell_faces != NULL); ASSERT(face_node_offsets != NULL); ASSERT(face_nodes != NULL); // Create the finite volume mesh and set up its cell->face and face->node // connectivity. int num_ghost_cells = 0; // FIXME! mesh_t* mesh = mesh_new(fe_mesh_comm(fe_mesh), num_cells, num_ghost_cells, num_faces, fe_mesh_num_nodes(fe_mesh)); memcpy(mesh->cell_face_offsets, cell_face_offsets, sizeof(int) * (mesh->num_cells+1)); memcpy(mesh->face_node_offsets, face_node_offsets, sizeof(int) * (mesh->num_faces+1)); mesh_reserve_connectivity_storage(mesh); memcpy(mesh->cell_faces, cell_faces, sizeof(int) * (mesh->cell_face_offsets[mesh->num_cells])); memcpy(mesh->face_nodes, face_nodes, sizeof(int) * (mesh->face_node_offsets[mesh->num_faces])); // Set up face->cell connectivity. for (int c = 0; c < mesh->num_cells; ++c) { for (int f = mesh->cell_face_offsets[c]; f < mesh->cell_face_offsets[c+1]; ++f) { int face = mesh->cell_faces[f]; if (mesh->face_cells[2*face] == -1) mesh->face_cells[2*face] = c; else mesh->face_cells[2*face+1] = c; } } // Set up face->edge connectivity and edge->node connectivity (if provided). if (fe_mesh->face_edges != NULL) { memcpy(mesh->face_edge_offsets, fe_mesh->face_edge_offsets, sizeof(int) * (mesh->num_faces+1)); mesh->face_edges = polymec_malloc(sizeof(int) * fe_mesh->face_edge_offsets[mesh->num_faces]); memcpy(mesh->face_edges, fe_mesh->face_edges, sizeof(int) * fe_mesh->face_edge_offsets[mesh->num_faces]); } else { // Construct edges if we didn't find them. mesh_construct_edges(mesh); } // Copy the node positions into place. memcpy(mesh->nodes, fe_mesh_node_positions(fe_mesh), sizeof(point_t) * mesh->num_nodes); // Calculate geometry. mesh_compute_geometry(mesh); // Sets -> tags. int pos = 0, *set; size_t set_size; char* set_name; while (fe_mesh_next_element_set(fe_mesh, &pos, &set_name, &set, &set_size)) { int* tag = mesh_create_tag(mesh->cell_tags, set_name, set_size); memcpy(tag, set, sizeof(int) * set_size); } pos = 0; while (fe_mesh_next_face_set(fe_mesh, &pos, &set_name, &set, &set_size)) { int* tag = mesh_create_tag(mesh->face_tags, set_name, set_size); memcpy(tag, set, sizeof(int) * set_size); } pos = 0; while (fe_mesh_next_edge_set(fe_mesh, &pos, &set_name, &set, &set_size)) { int* tag = mesh_create_tag(mesh->edge_tags, set_name, set_size); memcpy(tag, set, sizeof(int) * set_size); } pos = 0; while (fe_mesh_next_node_set(fe_mesh, &pos, &set_name, &set, &set_size)) { int* tag = mesh_create_tag(mesh->node_tags, set_name, set_size); memcpy(tag, set, sizeof(int) * set_size); } // Clean up. polymec_free(cell_face_offsets); polymec_free(cell_faces); if (fe_mesh_num_faces(fe_mesh) == 0) { polymec_free(face_node_offsets); polymec_free(face_nodes); } return mesh; }
void test_matrix() { struct MeshConfig *conf; struct MD *x[2], *x0[2]; int i; double c[2]; double z0; FILE *fplot; conf = mesh_new( 2.4e-3, 10e-3, 0, 3e-3, 0.79e-3, 2.2 ); z0 = mom(conf, x0, x, c); printf("C0 = %le F C1 = %le F\n", c[0], c[1]); printf("Z0 = %lf Ohm\n", z0); fplot = fopen("dielectric.plot", "w"); if (fplot) { fprintf(fplot, "#!"PATH_GNUPLOT"\n"); fprintf(fplot, "# top all charges\n"); fprintf(fplot, "plot '-' notitle with impulse, \\\n" "\t'-' notitle with impulse\n"); for (i = conf->index[ID_STRIP0_START]; i < conf->index[ID_STRIP0_END]; ++i) { fprintf(fplot, "%le %le\n", conf->mesh[i].centre, x[1]->buf[i]); } for (i = conf->index[ID_DIELECTRIC0_START]; i < conf->index[ID_DIELECTRIC0_END]; ++i) { fprintf(fplot, "%le %le\n", conf->mesh[i].centre, x[1]->buf[i]); } fprintf(fplot, "e\n"); fprintf(fplot, "# bottom all charges\n"); for (i = conf->index[ID_STRIP1_START]; i < conf->index[ID_STRIP1_END]; ++i) { fprintf(fplot, "%le %le\n", conf->mesh[i].centre, x[1]->buf[i]); } for (i = conf->index[ID_DIELECTRIC1_START]; i < conf->index[ID_DIELECTRIC1_END]; ++i) { fprintf(fplot, "%le %le\n", conf->mesh[i].centre, x[1]->buf[i]); } fprintf(fplot, "e\npause -1\n"); /*****/ fprintf(fplot, "# top free charges\n"); fprintf(fplot, "plot '-' notitle with impulse, \\\n" "\t'-' notitle with impulse\n"); for (i = conf->index[ID_STRIP0_START]; i < conf->index[ID_STRIP0_END]; ++i) { fprintf(fplot, "%le %le\n", conf->mesh[i].centre, x[0]->buf[i]); } for (i = conf->index[ID_DIELECTRIC0_START]; i < conf->index[ID_DIELECTRIC0_END]; ++i) { fprintf(fplot, "%le %le\n", conf->mesh[i].centre, x[0]->buf[i]); } fprintf(fplot, "e\n"); fprintf(fplot, "# bottom free charges\n"); for (i = conf->index[ID_STRIP1_START]; i < conf->index[ID_STRIP1_END]; ++i) { fprintf(fplot, "%le %le\n", conf->mesh[i].centre, x[0]->buf[i]); } for (i = conf->index[ID_DIELECTRIC1_START]; i < conf->index[ID_DIELECTRIC1_END]; ++i) { fprintf(fplot, "%le %le\n", conf->mesh[i].centre, x[0]->buf[i]); } fprintf(fplot, "e\npause -1\n"); fclose(fplot); } fplot = fopen("freespace.plot", "w"); if (fplot) { fprintf(fplot, "#!"PATH_GNUPLOT"\n"); fprintf(fplot, "# top free charges\n"); fprintf(fplot, "plot '-' notitle with impulse, \\\n" "\t'-' notitle with impulse\n"); for (i = conf->index[ID_STRIP0_START]; i < conf->index[ID_STRIP0_END]; ++i) { fprintf(fplot, "%le %le\n", conf->mesh[i].centre, x[1]->buf[i]); } fprintf(fplot, "e\n"); fprintf(fplot, "# bottom free charges\n"); for (i = conf->index[ID_STRIP1_START]; i < conf->index[ID_STRIP1_END]; ++i) { fprintf(fplot, "%le %le\n", conf->mesh[i].centre, x[1]->buf[i]); } fprintf(fplot, "e\npause -1\n"); fclose(fplot); } md_free(x[0]); md_free(x[1]); mesh_free(conf); }
// resolves collisions between bodies, returning new body count int collide(int n, body bodies[]) { // initialize disjoint set and bodies to include set* bsets[n]; int include[n]; for (int i = 0; i < n; i++) { bsets[i] = make_set(i); include[i] = 1; } // find largest object double maxrad = RADIUS(bodies[0].m); for (int i = 0; i < n; i++) { double rad = RADIUS(bodies[i].m); if (rad > maxrad) maxrad = rad; } // form mesh for collision detection mesh* m = mesh_new(maxrad * 2); for (int i = 0; i < n; i++) mesh_put(m, bodies[i].pos, i); // find collisions for (int i = 0; i < n; i++) { vector ipos = bodies[i].pos; double irad = RADIUS(bodies[i].m); // which bodies are in contact with this one? // look up position in mesh body_list* next = mesh_get(m, ipos, 1); for (body_list* cur = next; cur; cur = next) { // get candidate collider int j = cur->index; vector jpos = bodies[j].pos; double jrad = RADIUS(bodies[j].m); // merge sets of colliding objects if (dist(ipos, jpos) < (irad + jrad) * (irad + jrad)) merge(bsets[i], bsets[j]); // traverse and free next = cur->next; free(cur); } } // free the mesh mesh_free(m); // merge objects for (int i = 0; i < n; i++) { int rootidx = get_value(find(bsets[i])); if (rootidx != i) { include[i] = 0; bodies[rootidx] = body_merge(bodies[rootidx], bodies[i]); } } // free sets for (int i = 0; i < n; i++) free(bsets[i]); // copy down int j = 0; for (int i = 0; i < n; i++) { if (include[i]) bodies[j++] = bodies[i]; } return j; }
mesh_t* crop_mesh(mesh_t* mesh, sp_func_t* boundary_func, mesh_crop_t crop_type) { // Mark the cells whose centers fall outside the boundary. int_unordered_set_t* outside_cells = int_unordered_set_new(); for (int cell = 0; cell < mesh->num_cells; ++cell) { real_t dist; sp_func_eval(boundary_func, &mesh->cell_centers[cell], &dist); if (dist > 0.0) int_unordered_set_insert(outside_cells, cell); } // Count up the remaining faces and nodes, and make a list of boundary faces. int_unordered_set_t* remaining_ghosts = int_unordered_set_new(); int_unordered_set_t* boundary_faces = int_unordered_set_new(); int_int_unordered_map_t* remaining_nodes = int_int_unordered_map_new(); int_int_unordered_map_t* remaining_faces = int_int_unordered_map_new(); int new_face_index = 0, new_node_index = 0; for (int cell = 0; cell < mesh->num_cells; ++cell) { if (int_unordered_set_contains(outside_cells, cell)) continue; int pos = 0, face; while (mesh_cell_next_face(mesh, cell, &pos, &face)) { // This face is still in the mesh. if (!int_int_unordered_map_contains(remaining_faces, face)) int_int_unordered_map_insert(remaining_faces, face, new_face_index++); // A boundary face is a face with only one cell attached to it. int opp_cell = mesh_face_opp_cell(mesh, face, cell); if ((opp_cell == -1) || int_unordered_set_contains(outside_cells, opp_cell)) int_unordered_set_insert(boundary_faces, face); else if (opp_cell >= mesh->num_cells) int_unordered_set_insert(remaining_ghosts, opp_cell); int pos1 = 0, node; while (mesh_face_next_node(mesh, face, &pos1, &node)) { if (!int_int_unordered_map_contains(remaining_nodes, node)) int_int_unordered_map_insert(remaining_nodes, node, new_node_index++); } } } // Convert the face and node maps to arrays. int* face_map = polymec_malloc(sizeof(int) * mesh->num_faces); for (int i = 0; i < mesh->num_faces; ++i) face_map[i] = -1; { int pos = 0, old_face, new_face; while (int_int_unordered_map_next(remaining_faces, &pos, &old_face, &new_face)) face_map[old_face] = new_face; } int* node_map = polymec_malloc(sizeof(int) * mesh->num_nodes); for (int i = 0; i < mesh->num_nodes; ++i) node_map[i] = -1; { int pos = 0, old_node, new_node; while (int_int_unordered_map_next(remaining_nodes, &pos, &old_node, &new_node)) node_map[old_node] = new_node; } // Do a partial clean up. int num_new_faces = remaining_faces->size; int num_new_nodes = remaining_nodes->size; int num_new_ghosts = remaining_ghosts->size; int_int_unordered_map_free(remaining_nodes); int_int_unordered_map_free(remaining_faces); int_unordered_set_free(remaining_ghosts); // Make a new mesh. mesh_t* cropped_mesh = mesh_new(mesh->comm, mesh->num_cells - outside_cells->size, num_new_ghosts, num_new_faces, num_new_nodes); // Reserve storage. int new_cell = 0; cropped_mesh->cell_face_offsets[0] = 0; for (int cell = 0; cell < mesh->num_cells; ++cell) { if (int_unordered_set_contains(outside_cells, cell)) continue; int num_cell_faces = mesh_cell_num_faces(mesh, cell); cropped_mesh->cell_face_offsets[new_cell+1] = cropped_mesh->cell_face_offsets[new_cell] + num_cell_faces; ++new_cell; } cropped_mesh->face_node_offsets[0] = 0; for (int f = 0; f < mesh->num_faces; ++f) { int new_face = face_map[f]; if (new_face != -1) { int num_face_nodes = mesh_face_num_nodes(mesh, f); cropped_mesh->face_node_offsets[new_face+1] = num_face_nodes; } } for (int f = 0; f < cropped_mesh->num_faces; ++f) cropped_mesh->face_node_offsets[f+1] += cropped_mesh->face_node_offsets[f]; mesh_reserve_connectivity_storage(cropped_mesh); // Hook up the faces and cells. new_cell = 0; for (int cell = 0; cell < mesh->num_cells; ++cell) { if (int_unordered_set_contains(outside_cells, cell)) continue; int num_cell_faces = mesh_cell_num_faces(mesh, cell); for (int f = 0; f < num_cell_faces; ++f) { int old_face = mesh->cell_faces[mesh->cell_face_offsets[cell]+f]; int pos_old_face = (old_face >= 0) ? old_face : ~old_face; int new_face = face_map[pos_old_face]; if (cropped_mesh->face_cells[2*new_face] == -1) cropped_mesh->face_cells[2*new_face] = new_cell; else cropped_mesh->face_cells[2*new_face+1] = new_cell; if (old_face < 0) new_face = ~new_face; cropped_mesh->cell_faces[cropped_mesh->cell_face_offsets[new_cell]+f] = new_face; } ++new_cell; } ASSERT(new_cell == cropped_mesh->num_cells); // Hook up faces and nodes. for (int f = 0; f < mesh->num_faces; ++f) { int new_face = face_map[f]; if (new_face != -1) { int num_face_nodes = mesh_face_num_nodes(mesh, f); for (int n = 0; n < num_face_nodes; ++n) { int old_node = mesh->face_nodes[mesh->face_node_offsets[f]+n]; int new_node = node_map[old_node]; cropped_mesh->face_nodes[cropped_mesh->face_node_offsets[new_face]+n] = new_node; } } } // Copy node positions. for (int n = 0; n < mesh->num_nodes; ++n) { if (node_map[n] != -1) cropped_mesh->nodes[node_map[n]] = mesh->nodes[n]; } // Construct edges. mesh_construct_edges(cropped_mesh); // Create the boundary faces tag. int* bf_tag = mesh_create_tag(cropped_mesh->face_tags, sp_func_name(boundary_func), boundary_faces->size); int pos = 0, i = 0, face; while (int_unordered_set_next(boundary_faces, &pos, &face)) bf_tag[i++] = face_map[face]; // Create a new exchanger from the old one. { exchanger_t* old_ex = mesh_exchanger(mesh); exchanger_t* new_ex = mesh_exchanger(cropped_mesh); int pos = 0, remote, *indices, num_indices; while (exchanger_next_send(old_ex, &pos, &remote, &indices, &num_indices)) { int send_indices[num_indices], j = 0; for (int i = 0; i < num_indices; ++i) if (!int_unordered_set_contains(outside_cells, indices[i])) send_indices[j++] = indices[i]; exchanger_set_send(new_ex, remote, send_indices, j, true); } pos = 0; while (exchanger_next_receive(old_ex, &pos, &remote, &indices, &num_indices)) { int recv_indices[num_indices], j = 0; for (int i = 0; i < num_indices; ++i) if (!int_unordered_set_contains(outside_cells, indices[i])) recv_indices[j++] = indices[i]; exchanger_set_receive(new_ex, remote, recv_indices, j, true); } } // Clean up. polymec_free(node_map); polymec_free(face_map); int_unordered_set_free(boundary_faces); int_unordered_set_free(outside_cells); // Now it remains just to project node positions. if (crop_type == PROJECT_NODES) project_nodes(cropped_mesh, boundary_func); else if (crop_type == PROJECT_FACES) project_faces(cropped_mesh, boundary_func); // Finally, compute the mesh geometry. mesh_compute_geometry(cropped_mesh); return cropped_mesh; }