P2trEdge* p2tr_point_edge_cw (P2trPoint* self, P2trEdge *e) { GList *node; if (P2TR_EDGE_START(e) != self) p2tr_exception_programmatic ("Not an edge of this point!"); node = g_list_find (self->outgoing_edges, e); if (node == NULL) p2tr_exception_programmatic ("Could not find the CW sibling edge" "because the edge is not present in the outgoing-edges list!"); return (P2trEdge*) g_list_cyclic_prev (self->outgoing_edges, node); }
/* ^ e1 * / * /_ e1.Tri (e2.Mirror.Tri) * / | * *---------> e2 * * Check if the angle marked is a part of the triangulation * domain */ static gboolean p2tr_cluster_cw_tri_between_is_in_domain (P2trEdge *e1, P2trEdge *e2) { if (P2TR_EDGE_START(e1) != P2TR_EDGE_START(e2) || e1->tri != e2->mirror->tri) p2tr_exception_programmatic ("Non clockwise adjacent edges!"); return e1->tri != NULL; }
void _p2tr_point_remove_edge (P2trPoint *self, P2trEdge* e) { GList *node; if (P2TR_EDGE_START(e) != self) p2tr_exception_programmatic ("Could not remove the given outgoing " "edge because doesn't start on this point!"); node = g_list_find (self->outgoing_edges, e); if (node == NULL) p2tr_exception_programmatic ("Could not remove the given outgoing " "edge because it's not present in the outgoing-edges list!"); self->outgoing_edges = g_list_delete_link (self->outgoing_edges, node); p2tr_edge_unref (e); }
P2trEdge* p2tr_point_get_edge_to (P2trPoint *start, P2trPoint *end) { P2trEdge* result = p2tr_point_has_edge_to (start, end); if (result == NULL) p2tr_exception_programmatic ("Tried to get an edge that doesn't exist!"); else return result; }
/** * Return the edge cluster of the specified edge from the specified end * point. THE EDGES IN THE CLUSTER MUST BE UNREFFED! * @param[in] P The point which is shared between all edges of the cluster * @param[in] E The edge whose cluster should be returned * @return The cluster of @ref E from the point @ref P */ P2trCluster* p2tr_cluster_get_for (P2trPoint *P, P2trEdge *E) { P2trCluster *cluster = g_slice_new (P2trCluster); gdouble temp_angle; P2trEdge *current, *next; cluster->min_angle = G_MAXDOUBLE; g_queue_init (&cluster->edges); if (P == E->end) P = P2TR_EDGE_START (E); else if (P != P2TR_EDGE_START (E)) p2tr_exception_programmatic ("Unexpected point for the edge!"); g_queue_push_head (&cluster->edges, E); current = E; next = p2tr_point_edge_cw (P, current); while (next != g_queue_peek_head (&cluster->edges) && (temp_angle = p2tr_edge_angle_between (current->mirror, next)) <= P2TR_CLUSTER_LIMIT_ANGLE && p2tr_cluster_cw_tri_between_is_in_domain (current, next)) { g_queue_push_tail (&cluster->edges, next); p2tr_edge_ref (next); current = next; next = p2tr_point_edge_cw (P, current); cluster->min_angle = MIN (cluster->min_angle, temp_angle); } current = E; next = p2tr_point_edge_ccw(P, current); while (next != g_queue_peek_tail (&cluster->edges) && (temp_angle = p2tr_edge_angle_between (current->mirror, next)) <= P2TR_CLUSTER_LIMIT_ANGLE && p2tr_cluster_cw_tri_between_is_in_domain (next, current)) { g_queue_push_head (&cluster->edges, next); p2tr_edge_ref (next); current = next; next = p2tr_point_edge_ccw (P, current); cluster->min_angle = MIN(cluster->min_angle, temp_angle); } return cluster; }
gdouble p2tr_edge_angle_between(P2trEdge *e1, P2trEdge *e2) { /* A = E1.angle, a = abs (A) * B = E1.angle, b = abs (B) * * W is the angle we wish to find. Note the fact that we want * to find the angle so that the edges go CLOCKWISE around it. * * Case 1: Signs of A and B agree | Case 2: Signs of A and B disagree * and A > 0 | and A > 0 * | * a = A, b = B | a = A, b = -B * ^^ | * E2 // | / * //\ | / * //b| | /a * - - - - * - |W- - - - - - - - | - - - - * - - - - * ^^a'| | ^^ \\b * ||_/ | // W \\ * E1 ||\ | E1 // \_/ \\ E2 * '||a\ | // \\ * - - - - - - | // vv * | * W = A' + B = (180 - A) + B | W = 180 - (a + b) = 180 - (A - B) * W = 180 - A + B | W = 180 - A + B * * By the illustration above, we can see that in general the angle W * can be computed by W = 180 - A + B in every case. The only thing to * note is that the range of the result of the computation is * [180 - 360, 180 + 360] = [-180, +540] so we may need to subtract * 360 to put it back in the range [-180, +180]. */ gdouble result; if (e1->end != P2TR_EDGE_START(e2)) p2tr_exception_programmatic ("The end-point of the first edge isn't" " the end-point of the second edge!"); result = G_PI - e1->angle + e2->angle; if (result > 2 * G_PI) result -= 2 * G_PI; return result; }
/** * Triangulate a polygon by creating edges to a center point. * 1. If there is a NULL point in the polygon, two triangles are not * created (these are the two that would have used it) * 2. THE RETURNED TRIANGLES MUST BE UNREFFED! */ static GList* p2tr_cdt_triangulate_fan (P2trCDT *self, P2trPoint *center, GList *edge_pts) { GList *new_tris = NULL; GList *iter; /* We can not triangulate unless at least two points are given */ if (edge_pts == NULL || edge_pts->next == NULL) { p2tr_exception_programmatic ("Not enough points to triangulate as" " a star!"); } for (iter = edge_pts; iter != NULL; iter = iter->next) { P2trPoint *A = (P2trPoint*) iter->data; P2trPoint *B = (P2trPoint*) g_list_cyclic_next (edge_pts, iter)->data; P2trEdge *AB, *BC, *CA; P2trTriangle *tri; if (A == NULL || B == NULL) continue; AB = p2tr_point_get_edge_to (A, B); BC = p2tr_mesh_new_or_existing_edge (self->mesh, B, center, FALSE); CA = p2tr_mesh_new_or_existing_edge (self->mesh, center, A, FALSE); tri = p2tr_mesh_new_triangle (self->mesh, AB, BC, CA); new_tris = g_list_prepend (new_tris, tri); p2tr_edge_unref (BC); p2tr_edge_unref (CA); } return new_tris; }
/** * Triangulate a polygon by creating edges to a center point. * 1. If there is a NULL point in the polygon, two triangles are not * created (these are the two that would have used it) * 2. THE RETURNED EDGES MUST BE UNREFFED! */ static P2trVEdgeSet* p2tr_cdt_triangulate_fan (P2trCDT *self, P2trPoint *center, GList *edge_pts) { P2trVEdgeSet* fan_edges = p2tr_vedge_set_new (); GList *iter; /* We can not triangulate unless at least two points are given */ if (edge_pts == NULL || edge_pts->next == NULL) { p2tr_exception_programmatic ("Not enough points to triangulate as" " a star!"); } for (iter = edge_pts; iter != NULL; iter = iter->next) { P2trPoint *A = (P2trPoint*) iter->data; P2trPoint *B = (P2trPoint*) g_list_cyclic_next (edge_pts, iter)->data; P2trEdge *AB, *BC, *CA; if (A == NULL || B == NULL) continue; AB = p2tr_point_get_edge_to (A, B, TRUE); BC = p2tr_mesh_new_or_existing_edge (self->mesh, B, center, FALSE); CA = p2tr_mesh_new_or_existing_edge (self->mesh, center, A, FALSE); p2tr_triangle_unref (p2tr_mesh_new_triangle (self->mesh, AB, BC, CA)); p2tr_vedge_set_add (fan_edges, CA); p2tr_vedge_set_add (fan_edges, BC); p2tr_vedge_set_add (fan_edges, AB); } return fan_edges; }