static gdouble edge_swap_cost (GtsEdge * e) { GSList * i; GtsTriangle * t1 = NULL, * t2 = NULL; GtsVertex * v1, * v2, * v3, * v4; GtsEdge * e1, * e2, * e3, * e4; gdouble ab, aa; i = e->triangles; while (i) { if (GTS_IS_FACE (i->data)) { if (!t1) t1 = i->data; else if (!t2) t2 = i->data; else return G_MAXDOUBLE; } i = i->next; } if (!t1 || !t2) return G_MAXDOUBLE; gts_triangle_vertices_edges (t1, e, &v1, &v2, &v3, &e, &e3, &e4); gts_triangle_vertices_edges (t2, e, &v2, &v1, &v4, &e, &e1, &e2); ab = triangles_angle (GTS_POINT (v1), GTS_POINT (v2), GTS_POINT (v3), GTS_POINT (v4)); aa = triangles_angle (GTS_POINT (v3), GTS_POINT (v4), GTS_POINT (v2), GTS_POINT (v1)); return fabs (ab) - fabs (aa); }
/** * gts_edge_swap: * @e: a #GtsEdge. * @s: a #GtsSurface. * * Performs an "edge swap" on the two triangles sharing @e and * belonging to @s. */ void gts_edge_swap (GtsEdge * e, GtsSurface * s) { GtsTriangle * t1 = NULL, * t2 = NULL, * t; GtsFace * f; GSList * i; GtsVertex * v1, * v2, * v3, * v4, * v5, * v6; GtsEdge * e1, * e2, * e3, * e4; GtsSegment * v3v6; g_return_if_fail (e != NULL); g_return_if_fail (s != NULL); i = e->triangles; while (i) { if (GTS_IS_FACE (i->data) && gts_face_has_parent_surface (i->data, s)) { if (!t1) t1 = i->data; else if (!t2) t2 = i->data; else g_return_if_fail (gts_edge_face_number (e, s) == 2); } i = i->next; } g_assert (t1 && t2); gts_triangle_vertices_edges (t1, e, &v1, &v2, &v3, &e, &e1, &e2); gts_triangle_vertices_edges (t2, e, &v4, &v5, &v6, &e, &e3, &e4); g_assert (v2 == v4 && v1 == v5); v3v6 = gts_vertices_are_connected (v3, v6); if (!GTS_IS_EDGE (v3v6)) v3v6 = GTS_SEGMENT (gts_edge_new (s->edge_class, v3, v6)); f = gts_face_new (s->face_class, e1, GTS_EDGE (v3v6), e4); if ((t = gts_triangle_is_duplicate (GTS_TRIANGLE (f))) && GTS_IS_FACE (t)) { gts_object_destroy (GTS_OBJECT (f)); f = GTS_FACE (t); } gts_surface_add_face (s, f); f = gts_face_new (s->face_class, GTS_EDGE (v3v6), e2, e3); if ((t = gts_triangle_is_duplicate (GTS_TRIANGLE (f))) && GTS_IS_FACE (t)) { gts_object_destroy (GTS_OBJECT (f)); f = GTS_FACE (t); } gts_surface_add_face (s, f); gts_surface_remove_face (s, GTS_FACE (t1)); gts_surface_remove_face (s, GTS_FACE (t2)); }
/** * gts_triangle_is_stabbed: * @t: a #GtsTriangle. * @p: a #GtsPoint. * @orientation: a pointer or %NULL. * * Returns: one of the vertices of @t, one of the edges of @t or @t if * any of these are stabbed by the ray starting at @p (included) and * ending at (@p->x, @p->y, +infty), %NULL otherwise. If the ray is * contained in the plane of the triangle %NULL is also returned. If * @orientation is not %NULL, it is set to the value of the * orientation of @p relative to @t (as given by * gts_point_orientation_3d()). */ GtsObject * gts_triangle_is_stabbed (GtsTriangle * t, GtsPoint * p, gdouble * orientation) { GtsVertex * v1, * v2, * v3, * inverted = NULL; GtsEdge * e1, * e2, * e3, * tmp; gdouble o, o1, o2, o3; g_return_val_if_fail (t != NULL, NULL); g_return_val_if_fail (p != NULL, NULL); gts_triangle_vertices_edges (t, NULL, &v1, &v2, &v3, &e1, &e2, &e3); o = gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), GTS_POINT (v3)); if (o == 0.) return NULL; if (o < 0.) { inverted = v1; v1 = v2; v2 = inverted; tmp = e2; e2 = e3; e3 = tmp; } o = gts_point_orientation_3d (GTS_POINT (v1), GTS_POINT (v2), GTS_POINT (v3), p); if (o < 0.) return NULL; o1 = gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), p); if (o1 < 0.) return NULL; o2 = gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p); if (o2 < 0.) return NULL; o3 = gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), p); if (o3 < 0.) return NULL; if (orientation) *orientation = inverted ? -o : o; if (o1 == 0.) { if (o2 == 0.) return GTS_OBJECT (v2); if (o3 == 0.) return GTS_OBJECT (v1); return GTS_OBJECT (e1); } if (o2 == 0.) { if (o3 == 0.) return GTS_OBJECT (v3); return GTS_OBJECT (e2); } if (o3 == 0.) return GTS_OBJECT (e3); return GTS_OBJECT (t); }
static gboolean triangle_is_hole (GtsTriangle * t) { GtsEdge * e1, * e2, * e3; GtsVertex * v1, * v2, * v3; gts_triangle_vertices_edges (t, NULL, &v1, &v2, &v3, &e1, &e2, &e3); if ((GTS_IS_CONSTRAINT (e1) && GTS_SEGMENT (e1)->v2 != v1) || (GTS_IS_CONSTRAINT (e2) && GTS_SEGMENT (e2)->v2 != v2) || (GTS_IS_CONSTRAINT (e3) && GTS_SEGMENT (e3)->v2 != v3)) return TRUE; return FALSE; }
static void edge_swap (GtsEdge * e, GtsSurface * s, GtsEHeap * heap) { GSList * i; GtsTriangle * t1 = NULL, * t2 = NULL; GtsVertex * v1, * v2, * v3, * v4; GtsEdge * e1, * e2, * e3, * e4; i = e->triangles; while (i) { if (GTS_IS_FACE (i->data)) { if (!t1) t1 = i->data; else if (!t2) t2 = i->data; else g_assert_not_reached (); } i = i->next; } g_assert (t1 && t2); gts_triangle_vertices_edges (t1, e, &v1, &v2, &v3, &e, &e3, &e4); gts_triangle_vertices_edges (t2, e, &v2, &v1, &v4, &e, &e1, &e2); gts_object_destroy (GTS_OBJECT (e)); e = gts_edge_new (s->edge_class, v3, v4); gts_surface_add_face (s, gts_face_new (s->face_class, e, e4, e1)); gts_surface_add_face (s, gts_face_new (s->face_class, e, e2, e3)); HEAP_INSERT_EDGE (heap, e); HEAP_REMOVE_EDGE (heap, e1); HEAP_INSERT_EDGE (heap, e1); HEAP_REMOVE_EDGE (heap, e2); HEAP_INSERT_EDGE (heap, e2); HEAP_REMOVE_EDGE (heap, e3); HEAP_INSERT_EDGE (heap, e3); HEAP_REMOVE_EDGE (heap, e4); HEAP_INSERT_EDGE (heap, e4); }
static void gts_constraint_split (GtsConstraint * c, GtsSurface * s, GtsFifo * fifo) { GSList * i; GtsVertex * v1, * v2; GtsEdge * e; g_return_if_fail (c != NULL); g_return_if_fail (s != NULL); v1 = GTS_SEGMENT (c)->v1; v2 = GTS_SEGMENT (c)->v2; e = GTS_EDGE (c); i = e->triangles; while (i) { GtsFace * f = i->data; if (GTS_IS_FACE (f) && gts_face_has_parent_surface (f, s)) { GtsVertex * v = gts_triangle_vertex_opposite (GTS_TRIANGLE (f), e); if (gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), GTS_POINT (v)) == 0.) { GSList * j = e->triangles; GtsFace * f1 = NULL; GtsEdge * e1, * e2; /* replaces edges with constraints */ gts_triangle_vertices_edges (GTS_TRIANGLE (f), e, &v1, &v2, &v, &e, &e1, &e2); if (!GTS_IS_CONSTRAINT (e1)) { GtsEdge * ne1 = gts_edge_new (GTS_EDGE_CLASS (GTS_OBJECT (c)->klass), v2, v); gts_edge_replace (e1, ne1); gts_object_destroy (GTS_OBJECT (e1)); e1 = ne1; if (fifo) gts_fifo_push (fifo, e1); } if (!GTS_IS_CONSTRAINT (e2)) { GtsEdge * ne2 = gts_edge_new (GTS_EDGE_CLASS (GTS_OBJECT (c)->klass), v, v1); gts_edge_replace (e2, ne2); gts_object_destroy (GTS_OBJECT (e2)); e2 = ne2; if (fifo) gts_fifo_push (fifo, e2); } /* look for face opposite */ while (j && !f1) { if (GTS_IS_FACE (j->data) && gts_face_has_parent_surface (j->data, s)) f1 = j->data; j = j->next; } if (f1) { /* c is not a boundary of s */ GtsEdge * e3, * e4, * e5; GtsVertex * v3; gts_triangle_vertices_edges (GTS_TRIANGLE (f1), e, &v1, &v2, &v3, &e, &e3, &e4); e5 = gts_edge_new (s->edge_class, v, v3); gts_surface_add_face (s, gts_face_new (s->face_class, e5, e2, e3)); gts_surface_add_face (s, gts_face_new (s->face_class, e5, e4, e1)); gts_object_destroy (GTS_OBJECT (f1)); } gts_object_destroy (GTS_OBJECT (f)); return; } } i = i->next; } }