gb_mesh_edge_ref_t gb_tessellator_mesh_make_edge(gb_tessellator_impl_t* impl, gb_point_ref_t org, gb_point_ref_t dst) { // check tb_assert(impl && impl->mesh); // make edge gb_mesh_edge_ref_t edge = gb_mesh_edge_make(impl->mesh); tb_assert_and_check_return_val(edge, tb_null); // init edge.winding gb_tessellator_edge_winding_set(edge, 0); gb_tessellator_edge_winding_set(gb_mesh_edge_sym(edge), 0); // init edge.region gb_tessellator_edge_region_set(edge, tb_null); gb_tessellator_edge_region_set(gb_mesh_edge_sym(edge), tb_null); // init edge.faces.inside, lface == rface gb_tessellator_face_inside_set(gb_mesh_edge_lface(edge), 0); // init edge.org if (org) gb_tessellator_vertex_point_set(gb_mesh_edge_org(edge), org); // init edge.dst if (dst) gb_tessellator_vertex_point_set(gb_mesh_edge_dst(edge), dst); // ok return edge; }
static tb_void_t gb_demo_utils_mesh_split() { // trace tb_trace_i("=========================================================================="); // init mesh gb_mesh_ref_t mesh = gb_mesh_init(tb_element_str(tb_true), tb_element_str(tb_true), tb_element_str(tb_true)); if (mesh) { // init listener gb_mesh_listener_set(mesh, gb_demo_utils_mesh_listener, mesh); gb_mesh_listener_event_add(mesh, GB_MESH_EVENT_FACE_MERGE | GB_MESH_EVENT_FACE_SPLIT | GB_MESH_EVENT_EDGE_MERGE | GB_MESH_EVENT_EDGE_SPLIT); // make a clockwise self-loop edge gb_mesh_edge_ref_t edge0 = gb_mesh_edge_make_loop(mesh, tb_false); if (edge0) { /* make a quadrangle * * e1 * v0 --------------> v1 * | | * e0 | rface | e2 lface * | | * v3 <-------------- v2 * e3 * */ gb_mesh_edge_ref_t edge1 = gb_mesh_edge_insert(mesh, edge0, edge0); gb_mesh_edge_ref_t edge2 = gb_mesh_edge_insert(mesh, edge1, edge0); gb_mesh_edge_ref_t edge3 = gb_mesh_edge_insert(mesh, edge2, edge0); // save face name gb_mesh_face_data_set(mesh, gb_mesh_edge_lface(edge0), "lface"); gb_mesh_face_data_set(mesh, gb_mesh_edge_rface(edge0), "rface"); // save edge name gb_mesh_edge_data_set(mesh, edge0, "e0"); gb_mesh_edge_data_set(mesh, edge1, "e1"); gb_mesh_edge_data_set(mesh, edge2, "e2"); gb_mesh_edge_data_set(mesh, edge3, "e3"); // save vertex name gb_mesh_vertex_data_set(mesh, gb_mesh_edge_dst(edge0), "v0"); gb_mesh_vertex_data_set(mesh, gb_mesh_edge_dst(edge1), "v1"); gb_mesh_vertex_data_set(mesh, gb_mesh_edge_dst(edge2), "v2"); gb_mesh_vertex_data_set(mesh, gb_mesh_edge_dst(edge3), "v3"); #ifdef __gb_debug__ // trace tb_trace_i(""); tb_trace_i("split: make"); // check mesh gb_mesh_check(mesh); // dump mesh gb_mesh_dump(mesh); #endif /* split a quadrangle * * e1 e4 * v0 ------ v4 -----> v1 * | | * e0 | rface | e2 lface * | | * v3 <----- v5 <---- v2 * e5 e3 * */ gb_mesh_edge_ref_t edge4 = gb_mesh_edge_split(mesh, edge1); gb_mesh_edge_ref_t edge5 = gb_mesh_edge_split(mesh, edge3); // save edge name gb_mesh_edge_data_set(mesh, edge4, "e4"); gb_mesh_edge_data_set(mesh, edge5, "e5"); // save vertex name gb_mesh_vertex_data_set(mesh, gb_mesh_edge_org(edge4), "v4"); gb_mesh_vertex_data_set(mesh, gb_mesh_edge_org(edge5), "v5"); #ifdef __gb_debug__ // trace tb_trace_i(""); tb_trace_i("split: done"); // check mesh gb_mesh_check(mesh); // dump mesh gb_mesh_dump(mesh); #endif } // exit mesh gb_mesh_exit(mesh); } }
static tb_void_t gb_demo_utils_mesh_splice() { // trace tb_trace_i("=========================================================================="); // init mesh gb_mesh_ref_t mesh = gb_mesh_init(tb_element_str(tb_true), tb_element_str(tb_true), tb_element_str(tb_true)); if (mesh) { // init listener gb_mesh_listener_set(mesh, gb_demo_utils_mesh_listener, mesh); gb_mesh_listener_event_add(mesh, GB_MESH_EVENT_FACE_MERGE | GB_MESH_EVENT_FACE_SPLIT | GB_MESH_EVENT_EDGE_MERGE | GB_MESH_EVENT_EDGE_SPLIT); /* make a edge * * lface * * O -----> D * * lface */ gb_mesh_edge_ref_t edge = gb_mesh_edge_make(mesh); if (edge) { // save face name gb_mesh_face_data_set(mesh, gb_mesh_edge_lface(edge), "lface"); // save vertex name gb_mesh_vertex_data_set(mesh, gb_mesh_edge_org(edge), "org"); gb_mesh_vertex_data_set(mesh, gb_mesh_edge_dst(edge), "dst"); #ifdef __gb_debug__ // trace tb_trace_i(""); tb_trace_i("splice: make"); // check mesh gb_mesh_check(mesh); // dump mesh gb_mesh_dump(mesh); #endif /* splice * * ------- * | | * | rface | * | | * O/D <--- * * lface * */ gb_mesh_edge_splice(mesh, edge, gb_mesh_edge_sym(edge)); #ifdef __gb_debug__ // trace tb_trace_i(""); tb_trace_i("splice: done"); // check mesh gb_mesh_check(mesh); // dump mesh gb_mesh_dump(mesh); #endif /* splice * * lface * * O -----> D * * lface * */ gb_mesh_edge_splice(mesh, edge, gb_mesh_edge_sym(edge)); #ifdef __gb_debug__ // trace tb_trace_i(""); tb_trace_i("splice: done"); // check mesh gb_mesh_check(mesh); // dump mesh gb_mesh_dump(mesh); #endif } // exit mesh gb_mesh_exit(mesh); } }
static tb_void_t gb_demo_utils_mesh_radiation() { // trace tb_trace_i("=========================================================================="); // init mesh gb_mesh_ref_t mesh = gb_mesh_init(tb_element_str(tb_true), tb_element_str(tb_true), tb_element_str(tb_true)); if (mesh) { // init listener gb_mesh_listener_set(mesh, gb_demo_utils_mesh_listener, mesh); gb_mesh_listener_event_add(mesh, GB_MESH_EVENT_FACE_MERGE | GB_MESH_EVENT_FACE_SPLIT | GB_MESH_EVENT_EDGE_MERGE | GB_MESH_EVENT_EDGE_SPLIT); // make a edge gb_mesh_edge_ref_t edge1 = gb_mesh_edge_make(mesh); if (edge1) { // the face gb_mesh_face_ref_t face = gb_mesh_edge_lface(edge1); tb_assert_abort(face == gb_mesh_edge_rface(edge1)); // save face name gb_mesh_face_data_set(mesh, face, "face"); /* make a radiation * * v4 * / \ * | * | * | e4 * | * | * | * <---------------- v0 ----------------> * v1 e1 | e3 v3 * | * | * | e2 * | * | * \ / * v2 */ gb_mesh_edge_ref_t edge2 = gb_mesh_edge_append(mesh, gb_mesh_edge_sym(edge1)); gb_mesh_edge_ref_t edge3 = gb_mesh_edge_append(mesh, gb_mesh_edge_sym(edge1)); gb_mesh_edge_ref_t edge4 = gb_mesh_edge_append(mesh, gb_mesh_edge_sym(edge1)); // save edge name gb_mesh_edge_data_set(mesh, edge1, "e1"); gb_mesh_edge_data_set(mesh, edge2, "e2"); gb_mesh_edge_data_set(mesh, edge3, "e3"); gb_mesh_edge_data_set(mesh, edge4, "e4"); // save vertex name gb_mesh_vertex_data_set(mesh, gb_mesh_edge_org(edge1), "v0"); gb_mesh_vertex_data_set(mesh, gb_mesh_edge_dst(edge1), "v1"); gb_mesh_vertex_data_set(mesh, gb_mesh_edge_dst(edge2), "v2"); gb_mesh_vertex_data_set(mesh, gb_mesh_edge_dst(edge3), "v3"); gb_mesh_vertex_data_set(mesh, gb_mesh_edge_dst(edge4), "v4"); #ifdef __gb_debug__ // trace tb_trace_i(""); tb_trace_i("radiation: make"); // check mesh gb_mesh_check(mesh); // dump mesh gb_mesh_dump(mesh); #endif /* remove one * * v4 * / \ * | * | * | e4 * | * | * | * v0 ----------------> * | e3 v3 * | * | * | e2 * | * | * \ / * v2 */ gb_mesh_edge_remove(mesh, edge1); #ifdef __gb_debug__ // trace tb_trace_i(""); tb_trace_i("radiation: kill"); // check mesh gb_mesh_check(mesh); // dump mesh gb_mesh_dump(mesh); #endif // remove all gb_mesh_edge_remove(mesh, edge2); gb_mesh_edge_remove(mesh, edge3); gb_mesh_edge_remove(mesh, edge4); // check tb_assert_abort(gb_mesh_is_empty(mesh)); } // exit mesh gb_mesh_exit(mesh); } }
/* make triangulation region * * TODO need optimization, maybe generate some degenerated triangles * * the region of this face must be horizontal monotone and counter-clockwise loop * * before: * * ccw * <------------ * | | * * 1 * . . right * left . 2 * . . * . . * 3 4 * . . * . . * 5 . * . . * . . * . . * 6 . * . . * . 7 * . . * 8 . * . 9 * . . * 10 11 * . . * . . * 12 * * | | * | | * \ / \ / * * * after: * 1 * . . R2 * L1 . . 2 * . .L4 . * . . . R3 * 3 . . R6 4 * . . . * L5 . .L8 . * 5 . * . . . R7 * L9 . R11 . * . . . * 6 . R12 . * . . . . * L10 . . 7 * . L14 . . * 8 . . R13 * . R16 . 9 * L15 . . * 10 L18 . 11 * . . * L19 . . R17 * 12 * */ static tb_void_t gb_tessellator_triangulation_make_face(gb_tessellator_impl_t* impl, gb_mesh_face_ref_t face) { // check tb_assert_abort(impl && face); // the mesh gb_mesh_ref_t mesh = impl->mesh; tb_assert_abort(mesh); // the face edge gb_mesh_edge_ref_t edge = gb_mesh_face_edge(face); // must be triangle region at least tb_assert_abort(edge && gb_mesh_edge_lnext(edge) != edge && gb_mesh_edge_lnext(gb_mesh_edge_lnext(edge)) != edge); /* get the uppermost left edge * * @note the face edge has been optimizated when we made monotone polygon. * * . * left . . right * . . * . . * . . * . . */ gb_mesh_edge_ref_t left = edge; while (gb_tessellator_edge_go_down_(left)) left = gb_mesh_edge_lprev(left); while (gb_tessellator_edge_go_up_(left)) left = gb_mesh_edge_lnext(left); // get the uppermost right edge gb_mesh_edge_ref_t right = gb_mesh_edge_lprev(left); // done while (gb_mesh_edge_lnext(left) != right) { /* the right edge is too lower? done some left edges * * . * left . . right * dst . . * . . org * . . * . . */ if (gb_tessellator_vertex_in_top_or_horizontal_(gb_mesh_edge_dst(left), gb_mesh_edge_org(right))) { /* done some left edges * * go up? connect it * * . * . . * . . * . . * L . L1 . . * . . . * . . . * . . . . . . . * L2 . * . R * . * * * on left? connect it * * TODO: will generate some degenerated triangles * * . * . . * on left?. . . * . . * . . . * . . * L . . . R * .. . * . . * . . * . . * . * . */ while ( gb_mesh_edge_lnext(right) != left && ( gb_tessellator_edge_go_up_(gb_mesh_edge_lprev(left)) || gb_tessellator_vertex_on_edge_or_left_( gb_mesh_edge_org(left) , gb_mesh_edge_org(gb_mesh_edge_lprev(left)) , gb_mesh_edge_dst(left)))) { // connect it edge = gb_mesh_edge_connect(mesh, left, gb_mesh_edge_lprev(left)); tb_assert_abort_and_check_return(edge); // update the left edge left = gb_mesh_edge_sym(edge); } // the next left edge left = gb_mesh_edge_lnext(left); } /* the left edge is too lower? done some right edges * * . * left . . right * . . org * dst . . * . . * . . */ else { /* done some right edges * * go down? connect it * * . * . . * . . * . . R * . . R1 . * . . . * . R2 . . * . . . . . . . . . * . * L . * . * * on right? connect it * * TODO: will generate some degenerated triangles * * . * . . * . . . * . . . * . . . on right? * . . . * L . . . R * . . . * . . * . . * . . * . * . */ while ( gb_mesh_edge_lnext(right) != left && ( gb_tessellator_edge_go_down_(gb_mesh_edge_lnext(right)) || gb_tessellator_vertex_on_edge_or_right_(gb_mesh_edge_dst(right) , gb_mesh_edge_dst(gb_mesh_edge_lnext(right)) , gb_mesh_edge_org(right)))) { // connect it edge = gb_mesh_edge_connect(mesh, gb_mesh_edge_lnext(right), right); tb_assert_abort_and_check_return(edge); // update the right edge right = gb_mesh_edge_sym(edge); } // the next right edge right = gb_mesh_edge_lprev(right); } } // the last region must be triangle at least tb_assert_abort(gb_mesh_edge_lnext(right) != left); /* tessellate the remaining region * * . . . . * . . * . . * . . * left . . right * . * */ while (gb_mesh_edge_lnext(gb_mesh_edge_lnext(right)) != left) { // connect it edge = gb_mesh_edge_connect(mesh, gb_mesh_edge_lnext(right), right); tb_assert_abort_and_check_return(edge); // the next edge right = gb_mesh_edge_sym(edge); } }