/** * 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_edge_free (P2trEdge *self) { p2tr_edge_remove (self); g_slice_free (P2trEdge, self); g_slice_free (P2trEdge, self->mirror); }
/** * Try to flip a given edge. If successfull, return the new edge on * @ref new_edge, append the new triangles to @ref new_tris and return * TRUE. * THE NEW TRIANGLES MUST BE UNREFFED! * THE NEW EDGE MUST BE UNREFFED! */ static gboolean p2tr_cdt_try_flip (P2trCDT *self, P2trEdge *to_flip, GQueue *new_tris, P2trEdge **new_edge) { /* C * / | \ * B-----A to_flip: A->B * \ | / to_flip.Tri: ABC * D */ P2trPoint *A, *B, *C, *D; P2trTriangle *ABC, *ADB; P2trEdge *DC; new_edge = NULL; if (to_flip->constrained || to_flip->delaunay) { return FALSE; } A = P2TR_EDGE_START (to_flip); B = to_flip->end; C = p2tr_triangle_get_opposite_point (to_flip->tri, to_flip); D = p2tr_triangle_get_opposite_point (to_flip->mirror->tri, to_flip->mirror); ABC = to_flip->tri; ADB = to_flip->mirror->tri; /* Check if the quadriliteral ADBC is concave (because if it is, we * can't flip the edge) */ if (p2tr_triangle_get_angle_at(ABC, A) + p2tr_triangle_get_angle_at(ADB, A) >= G_PI) return FALSE; if (p2tr_triangle_get_angle_at(ABC, B) + p2tr_triangle_get_angle_at(ADB, B) >= G_PI) return FALSE; p2tr_edge_remove (to_flip); DC = p2tr_mesh_new_edge (self->mesh, D, C, FALSE); DC->delaunay = DC->mirror->delaunay = TRUE; g_queue_push_tail (new_tris, p2tr_mesh_new_triangle (self->mesh, p2tr_point_get_edge_to (C, A), p2tr_point_get_edge_to (A, D), DC)); g_queue_push_tail (new_tris, p2tr_mesh_new_triangle (self->mesh, p2tr_point_get_edge_to (D, B), p2tr_point_get_edge_to (B, C), DC->mirror)); *new_edge = DC; return TRUE; }
void p2tr_point_remove (P2trPoint *self) { /* We can not iterate over the list of edges while removing the edges, * because the removal action will modify the list. Instead we will * simply look at the first edge untill the list is emptied. */ while (self->outgoing_edges != NULL) p2tr_edge_remove ((P2trEdge*) self->outgoing_edges->data); if (self->mesh != NULL) { p2tr_mesh_on_point_removed (self->mesh, self); p2tr_mesh_unref (self->mesh); self->mesh = NULL; } }
/** * Try to flip a given edge, If successfull, return the new edge (reffed!), * otherwise return NULL */ P2trEdge* p2tr_cdt_try_flip (P2trCDT *self, P2trEdge *to_flip) { /* C * / | \ * B-----A to_flip: A->B * \ | / to_flip.Tri: ABC * D */ P2trPoint *A, *B, *C, *D; P2trEdge *AB, *CA, *AD, *DB, *BC, *DC; g_assert (! to_flip->constrained && ! to_flip->delaunay); A = P2TR_EDGE_START (to_flip); B = to_flip->end; C = p2tr_triangle_get_opposite_point (to_flip->tri, to_flip, FALSE); D = p2tr_triangle_get_opposite_point (to_flip->mirror->tri, to_flip->mirror, FALSE); AB = to_flip; /* Check if the quadriliteral ADBC is concave (because if it is, we * can't flip the edge) */ if (p2tr_triangle_circumcircle_contains_point (AB->tri, &D->c) != P2TR_INCIRCLE_IN) return NULL; CA = p2tr_point_get_edge_to (C, A, FALSE); AD = p2tr_point_get_edge_to (A, D, FALSE); DB = p2tr_point_get_edge_to (D, B, FALSE); BC = p2tr_point_get_edge_to (B, C, FALSE); p2tr_edge_remove (AB); DC = p2tr_mesh_new_edge (self->mesh, D, C, FALSE); p2tr_triangle_unref (p2tr_mesh_new_triangle (self->mesh, CA, AD, DC)); p2tr_triangle_unref (p2tr_mesh_new_triangle (self->mesh, DB, BC, DC->mirror)); return DC; }