/** * Insert a point so that is splits an existing edge. This function * assumes that the point is on the edge itself and between its * end-points. * If the edge being split is constrained, then the function returns a * list containing both parts resulted from the splitting. In that case, * THE RETURNED EDGES MUST BE UNREFERENCED! */ GList* p2tr_cdt_split_edge (P2trCDT *self, P2trEdge *e, P2trPoint *C) { /* W * /|\ * / | \ * / | \ E.Mirror.Tri: YXW * X*---*---*Y E: X->Y * \ |C / E.Tri: XYV * \ | / * \|/ * V */ P2trPoint *X = P2TR_EDGE_START (e), *Y = e->end; P2trPoint *V = (e->tri != NULL) ? p2tr_triangle_get_opposite_point(e->tri, e) : NULL; P2trPoint *W = (e->mirror->tri != NULL) ? p2tr_triangle_get_opposite_point (e->mirror->tri, e->mirror) : NULL; gboolean constrained = e->constrained; P2trEdge *XC, *CY; GList *new_tris = NULL, *fan = NULL, *new_edges = NULL; p2tr_edge_remove (e); XC = p2tr_mesh_new_edge (self->mesh, X, C, constrained); CY = p2tr_mesh_new_edge (self->mesh, C, Y, constrained); fan = p2tr_utils_new_reversed_pointer_list (4, W, X, V, Y); new_tris = p2tr_cdt_triangulate_fan (self, C, fan); g_list_free (fan); /* Now make this a CDT again * The new triangles will be unreffed by the flip_fix function, which * is good since we receive them with an extra reference! */ p2tr_cdt_flip_fix (self, new_tris); g_list_free (new_tris); if (constrained) { /* If this was a subsegment, then both parts of the subsegment * should exist */ if (p2tr_edge_is_removed (XC) || p2tr_edge_is_removed (CY)) p2tr_exception_geometric ("Subsegments gone!"); else { new_edges = g_list_prepend (new_edges, CY); new_edges = g_list_prepend (new_edges, XC); } } else { p2tr_edge_unref (XC); p2tr_edge_unref (CY); } p2tr_cdt_on_new_point (self, C); return new_edges; }
void p2tr_cdt_validate_unused (P2trCDT* self) { P2trEdge *ed; P2trTriangle *tri; P2trHashSetIter iter; p2tr_hash_set_iter_init (&iter, self->mesh->edges); while (p2tr_hash_set_iter_next (&iter, (gpointer*)&ed)) { g_assert (ed->mirror != NULL); g_assert (! p2tr_edge_is_removed (ed)); } p2tr_hash_set_iter_init (&iter, self->mesh->triangles); while (p2tr_hash_set_iter_next (&iter, (gpointer*)&tri)) g_assert (! p2tr_triangle_is_removed (tri)); }
void p2tr_cdt_flip_fix (P2trCDT *self, P2trVEdgeSet *candidates) { P2trEdge *edge; P2trVEdge *vedge; while (p2tr_vedge_set_pop (candidates, &vedge)) { if (! p2tr_vedge_try_get_and_unref (vedge, &edge)) continue; if (! edge->constrained /* TODO: we probably don't need this check... */ && ! p2tr_edge_is_removed (edge)) { /* If the edge is not constrained, then it should be * a part of two triangles */ P2trPoint *A = P2TR_EDGE_START(edge), *B = edge->end; P2trPoint *C1 = p2tr_triangle_get_opposite_point (edge->tri, edge, FALSE); P2trPoint *C2 = p2tr_triangle_get_opposite_point (edge->mirror->tri, edge->mirror, FALSE); P2trEdge *flipped = p2tr_cdt_try_flip (self, edge); if (flipped != NULL) { p2tr_vedge_set_add (candidates, p2tr_point_get_edge_to (A, C1, TRUE)); p2tr_vedge_set_add (candidates, p2tr_point_get_edge_to (A, C2, TRUE)); p2tr_vedge_set_add (candidates, p2tr_point_get_edge_to (B, C1, TRUE)); p2tr_vedge_set_add (candidates, p2tr_point_get_edge_to (B, C2, TRUE)); p2tr_edge_unref (flipped); } } p2tr_edge_unref (edge); } }