Index: trunk/src_3rd/gts/face.c =================================================================== --- trunk/src_3rd/gts/face.c (revision 6802) +++ trunk/src_3rd/gts/face.c (nonexistent) @@ -1,297 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "gts.h" - -gboolean gts_allow_floating_faces = FALSE; - -static void face_destroy (GtsObject * object) -{ - GtsFace * face = GTS_FACE (object); - GSList * i; - - i = face->surfaces; - while (i) { - GSList * next = i->next; - gts_surface_remove_face (i->data, face); - i = next; - } - g_assert (face->surfaces == NULL); - - (* GTS_OBJECT_CLASS (gts_face_class ())->parent_class->destroy) (object); -} - -static void face_clone (GtsObject * clone, GtsObject * object) -{ - (* GTS_OBJECT_CLASS (gts_face_class ())->parent_class->clone) (clone, - object); - GTS_FACE (clone)->surfaces = NULL; -} - -static void face_class_init (GtsFaceClass * klass) -{ - GTS_OBJECT_CLASS (klass)->clone = face_clone; - GTS_OBJECT_CLASS (klass)->destroy = face_destroy; -} - -static void face_init (GtsFace * face) -{ - face->surfaces = NULL; -} - -/** - * gts_face_class: - * - * Returns: the #GtsFaceClass. - */ -GtsFaceClass * gts_face_class (void) -{ - static GtsFaceClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo face_info = { - "GtsFace", - sizeof (GtsFace), - sizeof (GtsFaceClass), - (GtsObjectClassInitFunc) face_class_init, - (GtsObjectInitFunc) face_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_triangle_class ()), - &face_info); - } - - return klass; -} - -/** - * gts_face_new: - * @klass: a #GtsFaceClass. - * @e1: a #GtsEdge. - * @e2: a #GtsEdge. - * @e3: a #GtsEdge. - * - * Returns: a new #GtsFace using @e1, @e2 and @e3 as edges. - */ -GtsFace * gts_face_new (GtsFaceClass * klass, - GtsEdge * e1, GtsEdge * e2, GtsEdge * e3) -{ - GtsFace * f; - - f = GTS_FACE (gts_object_new (GTS_OBJECT_CLASS (klass))); - gts_triangle_set (GTS_TRIANGLE (f), e1, e2, e3); - - return f; -} - -/** - * gts_face_has_parent_surface: - * @f: a #GtsFace. - * @s: a #GtsSurface. - * - * Returns: %TRUE if @f belongs to @s, %FALSE otherwise. - */ -gboolean gts_face_has_parent_surface (GtsFace * f, GtsSurface * s) -{ - GSList * i; - - g_return_val_if_fail (f != NULL, FALSE); - - i = f->surfaces; - while (i) { - if (i->data == s) - return TRUE; - i = i->next; - } - return FALSE; -} - -/** - * gts_faces_from_edges: - * @edges: a list of #GtsEdge. - * @s: a #GtsSurface or %NULL. - * - * Builds a list of unique faces which belong to @s and have - * one of their edges in @edges. - * - * Returns: the list of faces. - */ -GSList * gts_faces_from_edges (GSList * edges, GtsSurface * s) -{ - GHashTable * hash; - GSList * faces = NULL, * i; - - hash = g_hash_table_new (NULL, NULL); - i = edges; - while (i) { - GSList * j = GTS_EDGE (i->data)->triangles; - while (j) { - GtsTriangle * t = j->data; - if (GTS_IS_FACE (t) && - (!s || gts_face_has_parent_surface (GTS_FACE (t), s)) && - g_hash_table_lookup (hash, t) == NULL) { - faces = g_slist_prepend (faces, t); - g_hash_table_insert (hash, t, i); - } - j = j->next; - } - i = i->next; - } - g_hash_table_destroy (hash); - - return faces; -} - -/** - * gts_face_neighbor_number: - * @f: a #GtsFace. - * @s: a #GtsSurface or %NULL. - * - * Returns: the number of faces neighbors of @f and belonging to @s. - */ -guint gts_face_neighbor_number (GtsFace * f, GtsSurface * s) -{ - GSList * i; - guint nn = 0; - GtsEdge * e[4], ** e1 = e; - - g_return_val_if_fail (f != NULL, 0); - - e[0] = GTS_TRIANGLE (f)->e1; - e[1] = GTS_TRIANGLE (f)->e2; - e[2] = GTS_TRIANGLE (f)->e3; - e[3] = NULL; - while (*e1) { - i = (*e1++)->triangles; - while (i) { - GtsTriangle * t = i->data; - if (GTS_FACE (t) != f && - GTS_IS_FACE (t) && - (!s || gts_face_has_parent_surface (GTS_FACE (t), s))) - nn++; - i = i->next; - } - } - - return nn; -} - -/** - * gts_face_neighbors: - * @f: a #GtsFace. - * @s: a #GtsSurface or %NULL. - * - * Returns: a list of unique #GtsFace neighbors of @f and belonging to @s. - */ -GSList * gts_face_neighbors (GtsFace * f, GtsSurface * s) -{ - GSList * i, * list = NULL; - GtsEdge * e[4], ** e1 = e; - - g_return_val_if_fail (f != NULL, NULL); - - e[0] = GTS_TRIANGLE (f)->e1; - e[1] = GTS_TRIANGLE (f)->e2; - e[2] = GTS_TRIANGLE (f)->e3; - e[3] = NULL; - while (*e1) { - i = (*e1++)->triangles; - while (i) { - GtsTriangle * t = i->data; - if (GTS_FACE (t) != f && - GTS_IS_FACE (t) && - (!s || gts_face_has_parent_surface (GTS_FACE (t), s))) - list = g_slist_prepend (list, t); - i = i->next; - } - } - - return list; -} - -/** - * gts_face_foreach_neighbor: - * @f: a #GtsFace. - * @s: a #GtsSurface or %NULL. - * @func: a #GtsFunc. - * @data: user data to pass to @func. - * - * Calls @func for each neighbor of @f belonging to @s (if not %NULL). - */ -void gts_face_foreach_neighbor (GtsFace * f, - GtsSurface * s, - GtsFunc func, - gpointer data) -{ - GSList * i; - GtsEdge * e[4], ** e1 = e; - - g_return_if_fail (f != NULL); - g_return_if_fail (func != NULL); - - e[0] = GTS_TRIANGLE (f)->e1; - e[1] = GTS_TRIANGLE (f)->e2; - e[2] = GTS_TRIANGLE (f)->e3; - e[3] = NULL; - while (*e1) { - i = (*e1++)->triangles; - while (i) { - GtsTriangle * t = i->data; - if (GTS_FACE (t) != f && - GTS_IS_FACE (t) && - (!s || gts_face_has_parent_surface (GTS_FACE (t), s))) - (* func) (t, data); - i = i->next; - } - } -} - -static gboolean triangle_is_incompatible (GtsTriangle * t, GtsEdge * e, GtsSurface * s) -{ - GSList * i = e->triangles; - - while (i) { - if (i->data != t && - GTS_IS_FACE (i->data) && - gts_face_has_parent_surface (i->data, s) && - !gts_triangles_are_compatible (t, i->data, e)) - return TRUE; - i = i->next; - } - return FALSE; -} - -/** - * gts_face_is_compatible: - * @f: a #GtsFace. - * @s: a #GtsSurface. - * - * Returns: %TRUE if @f is compatible with all its neighbors belonging - * to @s, %FALSE otherwise. - */ -gboolean gts_face_is_compatible (GtsFace * f, GtsSurface * s) -{ - g_return_val_if_fail (f != NULL, FALSE); - g_return_val_if_fail (s != NULL, FALSE); - - return !(triangle_is_incompatible (GTS_TRIANGLE (f), GTS_TRIANGLE (f)->e1, s) || - triangle_is_incompatible (GTS_TRIANGLE (f), GTS_TRIANGLE (f)->e2, s) || - triangle_is_incompatible (GTS_TRIANGLE (f), GTS_TRIANGLE (f)->e3, s)); -} Index: trunk/src_3rd/gts/Makefile.in =================================================================== --- trunk/src_3rd/gts/Makefile.in (revision 6802) +++ trunk/src_3rd/gts/Makefile.in (nonexistent) @@ -1,74 +0,0 @@ -if /local/gts/enable -then -put /local/gts/CFLAGS [@-I. -I.. -I../.. -DG_LOG_DOMAIN=\"Gts\" @libs/sul/glib/cflags@@] -put /local/gts/OBJS [@ - object.o - point.o - vertex.o - segment.o - edge.o - triangle.o - face.o - kdtree.o - bbtree.o - misc.o - predicates.o - heap.o - eheap.o - fifo.o - matrix.o - surface.o - stripe.o - vopt.o - refine.o - iso.o - isotetra.o - split.o - psurface.o - hsurface.o - cdt.o - boolean.o - named.o - oocs.o - container.o - graph.o - pgraph.o - partition.o - curvature.o - tribox3.o -@] - -put /tmpasm/OFS { } -uniq /local/gts/OBJS -put /local/gts/SRCS /local/gts/OBJS -gsub /local/gts/SRCS {.o } {.c } - -print [@ -CFLAGS = @/local/gts/CFLAGS@ -OBJS = @/local/gts/OBJS@ -CC=@cc/cc@ - -libgts.a: $(OBJS) - @/host/fstools/ar@ rvu libgts.a $(OBJS) - -clean: - -@/host/fstools/rm@ $(OBJS) libgts.a -@] - -# generate explicit rules for .c -> .o -put /local/comp/OBJS /local/gts/OBJS -include {../../scconfig/Makefile.comp.inc} - -# generate deps -put /local/dep/CFLAGS /local/gts/CFLAGS -put /local/dep/SRCS /local/gts/SRCS -include {../../scconfig/Makefile.dep.inc} -else -print [@ -all: - -libgts.a: - -clean: -@] -end Index: trunk/src_3rd/gts/segment.c =================================================================== --- trunk/src_3rd/gts/segment.c (revision 6802) +++ trunk/src_3rd/gts/segment.c (nonexistent) @@ -1,233 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "gts.h" - -static void segment_destroy (GtsObject * object) -{ - GtsSegment * segment = GTS_SEGMENT (object); - GtsVertex * v1 = segment->v1; - GtsVertex * v2 = segment->v2; - - v1->segments = g_slist_remove (v1->segments, segment); - if (!GTS_OBJECT_DESTROYED (v1) && - !gts_allow_floating_vertices && v1->segments == NULL) - gts_object_destroy (GTS_OBJECT (v1)); - - v2->segments = g_slist_remove (v2->segments, segment); - if (!GTS_OBJECT_DESTROYED (v2) && - !gts_allow_floating_vertices && v2->segments == NULL) - gts_object_destroy (GTS_OBJECT (v2)); - - (* GTS_OBJECT_CLASS (gts_segment_class ())->parent_class->destroy) (object); -} - -static void segment_class_init (GtsObjectClass * klass) -{ - klass->destroy = segment_destroy; -} - -static void segment_init (GtsSegment * segment) -{ - segment->v1 = segment->v2 = NULL; -} - -/** - * gts_segment_class: - * - * Returns: the #GtsSegmentClass. - */ -GtsSegmentClass * gts_segment_class (void) -{ - static GtsSegmentClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo segment_info = { - "GtsSegment", - sizeof (GtsSegment), - sizeof (GtsSegmentClass), - (GtsObjectClassInitFunc) segment_class_init, - (GtsObjectInitFunc) segment_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (gts_object_class (), - &segment_info); - } - - return klass; -} - -/** - * gts_segment_new: - * @klass: a #GtsSegmentClass. - * @v1: a #GtsVertex. - * @v2: another #GtsVertex different from @v1. - * - * Returns: a new #GtsSegment linking @v1 and @v2. - */ -GtsSegment * gts_segment_new (GtsSegmentClass * klass, - GtsVertex * v1, GtsVertex * v2) -{ - GtsSegment * s; - - g_return_val_if_fail (v1 != NULL, NULL); - g_return_val_if_fail (v2 != NULL, NULL); - g_return_val_if_fail (v1 != v2, NULL); - - s = GTS_SEGMENT (gts_object_new (GTS_OBJECT_CLASS (klass))); - s->v1 = v1; - s->v2 = v2; - v1->segments = g_slist_prepend (v1->segments, s); - v2->segments = g_slist_prepend (v2->segments, s); - - return s; -} - -/** - * gts_segment_is_duplicate: - * @s: a #GtsSegment. - * - * Returns: the first #GtsSegment different from @s which shares the - * same endpoints or %NULL if there is none. - */ -GtsSegment * gts_segment_is_duplicate (GtsSegment * s) -{ - GSList * i; - GtsVertex * v2; - - g_return_val_if_fail (s != NULL, NULL); - - v2 = s->v2; - i = s->v1->segments; - if (s->v1 == v2) /* s is degenerate: special treatment */ - while (i) { - GtsSegment * s1 = i->data; - if (s1 != s && s1->v1 == v2 && s1->v2 == v2) - return s1; - i = i->next; - } - else /* s is not degenerate */ - while (i) { - GtsSegment * s1 = i->data; - if (s1 != s && (s1->v1 == v2 || s1->v2 == v2)) - return s1; - i = i->next; - } - return NULL; -} - -/** - * gts_segments_are_intersecting: - * @s1: a #GtsSegment. - * @s2: a #GtsSegment. - * - * Returns: %GTS_IN if @s1 and @s2 are intersecting, %GTS_ON if one of the - * endpoints of @s1 (resp. @s2) lies on @s2 (resp. @s1), %GTS_OUT otherwise. - */ -GtsIntersect gts_segments_are_intersecting (GtsSegment * s1, GtsSegment * s2) -{ - GtsPoint * p1, * p2, * p3, * p4; - gdouble d1, d2, d3, d4; - - g_return_val_if_fail (s1 != NULL && s2 != NULL, FALSE); - - p1 = GTS_POINT (s1->v1); p2 = GTS_POINT (s1->v2); - p3 = GTS_POINT (s2->v1); p4 = GTS_POINT (s2->v2); - d1 = gts_point_orientation (p1, p2, p3); - d2 = gts_point_orientation (p1, p2, p4); - if ((d1 > 0.0 && d2 > 0.0) || - (d1 < 0.0 && d2 < 0.0)) - return GTS_OUT; - d3 = gts_point_orientation (p3, p4, p1); - d4 = gts_point_orientation (p3, p4, p2); - if ((d3 > 0.0 && d4 > 0.0) || - (d3 < 0.0 && d4 < 0.0)) - return GTS_OUT; - if (d1 == 0.0 || d2 == 0.0 || d3 == 0.0 || d4 == 0.0) - return GTS_ON; - return GTS_IN; -} - -/** - * gts_segment_midvertex: - * @s: a #GtsSegment. - * @klass: a #GtsVertexClass to be used for the new vertex. - * - * Returns: a new #GtsVertex, midvertex of @s. - */ -GtsVertex * gts_segment_midvertex (GtsSegment * s, GtsVertexClass * klass) -{ - GtsPoint * p1, * p2; - - g_return_val_if_fail (s != NULL, NULL); - g_return_val_if_fail (klass != NULL, NULL); - - p1 = GTS_POINT (s->v1); p2 = GTS_POINT (s->v2); - return gts_vertex_new (klass, - (p1->x + p2->x)/2., - (p1->y + p2->y)/2., - (p1->z + p2->z)/2.); -} - -/** - * gts_segments_from_vertices: - * @vertices: a list of #GtsVertex. - * - * Returns: a list of unique #GtsSegment which have one of their vertices in - * @vertices. - */ -GSList * gts_segments_from_vertices (GSList * vertices) -{ - GHashTable * hash; - GSList * segments = NULL, * i; - - hash = g_hash_table_new (NULL, NULL); - i = vertices; - while (i) { - GSList * j = GTS_VERTEX (i->data)->segments; - while (j) { - GtsSegment * s = j->data; - if (g_hash_table_lookup (hash, s) == NULL) { - segments = g_slist_prepend (segments, s); - g_hash_table_insert (hash, s, i); - } - j = j->next; - } - i = i->next; - } - g_hash_table_destroy (hash); - return segments; -} - -/** - * gts_segment_is_ok: - * @s: a #GtsSegment. - * - * Returns: %TRUE if @s is not degenerate (i.e. @s->v1 != @s->v2) and not - * duplicate, %FALSE otherwise. - */ -gboolean gts_segment_is_ok (GtsSegment * s) -{ - g_return_val_if_fail (s != NULL, FALSE); - g_return_val_if_fail (s->v1 != s->v2, FALSE); - g_return_val_if_fail (!gts_segment_is_duplicate (s), FALSE); - g_return_val_if_fail (GTS_OBJECT (s)->reserved == NULL, FALSE); - return TRUE; -} Index: trunk/src_3rd/gts/oocs.c =================================================================== --- trunk/src_3rd/gts/oocs.c (revision 6802) +++ trunk/src_3rd/gts/oocs.c (nonexistent) @@ -1,387 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include "gts.h" - -static void cluster_destroy (GtsObject * object) -{ - GtsCluster * c = GTS_CLUSTER (object); - - if (c->v && gts_vertex_is_unattached (c->v)) - gts_object_destroy (GTS_OBJECT (c->v)); - - /* do not forget to call destroy method of the parent */ - (* GTS_OBJECT_CLASS (gts_cluster_class ())->parent_class->destroy) (object); -} - -static void cluster_add (GtsCluster * c, GtsPoint * p, gpointer data) -{ - GtsPoint * cp; - - g_return_if_fail (c != NULL); - g_return_if_fail (c->v != NULL); - g_return_if_fail (p != NULL); - - cp = GTS_POINT (c->v); - - cp->x += p->x; - cp->y += p->y; - cp->z += p->z; - c->n++; -} - -static void cluster_update (GtsCluster * c) -{ - GtsPoint * p; - - g_return_if_fail (c != NULL); - g_return_if_fail (c->v != NULL); - - if (c->n > 1) { - p = GTS_POINT (c->v); - p->x /= c->n; - p->y /= c->n; - p->z /= c->n; - } -} - -static void cluster_class_init (GtsClusterClass * klass) -{ - klass->add = cluster_add; - klass->update = cluster_update; - - GTS_OBJECT_CLASS (klass)->destroy = cluster_destroy; -} - -static void cluster_init (GtsCluster * c) -{ - c->v = NULL; - c->n = 0; -} - -/** - * gts_cluster_class: - * - * Returns: the #GtsClusterClass. - */ -GtsClusterClass * gts_cluster_class (void) -{ - static GtsClusterClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo cluster_info = { - "GtsCluster", - sizeof (GtsCluster), - sizeof (GtsClusterClass), - (GtsObjectClassInitFunc) cluster_class_init, - (GtsObjectInitFunc) cluster_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (gts_object_class (), &cluster_info); - } - - return klass; -} - -/** - * gts_cluster_new: - * @klass: a #GtsClusterClass. - * @id: the id of the new cluster. - * @vklass: a #GtsVertexClass for the representative vertex of the cluster. - * - * Returns: a new #GtsCluster. - */ -GtsCluster * gts_cluster_new (GtsClusterClass * klass, - GtsClusterId id, - GtsVertexClass * vklass) -{ - GtsCluster * c; - - c = GTS_CLUSTER (gts_object_new (GTS_OBJECT_CLASS (klass))); - c->id = id; - c->v = gts_vertex_new (vklass, 0., 0., 0.); - - return c; -} - -/** - * gts_cluster_add: - * @c: a #GtsCluster. - * @p: a #GtsPoint. - * @data: data to pass to the add() virtual method of #GtsClusterClass. - * - * Adds point @p to cluster @c. - */ -void gts_cluster_add (GtsCluster * c, GtsPoint * p, gpointer data) -{ - g_return_if_fail (c != NULL); - g_return_if_fail (p != NULL); - - (* GTS_CLUSTER_CLASS (GTS_OBJECT (c)->klass)->add) (c, p, data); -} - -/** - * gts_cluster_update: - * @c: a #GtsCluster. - * - * Updates the position of the vertex representative of all the - * vertices added to @c. - */ -void gts_cluster_update (GtsCluster * c) -{ - g_return_if_fail (c != NULL); - - (* GTS_CLUSTER_CLASS (GTS_OBJECT (c)->klass)->update) (c); -} - -static void destroy_cluster (GtsClusterId * id, GtsObject * cluster) -{ - gts_object_destroy (cluster); -} - -static void cluster_grid_destroy (GtsObject * object) -{ - GtsClusterGrid * cluster_grid = GTS_CLUSTER_GRID (object); - - g_hash_table_foreach (cluster_grid->clusters, - (GHFunc) destroy_cluster, NULL); - g_hash_table_destroy (cluster_grid->clusters); - - (* GTS_OBJECT_CLASS (gts_cluster_grid_class ())->parent_class->destroy) - (object); -} - -static void cluster_grid_class_init (GtsClusterGridClass * klass) -{ - GTS_OBJECT_CLASS (klass)->destroy = cluster_grid_destroy; -} - -static gint cluster_id_equal (gconstpointer v1, - gconstpointer v2) -{ - const GtsClusterId * id1 = (const GtsClusterId *) v1; - const GtsClusterId * id2 = (const GtsClusterId *) v2; - return ((id1->x == id2->x) && (id1->y == id2->y) && (id1->z == id2->z)); -} - -static guint cluster_id_hash (gconstpointer key) -{ - const GtsClusterId * id = (const GtsClusterId *) key; - return id->x + id->y + id->z; -} - -static void cluster_grid_init (GtsClusterGrid * cluster_grid) -{ - cluster_grid->surface = NULL; - cluster_grid->bbox = NULL; - cluster_grid->cluster_class = gts_cluster_class (); - cluster_grid->clusters = g_hash_table_new (cluster_id_hash, - cluster_id_equal); -} - -/** - * gts_cluster_grid_class: - * - * Returns: the #GtsClusterGridClass. - */ -GtsClusterGridClass * gts_cluster_grid_class (void) -{ - static GtsClusterGridClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo cluster_grid_info = { - "GtsClusterGrid", - sizeof (GtsClusterGrid), - sizeof (GtsClusterGridClass), - (GtsObjectClassInitFunc) cluster_grid_class_init, - (GtsObjectInitFunc) cluster_grid_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (gts_object_class (), &cluster_grid_info); - } - - return klass; -} - -/** - * gts_cluster_grid_new: - * @klass: a #GtsClusterGridClass. - * @cluster_class: the klass to be used for the vertex clusters. - * @s: the simplified surface. - * @bbox: bounding box of the surface to be simplified. - * @delta: the size of one grid cell of the simplification grid. - * - * Returns: a new #GtsClusterGrid. - */ -GtsClusterGrid * gts_cluster_grid_new (GtsClusterGridClass * klass, - GtsClusterClass * cluster_class, - GtsSurface * s, - GtsBBox * bbox, - gdouble delta) -{ - GtsClusterGrid * cluster_grid; - GtsVector size; - - g_return_val_if_fail (klass != NULL, NULL); - g_return_val_if_fail (cluster_class != NULL, NULL); - g_return_val_if_fail (s != NULL, NULL); - g_return_val_if_fail (bbox != NULL, NULL); - g_return_val_if_fail (delta > 0., NULL); - - size[0] = ceil ((bbox->x2 - bbox->x1)/delta); - size[1] = ceil ((bbox->y2 - bbox->y1)/delta); - size[2] = ceil ((bbox->z2 - bbox->z1)/delta); - g_return_val_if_fail (size[0] <= 2.*G_MAXINT + 2. && - size[1] <= 2.*G_MAXINT + 2. && - size[2] <= 2.*G_MAXINT + 2., NULL); - cluster_grid = - GTS_CLUSTER_GRID (gts_object_new (GTS_OBJECT_CLASS (klass))); - cluster_grid->cluster_class = cluster_class; - cluster_grid->surface = s; - cluster_grid->bbox = bbox; - cluster_grid->size[0] = size[0]; - cluster_grid->size[1] = size[1]; - cluster_grid->size[2] = size[2]; - - return cluster_grid; -} - -static GtsClusterId cluster_index (GtsPoint * p, - GtsBBox * bb, - GtsVector n) -{ - GtsClusterId id = {0, 0, 0}; - - g_return_val_if_fail (p->x >= bb->x1 && p->x <= bb->x2, id); - g_return_val_if_fail (p->y >= bb->y1 && p->y <= bb->y2, id); - g_return_val_if_fail (p->z >= bb->z1 && p->z <= bb->z2, id); - - id.x = (guint) (p->x == bb->x2 ? n[0] - 1. : n[0]*(p->x - bb->x1)/(bb->x2 - bb->x1)); - id.y = (guint) (p->y == bb->y2 ? n[1] - 1. : n[1]*(p->y - bb->y1)/(bb->y2 - bb->y1)); - id.z = (guint) (p->z == bb->z2 ? n[2] - 1. : n[2]*(p->z - bb->z1)/(bb->z2 - bb->z1)); - - return id; -} - -static GtsCluster * cluster_grid_add_point (GtsClusterGrid * cluster_grid, - GtsPoint * p, - gpointer data) -{ - GtsClusterId id = cluster_index (p, - cluster_grid->bbox, - cluster_grid->size); - GtsCluster * c = g_hash_table_lookup (cluster_grid->clusters, &id); - - if (c == NULL) { - c = gts_cluster_new (cluster_grid->cluster_class, id, - cluster_grid->surface->vertex_class); - g_hash_table_insert (cluster_grid->clusters, &c->id, c); - } - - gts_cluster_add (c, p, data); - - return c; -} - -/** - * gts_cluster_grid_add_triangle: - * @cluster_grid: a #GtsClusterGrid. - * @p1: a #GtsPoint. - * @p2: a #GtsPoint. - * @p3: a #GtsPoint. - * @data: user data to pass to the cluster add() method. - * - * Adds the triangle defined by @p1, @p2 and @p3 to the respective clusters - * of @cluster_grid. - */ -void gts_cluster_grid_add_triangle (GtsClusterGrid * cluster_grid, - GtsPoint * p1, - GtsPoint * p2, - GtsPoint * p3, - gpointer data) -{ - GtsCluster * c1, * c2, * c3; - - g_return_if_fail (cluster_grid != NULL); - g_return_if_fail (p1 != NULL); - g_return_if_fail (p2 != NULL); - g_return_if_fail (p3 != NULL); - g_return_if_fail (cluster_grid->surface != NULL); - - c1 = cluster_grid_add_point (cluster_grid, p1, data); - c2 = cluster_grid_add_point (cluster_grid, p2, data); - c3 = cluster_grid_add_point (cluster_grid, p3, data); - - if (c1 != c2 && c2 != c3 && c3 != c1) { - GtsVertex * v1, * v2, * v3; - GtsEdge * e1, * e2, * e3; - gboolean new_edge = FALSE; - - v1 = c1->v; v2 = c2->v; v3 = c3->v; - - if ((e1 = GTS_EDGE (gts_vertices_are_connected (v1, v2))) == NULL) { - e1 = gts_edge_new (cluster_grid->surface->edge_class, v1, v2); - new_edge = TRUE; - } - if ((e2 = GTS_EDGE (gts_vertices_are_connected (v2, v3))) == NULL) { - e2 = gts_edge_new (cluster_grid->surface->edge_class, v2, v3); - new_edge = TRUE; - } - if ((e3 = GTS_EDGE (gts_vertices_are_connected (v3, v1))) == NULL) { - e3 = gts_edge_new (cluster_grid->surface->edge_class, v3, v1); - new_edge = TRUE; - } - if (new_edge || !gts_triangle_use_edges (e1, e2, e3)) - gts_surface_add_face (cluster_grid->surface, - gts_face_new (cluster_grid->surface->face_class, - e1, e2, e3)); - } -} - -static void update_cluster (gint * id, GtsCluster * cluster, GtsRange * stats) -{ - gts_cluster_update (cluster); - gts_range_add_value (stats, cluster->n); -} - -/** - * gts_cluster_grid_update: - * @cluster_grid: a #GtsClusterGrid. - * - * Updates the representative vertices of all the clusters of @cluster_grid. - * - * Returns: a #GtsRange describing the statistics for the number of vertices - * added to each cluster of @cluster_grid. - */ -GtsRange gts_cluster_grid_update (GtsClusterGrid * cluster_grid) -{ - GtsRange stats; - - gts_range_init (&stats); - g_return_val_if_fail (cluster_grid != NULL, stats); - - g_hash_table_foreach (cluster_grid->clusters, - (GHFunc) update_cluster, &stats); - gts_range_update (&stats); - - return stats; -} Index: trunk/src_3rd/gts/triangle.c =================================================================== --- trunk/src_3rd/gts/triangle.c (revision 6802) +++ trunk/src_3rd/gts/triangle.c (nonexistent) @@ -1,1094 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include "gts.h" - -static void triangle_destroy (GtsObject * object) -{ - GtsTriangle * triangle = GTS_TRIANGLE (object); - GtsEdge * e1 = triangle->e1; - GtsEdge * e2 = triangle->e2; - GtsEdge * e3 = triangle->e3; - - e1->triangles = g_slist_remove (e1->triangles, triangle); - if (!GTS_OBJECT_DESTROYED (e1) && - !gts_allow_floating_edges && e1->triangles == NULL) - gts_object_destroy (GTS_OBJECT (e1)); - - e2->triangles = g_slist_remove (e2->triangles, triangle); - if (!GTS_OBJECT_DESTROYED (e2) && - !gts_allow_floating_edges && e2->triangles == NULL) - gts_object_destroy (GTS_OBJECT (e2)); - - e3->triangles = g_slist_remove (e3->triangles, triangle); - if (!GTS_OBJECT_DESTROYED (e3) && - !gts_allow_floating_edges && e3->triangles == NULL) - gts_object_destroy (GTS_OBJECT (e3)); - - (* GTS_OBJECT_CLASS (gts_triangle_class ())->parent_class->destroy) (object); -} - -static void triangle_class_init (GtsObjectClass * klass) -{ - klass->destroy = triangle_destroy; -} - -static void triangle_init (GtsTriangle * triangle) -{ - triangle->e1 = triangle->e2 = triangle->e3 = NULL; -} - -/** - * gts_triangle_class: - * - * Returns: the #GtsTriangleClass. - */ -GtsTriangleClass * gts_triangle_class (void) -{ - static GtsTriangleClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo triangle_info = { - "GtsTriangle", - sizeof (GtsTriangle), - sizeof (GtsTriangleClass), - (GtsObjectClassInitFunc) triangle_class_init, - (GtsObjectInitFunc) triangle_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (gts_object_class (), - &triangle_info); - } - - return klass; -} - -/** - * gts_triangle_set: - * @triangle: a #GtsTriangle. - * @e1: a #GtsEdge. - * @e2: another #GtsEdge touching @e1. - * @e3: another #GtsEdge touching both @e1 and @e2. - * - * Sets the edge of @triangle to @e1, @e2 and @e3 while checking that they - * define a valid triangle. - */ -void gts_triangle_set (GtsTriangle * triangle, - GtsEdge * e1, - GtsEdge * e2, - GtsEdge * e3) -{ - g_return_if_fail (e1 != NULL); - g_return_if_fail (e2 != NULL); - g_return_if_fail (e3 != NULL); - g_return_if_fail (e1 != e2 && e1 != e3 && e2 != e3); - - triangle->e1 = e1; - triangle->e2 = e2; - triangle->e3 = e3; - - if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v1) - g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), - GTS_SEGMENT (e1)->v2, - GTS_SEGMENT (e2)->v2)); - else if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v1) - g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), - GTS_SEGMENT (e1)->v1, - GTS_SEGMENT (e2)->v2)); - else if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v2) - g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), - GTS_SEGMENT (e1)->v1, - GTS_SEGMENT (e2)->v1)); - else if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v2) - g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), - GTS_SEGMENT (e1)->v2, - GTS_SEGMENT (e2)->v1)); - else - g_assert_not_reached (); - - e1->triangles = g_slist_prepend (e1->triangles, triangle); - e2->triangles = g_slist_prepend (e2->triangles, triangle); - e3->triangles = g_slist_prepend (e3->triangles, triangle); -} - -/** - * gts_triangle_new: - * @klass: a #GtsTriangleClass. - * @e1: a #GtsEdge. - * @e2: another #GtsEdge touching @e1. - * @e3: another #GtsEdge touching both @e1 and @e2. - * - * Returns: a new #GtsTriangle having @e1, @e2 and @e3 as edges. - */ -GtsTriangle * gts_triangle_new (GtsTriangleClass * klass, - GtsEdge * e1, - GtsEdge * e2, - GtsEdge * e3) -{ - GtsTriangle * t; - - t = GTS_TRIANGLE (gts_object_new (GTS_OBJECT_CLASS (klass))); - gts_triangle_set (t, e1, e2, e3); - - return t; -} - -/** - * gts_triangle_vertex_opposite: - * @t: a #GtsTriangle. - * @e: a #GtsEdge used by @t. - * - * This function fails if @e is not an edge of @t. - * - * Returns: a #GtsVertex, vertex of @t which does not belong to @e. - */ -GtsVertex * gts_triangle_vertex_opposite (GtsTriangle * t, GtsEdge * e) -{ - g_return_val_if_fail (t != NULL, NULL); - g_return_val_if_fail (e != NULL, NULL); - - if (t->e1 == e) { - GtsVertex * v = GTS_SEGMENT (t->e2)->v1; - if (v != GTS_SEGMENT (e)->v1 && v != GTS_SEGMENT (e)->v2) - return v; - return GTS_SEGMENT (t->e2)->v2; - } - if (t->e2 == e) { - GtsVertex * v = GTS_SEGMENT (t->e1)->v1; - if (v != GTS_SEGMENT (e)->v1 && v != GTS_SEGMENT (e)->v2) - return v; - return GTS_SEGMENT (t->e1)->v2; - } - if (t->e3 == e) { - GtsVertex * v = GTS_SEGMENT (t->e2)->v1; - if (v != GTS_SEGMENT (e)->v1 && v != GTS_SEGMENT (e)->v2) - return v; - return GTS_SEGMENT (t->e2)->v2; - } - g_assert_not_reached (); - return NULL; -} - -/** - * gts_triangle_edge_opposite: - * @t: a #GtsTriangle. - * @v: a #GtsVertex of @t. - * - * Returns: the edge of @t opposite @v or %NULL if @v is not a vertice of @t. - */ -GtsEdge * gts_triangle_edge_opposite (GtsTriangle * t, GtsVertex * v) -{ - GtsSegment * s1, * s2, * s3; - - g_return_val_if_fail (t != NULL, NULL); - g_return_val_if_fail (v != NULL, NULL); - - s1 = GTS_SEGMENT (t->e1); - s2 = GTS_SEGMENT (t->e2); - - if (s1->v1 != v && s1->v2 != v) { - if (s2->v1 != v && s2->v2 != v) - return NULL; - return t->e1; - } - if (s2->v1 != v && s2->v2 != v) - return t->e2; - s3 = GTS_SEGMENT (t->e3); - g_assert (s3->v1 != v && s3->v2 != v); - return t->e3; -} - -/** - * gts_triangles_angle: - * @t1: a #GtsTriangle. - * @t2: a #GtsTriangle. - * - * Returns: the value (in radians) of the angle between @t1 and @t2. - */ -gdouble gts_triangles_angle (GtsTriangle * t1, - GtsTriangle * t2) -{ - gdouble nx1, ny1, nz1, nx2, ny2, nz2; - gdouble pvx, pvy, pvz; - gdouble theta; - - g_return_val_if_fail (t1 != NULL && t2 != NULL, 0.0); - - gts_triangle_normal (t1, &nx1, &ny1, &nz1); - gts_triangle_normal (t2, &nx2, &ny2, &nz2); - - pvx = ny1*nz2 - nz1*ny2; - pvy = nz1*nx2 - nx1*nz2; - pvz = nx1*ny2 - ny1*nx2; - - theta = atan2 (sqrt (pvx*pvx + pvy*pvy + pvz*pvz), - nx1*nx2 + ny1*ny2 + nz1*nz2) - M_PI; - return theta < - M_PI ? theta + 2.*M_PI : theta; -} - -/** - * gts_triangles_are_compatible: - * @t1: a #GtsTriangle. - * @t2: a #GtsTriangle. - * @e: a #GtsEdge used by both @t1 and @t2. - * - * Checks if @t1 and @t2 have compatible orientations i.e. if @t1 and - * @t2 can be part of the same surface without conflict in the surface - * normal orientation. - * - * Returns: %TRUE if @t1 and @t2 are compatible, %FALSE otherwise. - */ -gboolean gts_triangles_are_compatible (GtsTriangle * t1, - GtsTriangle * t2, - GtsEdge * e) -{ - GtsEdge * e1 = NULL, * e2 = NULL; - - g_return_val_if_fail (t1 != NULL, FALSE); - g_return_val_if_fail (t2 != NULL, FALSE); - g_return_val_if_fail (e != NULL, FALSE); - - if (t1->e1 == e) e1 = t1->e2; - else if (t1->e2 == e) e1 = t1->e3; - else if (t1->e3 == e) e1 = t1->e1; - else - g_assert_not_reached (); - if (t2->e1 == e) e2 = t2->e2; - else if (t2->e2 == e) e2 = t2->e3; - else if (t2->e3 == e) e2 = t2->e1; - else - g_assert_not_reached (); - if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v1 || - GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v2 || - GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v1 || - GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v2) - return FALSE; - return TRUE; -} - -/** - * gts_triangle_area: - * @t: a #GtsTriangle. - * - * Returns: the area of the triangle @t. - */ -gdouble gts_triangle_area (GtsTriangle * t) -{ - gdouble x, y, z; - - g_return_val_if_fail (t != NULL, 0.0); - - gts_triangle_normal (t, &x, &y, &z); - - return sqrt (x*x + y*y + z*z)/2.; -} - -/** - * gts_triangle_perimeter: - * @t: a #GtsTriangle. - * - * Returns: the perimeter of the triangle @t. - */ -gdouble gts_triangle_perimeter (GtsTriangle * t) -{ - GtsVertex * v; - - g_return_val_if_fail (t != NULL, 0.0); - - v = gts_triangle_vertex (t); - return - gts_point_distance (GTS_POINT (GTS_SEGMENT (t->e1)->v1), - GTS_POINT (GTS_SEGMENT (t->e1)->v2)) + - gts_point_distance (GTS_POINT (GTS_SEGMENT (t->e1)->v1), - GTS_POINT (v)) + - gts_point_distance (GTS_POINT (GTS_SEGMENT (t->e1)->v2), - GTS_POINT (v)); -} - -/* perimeter of the equilateral triangle of area unity */ -#define GOLDEN_PERIMETER 4.5590141139 - -/** - * gts_triangle_quality: - * @t: a #GtsTriangle. - * - * The quality of a triangle is defined as the ratio of the square - * root of its surface area to its perimeter relative to this same - * ratio for an equilateral triangle with the same area. The quality - * is then one for an equilateral triangle and tends to zero for a - * very stretched triangle. - * - * Returns: the quality of the triangle @t. - */ -gdouble gts_triangle_quality (GtsTriangle * t) -{ - gdouble perimeter; - - g_return_val_if_fail (t != NULL, 0.0); - - perimeter = gts_triangle_perimeter (t); - return perimeter > 0.0 ? - GOLDEN_PERIMETER*sqrt (gts_triangle_area (t))/perimeter : - 0.0; -} - -/** - * gts_triangle_normal: - * @t: a #GtsTriangle. - * @x: the x coordinate of the normal. - * @y: the y coordinate of the normal. - * @z: the z coordinate of the normal. - * - * Computes the coordinates of the oriented normal of @t as the - * cross-product of two edges, using the left-hand rule. The normal is - * not normalized. If this triangle is part of a closed and oriented - * surface, the normal points to the outside of the surface. - */ -void gts_triangle_normal (GtsTriangle * t, - gdouble * x, - gdouble * y, - gdouble * z) -{ - GtsVertex * v1, * v2 = NULL, * v3 = NULL; - GtsPoint * p1, * p2, * p3; - gdouble x1, y1, z1, x2, y2, z2; - - g_return_if_fail (t != NULL); - - v1 = GTS_SEGMENT (t->e1)->v1; - if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v1) { - v2 = GTS_SEGMENT (t->e2)->v2; - v3 = GTS_SEGMENT (t->e1)->v2; - } - else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v2) { - v2 = GTS_SEGMENT (t->e1)->v2; - v3 = GTS_SEGMENT (t->e2)->v1; - } - else if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v2) { - v2 = GTS_SEGMENT (t->e2)->v1; - v3 = GTS_SEGMENT (t->e1)->v2; - } - else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v1) { - v2 = GTS_SEGMENT (t->e1)->v2; - v3 = GTS_SEGMENT (t->e2)->v2; - } - else { - fprintf (stderr, "t: %p t->e1: %p t->e2: %p t->e3: %p t->e1->v1: %p t->e1->v2: %p t->e2->v1: %p t->e2->v2: %p t->e3->v1: %p t->e3->v2: %p\n", - t, t->e1, t->e2, - t->e3, GTS_SEGMENT (t->e1)->v1, GTS_SEGMENT (t->e1)->v2, - GTS_SEGMENT (t->e2)->v1, GTS_SEGMENT (t->e2)->v2, - GTS_SEGMENT (t->e3)->v1, GTS_SEGMENT (t->e3)->v2); - g_assert_not_reached (); - } - - p1 = GTS_POINT (v1); - p2 = GTS_POINT (v2); - p3 = GTS_POINT (v3); - - x1 = p2->x - p1->x; - y1 = p2->y - p1->y; - z1 = p2->z - p1->z; - - x2 = p3->x - p1->x; - y2 = p3->y - p1->y; - z2 = p3->z - p1->z; - - *x = y1*z2 - z1*y2; - *y = z1*x2 - x1*z2; - *z = x1*y2 - y1*x2; -} - -/** - * gts_triangle_orientation: - * @t: a #GtsTriangle. - * - * Checks for the orientation of the plane (x,y) projection of a - * triangle. See gts_point_orientation() for details. This function - * is geometrically robust. - * - * Returns: a number depending on the orientation of the vertices of @t. - */ -gdouble gts_triangle_orientation (GtsTriangle * t) -{ - GtsVertex * v1, * v2 = NULL, * v3 = NULL; - - g_return_val_if_fail (t != NULL, 0.0); - - v1 = GTS_SEGMENT (t->e1)->v1; - if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v1) { - v2 = GTS_SEGMENT (t->e2)->v2; - v3 = GTS_SEGMENT (t->e1)->v2; - } - else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v2) { - v2 = GTS_SEGMENT (t->e1)->v2; - v3 = GTS_SEGMENT (t->e2)->v1; - } - else if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v2) { - v2 = GTS_SEGMENT (t->e2)->v1; - v3 = GTS_SEGMENT (t->e1)->v2; - } - else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v1) { - v2 = GTS_SEGMENT (t->e1)->v2; - v3 = GTS_SEGMENT (t->e2)->v2; - } - else - g_assert_not_reached (); - return gts_point_orientation (GTS_POINT (v1), - GTS_POINT (v2), - GTS_POINT (v3)); -} - -/** - * gts_triangle_revert: - * @t: a #GtsTriangle. - * - * Changes the orientation of triangle @t, turning it inside out. - */ -void gts_triangle_revert (GtsTriangle * t) -{ - GtsEdge * e; - - g_return_if_fail (t != NULL); - - e = t->e1; - t->e1 = t->e2; - t->e2 = e; -} - -/** - * gts_triangles_from_edges: - * @edges: a list of #GtsEdge. - * - * Builds a list of unique triangles which have one of their edges in @edges. - * - * Returns: the list of triangles. - */ -GSList * gts_triangles_from_edges (GSList * edges) -{ - GHashTable * hash; - GSList * triangles = NULL, * i; - - hash = g_hash_table_new (NULL, NULL); - i = edges; - while (i) { - GSList * j = GTS_EDGE (i->data)->triangles; - while (j) { - GtsTriangle * t = j->data; - if (g_hash_table_lookup (hash, t) == NULL) { - triangles = g_slist_prepend (triangles, t); - g_hash_table_insert (hash, t, i); - } - j = j->next; - } - i = i->next; - } - g_hash_table_destroy (hash); - - return triangles; -} - -/** - * gts_triangle_vertices_edges: - * @t: a #GtsTriangle. - * @e: a #GtsEdge belonging to the edges of @t or %NULL. - * @v1: a #GtsVertex used by @t. - * @v2: a #GtsVertex used by @t. - * @v3: a #GtsVertex used by @t. - * @e1: a #GtsEdge used by @t. - * @e2: a #GtsEdge used by @t. - * @e3: a #GtsEdge used by @t. - * - * Given @t and @e, returns @v1, @v2, @v3, @e1, @e2 and @e3. @e1 - * has @v1 and @v2 as vertices, @e2 has @v2 and @v3 as vertices - * and @e3 has @v3 and @v1 as vertices. @v1, @v2 and @v3 respects - * the orientation of @t. If @e is not NULL, @e1 and @e are - * identical. - */ -void gts_triangle_vertices_edges (GtsTriangle * t, - GtsEdge * e, - GtsVertex ** v1, - GtsVertex ** v2, - GtsVertex ** v3, - GtsEdge ** e1, - GtsEdge ** e2, - GtsEdge ** e3) -{ - GtsEdge * ee1, * ee2; - - g_return_if_fail (t != NULL); - - if (e == t->e1 || e == NULL) { - *e1 = ee1 = t->e1; *e2 = ee2 = t->e2; *e3 = t->e3; - } - else if (e == t->e2) { - *e1 = ee1 = e; *e2 = ee2 = t->e3; *e3 = t->e1; - } - else if (e == t->e3) { - *e1 = ee1 = e; *e2 = ee2 = t->e1; *e3 = t->e2; - } - else { - g_assert_not_reached (); - ee1 = ee2 = NULL; /* to avoid complaints from the compiler */ - } - if (GTS_SEGMENT (ee1)->v2 == GTS_SEGMENT (ee2)->v1) { - *v1 = GTS_SEGMENT (ee1)->v1; - *v2 = GTS_SEGMENT (ee1)->v2; - *v3 = GTS_SEGMENT (ee2)->v2; - } - else if (GTS_SEGMENT (ee1)->v2 == GTS_SEGMENT (ee2)->v2) { - *v1 = GTS_SEGMENT (ee1)->v1; - *v2 = GTS_SEGMENT (ee1)->v2; - *v3 = GTS_SEGMENT (ee2)->v1; - } - else if (GTS_SEGMENT (ee1)->v1 == GTS_SEGMENT (ee2)->v1) { - *v1 = GTS_SEGMENT (ee1)->v2; - *v2 = GTS_SEGMENT (ee1)->v1; - *v3 = GTS_SEGMENT (ee2)->v2; - } - else if (GTS_SEGMENT (ee1)->v1 == GTS_SEGMENT (ee2)->v2) { - *v1 = GTS_SEGMENT (ee1)->v2; - *v2 = GTS_SEGMENT (ee1)->v1; - *v3 = GTS_SEGMENT (ee2)->v1; - } - else - g_assert_not_reached (); -} - -/* sqrt(3) */ -#define SQRT3 1.73205080757 - -/** - * gts_triangle_enclosing: - * @klass: the class of the new triangle. - * @points: a list of #GtsPoint. - * @scale: a scaling factor (must be larger than one). - * - * Builds a new triangle (including new vertices and edges) enclosing - * the plane projection of all the points in @points. This triangle is - * equilateral and encloses a rectangle defined by the maximum and - * minimum x and y coordinates of the points. @scale is an homothetic - * scaling factor. If equal to one, the triangle encloses exactly the - * enclosing rectangle. - * - * Returns: a new #GtsTriangle. - */ -GtsTriangle * gts_triangle_enclosing (GtsTriangleClass * klass, - GSList * points, gdouble scale) -{ - gdouble xmax, xmin, ymax, ymin; - gdouble xo, yo, r; - GtsVertex * v1, * v2, * v3; - GtsEdge * e1, * e2, * e3; - - if (points == NULL) - return NULL; - - xmax = xmin = GTS_POINT (points->data)->x; - ymax = ymin = GTS_POINT (points->data)->y; - points = points->next; - while (points) { - GtsPoint * p = points->data; - if (p->x > xmax) xmax = p->x; - else if (p->x < xmin) xmin = p->x; - if (p->y > ymax) ymax = p->y; - else if (p->y < ymin) ymin = p->y; - points = points->next; - } - xo = (xmax + xmin)/2.; - yo = (ymax + ymin)/2.; - r = scale*sqrt((xmax - xo)*(xmax - xo) + (ymax - yo)*(ymax - yo)); - if (r == 0.0) r = scale; - v1 = gts_vertex_new (gts_vertex_class (), - xo + r*SQRT3, yo - r, 0.0); - v2 = gts_vertex_new (gts_vertex_class (), - xo, yo + 2.*r, 0.0); - v3 = gts_vertex_new (gts_vertex_class (), - xo - r*SQRT3, yo - r, 0.0); - e1 = gts_edge_new (gts_edge_class (), v1, v2); - e2 = gts_edge_new (gts_edge_class (), v2, v3); - e3 = gts_edge_new (gts_edge_class (), v3, v1); - return gts_triangle_new (gts_triangle_class (), e1, e2, e3); -} - -/** - * gts_triangle_neighbor_number: - * @t: a #GtsTriangle. - * - * Returns: the number of triangles neighbors of @t. - */ -guint gts_triangle_neighbor_number (GtsTriangle * t) -{ - GSList * i; - guint nn = 0; - GtsEdge * ee[4], ** e = ee; - - g_return_val_if_fail (t != NULL, 0); - - ee[0] = t->e1; ee[1] = t->e2; ee[2] = t->e3; ee[3] = NULL; - while (*e) { - i = (*e++)->triangles; - while (i) { - GtsTriangle * t1 = i->data; - if (t1 != t) - nn++; - i = i->next; - } - } - return nn; -} - -/** - * gts_triangle_neighbors: - * @t: a #GtsTriangle. - * - * Returns: a list of #GtsTriangle neighbors of @t. - */ -GSList * gts_triangle_neighbors (GtsTriangle * t) -{ - GSList * i, * list = NULL; - GtsEdge * ee[4], ** e = ee; - - g_return_val_if_fail (t != NULL, NULL); - - ee[0] = t->e1; ee[1] = t->e2; ee[2] = t->e3; ee[3] = NULL; - while (*e) { - i = (*e++)->triangles; - while (i) { - GtsTriangle * t1 = i->data; - if (t1 != t) - list = g_slist_prepend (list, t1); - i = i->next; - } - } - return list; -} - -/** - * gts_triangles_common_edge: - * @t1: a #GtsTriangle. - * @t2: a #GtsTriangle. - * - * Returns: a #GtsEdge common to both @t1 and @t2 or %NULL if @t1 and @t2 - * do not share any edge. - */ -GtsEdge * gts_triangles_common_edge (GtsTriangle * t1, - GtsTriangle * t2) -{ - g_return_val_if_fail (t1 != NULL, NULL); - g_return_val_if_fail (t2 != NULL, NULL); - - if (t1->e1 == t2->e1 || t1->e1 == t2->e2 || t1->e1 == t2->e3) - return t1->e1; - if (t1->e2 == t2->e1 || t1->e2 == t2->e2 || t1->e2 == t2->e3) - return t1->e2; - if (t1->e3 == t2->e1 || t1->e3 == t2->e2 || t1->e3 == t2->e3) - return t1->e3; - return NULL; -} - -/** - * gts_triangle_is_duplicate: - * @t: a #GtsTriangle. - * - * Returns: a #GtsTriangle different from @t but sharing all its edges - * with @t or %NULL if there is none. - */ -GtsTriangle * gts_triangle_is_duplicate (GtsTriangle * t) -{ - GSList * i; - GtsEdge * e2, * e3; - - g_return_val_if_fail (t != NULL, NULL); - - e2 = t->e2; - e3 = t->e3; - i = t->e1->triangles; - while (i) { - GtsTriangle * t1 = i->data; - if (t1 != t && - (t1->e1 == e2 || t1->e2 == e2 || t1->e3 == e2) && - (t1->e1 == e3 || t1->e2 == e3 || t1->e3 == e3)) - return t1; - i = i->next; - } - - return NULL; -} - -/** - * gts_triangle_use_edges: - * @e1: a #GtsEdge. - * @e2: a #GtsEdge. - * @e3: a #GtsEdge. - * - * Returns: a #GtsTriangle having @e1, @e2 and @e3 as edges or %NULL if @e1, - * @e2 and @e3 are not part of any triangle. - */ -GtsTriangle * gts_triangle_use_edges (GtsEdge * e1, - GtsEdge * e2, - GtsEdge * e3) -{ - GSList * i; - - g_return_val_if_fail (e1 != NULL, NULL); - g_return_val_if_fail (e2 != NULL, NULL); - g_return_val_if_fail (e3 != NULL, NULL); - - i = e1->triangles; - while (i) { - GtsTriangle * t = i->data; - if ((t->e1 == e2 && (t->e2 == e3 || t->e3 == e3)) || - (t->e2 == e2 && (t->e1 == e3 || t->e3 == e3)) || - (t->e3 == e2 && (t->e1 == e3 || t->e2 == e3))) - return t; - i = i->next; - } - - return NULL; -} - -/** - * gts_triangle_is_ok: - * @t: a #GtsTriangle. - * - * Returns: %TRUE if @t is a non-degenerate, non-duplicate triangle, - * %FALSE otherwise. - */ -gboolean gts_triangle_is_ok (GtsTriangle * t) -{ - g_return_val_if_fail (t != NULL, FALSE); - g_return_val_if_fail (t->e1 != NULL, FALSE); - g_return_val_if_fail (t->e2 != NULL, FALSE); - g_return_val_if_fail (t->e3 != NULL, FALSE); - g_return_val_if_fail (t->e1 != t->e2 && t->e1 != t->e3 && t->e2 != t->e3, - FALSE); - g_return_val_if_fail (gts_segments_touch (GTS_SEGMENT (t->e1), - GTS_SEGMENT (t->e2)), - FALSE); - g_return_val_if_fail (gts_segments_touch (GTS_SEGMENT (t->e1), - GTS_SEGMENT (t->e3)), - FALSE); - g_return_val_if_fail (gts_segments_touch (GTS_SEGMENT (t->e2), - GTS_SEGMENT (t->e3)), - FALSE); - g_return_val_if_fail (GTS_SEGMENT (t->e1)->v1 != GTS_SEGMENT (t->e1)->v2, - FALSE); - g_return_val_if_fail (GTS_SEGMENT (t->e2)->v1 != GTS_SEGMENT (t->e2)->v2, - FALSE); - g_return_val_if_fail (GTS_SEGMENT (t->e3)->v1 != GTS_SEGMENT (t->e3)->v2, - FALSE); - g_return_val_if_fail (GTS_OBJECT (t)->reserved == NULL, FALSE); - g_return_val_if_fail (!gts_triangle_is_duplicate (t), FALSE); - return TRUE; -} - -/** - * gts_triangle_vertices: - * @t: a #GtsTriangle. - * @v1: a pointer on a #GtsVertex. - * @v2: a pointer on a #GtsVertex. - * @v3: a pointer on a #GtsVertex. - * - * Fills @v1, @v2 and @v3 with the oriented set of vertices, summits of @t. - */ -void gts_triangle_vertices (GtsTriangle * t, - GtsVertex ** v1, GtsVertex ** v2, GtsVertex ** v3) -{ - GtsSegment * e1, * e2; - - g_return_if_fail (t != NULL); - g_return_if_fail (v1 != NULL && v2 != NULL && v3 != NULL); - - e1 = GTS_SEGMENT (t->e1); - e2 = GTS_SEGMENT (t->e2); - - if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v1) { - *v1 = GTS_SEGMENT (e1)->v1; - *v2 = GTS_SEGMENT (e1)->v2; - *v3 = GTS_SEGMENT (e2)->v2; - } - else if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v2) { - *v1 = GTS_SEGMENT (e1)->v1; - *v2 = GTS_SEGMENT (e1)->v2; - *v3 = GTS_SEGMENT (e2)->v1; - } - else if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v1) { - *v1 = GTS_SEGMENT (e1)->v2; - *v2 = GTS_SEGMENT (e1)->v1; - *v3 = GTS_SEGMENT (e2)->v2; - } - else { - *v1 = GTS_SEGMENT (e1)->v2; - *v2 = GTS_SEGMENT (e1)->v1; - *v3 = GTS_SEGMENT (e2)->v1; - } -} - -/** - * gts_triangle_circumcircle_center: - * @t: a #GtsTriangle. - * @point_class: a #GtsPointClass. - * - * Returns: a new #GtsPoint, center of the circumscribing circle of @t or - * %NULL if the circumscribing circle is not defined. - */ -GtsPoint * gts_triangle_circumcircle_center (GtsTriangle * t, - GtsPointClass * point_class) -{ - GtsVertex * v1, * v2, * v3; - gdouble xa, ya, xb, yb, xc, yc; - gdouble xd, yd, xe, ye; - gdouble xad, yad, xae, yae; - gdouble det; - - g_return_val_if_fail (t != NULL, NULL); - g_return_val_if_fail (point_class != NULL, NULL); - - gts_triangle_vertices (t, &v1, &v2, &v3); - - xa = GTS_POINT (v1)->x; ya = GTS_POINT (v1)->y; - xb = GTS_POINT (v2)->x; yb = GTS_POINT (v2)->y; - xc = GTS_POINT (v3)->x; yc = GTS_POINT (v3)->y; - xd = (xa + xb)/2.; yd = (ya + yb)/2.; - xe = (xa + xc)/2.; ye = (ya + yc)/2.; - xad = xd - xa; yad = yd - ya; - xae = xe - xa; yae = ye - ya; - det = xad*yae - xae*yad; - if (det == 0.) - return NULL; - return gts_point_new (point_class, - (yae*yad*(yd - ye) + xad*yae*xd - xae*yad*xe)/det, - -(xae*xad*(xd - xe) + yad*xae*yd - yae*xad*ye)/det, - 0.); -} - -/* square of the maximum area ratio admissible */ -#define AREA_RATIO_MAX2 1e8 - -static gboolean points_are_folded (GtsPoint * A, - GtsPoint * B, - GtsPoint * C, - GtsPoint * D, - gdouble max) -{ - GtsVector AB, AC, AD; - GtsVector n1, n2; - gdouble nn1, nn2, n1n2; - - gts_vector_init (AB, A, B); - gts_vector_init (AC, A, C); - gts_vector_init (AD, A, D); - gts_vector_cross (n1, AB, AC); - gts_vector_cross (n2, AD, AB); - - nn1 = gts_vector_scalar (n1, n1); - nn2 = gts_vector_scalar (n2, n2); - if (nn1 >= AREA_RATIO_MAX2*nn2 || nn2 >= AREA_RATIO_MAX2*nn1) - return TRUE; - n1n2 = gts_vector_scalar (n1, n2); - if (n1n2 > 0.) - return FALSE; - if (n1n2*n1n2/(nn1*nn2) > max) - return TRUE; - return FALSE; -} - -static GtsVertex * triangle_use_vertices (GtsTriangle * t, - GtsVertex * A, - GtsVertex * B) -{ - GtsVertex - * v1 = GTS_SEGMENT (t->e1)->v1, - * v2 = GTS_SEGMENT (t->e1)->v2, - * v3 = gts_triangle_vertex (t); - - if (v1 == A) { - if (v2 == B) - return v3; - g_assert (v3 == B); - return v2; - } - if (v2 == A) { - if (v1 == B) - return v3; - g_assert (v3 == B); - return v1; - } - if (v3 == A) { - if (v1 == B) - return v2; - g_assert (v2 == B); - return v1; - } - g_assert_not_reached (); - return NULL; -} - -/** - * gts_triangles_are_folded: - * @triangles: a list of #GtsTriangle. - * @A: a #GtsVertex. - * @B: another #GtsVertex. - * @max: the maximum value of the square of the cosine of the angle between - * two triangles. - * - * Given a list of triangles sharing @A and @B as vertices, checks if any - * two triangles in the list make an angle larger than a given value defined - * by @max. - * - * Returns: %TRUE if any pair of triangles in @triangles makes an angle larger - * than the maximum value, %FALSE otherwise. - */ -gboolean gts_triangles_are_folded (GSList * triangles, - GtsVertex * A, GtsVertex * B, - gdouble max) -{ - GSList * i; - - g_return_val_if_fail (A != NULL, TRUE); - g_return_val_if_fail (B != NULL, TRUE); - - i = triangles; - while (i) { - GtsVertex * C = triangle_use_vertices (i->data, A, B); - GSList * j = i->next; - while (j) { - GtsVertex * D = triangle_use_vertices (j->data, A, B); - if (points_are_folded (GTS_POINT (A), - GTS_POINT (B), - GTS_POINT (C), - GTS_POINT (D), - max)) - return TRUE; - j = j->next; - } - i = i->next; - } - return FALSE; -} - -/** - * 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); -} - -/** - * gts_triangle_interpolate_height: - * @t: a #GtsTriangle. - * @p: a #GtsPoint. - * - * Fills the z-coordinate of point @p belonging to the plane - * projection of triangle @t with the linearly interpolated value of - * the z-coordinates of the vertices of @t. - */ -void gts_triangle_interpolate_height (GtsTriangle * t, GtsPoint * p) -{ - GtsPoint * p1, * p2, * p3; - gdouble x1, x2, y1, y2, det; - - g_return_if_fail (t != NULL); - g_return_if_fail (p != NULL); - - p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1); - p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); - p3 = GTS_POINT (gts_triangle_vertex (t)); - - x1 = p2->x - p1->x; - y1 = p2->y - p1->y; - x2 = p3->x - p1->x; - y2 = p3->y - p1->y; - det = x1*y2 - x2*y1; - if (det == 0.) - p->z = (p1->z + p2->z + p3->z)/3.; - else { - gdouble x = p->x - p1->x; - gdouble y = p->y - p1->y; - gdouble a = (x*y2 - y*x2)/det; - gdouble b = (y*x1 - x*y1)/det; - - p->z = (1. - a - b)*p1->z + a*p2->z + b*p3->z; - } -} Index: trunk/src_3rd/gts/stripe.c =================================================================== --- trunk/src_3rd/gts/stripe.c (revision 6802) +++ trunk/src_3rd/gts/stripe.c (nonexistent) @@ -1,766 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999-2003 Wagner Toledo Correa, Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "gts.h" - -#define PRINT_HEAP_ELEMENTS 0 - -typedef struct { - GtsTriangle * t; - gboolean used; - GSList * neighbors; - GtsEHeapPair *pos; -} tri_data_t; - -typedef struct { - GHashTable * ht; -} map_t; - -typedef struct { - map_t * map; - GtsEHeap * heap; -} heap_t; - -static tri_data_t * tri_data_new (GtsTriangle * t); -static void tri_data_destroy (tri_data_t * td); -static guint tri_data_num_unused_neighbors2 (const tri_data_t * td, - const map_t * map); -static GHashTable * tri_data_unused_neighbors2 (const tri_data_t * td, - const map_t * map); - -static map_t * map_new (GtsSurface * s); -static void map_destroy (map_t * map); -static tri_data_t * map_lookup (const map_t * map, GtsTriangle * t); - - -static heap_t * heap_new (GtsSurface * s); -static void heap_destroy (heap_t * heap); -static gboolean heap_is_empty (const heap_t * heap); -static GtsTriangle * heap_top (const heap_t * heap); -static void heap_remove (heap_t * heap, GtsTriangle * t); - -/* helper functions */ - -static gboolean vertices_are_unique (GtsVertex * v1, - GtsVertex * v2, - GtsVertex * v3) -{ - g_assert (v1 && v2 && v3); - return (v1 != v2 && v1 != v3 && v2 != v3); -} - -static gboolean vertex_is_one_of (GtsVertex * v, - GtsVertex * v1, - GtsVertex * v2, - GtsVertex * v3) -{ - g_assert (v && v1 && v2 && v3); - return v == v1 || v == v2 || v == v3; -} - -static guint num_shared_vertices (GtsVertex * u1, - GtsVertex * u2, - GtsVertex * u3, - GtsVertex * v1, - GtsVertex * v2, - GtsVertex * v3) -{ - guint n = 0; - - g_assert (u1 && u2 && u3); - g_assert (v1 && v2 && v3); - g_assert (vertices_are_unique (u1, u2, u3)); - g_assert (vertices_are_unique (v1, v2, v3)); - - if (vertex_is_one_of (v1, u1, u2, u3)) - n++; - if (vertex_is_one_of (v2, u1, u2, u3)) - n++; - if (vertex_is_one_of (v3, u1, u2, u3)) - n++; - return n; -} - -static gboolean vertices_match (GtsVertex * v1, - GtsVertex * v2, - GtsVertex * v3, - GtsVertex ** v4, - GtsVertex ** v5, - GtsVertex ** v6) -{ - guint i; - - g_assert (v4 && v5 && v6); - g_assert (*v4 && *v5 && *v6); - g_assert (vertices_are_unique (*v4, *v5, *v6)); - - for (i = 0; i < 2; i++) { - if ((!v1 || (v1 == *v4)) && - (!v2 || (v2 == *v5)) && - (!v3 || (v3 == *v6))) - return TRUE; - else { - GtsVertex * v7 = * v4; - - *v4 = *v5; - *v5 = *v6; - *v6 = v7; - } - } - return ((!v1 || (v1 == *v4)) && - (!v2 || (v2 == *v5)) && - (!v3 || (v3 == *v6))); -} - -static GtsVertex * non_shared_vertex1 (GtsVertex * u1, - GtsVertex * u2, - GtsVertex * u3, - GtsVertex * v1, - GtsVertex * v2, - GtsVertex * v3) -{ - GtsVertex * u = NULL; - - g_assert (u1 && u2 && u3); - g_assert (v1 && v2 && v3); - g_assert (vertices_are_unique (u1, u2, u3)); - g_assert (vertices_are_unique (v1, v2, v3)); - g_assert (num_shared_vertices (u1, u2, u3, v1, v2, v3) == 2); - - if (!vertex_is_one_of (u1, v1, v2, v3)) { - g_assert (vertex_is_one_of (u2, v1, v2, v3)); - g_assert (vertex_is_one_of (u3, v1, v2, v3)); - u = u1; - } else if (!vertex_is_one_of (u2, v1, v2, v3)) { - g_assert (vertex_is_one_of (u1, v1, v2, v3)); - g_assert (vertex_is_one_of (u3, v1, v2, v3)); - u = u2; - } else if (!vertex_is_one_of (u3, v1, v2, v3)) { - g_assert (vertex_is_one_of (u1, v1, v2, v3)); - g_assert (vertex_is_one_of (u2, v1, v2, v3)); - u = u3; - } else - g_assert_not_reached (); - - return u; -} - -static void match_vertex (GtsVertex * v, - GtsVertex ** v1, - GtsVertex ** v2, - GtsVertex ** v3) -{ - g_assert (v && v1 && v2 && v3); - g_assert (*v1 && *v2 && *v3); - g_assert (vertex_is_one_of (v, *v1, *v2, *v3)); - while (*v1 != v) { - GtsVertex *v0 = *v1; - - *v1 = *v2; - *v2 = *v3; - *v3 = v0; - } -} - -/* tri_data_t functions */ - -static tri_data_t * tri_data_new (GtsTriangle * t) -{ - tri_data_t * td; - - td = g_malloc (sizeof (tri_data_t)); - td->t = t; - td->used = FALSE; - td->neighbors = gts_triangle_neighbors (t); - td->pos = NULL; - - return td; -} - -static void tri_data_destroy (tri_data_t * td) -{ - if (!td) - return; - g_slist_free (td->neighbors); - g_free (td); -} - -static guint tri_data_num_unused_neighbors2 (const tri_data_t * td, - const map_t * map) -{ - GHashTable *h; - guint n; - - g_assert (td); - g_assert (map); - h = tri_data_unused_neighbors2 (td, map); - n = g_hash_table_size (h); - g_hash_table_destroy (h); - return n; -} - -static void copy_key_to_array (gpointer key, - gpointer value, - gpointer user_data) -{ - GtsTriangle * t = key; - GtsTriangle *** p = user_data; - - (void) value; - g_assert (t); - g_assert (p && *p); - **p = t; - (*p)++; -} - -static gboolean are_neighbors_unique (GHashTable *h) -{ - GtsTriangle ** a; - GtsTriangle ** p; - gint i, j, n; /* guint won't work if n == 0 */ - - g_assert (h); - n = g_hash_table_size (h); -#ifdef DEBUG - if (n > 9) - g_warning ("triangle has %d 2-level neighbors", n); -#endif /* DEBUG */ - a = g_malloc(n*sizeof (GtsTriangle *)); - p = a; - g_hash_table_foreach (h, copy_key_to_array, &p); - for (i = 0; i < n - 1; i++) { - g_assert (a[i]); - for (j = i + 1; j < n; j++) { - g_assert (a[j]); - if (a[i] == a[j]) { - g_free (a); - return FALSE; - } - } - } - g_free (a); - return TRUE; -} - -static GHashTable * tri_data_unused_neighbors2 (const tri_data_t * td, - const map_t * map) -{ - GHashTable * h = g_hash_table_new (NULL, NULL); - GSList * li; - - g_assert (td); - g_assert (map); - for (li = td->neighbors; li != NULL; li = li->next) { - GtsTriangle * t2 = li->data; - tri_data_t * td2 = map_lookup (map, t2); - GSList * lj; - - g_assert (td2); - if (!td2->used) { - g_hash_table_insert (h, t2, td2); - for (lj = td2->neighbors; lj != NULL; lj = lj->next) { - GtsTriangle * t3 = lj->data; - tri_data_t * td3 = map_lookup (map, t3); - - g_assert (td3); - if (td3 != td && !td3->used) - g_hash_table_insert (h, t3, td3); - } - } - } - g_assert (are_neighbors_unique (h)); - return h; -} - -#if PRINT_HEAP_ELEMENTS -static void tri_data_print (const tri_data_t * td, FILE * fp) -{ - g_assert (td); - g_assert (fp); - fprintf(fp, "td=%p t=%p used=%d pos=%p key=%f\n", - td, td->t, td->used, td->pos, - td->pos ? td->pos->key : -1.0); -} -#endif /* PRINT_HEAP_ELEMENTS */ - -/* heap_t functions */ - -static gdouble triangle_priority (gpointer item, gpointer data) -{ - GtsTriangle * t = item; - map_t * map = data; - tri_data_t * td; - gdouble k; - - g_assert (t); - g_assert (map); - td = map_lookup (map, t); - g_assert (td); - k = tri_data_num_unused_neighbors2 (td, map); - return k; -} - -#if PRINT_HEAP_ELEMENTS -static void print_heap_element (gpointer data, gpointer user_data) -{ - GtsTriangle * t = data; - map_t * map = user_data; - tri_data_t * td; - - g_assert (t); - g_assert (map); - td = map_lookup (map, t); - g_assert (td); - g_assert (!td->used); - g_assert (td->pos); - tri_data_print (td, stderr); -} -#endif /* PRINT_HEAP_ELEMENTS */ - -static void insert_entry_into_heap (gpointer key, - gpointer value, - gpointer user_data) -{ - GtsTriangle * t = key; - tri_data_t * td = value; - GtsEHeap * heap = user_data; - - g_assert (!td->pos); - td->pos = gts_eheap_insert (heap, t); - g_assert (td->pos); -} - -static heap_t * heap_new (GtsSurface *s) -{ - heap_t * heap; - - g_assert (s); - heap = g_malloc (sizeof (heap_t)); - heap->map = map_new (s); - heap->heap = gts_eheap_new (triangle_priority, heap->map); - g_hash_table_foreach (heap->map->ht, - insert_entry_into_heap, - heap->heap); -#if PRINT_HEAP_ELEMENTS - gts_eheap_foreach (heap->heap, print_heap_element, heap->map); -#endif /* PRINT_HEAP_ELEMENTS */ - return heap; -} - -static void heap_destroy (heap_t * heap) -{ - if (!heap) - return; - map_destroy (heap->map); - gts_eheap_destroy (heap->heap); - g_free (heap); -} - -static gboolean heap_is_empty (const heap_t * heap) -{ - g_assert (heap); - g_assert (heap->heap); - return gts_eheap_size (heap->heap) == 0; -} - -typedef struct { - const heap_t * heap; - double min_key; -} min_key_t; - -static GtsTriangle * heap_top (const heap_t * heap) -{ - GtsTriangle * t; - - g_assert (heap); - g_assert (heap->heap); - t = gts_eheap_top (heap->heap, NULL); - return t; -} - -static void decrease_key (gpointer key, gpointer value, gpointer user_data) -{ - GtsTriangle * t = key; - tri_data_t * td = value; - heap_t *heap = user_data; - gdouble k; - - (void) t; - g_assert (heap); - g_assert (heap->map); - g_assert (heap->heap); - g_assert (td); - g_assert (!td->used); - g_assert (td->pos); - - k = tri_data_num_unused_neighbors2 (td, heap->map); - g_assert (k <= td->pos->key); -#ifdef DEBUG - if (k == td->pos->key) - g_warning ("same key: %f\n", k); -#endif /* DEBUG */ - if (k != td->pos->key) { - g_assert (k < td->pos->key); - g_assert (k >= 0.0); - gts_eheap_decrease_key (heap->heap, td->pos, k); - } -} - -static void heap_remove (heap_t * heap, GtsTriangle * t) -{ - tri_data_t * td; - GHashTable * h; - - g_assert (heap); - g_assert (t); - td = map_lookup (heap->map, t); - g_assert (td); - g_assert (!td->used); - g_assert (td->pos); - td->used = TRUE; - gts_eheap_remove (heap->heap, td->pos); - td->pos = NULL; - - /* fprintf(stderr, "td: %p\n", td); */ - h = tri_data_unused_neighbors2 (td, heap->map); - g_hash_table_foreach (h, decrease_key, heap); - g_hash_table_destroy (h); -} - -/* map_t functions */ - -static gint create_map_entry (gpointer item, gpointer data) -{ - GtsTriangle * t = item; - GHashTable * ht = data; - tri_data_t * td; - - g_assert (t); - g_assert (ht); - td = tri_data_new (t); - g_hash_table_insert (ht, t, td); - return 0; -} - -static void free_map_entry (gpointer key, gpointer value, gpointer user_data) -{ - GtsTriangle * t = key; - tri_data_t * td = value; - - (void) user_data; - g_assert (t); - g_assert (td); - g_assert (td->t == t); - tri_data_destroy (td); -} - -static map_t * map_new (GtsSurface * s) -{ - map_t * map; - - map = g_malloc (sizeof (map_t)); - map->ht = g_hash_table_new (NULL, NULL); - gts_surface_foreach_face (s, create_map_entry, map->ht); - return map; -} - -static void map_destroy (map_t * map) -{ - if (!map) - return; - g_hash_table_foreach (map->ht, free_map_entry, NULL); - g_hash_table_destroy (map->ht); - g_free (map); -} - -static tri_data_t * map_lookup (const map_t * map, GtsTriangle * t) -{ - tri_data_t * td; - - g_assert (map); - g_assert (map->ht); - g_assert (t); - td = g_hash_table_lookup (map->ht, t); - g_assert (td); - g_assert (td->t == t); - return td; -} - -/* other helper functions */ - -static GtsTriangle * find_min_neighbor (heap_t * heap, GtsTriangle * t) -{ - GtsTriangle * min_neighbor = NULL; - gdouble min_key = G_MAXDOUBLE; - tri_data_t * td; - GSList * li; - - g_assert (heap); - g_assert (t); - - td = map_lookup (heap->map, t); - for (li = td->neighbors; li != NULL; li = li->next) { - GtsTriangle * t2 = li->data; - tri_data_t * td2 = map_lookup (heap->map, t2); - gdouble k; - - g_assert (td2); - if (td2->used) - continue; - g_assert (td2->pos); - k = td2->pos->key; - if (k < min_key) { - min_key = k; - min_neighbor = t2; - } - } - return min_neighbor; -} - -static GtsTriangle * find_neighbor_forward (heap_t * heap, - GtsTriangle * t, - GtsVertex ** v1, - GtsVertex ** v2, - GtsVertex ** v3, - gboolean left_turn) -{ - GtsTriangle * neighbor = NULL; - tri_data_t * td; - GSList * li; - - g_assert (heap); - g_assert (t); - g_assert (v1 && v2 && v3); - g_assert (vertices_are_unique (*v1, *v2, *v3)); - - td = map_lookup (heap->map, t); - g_assert (td); - for (li = td->neighbors; li && !neighbor; li = li->next) { - GtsTriangle * t2 = li->data; - tri_data_t * td2 = map_lookup (heap->map, t2); - GtsVertex * v4, * v5, * v6; - - g_assert (td2); - if (t2 == t || td2->used) - continue; - gts_triangle_vertices (t2, &v4, &v5, &v6); - if (left_turn) { - if (!vertices_match (*v1, *v3, NULL, &v4, &v5, &v6)) - continue; - } else { - if (!vertices_match (*v3, *v2, NULL, &v4, &v5, &v6)) - continue; - } - neighbor = t2; - *v1 = v4; - *v2 = v5; - *v3 = v6; - } - return neighbor; -} - -static GtsTriangle * find_neighbor_backward (heap_t * heap, - GtsTriangle * t, - GtsVertex ** v1, - GtsVertex ** v2, - GtsVertex ** v3, - gboolean left_turn) -{ - GtsTriangle * neighbor = NULL; - tri_data_t * td; - GSList * li; - - g_assert (heap); - g_assert (t); - g_assert (v1 && v2 && v3); - g_assert (vertices_are_unique (*v1, *v2, *v3)); - - td = map_lookup (heap->map, t); - g_assert (td); - for (li = td->neighbors; li && !neighbor; li = li->next) { - GtsTriangle * t2 = li->data; - tri_data_t * td2 = map_lookup (heap->map, t2); - GtsVertex * v4, * v5, * v6; - - g_assert (td2); - if (t2 == t || td2->used) - continue; - gts_triangle_vertices (t2, &v4, &v5, &v6); - if (left_turn) { - if (!vertices_match (NULL, *v2, *v1, &v4, &v5, &v6)) - continue; - } else if (!vertices_match(*v1, NULL, *v2, &v4, &v5, &v6)) - continue; - neighbor = t2; - *v1 = v4; - *v2 = v5; - *v3 = v6; - } - return neighbor; -} - -static GSList * grow_strip_forward (heap_t * heap, - GSList * strip, - GtsTriangle * t, - GtsVertex * v1, - GtsVertex * v2, - GtsVertex * v3) -{ - gboolean left_turn; - - g_assert (heap); - g_assert (g_slist_length(strip) == 2); - g_assert (t); - g_assert (v1 && v2 && v3); - g_assert (vertices_are_unique (v1, v2, v3)); - - left_turn = TRUE; - while ((t = find_neighbor_forward (heap, t, &v1, &v2, &v3, - left_turn)) != NULL) { - heap_remove (heap, t); - strip = g_slist_prepend (strip, t); - left_turn = !left_turn; - } - return strip; -} - -static GSList * grow_strip_backward (heap_t * heap, - GSList * strip, - GtsTriangle * t, - GtsVertex * v1, - GtsVertex * v2, - GtsVertex * v3) -{ - /* we have to make sure we add an even number of triangles */ - GtsTriangle * t2; - - g_assert (heap); - g_assert (g_slist_length(strip) >= 2); - g_assert (t); - g_assert (v1 && v2 && v3); - g_assert (vertices_are_unique (v1, v2, v3)); - - while ((t2 = find_neighbor_backward (heap, t, &v1, &v2, &v3, - FALSE)) != NULL - && (t = find_neighbor_backward (heap, t2, &v1, &v2, &v3, - TRUE)) != NULL) { - heap_remove (heap, t2); - heap_remove (heap, t); - strip = g_slist_prepend (strip, t2); - strip = g_slist_prepend (strip, t); - } - return strip; -} - -static gboolean find_right_turn (GtsVertex ** v1, - GtsVertex ** v2, - GtsVertex ** v3, - GtsVertex ** v4, - GtsVertex ** v5, - GtsVertex ** v6) -{ - GtsVertex * v; - - g_assert (v1 && v2 && v3); - g_assert (v4 && v5 && v6); - g_assert (vertices_are_unique (*v1, *v2, *v3)); - g_assert (vertices_are_unique (*v4, *v5, *v6)); - g_assert (num_shared_vertices (*v1, *v2, *v3, *v4, *v5, *v6) == 2); - - v = non_shared_vertex1 (*v1, *v2, *v3, *v4, *v5, *v6); - match_vertex (v, v1, v2, v3); - match_vertex (*v3, v4, v5, v6); - - g_assert (v1 && v2 && v3); - g_assert (v4 && v5 && v6); - g_assert (*v4 == *v3); - - if (*v5 == *v2) { - g_assert (vertices_are_unique (*v1, *v2, *v3)); - g_assert (vertices_are_unique (*v4, *v5, *v6)); - g_assert (num_shared_vertices (*v1, *v2, *v3, - *v4, *v5, *v6) == 2); - return TRUE; - } else { -#ifdef DEBUG - g_warning ("couldn't find a right turn"); -#endif /* DEBUG */ - return FALSE; - } -} - -/** - * gts_surface_strip: - * @s: a #GtsSurface. - * - * Decompose @s into triangle strips for fast-rendering. - * - * Returns: a list of triangle strips containing all the triangles of @s. - * A triangle strip is itself a list of successive triangles having one edge - * in common. - */ -GSList * gts_surface_strip (GtsSurface *s) -{ - GSList * strips = NULL; - heap_t * heap; - - g_return_val_if_fail (s != NULL, NULL); - - heap = heap_new (s); - while (!heap_is_empty (heap)) { - GtsTriangle * t1, * t2; - GtsVertex * v1, * v2, * v3, * v4, * v5, * v6; - GSList * strip = NULL; - - /* remove heap top */ - t1 = heap_top (heap); - g_assert (t1); - heap_remove (heap, t1); - - /* start a new strip */ - strip = g_slist_prepend (strip, t1); - - /* find second triangle */ - t2 = find_min_neighbor (heap, t1); - if (t2) { - g_assert (t2 != t1); - - /* find right turn */ - gts_triangle_vertices (t1, &v1, &v2, &v3); - gts_triangle_vertices (t2, &v4, &v5, &v6); - if (find_right_turn (&v1, &v2, &v3, &v4, &v5, &v6)) { - heap_remove (heap, t2); - strip = g_slist_prepend (strip, t2); - - /* grow strip forward */ - strip = grow_strip_forward (heap, strip, t2, v4, v5, v6); - - strip = g_slist_reverse (strip); - - /* grow strip backward */ - strip = grow_strip_backward (heap, strip, t1, v1, v2, v3); - } - } - strips = g_slist_prepend (strips, strip); - } - strips = g_slist_reverse (strips); - heap_destroy (heap); - - return strips; -} Index: trunk/src_3rd/gts/object.c =================================================================== --- trunk/src_3rd/gts/object.c (revision 6802) +++ trunk/src_3rd/gts/object.c (nonexistent) @@ -1,345 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include "gts.h" -#include "gts-private.h" - -static GHashTable * class_table = NULL; - -static void gts_object_class_init (GtsObjectClass * klass, - GtsObjectClass * parent_class) -{ - if (parent_class) { - gts_object_class_init (klass, parent_class->parent_class); - if (parent_class->info.class_init_func) - (*parent_class->info.class_init_func) (klass); - } -} - -/** - * gts_object_class_new: - * @parent_class: a #GtsObjectClass. - * @info: a #GtsObjectClassInfo, description of the new class to create. - * - * Returns: a new #GtsObjectClass derived from @parent_class and described by - * @info. - */ -gpointer gts_object_class_new (GtsObjectClass * parent_class, - GtsObjectClassInfo * info) -{ - GtsObjectClass * klass; - - g_return_val_if_fail (info != NULL, NULL); - g_return_val_if_fail (parent_class == NULL || - info->object_size >= parent_class->info.object_size, - NULL); - g_return_val_if_fail (parent_class == NULL || - info->class_size >= parent_class->info.class_size, - NULL); - - klass = g_malloc0 (info->class_size); - klass->info = *info; - klass->parent_class = parent_class; - gts_object_class_init (klass, klass); - - if (!class_table) - class_table = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_insert (class_table, klass->info.name, klass); - - return klass; -} - -/** - * gts_object_class_from_name: - * @name: the name of a #GtsObjectClass. - * - * Returns: the #GtsObjectClass with name @name or %NULL if it hasn't been - * instantiated yet. - */ -GtsObjectClass * gts_object_class_from_name (const gchar * name) -{ - g_return_val_if_fail (name != NULL, NULL); - - if (!class_table) - return NULL; - return g_hash_table_lookup (class_table, name); -} - -static void object_destroy (GtsObject * object) -{ -#ifdef DEBUG_IDENTITY -#ifdef DEBUG_LEAKS - fprintf (stderr, "destroy %s %p->%d\n", - object->klass->info.name, - object, - id (object)); -#endif - id_remove (object); -#endif - object->klass = NULL; - g_free (object); -} - -static void object_clone (GtsObject * clone, GtsObject * object) -{ - memcpy (clone, object, object->klass->info.object_size); - clone->reserved = NULL; -} - -static void object_class_init (GtsObjectClass * klass) -{ - klass->clone = object_clone; - klass->destroy = object_destroy; - klass->read = NULL; - klass->write = NULL; - klass->color = NULL; - klass->attributes = NULL; -} - -static void object_init (GtsObject * object) -{ - object->reserved = NULL; - object->flags = 0; -} - -/** - * gts_object_class: - * - * Returns: the #GtsObjectClass. - */ -GtsObjectClass * gts_object_class (void) -{ - static GtsObjectClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo object_info = { - "GtsObject", - sizeof (GtsObject), - sizeof (GtsObjectClass), - (GtsObjectClassInitFunc) object_class_init, - (GtsObjectInitFunc) object_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (NULL, &object_info); - } - - return klass; -} - -/** - * gts_object_check_cast: - * @object: a #GtsObject. - * @klass: a #GtsObjectClass. - * - * Returns: @object while emitting warnings if @object is not of class @klass. - */ -gpointer gts_object_check_cast (gpointer object, - gpointer klass) -{ - if (!object) { - g_warning ("invalid cast from (NULL) pointer to `%s'", - GTS_OBJECT_CLASS (klass)->info.name); - return object; - } - if (!((GtsObject *) object)->klass) { - g_warning ("invalid unclassed pointer in cast to `%s'", - GTS_OBJECT_CLASS (klass)->info.name); - return object; - } - if (!gts_object_is_from_class (object, klass)) { - g_warning ("invalid cast from `%s' to `%s'", - ((GtsObject *) object)->klass->info.name, - GTS_OBJECT_CLASS (klass)->info.name); - return object; - } - return object; -} - -/** - * gts_object_class_check_cast: - * @klass: a #GtsObjectClass. - * @from: a #GtsObjectClass. - * - * Returns: @klass while emitting warnings if @klass is not derived from - * @from. - */ -gpointer gts_object_class_check_cast (gpointer klass, - gpointer from) -{ - if (!klass) { - g_warning ("invalid cast from (NULL) pointer to `%s'", - GTS_OBJECT_CLASS (from)->info.name); - return klass; - } - if (!gts_object_class_is_from_class (klass, from)) { - g_warning ("invalid cast from `%s' to `%s'", - GTS_OBJECT_CLASS (klass)->info.name, - GTS_OBJECT_CLASS (from)->info.name); - return klass; - } - return klass; -} - -/** - * gts_object_init: - * @object: a #GtsObject. - * @klass: a #GtsObjectClass. - * - * Calls the init method of @klass with @object as argument. This is done - * recursively in the correct order (from the base class to the top). You - * should rarely need this function as it is called automatically by the - * constructor for each class. - */ -void gts_object_init (GtsObject * object, GtsObjectClass * klass) -{ - GtsObjectClass * parent_class; - - g_return_if_fail (object != NULL); - g_return_if_fail (klass != NULL); - - parent_class = klass->parent_class; - if (parent_class) - gts_object_init (object, parent_class); - if (klass->info.object_init_func) - (*klass->info.object_init_func) (object); -} - -/** - * gts_object_new: - * @klass: a #GtsObjectClass. - * - * Returns: a new initialized object of class @klass. - */ -GtsObject * gts_object_new (GtsObjectClass * klass) -{ - GtsObject * object; - - g_return_val_if_fail (klass != NULL, NULL); - - object = g_malloc0 (klass->info.object_size); - object->klass = klass; - gts_object_init (object, klass); - -#ifdef DEBUG_IDENTITY - id_insert (object); -#ifdef DEBUG_LEAKS - fprintf (stderr, "new %s %p->%d\n", klass->info.name, - object, - id (object)); -#endif -#endif - - return object; -} - -/** - * gts_object_clone: - * @object: a #GtsObject. - * - * Calls the clone method of @object. The call to this function will fail - * if no clone method exists for the given object. - * - * Returns: a new object clone of @object. - */ -GtsObject * gts_object_clone (GtsObject * object) -{ - GtsObject * clone; - - g_return_val_if_fail (object != NULL, NULL); - g_return_val_if_fail (object->klass->clone, NULL); - - clone = g_malloc0 (object->klass->info.object_size); - clone->klass = object->klass; - object_init (clone); - (* object->klass->clone) (clone, object); - -#ifdef DEBUG_IDENTITY - id_insert (clone); -#ifdef DEBUG_LEAKS - fprintf (stderr, "clone %s %p->%d\n", clone->klass->info.name, - clone, - id (clone)); -#endif -#endif - - return clone; -} - -/** - * gts_object_destroy: - * @object: a #GtsObject. - * - * Calls the destroy method of @object, freeing all memory allocated for it. - */ -void gts_object_destroy (GtsObject * object) -{ - g_assert (object->klass->destroy); - GTS_OBJECT_SET_FLAGS (object, GTS_DESTROYED); - (* object->klass->destroy) (object); -} - -/** - * gts_object_reset_reserved: - * @object: a #GtsObject. - * - * Reset the reserved field of @object. - */ -void gts_object_reset_reserved (GtsObject * object) -{ - g_return_if_fail (object != NULL); - - object->reserved = NULL; -} - -/** - * gts_object_attributes: - * @object: a #GtsObject. - * @from: a #GtsObject. - * - * Calls the attributes() method of @object using @from as source. - */ -void gts_object_attributes (GtsObject * object, GtsObject * from) -{ - g_return_if_fail (object != NULL); - - if (object->klass->attributes) - (* object->klass->attributes) (object, from); -} - -static void free_class (gchar * name, GtsObjectClass * klass) -{ - g_free (klass); -} - -/** - * gts_finalize: - * - * Free all the memory allocated by the object system of GTS. No other - * GTS function can be called after this function has been called. - */ -void gts_finalize (void) -{ - if (class_table) { - g_hash_table_foreach (class_table, (GHFunc) free_class, NULL); - g_hash_table_destroy (class_table); - class_table = NULL; - } -} Index: trunk/src_3rd/gts/refine.c =================================================================== --- trunk/src_3rd/gts/refine.c (revision 6802) +++ trunk/src_3rd/gts/refine.c (nonexistent) @@ -1,418 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include "gts.h" - -/** - * gts_vertex_encroaches_edge: - * @v: a #GtsVertex. - * @e: a #GtsEdge. - * - * Returns: %TRUE if @v is strictly contained in the diametral circle of @e, - * %FALSE otherwise. - */ -gboolean gts_vertex_encroaches_edge (GtsVertex * v, GtsEdge * e) -{ - GtsPoint * p, * p1, * p2; - - g_return_val_if_fail (v != NULL, FALSE); - g_return_val_if_fail (e != NULL, FALSE); - - p = GTS_POINT (v); - p1 = GTS_POINT (GTS_SEGMENT (e)->v1); - p2 = GTS_POINT (GTS_SEGMENT (e)->v2); - - if ((p1->x - p->x)*(p2->x - p->x) + (p1->y - p->y)*(p2->y - p->y) < 0.0) - return TRUE; - return FALSE; -} - -/** - * gts_edge_is_encroached: - * @e: a #GtsEdge. - * @s: a #GtsSurface describing a (constrained) Delaunay triangulation. - * @encroaches: a #GtsEncroachFunc. - * @data: user data to be passed to @encroaches. - * - * Returns: a #GtsVertex belonging to @s and encroaching upon @e - * (as defined by @encroaches) or %NULL if there is none. - */ -GtsVertex * gts_edge_is_encroached (GtsEdge * e, - GtsSurface * s, - GtsEncroachFunc encroaches, - gpointer data) -{ - GSList * i; - - g_return_val_if_fail (e != NULL, NULL); - g_return_val_if_fail (s != NULL, NULL); - g_return_val_if_fail (encroaches != NULL, NULL); - - 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 ((* encroaches) (v, e, s, data)) - return v; - } - i = i->next; - } - - return NULL; -} - -#define ALREADY_ENCROACHED(c) (GTS_OBJECT (c)->reserved) - -static void vertex_encroaches (GtsVertex * v, - GtsSurface * surface, - GtsFifo * encroached, - GtsEncroachFunc encroaches, - gpointer data) -{ - GSList * triangles, * i; - - g_return_if_fail (v != NULL); - g_return_if_fail (surface != NULL); - g_return_if_fail (encroached != NULL); - g_return_if_fail (encroaches != NULL); - - i = triangles = gts_vertex_triangles (v, NULL); - while (i) { - GtsFace * f = i->data; - if (GTS_IS_FACE (f) && gts_face_has_parent_surface (f, surface)) { - GtsEdge * e = gts_triangle_edge_opposite (i->data, v); - if (!ALREADY_ENCROACHED (e) && - GTS_IS_CONSTRAINT (e) && - (* encroaches) (v, e, surface, data)) { - gts_fifo_push (encroached, e); - ALREADY_ENCROACHED (e) = encroached; - } - } - i = i->next; - } - g_slist_free (triangles); -} - -static void make_encroached_fifo (GtsEdge * e, gpointer * datas) -{ - GtsFifo * fifo = datas[0]; - GtsSurface * s = datas[1]; - GtsEncroachFunc encroaches = (GtsEncroachFunc) datas[2]; - gpointer data = datas[3]; - - if (GTS_IS_CONSTRAINT (e) && - gts_edge_is_encroached (e, s, encroaches, data)) { - gts_fifo_push (fifo, e); - ALREADY_ENCROACHED (e) = fifo; - } -} - -#define SQUARE_ROOT_TWO 1.41421356237309504880168872420969807856967187 -#define DISTANCE_2D(v1, v2) (sqrt ((GTS_POINT (v2)->x - GTS_POINT (v1)->x)*\ - (GTS_POINT (v2)->x - GTS_POINT (v1)->x) +\ - (GTS_POINT (v2)->y - GTS_POINT (v1)->y)*\ - (GTS_POINT (v2)->y - GTS_POINT (v1)->y))) - -/* finds where to split the given edge to avoid infinite cycles. (see - Shewchuk's thesis for details */ -static GtsVertex * split_edge (GtsEdge * e, - GtsSurface * surface) -{ - GSList * i = e->triangles; - GtsEdge * c = NULL; - - /* look for constraints touching e */ - while (i && !c) { - GtsTriangle * t = i->data; - if (GTS_IS_FACE (t) && - gts_face_has_parent_surface (GTS_FACE (t), surface)) { - GtsEdge * e1, * e2; - if (t->e1 == e) { e1 = t->e2; e2 = t->e3; } - else if (t->e2 == e) { e1 = t->e1; e2 = t->e3; } - else { e1 = t->e1; e2 = t->e2; } - if (GTS_IS_CONSTRAINT (e1) && !GTS_IS_CONSTRAINT (e2)) - c = e1; - else if (GTS_IS_CONSTRAINT (e2) && !GTS_IS_CONSTRAINT (e1)) - c = e2; - } - i = i->next; - } - if (c) { - /* use power of two concentric shells */ - GtsVertex * v1 = GTS_SEGMENT (e)->v1; - GtsVertex * v2 = GTS_SEGMENT (e)->v2; - gdouble l = DISTANCE_2D (v1, v2); - gdouble nearestpower = 1., split; - - while (l > SQUARE_ROOT_TWO*nearestpower) - nearestpower *= 2.; - while (l < SQUARE_ROOT_TWO*nearestpower/2.) - nearestpower /= 2.; - split = nearestpower/l/2.; - - if (GTS_SEGMENT (c)->v1 == v2 || GTS_SEGMENT (c)->v2 == v2) - split = 1. - split; - return gts_vertex_new (surface->vertex_class, - (1. - split)*GTS_POINT (v1)->x + - split*GTS_POINT (v2)->x, - (1. - split)*GTS_POINT (v1)->y + - split*GTS_POINT (v2)->y, - (1. - split)*GTS_POINT (v1)->z + - split*GTS_POINT (v2)->z); - } - else - return gts_segment_midvertex (GTS_SEGMENT (e), surface->vertex_class); -} - -static gint split_encroached (GtsSurface * surface, - GtsFifo * encroached, - gint steiner_max, - GtsEncroachFunc encroaches, - gpointer data) -{ - GtsSegment * s; - - while (steiner_max-- != 0 && (s = gts_fifo_pop (encroached))) { - GtsVertex * v = split_edge (GTS_EDGE (s), surface); - GtsFace * boundary = gts_edge_is_boundary (GTS_EDGE (s), surface); - GtsFace * f = boundary; -#if 1 - GtsEdge * e1 = GTS_EDGE (gts_object_clone (GTS_OBJECT (s))); - GtsEdge * e2 = GTS_EDGE (gts_object_clone (GTS_OBJECT (s))); - - GTS_SEGMENT (e1)->v1 = s->v1; - s->v1->segments = g_slist_prepend (s->v1->segments, e1); - GTS_SEGMENT (e1)->v2 = v; - v->segments = g_slist_prepend (v->segments, e1); - - GTS_SEGMENT (e2)->v1 = v; - v->segments = g_slist_prepend (v->segments, e2); - GTS_SEGMENT (e2)->v2 = s->v2; - s->v2->segments = g_slist_prepend (s->v2->segments, e2); -#else - GtsEdge * e1 = gts_edge_new (GTS_EDGE_CLASS (GTS_OBJECT (s)->klass), - s->v1, v); - GtsEdge * e2 = gts_edge_new (GTS_EDGE_CLASS (GTS_OBJECT (s)->klass), - v, s->v2); -#endif - - GTS_OBJECT (s)->klass = GTS_OBJECT_CLASS (surface->edge_class); - - if (f == NULL) - g_assert ((f = gts_edge_has_parent_surface (GTS_EDGE (s), surface))); - g_assert (gts_delaunay_add_vertex_to_face (surface, v, f) == NULL); - - if (boundary) - gts_object_destroy (GTS_OBJECT (s)); - - vertex_encroaches (v, surface, encroached, encroaches, data); - - if (gts_edge_is_encroached (e1, surface, encroaches, data)) { - gts_fifo_push (encroached, e1); - ALREADY_ENCROACHED (e1) = encroached; - } - if (gts_edge_is_encroached (e2, surface, encroaches, data)) { - gts_fifo_push (encroached, e2); - ALREADY_ENCROACHED (e2) = encroached; - } - } - - return steiner_max; -} - -/** - * gts_delaunay_conform: - * @surface: a #GtsSurface describing a constrained Delaunay triangulation. - * @steiner_max: maximum number of Steiner points. - * @encroaches: a #GtsEncroachFunc. - * @data: user-data to pass to @encroaches. - * - * Recursively split constraints of @surface which are encroached by - * vertices of @surface (see Shewchuk 96 for details). The split - * constraints are destroyed and replaced by a set of new constraints - * of the same class. If gts_vertex_encroaches_edge() is used for - * @encroaches, the resulting surface will be Delaunay conforming. - * - * If @steiner_max is positive or nul, the recursive splitting - * procedure will stop when this maximum number of Steiner points is - * reached. In that case the resulting surface will not necessarily be - * Delaunay conforming. - * - * Returns: the number of remaining encroached edges. If @steiner_max - * is set to a negative value and gts_vertex_encroaches_edge() is used - * for @encroaches this should always be zero. - */ -guint gts_delaunay_conform (GtsSurface * surface, - gint steiner_max, - GtsEncroachFunc encroaches, - gpointer data) -{ - GtsFifo * encroached; - gpointer datas[4]; - guint encroached_number; - - g_return_val_if_fail (surface != NULL, 0); - g_return_val_if_fail (surface != NULL, 0); - g_return_val_if_fail (encroaches != NULL, 0); - - datas[0] = encroached = gts_fifo_new (); - datas[1] = surface; - datas[2] = encroaches; - datas[3] = data; - gts_surface_foreach_edge (surface, (GtsFunc) make_encroached_fifo, datas); - - split_encroached (surface, - encroached, - steiner_max, - encroaches, data); - gts_fifo_foreach (encroached, (GtsFunc) gts_object_reset_reserved, NULL); - encroached_number = gts_fifo_size (encroached); - gts_fifo_destroy (encroached); - return encroached_number; -} - -#define EHEAP_PAIR(f) (GTS_OBJECT (f)->reserved) - -static void heap_surface_add_face (GtsSurface * s, GtsFace * f) -{ - GtsEHeap * heap = GTS_OBJECT (s)->reserved; - gdouble key = gts_eheap_key (heap, f); - - if (key != 0.) - EHEAP_PAIR (f) = gts_eheap_insert_with_key (heap, f, key); - - if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass->parent_class)->add_face) - (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass->parent_class)->add_face) - (s, f); -} - -static void heap_surface_remove_face (GtsSurface * s, GtsFace * f) -{ - GtsEHeap * heap = GTS_OBJECT (s)->reserved; - - if (EHEAP_PAIR (f)) - gts_eheap_remove (heap, EHEAP_PAIR (f)); - - if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass->parent_class)->remove_face) - (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass->parent_class)->remove_face) - (s, f); -} - -static void heap_surface_class_init (GtsSurfaceClass * klass) -{ - klass->add_face = heap_surface_add_face; - klass->remove_face = heap_surface_remove_face; -} - -static GtsObjectClass * heap_surface_class_new (GtsObjectClass * parent_class) -{ - GtsObjectClassInfo heap_surface_info; - - heap_surface_info = parent_class->info; - heap_surface_info.class_init_func = (GtsObjectClassInitFunc) - heap_surface_class_init; - return gts_object_class_new (parent_class, - &heap_surface_info); -} - -static void make_face_heap (GtsFace * f, GtsEHeap * heap) -{ - gdouble key = gts_eheap_key (heap, f); - - if (key != 0.) - EHEAP_PAIR (f) = gts_eheap_insert_with_key (heap, f, key); -} - -/** - * gts_delaunay_refine: - * @surface: a #GtsSurface describing a conforming Delaunay triangulation. - * @steiner_max: maximum number of Steiner points. - * @encroaches: a #GtsEncroachFunc. - * @encroach_data: user-data to pass to @encroaches. - * @cost: a #GtsKeyFunc used to sort the faces during refinement. - * @cost_data: user-data to pass to @cost. - * - * An implementation of the refinement algorithm described in Ruppert - * (1995) and Shewchuk (1996). - * - * Returns: the number of unrefined faces of @surface left. Should be zero - * if @steiner_max is set to a negative value. - */ -guint gts_delaunay_refine (GtsSurface * surface, - gint steiner_max, - GtsEncroachFunc encroaches, - gpointer encroach_data, - GtsKeyFunc cost, - gpointer cost_data) -{ - GtsObjectClass * heap_surface_class; - GtsObjectClass * original_class; - GtsEHeap * heap; - GtsFifo * encroached; - GtsFace * f; - guint unrefined_number; - - g_return_val_if_fail (surface != NULL, 0); - g_return_val_if_fail (encroaches != NULL, 0); - g_return_val_if_fail (cost != NULL, 0); - - original_class = GTS_OBJECT (surface)->klass; - heap_surface_class = heap_surface_class_new (original_class); - GTS_OBJECT (surface)->klass = heap_surface_class; - - heap = gts_eheap_new (cost, cost_data); - gts_surface_foreach_face (surface, (GtsFunc) make_face_heap, heap); - encroached = gts_fifo_new (); - - GTS_OBJECT (surface)->reserved = heap; - - while (steiner_max-- != 0 && (f = gts_eheap_remove_top (heap, NULL))) { - GtsVertex * c = - GTS_VERTEX (gts_triangle_circumcircle_center (GTS_TRIANGLE (f), - GTS_POINT_CLASS (surface->vertex_class))); - EHEAP_PAIR (f) = NULL; - g_assert (c != NULL); - g_assert (gts_delaunay_add_vertex (surface, c, f) == NULL); - - vertex_encroaches (c, surface, encroached, encroaches, encroach_data); - if (!gts_fifo_is_empty (encroached)) { - gts_delaunay_remove_vertex (surface, c); - steiner_max = split_encroached (surface, - encroached, - steiner_max, - encroaches, - encroach_data); - } - } - - unrefined_number = gts_eheap_size (heap); - gts_eheap_foreach (heap, (GFunc) gts_object_reset_reserved, NULL); - gts_eheap_destroy (heap); - - gts_fifo_foreach (encroached, (GtsFunc) gts_object_reset_reserved, NULL); - gts_fifo_destroy (encroached); - - GTS_OBJECT (surface)->klass = original_class; - GTS_OBJECT (surface)->reserved = NULL; - g_free (heap_surface_class); - - return unrefined_number; -} Index: trunk/src_3rd/gts/cdt.c =================================================================== --- trunk/src_3rd/gts/cdt.c (revision 6802) +++ trunk/src_3rd/gts/cdt.c (nonexistent) @@ -1,1173 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include - - -#include -#include "gts.h" - -#ifdef USE_SURFACE_BTREE - -static gint find_closest (GtsTriangle * t, gpointer value, gpointer * data) -{ - guint * ns = data[2]; - guint * n = data[3]; - - if (*n >= *ns) - return TRUE; - else { - gdouble * dmin = data[0]; - gpointer * closest = data[1]; - GtsPoint * p = data[4]; - - if (gts_triangle_orientation (t) > 0.) { - GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1); - gdouble d = (p->x - p1->x)*(p->x - p1->x) + (p->y - p1->y)*(p->y - p1->y); - - if (d < *dmin) { - *dmin = d; - *closest = t; - } - (*n)++; - } - } - return FALSE; -} - -/* select the face closest to @p among n^1/3 randomly picked faces - * of @surface */ -static GtsFace * closest_face (GtsSurface * s, GtsPoint * p) -{ - guint n = 0, nt, ns; - gdouble dmin = G_MAXDOUBLE; - GtsFace * closest = NULL; - gpointer data[5]; - - nt = gts_surface_face_number (s); - if (!nt) - return NULL; - ns = exp (log ((gdouble) nt)/3.); - - data[0] = &dmin; - data[1] = &closest; - data[2] = &ns; - data[3] = &n; - data[4] = p; - g_tree_traverse (s->faces, (GTraverseFunc) find_closest, G_IN_ORDER, data); - - return closest; -} - -#else /* not USE_SURFACE_BTREE */ - -typedef struct _SFindClosest SFindClosest; - -struct _SFindClosest { - gdouble dmin; - GtsFace *closest; - GtsPoint * p; - gint stop; -}; - -# if GLIB_CHECK_VERSION(2,4,0) -/* finally, with g_hash_table_find we are able to stop iteration over the hash - table in the middle */ - -static gboolean find_closest (gpointer key, gpointer value, gpointer user_data) -{ - SFindClosest * data = (SFindClosest *) user_data; - GtsFace * f = GTS_FACE (value); - - if (gts_triangle_orientation (GTS_TRIANGLE (f)) > 0.) { - GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (GTS_TRIANGLE (f)->e1)->v1); - gdouble d = ((data->p->x - p1->x)*(data->p->x - p1->x) + - (data->p->y - p1->y)*(data->p->y - p1->y)); - - if (d < data->dmin) { - data->dmin = d; - data->closest = f; - } - } - data->stop--; - return !(data->stop > 0); -} - -static GtsFace * closest_face (GtsSurface * s, GtsPoint * p) -{ - SFindClosest fc; - - fc.dmin = G_MAXDOUBLE; - fc.closest = NULL; - fc.p = p; - fc.stop = (gint) exp (log ((gdouble) g_hash_table_size (s->faces))/3.); - g_hash_table_find (s->faces, find_closest, &fc); - - return fc.closest; -} - -# else /* VERSION < 2.4.0 */ - -static void -find_closest (gpointer key, gpointer value, gpointer user_data) -{ - SFindClosest * data = (SFindClosest *) user_data; - GtsFace * f = GTS_FACE (value); - - if (gts_triangle_orientation (GTS_TRIANGLE (f)) > 0.) { - GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (GTS_TRIANGLE (f)->e1)->v1); - gdouble d = ((data->p->x - p1->x)*(data->p->x - p1->x) + - (data->p->y - p1->y)*(data->p->y - p1->y)); - - if (d < data->dmin) { - data->dmin = d; - data->closest = f; - } - } - data->stop--; -} - -/* select the face closest to @p among n^1/3 randomly picked faces - * of @surface */ -static GtsFace * closest_face (GtsSurface * s, GtsPoint * p) -{ - SFindClosest fc; - - if (!g_hash_table_size (s->faces)) - return NULL; - - fc.dmin = G_MAXDOUBLE; - fc.closest = NULL; - fc.p = p; - fc.stop = (gint) exp (log ((gdouble) g_hash_table_size (s->faces))/3.); - g_hash_table_foreach (s->faces, find_closest, &fc); - return fc.closest; -} -# endif /* VERSION < 2.4.0 */ -#endif /* not USE_SURFACE_BTREE */ - -/* returns the face belonging to @surface and neighbor of @f via @e */ -static GtsFace * neighbor (GtsFace * f, - GtsEdge * e, - GtsSurface * surface) -{ - GSList * i = e->triangles; - GtsTriangle * t = GTS_TRIANGLE (f); - - while (i) { - GtsTriangle * t1 = i->data; - if (t1 != t && - GTS_IS_FACE (t1) && - gts_face_has_parent_surface (GTS_FACE (t1), surface)) - return GTS_FACE (t1); - i = i->next; - } - return NULL; -} - -/* given a triangle @t and a segment s (@o -> @p). - @o must be in @t. Returns the - edge of @t which is intersected by s or %NULL if @p is also - contained in @t (on_summit is set to %FALSE) or if s intersects @t - exactly on one of its summit (on_summit is set to %TRUE). */ -static GtsEdge * triangle_next_edge (GtsTriangle * t, - GtsPoint * o, GtsPoint * p, - gboolean * on_summit) -{ - GtsVertex * v1, * v2, * v3; - GtsEdge * e1, * e2, * e3; - gdouble orient = 0.0; - - gts_triangle_vertices_edges (t, NULL, - &v1, &v2, &v3, - &e1, &e2, &e3); - - *on_summit = FALSE; - orient = gts_point_orientation (o, GTS_POINT (v1), p); - if (orient > 0.0) { - orient = gts_point_orientation (o, GTS_POINT (v2), p); - if (orient > 0.0) { - if (gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p) >= 0.0) - return NULL; - return e2; - } - if (orient < 0.0) { - if (gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), p) >= 0.0) - return NULL; - return e1; - } - if (gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), p) < 0.0) - *on_summit = TRUE; - return NULL; - } - - if (orient < 0.0) { - orient = gts_point_orientation (o, GTS_POINT (v3), p); - if (orient > 0.0) { - if (gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), p) >= 0.0) - return NULL; - return e3; - } - if (orient < 0.0) { - if (gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p) >= 0.0) - return NULL; - return e2; - } - if (gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), p) < 0.0) - *on_summit = TRUE; - return NULL; - } - - if (gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p) < 0.0) - return e2; - if (gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), p) < 0.0) - *on_summit = TRUE; - return NULL; -} - -static void triangle_barycenter (GtsTriangle * t, GtsPoint * b) -{ - GtsPoint * p = GTS_POINT (gts_triangle_vertex (t)); - b->x = (p->x + - GTS_POINT (GTS_SEGMENT(t->e1)->v1)->x + - GTS_POINT (GTS_SEGMENT(t->e1)->v2)->x)/3.; - b->y = (p->y + - GTS_POINT (GTS_SEGMENT(t->e1)->v1)->y + - GTS_POINT (GTS_SEGMENT(t->e1)->v2)->y)/3.; -} - -static GtsFace * point_locate (GtsPoint * o, - GtsPoint * p, - GtsFace * f, - GtsSurface * surface) -{ - GtsEdge * prev; - gboolean on_summit; - GtsVertex * v1, * v2, * v3; - GtsEdge * e2, * e3; - - prev = triangle_next_edge (GTS_TRIANGLE (f), o, p, &on_summit); - - if (!prev) { - GtsFace * f1; - - if (!on_summit) - return f; /* p is inside f */ - - /* s intersects f exactly on a summit: restarts from a neighbor of f */ - if ((f1 = neighbor (f, GTS_TRIANGLE (f)->e1, surface)) || - (f1 = neighbor (f, GTS_TRIANGLE (f)->e2, surface)) || - (f1 = neighbor (f, GTS_TRIANGLE (f)->e3, surface))) { - triangle_barycenter (GTS_TRIANGLE (f1), o); - return point_locate (o, p, f1, surface); - } - return NULL; - } - - f = neighbor (f, prev, surface); - if (f) - gts_triangle_vertices_edges (GTS_TRIANGLE (f), prev, - &v1, &v2, &v3, &prev, &e2, &e3); - while (f) { - gdouble orient = gts_point_orientation (o, GTS_POINT (v3), p); - - if (orient < 0.0) { - if (gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p) >= 0.0) - return f; /* p is inside f */ - f = neighbor (f, e2, surface); - prev = e2; - v1 = v3; - } - else if (orient > 0.0) { - if (gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), p) >= 0.0) - return f; /* p is inside f */ - f = neighbor (f, e3, surface); - prev = e3; - v2 = v3; - } - else { - GtsFace * f1; - - if (gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p) >= 0.0) - return f; /* p is inside f */ - - /* s intersects f exactly on v3: restarts from a neighbor of f */ - if ((f1 = neighbor (f, e2, surface)) || - (f1 = neighbor (f, e3, surface))) { - triangle_barycenter (GTS_TRIANGLE (f1), o); - return point_locate (o, p, f1, surface); - } - return NULL; - } - /* update e2, e3, v3 for the new triangle */ - if (f) { - if (prev == GTS_TRIANGLE (f)->e1) { - e2 = GTS_TRIANGLE (f)->e2; e3 = GTS_TRIANGLE (f)->e3; - } - else if (prev == GTS_TRIANGLE (f)->e2) { - e2 = GTS_TRIANGLE (f)->e3; e3 = GTS_TRIANGLE (f)->e1; - } - else { - e2 = GTS_TRIANGLE (f)->e1; e3 = GTS_TRIANGLE (f)->e2; - } - if (GTS_SEGMENT (e2)->v1 == v1 || GTS_SEGMENT (e2)->v1 == v2) - v3 = GTS_SEGMENT (e2)->v2; - else - v3 = GTS_SEGMENT (e2)->v1; - } - } - return NULL; -} - -/** - * gts_point_locate: - * @p: a #GtsPoint. - * @surface: a #GtsSurface. - * @guess: %NULL or a face of @surface close to @p. - * - * Locates the face of the planar projection of @surface containing - * @p. The planar projection of @surface must define a connected set - * of triangles without holes and bounded by a convex boundary. The - * algorithm is randomized and performs in O(n^1/3) expected time - * where n is the number of triangles of @surface. - * - * If a good @guess is given the point location can be significantly faster. - * - * Returns: a #GtsFace of @surface containing @p or %NULL if @p is not - * contained within the boundary of @surface. - */ -GtsFace * gts_point_locate (GtsPoint * p, - GtsSurface * surface, - GtsFace * guess) -{ - GtsFace * fr; - GtsPoint * o; - - g_return_val_if_fail (p != NULL, NULL); - g_return_val_if_fail (surface != NULL, NULL); - g_return_val_if_fail (guess == NULL || - gts_face_has_parent_surface (guess, surface), NULL); - - if (guess == NULL) - guess = closest_face (surface, p); - else - g_return_val_if_fail (gts_triangle_orientation (GTS_TRIANGLE (guess)) > 0., NULL); - - if (guess == NULL) - return NULL; - - o = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class ()))); - triangle_barycenter (GTS_TRIANGLE (guess), o); - fr = point_locate (o, p, guess, surface); - gts_object_destroy (GTS_OBJECT (o)); - - return fr; -} - - -/** - * gts_constraint_class: - * - * Returns: the #GtsConstraintClass. - */ -GtsConstraintClass * gts_constraint_class (void) -{ - static GtsConstraintClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo constraint_info = { - "GtsConstraint", - sizeof (GtsConstraint), - sizeof (GtsConstraintClass), - (GtsObjectClassInitFunc) NULL, - (GtsObjectInitFunc) NULL, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_edge_class ()), - &constraint_info); - } - - return klass; -} - -static void split_list (GtsListFace * f, GtsListFace * f1, GtsListFace * f2, - GtsPoint * p1, GtsPoint * p2, - GSList ** last1, GSList ** last2) -{ - GSList * i = f->points, * l1 = *last1, * l2 = *last2; - - while (i) { - GtsPoint * p = i->data; - - if (gts_point_orientation (p1, p2, p) >= 0.) { - if (l1) l1->next = i; else f1->points = i; - l1 = i; - } - else { - if (l2) l2->next = i; else f2->points = i; - l2 = i; - } - i = i->next; - } - f->points = NULL; - *last1 = l1; - *last2 = l2; -} - -/* cf. figure misc/swap.fig */ -static void swap_if_in_circle (GtsFace * f1, - GtsVertex * v1, - GtsVertex * v2, - GtsVertex * v3, - GtsEdge * e1, - GtsEdge * e2, - GtsEdge * e3, - GtsSurface * surface) -{ - GtsFace * f2; - GtsEdge * e4, *e5; - GtsVertex * v4; - - if (GTS_IS_CONSTRAINT (e1)) /* @e1 is a constraint can not swap */ - return; - - f2 = neighbor (f1, e1, surface); - if (f2 == NULL) /* @e1 is a boundary of @surface */ - return; - - if (GTS_TRIANGLE (f2)->e1 == e1) { - e4 = GTS_TRIANGLE (f2)->e2; e5 = GTS_TRIANGLE (f2)->e3; - } - else if (GTS_TRIANGLE (f2)->e2 == e1) { - e4 = GTS_TRIANGLE (f2)->e3; e5 = GTS_TRIANGLE (f2)->e1; - } - else { - e4 = GTS_TRIANGLE (f2)->e1; e5 = GTS_TRIANGLE (f2)->e2; - } - if (GTS_SEGMENT (e4)->v1 == GTS_SEGMENT (e1)->v1 || - GTS_SEGMENT (e4)->v1 == GTS_SEGMENT (e1)->v2) - v4 = GTS_SEGMENT (e4)->v2; - else - v4 = GTS_SEGMENT (e4)->v1; - - if (gts_point_in_circle (GTS_POINT (v4), GTS_POINT (v1), - GTS_POINT (v2), GTS_POINT (v3)) > 0.0) { - GtsEdge * en; - GtsSegment * sn = gts_vertices_are_connected (v3, v4); - GtsFace * f3, * f4; - - if (!GTS_IS_EDGE (sn)) - en = gts_edge_new (surface->edge_class, v3, v4); - else - en = GTS_EDGE (sn); - - f3 = gts_face_new (surface->face_class, en, e5, e2); - gts_object_attributes (GTS_OBJECT (f3), GTS_OBJECT (f1)); - f4 = gts_face_new (surface->face_class, en, e3, e4); - gts_object_attributes (GTS_OBJECT (f4), GTS_OBJECT (f2)); - - if (GTS_IS_LIST_FACE (f3)) { - GSList * last3 = NULL, * last4 = NULL; - - if (GTS_IS_LIST_FACE (f1)) - split_list (GTS_LIST_FACE (f1), GTS_LIST_FACE (f3), GTS_LIST_FACE (f4), - GTS_POINT (v3), GTS_POINT (v4), &last3, &last4); - if (GTS_IS_LIST_FACE (f2)) - split_list (GTS_LIST_FACE (f2), GTS_LIST_FACE (f3), GTS_LIST_FACE (f4), - GTS_POINT (v3), GTS_POINT (v4), &last3, &last4); - if (last3) last3->next = NULL; - if (last4) last4->next = NULL; - } - - gts_surface_remove_face (surface, f1); - gts_surface_remove_face (surface, f2); - gts_surface_add_face (surface, f3); - gts_surface_add_face (surface, f4); - - swap_if_in_circle (f3, v4, v2, v3, e5, e2, en, surface); - swap_if_in_circle (f4, v1, v4, v3, e4, en, e3, surface); - } -} - -/** - * gts_delaunay_add_vertex_to_face: - * @surface: a #GtsSurface. - * @v: a #GtsVertex. - * @f: a #GtsFace belonging to @surface. - * - * Adds vertex @v to the face @f of the Delaunay triangulation defined - * by @surface. - * - * Returns: %NULL is @v has been successfully added to @surface or was - * already contained in @surface or a #GtsVertex having the same x and - * y coordinates as @v. - */ -GtsVertex * gts_delaunay_add_vertex_to_face (GtsSurface * surface, - GtsVertex * v, - GtsFace * f) -{ - GtsEdge * e1, * e2, * e3; - GtsSegment * s4, * s5, * s6; - GtsEdge * e4, * e5, * e6; - GtsVertex * v1, * v2, * v3; - GtsFace * nf[3]; - - g_return_val_if_fail (surface != NULL, v); - g_return_val_if_fail (v != NULL, v); - g_return_val_if_fail (f != NULL, v); - - gts_triangle_vertices_edges (GTS_TRIANGLE (f), NULL, - &v1, &v2, &v3, &e1, &e2, &e3); - if (v == v1 || v == v2 || v == v3) /* v already in @surface */ - return NULL; - if (GTS_POINT (v)->x == GTS_POINT (v1)->x && - GTS_POINT (v)->y == GTS_POINT (v1)->y) - return v1; - if (GTS_POINT (v)->x == GTS_POINT (v2)->x && - GTS_POINT (v)->y == GTS_POINT (v2)->y) - return v2; - if (GTS_POINT (v)->x == GTS_POINT (v3)->x && - GTS_POINT (v)->y == GTS_POINT (v3)->y) - return v3; - - s4 = gts_vertices_are_connected (v, v1); - if (!GTS_IS_EDGE (s4)) - e4 = gts_edge_new (surface->edge_class, v, v1); - else - e4 = GTS_EDGE (s4); - s5 = gts_vertices_are_connected (v, v2); - if (!GTS_IS_EDGE (s5)) - e5 = gts_edge_new (surface->edge_class, v, v2); - else - e5 = GTS_EDGE (s5); - s6 = gts_vertices_are_connected (v, v3); - if (!GTS_IS_EDGE (s6)) - e6 = gts_edge_new (surface->edge_class, v, v3); - else - e6 = GTS_EDGE (s6); - - /* cf. figure misc/swap.fig */ - nf[0] = gts_face_new (surface->face_class, e4, e1, e5); - gts_object_attributes (GTS_OBJECT (nf[0]), GTS_OBJECT (f)); - nf[1] = gts_face_new (surface->face_class, e5, e2, e6); - gts_object_attributes (GTS_OBJECT (nf[1]), GTS_OBJECT (f)); - nf[2] = gts_face_new (surface->face_class, e6, e3, e4); - gts_object_attributes (GTS_OBJECT (nf[2]), GTS_OBJECT (f)); - - if (GTS_IS_LIST_FACE (f) && GTS_IS_LIST_FACE (nf[0])) { - GSList * i = GTS_LIST_FACE (f)->points, * last[3] = { NULL, NULL, NULL }; - - while (i) { - GtsPoint * p = i->data; - GSList * next = i->next; - guint j; - - if (p != GTS_POINT (v)) { - if (gts_point_orientation (GTS_POINT (v), GTS_POINT (v1), p) >= 0.) { - gdouble o = gts_point_orientation (GTS_POINT (v), GTS_POINT (v2), p); - - if (o != 0.) - j = o > 0. ? 1 : 0; - else - j = gts_point_orientation (GTS_POINT (v), GTS_POINT (v3), p) - > 0. ? 0 : 1; - } - else if (gts_point_orientation (GTS_POINT (v), GTS_POINT (v3), p) > 0.) - j = 2; - else - j = 1; - if (last[j]) - last[j]->next = i; - else - GTS_LIST_FACE (nf[j])->points = i; - last[j] = i; - } - else - g_slist_free_1 (i); - i = next; - } - GTS_LIST_FACE (f)->points = NULL; - if (last[0]) last[0]->next = NULL; - if (last[1]) last[1]->next = NULL; - if (last[2]) last[2]->next = NULL; - } - - gts_surface_remove_face (surface, f); - gts_surface_add_face (surface, nf[0]); - gts_surface_add_face (surface, nf[1]); - gts_surface_add_face (surface, nf[2]); - - swap_if_in_circle (nf[0], v1, v2, v, e1, e5, e4, surface); - swap_if_in_circle (nf[1], v2, v3, v, e2, e6, e5, surface); - swap_if_in_circle (nf[2], v3, v1, v, e3, e4, e6, surface); - - return NULL; -} - -/** - * gts_delaunay_add_vertex: - * @surface: a #GtsSurface. - * @v: a #GtsVertex. - * @guess: %NULL or a #GtsFace belonging to @surface to be used as an initial - * guess for point location. - * - * Adds vertex @v to the Delaunay triangulation defined by - * @surface. If @v is not contained in the convex hull bounding - * @surface, @v is not added to the triangulation. - * - * Returns: %NULL is @v has been successfully added to @surface or was - * already contained in @surface, @v if @v is not contained in the - * convex hull bounding surface or a #GtsVertex having the same x and - * y coordinates as @v. - */ -GtsVertex * gts_delaunay_add_vertex (GtsSurface * surface, - GtsVertex * v, - GtsFace * guess) -{ - GtsFace * f; - - g_return_val_if_fail (surface != NULL, v); - g_return_val_if_fail (v != NULL, v); - - if (!(f = gts_point_locate (GTS_POINT (v), surface, guess))) - return v; - return gts_delaunay_add_vertex_to_face (surface, v, f); -} - -static gboolean polygon_in_circle (GSList * poly, - GtsPoint * p1, - GtsPoint * p2, - GtsPoint * p3) -{ - GtsVertex * v1 = NULL, * v2 = NULL; - - while (poly) { - GtsSegment * s = poly->data; - GtsVertex * v; - v = s->v1; - if (v != v1 && v != v2 && - v != GTS_VERTEX (p1) && - v != GTS_VERTEX (p2) && - v != GTS_VERTEX (p3) && - gts_point_in_circle (GTS_POINT (v), p1, p2, p3) > 0.) - return TRUE; - v = s->v2; - if (v != v1 && v != v2 && - v != GTS_VERTEX (p1) && - v != GTS_VERTEX (p2) && - v != GTS_VERTEX (p3) && - gts_point_in_circle (GTS_POINT (v), p1, p2, p3) > 0.) - return TRUE; - v1 = s->v1; - v2 = s->v2; - poly = poly->next; - } - return FALSE; -} - -static void triangulate_polygon (GSList * poly, - GtsSurface * surface, - GtsFace * ref) -{ - GSList * i, * poly1, * poly2; - GtsVertex * v1, * v2, * v3 = NULL; - gboolean found = FALSE; - GtsSegment * s, * s1, * s2; - GtsEdge * e1, * e2; - GtsFace * f; - - if (poly == NULL || poly->next == NULL) { - g_slist_free (poly); - return; - } - - s = poly->data; - s1 = poly->next->data; - if (s->v1 == s1->v1 || s->v1 == s1->v2) { - v1 = s->v2; - v2 = s->v1; - } - else { - g_assert (s->v2 == s1->v1 || s->v2 == s1->v2); - v1 = s->v1; - v2 = s->v2; - } - - i = poly->next; - v3 = v2; - while (i && !found) { - s1 = i->data; - if (s1->v1 == v3) - v3 = s1->v2; - else { - g_assert (s1->v2 == v3); - v3 = s1->v1; - } - if (v3 != v1 && - gts_point_orientation (GTS_POINT (v1), - GTS_POINT (v2), - GTS_POINT (v3)) >= 0. && - !polygon_in_circle (poly, - GTS_POINT (v1), - GTS_POINT (v2), - GTS_POINT (v3))) - found = TRUE; - else - i = i->next; - } - - if (!found) { - g_slist_free (poly); - return; - } - - s1 = gts_vertices_are_connected (v2, v3); - if (!GTS_IS_EDGE (s1)) - e1 = gts_edge_new (surface->edge_class, v2, v3); - else - e1 = GTS_EDGE (s1); - s2 = gts_vertices_are_connected (v3, v1); - if (!GTS_IS_EDGE (s2)) - e2 = gts_edge_new (surface->edge_class, v3, v1); - else - e2 = GTS_EDGE (s2); - f = gts_face_new (surface->face_class, GTS_EDGE (s), e1, e2); - gts_object_attributes (GTS_OBJECT (f), GTS_OBJECT (ref)); - gts_surface_add_face (surface, f); - - poly1 = poly->next; - g_slist_free_1 (poly); - if (i->next && e2 != i->next->data) - poly2 = g_slist_prepend (i->next, e2); - else - poly2 = i->next; - if (e1 != i->data) - i->next = g_slist_prepend (NULL, e1); - else - i->next = NULL; - - triangulate_polygon (poly1, surface, ref); - triangulate_polygon (poly2, surface, ref); -} - -/** - * gts_delaunay_remove_vertex: - * @surface: a #GtsSurface. - * @v: a #GtsVertex. - * - * Removes @v from the Delaunay triangulation defined by @surface and - * restores the Delaunay property. Vertex @v must not be used by any - * constrained edge otherwise the triangulation is not guaranteed to - * be Delaunay. - */ -void gts_delaunay_remove_vertex (GtsSurface * surface, GtsVertex * v) -{ - GSList * triangles, * i; - GtsFace * ref = NULL; - - g_return_if_fail (surface != NULL); - g_return_if_fail (v != NULL); - - i = triangles = gts_vertex_triangles (v, NULL); - while (i && !ref) { - if (GTS_IS_FACE (i->data) && - gts_face_has_parent_surface (i->data, surface)) - ref = i->data; - i = i->next; - } - if (!ref) { - g_slist_free (triangles); - g_return_if_fail (ref); - } - triangulate_polygon (gts_vertex_fan_oriented (v, surface), surface, ref); - i = triangles; - while (i) { - if (GTS_IS_FACE (i->data) && - gts_face_has_parent_surface (i->data, surface)) - gts_surface_remove_face (surface, i->data); - i = i->next; - } - g_slist_free (triangles); -} - -#define NEXT_CUT(edge, edge1, list) { next = neighbor (f, edge, surface);\ - remove_triangles (e, surface);\ - if (!constraint && !e->triangles)\ - gts_object_destroy (GTS_OBJECT (e));\ - g_assert (next);\ - *list = g_slist_prepend (*list, edge1);\ - return g_slist_concat (constraint,\ - remove_intersected_edge (s, edge,\ - next, surface, left, right));\ - } - -static void remove_triangles (GtsEdge * e, GtsSurface * s) -{ - GSList * i = e->triangles; - - while (i) { - GSList * next = i->next; - - if (GTS_IS_FACE (i->data) && gts_face_has_parent_surface (i->data, s)) - gts_surface_remove_face (s, i->data); - i = next; - } -} - -static GSList * -remove_intersected_edge (GtsSegment * s, - GtsEdge * e, - GtsFace * f, - GtsSurface * surface, - GSList ** left, GSList ** right) -{ - GtsVertex * v1, * v2, * v3; - GtsEdge * e1, * e2; - gdouble o1, o2; - GtsFace * next; - GSList * constraint = NULL; - - if (GTS_IS_CONSTRAINT (e)) - constraint = g_slist_prepend (NULL, e); - - gts_triangle_vertices_edges (GTS_TRIANGLE (f), e, - &v1, &v2, &v3, &e, &e1, &e2); - - o1 = gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), - GTS_POINT (s->v2)); - o2 = gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), - GTS_POINT (s->v2)); - - if (o1 == 0. && o2 == 0.) { -/* if(o2 != 0.) { - fprintf(stderr, "o1 = %f o2 = %f\n", o1, o2); - fprintf(stderr, "v1 = %f, %f\n", GTS_POINT(v1)->x, GTS_POINT(v1)->y); - fprintf(stderr, "v2 = %f, %f\n", GTS_POINT(v2)->x, GTS_POINT(v2)->y); - fprintf(stderr, "v3 = %f, %f\n", GTS_POINT(v3)->x, GTS_POINT(v3)->y); - fprintf(stderr, "s->v2 = %f, %f\n", GTS_POINT(s->v2)->x, GTS_POINT(s->v2)->y); - - g_assert (o2 == 0.); - }*/ - // if(o2 == 0.) { - remove_triangles (e, surface); - if (!constraint && !e->triangles) - gts_object_destroy (GTS_OBJECT (e)); - *left = g_slist_prepend (*left, e2); - *right = g_slist_prepend (*right, e1); -// } - } - else if (o1 > 0.) { - g_assert (o2 <= 0.); - NEXT_CUT (e2, e1, right) - } - else if (o2 >= 0.) - NEXT_CUT (e1, e2, left) - else { - gdouble o3 = gts_point_orientation (GTS_POINT (s->v1), GTS_POINT (s->v2), - GTS_POINT (v3)); - if (o3 > 0.) - NEXT_CUT (e1, e2, left) - else - NEXT_CUT (e2, e1, right) - } - return constraint; -} - -static GSList * -remove_intersected_vertex (GtsSegment * s, - GtsVertex * v, - GtsSurface * surface, - GSList ** left, - GSList ** right, - GtsFace ** ref) -{ - GSList * triangles = gts_vertex_triangles (v, NULL); - GSList * i; - - i = triangles; - while (i) { - GtsTriangle * t = i->data; - if (GTS_IS_FACE (t) && - gts_face_has_parent_surface (GTS_FACE (t), surface)) { - GtsVertex * v1, * v2, * v3; - gdouble o1, o2; - - gts_triangle_vertices (t, &v1, &v2, &v3); - if (v == v2) { - v2 = v3; - v3 = v1; - } - else if (v == v3) { - v3 = v2; - v2 = v1; - } - else - g_assert (v == v1); - - if ((o1 = gts_point_orientation (GTS_POINT (v), GTS_POINT (v2), - GTS_POINT (s->v2))) >= 0. && - (o2 = gts_point_orientation (GTS_POINT (v3), GTS_POINT (v), - GTS_POINT (s->v2))) >= 0.) { - gdouble o3 = gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), - GTS_POINT (s->v2)); - GtsEdge * e = gts_triangle_edge_opposite (t, v); - GtsEdge * e1, * e2; - GtsFace * next = neighbor (GTS_FACE (t), e, surface); - - *ref = GTS_FACE (t); - gts_triangle_vertices_edges (t, e, &v2, &v3, &v, &e, &e2, &e1); - - g_slist_free (triangles); - - if (o3 >= 0.) /* @s->v2 is inside (or on the edge) of t */ - return NULL; - - gts_allow_floating_faces = TRUE; - gts_surface_remove_face (surface, GTS_FACE (t)); - gts_allow_floating_faces = FALSE; - - *left = g_slist_prepend (*left, e2); - *right = g_slist_prepend (*right, e1); - - g_assert (next); - return remove_intersected_edge (s, e, next, surface, left, right); - } - } - i = i->next; - } - - g_assert_not_reached (); - return NULL; -} - -/** - * gts_delaunay_add_constraint: - * @surface: a #GtsSurface. - * @c: a #GtsConstraint. - * - * Add constraint @c to the constrained Delaunay triangulation defined by - * @surface. - * - * Returns: a list of #GtsConstraint conflicting (i.e. intersecting) with @c - * which were removed from @surface (%NULL if there was none). - */ -GSList * gts_delaunay_add_constraint (GtsSurface * surface, - GtsConstraint * c) -{ - GSList * constraints; - GtsVertex * v1; //, * v2; - GSList * left = NULL, * right = NULL; - GtsFace * ref = NULL; - - g_return_val_if_fail (surface != NULL, NULL); - g_return_val_if_fail (c != NULL, NULL); - g_return_val_if_fail (GTS_IS_CONSTRAINT (c), NULL); - - v1 = GTS_SEGMENT (c)->v1; - //v2 = GTS_SEGMENT (c)->v2; - - gts_allow_floating_edges = TRUE; - constraints = remove_intersected_vertex (GTS_SEGMENT (c), v1, surface, - &left, &right, &ref); - gts_allow_floating_edges = FALSE; -#if 1 - triangulate_polygon (g_slist_prepend (g_slist_reverse (right), c), - surface, ref); - triangulate_polygon (g_slist_prepend (left, c), - surface, ref); -#else - right = g_slist_prepend (g_slist_reverse (right), c); - left = g_slist_prepend (left, c); - { - FILE * fp0 = fopen ("hole", "wt"); - FILE * fp1 = fopen ("right", "wt"); - FILE * fp2 = fopen ("left", "wt"); - GSList * i = left; - - gts_surface_write (surface, fp0); - fclose (fp0); - - fprintf (fp2, "LIST {\n"); - while (i) { - GtsSegment * s = i->data; - fprintf (fp2, - "# %p: %p->%p\n" - "VECT 1 2 0 2 0 %g %g 0 %g %g 0\n", - s, s->v1, s->v2, - GTS_POINT (s->v1)->x, GTS_POINT (s->v1)->y, - GTS_POINT (s->v2)->x, GTS_POINT (s->v2)->y); - i = i->next; - } - fprintf (fp2, "}\n"); - fprintf (fp1, "LIST {\n"); - i = right; - while (i) { - GtsSegment * s = i->data; - fprintf (fp1, - "# %p: %p->%p\n" - "VECT 1 2 0 2 0 %g %g 0 %g %g 0\n", - s, s->v1, s->v2, - GTS_POINT (s->v1)->x, GTS_POINT (s->v1)->y, - GTS_POINT (s->v2)->x, GTS_POINT (s->v2)->y); - i = i->next; - } - fprintf (fp1, "}\n"); - fclose (fp1); - fclose (fp2); - } - triangulate_polygon (right, surface); - triangulate_polygon (left, surface); -#endif - if (ref && !ref->surfaces) { - gts_allow_floating_edges = TRUE; - gts_object_destroy (GTS_OBJECT (ref)); - gts_allow_floating_edges = FALSE; - } - return constraints; -} - -static void delaunay_check (GtsTriangle * t, gpointer * data) -{ - GtsSurface * surface = data[0]; - GtsFace ** face = data[1]; - - if (*face == NULL) { - GSList * i, * list; - GtsVertex * v1, * v2, * v3; - - gts_triangle_vertices (t, &v1, &v2, &v3); - list = gts_vertex_neighbors (v1, NULL, surface); - list = gts_vertex_neighbors (v2, list, surface); - list = gts_vertex_neighbors (v3, list, surface); - i = list; - while (i && *face == NULL) { - GtsVertex * v = i->data; - if (v != v1 && v != v2 && v != v3 && - gts_point_in_circle (GTS_POINT (v), - GTS_POINT (v1), - GTS_POINT (v2), - GTS_POINT (v3)) > 0.) - *face = GTS_FACE (t); - i = i->next; - } - g_slist_free (list); - } -} - -/** - * gts_delaunay_check: - * @surface: a #GtsSurface. - * - * Returns: %NULL if the planar projection of @surface is a Delaunay - * triangulation (unconstrained), a #GtsFace violating the Delaunay - * property otherwise. - */ -GtsFace * gts_delaunay_check (GtsSurface * surface) -{ - GtsFace * face = NULL; - gpointer data[2]; - - g_return_val_if_fail (surface != NULL, FALSE); - - data[0] = surface; - data[1] = &face; - gts_surface_foreach_face (surface, (GtsFunc) delaunay_check, data); - - return face; -} - -/** - * gts_delaunay_remove_hull: - * @surface: a #GtsSurface. - * - * Removes all the edges of the boundary of @surface which are not - * constraints. - */ -void gts_delaunay_remove_hull (GtsSurface * surface) -{ - GSList * boundary; - - g_return_if_fail (surface != NULL); - - boundary = gts_surface_boundary (surface); - gts_allow_floating_edges = TRUE; - while (boundary) { - GSList * i = boundary; - GtsEdge * e = i->data; - - boundary = i->next; - g_slist_free_1 (i); - if (!GTS_IS_CONSTRAINT (e)) { - GtsTriangle * t = GTS_TRIANGLE (gts_edge_is_boundary (e, surface)); - - if (t != NULL) { - if (t->e1 != e && !GTS_IS_CONSTRAINT (t->e1) && - !gts_edge_is_boundary (t->e1, surface)) - boundary = g_slist_prepend (boundary, t->e1); - if (t->e2 != e && !GTS_IS_CONSTRAINT (t->e2) && - !gts_edge_is_boundary (t->e2, surface)) - boundary = g_slist_prepend (boundary, t->e2); - if (t->e3 != e && !GTS_IS_CONSTRAINT (t->e3) && - !gts_edge_is_boundary (t->e3, surface)) - boundary = g_slist_prepend (boundary, t->e3); - gts_surface_remove_face (surface, GTS_FACE (t)); - } - if (!e->triangles) - gts_object_destroy (GTS_OBJECT (e)); - } - } - gts_allow_floating_edges = FALSE; -} - -/* GtsListFace: Object */ - -static void gts_list_face_destroy (GtsObject * object) -{ - g_slist_free (GTS_LIST_FACE (object)->points); - - (* GTS_OBJECT_CLASS (gts_list_face_class ())->parent_class->destroy) - (object); -} - -static void gts_list_face_class_init (GtsFaceClass * klass) -{ - GTS_OBJECT_CLASS (klass)->destroy = gts_list_face_destroy; -} - -GtsFaceClass * gts_list_face_class (void) -{ - static GtsFaceClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo gts_list_face_info = { - "GtsListFace", - sizeof (GtsListFace), - sizeof (GtsFaceClass), - (GtsObjectClassInitFunc) gts_list_face_class_init, - (GtsObjectInitFunc) NULL, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_face_class ()), - >s_list_face_info); - } - - return klass; -} Index: trunk/src_3rd/gts/vertex.c =================================================================== --- trunk/src_3rd/gts/vertex.c (revision 6802) +++ trunk/src_3rd/gts/vertex.c (nonexistent) @@ -1,780 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include "gts.h" - -gboolean gts_allow_floating_vertices = FALSE; - -static void vertex_destroy (GtsObject * object) -{ - GtsVertex * vertex = GTS_VERTEX (object); - GSList * i; - - i = vertex->segments; - while (i) { - GTS_OBJECT_SET_FLAGS (i->data, GTS_DESTROYED); - i = i->next; - } - i = vertex->segments; - while (i) { - GSList * next = i->next; - gts_object_destroy (i->data); - i = next; - } - g_assert (vertex->segments == NULL); - - (* GTS_OBJECT_CLASS (gts_vertex_class ())->parent_class->destroy) (object); -} - -static void vertex_clone (GtsObject * clone, GtsObject * object) -{ - (* GTS_OBJECT_CLASS (gts_vertex_class ())->parent_class->clone) (clone, - object); - GTS_VERTEX (clone)->segments = NULL; -} - -static void vertex_class_init (GtsVertexClass * klass) -{ - klass->intersection_attributes = NULL; - GTS_OBJECT_CLASS (klass)->clone = vertex_clone; - GTS_OBJECT_CLASS (klass)->destroy = vertex_destroy; -} - -static void vertex_init (GtsVertex * vertex) -{ - vertex->segments = NULL; -} - -/** - * gts_vertex_class: - * - * Returns: the #GtsVertexClass. - */ -GtsVertexClass * gts_vertex_class (void) -{ - static GtsVertexClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo vertex_info = { - "GtsVertex", - sizeof (GtsVertex), - sizeof (GtsVertexClass), - (GtsObjectClassInitFunc) vertex_class_init, - (GtsObjectInitFunc) vertex_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_point_class ()), - &vertex_info); - } - - return klass; -} - -/** - * gts_vertex_new: - * @klass: a #GtsVertexClass. - * @x: the x-coordinate of the vertex to create. - * @y: the y-coordinate of the vertex to create. - * @z: the y-coordinate of the vertex to create. - * - * Returns: a new #GtsVertex with @x, @y and @z as coordinates. - */ -GtsVertex * gts_vertex_new (GtsVertexClass * klass, - gdouble x, gdouble y, gdouble z) -{ - GtsVertex * v; - - v = GTS_VERTEX (gts_object_new (GTS_OBJECT_CLASS (klass))); - gts_point_set (GTS_POINT (v), x, y, z); - - return v; -} - -/** - * gts_vertex_replace: - * @v: a #GtsVertex. - * @with: another #GtsVertex. - * - * Replaces vertex @v with vertex @with. @v and @with must be - * different. All the #GtsSegment which have @v has one of their - * vertices are updated. The segments list of vertex @v is freed and - * @v->segments is set to %NULL. - */ -void gts_vertex_replace (GtsVertex * v, GtsVertex * with) -{ - GSList * i; - - g_return_if_fail (v != NULL); - g_return_if_fail (with != NULL); - g_return_if_fail (v != with); - - i = v->segments; - while (i) { - GtsSegment * s = i->data; - if (s->v1 != with && s->v2 != with) - with->segments = g_slist_prepend (with->segments, s); - if (s->v1 == v) s->v1 = with; - if (s->v2 == v) s->v2 = with; - i = i->next; - } - g_slist_free (v->segments); - v->segments = NULL; -} - -/** - * gts_vertex_is_unattached: - * @v: a #GtsVertex. - * - * Returns: %TRUE if @v is not the endpoint of any #GtsSegment, - * %FALSE otherwise. - */ -gboolean gts_vertex_is_unattached (GtsVertex * v) -{ - g_return_val_if_fail (v != NULL, FALSE); - if (v->segments == NULL) - return TRUE; - return FALSE; -} - -/** - * gts_vertices_are_connected: - * @v1: a #GtsVertex. - * @v2: another #GtsVertex. - * - * Returns: if @v1 and @v2 are the vertices of the same #GtsSegment - * this segment else %NULL. - */ -GtsSegment * gts_vertices_are_connected (GtsVertex * v1, GtsVertex * v2) -{ - GSList * i; - - g_return_val_if_fail (v1 != NULL, FALSE); - g_return_val_if_fail (v2 != NULL, FALSE); - - i = v1->segments; - while (i) { - GtsSegment * s = i->data; - - if (s->v1 == v2 || s->v2 == v2) - return s; - i = i->next; - } - return NULL; -} - -/** - * gts_vertices_from_segments: - * @segments: a list of #GtsSegment. - * - * Returns: a list of #GtsVertex, vertices of a #GtsSegment in @segments. - * Each element in the list is unique (no duplicates). - */ -GSList * gts_vertices_from_segments (GSList * segments) -{ - GHashTable * hash; - GSList * vertices = NULL, * i; - - hash = g_hash_table_new (NULL, NULL); - i = segments; - while (i) { - GtsSegment * s = i->data; - if (g_hash_table_lookup (hash, s->v1) == NULL) { - vertices = g_slist_prepend (vertices, s->v1); - g_hash_table_insert (hash, s->v1, s); - } - if (g_hash_table_lookup (hash, s->v2) == NULL) { - vertices = g_slist_prepend (vertices, s->v2); - g_hash_table_insert (hash, s->v2, s); - } - i = i->next; - } - g_hash_table_destroy (hash); - return vertices; -} - -/** - * gts_vertex_triangles: - * @v: a #GtsVertex. - * @list: a list of #GtsTriangle. - * - * Adds all the #GtsTriangle which share @v as a vertex and do not - * already belong to @list. - * - * Returns: the new list of unique #GtsTriangle which share @v as a - * vertex. - */ -GSList * gts_vertex_triangles (GtsVertex * v, - GSList * list) -{ - GSList * i; - - g_return_val_if_fail (v != NULL, NULL); - - i = v->segments; - while (i) { - GtsSegment * s = i->data; - if (GTS_IS_EDGE (s)) { - GSList * j = GTS_EDGE (s)->triangles; - while (j) { - if (!g_slist_find (list, j->data)) - list = g_slist_prepend (list, j->data); - j = j->next; - } - } - i = i->next; - } - return list; -} - -/** - * gts_vertex_faces: - * @v: a #GtsVertex. - * @surface: a #GtsSurface or %NULL. - * @list: a list of #GtsFace. - * - * Adds all the #GtsFace belonging to @surface (if not %NULL) which share - * @v as a vertex and do not already belong to @list. - * - * Returns: the new list of unique #GtsFace belonging to @surface - * which share @v as a vertex. - */ -GSList * gts_vertex_faces (GtsVertex * v, - GtsSurface * surface, - GSList * list) -{ - GSList * i; - - g_return_val_if_fail (v != NULL, NULL); - - i = v->segments; - while (i) { - GtsSegment * s = i->data; - if (GTS_IS_EDGE (s)) { - GSList * j = GTS_EDGE (s)->triangles; - while (j) { - GtsTriangle * t = j->data; - if (GTS_IS_FACE (t) - && - (!surface || gts_face_has_parent_surface (GTS_FACE (t), surface)) - && - !g_slist_find (list, t)) - list = g_slist_prepend (list, t); - j = j->next; - } - } - i = i->next; - } - return list; -} - -/** - * gts_vertex_neighbors: - * @v: a #GtsVertex. - * @list: a list of #GtsVertex. - * @surface: a #GtsSurface or %NULL. - * - * Adds to @list all the #GtsVertex connected to @v by a #GtsSegment and not - * already in @list. If @surface is not %NULL only the vertices connected to - * @v by an edge belonging to @surface are considered. - * - * Returns: the new list of unique #GtsVertex. - */ -GSList * gts_vertex_neighbors (GtsVertex * v, - GSList * list, - GtsSurface * surface) -{ - GSList * i; - - g_return_val_if_fail (v != NULL, NULL); - - i = v->segments; - while (i) { - GtsSegment * s = i->data; - GtsVertex * v1 = s->v1 == v ? s->v2 : s->v1; - if (v1 != v && - (!surface || - (GTS_IS_EDGE (s) && - gts_edge_has_parent_surface (GTS_EDGE (s), surface))) && - !g_slist_find (list, v1)) - list = g_slist_prepend (list, v1); - i = i->next; - } - return list; -} - -/** - * gts_vertex_is_boundary: - * @v: a #GtsVertex. - * @surface: a #GtsSurface or %NULL. - * - * Returns: %TRUE if @v is used by a #GtsEdge boundary of @surface as - * determined by gts_edge_is_boundary(), %FALSE otherwise. - */ -gboolean gts_vertex_is_boundary (GtsVertex * v, GtsSurface * surface) -{ - GSList * i; - - g_return_val_if_fail (v != NULL, FALSE); - - i = v->segments; - while (i) { - if (GTS_IS_EDGE (i->data) && - gts_edge_is_boundary (i->data, surface)) - return TRUE; - i = i->next; - } - - return FALSE; -} - -/** - * gts_vertices_merge: - * @vertices: a list of #GtsVertex. - * @epsilon: half the size of the bounding box to consider for each vertex. - * @check: function called for each pair of vertices about to be merged - * or %NULL. - * - * For each vertex v in @vertices look if there are any vertex of - * @vertices contained in a box centered on v of size 2*@epsilon. If - * there are and if @check is not %NULL and returns %TRUE, replace - * them with v (using gts_vertex_replace()), destroy them and remove - * them from list. This is done efficiently using Kd-Trees. - * - * Returns: the updated list of vertices. - */ -GList * gts_vertices_merge (GList * vertices, - gdouble epsilon, - gboolean (* check) (GtsVertex *, GtsVertex *)) -{ - GPtrArray * array; - GList * i; - GNode * kdtree; - - g_return_val_if_fail (vertices != NULL, 0); - - array = g_ptr_array_new (); - i = vertices; - while (i) { - g_ptr_array_add (array, i->data); - i = i->next; - } - kdtree = gts_kdtree_new (array, NULL); - g_ptr_array_free (array, TRUE); - - i = vertices; - while (i) { - GtsVertex * v = i->data; - if (!GTS_OBJECT (v)->reserved) { /* Do something only if v is active */ - GtsBBox * bbox; - GSList * selected, * j; - - /* build bounding box */ - bbox = gts_bbox_new (gts_bbox_class (), - v, - GTS_POINT (v)->x - epsilon, - GTS_POINT (v)->y - epsilon, - GTS_POINT (v)->z - epsilon, - GTS_POINT (v)->x + epsilon, - GTS_POINT (v)->y + epsilon, - GTS_POINT (v)->z + epsilon); - - /* select vertices which are inside bbox using kdtree */ - j = selected = gts_kdtree_range (kdtree, bbox, NULL); - while (j) { - GtsVertex * sv = j->data; - if (sv != v && !GTS_OBJECT (sv)->reserved && (!check || (*check) (sv, v))) { - /* sv is not v and is active */ - gts_vertex_replace (sv, v); - GTS_OBJECT (sv)->reserved = sv; /* mark sv as inactive */ - } - j = j->next; - } - g_slist_free (selected); - gts_object_destroy (GTS_OBJECT (bbox)); - } - i = i->next; - } - - gts_kdtree_destroy (kdtree); - - /* destroy inactive vertices and removes them from list */ - - /* we want to control vertex destruction */ - gts_allow_floating_vertices = TRUE; - - i = vertices; - while (i) { - GtsVertex * v = i->data; - GList * next = i->next; - if (GTS_OBJECT (v)->reserved) { /* v is inactive */ - gts_object_destroy (GTS_OBJECT (v)); - vertices = g_list_remove_link (vertices, i); - g_list_free_1 (i); - } - i = next; - } - gts_allow_floating_vertices = FALSE; - - return vertices; -} - -/* returns the list of edges belonging to @surface turning around @v */ -static GSList * edge_fan_list (GtsVertex * v, - GtsSurface * surface, - GtsFace * f, - GtsEdge * e, - GtsFace * first) -{ - GSList * i = e->triangles; - GtsFace * neighbor = NULL; - GtsEdge * next = NULL, * enext = NULL; - - while (i) { - GtsFace * f1 = i->data; - if (GTS_IS_FACE (f1) && - f1 != f && - gts_face_has_parent_surface (f1, surface)) { - g_return_val_if_fail (neighbor == NULL, NULL); /* non-manifold edge */ - neighbor = f1; - } - i = i->next; - } - if (neighbor == NULL || neighbor == first) /* end of fan */ - return NULL; - - if (GTS_TRIANGLE (neighbor)->e1 == e) { - next = GTS_TRIANGLE (neighbor)->e2; - enext = GTS_TRIANGLE (neighbor)->e3; - } - else if (GTS_TRIANGLE (neighbor)->e2 == e) { - next = GTS_TRIANGLE (neighbor)->e3; - enext = GTS_TRIANGLE (neighbor)->e1; - } - else if (GTS_TRIANGLE (neighbor)->e3 == e) { - next = GTS_TRIANGLE (neighbor)->e1; - enext = GTS_TRIANGLE (neighbor)->e2; - } - else - g_assert_not_reached (); - - /* checking for correct orientation */ - g_return_val_if_fail (GTS_SEGMENT (enext)->v1 == v || - GTS_SEGMENT (enext)->v2 == v, NULL); - - return g_slist_prepend (edge_fan_list (v, surface, neighbor, enext, first), - next); -} - -/** - * gts_vertex_fan_oriented: - * @v: a #GtsVertex. - * @surface: a #GtsSurface. - * - * Returns: a list of #GtsEdge describing in counterclockwise order the - * boundary of the fan of summit @v, the faces of the fan belonging to - * @surface. - */ -GSList * gts_vertex_fan_oriented (GtsVertex * v, GtsSurface * surface) -{ - GtsFace * f = NULL; - guint d = 2; - GSList * i; - GtsVertex * v1, * v2, * v3; - GtsEdge * e1, * e2, * e3; - - g_return_val_if_fail (v != NULL, NULL); - g_return_val_if_fail (surface != NULL, NULL); - - i = v->segments; - while (i) { - GtsEdge * e = i->data; - if (GTS_IS_EDGE (e)) { - GSList * j = e->triangles; - GtsFace * f1 = NULL; - guint degree = 0; - while (j) { - if (GTS_IS_FACE (j->data) && - gts_face_has_parent_surface (j->data, surface)) { - f1 = j->data; - degree++; - } - j = j->next; - } - if (f1 != NULL) { - g_return_val_if_fail (degree <= 2, NULL); /* non-manifold edge */ - if (degree == 1) { - gts_triangle_vertices_edges (GTS_TRIANGLE (f1), NULL, - &v1, &v2, &v3, &e1, &e2, &e3); - if (v == v2) { - e2 = e3; - e3 = e1; - } - else if (v == v3) { - e3 = e2; - e2 = e1; - } - if (e3 != e) { - d = 1; - f = f1; - } - } - else if (degree <= d) - f = f1; - } - } - i = i->next; - } - - if (f == NULL) - return NULL; - - gts_triangle_vertices_edges (GTS_TRIANGLE (f), NULL, - &v1, &v2, &v3, &e1, &e2, &e3); - if (v == v2) { - e2 = e3; - e3 = e1; - } - else if (v == v3) { - e3 = e2; - e2 = e1; - } - - return g_slist_prepend (edge_fan_list (v, surface, f, e3, f), e2); -} - -#define edge_use_vertex(e, v) (GTS_SEGMENT(e)->v1 == v ||\ - GTS_SEGMENT(e)->v2 == v) - -static GtsEdge * replace_vertex (GtsTriangle * t, - GtsEdge * e1, - GtsVertex * v, - GtsVertex * with) -{ - GtsEdge * e = NULL; - - if (t->e1 != e1 && edge_use_vertex (t->e1, v)) - e = t->e1; - else if (t->e2 != e1 && edge_use_vertex (t->e2, v)) - e = t->e2; - else if (t->e3 != e1 && edge_use_vertex (t->e3, v)) - e = t->e3; - else - return NULL; - - if (with != v) { - GtsSegment * s = GTS_SEGMENT (e); - if (s->v1 == v) s->v1 = with; - if (s->v2 == v) s->v2 = with; - with->segments = g_slist_prepend (with->segments, s); - v->segments = g_slist_remove (v->segments, s); - } - - return e; -} - -static void triangle_next (GtsEdge * e, GtsVertex * v, GtsVertex * with) -{ - GSList * i; - - if (e == NULL) - return; - - i = e->triangles; - while (i) { - GtsTriangle * t = i->data; - if (GTS_OBJECT (t)->reserved) { - GTS_OBJECT (t)->reserved = NULL; - triangle_next (replace_vertex (t, e, v, with), v, with); - } - i = i->next; - } -} - -/** - * gts_vertex_is_contact: - * @v: a #GtsVertex. - * @sever: if %TRUE and if @v is a contact vertex between two or more - * sets of connected triangles replaces it with as many vertices, - * clones of @v. - * - * Returns: the number of sets of connected triangles sharing @v as a - * contact vertex. - */ -guint gts_vertex_is_contact (GtsVertex * v, gboolean sever) -{ - GSList * triangles, * i; - GtsVertex * with = v; - guint ncomponent = 0; - - g_return_val_if_fail (v != NULL, 0); - - triangles = gts_vertex_triangles (v, NULL); - i = triangles; - while (i) { - GTS_OBJECT (i->data)->reserved = i; - i = i->next; - } - - i = triangles; - while (i) { - GtsTriangle * t = i->data; - if (GTS_OBJECT (t)->reserved) { - GtsEdge * e; - if (ncomponent && sever) - with = GTS_VERTEX (gts_object_clone (GTS_OBJECT (v))); - GTS_OBJECT (t)->reserved = NULL; - e = replace_vertex (t, NULL, v, with); - triangle_next (e, v, with); - triangle_next (replace_vertex (t, e, v, with), v, with); - ncomponent++; - } - i = i->next; - } - g_slist_free (triangles); - - return ncomponent; -} - -/* GtsVertexNormal: Object */ - -static void vertex_normal_attributes (GtsVertex * v, - GtsObject * e, - GtsObject * t) -{ - g_return_if_fail (GTS_IS_EDGE (e)); - g_return_if_fail (GTS_IS_TRIANGLE (t)); - - if (GTS_IS_VERTEX_NORMAL (GTS_SEGMENT (e)->v1) && - GTS_IS_VERTEX_NORMAL (GTS_SEGMENT (e)->v2)) { - GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (e)->v1); - GtsPoint * p2 = GTS_POINT (GTS_SEGMENT (e)->v2); - GtsPoint * p = GTS_POINT (v); - gdouble a, b, lambda; - guint i; - - a = p2->x - p1->x; b = p->x - p1->x; - if (fabs (p2->y - p1->y) > fabs (a)) { - a = p2->y - p1->y; b = p->y - p1->y; - } - if (fabs (p2->z - p1->z) > fabs (a)) { - a = p2->z - p1->z; b = p->z - p1->z; - } - lambda = a != 0. ? b/a : 0.; - for (i = 0; i < 3; i++) - GTS_VERTEX_NORMAL (v)->n[i] = - (1. - lambda)*GTS_VERTEX_NORMAL (GTS_SEGMENT (e)->v1)->n[i] + - lambda*GTS_VERTEX_NORMAL (GTS_SEGMENT (e)->v2)->n[i]; - } - else { - GtsVertex * v1, * v2, * v3; - - gts_triangle_vertices (GTS_TRIANGLE (t), &v1, &v2, &v3); - if (GTS_IS_VERTEX_NORMAL (v1) && - GTS_IS_VERTEX_NORMAL (v2) && - GTS_IS_VERTEX_NORMAL (v3)) { - GtsVector a1, a2, a3, det; - guint i, j = 0; - gdouble l1, l2; - - gts_vector_init (a1, GTS_POINT (v1), GTS_POINT (v)); - gts_vector_init (a2, GTS_POINT (v1), GTS_POINT (v2)); - gts_vector_init (a3, GTS_POINT (v1), GTS_POINT (v3)); - gts_vector_cross (det, a2, a3); - if (fabs (det[1]) > fabs (det[0])) j = 1; - if (fabs (det[2]) > fabs (det[j])) j = 2; - if (det[j] == 0.) { - g_warning ("vertex_normal_attributes: det[%d] == 0.", j); - return; - } - switch (j) { - case 0: - l1 = (a1[1]*a3[2] - a1[2]*a3[1])/det[0]; - l2 = (a1[2]*a2[1] - a1[1]*a2[2])/det[0]; - break; - case 1: - l1 = (a1[2]*a3[0] - a1[0]*a3[2])/det[1]; - l2 = (a1[0]*a2[2] - a1[2]*a2[0])/det[1]; - break; - case 2: - l1 = (a1[0]*a3[1] - a1[1]*a3[0])/det[2]; - l2 = (a1[1]*a2[0] - a1[0]*a2[1])/det[2]; - break; - default: - l1 = l2 = 0.; - } - for (i = 0; i < 3; i++) - GTS_VERTEX_NORMAL (v)->n[i] = - GTS_VERTEX_NORMAL (v1)->n[i]*(1. - l1 - l2) + - GTS_VERTEX_NORMAL (v2)->n[i]*l1 + - GTS_VERTEX_NORMAL (v3)->n[i]*l2; - } - } -} - -static void gts_vertex_normal_class_init (GtsVertexClass * klass) -{ - klass->intersection_attributes = vertex_normal_attributes; -} - -GtsVertexClass * gts_vertex_normal_class (void) -{ - static GtsVertexClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo gts_vertex_normal_info = { - "GtsVertexNormal", - sizeof (GtsVertexNormal), - sizeof (GtsVertexClass), - (GtsObjectClassInitFunc) gts_vertex_normal_class_init, - (GtsObjectInitFunc) NULL, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_vertex_class ()), - >s_vertex_normal_info); - } - - return klass; -} - -/* GtsColorVertex: Object */ - -GtsVertexClass * gts_color_vertex_class (void) -{ - static GtsVertexClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo gts_color_vertex_info = { - "GtsColorVertex", - sizeof (GtsColorVertex), - sizeof (GtsVertexClass), - (GtsObjectClassInitFunc) NULL, - (GtsObjectInitFunc) NULL, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_vertex_class ()), - >s_color_vertex_info); - } - - return klass; -} - Index: trunk/src_3rd/gts/heap.c =================================================================== --- trunk/src_3rd/gts/heap.c (revision 6802) +++ trunk/src_3rd/gts/heap.c (nonexistent) @@ -1,258 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include "gts.h" - -#define PARENT(i) ((i) >= 2 ? (i)/2 : 0) -#define LEFT_CHILD(i) (2*(i)) -#define RIGHT_CHILD(i) (2*(i) + 1) - -struct _GtsHeap { - GPtrArray * elts; - GCompareFunc func; - gboolean frozen; -}; - -/** - * gts_heap_new: - * @compare_func: a GCompareFunc. - * - * Returns: a new #GtsHeap using @compare_func as a sorting function. - */ -GtsHeap * gts_heap_new (GCompareFunc compare_func) -{ - GtsHeap * heap; - - g_return_val_if_fail (compare_func != NULL, NULL); - - heap = g_malloc (sizeof(GtsHeap)); - heap->elts = g_ptr_array_new (); - heap->func = compare_func; - heap->frozen = FALSE; - return heap; -} - -static void sift_up (GtsHeap * heap, guint i) -{ - gpointer parent, child; - guint p; - gpointer * pdata = heap->elts->pdata; - GCompareFunc func = heap->func; - - child = pdata[i - 1]; - while ((p = PARENT (i))) { - parent = pdata[p - 1]; - if ((*func) (parent, child) > 0) { - pdata[p - 1] = child; - pdata[i - 1] = parent; - i = p; - } - else - i = 0; - } -} - -/** - * gts_heap_insert: - * @heap: a #GtsHeap. - * @p: a pointer to add to the heap. - * - * Inserts a new element @p in the heap. - */ -void gts_heap_insert (GtsHeap * heap, gpointer p) -{ - g_return_if_fail (heap != NULL); - - g_ptr_array_add (heap->elts, p); - if (!heap->frozen) - sift_up (heap, heap->elts->len); -} - -static void sift_down (GtsHeap * heap, guint i) -{ - gpointer left_child, right_child, child, parent; - guint lc, rc, c; - gpointer * pdata = heap->elts->pdata; - guint len = heap->elts->len; - GCompareFunc func = heap->func; - - lc = LEFT_CHILD (i); - rc = RIGHT_CHILD (i); - left_child = lc <= len ? pdata[lc - 1] : NULL; - right_child = rc <= len ? pdata[rc - 1] : NULL; - - parent = pdata[i - 1]; - while (left_child != NULL) { - if (right_child == NULL || - (*func) (left_child, right_child) < 0) { - child = left_child; - c = lc; - } - else { - child = right_child; - c = rc; - } - if ((*func) (parent, child) > 0) { - pdata[i - 1] = child; - pdata[c - 1] = parent; - i = c; - lc = LEFT_CHILD (i); - rc = RIGHT_CHILD (i); - left_child = lc <= len ? pdata[lc - 1] : NULL; - right_child = rc <= len ? pdata[rc - 1] : NULL; - } - else - left_child = NULL; - } -} - -/** - * gts_heap_remove_top: - * @heap: a #GtsHeap. - * - * Removes the element at the top of the heap. - * - * Returns: the element at the top of the heap. - */ -gpointer gts_heap_remove_top (GtsHeap * heap) -{ - gpointer root; - GPtrArray * elts; - guint len; - - g_return_val_if_fail (heap != NULL, NULL); - - elts = heap->elts; len = elts->len; - - if (len == 0) - return NULL; - if (len == 1) - return g_ptr_array_remove_index (elts, 0); - - root = elts->pdata[0]; - elts->pdata[0] = g_ptr_array_remove_index (elts, len - 1); - sift_down (heap, 1); - return root; -} - -/** - * gts_heap_top: - * @heap: a #GtsHeap. - * - * Returns: the element at the top of the heap. - */ -gpointer gts_heap_top (GtsHeap * heap) -{ - GPtrArray * elts; - guint len; - - g_return_val_if_fail (heap != NULL, NULL); - - elts = heap->elts; - len = elts->len; - if (len == 0) - return NULL; - return elts->pdata[0]; -} - -/** - * gts_heap_destroy: - * @heap: a #GtsHeap. - * - * Free all the memory allocated for @heap. - */ -void gts_heap_destroy (GtsHeap * heap) -{ - g_return_if_fail (heap != NULL); - - g_ptr_array_free (heap->elts, TRUE); - g_free (heap); -} - -/** - * gts_heap_thaw: - * @heap: a #GtsHeap. - * - * If @heap has been frozen previously using gts_heap_freeze(), reorder it - * in O(n) time and unfreeze it. - */ -void gts_heap_thaw (GtsHeap * heap) -{ - guint i; - - g_return_if_fail (heap != NULL); - - if (!heap->frozen) - return; - - for (i = heap->elts->len/2; i > 0; i--) - sift_down (heap, i); - - heap->frozen = FALSE; -} - -/** - * gts_heap_foreach: - * @heap: a #GtsHeap. - * @func: the function to call for each element in the heap. - * @user_data: to pass to @func. - */ -void gts_heap_foreach (GtsHeap * heap, - GFunc func, - gpointer user_data) -{ - guint i; - GPtrArray * elts; - - g_return_if_fail (heap != NULL); - g_return_if_fail (func != NULL); - - elts = heap->elts; - for (i = 0; i < elts->len; i++) - (*func) (elts->pdata[i], user_data); -} - -/** - * gts_heap_freeze: - * @heap: a #GtsHeap. - * - * Freezes the heap. Any subsequent operation will not preserve the heap - * property. Used in conjunction with gts_heap_insert() and gts_heap_thaw() - * to create a heap in O(n) time. - */ -void gts_heap_freeze (GtsHeap * heap) -{ - g_return_if_fail (heap != NULL); - - heap->frozen = TRUE; -} - -/** - * gts_heap_size: - * @heap: a #GtsHeap. - * - * Returns: the number of items in @heap. - */ -guint gts_heap_size (GtsHeap * heap) -{ - g_return_val_if_fail (heap != NULL, 0); - - return heap->elts->len; -} Index: trunk/src_3rd/gts/kdtree.c =================================================================== --- trunk/src_3rd/gts/kdtree.c (revision 6802) +++ trunk/src_3rd/gts/kdtree.c (nonexistent) @@ -1,152 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include "gts.h" - - -static int compare_x (const void * p1, const void * p2) { - GtsPoint - * pp1 = *((gpointer *) p1), - * pp2 = *((gpointer *) p2); - if (pp1->x > pp2->x) - return 1; - return -1; -} - -static int compare_y (const void * p1, const void * p2) { - GtsPoint - * pp1 = *((gpointer *) p1), - * pp2 = *((gpointer *) p2); - if (pp1->y > pp2->y) - return 1; - return -1; -} - -static int compare_z (const void * p1, const void * p2) { - GtsPoint - * pp1 = *((gpointer *) p1), - * pp2 = *((gpointer *) p2); - if (pp1->z > pp2->z) - return 1; - return -1; -} - -/** - * gts_kdtree_new: - * @points: an array of #GtsPoint. - * @compare: always %NULL. - * - * Note that the order of the points in array @points is modified by this - * function. - * - * Returns: a new 3D tree for @points. - */ -GNode * gts_kdtree_new (GPtrArray * points, - int (*compare) (const void *, const void *)) -{ - guint middle; - GPtrArray array; - GNode * node; - GtsPoint * point; - - g_return_val_if_fail (points != NULL, NULL); - g_return_val_if_fail (points->len > 0, NULL); - - /* sort the points */ - if (compare == compare_x) compare = compare_y; - else if (compare == compare_y) compare = compare_z; - else compare = compare_x; - qsort (points->pdata, points->len, sizeof (gpointer), compare); - - middle = (points->len - 1)/2; - point = points->pdata[middle]; - node = g_node_new (point); - - if (points->len > 1) { - array.len = middle; - if (array.len > 0) { - array.pdata = points->pdata; - g_node_prepend (node, gts_kdtree_new (&array, compare)); - } - else - g_node_prepend (node, g_node_new (NULL)); - - array.len = points->len - middle - 1; - if (array.len > 0) { - array.pdata = &(points->pdata[middle + 1]); - g_node_prepend (node, gts_kdtree_new (&array, compare)); - } - else - g_node_prepend (node, g_node_new (NULL)); - } - - return node; -} - -/** - * gts_kdtree_range: - * @tree: a 3D tree. - * @bbox: a #GtsBBox. - * @compare: always %NULL. - * - * Returns: a list of #GtsPoint belonging to @tree which are inside @bbox. - */ -GSList * gts_kdtree_range (GNode * tree_3d, - GtsBBox * bbox, - int (*compare) (const void *, const void *)) -{ - GSList * list = NULL; - GtsPoint * p; - gdouble left, right, v; - GNode * node; - - g_return_val_if_fail (tree_3d != NULL, NULL); - g_return_val_if_fail (bbox != NULL, NULL); - - p = tree_3d->data; - if (p == NULL) - return NULL; - - if (gts_bbox_point_is_inside (bbox, p)) - list = g_slist_prepend (list, p); - - if (compare == compare_x) { - left = bbox->y1; right = bbox->y2; v = p->y; - compare = compare_y; - } - else if (compare == compare_y) { - left = bbox->z1; right = bbox->z2; v = p->z; - compare = compare_z; - } - else { - left = bbox->x1; right = bbox->x2; v = p->x; - compare = compare_x; - } - - if ((node = tree_3d->children)) { - if (right >= v) - list = g_slist_concat (list, gts_kdtree_range (node, bbox, compare)); - node = node->next; - if (left <= v) - list = g_slist_concat (list, gts_kdtree_range (node, bbox, compare)); - } - return list; -} - Index: trunk/src_3rd/gts/curvature.c =================================================================== --- trunk/src_3rd/gts/curvature.c (revision 6802) +++ trunk/src_3rd/gts/curvature.c (nonexistent) @@ -1,621 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999-2002 Ray Jones, Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include "gts.h" - -static gboolean angle_obtuse (GtsVertex * v, GtsFace * f) -{ - GtsEdge * e = gts_triangle_edge_opposite (GTS_TRIANGLE (f), v); - GtsVector vec1, vec2; - - gts_vector_init (vec1, GTS_POINT (v), GTS_POINT (GTS_SEGMENT (e)->v1)); - gts_vector_init (vec2, GTS_POINT (v), GTS_POINT (GTS_SEGMENT (e)->v2)); - - return (gts_vector_scalar (vec1, vec2) < 0.0); -} - -static gboolean triangle_obtuse (GtsVertex * v, GtsFace * f) -{ - GtsEdge * e = gts_triangle_edge_opposite (GTS_TRIANGLE (f), v); - - return (angle_obtuse (v, f) || - angle_obtuse (GTS_SEGMENT (e)->v1, f) || - angle_obtuse (GTS_SEGMENT (e)->v2, f)); -} - -static gdouble cotan (GtsVertex * vo, GtsVertex * v1, GtsVertex * v2) -{ - /* cf. Appendix B of [Meyer et al 2002] */ - GtsVector u, v; - gdouble udotv, denom; - - gts_vector_init (u, GTS_POINT (vo), GTS_POINT (v1)); - gts_vector_init (v, GTS_POINT (vo), GTS_POINT (v2)); - - udotv = gts_vector_scalar (u, v); - denom = sqrt (gts_vector_scalar (u,u)*gts_vector_scalar (v,v) - - udotv*udotv); - - - /* denom can be zero if u==v. Returning 0 is acceptable, based on - * the callers of this function below. */ - if (denom == 0.0) return (0.0); - - return (udotv/denom); -} - -static gdouble angle_from_cotan (GtsVertex * vo, - GtsVertex * v1, GtsVertex * v2) -{ - /* cf. Appendix B and the caption of Table 1 from [Meyer et al 2002] */ - GtsVector u, v; - gdouble udotv, denom; - - gts_vector_init (u, GTS_POINT (vo), GTS_POINT (v1)); - gts_vector_init (v, GTS_POINT (vo), GTS_POINT (v2)); - - udotv = gts_vector_scalar (u, v); - denom = sqrt (gts_vector_scalar (u,u)*gts_vector_scalar (v,v) - - udotv*udotv); - - /* Note: I assume this is what they mean by using atan2 (). -Ray Jones */ - - /* tan = denom/udotv = y/x (see man page for atan2) */ - return (fabs (atan2 (denom, udotv))); -} - -static gdouble region_area (GtsVertex * v, GtsFace * f) -{ - /* cf. Section 3.3 of [Meyer et al 2002] */ - - if (gts_triangle_area (GTS_TRIANGLE (f)) == 0.0) return (0.0); - - if (triangle_obtuse (v, f)) { - if (angle_obtuse (v, f)) - return (gts_triangle_area (GTS_TRIANGLE (f))/2.0); - else - return (gts_triangle_area (GTS_TRIANGLE (f))/4.0); - } else { - GtsEdge * e = gts_triangle_edge_opposite (GTS_TRIANGLE (f), v); - - return ((cotan (GTS_SEGMENT (e)->v1, v, GTS_SEGMENT (e)->v2)* - gts_point_distance2 (GTS_POINT (v), - GTS_POINT (GTS_SEGMENT (e)->v2)) + - cotan (GTS_SEGMENT (e)->v2, v, GTS_SEGMENT (e)->v1)* - gts_point_distance2 (GTS_POINT (v), - GTS_POINT (GTS_SEGMENT (e)->v1))) - /8.0); - } -} - -/** - * gts_vertex_mean_curvature_normal: - * @v: a #GtsVertex. - * @s: a #GtsSurface. - * @Kh: the Mean Curvature Normal at @v. - * - * Computes the Discrete Mean Curvature Normal approximation at @v. - * The mean curvature at @v is half the magnitude of the vector @Kh. - * - * Note: the normal computed is not unit length, and may point either - * into or out of the surface, depending on the curvature at @v. It - * is the responsibility of the caller of the function to use the mean - * curvature normal appropriately. - * - * This approximation is from the paper: - * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds - * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr - * VisMath '02, Berlin (Germany) - * http://www-grail.usc.edu/pubs.html - * - * Returns: %TRUE if the operator could be evaluated, %FALSE if the - * evaluation failed for some reason (@v is boundary or is the - * endpoint of a non-manifold edge.) - */ -gboolean gts_vertex_mean_curvature_normal (GtsVertex * v, GtsSurface * s, - GtsVector Kh) -{ - GSList * faces, * edges, * i; - gdouble area = 0.0; - - g_return_val_if_fail (v != NULL, FALSE); - g_return_val_if_fail (s != NULL, FALSE); - - /* this operator is not defined for boundary edges */ - if (gts_vertex_is_boundary (v, s)) return (FALSE); - - faces = gts_vertex_faces (v, s, NULL); - g_return_val_if_fail (faces != NULL, FALSE); - - edges = gts_vertex_fan_oriented (v, s); - if (edges == NULL) { - g_slist_free (faces); - return (FALSE); - } - - i = faces; - while (i) { - GtsFace * f = i->data; - - area += region_area (v, f); - i = i->next; - } - g_slist_free (faces); - - Kh[0] = Kh[1] = Kh[2] = 0.0; - - i = edges; - while (i) { - GtsEdge * e = i->data; - GtsVertex * v1 = GTS_SEGMENT (e)->v1; - GtsVertex * v2 = GTS_SEGMENT (e)->v2; - gdouble temp; - - temp = cotan (v1, v, v2); - Kh[0] += temp*(GTS_POINT (v2)->x - GTS_POINT (v)->x); - Kh[1] += temp*(GTS_POINT (v2)->y - GTS_POINT (v)->y); - Kh[2] += temp*(GTS_POINT (v2)->z - GTS_POINT (v)->z); - - temp = cotan (v2, v, v1); - Kh[0] += temp*(GTS_POINT (v1)->x - GTS_POINT (v)->x); - Kh[1] += temp*(GTS_POINT (v1)->y - GTS_POINT (v)->y); - Kh[2] += temp*(GTS_POINT (v1)->z - GTS_POINT (v)->z); - - i = i->next; - } - g_slist_free (edges); - - if (area > 0.0) { - Kh[0] /= 2*area; - Kh[1] /= 2*area; - Kh[2] /= 2*area; - } else { - return (FALSE); - } - - return TRUE; -} - -/** - * gts_vertex_gaussian_curvature: - * @v: a #GtsVertex. - * @s: a #GtsSurface. - * @Kg: the Discrete Gaussian Curvature approximation at @v. - * - * Computes the Discrete Gaussian Curvature approximation at @v. - * - * This approximation is from the paper: - * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds - * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr - * VisMath '02, Berlin (Germany) - * http://www-grail.usc.edu/pubs.html - * - * Returns: %TRUE if the operator could be evaluated, %FALSE if the - * evaluation failed for some reason (@v is boundary or is the - * endpoint of a non-manifold edge.) - */ -gboolean gts_vertex_gaussian_curvature (GtsVertex * v, GtsSurface * s, - gdouble * Kg) -{ - GSList * faces, * edges, * i; - gdouble area = 0.0; - gdouble angle_sum = 0.0; - - g_return_val_if_fail (v != NULL, FALSE); - g_return_val_if_fail (s != NULL, FALSE); - g_return_val_if_fail (Kg != NULL, FALSE); - - /* this operator is not defined for boundary edges */ - if (gts_vertex_is_boundary (v, s)) return (FALSE); - - faces = gts_vertex_faces (v, s, NULL); - g_return_val_if_fail (faces != NULL, FALSE); - - edges = gts_vertex_fan_oriented (v, s); - if (edges == NULL) { - g_slist_free (faces); - return (FALSE); - } - - i = faces; - while (i) { - GtsFace * f = i->data; - - area += region_area (v, f); - i = i->next; - } - g_slist_free (faces); - - i = edges; - while (i) { - GtsEdge * e = i->data; - GtsVertex * v1 = GTS_SEGMENT (e)->v1; - GtsVertex * v2 = GTS_SEGMENT (e)->v2; - - angle_sum += angle_from_cotan (v, v1, v2); - i = i->next; - } - g_slist_free (edges); - - *Kg = (2.0*M_PI - angle_sum)/area; - - return TRUE; -} - -/** - * gts_vertex_principal_curvatures: - * @Kh: mean curvature. - * @Kg: Gaussian curvature. - * @K1: first principal curvature. - * @K2: second principal curvature. - * - * Computes the principal curvatures at a point given the mean and - * Gaussian curvatures at that point. - * - * The mean curvature can be computed as one-half the magnitude of the - * vector computed by gts_vertex_mean_curvature_normal(). - * - * The Gaussian curvature can be computed with - * gts_vertex_gaussian_curvature(). - */ -void gts_vertex_principal_curvatures (gdouble Kh, gdouble Kg, - gdouble * K1, gdouble * K2) -{ - gdouble temp = Kh*Kh - Kg; - - g_return_if_fail (K1 != NULL); - g_return_if_fail (K2 != NULL); - - if (temp < 0.0) temp = 0.0; - temp = sqrt (temp); - *K1 = Kh + temp; - *K2 = Kh - temp; -} - -/* from Maple */ -static void linsolve (gdouble m11, gdouble m12, gdouble b1, - gdouble m21, gdouble m22, gdouble b2, - gdouble * x1, gdouble * x2) -{ - gdouble temp; - - temp = 1.0 / (m21*m12 - m11*m22); - *x1 = (m12*b2 - m22*b1)*temp; - *x2 = (m11*b2 - m21*b1)*temp; -} - -/* from Maple - largest eigenvector of [a b; b c] */ -static void eigenvector (gdouble a, gdouble b, gdouble c, - GtsVector e) -{ - if (b == 0.0) { - e[0] = 0.0; - } else { - e[0] = -(c - a - sqrt (c*c - 2*a*c + a*a + 4*b*b))/(2*b); - } - e[1] = 1.0; - e[2] = 0.0; -} - -/** - * gts_vertex_principal_directions: - * @v: a #GtsVertex. - * @s: a #GtsSurface. - * @Kh: mean curvature normal (a #GtsVector). - * @Kg: Gaussian curvature (a gdouble). - * @e1: first principal curvature direction (direction of largest curvature). - * @e2: second principal curvature direction. - * - * Computes the principal curvature directions at a point given @Kh - * and @Kg, the mean curvature normal and Gaussian curvatures at that - * point, computed with gts_vertex_mean_curvature_normal() and - * gts_vertex_gaussian_curvature(), respectively. - * - * Note that this computation is very approximate and tends to be - * unstable. Smoothing of the surface or the principal directions may - * be necessary to achieve reasonable results. - */ -void gts_vertex_principal_directions (GtsVertex * v, GtsSurface * s, - GtsVector Kh, gdouble Kg, - GtsVector e1, GtsVector e2) -{ - GtsVector N; - gdouble normKh; - GSList * i, * j; - GtsVector basis1, basis2, d, eig; - gdouble ve2, vdotN; - gdouble aterm_da, bterm_da, cterm_da, const_da; - gdouble aterm_db, bterm_db, cterm_db, const_db; - gdouble a, b, c; - gdouble K1, K2; - gdouble *weights, *kappas, *d1s, *d2s; - gint edge_count; - gdouble err_e1, err_e2; - int e; - - /* compute unit normal */ - normKh = sqrt (gts_vector_scalar (Kh, Kh)); - - if (normKh > 0.0) { - N[0] = Kh[0] / normKh; - N[1] = Kh[1] / normKh; - N[2] = Kh[2] / normKh; - } else { - /* This vertex is a point of zero mean curvature (flat or saddle - * point). Compute a normal by averaging the adjacent triangles - */ - N[0] = N[1] = N[2] = 0.0; - i = gts_vertex_faces (v, s, NULL); - while (i) { - gdouble x, y, z; - gts_triangle_normal (GTS_TRIANGLE ((GtsFace *) i->data), - &x, &y, &z); - N[0] += x; - N[1] += y; - N[2] += z; - - i = i->next; - } - g_return_if_fail (gts_vector_norm (N) > 0.0); - gts_vector_normalize (N); - } - - - /* construct a basis from N: */ - /* set basis1 to any component not the largest of N */ - basis1[0] = basis1[1] = basis1[2] = 0.0; - if (fabs (N[0]) > fabs (N[1])) - basis1[1] = 1.0; - else - basis1[0] = 1.0; - - /* make basis2 orthogonal to N */ - gts_vector_cross (basis2, N, basis1); - gts_vector_normalize (basis2); - - /* make basis1 orthogonal to N and basis2 */ - gts_vector_cross (basis1, N, basis2); - gts_vector_normalize (basis1); - - aterm_da = bterm_da = cterm_da = const_da = 0.0; - aterm_db = bterm_db = cterm_db = const_db = 0.0; - - weights = g_malloc (sizeof (gdouble)*g_slist_length (v->segments)); - kappas = g_malloc (sizeof (gdouble)*g_slist_length (v->segments)); - d1s = g_malloc (sizeof (gdouble)*g_slist_length (v->segments)); - d2s = g_malloc (sizeof (gdouble)*g_slist_length (v->segments)); - edge_count = 0; - - i = v->segments; - while (i) { - GtsEdge * e; - GtsFace * f1, * f2; - gdouble weight, kappa, d1, d2; - GtsVector vec_edge; - - if (! GTS_IS_EDGE (i->data)) { - i = i->next; - continue; - } - - e = i->data; - - /* since this vertex passed the tests in - * gts_vertex_mean_curvature_normal(), this should be true. */ - g_assert (gts_edge_face_number (e, s) == 2); - - /* identify the two triangles bordering e in s */ - f1 = f2 = NULL; - j = e->triangles; - while (j) { - if ((! GTS_IS_FACE (j->data)) || - (! gts_face_has_parent_surface (GTS_FACE (j->data), s))) { - j = j->next; - continue; - } - if (f1 == NULL) - f1 = GTS_FACE (j->data); - else { - f2 = GTS_FACE (j->data); - break; - } - j = j->next; - } - g_assert (f2 != NULL); - - /* We are solving for the values of the curvature tensor - * B = [ a b ; b c ]. - * The computations here are from section 5 of [Meyer et al 2002]. - * - * The first step is to calculate the linear equations governing - * the values of (a,b,c). These can be computed by setting the - * derivatives of the error E to zero (section 5.3). - * - * Since a + c = norm(Kh), we only compute the linear equations - * for dE/da and dE/db. (NB: [Meyer et al 2002] has the - * equation a + b = norm(Kh), but I'm almost positive this is - * incorrect.) - * - * Note that the w_ij (defined in section 5.2) are all scaled by - * (1/8*A_mixed). We drop this uniform scale factor because the - * solution of the linear equations doesn't rely on it. - * - * The terms of the linear equations are xterm_dy with x in - * {a,b,c} and y in {a,b}. There are also const_dy terms that are - * the constant factors in the equations. - */ - - /* find the vector from v along edge e */ - gts_vector_init (vec_edge, GTS_POINT (v), - GTS_POINT ((GTS_SEGMENT (e)->v1 == v) ? - GTS_SEGMENT (e)->v2 : GTS_SEGMENT (e)->v1)); - ve2 = gts_vector_scalar (vec_edge, vec_edge); - vdotN = gts_vector_scalar (vec_edge, N); - - /* section 5.2 - There is a typo in the computation of kappa. The - * edges should be x_j-x_i. - */ - kappa = 2.0 * vdotN / ve2; - - /* section 5.2 */ - - /* I don't like performing a minimization where some of the - * weights can be negative (as can be the case if f1 or f2 are - * obtuse). To ensure all-positive weights, we check for - * obtuseness and use values similar to those in region_area(). */ - weight = 0.0; - if (! triangle_obtuse(v, f1)) { - weight += ve2 * - cotan (gts_triangle_vertex_opposite (GTS_TRIANGLE (f1), e), - GTS_SEGMENT (e)->v1, GTS_SEGMENT (e)->v2) / 8.0; - } else { - if (angle_obtuse (v, f1)) { - weight += ve2 * gts_triangle_area (GTS_TRIANGLE (f1)) / 4.0; - } else { - weight += ve2 * gts_triangle_area (GTS_TRIANGLE (f1)) / 8.0; - } - } - - if (! triangle_obtuse(v, f2)) { - weight += ve2 * - cotan (gts_triangle_vertex_opposite (GTS_TRIANGLE (f2), e), - GTS_SEGMENT (e)->v1, GTS_SEGMENT (e)->v2) / 8.0; - } else { - if (angle_obtuse (v, f2)) { - weight += ve2 * gts_triangle_area (GTS_TRIANGLE (f2)) / 4.0; - } else { - weight += ve2 * gts_triangle_area (GTS_TRIANGLE (f2)) / 8.0; - } - } - - /* projection of edge perpendicular to N (section 5.3) */ - d[0] = vec_edge[0] - vdotN * N[0]; - d[1] = vec_edge[1] - vdotN * N[1]; - d[2] = vec_edge[2] - vdotN * N[2]; - gts_vector_normalize (d); - - /* not explicit in the paper, but necessary. Move d to 2D basis. */ - d1 = gts_vector_scalar (d, basis1); - d2 = gts_vector_scalar (d, basis2); - - /* store off the curvature, direction of edge, and weights for later use */ - weights[edge_count] = weight; - kappas[edge_count] = kappa; - d1s[edge_count] = d1; - d2s[edge_count] = d2; - edge_count++; - - /* Finally, update the linear equations */ - aterm_da += weight * d1 * d1 * d1 * d1; - bterm_da += weight * d1 * d1 * 2 * d1 * d2; - cterm_da += weight * d1 * d1 * d2 * d2; - const_da += weight * d1 * d1 * (- kappa); - - aterm_db += weight * d1 * d2 * d1 * d1; - bterm_db += weight * d1 * d2 * 2 * d1 * d2; - cterm_db += weight * d1 * d2 * d2 * d2; - const_db += weight * d1 * d2 * (- kappa); - - i = i->next; - } - - /* now use the identity (Section 5.3) a + c = |Kh| = 2 * kappa_h */ - aterm_da -= cterm_da; - const_da += cterm_da * normKh; - - aterm_db -= cterm_db; - const_db += cterm_db * normKh; - - /* check for solvability of the linear system */ - if (((aterm_da * bterm_db - aterm_db * bterm_da) != 0.0) && - ((const_da != 0.0) || (const_db != 0.0))) { - linsolve (aterm_da, bterm_da, -const_da, - aterm_db, bterm_db, -const_db, - &a, &b); - - c = normKh - a; - - eigenvector (a, b, c, eig); - } else { - /* region of v is planar */ - eig[0] = 1.0; - eig[1] = 0.0; - } - - /* Although the eigenvectors of B are good estimates of the - * principal directions, it seems that which one is attached to - * which curvature direction is a bit arbitrary. This may be a bug - * in my implementation, or just a side-effect of the inaccuracy of - * B due to the discrete nature of the sampling. - * - * To overcome this behavior, we'll evaluate which assignment best - * matches the given eigenvectors by comparing the curvature - * estimates computed above and the curvatures calculated from the - * discrete differential operators. */ - - gts_vertex_principal_curvatures (0.5 * normKh, Kg, &K1, &K2); - - err_e1 = err_e2 = 0.0; - /* loop through the values previously saved */ - for (e = 0; e < edge_count; e++) { - gdouble weight, kappa, d1, d2; - gdouble temp1, temp2; - gdouble delta; - - weight = weights[e]; - kappa = kappas[e]; - d1 = d1s[e]; - d2 = d2s[e]; - - temp1 = fabs (eig[0] * d1 + eig[1] * d2); - temp1 = temp1 * temp1; - temp2 = fabs (eig[1] * d1 - eig[0] * d2); - temp2 = temp2 * temp2; - - /* err_e1 is for K1 associated with e1 */ - delta = K1 * temp1 + K2 * temp2 - kappa; - err_e1 += weight * delta * delta; - - /* err_e2 is for K1 associated with e2 */ - delta = K2 * temp1 + K1 * temp2 - kappa; - err_e2 += weight * delta * delta; - } - g_free (weights); - g_free (kappas); - g_free (d1s); - g_free (d2s); - - /* rotate eig by a right angle if that would decrease the error */ - if (err_e2 < err_e1) { - gdouble temp = eig[0]; - - eig[0] = eig[1]; - eig[1] = -temp; - } - - e1[0] = eig[0] * basis1[0] + eig[1] * basis2[0]; - e1[1] = eig[0] * basis1[1] + eig[1] * basis2[1]; - e1[2] = eig[0] * basis1[2] + eig[1] * basis2[2]; - gts_vector_normalize (e1); - - /* make N,e1,e2 a right handed coordinate sytem */ - gts_vector_cross (e2, N, e1); - gts_vector_normalize (e2); -} Index: trunk/src_3rd/gts/pgraph.c =================================================================== --- trunk/src_3rd/gts/pgraph.c (revision 6802) +++ trunk/src_3rd/gts/pgraph.c (nonexistent) @@ -1,584 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "gts.h" - -/* GtsGNodeSplit */ - -static void gnode_split_destroy (GtsObject * object) -{ - GtsGNodeSplit * ns = GTS_GNODE_SPLIT (object); - - if (gts_container_size (GTS_CONTAINER (ns->n)) == 0) { - g_assert (GTS_SLIST_CONTAINEE (ns->n)->containers == NULL); - gts_object_destroy (GTS_OBJECT (ns->n)); - } - else { - /* GtsGNode * n1 = GTS_GNODE_SPLIT_N1 (ns); */ - /* GtsGNode * n2 = GTS_GNODE_SPLIT_N2 (ns); */ - - g_warning ("Memory deallocation for GtsGNodeSplit not fully implemented yet: memory leak!"); - } - - (* GTS_OBJECT_CLASS (gts_gnode_split_class ())->parent_class->destroy) - (object); -} - -static void gnode_split_class_init (GtsGNodeSplitClass * klass) -{ - GTS_OBJECT_CLASS (klass)->destroy = gnode_split_destroy; -} - -static void gnode_split_init (GtsGNodeSplit * ns) -{ - ns->n = NULL; - ns->n1 = ns->n2 = NULL; -} - -/** - * gts_gnode_split_class: - * - * Returns: the #GtsGNodeSplitClass. - */ -GtsGNodeSplitClass * gts_gnode_split_class (void) -{ - static GtsGNodeSplitClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo gnode_split_info = { - "GtsGNodeSplit", - sizeof (GtsGNodeSplit), - sizeof (GtsGNodeSplitClass), - (GtsObjectClassInitFunc) gnode_split_class_init, - (GtsObjectInitFunc) gnode_split_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (gts_object_class (), &gnode_split_info); - } - - return klass; -} - -/** - * gts_gnode_split_new: - * @klass: a #GtsGNodeSplitClass. - * @n: a #GtsGNode. - * @n1: a #GtsGNodeSplit or #GtsGNode. - * @n2: a #GtsGNodeSplit or #GtsGNode. - * - * Creates a new #GtsGNodeSplit which would collapse @n1 and @n2 into - * @n. The collapse itself is not performed. - * - * Returns: the new #GtsGNodeSplit. - */ -GtsGNodeSplit * gts_gnode_split_new (GtsGNodeSplitClass * klass, - GtsGNode * n, - GtsObject * n1, - GtsObject * n2) -{ - GtsGNodeSplit * ns; - - g_return_val_if_fail (klass != NULL, NULL); - g_return_val_if_fail (n != NULL, NULL); - g_return_val_if_fail (GTS_IS_GNODE_SPLIT (n1) || GTS_IS_GNODE (n1), NULL); - g_return_val_if_fail (GTS_IS_GNODE_SPLIT (n2) || GTS_IS_GNODE (n2), NULL); - - ns = GTS_GNODE_SPLIT (gts_object_new (GTS_OBJECT_CLASS (klass))); - ns->n = n; - ns->n1 = n1; - ns->n2 = n2; - - return ns; -} - -static void connect_edge (GtsGEdge * e, gpointer * data) -{ - GtsGNode * n = data[0]; - GtsGNode * n1 = data[1]; - GtsGNode * n2 = data[2]; - - if (GTS_OBJECT (e)->reserved || /* edge is disconnected */ - gts_gedge_connects (e, n1, n2)) - return; - if (e->n1 == n1 || e->n1 == n2) - e->n1 = n; - else if (e->n2 == n1 || e->n2 == n2) - e->n2 = n; - else - g_assert_not_reached (); - gts_container_add (GTS_CONTAINER (n), GTS_CONTAINEE (e)); -} - -/** - * gts_gnode_split_collapse: - * @ns: a #GtsGNodeSplit. - * @g: a #GtsGraph. - * @klass: a #GtsWGEdgeClass. - * - * Collapses the node split @ns. Any new edge created during the - * process will be of class @klass. - */ -void gts_gnode_split_collapse (GtsGNodeSplit * ns, - GtsGraph * g, - GtsWGEdgeClass * klass) -{ - GtsGNode * n1, * n2; - GSList * i; - gpointer data[3]; - - g_return_if_fail (ns != NULL); - g_return_if_fail (g != NULL); - g_return_if_fail (gts_container_size (GTS_CONTAINER (ns->n)) == 0); - - n1 = GTS_GNODE_SPLIT_N1 (ns); - n2 = GTS_GNODE_SPLIT_N2 (ns); - - /* look for triangles */ - i = GTS_SLIST_CONTAINER (n1)->items; - while (i) { - GtsGEdge * e13 = i->data; - GtsGNode * n3 = GTS_GNODE_NEIGHBOR (n1, e13); - if (n3 != n2) { - GSList * j = GTS_SLIST_CONTAINER (n3)->items; - while (j) { - GtsGEdge * e32 = j->data; - GSList * next = j->next; - GtsGNode * n4 = GTS_GNODE_NEIGHBOR (n3, e32); - if (n4 == n2) { /* found triangle n1 (e13) n3 (e32) n2 */ - gts_wgedge_new (klass, ns->n, n3, - gts_gedge_weight (e13) + gts_gedge_weight (e32)); - GTS_OBJECT (e13)->reserved = n3; - GTS_OBJECT (e32)->reserved = n3; - GTS_SLIST_CONTAINER (n3)->items = - g_slist_remove (GTS_SLIST_CONTAINER (n3)->items, e32); - } - j = next; - } - if (GTS_OBJECT (e13)->reserved == n3) - GTS_SLIST_CONTAINER (n3)->items = - g_slist_remove (GTS_SLIST_CONTAINER (n3)->items, e13); - } - i = i->next; - } - - /* connect edges to new node */ - data[0] = ns->n; - data[1] = n1; - data[2] = n2; - gts_container_foreach (GTS_CONTAINER (n1), (GtsFunc) connect_edge, data); - gts_container_foreach (GTS_CONTAINER (n2), (GtsFunc) connect_edge, data); - - gts_allow_floating_gnodes = TRUE; - gts_container_remove (GTS_CONTAINER (g), GTS_CONTAINEE (n1)); - gts_container_remove (GTS_CONTAINER (g), GTS_CONTAINEE (n2)); - gts_allow_floating_gnodes = FALSE; - gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (ns->n)); -} - -static void restore_edge (GtsGEdge * e, gpointer * data) -{ - GtsGNode * n = data[0]; - GtsGNode * n1 = data[1]; - GtsGNode * n2 = data[2]; - GtsGNode * n3 = GTS_OBJECT (e)->reserved; - - if (n3) { /* e is a disconnected edge */ - GTS_OBJECT (e)->reserved = NULL; - gts_container_add (GTS_CONTAINER (n3), GTS_CONTAINEE (e)); - return; - } - - if (gts_gedge_connects (e, n1, n2)) - return; - - if (e->n1 == n) - e->n1 = n1; - else if (e->n2 == n) - e->n2 = n1; - else - g_assert_not_reached (); - GTS_SLIST_CONTAINER (n)->items = - g_slist_remove (GTS_SLIST_CONTAINER (n)->items, e); -} - -/** - * gts_gnode_split_expand: - * @ns: a #GtsGNodeSplit. - * @g: a #GtsGraph. - * - * Expands the node split ns adding the new nodes to @g. - */ -void gts_gnode_split_expand (GtsGNodeSplit * ns, - GtsGraph * g) -{ - GtsGNode * n1, * n2; - gpointer data[3]; - GSList * i; - - g_return_if_fail (ns != NULL); - g_return_if_fail (g != NULL); - g_return_if_fail (gts_containee_is_contained (GTS_CONTAINEE (ns->n), - GTS_CONTAINER (g))); - - n1 = GTS_GNODE_SPLIT_N1 (ns); - n2 = GTS_GNODE_SPLIT_N2 (ns); - - data[0] = ns->n; - data[1] = n1; - data[2] = n2; - gts_container_foreach (GTS_CONTAINER (n1), (GtsFunc) restore_edge, data); - data[1] = n2; - data[2] = n1; - gts_container_foreach (GTS_CONTAINER (n2), (GtsFunc) restore_edge, data); - - i = GTS_SLIST_CONTAINER (ns->n)->items; - while (i) { - GSList * next = i->next; - gts_container_remove (GTS_CONTAINER (ns->n), GTS_CONTAINEE (i->data)); - i = next; - } - g_assert (gts_container_size (GTS_CONTAINER (ns->n)) == 0); - - gts_allow_floating_gnodes = TRUE; - gts_container_remove (GTS_CONTAINER (g), GTS_CONTAINEE (ns->n)); - gts_allow_floating_gnodes = FALSE; - - gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (n1)); - gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (n2)); -} - -/* GtsPGraph */ - -static void pgraph_destroy (GtsObject * object) -{ - GtsPGraph * pg = GTS_PGRAPH (object); - guint i; - - for (i = 0; i < pg->split->len; i++) - gts_object_destroy (GTS_OBJECT (g_ptr_array_index (pg->split, i))); - g_ptr_array_free (pg->split, TRUE); - g_array_free (pg->levels, TRUE); - - (* GTS_OBJECT_CLASS (gts_pgraph_class ())->parent_class->destroy) (object); -} - -static void pgraph_class_init (GtsPGraphClass * klass) -{ - GTS_OBJECT_CLASS (klass)->destroy = pgraph_destroy; -} - -static void pgraph_init (GtsPGraph * pg) -{ - pg->g = NULL; - pg->split = g_ptr_array_new (); - pg->levels = g_array_new (FALSE, FALSE, sizeof (guint)); - pg->level = 0; - pg->split_class = gts_gnode_split_class (); - pg->edge_class = gts_wgedge_class (); - pg->pos = pg->min = 0; -} - -/** - * gts_pgraph_class: - * - * Returns: the #GtsPGraphClass. - */ -GtsPGraphClass * gts_pgraph_class (void) -{ - static GtsPGraphClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo pgraph_info = { - "GtsPGraph", - sizeof (GtsPGraph), - sizeof (GtsPGraphClass), - (GtsObjectClassInitFunc) pgraph_class_init, - (GtsObjectInitFunc) pgraph_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (gts_object_class (), &pgraph_info); - } - - return klass; -} - -static void match_neighbor (GtsGNode * n, gpointer * data) -{ - if (!GTS_OBJECT (n)->reserved) { - GtsGraph * g = data[0]; - GSList ** list = data[1]; - GSList * i = GTS_SLIST_CONTAINER (n)->items; - gfloat wmax = - G_MAXFLOAT; - GtsGEdge * emax = NULL; - - while (i) { - GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); - if (!GTS_OBJECT (n1)->reserved && - gts_gedge_weight (i->data) > wmax && - gts_containee_is_contained (GTS_CONTAINEE (n1), GTS_CONTAINER (g))) { - emax = i->data; - wmax = gts_gedge_weight (emax); - } - i = i->next; - } - if (emax) { - GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, emax); - - GTS_OBJECT (n1)->reserved = n; - GTS_OBJECT (n)->reserved = n1; - *list = g_slist_prepend (*list, emax); - } - } -} - -static GSList * maximal_matching (GtsGraph * g) -{ - GSList * list = NULL; - gpointer data[2]; - - data[0] = g; - data[1] = &list; - gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) match_neighbor, data); - gts_container_foreach (GTS_CONTAINER (g), - (GtsFunc) gts_object_reset_reserved, - NULL); - - return list; -} - -/** - * gts_pgraph_new: - * @klass: a #GtsPGraphClass. - * @g: a #GtsGraph. - * @split_class: a #GtsGNodeSplitClass. - * @node_class: a #GtsWGNodeClass. - * @edge_class: a #GtsWGEdgeClass. - * @min: the minimum number of nodes. - * - * Creates a new multilevel approximation of graph @g. At each level a - * maximal matching is created using the Heavy Edge Matching (HEM) - * technique of Karypis and Kumar (1997). The newly created nodes are - * of type @node_class and their weight is set to the sum of the - * weights of their children. The newly created edges are of type - * @edge_class and their weight is set to the sum of the weight of the - * collapsed edges. The last level is reached when the maximal - * matching obtained would lead to a graph with less than @min nodes. - * - * Returns: the new #GtsPGraph containing the multilevel - * representation of @g. - */ -GtsPGraph * gts_pgraph_new (GtsPGraphClass * klass, - GtsGraph * g, - GtsGNodeSplitClass * split_class, - GtsWGNodeClass * node_class, - GtsWGEdgeClass * edge_class, - guint min) -{ - GtsPGraph * pg; - GSList * matching; - - g_return_val_if_fail (klass != NULL, NULL); - g_return_val_if_fail (g != NULL, NULL); - g_return_val_if_fail (split_class != NULL, NULL); - g_return_val_if_fail (node_class != NULL, NULL); - g_return_val_if_fail (edge_class != NULL, NULL); - - pg = GTS_PGRAPH (gts_object_new (GTS_OBJECT_CLASS (klass))); - pg->g = g; - pg->split_class = split_class; - pg->edge_class = edge_class; - - while (gts_container_size (GTS_CONTAINER (g)) > min && - (matching = maximal_matching (g))) { - GSList * i = matching; - guint size = gts_container_size (GTS_CONTAINER (g)); - - g_array_append_val (pg->levels, size); - - while (i && gts_container_size (GTS_CONTAINER (g)) > min) { - GtsGEdge * e = i->data; - GtsGNode * n = GTS_GNODE (gts_wgnode_new (node_class, - gts_gnode_weight (e->n1) + - gts_gnode_weight (e->n2))); - GtsGNodeSplit * ns = gts_gnode_split_new (split_class, n, - GTS_OBJECT (e->n1), - GTS_OBJECT (e->n2)); - gts_gnode_split_collapse (ns, g, edge_class); - g_ptr_array_add (pg->split, ns); - i = i->next; - } - g_slist_free (matching); - } - - pg->pos = pg->split->len; - pg->min = gts_container_size (GTS_CONTAINER (g)); - pg->level = pg->levels->len; - - return pg; -} - -/** - * gts_pgraph_add_node: - * @pg: a #GtsPGraph. - * - * Adds one node to the multilevel graph @pg by expanding the next - * available #GtsGNodeSplit. - * - * Returns: the expanded #GtsGNodeSplit or #NULL if all the - * #GtsGNodeSplit have already been expanded. - */ -GtsGNodeSplit * gts_pgraph_add_node (GtsPGraph * pg) -{ - GtsGNodeSplit * ns; - - g_return_val_if_fail (pg != NULL, NULL); - - if (pg->pos == 0) - return NULL; - - ns = g_ptr_array_index (pg->split, --pg->pos); - gts_gnode_split_expand (ns, pg->g); - - return ns; -} - -/** - * gts_pgraph_remove_node: - * @pg: a #GtsPGraph. - * - * Removes one node from the multilevel graph @pg by collapsing the - * first available #GtsGNodeSplit. - * - * Returns: the collapsed #GtsGNodeSplit or %NULL if all the - * #GtsGNodeSplit have already been collapsed. - */ -GtsGNodeSplit * gts_pgraph_remove_node (GtsPGraph * pg) -{ - GtsGNodeSplit * ns; - - g_return_val_if_fail (pg != NULL, NULL); - - if (pg->pos == pg->split->len) - return NULL; - - ns = g_ptr_array_index (pg->split, pg->pos++); - gts_gnode_split_collapse (ns, pg->g, pg->edge_class); - - return ns; -} - -/** - * gts_pgraph_max_node_number: - * @pg: a #GtsPGraph. - * - * Returns: the maximum number of nodes of @pg i.e. the number of - * nodes if all the #GtsGNodeSplit were expanded. - */ -guint gts_pgraph_max_node_number (GtsPGraph * pg) -{ - g_return_val_if_fail (pg != NULL, 0); - - return pg->min + pg->split->len; -} - -/** - * gts_pgraph_min_node_number: - * @pg: a #GtsPGraph. - * - * Returns: the minimum number of nodes of @pg i.e. the number of - * nodes if all the #GtsGNodeSplit were collapsed. - */ -guint gts_pgraph_min_node_number (GtsPGraph * pg) -{ - g_return_val_if_fail (pg != NULL, 0); - - return pg->min; -} - -/** - * gts_pgraph_set_node_number: - * @pg: a #GtsPGraph. - * @n: a number of nodes. - * - * Performs the required number of collapses or expansions to set the - * number of nodes of @pg to @n. - */ -void gts_pgraph_set_node_number (GtsPGraph * pg, guint n) -{ - g_return_if_fail (pg != NULL); - - n = pg->min + pg->split->len - n; - while (pg->pos > n && gts_pgraph_add_node (pg)) - ; - while (pg->pos < n && gts_pgraph_remove_node (pg)) - ; -} - -/** - * gts_pgraph_get_node_number: - * @pg: a #GtsPGraph. - * - * Returns: the current number of nodes of @pg. - */ -guint gts_pgraph_get_node_number (GtsPGraph * pg) -{ - g_return_val_if_fail (pg != NULL, 0); - - return pg->min + pg->split->len - pg->pos; -} - -/** - * gts_pgraph_down: - * @pg: a #GtsPGraph. - * @func: a #GtsFunc or %NULL. - * @data: user data to pass to @func. - * - * Performs the required number of expansions to go from the current - * level to the level immediately below. - * - * If @func is not %NULL, it is called after each #GtsGNodeSplit has - * been expanded. - * - * Returns: %FALSE if it is not possible to go down one level, %TRUE - * otherwise. - */ -gboolean gts_pgraph_down (GtsPGraph * pg, - GtsFunc func, - gpointer data) -{ - guint size; - - g_return_val_if_fail (pg != NULL, FALSE); - - if (pg->level == 0) - return FALSE; - - size = g_array_index (pg->levels, guint, --(pg->level)); - while (gts_container_size (GTS_CONTAINER (pg->g)) < size) { - GtsGNodeSplit * ns = gts_pgraph_add_node (pg); - - g_assert (ns); - if (func) - (* func) (ns, data); - } - return TRUE; -} - Index: trunk/src_3rd/gts/named.c =================================================================== --- trunk/src_3rd/gts/named.c (revision 6802) +++ trunk/src_3rd/gts/named.c (nonexistent) @@ -1,188 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include "gts.h" - -static void nvertex_read (GtsObject ** po, GtsFile * fp) -{ - if ((*po)->klass->parent_class->read) - (* (*po)->klass->parent_class->read) (po, fp); - - if (fp->type != '\n' && fp->type != GTS_ERROR) { - strncpy (GTS_NVERTEX (*po)->name, fp->token->str, GTS_NAME_LENGTH); - gts_file_next_token (fp); - } -} - -static void nvertex_write (GtsObject * o, FILE * fptr) -{ - GtsNVertex * nv = GTS_NVERTEX (o); - - (* o->klass->parent_class->write) (o, fptr); - if (nv->name[0] != '\0') - fprintf (fptr, " %s", nv->name); -} - -static void nvertex_class_init (GtsNVertexClass * klass) -{ - GTS_OBJECT_CLASS (klass)->read = nvertex_read; - GTS_OBJECT_CLASS (klass)->write = nvertex_write; -} - -static void nvertex_init (GtsNVertex * nvertex) -{ - nvertex->name[0] = '\0'; -} - -/** - * gts_nvertex_class: - * - * Returns: the #GtsNVertexClass. - */ -GtsNVertexClass * gts_nvertex_class (void) -{ - static GtsNVertexClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo nvertex_info = { - "GtsNVertex", - sizeof (GtsNVertex), - sizeof (GtsNVertexClass), - (GtsObjectClassInitFunc) nvertex_class_init, - (GtsObjectInitFunc) nvertex_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_vertex_class ()), - &nvertex_info); - } - - return klass; -} - -static void nedge_read (GtsObject ** po, GtsFile * fp) -{ - if (fp->type != GTS_STRING) { - gts_file_error (fp, "expecting a string (name)"); - return; - } - strncpy (GTS_NEDGE (*po)->name, fp->token->str, GTS_NAME_LENGTH); - gts_file_next_token (fp); -} - -static void nedge_write (GtsObject * o, FILE * fptr) -{ - GtsNEdge * ne = GTS_NEDGE (o); - - if (ne->name[0] != '\0') - fprintf (fptr, " %s", ne->name); -} - -static void nedge_class_init (GtsNEdgeClass * klass) -{ - GTS_OBJECT_CLASS (klass)->read = nedge_read; - GTS_OBJECT_CLASS (klass)->write = nedge_write; -} - -static void nedge_init (GtsNEdge * nedge) -{ - nedge->name[0] = '\0'; -} - -/** - * gts_nedge_class: - * - * Returns: the #GtsNEdgeClass. - */ -GtsNEdgeClass * gts_nedge_class (void) -{ - static GtsNEdgeClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo nedge_info = { - "GtsNEdge", - sizeof (GtsNEdge), - sizeof (GtsNEdgeClass), - (GtsObjectClassInitFunc) nedge_class_init, - (GtsObjectInitFunc) nedge_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_edge_class ()), - &nedge_info); - } - - return klass; -} - -static void nface_read (GtsObject ** po, GtsFile * fp) -{ - if (fp->type != GTS_STRING) { - gts_file_error (fp, "expecting a string (name)"); - return; - } - strncpy (GTS_NFACE (*po)->name, fp->token->str, GTS_NAME_LENGTH); - gts_file_next_token (fp); -} - -static void nface_write (GtsObject * o, FILE * fptr) -{ - GtsNFace * nf = GTS_NFACE (o); - - if (nf->name[0] != '\0') - fprintf (fptr, " %s", GTS_NFACE (o)->name); -} - -static void nface_class_init (GtsNFaceClass * klass) -{ - GTS_OBJECT_CLASS (klass)->read = nface_read; - GTS_OBJECT_CLASS (klass)->write = nface_write; -} - -static void nface_init (GtsNFace * nface) -{ - nface->name[0] = '\0'; -} - -/** - * gts_nface_class: - * - * Returns: the #GtsNFaceClass. - */ -GtsNFaceClass * gts_nface_class (void) -{ - static GtsNFaceClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo nface_info = { - "GtsNFace", - sizeof (GtsNFace), - sizeof (GtsNFaceClass), - (GtsObjectClassInitFunc) nface_class_init, - (GtsObjectInitFunc) nface_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_face_class ()), - &nface_info); - } - - return klass; -} Index: trunk/src_3rd/gts/vopt.c =================================================================== --- trunk/src_3rd/gts/vopt.c (revision 6802) +++ trunk/src_3rd/gts/vopt.c (nonexistent) @@ -1,521 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "gts.h" - -/* #define DEBUG_VOPT */ - -/* compute the normal (nx, ny, nz) as the cross-product of the first two - oriented edges and the norm nt = |t| as (v1xv2).v3 */ -static void triangle_normal (GtsTriangle * t, - gdouble * nx, - gdouble * ny, - gdouble * nz, - gdouble * nt) -{ - GtsPoint * p1, * p2 = NULL, * p3 = NULL; - gdouble x1, y1, z1, x2, y2, z2; - - g_return_if_fail (t != NULL); - - p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1); - if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v1) { - p2 = GTS_POINT (GTS_SEGMENT (t->e2)->v2); - p3 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); - } - else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v2) { - p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); - p3 = GTS_POINT (GTS_SEGMENT (t->e2)->v1); - } - else if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v2) { - p2 = GTS_POINT (GTS_SEGMENT (t->e2)->v1); - p3 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); - } - else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v1) { - p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); - p3 = GTS_POINT (GTS_SEGMENT (t->e2)->v2); - } - else - g_assert_not_reached (); - - x1 = p2->x - p1->x; - y1 = p2->y - p1->y; - z1 = p2->z - p1->z; - - x2 = p3->x - p1->x; - y2 = p3->y - p1->y; - z2 = p3->z - p1->z; - - *nt = ((p1->y*p2->z - p1->z*p2->y)*p3->x + - (p1->z*p2->x - p1->x*p2->z)*p3->y + - (p1->x*p2->y - p1->y*p2->x)*p3->z); - *nx = y1*z2 - z1*y2; - *ny = z1*x2 - x1*z2; - *nz = x1*y2 - y1*x2; -} - -static void boundary_preservation (GtsEdge * edge, - GtsFace * f, - GtsVector e1, GtsVector e2, - GtsMatrix * H, GtsVector c) -{ - GtsTriangle * t = GTS_TRIANGLE (f); - GtsEdge * edge2; - GtsVertex * v1 = GTS_SEGMENT (edge)->v1, * v2 = GTS_SEGMENT (edge)->v2; - GtsPoint * p1, * p2; - GtsVector e, e3; - - /* find orientation of segment */ - edge2 = edge == t->e1 ? t->e2 : edge == t->e2 ? t->e3 : t->e1; - if (v2 != GTS_SEGMENT (edge2)->v1 && v2 != GTS_SEGMENT (edge2)->v2) { - v2 = v1; v1 = GTS_SEGMENT (edge)->v2; - } - p1 = GTS_POINT (v1); - p2 = GTS_POINT (v2); - - e[0] = p2->x - p1->x; - e[1] = p2->y - p1->y; - e[2] = p2->z - p1->z; - - e1[0] += e[0]; - e1[1] += e[1]; - e1[2] += e[2]; - - e3[0] = p2->y*p1->z - p2->z*p1->y; - e3[1] = p2->z*p1->x - p2->x*p1->z; - e3[2] = p2->x*p1->y - p2->y*p1->x; - - e2[0] += e3[0]; - e2[1] += e3[1]; - e2[2] += e3[2]; - - H[0][0] += e[1]*e[1] + e[2]*e[2]; - H[0][1] -= e[0]*e[1]; - H[0][2] -= e[0]*e[2]; - H[1][0] = H[0][1]; - H[1][1] += e[0]*e[0] + e[2]*e[2]; - H[1][2] -= e[1]*e[2]; - H[2][0] = H[0][2]; - H[2][1] = H[1][2]; - H[2][2] += e[0]*e[0] + e[1]*e[1]; - - c[0] += e[1]*e3[2] - e[2]*e3[1]; - c[1] += e[2]*e3[0] - e[0]*e3[2]; - c[2] += e[0]*e3[1] - e[1]*e3[0]; -} - -static gdouble boundary_cost (GtsEdge * edge, - GtsFace * f, - GtsVertex * v) -{ - GtsTriangle * t = GTS_TRIANGLE (f); - GtsEdge * edge2; - GtsVertex * v1 = GTS_SEGMENT (edge)->v1, * v2 = GTS_SEGMENT (edge)->v2; - GtsPoint * p1, * p2; - GtsVector e; - GtsPoint * p = GTS_POINT (v); - - /* find orientation of segment */ - edge2 = edge == t->e1 ? t->e2 : edge == t->e2 ? t->e3 : t->e1; - if (v2 != GTS_SEGMENT (edge2)->v1 && v2 != GTS_SEGMENT (edge2)->v2) { - v2 = v1; v1 = GTS_SEGMENT (edge)->v2; - } - p1 = GTS_POINT (v1); - p2 = GTS_POINT (v2); - - e[0] = (p2->y - p1->y)*(p->z - p2->z) - (p2->z - p1->z)*(p->y - p2->y); - e[1] = (p2->z - p1->z)*(p->x - p2->x) - (p2->x - p1->x)*(p->z - p2->z); - e[2] = (p2->x - p1->x)*(p->y - p2->y) - (p2->y - p1->y)*(p->x - p2->x); - - return e[0]*e[0] + e[1]*e[1] + e[2]*e[2]; -} - -static gdouble edge_boundary_cost (GtsEdge * e, GtsVertex * v) -{ - gdouble cost = 0.; - GSList * i; - - i = GTS_SEGMENT (e)->v1->segments; - while (i) { - GtsFace * f; - if (GTS_IS_EDGE (i->data) && - (f = gts_edge_is_boundary (i->data, NULL))) - cost += boundary_cost (i->data, f, v); - i = i->next; - } - i = GTS_SEGMENT (e)->v2->segments; - while (i) { - GtsFace * f; - if (i->data != e && - GTS_IS_EDGE (i->data) && - (f = gts_edge_is_boundary (i->data, NULL))) - cost += boundary_cost (i->data, f, v); - i = i->next; - } - - return cost/4.; -} - -static gdouble edge_volume_cost (GtsEdge * e, GtsVertex * v) -{ - GSList * i, * triangles; - gdouble n1, n2, n3, nt; - gdouble cost = 0.0, a; - - triangles = gts_vertex_triangles (GTS_SEGMENT (e)->v1, NULL); - triangles = gts_vertex_triangles (GTS_SEGMENT (e)->v2, triangles); - - i = triangles; - while (i) { - if (GTS_IS_FACE (i->data)) { - triangle_normal (i->data, &n1, &n2, &n3, &nt); - a = GTS_POINT (v)->x*n1 + - GTS_POINT (v)->y*n2 + - GTS_POINT (v)->z*n3 - nt; - cost += a*a; - } - i = i->next; - } - g_slist_free (triangles); - - return cost/36.; -} - -static gdouble edge_shape_cost (GtsEdge * e, GtsVertex * v) -{ - GSList * list, * i; - GtsVertex - * v1 = GTS_SEGMENT (e)->v1, - * v2 = GTS_SEGMENT (e)->v2; - gdouble cost = 0.; - - list = gts_vertex_neighbors (v1, NULL, NULL); - list = gts_vertex_neighbors (v2, list, NULL); - i = list; - while (i) { - GtsPoint * p = i->data; - if (p != GTS_POINT (v1) && p != GTS_POINT (v2)) - cost += gts_point_distance2 (p, GTS_POINT (v)); - i = i->next; - } - g_slist_free (list); - - return cost; -} - -/** - * gts_volume_optimized_vertex: - * @edge: a #GtsEdge. - * @klass: a #GtsVertexClass to be used for the new vertex. - * @params: a #GtsVolumeOptimizedParms. - * - * Returns: a #GtsVertex which can be used to replace @edge for an - * edge collapse operation. The position of the vertex is optimized in - * order to minimize the changes in area and volume for the surface - * using @edge. The volume enclosed by the surface is locally - * preserved. For more details see "Fast and memory efficient - * polygonal simplification" (1998) and "Evaluation of memoryless - * simplification" (1999) by Lindstrom and Turk. - */ -GtsVertex * gts_volume_optimized_vertex (GtsEdge * edge, - GtsVertexClass * klass, - GtsVolumeOptimizedParams * params) -{ - GSList * triangles, * i; - gdouble sn1 = 0., sn2 = 0., sn3 = 0.; - gdouble sn11 = 0., sn22 = 0., sn33 = 0.; - gdouble sn12 = 0., sn13 = 0., sn23 = 0.; - gdouble st = 0., stn1 = 0., stn2 = 0., stn3 = 0.; - gdouble n1, n2, n3, nt; - GtsMatrix * A, * Ai; - GtsVector A1, b; - GtsVector e1 = {0., 0., 0.}, e2 = {0., 0., 0.}; - GtsMatrix * Hb; - GtsVector cb = {0., 0., 0.}; - GtsVertex * v; - GtsVertex * v1, * v2; - guint n = 0, nb = 0; -#ifdef DEBUG_VOPT - guint nold = 0; -#endif - - g_return_val_if_fail (edge != NULL, NULL); - g_return_val_if_fail (klass != NULL, NULL); - g_return_val_if_fail (params != NULL, NULL); - - A = gts_matrix_zero (NULL); - Hb = gts_matrix_zero (NULL); - v1 = GTS_SEGMENT (edge)->v1; - v2 = GTS_SEGMENT (edge)->v2; - - /* boundary preservation */ - i = v1->segments; - while (i) { - GtsEdge * edge1 = i->data; - GtsFace * f; - if (GTS_IS_EDGE (edge1) && - (f = gts_edge_is_boundary (edge1, NULL))) { - boundary_preservation (edge1, f, e1, e2, Hb, cb); - nb++; - } - i = i->next; - } - i = v2->segments; - while (i) { - GtsEdge * edge1 = i->data; - GtsFace * f; - if (edge1 != edge && - GTS_IS_EDGE (edge1) && - (f = gts_edge_is_boundary (edge1, NULL))) { - boundary_preservation (edge1, f, e1, e2, Hb, cb); - nb++; - } - i = i->next; - } - if (nb > 0) { - GtsMatrix * H = gts_matrix_new ( - e1[2]*e1[2] + e1[1]*e1[1], - e1[0]*e1[1], - e1[0]*e1[2], 0., - - e1[0]*e1[1], e1[2]*e1[2] + e1[0]*e1[0], - e1[1]*e1[2], 0., - - e1[0]*e1[2], - e1[1]*e1[2], e1[1]*e1[1] + e1[0]*e1[0], 0., - 0., 0., 0., 0.); - GtsVector c; - - c[0] = e1[1]*e2[2] - e1[2]*e2[1]; - c[1] = e1[2]*e2[0] - e1[0]*e2[2]; - c[2] = e1[0]*e2[1] - e1[1]*e2[0]; - n = gts_matrix_quadratic_optimization (A, b, n, H, c); - gts_matrix_destroy (H); - } - - g_assert (n <= 2); - -#ifdef DEBUG_VOPT - if (n != nold) { - fprintf (stderr, "--- boundary preservation ---\n"); - gts_matrix_print (A, stderr); - gts_vector_print (b, stderr); - nold = n; - } -#endif - - /* volume preservation */ - triangles = gts_vertex_triangles (v1, NULL); - triangles = gts_vertex_triangles (v2, triangles); - - i = triangles; - while (i) { - if (GTS_IS_FACE (i->data)) { - triangle_normal (i->data, &n1, &n2, &n3, &nt); - sn1 += n1; sn2 += n2; sn3 += n3; - sn11 += n1*n1; sn22 += n2*n2; sn33 += n3*n3; - sn12 += n1*n2; sn13 += n1*n3; sn23 += n2*n3; - st += nt; stn1 += nt*n1; stn2 += nt*n2; stn3 += nt*n3; - } - i = i->next; - } - g_slist_free (triangles); - - A1[0] = sn1; A1[1] = sn2; A1[2] = sn3; - n = gts_matrix_compatible_row (A, b, n, A1, st); - -#ifdef DEBUG_VOPT - if (n != nold) { - fprintf (stderr, "--- volume preservation ---\n"); - gts_matrix_print (A, stderr); - gts_vector_print (b, stderr); - nold = n; - } -#endif - -#if 1 /* Weighted average of volume and boundary optimization */ - if (n < 3) { - /* volume optimization and boundary optimization */ - GtsMatrix * H = gts_matrix_new (sn11, sn12, sn13, 0., - sn12, sn22, sn23, 0., - sn13, sn23, sn33, 0., - 0., 0., 0., 0.); - GtsVector c; - gdouble le = 9.*params->boundary_weight* - gts_point_distance2 (GTS_POINT (v1), - GTS_POINT (v2)); - guint i, j; - - c[0] = - stn1; c[1] = - stn2; c[2] = - stn3; - if (nb > 0) - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) - H[i][j] = params->volume_weight*H[i][j] + le*Hb[i][j]; - c[i] = params->volume_weight*c[i] + le*cb[i]; - } - n = gts_matrix_quadratic_optimization (A, b, n, H, c); - gts_matrix_destroy (H); - } - -#ifdef DEBUG_VOPT - if (n != nold) { - fprintf (stderr, "--- volume and boundary optimization ---\n"); - gts_matrix_print (A, stderr); - gts_vector_print (b, stderr); - nold = n; - } -#endif - - if (n < 3) { - /* triangle shape optimization */ - gdouble nv = 0.0; - GtsMatrix * H; - GtsVector c = {0., 0., 0.}; - GSList * list, * i; - - list = gts_vertex_neighbors (v1, NULL, NULL); - list = gts_vertex_neighbors (v2, list, NULL); - - i = list; - while (i) { - GtsPoint * p1 = i->data; - if (p1 != GTS_POINT (v1) && p1 != GTS_POINT (v2)) { - nv += 1.0; - c[0] -= p1->x; - c[1] -= p1->y; - c[2] -= p1->z; - } - i = i->next; - } - g_slist_free (list); - - H = gts_matrix_new (nv, 0., 0., 0., - 0., nv, 0., 0., - 0., 0., nv, 0., - 0., 0., 0., 0.); - n = gts_matrix_quadratic_optimization (A, b, n, H, c); - gts_matrix_destroy (H); - } - -#ifdef DEBUG_VOPT - if (n != nold) { - fprintf (stderr, "--- triangle shape optimization ---\n"); - gts_matrix_print (A, stderr); - gts_vector_print (b, stderr); - nold = n; - } -#endif -#else /* Weighted average of volume, boundary and shape optimization */ - if (n < 3) { - /* volume optimization, boundary and shape optimization */ - GtsMatrix * H; - GtsVector c; - gdouble l2 = gts_point_distance2 (GTS_POINT (v1), - GTS_POINT (v2)); - gdouble wv = params->volume_weight/32.; - gdouble wb = params->boundary_weight/4.*l2; - gdouble ws = params->shape_weight*l2*l2; - - gdouble nv = 0.0; - GtsVector cs = {0., 0., 0.}; - GSList * list, * i; - - list = gts_vertex_neighbors (v1, NULL, NULL); - list = gts_vertex_neighbors (v2, list, NULL); - - i = list; - while (i) { - GtsPoint * p1 = i->data; - if (p1 != GTS_POINT (v1) && p1 != GTS_POINT (v2)) { - nv += 1.0; - cs[0] -= p1->x; - cs[1] -= p1->y; - cs[2] -= p1->z; - } - i = i->next; - } - g_slist_free (list); - - H = gts_matrix_new (wv*sn11 + wb*Hb[0][0] + ws*nv, - wv*sn12 + wb*Hb[0][1], - wv*sn13 + wb*Hb[0][2], - wv*sn12 + wb*Hb[1][0], - wv*sn22 + wb*Hb[1][1] + ws*nv, - wv*sn23 + wb*Hb[1][2], - wv*sn13 + wb*Hb[2][0], - wv*sn23 + wb*Hb[2][1], - wv*sn33 + wb*Hb[2][2] + ws*nv); - - c[0] = - wv*stn1 + wb*cb[0] + ws*cs[0]; - c[1] = - wv*stn2 + wb*cb[1] + ws*cs[1]; - c[2] = - wv*stn3 + wb*cb[2] + ws*cs[2]; - - n = gts_matrix_quadratic_optimization (A, b, n, H, c); - gts_matrix_destroy (H); - } - -#ifdef DEBUG_VOPT - if (n != nold) { - fprintf (stderr, "--- volume, boundary and shape optimization ---\n"); - gts_matrix_print (A, stderr); - gts_vector_print (b, stderr); - nold = n; - } -#endif -#endif /* Weighted average of volume, boundary and shape optimization */ - - g_assert (n == 3); - g_assert ((Ai = gts_matrix3_inverse (A))); - - v = gts_vertex_new (klass, - Ai[0][0]*b[0] + Ai[0][1]*b[1] + Ai[0][2]*b[2], - Ai[1][0]*b[0] + Ai[1][1]*b[1] + Ai[1][2]*b[2], - Ai[2][0]*b[0] + Ai[2][1]*b[1] + Ai[2][2]*b[2]); - - gts_matrix_destroy (A); - gts_matrix_destroy (Ai); - gts_matrix_destroy (Hb); - - return v; -} - -/** - * gts_volume_optimized_cost: - * @e: a #GtsEdge. - * @params: a #GtsVolumeOptimizedParams. - * - * Returns: the cost for the collapse of @e as minimized by the function - * gts_volume_optimized_vertex(). - */ -gdouble gts_volume_optimized_cost (GtsEdge * e, - GtsVolumeOptimizedParams * params) -{ - GtsVertex * v; - gdouble cost; - gdouble length2; - - g_return_val_if_fail (e != NULL, G_MAXDOUBLE); - g_return_val_if_fail (params != NULL, G_MAXDOUBLE); - - v = gts_volume_optimized_vertex (e, gts_vertex_class (), params); - - length2 = gts_point_distance2 (GTS_POINT (GTS_SEGMENT (e)->v1), - GTS_POINT (GTS_SEGMENT (e)->v2)); - cost = - params->volume_weight*edge_volume_cost (e, v) + - params->boundary_weight*length2*edge_boundary_cost (e, v) + - params->shape_weight*length2*length2*edge_shape_cost (e, v); - gts_object_destroy (GTS_OBJECT (v)); - - return cost; -} Index: trunk/src_3rd/gts/point.c =================================================================== --- trunk/src_3rd/gts/point.c (revision 6802) +++ trunk/src_3rd/gts/point.c (nonexistent) @@ -1,986 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include -#include "gts.h" -#include "gts-private.h" -#include "predicates.h" - -static void point_read (GtsObject ** o, GtsFile * f) -{ - GtsPoint * p = GTS_POINT (*o); - - if (GTS_POINT_CLASS ((*o)->klass)->binary) { - if (gts_file_read (f, &(p->x), sizeof (gdouble), 1) != 1) { - gts_file_error (f, "expecting a binary number (x coordinate)"); - return; - } - if (gts_file_read (f, &(p->y), sizeof (gdouble), 1) != 1) { - gts_file_error (f, "expecting a binary number (y coordinate)"); - return; - } - if (gts_file_read (f, &(p->z), sizeof (gdouble), 1) != 1) { - gts_file_error (f, "expecting a binary number (z coordinate)"); - return; - } - } - else { - if (f->type != GTS_INT && f->type != GTS_FLOAT) { - gts_file_error (f, "expecting a number (x coordinate)"); - return; - } - p->x = atof (f->token->str); - - gts_file_next_token (f); - if (f->type != GTS_INT && f->type != GTS_FLOAT) { - gts_file_error (f, "expecting a number (y coordinate)"); - return; - } - p->y = atof (f->token->str); - - gts_file_next_token (f); - if (f->type != GTS_INT && f->type != GTS_FLOAT) { - gts_file_error (f, "expecting a number (z coordinate)"); - return; - } - p->z = atof (f->token->str); - - gts_file_next_token (f); - } -} - -static void point_write (GtsObject * o, FILE * fptr) -{ - GtsPoint * p = GTS_POINT (o); - - if (GTS_POINT_CLASS ((o)->klass)->binary) { - fwrite (&(p->x), sizeof (gdouble), 1, fptr); - fwrite (&(p->y), sizeof (gdouble), 1, fptr); - fwrite (&(p->z), sizeof (gdouble), 1, fptr); - } - else - fprintf (fptr, "%.10g %.10g %.10g", p->x, p->y, p->z); -} - -static void point_class_init (GtsObjectClass * klass) -{ - klass->read = point_read; - klass->write = point_write; -} - -/** - * gts_point_class: - * - * Returns: the #GtsPointClass. - */ -GtsPointClass * gts_point_class (void) -{ - static GtsPointClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo point_info = { - "GtsPoint", - sizeof (GtsPoint), - sizeof (GtsPointClass), - (GtsObjectClassInitFunc) point_class_init, - (GtsObjectInitFunc) NULL, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (gts_object_class (), - &point_info); - } - - return klass; -} - -/** - * gts_point_new: - * @klass: a #GtsPointClass. - * @x: the x-coordinate. - * @y: the y-coordinate. - * @z: the z-coordinate. - * - * Returns: a new #GtsPoint. - */ -GtsPoint * gts_point_new (GtsPointClass * klass, - gdouble x, gdouble y, gdouble z) -{ - GtsPoint * p; - - p = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (klass))); - p->x = x; - p->y = y; - p->z = z; - - return p; -} - -/** - * gts_point_set: - * @p: a #GtsPoint. - * @x: the x-coordinate. - * @y: the y-coordinate. - * @z: the z-coordinate. - * - * Sets the coordinates of @p. - */ -void gts_point_set (GtsPoint * p, gdouble x, gdouble y, gdouble z) -{ - g_return_if_fail (p != NULL); - - p->x = x; - p->y = y; - p->z = z; -} - -/** - * gts_point_distance: - * @p1: a #GtsPoint. - * @p2: another #GtsPoint. - * - * Returns: the Euclidean distance between @p1 and @p2. - */ -gdouble gts_point_distance (GtsPoint * p1, GtsPoint * p2) -{ - g_return_val_if_fail (p1 != NULL && p2 != NULL, 0.0); - - return sqrt ((p1->x - p2->x)*(p1->x - p2->x) + - (p1->y - p2->y)*(p1->y - p2->y) + - (p1->z - p2->z)*(p1->z - p2->z)); -} - -/** - * gts_point_distance2: - * @p1: a #GtsPoint. - * @p2: another #GtsPoint. - * - * Returns: the square of the Euclidean distance between @p1 and @p2. - */ -gdouble gts_point_distance2 (GtsPoint * p1, GtsPoint * p2) -{ - g_return_val_if_fail (p1 != NULL && p2 != NULL, 0.0); - - return - (p1->x - p2->x)*(p1->x - p2->x) + - (p1->y - p2->y)*(p1->y - p2->y) + - (p1->z - p2->z)*(p1->z - p2->z); -} - -/** - * gts_point_orientation_3d: - * @p1: a #GtsPoint. - * @p2: a #GtsPoint. - * @p3: a #GtsPoint. - * @p4: a #GtsPoint. - * - * Checks if @p4 lies above, below or on the plane passing through the - * points @p1, @p2 and @p3. Below is defined so that @p1, @p2 and @p3 - * appear in counterclockwise order when viewed from above the - * plane. The returned value is an approximation of six times the - * signed volume of the tetrahedron defined by the four points. This - * function uses adaptive floating point arithmetic and is - * consequently geometrically robust. - * - * Returns: a positive value if @p4 lies below, a negative value if - * @p4 lies above the plane, zero if the four points are coplanar. - */ -gdouble gts_point_orientation_3d (GtsPoint * p1, - GtsPoint * p2, - GtsPoint * p3, - GtsPoint * p4) -{ - g_return_val_if_fail (p1 != NULL && p2 != NULL && - p3 != NULL && p4 != NULL, 0.0); - return orient3d ((gdouble *) &p1->x, - (gdouble *) &p2->x, - (gdouble *) &p3->x, - (gdouble *) &p4->x); -} - -/** - * gts_point_is_in_triangle: - * @p: a #GtsPoint. - * @t: a #GtsTriangle. - * - * Tests if the planar projection (x, y) of @p is inside, outside or - * on the boundary of the planar projection of @t. This function is - * geometrically robust. - * - * Returns: %GTS_IN if @p is inside @t, %GTS_ON if @p is on the boundary of - * @t, %GTS_OUT otherwise. - */ -GtsIntersect gts_point_is_in_triangle (GtsPoint * p, GtsTriangle * t) -{ - GtsVertex * v1, * v2, * v3; - gdouble d1, d2, d3; - - g_return_val_if_fail (p != NULL && t != NULL, FALSE); - - gts_triangle_vertices (t, &v1, &v2, &v3); - - d1 = gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), p); - if (d1 < 0.0) - return GTS_OUT; - d2 = gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p); - if (d2 < 0.0) - return GTS_OUT; - d3 = gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), p); - if (d3 < 0.0) - return GTS_OUT; - if (d1 == 0.0 || d2 == 0.0 || d3 == 0.0) - return GTS_ON; - return GTS_IN; -} - -/** - * gts_point_in_triangle_circle: - * @p: a #GtsPoint. - * @t: a #GtsTriangle. - * - * Tests if the planar projection (x, y) of @p is inside or outside - * the circumcircle of the planar projection of @t. This function is - * geometrically robust. - * - * Returns: a positive number if @p lies inside, - * a negative number if @p lies outside and zero if @p lies on - * the circumcircle of @t. - */ -gdouble gts_point_in_triangle_circle (GtsPoint * p, GtsTriangle * t) -{ - GtsPoint * p1, * p2, * p3; - - g_return_val_if_fail (p != NULL && t != NULL, 0.0); - - gts_triangle_vertices (t, - (GtsVertex **) &p1, - (GtsVertex **) &p2, - (GtsVertex **) &p3); - - return incircle ((gdouble *) &p1->x, - (gdouble *) &p2->x, - (gdouble *) &p3->x, - (gdouble *) &p->x); -} - -/** - * gts_point_in_circle: - * @p: a #GtsPoint. - * @p1: a #GtsPoint. - * @p2: a #GtsPoint. - * @p3: a #GtsPoint. - * - * Tests if the planar projection (x, y) of @p is inside or outside the - * circle defined by the planar projection of @p1, @p2 and @p3. - * - * Returns: a positive number if @p lies inside, - * a negative number if @p lies outside and zero if @p lies on - * the circle. - */ -gdouble gts_point_in_circle (GtsPoint * p, - GtsPoint * p1, GtsPoint * p2, GtsPoint * p3) -{ - g_return_val_if_fail (p != NULL && p1 != NULL && p2 != NULL && p3 != NULL, - 0.0); - - return incircle ((gdouble *) &p1->x, - (gdouble *) &p2->x, - (gdouble *) &p3->x, - (gdouble *) &p->x); -} - -/** - * gts_point_in_sphere: - * @p: a #GtsPoint. - * @p1: a #GtsPoint. - * @p2: a #GtsPoint. - * @p3: a #GtsPoint. - * @p4: a #GtsPoint. - * - * Tests if @p is inside or outside the sphere defined by @p1, @p2, - * @p3 and @p4. - * - * Returns: a positive number if @p lies inside, - * a negative number if @p lies outside and zero if @p lies on - * the sphere. - */ -gdouble gts_point_in_sphere (GtsPoint * p, - GtsPoint * p1, GtsPoint * p2, GtsPoint * p3, GtsPoint * p4) -{ - g_return_val_if_fail (p != NULL && p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL, - 0.0); - - return insphere ((gdouble *) &p1->x, - (gdouble *) &p2->x, - (gdouble *) &p3->x, - (gdouble *) &p4->x, - (gdouble *) &p->x); -} - -/** - * gts_point_segment_distance2: - * @p: a #GtsPoint. - * @s: a #GtsSegment. - * - * Returns: the square of the minimun Euclidean distance between @p and @s. - */ -gdouble gts_point_segment_distance2 (GtsPoint * p, GtsSegment * s) -{ - gdouble t, ns2, x, y, z; - GtsPoint * p1, * p2; - - g_return_val_if_fail (p != NULL, 0.0); - g_return_val_if_fail (s != NULL, 0.0); - - p1 = GTS_POINT (s->v1); - p2 = GTS_POINT (s->v2); - ns2 = gts_point_distance2 (p1, p2); - if (ns2 == 0.0) - return gts_point_distance2 (p, p1); - t = ((p2->x - p1->x)*(p->x - p1->x) + - (p2->y - p1->y)*(p->y - p1->y) + - (p2->z - p1->z)*(p->z - p1->z))/ns2; - if (t > 1.0) - return gts_point_distance2 (p, p2); - if (t < 0.0) - return gts_point_distance2 (p, p1); - x = (1. - t)*p1->x + t*p2->x - p->x; - y = (1. - t)*p1->y + t*p2->y - p->y; - z = (1. - t)*p1->z + t*p2->z - p->z; - return x*x + y*y + z*z; -} - -/** - * gts_point_segment_distance: - * @p: a #GtsPoint. - * @s: a #GtsSegment. - * - * Returns: the minimun Euclidean distance between @p and @s. - */ -gdouble gts_point_segment_distance (GtsPoint * p, GtsSegment * s) -{ - g_return_val_if_fail (p != NULL, 0.0); - g_return_val_if_fail (s != NULL, 0.0); - - return sqrt (gts_point_segment_distance2 (p, s)); -} - -/** - * gts_point_segment_closest: - * @p: a #GtsPoint. - * @s: a #GtsSegment. - * @closest: a #GtsPoint. - * - * Set the coordinates of @closest to the coordinates of the point belonging - * to @s closest to @p. - */ -void gts_point_segment_closest (GtsPoint * p, - GtsSegment * s, - GtsPoint * closest) -{ - gdouble t, ns2; - GtsPoint * p1, * p2; - - g_return_if_fail (p != NULL); - g_return_if_fail (s != NULL); - g_return_if_fail (closest != NULL); - - p1 = GTS_POINT (s->v1); - p2 = GTS_POINT (s->v2); - ns2 = gts_point_distance2 (p1, p2); - - if (ns2 == 0.0) { - gts_point_set (closest, p1->x, p1->y, p1->z); - return; - } - - t = ((p2->x - p1->x)*(p->x - p1->x) + - (p2->y - p1->y)*(p->y - p1->y) + - (p2->z - p1->z)*(p->z - p1->z))/ns2; - - if (t > 1.0) - gts_point_set (closest, p2->x, p2->y, p2->z); - else if (t < 0.0) - gts_point_set (closest, p1->x, p1->y, p1->z); - else - gts_point_set (closest, - (1. - t)*p1->x + t*p2->x, - (1. - t)*p1->y + t*p2->y, - (1. - t)*p1->z + t*p2->z); -} - -/** - * gts_point_triangle_distance2: - * @p: a #GtsPoint. - * @t: a #GtsTriangle. - * - * Returns: the square of the minimun Euclidean distance between @p and @t. - */ -gdouble gts_point_triangle_distance2 (GtsPoint * p, GtsTriangle * t) -{ - GtsPoint * p1, * p2, * p3; - GtsEdge * e1, * e2, * e3; - GtsVector p1p2, p1p3, pp1; - gdouble A, B, C, D, E, det; - gdouble t1, t2; - gdouble x, y, z; - - g_return_val_if_fail (p != NULL, 0.0); - g_return_val_if_fail (t != NULL, 0.0); - - gts_triangle_vertices_edges (t, NULL, - (GtsVertex **) &p1, - (GtsVertex **) &p2, - (GtsVertex **) &p3, - &e1, &e2, &e3); - - gts_vector_init (p1p2, p1, p2); - gts_vector_init (p1p3, p1, p3); - gts_vector_init (pp1, p, p1); - - B = gts_vector_scalar (p1p3, p1p2); - E = gts_vector_scalar (p1p2, p1p2); - C = gts_vector_scalar (p1p3, p1p3); - - det = B*B - E*C; - if (det == 0.) { /* p1p2 and p1p3 are colinear */ - gdouble d1 = gts_point_segment_distance2 (p, GTS_SEGMENT (e1)); - gdouble d2 = gts_point_segment_distance2 (p, GTS_SEGMENT (e3)); - if (d1 < d2) - return d1; - return d2; - } - - A = gts_vector_scalar (p1p3, pp1); - D = gts_vector_scalar (p1p2, pp1); - - t1 = (D*C - A*B)/det; - t2 = (A*E - D*B)/det; - - if (t1 < 0.) - return gts_point_segment_distance2 (p, GTS_SEGMENT (e3)); - if (t2 < 0.) - return gts_point_segment_distance2 (p, GTS_SEGMENT (e1)); - if (t1 + t2 > 1.) - return gts_point_segment_distance2 (p, GTS_SEGMENT (e2)); - - x = pp1[0] + t1*p1p2[0] + t2*p1p3[0]; - y = pp1[1] + t1*p1p2[1] + t2*p1p3[1]; - z = pp1[2] + t1*p1p2[2] + t2*p1p3[2]; - - return x*x + y*y + z*z; -} - -/** - * gts_point_triangle_distance: - * @p: a #GtsPoint. - * @t: a #GtsTriangle. - * - * Returns: the minimun Euclidean distance between @p and @t. - */ -gdouble gts_point_triangle_distance (GtsPoint * p, GtsTriangle * t) -{ - g_return_val_if_fail (p != NULL, 0.0); - g_return_val_if_fail (t != NULL, 0.0); - - return sqrt (gts_point_triangle_distance2 (p, t)); -} - -/** - * gts_point_triangle_closest: - * @p: a #GtsPoint. - * @t: a #GtsTriangle. - * @closest: a #GtsPoint. - * - * Set the coordinates of @closest to those of the point belonging to @t and - * closest to @p. - */ -void gts_point_triangle_closest (GtsPoint * p, - GtsTriangle * t, - GtsPoint * closest) -{ - GtsPoint * p1, * p2, * p3; - GtsEdge * e1, * e2, * e3; - GtsVector p1p2, p1p3, pp1; - gdouble A, B, C, D, E, det; - gdouble t1, t2; - - g_return_if_fail (p != NULL); - g_return_if_fail (t != NULL); - g_return_if_fail (closest != NULL); - - gts_triangle_vertices_edges (t, NULL, - (GtsVertex **) &p1, - (GtsVertex **) &p2, - (GtsVertex **) &p3, - &e1, &e2, &e3); - - gts_vector_init (p1p2, p1, p2); - gts_vector_init (p1p3, p1, p3); - gts_vector_init (pp1, p, p1); - - B = gts_vector_scalar (p1p3, p1p2); - E = gts_vector_scalar (p1p2, p1p2); - C = gts_vector_scalar (p1p3, p1p3); - - det = B*B - E*C; - if (det == 0.) { /* p1p2 and p1p3 are colinear */ - GtsPoint * cp = - GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class ()))); - gts_point_segment_closest (p, GTS_SEGMENT (e1), cp); - gts_point_segment_closest (p, GTS_SEGMENT (e3), closest); - - if (gts_point_distance2 (cp, p) < gts_point_distance2 (closest, p)) - gts_point_set (closest, cp->x, cp->y, cp->z); - gts_object_destroy (GTS_OBJECT (cp)); - return; - } - - A = gts_vector_scalar (p1p3, pp1); - D = gts_vector_scalar (p1p2, pp1); - - t1 = (D*C - A*B)/det; - t2 = (A*E - D*B)/det; - - if (t1 < 0.) - gts_point_segment_closest (p, GTS_SEGMENT (e3), closest); - else if (t2 < 0.) - gts_point_segment_closest (p, GTS_SEGMENT (e1), closest); - else if (t1 + t2 > 1.) - gts_point_segment_closest (p, GTS_SEGMENT (e2), closest); - else - gts_point_set (closest, - p1->x + t1*p1p2[0] + t2*p1p3[0], - p1->y + t1*p1p2[1] + t2*p1p3[1], - p1->z + t1*p1p2[2] + t2*p1p3[2]); -} - -/** - * gts_segment_triangle_intersection: - * @s: a #GtsSegment. - * @t: a #GtsTriangle. - * @boundary: if %TRUE, the boundary of @t is taken into account. - * @klass: a #GtsPointClass to be used for the new point. - * - * Checks if @s intersects @t. If this is the case, creates a new - * point pi intersection of @s with @t. - * - * This function is geometrically robust in the sense that it will not - * return a point if @s and @t do not intersect and will return a - * point if @s and @t do intersect. However, the point coordinates are - * subject to round-off errors. - * - * Note that this function will not return any point if @s is contained in - * the plane defined by @t. - * - * Returns: a summit of @t (if @boundary is set to %TRUE), one of the endpoints - * of @s or a new #GtsPoint, intersection of @s with @t or %NULL if @s - * and @t don't intersect. - */ -GtsPoint * gts_segment_triangle_intersection (GtsSegment * s, - GtsTriangle * t, - gboolean boundary, - GtsPointClass * klass) -{ - GtsPoint * A, * B, * C, * D, * E, * I; - gdouble ABCE, ABCD, ADCE, ABDE, BCDE; - gdouble c; - - g_return_val_if_fail (s != NULL, NULL); - g_return_val_if_fail (t != NULL, NULL); - g_return_val_if_fail (klass != NULL, NULL); - - A = GTS_POINT (GTS_SEGMENT (t->e1)->v1); - B = GTS_POINT (GTS_SEGMENT (t->e1)->v2); - C = GTS_POINT (gts_triangle_vertex (t)); - D = GTS_POINT (s->v1); - E = GTS_POINT (s->v2); - - ABCE = gts_point_orientation_3d (A, B, C, E); - ABCD = gts_point_orientation_3d (A, B, C, D); - if (ABCE < 0.0 || ABCD > 0.0) { - GtsPoint * tmpp; - gdouble tmp; - tmpp = E; E = D; D = tmpp; - tmp = ABCE; ABCE = ABCD; ABCD = tmp; - } - if (ABCE < 0.0 || ABCD > 0.0) - return NULL; - ADCE = gts_point_orientation_3d (A, D, C, E); - if ((boundary && ADCE < 0.) || (!boundary && ADCE <= 0.)) - return NULL; - ABDE = gts_point_orientation_3d (A, B, D, E); - if ((boundary && ABDE < 0.) || (!boundary && ABDE <= 0.)) - return NULL; - BCDE = gts_point_orientation_3d (B, C, D, E); - if ((boundary && BCDE < 0.) || (!boundary && BCDE <= 0.)) - return NULL; - if (ABCE == 0.0) { - if (ABCD == 0.0) - /* s is contained in the plane defined by t*/ - return NULL; - return E; - } - if (ABCD == 0.0) - return D; - if (boundary) { /* corners of @t */ - if (ABDE == 0.) { - if (ADCE == 0.) - return A; - if (BCDE == 0.) - return B; - } - else if (BCDE == 0. && ADCE == 0.) - return C; - } - c = ABCE/(ABCE - ABCD); - I = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (klass))); - gts_point_set (I, - E->x + c*(D->x - E->x), - E->y + c*(D->y - E->y), - E->z + c*(D->z - E->z)); - return I; -} - -/** - * gts_point_transform: - * @p: a #GtsPoint. - * @m: the #GtsMatrix representing the transformation to - * apply to the coordinates of @p. - * - * Transform the coordinates of @p according to @m. (p[] becomes m[][].p[]). - */ -void gts_point_transform (GtsPoint * p, GtsMatrix * m) -{ - gdouble x, y, z; - g_return_if_fail (p != NULL && m != NULL); - x = m[0][0]*p->x + m[0][1]*p->y + m[0][2]*p->z + m[0][3]; - y = m[1][0]*p->x + m[1][1]*p->y + m[1][2]*p->z + m[1][3]; - z = m[2][0]*p->x + m[2][1]*p->y + m[2][2]*p->z + m[2][3]; - p->x = x; p->y = y; p->z = z; -} - -/** - * gts_point_orientation: - * @p1: a #GtsPoint. - * @p2: a #GtsPoint. - * @p3: a #GtsPoint. - * - * Checks for orientation of the projection of three points on the - * (x,y) plane. The result is also an approximation of twice the - * signed area of the triangle defined by the three points. This - * function uses adaptive floating point arithmetic and is - * consequently geometrically robust. - * - * Returns: a positive value if @p1, @p2 and @p3 appear in - * counterclockwise order, a negative value if they appear in - * clockwise order and zero if they are colinear. - */ -gdouble gts_point_orientation (GtsPoint * p1, GtsPoint * p2, GtsPoint * p3) -{ - g_return_val_if_fail (p1 != NULL && p2 != NULL && p3 != NULL, 0.0); - - return orient2d ((gdouble *) &p1->x, - (gdouble *) &p2->x, - (gdouble *) &p3->x); -} - -static gboolean ray_intersects_triangle (GtsPoint * D, GtsPoint * E, - GtsTriangle * t) -{ - GtsPoint * A, * B, * C; - gint ABCE, ABCD, ADCE, ABDE, BCDE; - - gts_triangle_vertices (t, (GtsVertex **) &A, - (GtsVertex **) &B, - (GtsVertex **) &C); - - ABCE = gts_point_orientation_3d_sos (A, B, C, E); - ABCD = gts_point_orientation_3d_sos (A, B, C, D); - if (ABCE < 0 || ABCD > 0) { - GtsPoint * tmpp; - gint tmp; - - tmpp = E; E = D; D = tmpp; - tmp = ABCE; ABCE = ABCD; ABCD = tmp; - } - if (ABCE < 0 || ABCD > 0) - return FALSE; - ADCE = gts_point_orientation_3d_sos (A, D, C, E); - if (ADCE < 0) - return FALSE; - ABDE = gts_point_orientation_3d_sos (A, B, D, E); - if (ABDE < 0) - return FALSE; - BCDE = gts_point_orientation_3d_sos (B, C, D, E); - if (BCDE < 0) - return FALSE; - return TRUE; -} - -/** - * gts_point_is_inside_surface: - * @p: a #GtsPoint. - * @tree: a bounding box tree of the faces of a closed, orientable - * surface (see gts_bb_tree_surface()). - * @is_open: %TRUE if the surface defined by @tree is "open" i.e. its volume - * is negative, %FALSE otherwise. - * - * Returns: %TRUE if @p is inside the surface defined by @tree, %FALSE - * otherwise. - */ -gboolean gts_point_is_inside_surface (GtsPoint * p, - GNode * tree, - gboolean is_open) -{ - GSList * list, * i; - guint nc = 0; - GtsPoint * p1; - GtsBBox * bb; - - g_return_val_if_fail (p != NULL, FALSE); - g_return_val_if_fail (tree != NULL, FALSE); - - bb = tree->data; - p1 = gts_point_new (gts_point_class (), bb->x2 + fabs (bb->x2)/10., p->y, p->z); - i = list = gts_bb_tree_stabbed (tree, p); - while (i) { - GtsTriangle * t = GTS_TRIANGLE (GTS_BBOX (i->data)->bounded); - - if (ray_intersects_triangle (p, p1, t)) - nc++; - i = i->next; - } - g_slist_free (list); - gts_object_destroy (GTS_OBJECT (p1)); - - return is_open ? (nc % 2 == 0) : (nc % 2 != 0); -} - -#define SIGN(x) ((x) > 0. ? 1 : -1) -#define ORIENT1D(a,b) ((a) > (b) ? 1 : (a) < (b) ? -1 : 0) - -static gint sortp (gpointer * p, guint n) -{ - gint sign = 1; - guint i, j; - - for (i = 0; i < n - 1; i++) - for (j = 0; j < n - 1 - i; j++) - if (GPOINTER_TO_UINT (p[j+1]) < GPOINTER_TO_UINT (p[j])) { - gpointer tmp = p[j]; - - p[j] = p[j+1]; - p[j+1] = tmp; - sign = - sign; - } - return sign; -} - -/** - * gts_point_orientation_3d_sos: - * @p1: a #GtsPoint. - * @p2: a #GtsPoint. - * @p3: a #GtsPoint. - * @p4: a #GtsPoint. - * - * Checks if @p4 lies above or below the plane passing through the - * points @p1, @p2 and @p3. Below is defined so that @p1, @p2 and @p3 - * appear in counterclockwise order when viewed from above the - * plane. This function uses adaptive floating point arithmetic and is - * consequently geometrically robust. - * - * Simulation of Simplicity (SoS) is used to break ties when the - * orientation is degenerate (i.e. @p4 lies on the plane defined by - * @p1, @p2 and @p3). - * - * Returns: +1 if @p4 lies below, -1 if @p4 lies above the plane. - */ -gint gts_point_orientation_3d_sos (GtsPoint * p1, - GtsPoint * p2, - GtsPoint * p3, - GtsPoint * p4) -{ - gdouble o; - - g_return_val_if_fail (p1 != NULL && p2 != NULL && - p3 != NULL && p4 != NULL, 0); - - o = orient3d ((gdouble *) &p1->x, - (gdouble *) &p2->x, - (gdouble *) &p3->x, - (gdouble *) &p4->x); - if (o != 0.) - return SIGN (o); - else { - GtsPoint * p[4]; - gdouble a[2], b[2], c[2]; - gint sign; - - p[0] = p1; p[1] = p2; p[2] = p3; p[3] = p4; - sign = sortp ((gpointer *) p, 4); - - /* epsilon^1/8 */ - a[0] = p[1]->x; a[1] = p[1]->y; - b[0] = p[2]->x; b[1] = p[2]->y; - c[0] = p[3]->x; c[1] = p[3]->y; - o = orient2d (a, b, c); - if (o != 0.) - return SIGN (o)*sign; - - /* epsilon^1/4 */ - a[0] = p[1]->x; a[1] = p[1]->z; - b[0] = p[2]->x; b[1] = p[2]->z; - c[0] = p[3]->x; c[1] = p[3]->z; - o = orient2d (a, b, c); - if (o != 0.) - return - SIGN (o)*sign; - - /* epsilon^1/2 */ - a[0] = p[1]->y; a[1] = p[1]->z; - b[0] = p[2]->y; b[1] = p[2]->z; - c[0] = p[3]->y; c[1] = p[3]->z; - o = orient2d (a, b, c); - if (o != 0.) - return SIGN (o)*sign; - - /* epsilon */ - a[0] = p[0]->x; a[1] = p[0]->y; - b[0] = p[2]->x; b[1] = p[2]->y; - c[0] = p[3]->x; c[1] = p[3]->y; - o = orient2d (a, b, c); - if (o != 0.) - return - SIGN (o)*sign; - - /* epsilon^5/4 */ - o = ORIENT1D (p[2]->x, p[3]->x); - if (o != 0.) - return SIGN (o)*sign; - - /* epsilon^3/2 */ - o = ORIENT1D (p[2]->y, p[3]->y); - if (o != 0.) - return - SIGN (o)*sign; - - /* epsilon^2 */ - a[0] = p[0]->x; a[1] = p[0]->z; - b[0] = p[2]->x; b[1] = p[2]->z; - c[0] = p[3]->x; c[1] = p[3]->z; - o = orient2d (a, b, c); - if (o != 0.) - return SIGN (o)*sign; - - /* epsilon^5/2 */ - o = ORIENT1D (p[2]->z, p[3]->z); - if (o != 0.) - return SIGN (o)*sign; - - /* epsilon^4 */ - a[0] = p[0]->y; a[1] = p[0]->z; - b[0] = p[2]->y; b[1] = p[2]->z; - c[0] = p[3]->y; c[1] = p[3]->z; - o = orient2d (a, b, c); - if (o != 0.) - return - SIGN (o)*sign; - - /* epsilon^8 */ - a[0] = p[0]->x; a[1] = p[0]->y; - b[0] = p[1]->x; b[1] = p[1]->y; - c[0] = p[3]->x; c[1] = p[3]->y; - o = orient2d (a, b, c); - if (o != 0.) - return SIGN (o)*sign; - - /* epsilon^33/4 */ - o = ORIENT1D (p[1]->x, p[3]->x); - if (o != 0.) - return - SIGN (o)*sign; - - /* epsilon^17/2 */ - o = ORIENT1D (p[1]->y, p[3]->y); - if (o != 0.) - return SIGN (o)*sign; - - /* epsilon^10 */ - o = ORIENT1D (p[0]->x, p[3]->x); - if (o != 0.) - return SIGN (o)*sign; - - /* epsilon^21/2 */ - return sign; - } -} - -/** - * gts_point_orientation_sos: - * @p1: a #GtsPoint. - * @p2: a #GtsPoint. - * @p3: a #GtsPoint. - * - * Checks for orientation of the projection of three points on the - * (x,y) plane. - * - * Simulation of Simplicity (SoS) is used to break ties when the - * orientation is degenerate (i.e. @p3 lies on the line defined by - * @p1 and @p2). - * - * Returns: a positive value if @p1, @p2 and @p3 appear in - * counterclockwise order or a negative value if they appear in - * clockwise order. - */ -gint gts_point_orientation_sos (GtsPoint * p1, - GtsPoint * p2, - GtsPoint * p3) -{ - gdouble o; - - g_return_val_if_fail (p1 != NULL && p2 != NULL && p3 != NULL, 0); - - o = orient2d ((gdouble *) &p1->x, - (gdouble *) &p2->x, - (gdouble *) &p3->x); - if (o != 0.) - return SIGN (o); - else { - GtsPoint * p[3]; - gint sign; - - p[0] = p1; p[1] = p2; p[2] = p3; - sign = sortp ((gpointer *) p, 3); - - /* epsilon^1/4 */ - o = ORIENT1D (p[1]->x, p[2]->x); - if (o != 0.) - return - SIGN (o)*sign; - - /* epsilon^1/2 */ - o = ORIENT1D (p[1]->y, p[2]->y); - if (o != 0.) - return SIGN (o)*sign; - - /* epsilon */ - o = ORIENT1D (p[0]->x, p[2]->x); - if (o != 0.) - return SIGN (o)*sign; - - /* epsilon^3/2 */ - return sign; - } -} Index: trunk/src_3rd/gts/isotetra.c =================================================================== --- trunk/src_3rd/gts/isotetra.c (revision 6802) +++ trunk/src_3rd/gts/isotetra.c (nonexistent) @@ -1,840 +0,0 @@ -/* GTS-Library conform marching tetrahedra algorithm - * Copyright (C) 2002 Gert Wollny - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#ifdef NATIVE_WIN32 -# include -# define M_SQRT2 1.41421356237309504880 -#endif /* NATIVE_WIN32 */ - -typedef struct { - gint nx, ny; - gdouble ** data; -} slice_t; - -typedef struct { - gint x, y, z; - gboolean mid; - gdouble d; -} tetra_vertex_t; - -/* this helper is a lookup table for vertices */ -typedef struct { - gint nx, ny; - GtsVertex ** vtop, ** vmid, **vbot; -} helper_t ; - -typedef struct { - GHashTable * vbot, * vtop; -} helper_bcl ; - - -static helper_t * init_helper (int nx, int ny) -{ - gint nxy = 4*nx*ny; - helper_t *retval = g_malloc0 (sizeof (helper_t)); - - retval->nx = nx; - retval->ny = ny; - retval->vtop = g_malloc0 (sizeof (GtsVertex *)*nxy); - retval->vmid = g_malloc0 (sizeof (GtsVertex *)*nxy); - retval->vbot = g_malloc0 (sizeof (GtsVertex *)*nxy); - return retval; -} - -static helper_bcl * init_helper_bcl (void) -{ - helper_bcl *retval = g_malloc0 (sizeof (helper_bcl)); - - retval->vtop = g_hash_table_new (g_str_hash, g_str_equal); - retval->vbot = g_hash_table_new (g_str_hash, g_str_equal); - return retval; -} - -static void free_helper (helper_t * h) -{ - g_free (h->vtop); - g_free (h->vmid); - g_free (h->vbot); - g_free (h); -} - -static void free_helper_bcl (helper_bcl * h) -{ - g_hash_table_destroy (h->vtop); - g_hash_table_destroy (h->vbot); - g_free (h); -} - -/* move the vertices in the bottom slice to the top, and clear the - other slices in the lookup tables */ -static void helper_advance (helper_t * h) -{ - GtsVertex ** help = h->vbot; - h->vbot = h->vtop; - h->vtop = help; - - memset (h->vmid, 0, 4*sizeof(GtsVertex *) * h->nx * h->ny); - memset (h->vbot, 0, 4*sizeof(GtsVertex *) * h->nx * h->ny); -} - -static void helper_advance_bcl (helper_bcl * h) -{ - GHashTable * help = g_hash_table_new (g_str_hash, g_str_equal); - - g_hash_table_destroy (h->vbot); - h->vbot = h->vtop; - h->vtop = help; -} - -/* find the zero-crossing of line through v1 and v2 and return the - corresponding GtsVertex */ -static GtsVertex * get_vertex (gint mz, - const tetra_vertex_t * v1, - const tetra_vertex_t * v2, - helper_t * help, - GtsCartesianGrid * g, - GtsVertexClass * klass) -{ - GtsVertex ** vertex; - gint x, y, index, idx2, z; - gdouble dx, dy, dz, d; - - g_assert (v1->d - v2->d != 0.); - - dx = dy = dz = 0.0; - d = v1->d/(v1->d - v2->d); - - index = 0; - - if (v1->x != v2->x) { - index |= 1; - dx = d; - } - - if (v1->y != v2->y) { - index |= 2; - dy = d; - } - - if (v1->z != v2->z) { - dz = d; - } - - x = v1->x; - if (v1->x > v2->x) { x = v2->x; dx = 1.0 - dx; } - - y = v1->y; - if (v1->y > v2->y) { y = v2->y; dy = 1.0 - dy;} - - z = v1->z; - if (v1->z > v2->z) { z = v2->z; dz = 1.0 - dz;} - - idx2 = 4 * ( x + y * help->nx ) + index; - - if (v1->z == v2->z) - vertex = (mz == z) ? &help->vtop[idx2] : &help->vbot[idx2]; - else - vertex = &help->vmid[idx2]; - - if (mz != z && dz != 0.0) { - fprintf(stderr, "%f \n", dz); - } - - /* if vertex is not yet created, do it now */ - if (!*vertex) - *vertex = gts_vertex_new (klass, - g->dx * ( x + dx) + g->x, - g->dy * ( y + dy) + g->y, - g->dz * ( z + dz) + g->z); - - return *vertex; -} - -static GtsVertex * get_vertex_bcl (gint mz, - const tetra_vertex_t * v1, - const tetra_vertex_t * v2, - helper_bcl * help, - GtsCartesianGrid * g, - GtsVertexClass * klass) -{ - GtsVertex * v; - GHashTable * table; - gchar * s1, * s2, * hash; - gdouble x1, x2, y1, y2, z1, z2, d; - - g_assert (v1->d - v2->d != 0.); - - /* first find correct hash table */ - if ((v1->z > mz) && (v2->z > mz)) - table = help->vtop; - else - table = help->vbot; - - d = v1->d / (v1->d - v2->d); - - /* sort vertices */ - s1 = g_strdup_printf ("%d %d %d %d", v1->x, v1->y, v1->z, v1->mid); - s2 = g_strdup_printf ("%d %d %d %d", v2->x, v2->y, v2->z, v2->mid); - - hash = (d == 0.0) ? g_strdup (s1) : - (d == 1.0) ? g_strdup (s2) : - (strcmp (s1, s2) < 0) ? g_strjoin (" ", s1, s2, NULL) : - g_strjoin (" ", s2, s1, NULL); - - /* return existing vertex or make a new one */ - v = g_hash_table_lookup (table, hash); - if (!v){ - - x1 = g->dx * (v1->x + (v1->mid / 2.0)) + g->x; - x2 = g->dx * (v2->x + (v2->mid / 2.0)) + g->x; - y1 = g->dy * (v1->y + (v1->mid / 2.0)) + g->y; - y2 = g->dy * (v2->y + (v2->mid / 2.0)) + g->y; - z1 = g->dz * (v1->z + (v1->mid / 2.0)) + g->z; - z2 = g->dz * (v2->z + (v2->mid / 2.0)) + g->z; - - v = gts_vertex_new (klass, x1 * (1.0 - d) + d * x2, - y1 * (1.0 - d) + d * y2, - z1 * (1.0 - d) + d * z2); - - g_hash_table_insert (table, g_strdup(hash), v); - } - g_free (s1); - g_free (s2); - g_free (hash); - - return v; -} - -/* create an edge connecting the zero crossings of lines through a - pair of vertices, or return an existing one */ -static GtsEdge * get_edge (GtsVertex * v1, GtsVertex * v2, - GtsEdgeClass * klass) -{ - GtsSegment *s; - GtsEdge *edge; - - g_assert (v1); - g_assert (v2); - - s = gts_vertices_are_connected (v1, v2); - - if (GTS_IS_EDGE (s)) - edge = GTS_EDGE(s); - else - edge = gts_edge_new (klass, v1, v2); - return edge; -} - -static void add_face (GtsSurface * surface, - const tetra_vertex_t * a1, const tetra_vertex_t * a2, - const tetra_vertex_t * b1, const tetra_vertex_t * b2, - const tetra_vertex_t * c1, const tetra_vertex_t * c2, - gint rev, helper_t * help, - gint z, GtsCartesianGrid * g) -{ - GtsFace * t; - GtsEdge * e1, * e2, * e3; - GtsVertex * v1 = get_vertex (z, a1, a2, help, g, surface->vertex_class); - GtsVertex * v2 = get_vertex (z, b1, b2, help, g, surface->vertex_class); - GtsVertex * v3 = get_vertex (z, c1, c2, help, g, surface->vertex_class); - - g_assert (v1 != v2); - g_assert (v2 != v3); - g_assert (v1 != v3); - - if (!rev) { - e1 = get_edge (v1, v2, surface->edge_class); - e2 = get_edge (v2, v3, surface->edge_class); - e3 = get_edge (v1, v3, surface->edge_class); - } else { - e1 = get_edge (v1, v3, surface->edge_class); - e2 = get_edge (v2, v3, surface->edge_class); - e3 = get_edge (v1, v2, surface->edge_class); - } - - t = gts_face_new (surface->face_class, e1, e2, e3); - gts_surface_add_face (surface, t); -} - -static void add_face_bcl (GtsSurface * surface, - const tetra_vertex_t * a1, - const tetra_vertex_t * a2, - const tetra_vertex_t * b1, - const tetra_vertex_t * b2, - const tetra_vertex_t * c1, - const tetra_vertex_t * c2, - gint rev, helper_bcl * help, - gint z, GtsCartesianGrid * g) -{ - GtsFace * t; - GtsEdge * e1, * e2, * e3; - GtsVertex * v1 = get_vertex_bcl (z, a1, a2, help, g, surface->vertex_class); - GtsVertex * v2 = get_vertex_bcl (z, b1, b2, help, g, surface->vertex_class); - GtsVertex * v3 = get_vertex_bcl (z, c1, c2, help, g, surface->vertex_class); - - if (v1 == v2 || v2 == v3 || v1 == v3) - return; - - if (!rev) { - e1 = get_edge (v1, v2, surface->edge_class); - e2 = get_edge (v2, v3, surface->edge_class); - e3 = get_edge (v1, v3, surface->edge_class); - } else { - e1 = get_edge (v1, v3, surface->edge_class); - e2 = get_edge (v2, v3, surface->edge_class); - e3 = get_edge (v1, v2, surface->edge_class); - } - - t = gts_face_new (surface->face_class, e1, e2, e3); - gts_surface_add_face (surface, t); -} - -/* create a new slice of site nx \times ny */ -static slice_t * new_slice (gint nx, gint ny) -{ - gint x; - slice_t * retval = g_malloc (sizeof (slice_t)); - - retval->data = g_malloc (nx*sizeof(gdouble *)); - retval->nx = nx; - retval->ny = ny; - for (x = 0; x < nx; x++) - retval->data[x] = g_malloc (ny*sizeof (gdouble)); - return retval; -} - -/* initialize a slice with inival */ -static void slice_init (slice_t * slice, gdouble inival) -{ - gint x, y; - - g_assert (slice); - - for (x = 0; x < slice->nx; x++) - for (y = 0; y < slice->ny; y++) - slice->data[x][y] = inival; -} - -/* free the memory of a slice */ -static void free_slice (slice_t * slice) -{ - gint x; - - g_return_if_fail (slice != NULL); - - for (x = 0; x < slice->nx; x++) - g_free (slice->data[x]); - g_free (slice->data); - g_free (slice); -} - -static void analyze_tetrahedra (const tetra_vertex_t * a, - const tetra_vertex_t * b, - const tetra_vertex_t * c, - const tetra_vertex_t * d, - gint parity, GtsSurface * surface, - helper_t * help, - gint z, GtsCartesianGrid * g) -{ - gint rev = parity; - gint code = 0; - - if (a->d >= 0.) code |= 1; - if (b->d >= 0.) code |= 2; - if (c->d >= 0.) code |= 4; - if (d->d >= 0.) code |= 8; - - switch (code) { - case 15: - case 0: return; /* all inside or outside */ - - case 14:rev = !parity; - case 1:add_face (surface, a, b, a, d, a, c, rev, help, z, g); - break; - case 13:rev = ! parity; - case 2:add_face (surface, a, b, b, c, b, d, rev, help, z, g); - break; - case 12:rev = !parity; - case 3:add_face (surface, a, d, a, c, b, c, rev, help, z, g); - add_face (surface, a, d, b, c, b, d, rev, help, z, g); - break; - case 11:rev = !parity; - case 4:add_face (surface, a, c, c, d, b, c, rev, help, z, g); - break; - case 10:rev = !parity; - case 5: add_face (surface, a, b, a, d, c, d, rev, help, z, g); - add_face (surface, a, b, c, d, b, c, rev, help, z, g); - break; - case 9:rev = !parity; - case 6:add_face (surface, a, b, a, c, c, d, rev, help, z, g); - add_face (surface, a, b, c, d, b, d, rev, help, z, g); - break; - case 7:rev = !parity; - case 8:add_face (surface, a, d, b, d, c, d, rev, help, z, g); - break; - } -} - -static void analyze_tetrahedra_bcl (const tetra_vertex_t * a, - const tetra_vertex_t * b, - const tetra_vertex_t * c, - const tetra_vertex_t * d, - GtsSurface * surface, - helper_bcl * help, - gint z, GtsCartesianGrid * g) -{ - gint rev = 0; - gint code = 0; - - if (a->d >= 0.) code |= 1; - if (b->d >= 0.) code |= 2; - if (c->d >= 0.) code |= 4; - if (d->d >= 0.) code |= 8; - - switch (code) { - case 15: - case 0: return; /* all inside or outside */ - - case 14:rev = !rev; - case 1:add_face_bcl (surface, a, b, a, d, a, c, rev, help, z, g); - break; - case 13:rev = !rev; - case 2:add_face_bcl (surface, a, b, b, c, b, d, rev, help, z, g); - break; - case 12:rev = !rev; - case 3:add_face_bcl (surface, a, d, a, c, b, c, rev, help, z, g); - add_face_bcl (surface, a, d, b, c, b, d, rev, help, z, g); - break; - case 11:rev = !rev; - case 4:add_face_bcl (surface, a, c, c, d, b, c, rev, help, z, g); - break; - case 10:rev = !rev; - case 5: add_face_bcl (surface, a, b, a, d, c, d, rev, help, z, g); - add_face_bcl (surface, a, b, c, d, b, c, rev, help, z, g); - break; - case 9:rev = !rev; - case 6:add_face_bcl (surface, a, b, a, c, c, d, rev, help, z, g); - add_face_bcl (surface, a, b, c, d, b, d, rev, help, z, g); - break; - case 7:rev = !rev; - case 8:add_face_bcl (surface, a, d, b, d, c, d, rev, help, z, g); - break; - } -} - -static void iso_slice_evaluate (slice_t * s1, slice_t * s2, - GtsCartesianGrid g, - gint z, GtsSurface * surface, helper_t * help) -{ - gint x,y; - tetra_vertex_t v0, v1, v2, v3, v4, v5, v6, v7; - gdouble ** s1p = s1->data; - gdouble ** s2p = s2->data; - - for (y = 0; y < g.ny-1; y++) - for (x = 0; x < g.nx-1; x++) { - gint parity = (((x ^ y) ^ z) & 1); - - v0.x = x ; v0.y = y ; v0.z = z ; v0.mid = FALSE; v0.d = s1p[x ][y ]; - v1.x = x ; v1.y = y+1; v1.z = z ; v1.mid = FALSE; v1.d = s1p[x ][y+1]; - v2.x = x+1; v2.y = y ; v2.z = z ; v2.mid = FALSE; v2.d = s1p[x+1][y ]; - v3.x = x+1; v3.y = y+1; v3.z = z ; v3.mid = FALSE; v3.d = s1p[x+1][y+1]; - v4.x = x ; v4.y = y ; v4.z = z+1; v4.mid = FALSE; v4.d = s2p[x ][y ]; - v5.x = x ; v5.y = y+1; v5.z = z+1; v5.mid = FALSE; v5.d = s2p[x ][y+1]; - v6.x = x+1; v6.y = y ; v6.z = z+1; v6.mid = FALSE; v6.d = s2p[x+1][y ]; - v7.x = x+1; v7.y = y+1; v7.z = z+1; v7.mid = FALSE; v7.d = s2p[x+1][y+1]; - - if (parity == 0) { - analyze_tetrahedra (&v0, &v1, &v2, &v4, parity, surface, help, z, &g); - analyze_tetrahedra (&v7, &v1, &v4, &v2, parity, surface, help, z, &g); - analyze_tetrahedra (&v1, &v7, &v3, &v2, parity, surface, help, z, &g); - analyze_tetrahedra (&v1, &v7, &v4, &v5, parity, surface, help, z, &g); - analyze_tetrahedra (&v2, &v6, &v4, &v7, parity, surface, help, z, &g); - }else{ - analyze_tetrahedra (&v4, &v5, &v6, &v0, parity, surface, help, z, &g); - analyze_tetrahedra (&v3, &v5, &v0, &v6, parity, surface, help, z, &g); - analyze_tetrahedra (&v5, &v3, &v7, &v6, parity, surface, help, z, &g); - analyze_tetrahedra (&v5, &v3, &v0, &v1, parity, surface, help, z, &g); - analyze_tetrahedra (&v6, &v2, &v0, &v3, parity, surface, help, z, &g); - } - } -} - -static void iso_slice_evaluate_bcl (slice_t * s1, slice_t * s2, slice_t * s3, - GtsCartesianGrid g, - gint z, GtsSurface * surface, - helper_bcl * help) -{ - gint x,y; - tetra_vertex_t v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, w0; - gdouble ** s1p = s1->data; - gdouble ** s2p = s2->data; - gdouble ** s3p = s3->data; - - for (y = 0; y < g.ny-2; y++) - for (x = 0; x < g.nx-2; x++) { - v0.x = x ; v0.y = y ; v0.z = z ; v0.mid = TRUE; - v0.d = (s1p[x ][y ] + s2p[x ][y ] + - s1p[x ][y+1] + s2p[x ][y+1] + - s1p[x+1][y ] + s2p[x+1][y ] + - s1p[x+1][y+1] + s2p[x+1][y+1])/8.0; - - v1.x = x+1; v1.y = y ; v1.z = z ; v1.mid = TRUE; - v1.d = (s1p[x+1][y ] + s2p[x+1][y ] + - s1p[x+1][y+1] + s2p[x+1][y+1] + - s1p[x+2][y ] + s2p[x+2][y ] + - s1p[x+2][y+1] + s2p[x+2][y+1])/8.0; - - v2.x = x ; v2.y = y+1; v2.z = z ; v2.mid = TRUE; - v2.d = (s1p[x ][y+1] + s2p[x ][y+1] + - s1p[x ][y+2] + s2p[x ][y+2] + - s1p[x+1][y+1] + s2p[x+1][y+1] + - s1p[x+1][y+2] + s2p[x+1][y+2])/8.0; - - v3.x = x ; v3.y = y ; v3.z = z+1; v3.mid = TRUE; - v3.d = (s2p[x ][y ] + s3p[x ][y ] + - s2p[x ][y+1] + s3p[x ][y+1] + - s2p[x+1][y ] + s3p[x+1][y ] + - s2p[x+1][y+1] + s3p[x+1][y+1])/8.0; - - v4.x = x+1; v4.y = y ; v4.z = z ; v4.mid = FALSE; v4.d = s1p[x+1][y ]; - v5.x = x ; v5.y = y+1; v5.z = z ; v5.mid = FALSE; v5.d = s1p[x ][y+1]; - v6.x = x+1; v6.y = y+1; v6.z = z ; v6.mid = FALSE; v6.d = s1p[x+1][y+1]; - v7.x = x+1; v7.y = y ; v7.z = z+1; v7.mid = FALSE; v7.d = s2p[x+1][y ]; - v8.x = x ; v8.y = y+1; v8.z = z+1; v8.mid = FALSE; v8.d = s2p[x ][y+1]; - v9.x = x+1; v9.y = y+1; v9.z = z+1; v9.mid = FALSE; v9.d = s2p[x+1][y+1]; - w0.x = x ; w0.y = y ; w0.z = z+1; w0.mid = FALSE; w0.d = s2p[x ][y ]; - - analyze_tetrahedra_bcl (&v0, &v9, &v6, &v1, surface, help, z, &g); - analyze_tetrahedra_bcl (&v0, &v6, &v4, &v1, surface, help, z, &g); - analyze_tetrahedra_bcl (&v0, &v4, &v7, &v1, surface, help, z, &g); - analyze_tetrahedra_bcl (&v0, &v7, &v9, &v1, surface, help, z, &g); - analyze_tetrahedra_bcl (&v0, &v5, &v6, &v2, surface, help, z, &g); - analyze_tetrahedra_bcl (&v0, &v6, &v9, &v2, surface, help, z, &g); - analyze_tetrahedra_bcl (&v0, &v9, &v8, &v2, surface, help, z, &g); - analyze_tetrahedra_bcl (&v0, &v8, &v5, &v2, surface, help, z, &g); - analyze_tetrahedra_bcl (&v0, &v8, &v9, &v3, surface, help, z, &g); - analyze_tetrahedra_bcl (&v0, &v9, &v7, &v3, surface, help, z, &g); - analyze_tetrahedra_bcl (&v0, &v7, &w0, &v3, surface, help, z, &g); - analyze_tetrahedra_bcl (&v0, &w0, &v8, &v3, surface, help, z, &g); - } -} - -/* copy src into dest by stripping off the iso value and leave out - the boundary (which should be G_MINDOUBLE) */ -static void copy_to_bounded (slice_t * dest, slice_t * src, - gdouble iso, gdouble fill) -{ - gint x,y; - gdouble * src_ptr; - gdouble * dest_ptr = dest->data[0]; - - g_assert(dest->ny == src->ny + 2); - g_assert(dest->nx == src->nx + 2); - - for (y = 0; y < dest->ny; ++y, ++dest_ptr) - *dest_ptr = fill; - - for (x = 1; x < src->nx - 1; ++x) { - dest_ptr = dest->data[x]; - src_ptr = src->data[x-1]; - *dest_ptr++ = fill; - for (y = 0; y < src->ny; ++y, ++dest_ptr, ++src_ptr) - *dest_ptr = *src_ptr - iso; - *dest_ptr++ = fill; - } - - dest_ptr = dest->data[y]; - - for (y = 0; y < dest->ny; ++y, ++dest_ptr) - *dest_ptr = fill; -} - -static void iso_sub (slice_t * s, gdouble iso) -{ - gint x,y; - - for (x = 0; x < s->nx; ++x) { - gdouble *ptr = s->data[x]; - - for (y = 0; y < s->ny; ++y, ++ptr) - *ptr -= iso; - } -} - - -/** - * gts_isosurface_tetra_bounded: - * @surface: a #GtsSurface. - * @g: a #GtsCartesianGrid. - * @f: a #GtsIsoCartesianFunc. - * @data: user data to be passed to @f. - * @iso: isosurface value. - * - * Adds to @surface new faces defining the isosurface f(x,y,z) = - * @iso. By convention, the normals to the surface are pointing toward - * the positive values of f(x,y,z) - @iso. To ensure a closed object, - * a boundary of G_MINDOUBLE is added around the domain - * - * The user function @f is called successively for each value of the z - * coordinate defined by @g. It must fill the corresponding (x,y) - * plane with the values of the function for which the isosurface is - * to be computed. - */ -void gts_isosurface_tetra_bounded (GtsSurface * surface, - GtsCartesianGrid g, - GtsIsoCartesianFunc f, - gpointer data, - gdouble iso) -{ - slice_t *slice1, *slice2, *transfer_slice; - GtsCartesianGrid g_intern = g; - helper_t *helper; - gint z; - - g_return_if_fail (surface != NULL); - g_return_if_fail (f != NULL); - g_return_if_fail (g.nx > 1); - g_return_if_fail (g.ny > 1); - g_return_if_fail (g.nz > 1); - - /* create the helper slices */ - slice1 = new_slice (g.nx + 2, g.ny + 2); - slice2 = new_slice (g.nx + 2, g.ny + 2); - - /* initialize the first slice as OUTSIDE */ - slice_init (slice1, -1.0); - - /* create a slice of the original image size */ - transfer_slice = new_slice (g.nx, g.ny); - - /* adapt the parameters to our enlarged image */ - g_intern.x -= g.dx; - g_intern.y -= g.dy; - g_intern.z -= g.dz; - g_intern.nx = g.nx + 2; - g_intern.ny = g.ny + 2; - g_intern.nz = g.nz; - - /* create the helper for vertex-lookup */ - helper = init_helper (g_intern.nx, g_intern.ny); - - /* go slicewise through the data */ - z = 0; - while (z < g.nz) { - slice_t * hs; - - /* request slice */ - f (transfer_slice->data, g, z, data); - g.z += g.dz; - - /* copy slice in enlarged image and mark the border as OUTSIDE */ - copy_to_bounded (slice2, transfer_slice, iso, -1.); - - /* triangulate */ - iso_slice_evaluate (slice1, slice2, g_intern, z, surface, helper); - - /* switch the input slices */ - hs = slice1; slice1 = slice2; slice2 = hs; - - /* switch the vertex lookup tables */ - helper_advance(helper); - ++z; - } - - /* initialize the last slice as OUTSIDE */ - slice_init (slice2, - 1.0); - - /* close the object */ - iso_slice_evaluate(slice1, slice2, g_intern, z, surface, helper); - - free_helper (helper); - free_slice (slice1); - free_slice (slice2); - free_slice (transfer_slice); -} - -/** - * gts_isosurface_tetra: - * @surface: a #GtsSurface. - * @g: a #GtsCartesianGrid. - * @f: a #GtsIsoCartesianFunc. - * @data: user data to be passed to @f. - * @iso: isosurface value. - * - * Adds to @surface new faces defining the isosurface f(x,y,z) = - * @iso. By convention, the normals to the surface are pointing toward - * the positive values of f(x,y,z) - @iso. - * - * The user function @f is called successively for each value of the z - * coordinate defined by @g. It must fill the corresponding (x,y) - * plane with the values of the function for which the isosurface is - * to be computed. - */ -void gts_isosurface_tetra (GtsSurface * surface, - GtsCartesianGrid g, - GtsIsoCartesianFunc f, - gpointer data, - gdouble iso) -{ - slice_t *slice1, *slice2; - helper_t *helper; - gint z; - GtsCartesianGrid g_internal; - - g_return_if_fail (surface != NULL); - g_return_if_fail (f != NULL); - g_return_if_fail (g.nx > 1); - g_return_if_fail (g.ny > 1); - g_return_if_fail (g.nz > 1); - - memcpy (&g_internal, &g, sizeof (GtsCartesianGrid)); - - /* create the helper slices */ - slice1 = new_slice (g.nx, g.ny); - slice2 = new_slice (g.nx, g.ny); - - /* create the helper for vertex-lookup */ - helper = init_helper (g.nx, g.ny); - - z = 0; - f (slice1->data, g, z, data); - iso_sub (slice1, iso); - - z++; - g.z += g.dz; - - /* go slicewise through the data */ - while (z < g.nz) { - slice_t * hs; - - /* request slice */ - f (slice2->data, g, z, data); - iso_sub (slice2, iso); - - g.z += g.dz; - - /* triangulate */ - iso_slice_evaluate (slice1, slice2, g_internal, z-1, surface, helper); - - /* switch the input slices */ - hs = slice1; slice1 = slice2; slice2 = hs; - - /* switch the vertex lookup tables */ - helper_advance (helper); - - ++z; - } - - free_helper(helper); - free_slice(slice1); - free_slice(slice2); -} - -/** - * gts_isosurface_tetra_bcl: - * @surface: a #GtsSurface. - * @g: a #GtsCartesianGrid. - * @f: a #GtsIsoCartesianFunc. - * @data: user data to be passed to @f. - * @iso: isosurface value. - * - * Adds to @surface new faces defining the isosurface f(x,y,z) = - * @iso. By convention, the normals to the surface are pointing toward - * the positive values of f(x,y,z) - @iso. - * - * The user function @f is called successively for each value of the z - * coordinate defined by @g. It must fill the corresponding (x,y) - * plane with the values of the function for which the isosurface is - * to be computed. - * - * This version produces the dual "body-centered" faces relative to - * the faces produced by gts_isosurface_tetra(). - */ -void gts_isosurface_tetra_bcl (GtsSurface * surface, - GtsCartesianGrid g, - GtsIsoCartesianFunc f, - gpointer data, - gdouble iso) -{ - slice_t *slice1, *slice2, *slice3; - helper_bcl *helper; - gint z; - GtsCartesianGrid g_internal; - - g_return_if_fail (surface != NULL); - g_return_if_fail (f != NULL); - g_return_if_fail (g.nx > 1); - g_return_if_fail (g.ny > 1); - g_return_if_fail (g.nz > 1); - - memcpy (&g_internal, &g, sizeof (GtsCartesianGrid)); - - /* create the helper slices */ - slice1 = new_slice (g.nx, g.ny); - slice2 = new_slice (g.nx, g.ny); - slice3 = new_slice (g.nx, g.ny); - - /* create the helper for vertex-lookup */ - helper = init_helper_bcl (); - - z = 0; - f (slice1->data, g, z, data); - iso_sub (slice1, iso); - - z++; - g.z += g.dz; - - f (slice2->data, g, z, data); - iso_sub (slice1, iso); - - z++; - g.z += g.dz; - - /* go slicewise through the data */ - while (z < g.nz) { - slice_t * hs; - - /* request slice */ - f (slice3->data, g, z, data); - iso_sub (slice3, iso); - - g.z += g.dz; - - /* triangulate */ - iso_slice_evaluate_bcl (slice1, slice2, slice3, g_internal, z-2, - surface, helper); - - /* switch the input slices */ - hs = slice1; slice1 = slice2; slice2 = slice3; slice3 = hs; - - /* switch the vertex lookup tables */ - helper_advance_bcl (helper); - - ++z; - } - - free_helper_bcl(helper); - free_slice(slice1); - free_slice(slice2); - free_slice(slice3); -} Index: trunk/src_3rd/gts/tribox3.c =================================================================== --- trunk/src_3rd/gts/tribox3.c (revision 6802) +++ trunk/src_3rd/gts/tribox3.c (nonexistent) @@ -1,192 +0,0 @@ -/** - * History: - * 2004-10-27 Stephane Popinet: changed float to double - */ - -/********************************************************/ -/* AABB-triangle overlap test code */ -/* by Tomas Akenine-Möller */ -/* Function: int triBoxOverlap(float boxcenter[3], */ -/* float boxhalfsize[3],float triverts[3][3]); */ -/* History: */ -/* 2001-03-05: released the code in its first version */ -/* 2001-06-18: changed the order of the tests, faster */ -/* */ -/* Acknowledgement: Many thanks to Pierre Terdiman for */ -/* suggestions and discussions on how to optimize code. */ -/* Thanks to David Hunt for finding a ">="-bug! */ -/********************************************************/ -#include -#include - -#define X 0 -#define Y 1 -#define Z 2 - -#define CROSS(dest,v1,v2) \ - dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \ - dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \ - dest[2]=v1[0]*v2[1]-v1[1]*v2[0]; - -#define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]) - -#define SUB(dest,v1,v2) \ - dest[0]=v1[0]-v2[0]; \ - dest[1]=v1[1]-v2[1]; \ - dest[2]=v1[2]-v2[2]; - -#define FINDMINMAX(x0,x1,x2,min,max) \ - min = max = x0; \ - if(x1max) max=x1;\ - if(x2max) max=x2; - -int planeBoxOverlap(double normal[3], double vert[3], double maxbox[3]) // -NJMP- -{ - int q; - double vmin[3],vmax[3],v; - for(q=X;q<=Z;q++) - { - v=vert[q]; // -NJMP- - if(normal[q]>0.0f) - { - vmin[q]=-maxbox[q] - v; // -NJMP- - vmax[q]= maxbox[q] - v; // -NJMP- - } - else - { - vmin[q]= maxbox[q] - v; // -NJMP- - vmax[q]=-maxbox[q] - v; // -NJMP- - } - } - if(DOT(normal,vmin)>0.0f) return 0; // -NJMP- - if(DOT(normal,vmax)>=0.0f) return 1; // -NJMP- - - return 0; -} - - -/*======================== X-tests ========================*/ -#define AXISTEST_X01(a, b, fa, fb) \ - p0 = a*v0[Y] - b*v0[Z]; \ - p2 = a*v2[Y] - b*v2[Z]; \ - if(p0rad || max<-rad) return 0; - -#define AXISTEST_X2(a, b, fa, fb) \ - p0 = a*v0[Y] - b*v0[Z]; \ - p1 = a*v1[Y] - b*v1[Z]; \ - if(p0rad || max<-rad) return 0; - -/*======================== Y-tests ========================*/ -#define AXISTEST_Y02(a, b, fa, fb) \ - p0 = -a*v0[X] + b*v0[Z]; \ - p2 = -a*v2[X] + b*v2[Z]; \ - if(p0rad || max<-rad) return 0; - -#define AXISTEST_Y1(a, b, fa, fb) \ - p0 = -a*v0[X] + b*v0[Z]; \ - p1 = -a*v1[X] + b*v1[Z]; \ - if(p0rad || max<-rad) return 0; - -/*======================== Z-tests ========================*/ - -#define AXISTEST_Z12(a, b, fa, fb) \ - p1 = a*v1[X] - b*v1[Y]; \ - p2 = a*v2[X] - b*v2[Y]; \ - if(p2rad || max<-rad) return 0; - -#define AXISTEST_Z0(a, b, fa, fb) \ - p0 = a*v0[X] - b*v0[Y]; \ - p1 = a*v1[X] - b*v1[Y]; \ - if(p0rad || max<-rad) return 0; - -int triBoxOverlap(double boxcenter[3],double boxhalfsize[3],double triverts[3][3]) -{ - - /* use separating axis theorem to test overlap between triangle and box */ - /* need to test for overlap in these directions: */ - /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */ - /* we do not even need to test these) */ - /* 2) normal of the triangle */ - /* 3) crossproduct(edge from tri, {x,y,z}-directin) */ - /* this gives 3x3=9 more tests */ - double v0[3],v1[3],v2[3]; -// double axis[3]; - double min,max,p0,p1,p2,rad,fex,fey,fez; // -NJMP- "d" local variable removed - double normal[3],e0[3],e1[3],e2[3]; - - /* This is the fastest branch on Sun */ - /* move everything so that the boxcenter is in (0,0,0) */ - SUB(v0,triverts[0],boxcenter); - SUB(v1,triverts[1],boxcenter); - SUB(v2,triverts[2],boxcenter); - - /* compute triangle edges */ - SUB(e0,v1,v0); /* tri edge 0 */ - SUB(e1,v2,v1); /* tri edge 1 */ - SUB(e2,v0,v2); /* tri edge 2 */ - - /* Bullet 3: */ - /* test the 9 tests first (this was faster) */ - fex = fabsf(e0[X]); - fey = fabsf(e0[Y]); - fez = fabsf(e0[Z]); - AXISTEST_X01(e0[Z], e0[Y], fez, fey); - AXISTEST_Y02(e0[Z], e0[X], fez, fex); - AXISTEST_Z12(e0[Y], e0[X], fey, fex); - - fex = fabsf(e1[X]); - fey = fabsf(e1[Y]); - fez = fabsf(e1[Z]); - AXISTEST_X01(e1[Z], e1[Y], fez, fey); - AXISTEST_Y02(e1[Z], e1[X], fez, fex); - AXISTEST_Z0(e1[Y], e1[X], fey, fex); - - fex = fabsf(e2[X]); - fey = fabsf(e2[Y]); - fez = fabsf(e2[Z]); - AXISTEST_X2(e2[Z], e2[Y], fez, fey); - AXISTEST_Y1(e2[Z], e2[X], fez, fex); - AXISTEST_Z12(e2[Y], e2[X], fey, fex); - - /* Bullet 1: */ - /* first test overlap in the {x,y,z}-directions */ - /* find min, max of the triangle each direction, and test for overlap in */ - /* that direction -- this is equivalent to testing a minimal AABB around */ - /* the triangle against the AABB */ - - /* test in X-direction */ - FINDMINMAX(v0[X],v1[X],v2[X],min,max); - if(min>boxhalfsize[X] || max<-boxhalfsize[X]) return 0; - - /* test in Y-direction */ - FINDMINMAX(v0[Y],v1[Y],v2[Y],min,max); - if(min>boxhalfsize[Y] || max<-boxhalfsize[Y]) return 0; - - /* test in Z-direction */ - FINDMINMAX(v0[Z],v1[Z],v2[Z],min,max); - if(min>boxhalfsize[Z] || max<-boxhalfsize[Z]) return 0; - - /* Bullet 2: */ - /* test if the box intersects the plane of the triangle */ - /* compute plane equation of triangle: normal*x+d=0 */ - CROSS(normal,e0,e1); - // -NJMP- (line removed here) - if(!planeBoxOverlap(normal,v0,boxhalfsize)) return 0; // -NJMP- - - return 1; /* box and triangle overlaps */ -} - Index: trunk/src_3rd/gts/rounding.h =================================================================== --- trunk/src_3rd/gts/rounding.h (revision 6802) +++ trunk/src_3rd/gts/rounding.h (nonexistent) @@ -1,85 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "config.h" - -#ifdef HAVE_FPU_CONTROL_H -# include -# ifdef _FPU_EXTENDED -# if !defined(__alpha__) || !defined(__GLIBC__) -# if defined(__arm__) - static fpu_control_t fpu_round_double = _FPU_DEFAULT; -# else - static fpu_control_t fpu_round_double = - (_FPU_DEFAULT & ~ _FPU_EXTENDED)|_FPU_DOUBLE; -# endif - static fpu_control_t fpu_init; -# define FPU_ROUND_DOUBLE { _FPU_GETCW(fpu_init);\ - _FPU_SETCW(fpu_round_double); } -# define FPU_RESTORE {_FPU_SETCW(fpu_init);} -# else /* __alpha__ && __GLIBC__ */ -# define FPU_ROUND_DOUBLE -# define FPU_RESTORE -# endif /* __alpha__ && __GLIBC__ */ -# else /* not FPU_EXTENDED */ -# define FPU_ROUND_DOUBLE -# define FPU_RESTORE -# endif /* not FPU_EXTENDED */ -#else /* not HAVE_FPU_CONTROL_H */ -# ifdef __FreeBSD__ -# include -# define FPU_ROUND_DOUBLE (fpsetprec(FP_PD)) -# define FPU_RESTORE (fpsetprec(FP_PE)) -# else /* not __FreeBSD__ */ -# ifdef WIN32 -# ifdef _MSC_VER -# include - static unsigned int fpu_init; -# define FPU_ROUND_DOUBLE (fpu_init = _controlfp (0, 0),\ - _controlfp (_PC_53, MCW_PC)) -# define FPU_RESTORE (_controlfp (fpu_init, 0xfffff)) -# elif __MINGW32__ -# include - static unsigned int fpu_init; -# define FPU_ROUND_DOUBLE (fpu_init = _controlfp (0, 0),\ - _controlfp (_PC_53, _MCW_PC)) -# define FPU_RESTORE (_controlfp (fpu_init, 0xfffff)) -# else /* not _MSC_VER or __MINGW32__ */ -# error "You need MSVC or MinGW for the Win32 version" -# endif /* not _MSC_VER or __MINGW32__ */ -# else /* not WIN32 */ -# ifdef __CYGWIN__ - typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__HI__))); - static fpu_control_t fpu_round_double = 0x027f; - static fpu_control_t fpu_init; -# define _FPU_GETCW(cw) __asm__ ("fnstcw %0" : "=m" (*&cw)) -# define _FPU_SETCW(cw) __asm__ ("fldcw %0" : : "m" (*&cw)) -# define FPU_ROUND_DOUBLE { _FPU_GETCW(fpu_init);\ - _FPU_SETCW(fpu_round_double); } -# define FPU_RESTORE { _FPU_SETCW(fpu_init);} -# else /* not __CYGWIN__ */ -# ifdef CPP_HAS_WARNING -# warning "Unknown CPU: assuming default double precision rounding" -# endif /* CPP_HAS_WARNING */ -# define FPU_ROUND_DOUBLE -# define FPU_RESTORE -# endif /* not __CYGWIN__ */ -# endif /* not WIN32 */ -# endif /* not __FreeBSD__ */ -#endif /* not HAVE_FPU_CONTROL_H */ Index: trunk/src_3rd/gts/split.c =================================================================== --- trunk/src_3rd/gts/split.c (revision 6802) +++ trunk/src_3rd/gts/split.c (nonexistent) @@ -1,1840 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include -#include "gts.h" - -#define DYNAMIC_SPLIT -#define NEW - -/* #define DEBUG - #define DEBUG_HEXPAND - #define DEBUG_EXPAND */ - -struct _GtsSplitCFace { - GtsFace * f; - GtsTriangle ** a1, ** a2; -}; - -typedef struct _CFace CFace; -typedef struct _CFaceClass CFaceClass; - -struct _CFace { - GtsObject object; - - GtsSplit * parent_split; - GtsTriangle * t; - guint flags; -}; -/* the size of the CFace structure must be smaller or equal to the size - of the GtsFace structure as both structures use the same memory location */ - -struct _CFaceClass { - GtsObjectClass parent_class; -}; - -#define IS_CFACE(obj) (gts_object_is_from_class (obj, cface_class ())) -#define CFACE(obj) ((CFace *) obj) -#define CFACE_ORIENTATION(cf) ((cf)->flags & 0x1) -#define CFACE_ORIENTATION_DIRECT(cf) ((cf)->flags |= 0x1) -#define CFACE_VVS(cf) ((cf)->flags & 0x2) -#define CFACE_VVS_DIRECT(cf) ((cf)->flags |= 0x2) -#define CFACE_E1 0x4 -#define CFACE_E2 0x8 -#define CFACE_KEEP_VVS 0x10 - -#define ROTATE_ORIENT(e, e1, e2, e3) { if (e1 == e) { e1 = e2; e2 = e3; }\ - else if (e2 == e) { e2 = e1; e1 = e3; }\ - else g_assert (e3 == e); } -#define SEGMENT_USE_VERTEX(s, v) ((s)->v1 == v || (s)->v2 == v) -#define TRIANGLE_REPLACE_EDGE(t, e, with) { if ((t)->e1 == e)\ - (t)->e1 = with;\ - else if ((t)->e2 == e)\ - (t)->e2 = with;\ - else {\ - g_assert ((t)->e3 == e);\ - (t)->e3 = with;\ - }\ - } - -#define HEAP_INSERT_OBJECT(h, e) (GTS_OBJECT (e)->reserved =\ - gts_eheap_insert (h, e)) -#define HEAP_REMOVE_OBJECT(h, e) (gts_eheap_remove (h, GTS_OBJECT (e)->reserved),\ - GTS_OBJECT (e)->reserved = NULL) - -static GtsObjectClass * cface_class (void) -{ - static GtsObjectClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo cface_info = { - "GtsCFace", - sizeof (CFace), - sizeof (CFaceClass), - (GtsObjectClassInitFunc) NULL, - (GtsObjectInitFunc) NULL, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (gts_object_class (), &cface_info); - g_assert (sizeof (CFace) <= sizeof (GtsFace)); - } - - return klass; -} - -/* Replace @e with @with for all the triangles using @e but @f. - Destroys @e and removes it from @heap (if not %NULL). - Returns a triangle using e different from f or %NULL. */ -static GtsTriangle * replace_edge_collapse (GtsEdge * e, - GtsEdge * with, - CFace * cf, - GtsEHeap * heap -#ifdef DYNAMIC_SPLIT - , GtsTriangle *** a1 -#endif -#ifdef NEW - , guint edge_flag -#endif - ) -{ - GSList * i; - GtsTriangle * rt = NULL; -#ifdef DYNAMIC_SPLIT - guint size; - GtsTriangle ** a; -#endif - -#ifdef NEW - i = e->triangles; - e->triangles = NULL; - size = g_slist_length (i)*sizeof (GtsTriangle *); - *a1 = a = g_malloc (size > 0 ? size : sizeof (GtsTriangle *)); - while (i) { - GtsTriangle * t = i->data; - GSList * next = i->next; - if (t != ((GtsTriangle *) cf)) { - if (IS_CFACE (t)) { - i->next = e->triangles; - e->triangles = i; - /* set the edge given by edge_flag (CFACE_E1 or CFACE_E2) */ - GTS_OBJECT (t)->reserved = GUINT_TO_POINTER (edge_flag); - cf->flags |= CFACE_KEEP_VVS; - } - else { - TRIANGLE_REPLACE_EDGE (t, e, with); - i->next = with->triangles; - with->triangles = i; - rt = t; - *(a++) = t; - } - } - else - g_slist_free_1 (i); - i = next; - } - *a = NULL; - if (!e->triangles) { - if (heap) - HEAP_REMOVE_OBJECT (heap, e); - gts_object_destroy (GTS_OBJECT (e)); - } -#else /* not NEW */ - i = e->triangles; -#ifdef DYNAMIC_SPLIT - size = g_slist_length (i)*sizeof (GtsTriangle *); - *a1 = a = g_malloc (size > 0 ? size : sizeof (GtsTriangle *)); -#endif - while (i) { - GtsTriangle * t = i->data; - GSList * next = i->next; - if (t != ((GtsTriangle *) cf)) { - TRIANGLE_REPLACE_EDGE (t, e, with); - i->next = with->triangles; - with->triangles = i; - rt = t; -#ifdef DYNAMIC_SPLIT - *(a++) = t; -#endif - } - else - g_slist_free_1 (i); - i = next; - } -#ifdef DYNAMIC_SPLIT - *a = NULL; -#endif - if (heap) - HEAP_REMOVE_OBJECT (heap, e); - e->triangles = NULL; - gts_object_destroy (GTS_OBJECT (e)); -#endif /* NEW */ - - return rt; -} - -static CFace * cface_new (GtsFace * f, - GtsEdge * e, - GtsVertex * v1, - GtsVertex * v2, - GtsSplit * vs, - GtsEHeap * heap, - GtsEdgeClass * klass -#ifdef DYNAMIC_SPLIT - , GtsSplitCFace * scf -#endif - ) -{ - CFace * cf; - GtsVertex * v; - GtsEdge * e1, * e2, * e3, * vvs; - GSList * i; - GtsTriangle * t, * t1 = NULL, * t2 = NULL; - guint flags; - - g_return_val_if_fail (f != NULL, NULL); -#ifndef NEW - g_return_val_if_fail (GTS_IS_FACE (f), NULL); -#endif - g_return_val_if_fail (e != NULL, NULL); - g_return_val_if_fail (vs != NULL, NULL); - - t = ((GtsTriangle *) f); - if (heap) - g_return_val_if_fail (!gts_triangle_is_duplicate (t), NULL); - -#ifdef NEW - /* get CFACE_E1 and CFACE_E2 info */ - flags = GPOINTER_TO_UINT (GTS_OBJECT (f)->reserved); -#endif - GTS_OBJECT_SET_FLAGS (f, GTS_DESTROYED); - - i = f->surfaces; - while (i) { - GSList * next = i->next; - gts_surface_remove_face (i->data, f); - i = next; - } - g_slist_free (f->surfaces); - - e1 = t->e1; e2 = t->e2; e3 = t->e3; - ROTATE_ORIENT (e, e1, e2, e3); - - cf = (CFace *) f; -#ifndef NEW - GTS_OBJECT (cf)->klass = cface_class (); -#else - cf->flags = flags; -#endif - gts_object_init (GTS_OBJECT (cf), cface_class ()); - cf->parent_split = vs; - - if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1), v2)) { - CFACE_ORIENTATION_DIRECT (cf); /* v1->v2->v */ - e3 = e1; e1 = e2; e2 = e3; - } - v = GTS_SEGMENT (e1)->v1 == v1 ? - GTS_SEGMENT (e1)->v2 : GTS_SEGMENT (e1)->v1; -#ifdef NEW - if ((cf->flags & CFACE_E1) || (cf->flags & CFACE_E2)) - g_assert ((vvs = GTS_EDGE (gts_vertices_are_connected (vs->v, v)))); - else -#endif - vvs = gts_edge_new (klass, v, vs->v); - - t1 = replace_edge_collapse (e1, vvs, cf, heap -#ifdef DYNAMIC_SPLIT - , &scf->a1 -#endif -#ifdef NEW - , CFACE_E1 -#endif - ); - t2 = replace_edge_collapse (e2, vvs, cf, heap -#ifdef DYNAMIC_SPLIT - , &scf->a2 -#endif -#ifdef NEW - , CFACE_E2 -#endif - ); - t = cf->t = t1 ? t1 : t2; - g_assert (t); - - /* set up flags necessary to find vvs */ - if (t->e1 == vvs) e2 = t->e2; - else if (t->e2 == vvs) e2 = t->e3; - else { - g_assert (t->e3 == vvs); - e2 = t->e1; - } - if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e2), v)) - CFACE_VVS_DIRECT (cf); - - return cf; -} - -static void find_vvs (GtsVertex * vs, - GtsTriangle * t, - GtsVertex ** v, GtsEdge ** vvs, - gboolean orientation) -{ - GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3, * tmp; - - if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e2), vs)) { - tmp = e1; e1 = e2; e2 = e3; e3 = tmp; - } - else if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e3), vs)) { - tmp = e1; e1 = e3; e3 = e2; e2 = tmp; - } - else - g_assert (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1), vs)); - if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e2), vs) || - !gts_segments_touch (GTS_SEGMENT (e1), GTS_SEGMENT (e2))) { - tmp = e1; e1 = e2; e2 = e3; e3 = tmp; - g_assert (gts_segments_touch (GTS_SEGMENT (e1), GTS_SEGMENT (e2))); - } - - *vvs = orientation ? e1 : e3; - - if (GTS_SEGMENT (*vvs)->v1 != vs) { - g_assert (GTS_SEGMENT (*vvs)->v2 == vs); - *v = GTS_SEGMENT (*vvs)->v1; - } - else - *v = GTS_SEGMENT (*vvs)->v2; -} - -static void replace_edge_expand (GtsEdge * e, - GtsEdge * with, - GtsTriangle ** a, - GtsVertex * v) -{ - GtsTriangle ** i = a, * t; - - while ((t = *(i++))) { -#ifdef DEBUG_EXPAND - g_assert (!IS_CFACE (t)); - fprintf (stderr, "replacing %p->%d: e: %p->%d with: %p->%d\n", - t, id (t), e, id (e), with, id (with)); -#endif - TRIANGLE_REPLACE_EDGE (t, e, with); - with->triangles = g_slist_prepend (with->triangles, t); - if (GTS_OBJECT (t)->reserved) { - /* apart from the triangles having e as an edge, t is the only - triangle using v */ - g_assert (GTS_OBJECT (t)->reserved == v); - GTS_OBJECT (t)->reserved = NULL; - } - else - GTS_OBJECT (t)->reserved = v; - } -} - -static void cface_expand (CFace * cf, - GtsTriangle ** a1, - GtsTriangle ** a2, - GtsEdge * e, - GtsVertex * v1, - GtsVertex * v2, - GtsVertex * vs, - GtsEdgeClass * klass) -{ - GtsVertex * v; - GtsEdge * e1, * e2, * vvs; - gboolean orientation; - guint flags; - - g_return_if_fail (cf != NULL); - g_return_if_fail (IS_CFACE (cf)); - g_return_if_fail (e != NULL); - g_return_if_fail (vs != NULL); - - flags = cf->flags; - orientation = CFACE_ORIENTATION (cf); - - find_vvs (vs, cf->t, &v, &vvs, CFACE_VVS (cf)); - -#ifdef NEW - if (flags & CFACE_E1) - e1 = GTS_EDGE (gts_vertices_are_connected (v1, v)); - else - e1 = gts_edge_new (klass, v, v1); - if (flags & CFACE_E2) - e2 = GTS_EDGE (gts_vertices_are_connected (v2, v)); - else - e2 = gts_edge_new (klass, v, v2); -#else - e1 = gts_edge_new (v, v1); - e2 = gts_edge_new (v, v2); -#endif - - replace_edge_expand (vvs, e1, a1, v1); - replace_edge_expand (vvs, e2, a2, v2); - -#ifdef NEW - if (!(flags & CFACE_KEEP_VVS)) { - g_slist_free (vvs->triangles); - vvs->triangles = NULL; - gts_object_destroy (GTS_OBJECT (vvs)); - } -#else - g_slist_free (vvs->triangles); - vvs->triangles = NULL; - gts_object_destroy (GTS_OBJECT (vvs)); -#endif - - /* gts_face_new : because I am "creating" a face */ - GTS_OBJECT (cf)->klass = GTS_OBJECT_CLASS (gts_face_class ()); - gts_object_init (GTS_OBJECT (cf), GTS_OBJECT (cf)->klass); - - if (orientation) - gts_triangle_set (GTS_TRIANGLE (cf), e, e2, e1); - else - gts_triangle_set (GTS_TRIANGLE (cf), e, e1, e2); -} - -static void split_destroy (GtsObject * object) -{ - GtsSplit * vs = GTS_SPLIT (object); - guint i = vs->ncf; - GtsSplitCFace * cf = vs->cfaces; - - while (i--) { - if (IS_CFACE (cf->f)) - gts_object_destroy (GTS_OBJECT (cf->f)); - g_free (cf->a1); - g_free (cf->a2); - cf++; - } - g_free (vs->cfaces); - - if (!gts_allow_floating_vertices && vs->v && vs->v->segments == NULL) - gts_object_destroy (GTS_OBJECT (vs->v)); - - (* GTS_OBJECT_CLASS (gts_split_class ())->parent_class->destroy) (object); -} - -static void split_class_init (GtsObjectClass * klass) -{ - klass->destroy = split_destroy; -} - -static void split_init (GtsSplit * split) -{ - split->v1 = split->v2 = NULL; - split->v = NULL; - split->cfaces = NULL; - split->ncf = 0; -} - -/** - * gts_split_class: - * - * Returns: the #GtsSplitClass. - */ -GtsSplitClass * gts_split_class (void) -{ - static GtsSplitClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo split_info = { - "GtsSplit", - sizeof (GtsSplit), - sizeof (GtsSplitClass), - (GtsObjectClassInitFunc) split_class_init, - (GtsObjectInitFunc) split_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (gts_object_class (), - &split_info); - } - - return klass; -} - -#ifdef DEBUG -static gboolean edge_collapse_is_valid (GtsEdge * e) -{ - GSList * i; - - g_return_val_if_fail (e != NULL, FALSE); - - if (gts_segment_is_duplicate (GTS_SEGMENT (e))) { - g_warning ("collapsing duplicate edge"); - return FALSE; - } - - i = GTS_SEGMENT (e)->v1->segments; - while (i) { - GtsEdge * e1 = i->data; - if (e1 != e && GTS_IS_EDGE (e1)) { - GtsEdge * e2 = NULL; - GSList * j = GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e)->v1 ? - GTS_SEGMENT (e1)->v2->segments : GTS_SEGMENT (e1)->v1->segments; - while (j && !e2) { - GtsEdge * e1 = j->data; - if (GTS_IS_EDGE (e1) && - (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e)->v2 || - GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e)->v2)) - e2 = e1; - j = j->next; - } - if (e2 && !gts_triangle_use_edges (e, e1, e2)) { - g_warning ("collapsing empty triangle"); - return FALSE; - } - } - i = i->next; - } - - if (gts_edge_is_boundary (e, NULL)) { - GtsTriangle * t = e->triangles->data; - if (gts_edge_is_boundary (t->e1, NULL) && - gts_edge_is_boundary (t->e2, NULL) && - gts_edge_is_boundary (t->e3, NULL)) { - g_warning ("collapsing single triangle"); - return FALSE; - } - } - else { - if (gts_vertex_is_boundary (GTS_SEGMENT (e)->v1, NULL) && - gts_vertex_is_boundary (GTS_SEGMENT (e)->v2, NULL)) { - g_warning ("collapsing two sides of a strip"); - return FALSE; - } - if (gts_edge_belongs_to_tetrahedron (e)) { - g_warning ("collapsing tetrahedron"); - return FALSE; - } - } - - return TRUE; -} -#endif /* DEBUG */ - -/* Not currently used. May be useful for some debug code */ -#ifdef DEBUG -static void print_split (GtsSplit * vs, FILE * fptr) -{ - guint j; - GtsSplitCFace * cf; - - g_return_if_fail (vs != NULL); - g_return_if_fail (fptr != NULL); - - fprintf (fptr, "%p: v: %p v1: %p v2: %p ncf: %u cfaces: %p\n", - vs, vs->v, vs->v1, vs->v2, vs->ncf, vs->cfaces); - cf = vs->cfaces; - j = vs->ncf; - while (j--) { - fprintf (stderr, " f: %p a1: %p a2: %p\n", - cf->f, cf->a1, cf->a2); - cf++; - } -} -#endif - -/** - * gts_split_collapse: - * @vs: a #GtsSplit. - * @klass: a #GtsEdgeClass. - * @heap: a #GtsEHeap or %NULL. - * - * Collapses the vertex split @vs. Any new edge created during the process will - * be of class @klass. If heap is not %NULL, the new edges will be inserted - * into it and the destroyed edges will be removed from it. - */ -void gts_split_collapse (GtsSplit * vs, - GtsEdgeClass * klass, - GtsEHeap * heap) -{ - GtsEdge * e; - GtsVertex * v, * v1, * v2; - GSList * i, * end; -#ifdef DYNAMIC_SPLIT - GtsSplitCFace * cf; - guint j; -#endif -#ifdef DEBUG - gboolean invalid = FALSE; - static guint ninvalid = 0; -#endif - - g_return_if_fail (vs != NULL); - g_return_if_fail (klass != NULL); - - v = vs->v; - - g_return_if_fail (v->segments == NULL); - - /* we don't want to destroy vertices */ - gts_allow_floating_vertices = TRUE; - - v1 = GTS_SPLIT_V1 (vs); - v2 = GTS_SPLIT_V2 (vs); - g_assert ((e = GTS_EDGE (gts_vertices_are_connected (v1, v2)))); - -#ifdef DEBUG - fprintf (stderr, "collapsing %p: v1: %p v2: %p v: %p\n", vs, v1, v2, v); - if (!edge_collapse_is_valid (e)) { - char fname[80]; - FILE * fptr; - GSList * triangles, * i; - - g_warning ("invalid edge collapse"); - invalid = TRUE; - sprintf (fname, "invalid.%d", ninvalid); - fptr = fopen (fname, "wt"); - gts_write_segment (GTS_SEGMENT (e), GTS_POINT (v), fptr); - triangles = gts_vertex_triangles (v1, NULL); - triangles = gts_vertex_triangles (v2, triangles); - i = triangles; - while (i) { - gts_write_triangle (i->data, GTS_POINT (v), fptr); - i = i->next; - } - g_slist_free (triangles); - fclose (fptr); - } -#endif - - i = e->triangles; -#ifdef DYNAMIC_SPLIT - cf = vs->cfaces; - j = vs->ncf; - while (j--) { - g_free (cf->a1); - g_free (cf->a2); - cf++; - } - g_free (vs->cfaces); - - vs->ncf = g_slist_length (i); - g_assert (vs->ncf > 0); - cf = vs->cfaces = g_malloc (vs->ncf*sizeof (GtsSplitCFace)); -#endif /* DYNAMIC_SPLIT */ -#ifdef NEW - while (i) { - cf->f = i->data; - g_assert (GTS_IS_FACE (cf->f)); - GTS_OBJECT (cf->f)->klass = GTS_OBJECT_CLASS (cface_class ()); - cf++; - i = i->next; - } - i = e->triangles; - cf = vs->cfaces; - while (i) { - cface_new (i->data, e, v1, v2, vs, heap, klass, cf); -#ifdef DEBUG - fprintf (stderr, "cface: %p->%d t: %p->%d a1: ", - cf->f, id (cf->f), CFACE (cf->f)->t, id (CFACE (cf->f)->t)); - { - GtsTriangle * t, ** a; - a = cf->a1; - while ((t = *(a++))) - fprintf (stderr, "%p->%d ", t, id (t)); - fprintf (stderr, "a2: "); - a = cf->a2; - while ((t = *(a++))) - fprintf (stderr, "%p->%d ", t, id (t)); - fprintf (stderr, "\n"); - } -#endif - cf++; - i = i->next; - } -#else /* not NEW */ - while (i) { - cface_new (i->data, e, v1, v2, vs, heap -#ifdef DYNAMIC_SPLIT - , cf -#endif /* DYNAMIC_SPLIT */ - ); -#ifdef DYNAMIC_SPLIT - cf->f = i->data; - cf++; -#endif /* DYNAMIC_SPLIT */ - i = i->next; - } -#endif /* NEW */ - g_slist_free (e->triangles); - e->triangles = NULL; - gts_object_destroy (GTS_OBJECT (e)); - - gts_allow_floating_vertices = FALSE; - - end = NULL; - i = v1->segments; - while (i) { - GtsSegment * s = i->data; - if (s->v1 == v1) - s->v1 = v; - else - s->v2 = v; - end = i; - i = i->next; - } - if (end) { - end->next = v->segments; - v->segments = v1->segments; - v1->segments = NULL; - } - - end = NULL; - i = v2->segments; - while (i) { - GtsSegment * s = i->data; - if (s->v1 == v2) - s->v1 = v; - else - s->v2 = v; - end = i; - i = i->next; - } - if (end) { - end->next = v->segments; - v->segments = v2->segments; - v2->segments = NULL; - } - -#ifdef DEBUG - if (invalid) { - char fname[80]; - FILE * fptr; - GSList * triangles, * i; - GtsSurface * surface = NULL; - - sprintf (fname, "invalid_after.%d", ninvalid); - fptr = fopen (fname, "wt"); - triangles = gts_vertex_triangles (v, NULL); - i = triangles; - while (i) { - GtsTriangle * t = i->data; - fprintf (stderr, "checking %p->%d\n", t, id (t)); - g_assert (GTS_IS_FACE (t)); - gts_write_triangle (t, GTS_POINT (v), fptr); - surface = GTS_FACE (t)->surfaces->data; - if (gts_triangle_is_duplicate (t)) - fprintf (stderr, "%p->%d is duplicate\n", t, id (t)); - if (gts_segment_is_duplicate (GTS_SEGMENT (t->e1))) - fprintf (stderr, "e1 of %p->%d is duplicate\n", t, id (t)); - if (gts_segment_is_duplicate (GTS_SEGMENT (t->e2))) - fprintf (stderr, "e2 of %p->%d is duplicate\n", t, id (t)); - if (gts_segment_is_duplicate (GTS_SEGMENT (t->e3))) - fprintf (stderr, "e3 of %p->%d is duplicate\n", t, id (t)); - i = i->next; - } - fclose (fptr); - g_slist_free (triangles); -#if 0 - gts_split_expand (vs, surface); - - sprintf (fname, "invalid_after_after.%d", ninvalid); - fptr = fopen (fname, "wt"); - triangles = gts_vertex_triangles (v1, NULL); - triangles = gts_vertex_triangles (v2, triangles); - i = triangles; - while (i) { - GtsTriangle * t = i->data; - gts_write_triangle (t, GTS_POINT (v), fptr); - surface = GTS_FACE (t)->surfaces->data; - if (gts_triangle_is_duplicate (t)) - fprintf (stderr, "%p->%d is duplicate\n", t, id (t)); - if (gts_segment_is_duplicate (GTS_SEGMENT (t->e1))) - fprintf (stderr, "e1 of %p->%d is duplicate\n", t, id (t)); - if (gts_segment_is_duplicate (GTS_SEGMENT (t->e2))) - fprintf (stderr, "e2 of %p->%d is duplicate\n", t, id (t)); - if (gts_segment_is_duplicate (GTS_SEGMENT (t->e3))) - fprintf (stderr, "e3 of %p->%d is duplicate\n", t, id (t)); - i = i->next; - } - fclose (fptr); - g_slist_free (triangles); - - exit (1); -#endif - ninvalid++; - } -#endif -} - -/** - * gts_split_expand: - * @vs: a #GtsSplit. - * @s: a #GtsSurface. - * @klass: a #GtsEdgeClass. - * - * Expands the vertex split @vs adding the newly created faces to @s. Any - * new edge will be of class @klass. - */ -void gts_split_expand (GtsSplit * vs, - GtsSurface * s, - GtsEdgeClass * klass) -{ - GSList * i; - GtsEdge * e; - GtsVertex * v, * v1, * v2; - gboolean changed = FALSE; - GtsSplitCFace * cf; - guint j; - - g_return_if_fail (vs != NULL); - g_return_if_fail (s != NULL); - g_return_if_fail (klass != NULL); - - /* we don't want to destroy vertices */ - gts_allow_floating_vertices = TRUE; - - v1 = GTS_SPLIT_V1 (vs); - v2 = GTS_SPLIT_V2 (vs); - v = vs->v; -#ifdef DEBUG_EXPAND - fprintf (stderr, "expanding %p->%d: v1: %p->%d v2: %p->%d v: %p->%d\n", - vs, id (vs), v1, id (v1), v2, id (v2), v, id (v)); -#endif - e = gts_edge_new (klass, v1, v2); - cf = vs->cfaces; - j = vs->ncf; - while (j--) { - cface_expand (CFACE (cf->f), cf->a1, cf->a2, e, v1, v2, v, klass); - gts_surface_add_face (s, cf->f); - cf++; - } - - gts_allow_floating_vertices = FALSE; - - /* this part is described by figure "expand.fig" */ - i = v->segments; - while (i) { - GtsEdge * e1 = i->data; - GtsVertex * with = NULL; - GSList * j = e1->triangles, * next = i->next; - // fprintf (stderr, "e1: %p->%d\n", e1, id (e1)); - while (j && !with) { - with = GTS_OBJECT (j->data)->reserved; - j = j->next; - } - if (with) { - j = e1->triangles; - while (j) { - GtsTriangle * t = j->data; - if (GTS_OBJECT (t)->reserved) { - g_assert (GTS_OBJECT (t)->reserved == with); - GTS_OBJECT (t)->reserved = NULL; - } - else - GTS_OBJECT (t)->reserved = with; - j = j->next; - } - if (GTS_SEGMENT (e1)->v1 == v) - GTS_SEGMENT (e1)->v1 = with; - else - GTS_SEGMENT (e1)->v2 = with; - - v->segments = g_slist_remove_link (v->segments, i); - i->next = with->segments; - with->segments = i; - changed = TRUE; - } - if (next) - i = next; - else { - /* check for infinite loop (the crossed out case in - figure "expand.fig") */ - g_assert (changed); - changed = FALSE; - i = v->segments; - } - } -} - -#ifndef DYNAMIC_SPLIT -static void cface_neighbors (GtsSplitCFace * cf, - GtsEdge * e, - GtsVertex * v1, - GtsVertex * v2) -{ - GtsTriangle * t = GTS_TRIANGLE (cf->f), ** a; - GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3; - GSList * i; - guint size; - - ROTATE_ORIENT (e, e1, e2, e3); - if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1), v2)) { - e3 = e1; e1 = e2; e2 = e3; - } - - i = e1->triangles; - size = g_slist_length (i)*sizeof (GtsTriangle *); - a = cf->a1 = g_malloc (size > 0 ? size : sizeof (GtsTriangle *)); - while (i) { - if (i->data != t) - *(a++) = i->data; - i = i->next; - } - *a = NULL; - - i = e2->triangles; - size = g_slist_length (i)*sizeof (GtsTriangle *); - a = cf->a2 = g_malloc (size > 0 ? size : sizeof (GtsTriangle *)); - while (i) { - if (i->data != t) - *(a++) = i->data; - i = i->next; - } - *a = NULL; -} -#endif /*ifndef DYNAMIC_SPLIT */ - -/** - * gts_split_new: - * @klass: a #GtsSplitClass. - * @v: a #GtsVertex. - * @o1: either a #GtsVertex or a #GtsSplit. - * @o2: either a #GtsVertex or a #GtsSplit. - * - * Creates a new #GtsSplit which would collapse @o1 and @o2 into @v. The - * collapse itself is not performed. - * - * Returns: the new #GtsSplit. - */ -GtsSplit * gts_split_new (GtsSplitClass * klass, - GtsVertex * v, - GtsObject * o1, - GtsObject * o2) -{ - GtsSplit * vs; -#ifndef DYNAMIC_SPLIT - GtsVertex * v1, * v2; - GtsEdge * e; - GSList * i; - GtsSplitCFace * cf; -#endif - - g_return_val_if_fail (klass != NULL, NULL); - g_return_val_if_fail (v != NULL, NULL); - g_return_val_if_fail (GTS_IS_SPLIT (o1) || GTS_IS_VERTEX (o1), NULL); - g_return_val_if_fail (GTS_IS_SPLIT (o2) || GTS_IS_VERTEX (o2), NULL); - - vs = GTS_SPLIT (gts_object_new (GTS_OBJECT_CLASS (klass))); - vs->v = v; - vs->v1 = o1; - vs->v2 = o2; -#ifdef DYNAMIC_SPLIT - vs->ncf = 0; - vs->cfaces = NULL; -#else - v1 = GTS_SPLIT_V1 (vs); - v2 = GTS_SPLIT_V2 (vs); - g_assert ((e = GTS_EDGE (gts_vertices_are_connected (v1, v2)))); - i = e->triangles; - vs->ncf = g_slist_length (i); - g_assert (vs->ncf > 0); - cf = vs->cfaces = g_malloc (vs->ncf*sizeof (GtsSplitCFace)); - while (i) { - cf->f = i->data; - cface_neighbors (cf, e, v1, v2); - i = i->next; - cf++; - } -#endif - - return vs; -} - -static gboolean -split_traverse_pre_order (GtsSplit * vs, - GtsSplitTraverseFunc func, - gpointer data) -{ - if (func (vs, data)) - return TRUE; - if (GTS_IS_SPLIT (vs->v1) && - split_traverse_pre_order (GTS_SPLIT (vs->v1), func, data)) - return TRUE; - if (GTS_IS_SPLIT (vs->v2) && - split_traverse_pre_order (GTS_SPLIT (vs->v2), func, data)) - return TRUE; - return FALSE; -} - -static gboolean -split_depth_traverse_pre_order (GtsSplit * vs, - guint depth, - GtsSplitTraverseFunc func, - gpointer data) -{ - if (func (vs, data)) - return TRUE; - - depth--; - if (!depth) - return FALSE; - - if (GTS_IS_SPLIT (vs->v1) && - split_depth_traverse_pre_order (GTS_SPLIT (vs->v1), depth, func, data)) - return TRUE; - if (GTS_IS_SPLIT (vs->v2) && - split_depth_traverse_pre_order (GTS_SPLIT (vs->v2), depth, func, data)) - return TRUE; - return FALSE; -} - -static gboolean -split_traverse_post_order (GtsSplit * vs, - GtsSplitTraverseFunc func, - gpointer data) -{ - if (GTS_IS_SPLIT (vs->v1) && - split_traverse_post_order (GTS_SPLIT (vs->v1), func, data)) - return TRUE; - if (GTS_IS_SPLIT (vs->v2) && - split_traverse_post_order (GTS_SPLIT (vs->v2), func, data)) - return TRUE; - if (func (vs, data)) - return TRUE; - return FALSE; -} - -static gboolean -split_depth_traverse_post_order (GtsSplit * vs, - guint depth, - GtsSplitTraverseFunc func, - gpointer data) -{ - depth--; - if (depth) { - if (GTS_IS_SPLIT (vs->v1) && - split_depth_traverse_post_order (GTS_SPLIT (vs->v1), - depth, func, data)) - return TRUE; - if (GTS_IS_SPLIT (vs->v2) && - split_depth_traverse_post_order (GTS_SPLIT (vs->v2), - depth, func, data)) - return TRUE; - } - if (func (vs, data)) - return TRUE; - return FALSE; -} - -/** - * gts_split_traverse: - * @root: the #GtsSplit to start the traversal from. - * @order: the order in which nodes are visited - G_PRE_ORDER or G_POST_ORDER. - * @depth: the maximum depth of the traversal. Nodes below this depth - * will not be visited. If depth is -1 all nodes in the tree are - * visited. If depth is 1, only the root is visited. If depth is 2, - * the root and its children are visited. And so on. - * @func: the function to call for each visited #GtsHSplit. - * @data: user data to pass to the function. - * - * Traverses the #GtsSplit tree having @root as root. Calls @func for each - * #GtsSplit of the tree in the order specified by @order. If order is set - * to G_PRE_ORDER @func is called for the #GtsSplit then its children, if order - * is set to G_POST_ORDER @func is called for the children and then for the - * #GtsSplit. - */ -void gts_split_traverse (GtsSplit * root, - GTraverseType order, - gint depth, - GtsSplitTraverseFunc func, - gpointer data) -{ - g_return_if_fail (root != NULL); - g_return_if_fail (func != NULL); - g_return_if_fail (order < G_LEVEL_ORDER); - g_return_if_fail (depth == -1 || depth > 0); - - switch (order) { - case G_PRE_ORDER: - if (depth < 0) - split_traverse_pre_order (root, func, data); - else - split_depth_traverse_pre_order (root, depth, func, data); - break; - case G_POST_ORDER: - if (depth < 0) - split_traverse_post_order (root, func, data); - else - split_depth_traverse_post_order (root, depth, func, data); - break; - default: - g_assert_not_reached (); - } -} - -/** - * gts_split_height: - * @root: a #GtsSplit. - * - * Returns: the maximum height of the vertex split tree having @root as root. - */ -guint gts_split_height (GtsSplit * root) -{ - guint height = 0, tmp_height; - - g_return_val_if_fail (root != NULL, 0); - - if (GTS_IS_SPLIT (root->v1)) { - tmp_height = gts_split_height (GTS_SPLIT (root->v1)); - if (tmp_height > height) - height = tmp_height; - } - if (GTS_IS_SPLIT (root->v2)) { - tmp_height = gts_split_height (GTS_SPLIT (root->v2)); - if (tmp_height > height) - height = tmp_height; - } - - return height + 1; -} - -#ifndef DYNAMIC_SPLIT -static gboolean list_array_are_identical (GSList * list, - gpointer * array, - gpointer excluded) -{ - while (list) { - gpointer data = list->data; - if (data != excluded) { - gboolean found = FALSE; - gpointer * a = array; - - while (!found && *a) - if (*(a++) == data) - found = TRUE; - if (!found) - return FALSE; - } - list = list->next; - } - return TRUE; -} -#endif /* ifndef DYNAMIC_SPLIT */ - -#ifndef NEW -gboolean gts_split_is_collapsable (GtsSplit * vs) -{ - guint i; - GtsSplitCFace * cf; - GtsVertex * v1, * v2; - GtsEdge * e; - - g_return_val_if_fail (vs != NULL, FALSE); - - v1 = GTS_SPLIT_V1 (vs); - v2 = GTS_SPLIT_V2 (vs); - g_return_val_if_fail ((e = GTS_EDGE (gts_vertices_are_connected (v1, v2))), - FALSE); - -#ifdef DYNAMIC_SPLIT - if (!gts_edge_collapse_is_valid (e)) - return FALSE; -#else - i = vs->ncf; - cf = vs->cfaces; - while (i--) { - GtsTriangle * t = GTS_TRIANGLE (cf->f); - GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3; - - ROTATE_ORIENT (e, e1, e2, e3); - if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1), v2)) { - e3 = e1; e1 = e2; e2 = e3; - } - - if (!list_array_are_identical (e1->triangles, (gpointer *) cf->a1, t)) - return FALSE; - if (!list_array_are_identical (e2->triangles, (gpointer *) cf->a2, t)) - return FALSE; - - cf++; - } -#endif - return TRUE; -} -#endif /* not NEW */ - -#ifdef DEBUG_HEXPAND -static guint expand_level = 0; - -static void expand_indent (FILE * fptr) -{ - guint i = expand_level; - while (i--) - fputc (' ', fptr); -} -#endif - -/** - * gts_hsplit_force_expand: - * @hs: a #GtsHSplit. - * @hsurface: a #GtsHSurface. - * - * Forces the expansion of @hs by first expanding all its dependencies not - * already expanded. - */ -void gts_hsplit_force_expand (GtsHSplit * hs, - GtsHSurface * hsurface) -{ - guint i; - GtsSplitCFace * cf; - - g_return_if_fail (hs != NULL); - g_return_if_fail (hsurface != NULL); - g_return_if_fail (hs->nchild == 0); - -#ifdef DEBUG_HEXPAND - expand_level += 2; -#endif - - if (hs->parent && hs->parent->nchild == 0) { -#ifdef DEBUG_HEXPAND - expand_indent (stderr); - fprintf (stderr, "expand parent %p\n", hs->parent); -#endif - gts_hsplit_force_expand (hs->parent, hsurface); - } - - i = GTS_SPLIT (hs)->ncf; - cf = GTS_SPLIT (hs)->cfaces; - while (i--) { - GtsTriangle ** j, * t; - - j = cf->a1; - while ((t = *(j++))) - if (IS_CFACE (t)) { -#ifdef DEBUG_HEXPAND - expand_indent (stderr); - fprintf (stderr, "expand a1: cf->f: %p t: %p parent_split: %p\n", - cf->f, - t, - GTS_HSPLIT (CFACE (t)->parent_split)); -#endif - gts_hsplit_force_expand (GTS_HSPLIT (CFACE (t)->parent_split), - hsurface); -#ifdef DEBUG_HEXPAND - g_assert (!IS_CFACE (t)); -#endif - } - j = cf->a2; - while ((t = *(j++))) - if (IS_CFACE (t)) { -#ifdef DEBUG_HEXPAND - expand_indent (stderr); - fprintf (stderr, "expand a2: cf->f: %p t: %p parent_split: %p\n", - cf->f, - t, - GTS_HSPLIT (CFACE (t)->parent_split)); -#endif - gts_hsplit_force_expand (GTS_HSPLIT (CFACE (t)->parent_split), - hsurface); - } - cf++; - } - - gts_hsplit_expand (hs, hsurface); - -#ifdef DEBUG_HEXPAND - expand_level -= 2; - expand_indent (stderr); - fprintf (stderr, "%p expanded\n", hs); -#endif -} - -static void index_object (GtsObject * o, guint * n) -{ - o->reserved = GUINT_TO_POINTER ((*n)++); -} - -static void index_face (GtsFace * f, gpointer * data) -{ - guint * nf = data[1]; - - g_hash_table_insert (data[0], f, GUINT_TO_POINTER ((*nf)++)); -} - -/** - * gts_psurface_write: - * @ps: a #GtsPSurface. - * @fptr: a file pointer. - * - * Writes to @fptr a GTS progressive surface description. - */ -void gts_psurface_write (GtsPSurface * ps, FILE * fptr) -{ - guint nv = 1; - guint nf = 1; - GHashTable * hash; - gpointer data[2]; - - g_return_if_fail (ps != NULL); - g_return_if_fail (fptr != NULL); - g_return_if_fail (GTS_PSURFACE_IS_CLOSED (ps)); - - while (gts_psurface_remove_vertex (ps)) - ; - - GTS_POINT_CLASS (ps->s->vertex_class)->binary = FALSE; - gts_surface_write (ps->s, fptr); - - gts_surface_foreach_vertex (ps->s, (GtsFunc) index_object, &nv); - hash = g_hash_table_new (NULL, NULL); - data[0] = hash; - data[1] = &nf; - gts_surface_foreach_face (ps->s, (GtsFunc) index_face, data); - - fprintf (fptr, "%u\n", ps->split->len); - while (ps->pos) { - GtsSplit * vs = g_ptr_array_index (ps->split, --ps->pos); - GtsSplitCFace * scf = vs->cfaces; - GtsVertex * v1, * v2; - guint i = vs->ncf; - - fprintf (fptr, "%u %u", - GPOINTER_TO_UINT (GTS_OBJECT (vs->v)->reserved), - vs->ncf); - if (GTS_OBJECT (vs)->klass->write) - (*GTS_OBJECT (vs)->klass->write) (GTS_OBJECT (vs), fptr); - fputc ('\n', fptr); - - v1 = GTS_IS_SPLIT (vs->v1) ? GTS_SPLIT (vs->v1)->v : GTS_VERTEX (vs->v1); - GTS_OBJECT (v1)->reserved = GUINT_TO_POINTER (nv++); - v2 = GTS_IS_SPLIT (vs->v2) ? GTS_SPLIT (vs->v2)->v : GTS_VERTEX (vs->v2); - GTS_OBJECT (v2)->reserved = GUINT_TO_POINTER (nv++); - - (*GTS_OBJECT (v1)->klass->write) (GTS_OBJECT (v1), fptr); - fputc ('\n', fptr); - - (*GTS_OBJECT (v2)->klass->write) (GTS_OBJECT (v2), fptr); - fputc ('\n', fptr); - - while (i--) { - CFace * cf = CFACE (scf->f); - GtsTriangle ** a, * t; - - fprintf (fptr, "%u %u", - GPOINTER_TO_UINT (g_hash_table_lookup (hash, cf->t)), - cf->flags); - if (GTS_OBJECT_CLASS (ps->s->face_class)->write) - (*GTS_OBJECT_CLASS (ps->s->face_class)->write) (GTS_OBJECT (cf), fptr); - fputc ('\n', fptr); - - a = scf->a1; - while ((t = *(a++))) - fprintf (fptr, "%u ", - GPOINTER_TO_UINT (g_hash_table_lookup (hash, t))); - fprintf (fptr, "\n"); - - a = scf->a2; - while ((t = *(a++))) - fprintf (fptr, "%u ", - GPOINTER_TO_UINT (g_hash_table_lookup (hash, t))); - fprintf (fptr, "\n"); - - g_hash_table_insert (hash, cf, GUINT_TO_POINTER (nf++)); - - scf++; - } - - gts_split_expand (vs, ps->s, ps->s->edge_class); - } - - gts_surface_foreach_vertex (ps->s, - (GtsFunc) gts_object_reset_reserved, NULL); - g_hash_table_destroy (hash); -} - -static guint surface_read (GtsSurface * surface, - GtsFile * f, - GPtrArray * vertices, - GPtrArray * faces) -{ - GtsEdge ** edges; - guint n, nv, ne, nf; - - g_return_val_if_fail (surface != NULL, 1); - g_return_val_if_fail (f != NULL, 1); - - if (f->type != GTS_INT) { - gts_file_error (f, "expecting an integer (number of vertices)"); - return f->line; - } - nv = atoi (f->token->str); - - gts_file_next_token (f); - if (f->type != GTS_INT) { - gts_file_error (f, "expecting an integer (number of edges)"); - return f->line; - } - ne = atoi (f->token->str); - - gts_file_next_token (f); - if (f->type != GTS_INT) { - gts_file_error (f, "expecting an integer (number of faces)"); - return f->line; - } - nf = atoi (f->token->str); - - gts_file_next_token (f); - if (f->type == GTS_STRING) { - if (f->type != GTS_STRING) { - gts_file_error (f, "expecting a string (GtsSurfaceClass)"); - return f->line; - } - gts_file_next_token (f); - if (f->type != GTS_STRING) { - gts_file_error (f, "expecting a string (GtsFaceClass)"); - return f->line; - } - gts_file_next_token (f); - if (f->type != GTS_STRING) { - gts_file_error (f, "expecting a string (GtsEdgeClass)"); - return f->line; - } - gts_file_next_token (f); - if (f->type != GTS_STRING) { - gts_file_error (f, "expecting a string (GtsVertexClass)"); - return f->line; - } - if (!strcmp (f->token->str, "GtsVertexBinary")) - GTS_POINT_CLASS (surface->vertex_class)->binary = TRUE; - else - gts_file_first_token_after (f, '\n'); - } - else - gts_file_first_token_after (f, '\n'); - - g_ptr_array_set_size (vertices, nv); - g_ptr_array_set_size (faces, nf); - /* allocate nv + 1 just in case nv == 0 */ - edges = g_malloc ((ne + 1)*sizeof (GtsEdge *)); - - n = 0; - while (n < nv && f->type != GTS_ERROR) { - GtsObject * new_vertex = - gts_object_new (GTS_OBJECT_CLASS (surface->vertex_class)); - - (* GTS_OBJECT_CLASS (surface->vertex_class)->read) (&new_vertex, f); - if (f->type != GTS_ERROR) { - if (!GTS_POINT_CLASS (surface->vertex_class)->binary) - gts_file_first_token_after (f, '\n'); - g_ptr_array_index (vertices, n++) = new_vertex; - } - else - gts_object_destroy (new_vertex); - } - if (f->type == GTS_ERROR) - nv = n; - if (GTS_POINT_CLASS (surface->vertex_class)->binary) - gts_file_first_token_after (f, '\n'); - - n = 0; - while (n < ne && f->type != GTS_ERROR) { - guint p1, p2; - - if (f->type != GTS_INT) - gts_file_error (f, "expecting an integer (first vertex index)"); - else { - p1 = atoi (f->token->str); - if (p1 == 0 || p1 > nv) - gts_file_error (f, "vertex index `%d' is out of range `[1,%d]'", - p1, nv); - else { - gts_file_next_token (f); - if (f->type != GTS_INT) - gts_file_error (f, "expecting an integer (second vertex index)"); - else { - p2 = atoi (f->token->str); - if (p2 == 0 || p2 > nv) - gts_file_error (f, "vertex index `%d' is out of range `[1,%d]'", - p2, nv); - else { - GtsEdge * new_edge = - gts_edge_new (surface->edge_class, - g_ptr_array_index (vertices, p1 - 1), - g_ptr_array_index (vertices, p2 - 1)); - - gts_file_next_token (f); - if (f->type != '\n') - if (GTS_OBJECT_CLASS (surface->edge_class)->read) - (*GTS_OBJECT_CLASS (surface->edge_class)->read) - ((GtsObject **) &new_edge, f); - gts_file_first_token_after (f, '\n'); - edges[n++] = new_edge; - } - } - } - } - } - if (f->type == GTS_ERROR) - ne = n; - - n = 0; - while (n < nf && f->type != GTS_ERROR) { - guint s1, s2, s3; - - if (f->type != GTS_INT) - gts_file_error (f, "expecting an integer (first edge index)"); - else { - s1 = atoi (f->token->str); - if (s1 == 0 || s1 > ne) - gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", - s1, ne); - else { - gts_file_next_token (f); - if (f->type != GTS_INT) - gts_file_error (f, "expecting an integer (second edge index)"); - else { - s2 = atoi (f->token->str); - if (s2 == 0 || s2 > ne) - gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", - s2, ne); - else { - gts_file_next_token (f); - if (f->type != GTS_INT) - gts_file_error (f, "expecting an integer (third edge index)"); - else { - s3 = atoi (f->token->str); - if (s3 == 0 || s3 > ne) - gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", - s3, ne); - else { - GtsFace * new_face = gts_face_new (surface->face_class, - edges[s1 - 1], - edges[s2 - 1], - edges[s3 - 1]); - - gts_file_next_token (f); - if (f->type != '\n') - if (GTS_OBJECT_CLASS (surface->face_class)->read) - (*GTS_OBJECT_CLASS (surface->face_class)->read) - ((GtsObject **) &new_face, f); - gts_file_first_token_after (f, '\n'); - gts_surface_add_face (surface, new_face); - g_ptr_array_index (faces, n++) = new_face; - } - } - } - } - } - } - } - - g_free (edges); - - if (f->type == GTS_ERROR) { - gts_allow_floating_vertices = TRUE; - while (nv) - gts_object_destroy (GTS_OBJECT (g_ptr_array_index (vertices, nv-- - 1))); - gts_allow_floating_vertices = FALSE; - return f->line; - } - - return 0; -} - -/** - * gts_psurface_open: - * @klass: a #GtsPSurfaceClass. - * @s: a #GtsSurface. - * @split_class: a #GtsSplitClass to use for the #GtsSplit. - * @f: a #GtsFile. - * - * Creates a new #GtsPSurface prepared for input from the file @f - * containing a valid GTS representation of a progressive surface. The initial - * shape of the progressive surface is loaded into @s. - * - * Before being usable as such this progressive surface must be closed using - * gts_psurface_close(). While open however, the functions - * gts_psurface_get_vertex_number(), gts_psurface_min_vertex_number() and - * gts_psurface_max_vertex_number() can still be used. - * - * Returns: a new #GtsPSurface or %NULL if there was a format error while - * reading the file, in which case @f contains information about the error. - */ -GtsPSurface * gts_psurface_open (GtsPSurfaceClass * klass, - GtsSurface * s, - GtsSplitClass * split_class, - GtsFile * f) -{ - GtsPSurface * ps; - - g_return_val_if_fail (klass != NULL, NULL); - g_return_val_if_fail (s != NULL, NULL); - g_return_val_if_fail (split_class != NULL, NULL); - g_return_val_if_fail (f != NULL, NULL); - - ps = GTS_PSURFACE (gts_object_new (GTS_OBJECT_CLASS (klass))); - ps->s = s; - ps->split_class = split_class; - - ps->vertices = g_ptr_array_new (); - ps->faces = g_ptr_array_new (); - - if (surface_read (s, f, ps->vertices, ps->faces)) { - ps->s = NULL; - gts_object_destroy (GTS_OBJECT (ps)); - return NULL; - } - - ps->min = gts_surface_vertex_number (ps->s); - ps->pos = 0; - - if (f->type == GTS_INT) { - gint ns = atoi (f->token->str); - - if (ns > 0) { - g_ptr_array_set_size (ps->split, ns); - gts_file_first_token_after (f, '\n'); - } - } - - return ps; -} - -/** - * gts_psurface_read_vertex: - * @ps: a #GtsPSurface prealably created with gts_psurface_open(). - * @fp: a #GtsFile. - * - * Reads in one vertex split operation from @fp and performs the expansion. - * - * If an error occurs while reading the file, the @error field of @fp is set. - * - * Returns: the newly created #GtsSplit or %NULL if no vertex split could be - * read from @fp. - */ -GtsSplit * gts_psurface_read_vertex (GtsPSurface * ps, GtsFile * fp) -{ - guint nv, ncf; - GtsSplit * vs, * parent; - GtsSplitCFace * scf; - - g_return_val_if_fail (ps != NULL, NULL); - g_return_val_if_fail (fp != NULL, NULL); - g_return_val_if_fail (!GTS_PSURFACE_IS_CLOSED (ps), NULL); - - if (ps->pos >= ps->split->len) - return NULL; - - if (fp->type == GTS_NONE) - return NULL; - if (fp->type != GTS_INT) { - gts_file_error (fp, "expecting an integer (vertex index)"); - return NULL; - } - nv = atoi (fp->token->str); - if (nv == 0 || nv > ps->vertices->len) { - gts_file_error (fp, "vertex index `%d' is out of range `[1,%d]'", - nv, ps->vertices->len); - return NULL; - } - - gts_file_next_token (fp); - if (fp->type != GTS_INT) { - gts_file_error (fp, "expecting an integer (ncf)"); - return NULL; - } - ncf = atoi (fp->token->str); - - vs = GTS_SPLIT (gts_object_new (GTS_OBJECT_CLASS (ps->split_class))); - - vs->v = g_ptr_array_index (ps->vertices, nv - 1); - vs->v1 = vs->v2 = NULL; - vs->cfaces = NULL; - vs->ncf = 0; - - gts_file_next_token (fp); - if (fp->type != '\n') - if (GTS_OBJECT (vs)->klass->read) - (* GTS_OBJECT (vs)->klass->read) ((GtsObject **) &vs, fp); - gts_file_first_token_after (fp, '\n'); - - if (fp->type != GTS_ERROR) { - vs->v1 = gts_object_new (GTS_OBJECT_CLASS (ps->s->vertex_class)); - (* GTS_OBJECT_CLASS (ps->s->vertex_class)->read) (&(vs->v1), fp); - if (fp->type != GTS_ERROR) { - vs->v1->reserved = vs; - g_ptr_array_add (ps->vertices, vs->v1); - - gts_file_first_token_after (fp, '\n'); - - vs->v2 = gts_object_new (GTS_OBJECT_CLASS (ps->s->vertex_class)); - (*GTS_OBJECT_CLASS (ps->s->vertex_class)->read) (&(vs->v2), fp); - if (fp->type != GTS_ERROR) { - vs->v2->reserved = vs; - g_ptr_array_add (ps->vertices, vs->v2); - gts_file_first_token_after (fp, '\n'); - } - } - } - - if (fp->type != GTS_ERROR) { - scf = vs->cfaces = g_malloc (sizeof (GtsSplitCFace)*ncf); - while (fp->type != GTS_ERROR && ncf--) { - guint it, flags; - GtsFace * f; - CFace * cf; - GPtrArray * a; - - if (fp->type != GTS_INT) - gts_file_error (fp, "expecting an integer (face index)"); - else { - it = atoi (fp->token->str); - if (it == 0 || it > ps->faces->len) - gts_file_error (fp, "face index `%d' is out of range `[1,%d]'", - it, ps->faces->len); - else { - gts_file_next_token (fp); - if (fp->type != GTS_INT) - gts_file_error (fp, "expecting an integer (flags)"); - else { - flags = atoi (fp->token->str); - f = - GTS_FACE (gts_object_new (GTS_OBJECT_CLASS (ps->s->face_class))); - - gts_file_next_token (fp); - if (fp->type != '\n') - if (GTS_OBJECT (f)->klass->read) - (*GTS_OBJECT (f)->klass->read) ((GtsObject **) &f, fp); - gts_file_first_token_after (fp, '\n'); - if (fp->type != GTS_ERROR) { - scf->f = f; - - cf = (CFace *) f; - GTS_OBJECT (cf)->klass = GTS_OBJECT_CLASS (cface_class ()); - cf->parent_split = vs; - cf->t = g_ptr_array_index (ps->faces, it - 1); - cf->flags = flags; - - a = g_ptr_array_new (); - do { - if (fp->type != GTS_INT) - gts_file_error (fp, "expecting an integer (face index)"); - else { - it = atoi (fp->token->str); - if (it > ps->faces->len) - gts_file_error (fp, - "face index `%d' is out of range `[1,%d]'", - it, ps->faces->len); - else { - g_ptr_array_add (a, g_ptr_array_index (ps->faces, - it - 1)); - gts_file_next_token (fp); - } - } - } while (fp->type != GTS_ERROR && fp->type != '\n'); - gts_file_first_token_after (fp, '\n'); - g_ptr_array_add (a, NULL); - scf->a1 = (GtsTriangle **) a->pdata; - g_ptr_array_free (a, FALSE); - - if (fp->type != GTS_ERROR) { - a = g_ptr_array_new (); - do { - if (fp->type != GTS_INT) - gts_file_error (fp, "expecting an integer (face index)"); - else { - it = atoi (fp->token->str); - if (it > ps->faces->len) - gts_file_error (fp, - "face index `%d' is out of range `[1,%d]'", - it, ps->faces->len); - else { - g_ptr_array_add (a, g_ptr_array_index (ps->faces, - it - 1)); - gts_file_next_token (fp); - } - } - } while (fp->type != GTS_ERROR && fp->type != '\n'); - gts_file_first_token_after (fp, '\n'); - g_ptr_array_add (a, NULL); - scf->a2 = (GtsTriangle **) a->pdata; - g_ptr_array_free (a, FALSE); - - g_ptr_array_add (ps->faces, f); - - vs->ncf++; - scf++; - } - } - } - } - } - } - } - - if (fp->type != GTS_ERROR) { - if ((parent = GTS_OBJECT (vs->v)->reserved)) { - GTS_OBJECT (vs->v)->reserved = NULL; - if (parent->v1 == GTS_OBJECT (vs->v)) - parent->v1 = GTS_OBJECT (vs); - else { - g_assert (parent->v2 == GTS_OBJECT (vs->v)); - parent->v2 = GTS_OBJECT (vs); - } - } - g_ptr_array_index (ps->split, ps->pos++) = vs; - gts_split_expand (vs, ps->s, ps->s->edge_class); - - return vs; - } - - if (vs->v1) gts_object_destroy (vs->v1); - if (vs->v2) gts_object_destroy (vs->v2); - gts_object_destroy (GTS_OBJECT (vs)); - - return NULL; -} - -/** - * gts_psurface_close: - * @ps: a #GtsPSurface prealably created with gts_psurface_open(). - * - * Closes a progressive surface. - */ -void gts_psurface_close (GtsPSurface * ps) -{ - g_return_if_fail (ps != NULL); - g_return_if_fail (!GTS_PSURFACE_IS_CLOSED (ps)); - - g_ptr_array_free (ps->vertices, TRUE); - g_ptr_array_free (ps->faces, TRUE); - ps->faces = ps->vertices = NULL; - - gts_surface_foreach_vertex (ps->s, - (GtsFunc) gts_object_reset_reserved, NULL); - if (ps->pos > 0) - g_ptr_array_set_size (ps->split, ps->pos); - if (ps->split->len > 1) { - guint i, half = ps->split->len/2, n = ps->split->len - 1; - - for (i = 0; i < half; i++) { - gpointer p1 = g_ptr_array_index (ps->split, i); - gpointer p2 = g_ptr_array_index (ps->split, n - i); - g_ptr_array_index (ps->split, n - i) = p1; - g_ptr_array_index (ps->split, i) = p2; - } - } - ps->pos = 0; -} Index: trunk/src_3rd/gts/hsurface.c =================================================================== --- trunk/src_3rd/gts/hsurface.c (revision 6802) +++ trunk/src_3rd/gts/hsurface.c (nonexistent) @@ -1,405 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include -#include "gts.h" - -#define HEAP_INSERT_HSPLIT(h, e) ((e)->index = gts_eheap_insert (h, e)) -#define HEAP_REMOVE_HSPLIT(h, e) (gts_eheap_remove (h, (e)->index),\ - (e)->index = NULL) - -static void hsplit_init (GtsHSplit * hsplit) -{ - hsplit->index = NULL; - hsplit->parent = NULL; - hsplit->nchild = 0; -} - -/** - * gts_hsplit_class: - * - * Returns: the #GtsHSplitClass. - */ -GtsHSplitClass * gts_hsplit_class (void) -{ - static GtsHSplitClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo hsplit_info = { - "GtsHSplit", - sizeof (GtsHSplit), - sizeof (GtsHSplitClass), - (GtsObjectClassInitFunc) NULL, - (GtsObjectInitFunc) hsplit_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_split_class ()), - &hsplit_info); - } - - return klass; -} - -/** - * gts_hsplit_new: - * @klass: a #GtsHSplitClass. - * @vs: a #GtsSplit. - * - * Returns: a new #GtsHSplit, hierarchical extension of @vs. - */ -GtsHSplit * gts_hsplit_new (GtsHSplitClass * klass, GtsSplit * vs) -{ - GtsHSplit * hs; - - g_return_val_if_fail (vs != NULL, NULL); - - hs = GTS_HSPLIT (gts_object_new (GTS_OBJECT_CLASS (klass))); - memcpy (hs, vs, sizeof (GtsSplit)); - GTS_OBJECT (hs)->reserved = NULL; - - return hs; -} - -/** - * gts_hsplit_collapse: - * @hs: a #GtsHSplit. - * @hsurface: a #GtsHSurface. - * - * Collapses the #GtsSplit defined by @hs, updates the expandable and - * collapsable priority heaps of @hsurface. - */ -void gts_hsplit_collapse (GtsHSplit * hs, - GtsHSurface * hsurface) -{ - GtsHSplit * parent; - GtsSplit * vs; - - g_return_if_fail (hs != NULL); - g_return_if_fail (hs->nchild == 2); - g_return_if_fail (hsurface != NULL); - - gts_split_collapse (GTS_SPLIT (hs), hsurface->s->edge_class, NULL); - - hsurface->nvertex--; - hs->nchild = 0; - HEAP_REMOVE_HSPLIT (hsurface->collapsable, hs); - HEAP_INSERT_HSPLIT (hsurface->expandable, hs); - - vs = GTS_SPLIT (hs); - if (GTS_IS_HSPLIT (vs->v1)) - HEAP_REMOVE_HSPLIT (hsurface->expandable, GTS_HSPLIT (vs->v1)); - if (GTS_IS_HSPLIT (vs->v2)) - HEAP_REMOVE_HSPLIT (hsurface->expandable, GTS_HSPLIT (vs->v2)); - - parent = hs->parent; - if (parent && ++parent->nchild == 2) - HEAP_INSERT_HSPLIT (hsurface->collapsable, parent); -} - -/** - * gts_hsplit_expand: - * @hs: a #GtsHSplit. - * @hsurface: a #GtsHSurface. - * - * Expands the #GtsSplit defined by @hs (which must be expandable) - * and updates the priority heaps of @hsurface. - */ -void gts_hsplit_expand (GtsHSplit * hs, - GtsHSurface * hsurface) -{ - GtsHSplit * parent; - GtsSplit * vs; - - g_return_if_fail (hs != NULL); - g_return_if_fail (hsurface != NULL); - g_return_if_fail (hs->nchild == 0); - - gts_split_expand (GTS_SPLIT (hs), hsurface->s, hsurface->s->edge_class); - hsurface->nvertex++; - hs->nchild = 2; - HEAP_REMOVE_HSPLIT (hsurface->expandable, hs); - HEAP_INSERT_HSPLIT (hsurface->collapsable, hs); - - vs = GTS_SPLIT (hs); - if (GTS_IS_HSPLIT (vs->v1)) - HEAP_INSERT_HSPLIT (hsurface->expandable, GTS_HSPLIT (vs->v1)); - if (GTS_IS_HSPLIT (vs->v2)) - HEAP_INSERT_HSPLIT (hsurface->expandable, GTS_HSPLIT (vs->v2)); - - parent = hs->parent; - if (parent && parent->nchild-- == 2) - HEAP_REMOVE_HSPLIT (hsurface->collapsable, parent); -} - -static void hsurface_destroy (GtsObject * object) -{ - GtsHSurface * hs = GTS_HSURFACE (object); - - gts_hsurface_traverse (hs, G_POST_ORDER, -1, - (GtsSplitTraverseFunc) gts_object_destroy, - NULL); - g_slist_free (hs->roots); - if (hs->expandable) - gts_eheap_destroy (hs->expandable); - if (hs->collapsable) - gts_eheap_destroy (hs->collapsable); - g_ptr_array_free (hs->split, TRUE); - - (* GTS_OBJECT_CLASS (gts_hsurface_class ())->parent_class->destroy) (object); -} - -static void hsurface_class_init (GtsObjectClass * klass) -{ - klass->destroy = hsurface_destroy; -} - -static void hsurface_init (GtsHSurface * hsurface) -{ - hsurface->s = NULL; - hsurface->roots = NULL; - hsurface->expandable = hsurface->collapsable = NULL; - hsurface->split = g_ptr_array_new (); - hsurface->nvertex = 0; -} - -/** - * gts_hsurface_class: - * - * Returns: the #GtsHSurfaceClass. - */ -GtsHSurfaceClass * gts_hsurface_class (void) -{ - static GtsHSurfaceClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo hsurface_info = { - "GtsHSurface", - sizeof (GtsHSurface), - sizeof (GtsHSurfaceClass), - (GtsObjectClassInitFunc) hsurface_class_init, - (GtsObjectInitFunc) hsurface_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (gts_object_class (), - &hsurface_info); - } - - return klass; -} - -/** - * gts_hsurface_new: - * @klass: a #GtsHSurfaceClass. - * @hsplit_class: a #GtsHSplitClass. - * @psurface: a #GtsPSurface. - * @expand_key: a #GtsKeyFunc used to order the priority heap of expandable - * #GtsHSplit. - * @expand_data: data to be passed to @expand_key. - * @collapse_key: a #GtsKeyFunc used to order the priority heap of collapsable - * #GtsHSplit. - * @collapse_data: data to be passed to @collapsed_key. - * - * Returns: a new #GtsHSurface, hierarchical extension of @psurface - * and using #GtsHSplit of class @hsplit_class. Note that @psurface is - * destroyed in the process. - */ -GtsHSurface * gts_hsurface_new (GtsHSurfaceClass * klass, - GtsHSplitClass * hsplit_class, - GtsPSurface * psurface, - GtsKeyFunc expand_key, - gpointer expand_data, - GtsKeyFunc collapse_key, - gpointer collapse_data) -{ - GtsHSurface * hsurface; - - g_return_val_if_fail (klass != NULL, NULL); - g_return_val_if_fail (hsplit_class != NULL, NULL); - g_return_val_if_fail (psurface != NULL, NULL); - g_return_val_if_fail (expand_key != NULL, NULL); - g_return_val_if_fail (collapse_key != NULL, NULL); - - hsurface = GTS_HSURFACE (gts_object_new (GTS_OBJECT_CLASS (klass))); - hsurface->s = psurface->s; - hsurface->expandable = gts_eheap_new (expand_key, expand_data); - hsurface->collapsable = gts_eheap_new (collapse_key, collapse_data); - g_ptr_array_set_size (hsurface->split, psurface->split->len); - - while (gts_psurface_remove_vertex (psurface)) - ; - while (psurface->pos) { - GtsSplit * vs = g_ptr_array_index (psurface->split, psurface->pos - 1); - GtsHSplit * hs = gts_hsplit_new (hsplit_class, vs); - - g_ptr_array_index (hsurface->split, psurface->pos - 1) = hs; - psurface->pos--; - - hs->parent = GTS_OBJECT (vs)->reserved; - if (hs->parent) { - GtsSplit * vsp = GTS_SPLIT (hs->parent); - - if (vsp->v1 == GTS_OBJECT (vs)) { - g_assert (vsp->v2 != GTS_OBJECT (vs)); - vsp->v1 = GTS_OBJECT (hs); - } - else { - g_assert (vsp->v2 == GTS_OBJECT (vs)); - vsp->v2 = GTS_OBJECT (hs); - } - } - else - hsurface->roots = g_slist_prepend (hsurface->roots, hs); - - hs->nchild = 0; - if (GTS_IS_SPLIT (vs->v1)) - GTS_OBJECT (vs->v1)->reserved = hs; - else - hs->nchild++; - if (GTS_IS_SPLIT (vs->v2)) - GTS_OBJECT (vs->v2)->reserved = hs; - else - hs->nchild++; - - gts_split_expand (vs, psurface->s, psurface->s->edge_class); - - if (hs->nchild == 2) - HEAP_INSERT_HSPLIT (hsurface->collapsable, hs); - } - - hsurface->nvertex = gts_surface_vertex_number (hsurface->s); - gts_object_destroy (GTS_OBJECT (psurface)); - - return hsurface; -} - -/** - * gts_hsurface_traverse: - * @hsurface: a #GtsHSurface. - * @order: the order in which nodes are visited - G_PRE_ORDER or G_POST_ORDER. - * @depth: the maximum depth of the traversal. Nodes below this depth - * will not be visited. If max_depth is -1 all nodes in the tree are - * visited. If depth is 1, only the root is visited. If depth is 2, - * the root and its children are visited. And so on. - * @func: the function to call for each visited #GtsHSplit. - * @data: user data to pass to the function. - * - * Traverses a hierarchical surface starting from its roots. It calls - * the given function for each #GtsHSplit visited. - * See also gts_split_traverse(). - */ -void gts_hsurface_traverse (GtsHSurface * hsurface, - GTraverseType order, - gint depth, - GtsSplitTraverseFunc func, - gpointer data) -{ - GSList * i; - - g_return_if_fail (hsurface != NULL); - g_return_if_fail (func != NULL); - g_return_if_fail (order < G_LEVEL_ORDER); - g_return_if_fail (depth == -1 || depth > 0); - - i = hsurface->roots; - while (i) { - gts_split_traverse (i->data, order, depth, func, data); - i = i->next; - } -} - -/** - * gts_hsurface_foreach: - * @hsurface: a #GtsHSurface. - * @order: the order in which #GtsHSplit are visited - G_PRE_ORDER or - * G_POST_ORDER. - * @func: the function to call for each visited #GtsHSplit. - * @data: user data to pass to the function. - * - * Starts by expanding all the #GtsHSplit of @hsurface. If @order is - * G_PRE_ORDER, calls @func for each #GtsHSplit and collapses it. If - * order is G_POST_ORDER, collapses each #GtsHSplit first and then - * calls @func. The traversal can be halted at any point by returning - * TRUE from func. - */ -void gts_hsurface_foreach (GtsHSurface * hsurface, - GTraverseType order, - GtsFunc func, - gpointer data) -{ - GtsHSplit * hs; - guint i = 0, len; - gboolean stop = FALSE; - - g_return_if_fail (hsurface != NULL); - g_return_if_fail (func != NULL); - g_return_if_fail (order == G_PRE_ORDER || order == G_POST_ORDER); - - while ((hs = gts_eheap_top (hsurface->expandable, NULL))) - gts_hsplit_expand (hs, hsurface); - - len = hsurface->split->len; - switch (order) { - case G_PRE_ORDER: - while (i < len && !stop) { - GtsHSplit * hs = g_ptr_array_index (hsurface->split, i); - stop = (*func) (hs, data); - if (!stop) - gts_hsplit_collapse (hs, hsurface); - i++; - } - break; - case G_POST_ORDER: - while (i < len && !stop) { - GtsHSplit * hs = g_ptr_array_index (hsurface->split, i); - gts_hsplit_collapse (hs, hsurface); - stop = (*func) (hs, data); - i++; - } - break; - default: - g_assert_not_reached (); - } -} - -/** - * gts_hsurface_height: - * @hsurface: a #GtsHSurface. - * - * Returns: the maximum height of the tree described by @hsurface. - */ -guint gts_hsurface_height (GtsHSurface * hsurface) -{ - GSList * i; - guint height = 0; - - g_return_val_if_fail (hsurface != NULL, 0); - - i = hsurface->roots; - while (i) { - guint tmp_height = gts_split_height (i->data); - if (tmp_height > height) - height = tmp_height; - i = i->next; - } - - return height; -} Index: trunk/src_3rd/gts/graph.c =================================================================== --- trunk/src_3rd/gts/graph.c (revision 6802) +++ trunk/src_3rd/gts/graph.c (nonexistent) @@ -1,1776 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include -#include "gts.h" - -/* GtsGNode */ - -gboolean gts_allow_floating_gnodes = FALSE; - -static void gnode_remove_container (GtsContainee * i, GtsContainer * c) -{ - (* GTS_CONTAINEE_CLASS (GTS_OBJECT_CLASS (gts_gnode_class ())->parent_class)->remove_container) (i, c); - if (GTS_SLIST_CONTAINEE (i)->containers == NULL && - !gts_allow_floating_gnodes && - !GTS_OBJECT_DESTROYED(GTS_OBJECT (i))) - gts_object_destroy (GTS_OBJECT (i)); -} - -static void gnode_class_init (GtsGNodeClass * klass) -{ - klass->weight = NULL; - - GTS_CONTAINEE_CLASS (klass)->remove_container = gnode_remove_container; -} - -static void gnode_init (GtsGNode * n) -{ - n->level = 0; -} - -/** - * gts_gnode_class: - * - * Returns: the #GtsGNodeClass. - */ -GtsGNodeClass * gts_gnode_class (void) -{ - static GtsGNodeClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo gnode_info = { - "GtsGNode", - sizeof (GtsGNode), - sizeof (GtsGNodeClass), - (GtsObjectClassInitFunc) gnode_class_init, - (GtsObjectInitFunc) gnode_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = - gts_object_class_new (GTS_OBJECT_CLASS (gts_slist_container_class ()), - &gnode_info); - } - - return klass; -} - -/** - * gts_gnode_new: - * @klass: a #GtsGNodeClass. - * - * Returns: a new #GtsGNode. - */ -GtsGNode * gts_gnode_new (GtsGNodeClass * klass) -{ - GtsGNode * object; - - object = GTS_GNODE (gts_object_new (GTS_OBJECT_CLASS (klass))); - - return object; -} - -/** - * gts_gnode_foreach_neighbor: - * @n: a #GtsGNode. - * @g: a #GtsGraph or %NULL. - * @func: a #GtsFunc. - * @data: user data to be passed to @func. - * - * Calls @func for each neighbor #GtsGNode of @n (belonging to @g if - * @g is not %NULL. - */ -void gts_gnode_foreach_neighbor (GtsGNode * n, - GtsGraph * g, - GtsFunc func, - gpointer data) -{ - GSList * i; - - g_return_if_fail (n != NULL); - g_return_if_fail (func != NULL); - - i = GTS_SLIST_CONTAINER (n)->items; - while (i) { - GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); - if (g == NULL || gts_containee_is_contained (GTS_CONTAINEE (n1), - GTS_CONTAINER (g))) - (* func) (n1, data); - i = i->next; - } -} - -/** - * gts_gnode_foreach_edge: - * @n: a #GtsGNode. - * @g: a #GtsGraph or %NULL. - * @func: a #GtsFunc. - * @data: user data to be passed to @func. - * - * Calls @func for each #GtsGEdge connecting @n to another #GtsGNode - * (belonging to @g if @g is not %NULL. - */ -void gts_gnode_foreach_edge (GtsGNode * n, - GtsGraph * g, - GtsFunc func, - gpointer data) -{ - GSList * i; - - g_return_if_fail (n != NULL); - g_return_if_fail (func != NULL); - - i = GTS_SLIST_CONTAINER (n)->items; - while (i) { - GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); - if (g == NULL || gts_containee_is_contained (GTS_CONTAINEE (n1), - GTS_CONTAINER (g))) - (* func) (i->data, data); - i = i->next; - } -} - -/** - * gts_gnode_degree: - * @n: a #GtsGNode. - * @g: a #GtsGraph or %NULL. - * - * Returns: the number of neighbors of @n (belonging to @g if @g is not %NULL). - */ -guint gts_gnode_degree (GtsGNode * n, - GtsGraph * g) -{ - GSList * i; - guint nn = 0; - - g_return_val_if_fail (n != NULL, 0); - - i = GTS_SLIST_CONTAINER (n)->items; - while (i) { - GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); - if (g == NULL || gts_containee_is_contained (GTS_CONTAINEE (n1), - GTS_CONTAINER (g))) - nn++; - i = i->next; - } - - return nn; -} - -/** - * gts_gnode_move_cost: - * @n: a #GtsGNode. - * @src: a #GtsGraph containing @n. - * @dst: another #GtsGraph. - * - * Returns: the cost (increase in the sum of the weights of the edges cut) of - * moving @n from @src to @dst. - */ -gfloat gts_gnode_move_cost (GtsGNode * n, - GtsGraph * src, - GtsGraph * dst) -{ - GSList * i; - gfloat cost = 0.; - - g_return_val_if_fail (n != NULL, G_MAXFLOAT); - g_return_val_if_fail (src != NULL, G_MAXFLOAT); - g_return_val_if_fail (dst != NULL, G_MAXFLOAT); - g_return_val_if_fail (gts_containee_is_contained (GTS_CONTAINEE (n), - GTS_CONTAINER (src)), - G_MAXFLOAT); - - i = GTS_SLIST_CONTAINER (n)->items; - while (i) { - GtsGEdge * ge = i->data; - GtsGNode * neighbor = GTS_GNODE_NEIGHBOR (n, ge); - - if (gts_containee_is_contained (GTS_CONTAINEE (neighbor), - GTS_CONTAINER (src))) - cost += gts_gedge_weight (ge); - else if (gts_containee_is_contained (GTS_CONTAINEE (neighbor), - GTS_CONTAINER (dst))) - cost -= gts_gedge_weight (ge); - i = i->next; - } - - return cost; -} - -/** - * gts_gnode_weight: - * @n: a #GtsGNode. - * - * Returns: the weight of @n as defined by the weight() method of the - * #GtsGNodeClass. - */ -gfloat gts_gnode_weight (GtsGNode * n) -{ - g_return_val_if_fail (n != NULL, 0.); - - if (GTS_GNODE_CLASS (GTS_OBJECT (n)->klass)->weight) - return (* GTS_GNODE_CLASS (GTS_OBJECT (n)->klass)->weight) (n); - return 1.; -} - -/* GtsNGNode */ - -static void ngnode_init (GtsNGNode * n) -{ - n->id = 0; -} - -/** - * gts_ngnode_class: - * - * Returns: the #GtsNGNodeClass. - */ -GtsNGNodeClass * gts_ngnode_class (void) -{ - static GtsNGNodeClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo ngnode_info = { - "GtsNGNode", - sizeof (GtsNGNode), - sizeof (GtsNGNodeClass), - (GtsObjectClassInitFunc) NULL, - (GtsObjectInitFunc) ngnode_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()), - &ngnode_info); - } - - return klass; -} - -/** - * gts_ngnode_new: - * @klass: a #GtsNGNodeClass. - * - * Returns: a new #GtsNGNode with identity @id. - */ -GtsNGNode * gts_ngnode_new (GtsNGNodeClass * klass, - guint id) -{ - GtsNGNode * n; - - n = GTS_NGNODE (gts_gnode_new (GTS_GNODE_CLASS (klass))); - n->id = id; - - return n; -} - -/* GtsWGNode */ - -static gfloat wgnode_weight (GtsGNode * n) -{ - return GTS_WGNODE (n)->weight; -} - -static void wgnode_class_init (GtsWGNodeClass * klass) -{ - GTS_GNODE_CLASS (klass)->weight = wgnode_weight; -} - -static void wgnode_init (GtsWGNode * n) -{ - n->weight = 1.; -} - -/** - * gts_wgnode_class: - * - * Returns: the #GtsWGNodeClass. - */ -GtsWGNodeClass * gts_wgnode_class (void) -{ - static GtsWGNodeClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo wgnode_info = { - "GtsWGNode", - sizeof (GtsWGNode), - sizeof (GtsWGNodeClass), - (GtsObjectClassInitFunc) wgnode_class_init, - (GtsObjectInitFunc) wgnode_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()), - &wgnode_info); - } - - return klass; -} - -/** - * gts_wgnode_new: - * @klass: a #GtsWGNodeClass. - * @weight: the weight of the #GtsWGNode to create. - * - * Returns: a new #GtsWGNode of weight @weight. - */ -GtsWGNode * gts_wgnode_new (GtsWGNodeClass * klass, - gfloat weight) -{ - GtsWGNode * n; - - n = GTS_WGNODE (gts_gnode_new (GTS_GNODE_CLASS (klass))); - n->weight = weight; - - return n; -} - -/* GtsPNode */ - -static void pnode_write (GtsGNode * n, FILE * fp) -{ - if (GTS_IS_NVERTEX (GTS_PNODE (n)->data)) - fprintf (fp, "label=\"%p:%s\",", - GTS_PNODE (n)->data, - GTS_NVERTEX (GTS_PNODE (n)->data)->name); - else - fprintf (fp, "label=\"%p\",", GTS_PNODE (n)->data); -} - -static void pnode_class_init (GtsPNodeClass * klass) -{ - GTS_GNODE_CLASS (klass)->write = pnode_write; -} - -static void pnode_init (GtsPNode * pn) -{ - pn->data = NULL; -} - -/** - * gts_pnode_class: - * - * Returns: the #GtsPNodeClass. - */ -GtsPNodeClass * gts_pnode_class (void) -{ - static GtsPNodeClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo pnode_info = { - "GtsPNode", - sizeof (GtsPNode), - sizeof (GtsPNodeClass), - (GtsObjectClassInitFunc) pnode_class_init, - (GtsObjectInitFunc) pnode_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()), - &pnode_info); - } - - return klass; -} - -/** - * gts_pnode_new: - * @klass: a #GtsPNodeClass. - * @data: user data. - * - * Returns: a new #GtsPNode associated with @data. - */ -GtsPNode * gts_pnode_new (GtsPNodeClass * klass, gpointer data) -{ - GtsPNode * pn; - - pn = GTS_PNODE (gts_object_new (GTS_OBJECT_CLASS (klass))); - pn->data = data; - - return pn; -} - -/* GtsFNode */ - -static void fnode_write (GtsGNode * n, FILE * fp) -{ - fprintf (fp, "label=\"%p\",", GTS_FNODE (n)->f); -} - -static void fnode_class_init (GtsGNodeClass * klass) -{ - klass->write = fnode_write; -} - -static void fnode_init (GtsFNode * fn) -{ - fn->f = NULL; -} - -/** - * gts_fnode_class: - * - * Returns: the #GtsFNodeClass. - */ -GtsFNodeClass * gts_fnode_class (void) -{ - static GtsFNodeClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo fnode_info = { - "GtsFNode", - sizeof (GtsFNode), - sizeof (GtsFNodeClass), - (GtsObjectClassInitFunc) fnode_class_init, - (GtsObjectInitFunc) fnode_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()), - &fnode_info); - } - - return klass; -} - -/** - * gts_fnode_new: - * @klass: a #GtsFNodeClass. - * @f: a #GtsFace. - * - * Returns: a new #GtsFNode associated with face @f. - */ -GtsFNode * gts_fnode_new (GtsFNodeClass * klass, GtsFace * f) -{ - GtsFNode * fn; - - g_return_val_if_fail (f != NULL, NULL); - - fn = GTS_FNODE (gts_object_new (GTS_OBJECT_CLASS (klass))); - fn->f = f; - - return fn; -} - -/* GtsGEdge */ - -static void gedge_destroy (GtsObject * object) -{ - GtsGEdge * ge = GTS_GEDGE (object); - - if (ge->n1) - gts_container_remove (GTS_CONTAINER (ge->n1), GTS_CONTAINEE (ge)); - if (ge->n2) - gts_container_remove (GTS_CONTAINER (ge->n2), GTS_CONTAINEE (ge)); - - (* GTS_OBJECT_CLASS (gts_gedge_class ())->parent_class->destroy) (object); -} - -static void gedge_remove_container (GtsContainee * i, GtsContainer * c) -{ - GtsGEdge * ge = GTS_GEDGE (i); - GtsGNode * n1 = ge->n1; - GtsGNode * n2 = ge->n2; - - ge->n1 = ge->n2 = NULL; - if (n1 != NULL && n2 != NULL) { - if (GTS_CONTAINER (n1) == c) { - if (n2 && n2 != n1) gts_container_remove (GTS_CONTAINER (n2), i); - } - else if (GTS_CONTAINER (n2) == c) { - if (n1 && n1 != n2) gts_container_remove (GTS_CONTAINER (n1), i); - } - else - g_assert_not_reached (); - (* GTS_OBJECT_CLASS (gts_gedge_class ())->parent_class->destroy) - (GTS_OBJECT (i)); - } -} - -static gboolean gedge_is_contained (GtsContainee * i, GtsContainer * c) -{ - GtsGEdge * ge = GTS_GEDGE (i); - - if (GTS_CONTAINER (ge->n1) == c || GTS_CONTAINER (ge->n2) == c) - return TRUE; - return FALSE; -} - -static void gedge_class_init (GtsGEdgeClass * klass) -{ - klass->link = NULL; - klass->weight = NULL; - - GTS_CONTAINEE_CLASS (klass)->remove_container = gedge_remove_container; - GTS_CONTAINEE_CLASS (klass)->is_contained = gedge_is_contained; - - GTS_OBJECT_CLASS (klass)->destroy = gedge_destroy; -} - -static void gedge_init (GtsGEdge * object) -{ - object->n1 = object->n2 = NULL; -} - -/** - * gts_gedge_class: - * - * Returns: the #GtsGEdgeClass. - */ -GtsGEdgeClass * gts_gedge_class (void) -{ - static GtsGEdgeClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo gedge_info = { - "GtsGEdge", - sizeof (GtsGEdge), - sizeof (GtsGEdgeClass), - (GtsObjectClassInitFunc) gedge_class_init, - (GtsObjectInitFunc) gedge_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_containee_class ()), - &gedge_info); - } - - return klass; -} - -/** - * gts_gedge_new: - * @klass: a #GtsGEdgeClass. - * @n1: a #GtsGNode. - * @n2: another #GtsGNode. - * - * Returns: a new #GtsGEdge linking @n1 and @n2. - */ -GtsGEdge * gts_gedge_new (GtsGEdgeClass * klass, GtsGNode * n1, GtsGNode * n2) -{ - GtsGEdge * object; - - g_return_val_if_fail (n1 != NULL, NULL); - g_return_val_if_fail (n2 != NULL, NULL); - - object = GTS_GEDGE (gts_object_new (GTS_OBJECT_CLASS (klass))); - object->n1 = n1; - gts_container_add (GTS_CONTAINER (n1), GTS_CONTAINEE (object)); - object->n2 = n2; - if (n1 != n2) - gts_container_add (GTS_CONTAINER (n2), GTS_CONTAINEE (object)); - - if (klass->link) - object = (* klass->link) (object, n1, n2); - - return object; -} - -/** - * gts_gedge_weight: - * @e: a #GtsGEdge. - * - * Returns: the weight of edge @e as defined by the weight() method of - * #GtsGEdgeClass. - */ -gfloat gts_gedge_weight (GtsGEdge * e) -{ - g_return_val_if_fail (e != NULL, 0.); - - if (GTS_GEDGE_CLASS (GTS_OBJECT (e)->klass)->weight) - return (* GTS_GEDGE_CLASS (GTS_OBJECT (e)->klass)->weight) (e); - return 1.; -} - -/* GtsPGEdge */ - -static void pgedge_write (GtsGEdge * ge, FILE * fp) -{ - if (GTS_IS_EDGE (GTS_PGEDGE (ge)->data)) { - GtsEdge * e = GTS_PGEDGE (ge)->data; - guint n = g_slist_length (e->triangles); - - fprintf (fp, "label=\"%p:%s:%d\",color=%s", e, - GTS_IS_NEDGE (e) ? GTS_NEDGE (e)->name : "", - n, - n == 0 ? "black" : - n == 1 ? "blue" : - n == 2 ? "green" : - n == 3 ? "violet" : - n == 4 ? "red" : - "pink"); - } - else - fprintf (fp, "label=\"%p\",", GTS_PGEDGE (ge)->data); -} - -static void pgedge_class_init (GtsPGEdgeClass * klass) -{ - GTS_GEDGE_CLASS (klass)->write = pgedge_write; -} - -static void pgedge_init (GtsPGEdge * e) -{ - e->data = NULL; -} - -/** - * gts_pgedge_class: - * - * Returns: the #GtsPGEdgeClass. - */ -GtsPGEdgeClass * gts_pgedge_class (void) -{ - static GtsPGEdgeClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo pgedge_info = { - "GtsPGEdge", - sizeof (GtsPGEdge), - sizeof (GtsPGEdgeClass), - (GtsObjectClassInitFunc) pgedge_class_init, - (GtsObjectInitFunc) pgedge_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gedge_class ()), - &pgedge_info); - } - - return klass; -} - -/** - * gts_pgedge_new: - * @klass: a #GtsPGEdgeClass. - * @n1: a #GtsGNode. - * @n2: another #GtsGNode. - * @data: user data. - * - * Returns: a new #GtsPGEdge associated with @data linking @n1 and @n2. - */ -GtsPGEdge * gts_pgedge_new (GtsPGEdgeClass * klass, - GtsGNode * g1, - GtsGNode * g2, - gpointer data) -{ - GtsPGEdge * we; - - we = GTS_PGEDGE (gts_gedge_new (GTS_GEDGE_CLASS (klass), g1, g2)); - we->data = data; - - return we; -} - -/* GtsWGEdge */ - -static gfloat wgedge_weight (GtsGEdge * e) -{ - return GTS_WGEDGE (e)->weight; -} - -static void wgedge_class_init (GtsWGEdgeClass * klass) -{ - GTS_GEDGE_CLASS (klass)->weight = wgedge_weight; -} - -static void wgedge_init (GtsWGEdge * e) -{ - e->weight = 1.; -} - -/** - * gts_wgedge_class: - * - * Returns: the #GtsWGEdgeClass. - */ -GtsWGEdgeClass * gts_wgedge_class (void) -{ - static GtsWGEdgeClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo wgedge_info = { - "GtsWGEdge", - sizeof (GtsWGEdge), - sizeof (GtsWGEdgeClass), - (GtsObjectClassInitFunc) wgedge_class_init, - (GtsObjectInitFunc) wgedge_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gedge_class ()), - &wgedge_info); - } - - return klass; -} - -/** - * gts_wgedge_new: - * @klass: a #GtsWGEdgeClass. - * @n1: a #GtsGNode. - * @n2: another #GtsGNode. - * @weight: the weight of the new edge. - * - * Returns: a new #GtsWGEdge of weight @weight linking @n1 and @n2. - */ -GtsWGEdge * gts_wgedge_new (GtsWGEdgeClass * klass, - GtsGNode * g1, - GtsGNode * g2, - gfloat weight) -{ - GtsWGEdge * we; - - we = GTS_WGEDGE (gts_gedge_new (GTS_GEDGE_CLASS (klass), g1, g2)); - we->weight = weight; - - return we; -} - -/* GtsGraph */ - -static void graph_init (GtsGraph * g) -{ - g->graph_class = gts_graph_class (); - g->node_class = gts_gnode_class (); - g->edge_class = gts_gedge_class (); -} - -static void graph_write (GtsObject * object, FILE * fp) -{ - GtsGraph * graph = GTS_GRAPH (object); - - fprintf (fp, " %s %s %s", - object->klass->info.name, - GTS_OBJECT_CLASS (graph->node_class)->info.name, - GTS_OBJECT_CLASS (graph->edge_class)->info.name); -} - -static void graph_read (GtsObject ** object, GtsFile * f) -{ - GtsObjectClass * klass; - - if (f->type != GTS_STRING) { - gts_file_error (f, "expecting a string (GtsGNodeClass)"); - return; - } - klass = gts_object_class_from_name (f->token->str); - if (klass == NULL) { - gts_file_error (f, "unknown class `%s'", f->token->str); - return; - } - if (!gts_object_class_is_from_class (klass, gts_gnode_class ())) { - gts_file_error (f, "class `%s' is not a GtsGNodeClass", f->token->str); - return; - } - GTS_GRAPH (*object)->node_class = GTS_GNODE_CLASS (klass); - gts_file_next_token (f); - - if (f->type != GTS_STRING) { - gts_file_error (f, "expecting a string (GtsGEdgeClass)"); - return; - } - klass = gts_object_class_from_name (f->token->str); - if (klass == NULL) { - gts_file_error (f, "unknown class `%s'", f->token->str); - return; - } - if (!gts_object_class_is_from_class (klass, gts_gedge_class ())) { - gts_file_error (f, "class `%s' is not a GtsGEdgeClass", f->token->str); - return; - } - GTS_GRAPH (*object)->edge_class = GTS_GEDGE_CLASS (klass); - gts_file_next_token (f); -} - -static void graph_class_init (GtsGraphClass * klass) -{ - klass->weight = NULL; - - GTS_OBJECT_CLASS (klass)->write = graph_write; - GTS_OBJECT_CLASS (klass)->read = graph_read; -} - -/** - * gts_graph_class: - * - * Returns: the #GtsGraphClass. - */ -GtsGraphClass * gts_graph_class (void) -{ - static GtsGraphClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo graph_info = { - "GtsGraph", - sizeof (GtsGraph), - sizeof (GtsGraphClass), - (GtsObjectClassInitFunc) graph_class_init, - (GtsObjectInitFunc) graph_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_hash_container_class ()), - &graph_info); - } - - return klass; -} - -/** - * gts_graph_new: - * @klass: a #GtsGraphClass. - * @node_class: a #GtsGNodeClass. - * @edge_class: a #GtsGEdgeClass. - * - * Returns: a new #GtsGraph using @node_class and @edge_class as node types. - */ -GtsGraph * gts_graph_new (GtsGraphClass * klass, - GtsGNodeClass * node_class, - GtsGEdgeClass * edge_class) -{ - GtsGraph * g; - - g_return_val_if_fail (klass != NULL, NULL); - g_return_val_if_fail (node_class != NULL, NULL); - g_return_val_if_fail (edge_class != NULL, NULL); - - g = GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (klass))); - g->node_class = node_class; - g->edge_class = edge_class; - - return g; -} - -static void compute_degree (GtsGNode * n, gpointer * data) -{ - GtsGraph * g = data[0]; - GtsRange * degree = data[1]; - - gts_range_add_value (degree, gts_gnode_degree (n, g)); -} - -/** - * gts_graph_print_stats: - * @g: a #GtsGraph. - * @fp: a file pointer. - * - * Writes to @fp a summary of the properties of @g. - */ -void gts_graph_print_stats (GtsGraph * g, FILE * fp) -{ - GtsRange degree; - gpointer data[2]; - - g_return_if_fail (g != NULL); - g_return_if_fail (fp != NULL); - - fprintf (fp, "# nodes: %d weight: %g\n", - gts_container_size (GTS_CONTAINER (g)), - gts_graph_weight (g)); - fprintf (fp, "# degree: "); - gts_range_init (°ree); - data[0] = g; - data[1] = °ree; - gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) compute_degree, data); - gts_range_update (°ree); - gts_range_print (°ree, fp); - fprintf (fp, "\n"); - fprintf (fp, "# edges cut: %d edges cut weight: %g\n", - gts_graph_edges_cut (g), - gts_graph_edges_cut_weight (g)); -} - -struct _GtsGraphTraverse { - GtsFifo * q; - GtsGraph * g; -}; - -static void reset_level (GtsGNode * n) -{ - n->level = 0; -} - -/** - * gts_graph_traverse_new: - * @g: a #GtsGraph. - * @n: a #GtsGNode belonging to @g. - * @type: the type of traversal. - * @reinit: if %TRUE, the traversal is reinitialized. - * - * Returns: a new #GtsGraphTraverse initialized for the traversal of - * @g of type @type, starting from @n. - */ -GtsGraphTraverse * gts_graph_traverse_new (GtsGraph * g, - GtsGNode * n, - GtsTraverseType type, - gboolean reinit) -{ - GtsGraphTraverse * t; - - g_return_val_if_fail (g != NULL, NULL); - g_return_val_if_fail (n != NULL, NULL); - g_return_val_if_fail (gts_containee_is_contained (GTS_CONTAINEE (n), - GTS_CONTAINER (g)), - NULL); - - if (reinit) - gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) reset_level, NULL); - - t = g_malloc (sizeof (GtsGraphTraverse)); - t->q = gts_fifo_new (); - t->g = g; - n->level = 1; - gts_fifo_push (t->q, n); - - return t; -} - -static void push_neighbor (GtsGNode * n, gpointer * data) -{ - GtsFifo * q = data[0]; - GtsGNode * u = data[1]; - - if (n->level == 0) { - n->level = u->level + 1; - gts_fifo_push (q, n); - } -} - -/** - * gts_graph_traverse_next: - * @t: a #GtsGraphTraverse. - * - * Returns: the next #GtsGNode of the traversal defined by @t or %NULL - * if the traversal is complete. - */ -GtsGNode * gts_graph_traverse_next (GtsGraphTraverse * t) -{ - GtsGNode * u; - - g_return_val_if_fail (t != NULL, NULL); - - u = gts_fifo_pop (t->q); - if (u) { - gpointer data[2]; - - data[0] = t->q; - data[1] = u; - gts_gnode_foreach_neighbor (u, t->g, (GtsFunc) push_neighbor, data); - } - - return u; -} - -/** - * gts_graph_traverse_what_next: - * @t: a #GtsGraphTraverse. - * - * Returns: the next #GtsGNode of the traversal defined by @t or %NULL - * if the traversal is complete but without advancing the traversal. - */ -GtsGNode * gts_graph_traverse_what_next (GtsGraphTraverse * t) -{ - g_return_val_if_fail (t != NULL, NULL); - - return gts_fifo_top (t->q); -} - -/** - * gts_graph_traverse_destroy: - * @t: a #GtsGraphTraverse. - * - * Frees all the memory allocated for @t. - */ -void gts_graph_traverse_destroy (GtsGraphTraverse * t) -{ - g_return_if_fail (t != NULL); - - gts_fifo_destroy (t->q); - g_free (t); -} - -static void edge_foreach_node (GtsGNode * n, gpointer * info) -{ - GtsFunc func = (GtsFunc) info[0]; - gpointer data = info[1]; - GHashTable * hash = info[2]; - GSList * i = GTS_SLIST_CONTAINER (n)->items; - - while (i) { - GtsGEdge * e = i->data; - if (!g_hash_table_lookup (hash, e)) { - (* func) (e, data); - g_hash_table_insert (hash, e, e); - } - i = i->next; - } -} - -/** - * gts_graph_foreach_edge: - * @g: a #GtsGraph. - * @func: a #GtsFunc. - * @data: user data to be passed to @func. - * - * Calls @func for each #GtsEdge of @g. - */ -void gts_graph_foreach_edge (GtsGraph * g, GtsFunc func, gpointer data) -{ - gpointer info[3]; - GHashTable * hash; - - g_return_if_fail (g != NULL); - g_return_if_fail (func != NULL); - - info[0] = func; - info[1] = data; - info[2] = hash = g_hash_table_new (NULL, NULL); - gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) edge_foreach_node, info); - g_hash_table_destroy (hash); -} - -/** - * gts_graph_weight: - * @g: a #GtsGraph. - * - * Returns: the weight of graph @g as defined by the weight() method - * of #GtsGraphClass. - */ -gfloat gts_graph_weight (GtsGraph * g) -{ - g_return_val_if_fail (g != NULL, 0.); - - if (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass)->weight) - return (* GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass)->weight) (g); - return (gfloat) gts_container_size (GTS_CONTAINER (g)); -} - -/** - * gts_graph_distance_sum: - * @g: a #GtsGraph. - * @center: a #GtsGNode of @g. - * - * Returns: the sum of the distances between all the other #GtsGNode - * of @g and @center. - */ -guint gts_graph_distance_sum (GtsGraph * g, GtsGNode * center) -{ - GtsGraphTraverse * t; - GtsGNode * n; - guint sum = 0; - - g_return_val_if_fail (g != NULL, 0); - g_return_val_if_fail (center != NULL, 0); - - t = gts_graph_traverse_new (g, center, GTS_BREADTH_FIRST, TRUE); - while ((n = gts_graph_traverse_next (t))) - sum += n->level - 1; - gts_graph_traverse_destroy (t); - - return sum; -} - -/** - * gts_graph_farthest: - * @g: a #GtsGraph. - * @gnodes: a list of #GtsGNode belonging to @g. - * - * Returns: the #GtsGNode belonging to @g and farthest from all the nodes in - * @gnodes (hmmm, definition of "farthest"?). - */ -GtsGNode * gts_graph_farthest (GtsGraph * g, GSList * gnodes) -{ - GtsGNode * farthest = NULL; - GSList * i; - gboolean reinit = TRUE, changed = TRUE; - guint level = 1; - - g_return_val_if_fail (g != NULL, NULL); - - /* initialize traversals */ - i = gnodes; - while (i) { - GTS_OBJECT (i->data)->reserved = - gts_graph_traverse_new (g, i->data, GTS_BREADTH_FIRST, reinit); - reinit = FALSE; - i = i->next; - } - - while (changed) { - changed = FALSE; - i = gnodes; - while (i) { - GtsGraphTraverse * t = GTS_OBJECT (i->data)->reserved; - GtsGNode * n; - while ((n = gts_graph_traverse_what_next (t)) && n->level == level) { - changed = TRUE; - farthest = n; - gts_graph_traverse_next (t); - } - i = i->next; - } - level++; - } - - /* destroy traversals */ - i = gnodes; - while (i) { - gts_graph_traverse_destroy (GTS_OBJECT (i->data)->reserved); - GTS_OBJECT (i->data)->reserved = NULL; - i = i->next; - } - return farthest; -} - -static void neighbor_count (GtsGNode * n, gpointer * data) -{ - guint * cuts = data[0]; - GtsGraph * g = data[1]; - - if (!gts_containee_is_contained (GTS_CONTAINEE (n), GTS_CONTAINER (g))) - (*cuts)++; -} - -static void count_edge_cuts (GtsGNode * n, gpointer * data) -{ - gts_gnode_foreach_neighbor (n, NULL, (GtsFunc) neighbor_count, data); -} - -/** - * gts_graph_edges_cut: - * @g: a #GtsGraph. - * - * Returns: the number of edges of @g connecting nodes belonging to @g - * to nodes not belonging to @g. - */ -guint gts_graph_edges_cut (GtsGraph * g) -{ - guint cuts = 0; - gpointer data[2]; - - g_return_val_if_fail (g != NULL, 0); - - data[0] = &cuts; - data[1] = g; - gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) count_edge_cuts, data); - - return cuts; -} - -static void sum_edge_cuts_weight (GtsGNode * n, gpointer * data) -{ - gfloat * weight = data[0]; - GtsGraph * g = data[1]; - GSList * i = GTS_SLIST_CONTAINER (n)->items; - - while (i) { - GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); - if (!gts_containee_is_contained (GTS_CONTAINEE (n1), GTS_CONTAINER (g))) - *weight += gts_gedge_weight (i->data); - i = i->next; - } -} - -/** - * gts_graph_edges_cut_weight: - * @g: a #GtsGraph. - * - * Returns: the sum of the weights of the edges of @g connecting nodes - * belonging to @g to nodes not belonging to @g. - */ -gfloat gts_graph_edges_cut_weight (GtsGraph * g) -{ - gfloat weight = 0.; - gpointer data[2]; - - g_return_val_if_fail (g != NULL, 0); - - data[0] = &weight; - data[1] = g; - gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) sum_edge_cuts_weight, - data); - - return weight; -} - -/** - * gts_graph_read_jostle: - * @g: a #GtsGraph. - * @fp: a #GtsFile. - * - * Adds to @g the nodes and edges defined in the file pointed to by - * @fp. This file must use the Jostle "graph" ASCII format. - * The nodes created are of type #GtsNGNode and their identities are the - * line number at which they appear in @fp. - * - * Returns: 0 if the lecture was successful, the line number at which - * an error occured otherwise (in which case the @error field of @fp - * is set). - */ -guint gts_graph_read_jostle (GtsGraph * g, GtsFile * fp) -{ - guint nn, ne, n; - GtsGNode ** nodes; - - g_return_val_if_fail (g != NULL, 1); - g_return_val_if_fail (fp != NULL, 1); - - if (fp->type != GTS_INT) { - gts_file_error (fp, "expecting an integer (number of nodes)"); - return fp->line; - } - nn = atoi (fp->token->str); - gts_file_next_token (fp); - - if (fp->type != GTS_INT) { - gts_file_error (fp, "expecting an integer (number of edges)"); - return fp->line; - } - ne = atoi (fp->token->str); - - gts_file_first_token_after (fp, '\n'); - nodes = g_malloc (sizeof (GtsGNode *)*(nn + 1)); - - n = 0; - while (n < nn && fp->type != GTS_ERROR) { - GtsNGNode * node = gts_ngnode_new (gts_ngnode_class (), fp->line); - - nodes[n++] = GTS_GNODE (node); - gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (node)); - do { - if (fp->type != GTS_INT) - gts_file_error (fp, "expecting an integer (node index)"); - else { - guint in = atoi (fp->token->str); - - if (in == 0 || in > nn) - gts_file_error (fp, "node index `%d' is out of range `[1,%d]'", - in, nn); - else if (in == n) - gts_file_error (fp, "node index `%d' references itself", in); - else if (in < n) { - gts_gedge_new (g->edge_class, GTS_GNODE (node), nodes[in - 1]); - ne--; - gts_file_next_token (fp); - } - } - } while (fp->type != GTS_ERROR && fp->type != '\n'); - } - g_free (nodes); - - if (fp->type != GTS_ERROR) { - if (n != nn) - gts_file_error (fp, "only `%d' nodes read out of `%d'", - n, nn); - else if (ne > 0) - gts_file_error (fp, "`%d' unallocated edges remaining", - ne); - } - - if (fp->type == GTS_ERROR) - return fp->line; - return 0; -} - -static void count_edges (GtsGEdge * e, guint * nedge) -{ - (*nedge)++; -} - -static void write_node (GtsObject * node, gpointer * data) -{ - FILE * fp = data[0]; - guint * nnode = data[1]; - - node->reserved = GUINT_TO_POINTER ((*nnode)++); - if (node->klass->write) - (* node->klass->write) (node, fp); - fputc ('\n', fp); -} - -static void write_edge (GtsGEdge * edge, FILE * fp) -{ - fprintf (fp, "%u %u", - GPOINTER_TO_UINT (GTS_OBJECT (edge->n1)->reserved), - GPOINTER_TO_UINT (GTS_OBJECT (edge->n2)->reserved)); - if (GTS_OBJECT (edge)->klass->write) - (* GTS_OBJECT (edge)->klass->write) (GTS_OBJECT (edge), fp); - fputc ('\n', fp); -} - -/** - * gts_graph_write: - * @g: a #GtsGraph. - * @fp: a file pointer. - * - * Writes in the file @fp an ASCII representation of @g. The file - * format is as follows. - * - * All the lines beginning with #GTS_COMMENTS are ignored. The first line - * contains two unsigned integers separated by spaces. The first - * integer is the number of nodes, nn, the second is the number of - * edges, ne. - * - * Follows nn lines containing node description. - * Follows ne lines containing the two indices (starting - * from one) of the nodes of each edge. - * - * The format described above is the least common denominator to all - * GTS files. Consistent with an object-oriented approach, the GTS - * file format is extensible. Each of the lines of the file can be - * extended with user-specific attributes accessible through the - * read() and write() virtual methods of each of the objects written - * (graph, nodes or edges). When read with different object classes, - * these extra attributes are just ignored. - */ -void gts_graph_write (GtsGraph * g, FILE * fp) -{ - guint nnode = 1, nedge = 0; - gpointer data[2]; - - g_return_if_fail (g != NULL); - g_return_if_fail (fp != NULL); - - gts_graph_foreach_edge (g, (GtsFunc) count_edges, &nedge); - fprintf (fp, "%u %u", gts_container_size (GTS_CONTAINER (g)), nedge); - if (GTS_OBJECT (g)->klass->write) - (* GTS_OBJECT (g)->klass->write) (GTS_OBJECT (g), fp); - fputc ('\n', fp); - data[0] = fp; - data[1] = &nnode; - gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) write_node, data); - gts_graph_foreach_edge (g, (GtsFunc) write_edge, fp); - gts_container_foreach (GTS_CONTAINER (g), - (GtsFunc) gts_object_reset_reserved, NULL); -} - -/** - * gts_graph_read: - * @fp: a #GtsFile. - * - * Reads a graph from a file. - * - * Returns: the new #GtsGraph or %NULL if an error occured (in which - * case the @error field of @fp is set). - */ -GtsGraph * gts_graph_read (GtsFile * fp) -{ - GtsGraph * g; - GtsGNode ** nodes; - guint nn, ne, n; - - g_return_val_if_fail (fp != NULL, NULL); - - if (fp->type != GTS_INT) { - gts_file_error (fp, "expecting an integer (number of nodes)"); - return NULL; - } - nn = atoi (fp->token->str); - gts_file_next_token (fp); - - if (fp->type != GTS_INT) { - gts_file_error (fp, "expecting an integer (number of edges)"); - return NULL; - } - ne = atoi (fp->token->str); - - gts_file_next_token (fp); - if (fp->type != '\n') { - GtsObjectClass * klass; - - gts_graph_class (); - gts_gnode_class (); - gts_gedge_class (); - - if (fp->type != GTS_STRING) { - gts_file_error (fp, "expecting a string (GtsGraphClass)"); - return NULL; - } - klass = gts_object_class_from_name (fp->token->str); - if (klass == NULL) { - gts_file_error (fp, "unknown class `%s'", fp->token->str); - return NULL; - } - if (!gts_object_class_is_from_class (klass, gts_graph_class ())) { - gts_file_error (fp, "class `%s' is not a GtsGraphClass", fp->token->str); - return NULL; - } - g = GTS_GRAPH (gts_object_new (klass)); - g->graph_class = GTS_GRAPH_CLASS (klass); - gts_file_next_token (fp); - (* klass->read) ((GtsObject **) &g, fp); - if (fp->type == GTS_ERROR) { - gts_object_destroy (GTS_OBJECT (g)); - return NULL; - } - } - else - g = GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (gts_graph_class ()))); - gts_file_first_token_after (fp, '\n'); - if (nn <= 0) - return g; - - nodes = g_malloc ((nn + 1)*sizeof (GtsGNode *)); - - n = 0; - while (n < nn && fp->type != GTS_ERROR) { - GtsObject * new_node = - gts_object_new (GTS_OBJECT_CLASS (g->node_class)); - - gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (new_node)); - if (GTS_OBJECT_CLASS (g->node_class)->read) - (*GTS_OBJECT_CLASS (g->node_class)->read) (&new_node, fp); - gts_file_first_token_after (fp, '\n'); - nodes[n++] = GTS_GNODE (new_node); - } - if (fp->type == GTS_ERROR) - nn = n; - - n = 0; - while (n < ne && fp->type != GTS_ERROR) { - guint n1, n2; - - if (fp->type != GTS_INT) - gts_file_error (fp, "expecting an integer (first node index)"); - else { - n1 = atoi (fp->token->str); - if (n1 == 0 || n1 > nn) - gts_file_error (fp, "node index `%d' is out of range `[1,%d]'", - n1, nn); - else { - gts_file_next_token (fp); - if (fp->type != GTS_INT) - gts_file_error (fp, "expecting an integer (second node index)"); - else { - n2 = atoi (fp->token->str); - if (n2 == 0 || n2 > nn) - gts_file_error (fp, "node index `%d' is out of range `[1,%d]'", - n2, nn); - else { - GtsGEdge * new_edge = - gts_gedge_new (g->edge_class, nodes[n1 - 1], nodes [n2 - 1]); - - gts_file_next_token (fp); - if (fp->type != '\n') - if (GTS_OBJECT_CLASS (g->edge_class)->read) - (*GTS_OBJECT_CLASS (g->edge_class)->read) - ((GtsObject **) &new_edge, fp); - gts_file_first_token_after (fp, '\n'); - n++; - } - } - } - } - } - - if (fp->type == GTS_ERROR) { - gts_allow_floating_gnodes = TRUE; - while (nn) - gts_object_destroy (GTS_OBJECT (nodes[nn-- - 1])); - gts_allow_floating_gnodes = FALSE; - } - g_free (nodes); - - if (fp->type == GTS_ERROR) { - gts_object_destroy (GTS_OBJECT (g)); - return NULL; - } - return g; -} - -static void write_dot_node (GtsGNode * node, gpointer * data) -{ - FILE * fp = data[0]; - guint * nnode = data[1]; - - fprintf (fp, " n%u", *nnode); - if (GTS_GNODE_CLASS (GTS_OBJECT (node)->klass)->write) { - fputs (" [", fp); - (* GTS_GNODE_CLASS (GTS_OBJECT (node)->klass)->write) (node, fp); - fputc (']', fp); - } - fputs (";\n", fp); - GTS_OBJECT (node)->reserved = GUINT_TO_POINTER ((*nnode)++); -} - -static void write_dot_edge (GtsGEdge * edge, FILE * fp) -{ - fprintf (fp, " n%u -> n%u", - GPOINTER_TO_UINT (GTS_OBJECT (edge->n1)->reserved), - GPOINTER_TO_UINT (GTS_OBJECT (edge->n2)->reserved)); - if (GTS_GEDGE_CLASS (GTS_OBJECT (edge)->klass)->write) { - fputs (" [", fp); - (* GTS_GEDGE_CLASS (GTS_OBJECT (edge)->klass)->write) (edge, fp); - fputc (']', fp); - } - fputs (";\n", fp); -} - -/** - * gts_graph_write_dot: - * @g: a #GtsGraph. - * @fp: a file pointer. - * - * Writes in the file @fp an ASCII representation of @g in the dot format of - * AT&T Bell Labs. - */ -void gts_graph_write_dot (GtsGraph * g, FILE * fp) -{ - guint nnode = 1; - gpointer data[2]; - - g_return_if_fail (g != NULL); - g_return_if_fail (fp != NULL); - - fprintf (fp, "digraph \"%p\" {\n", g); - data[0] = fp; - data[1] = &nnode; - gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) write_dot_node, data); - gts_graph_foreach_edge (g, (GtsFunc) write_dot_edge, fp); - fputs ("}\n", fp); - - gts_container_foreach (GTS_CONTAINER (g), - (GtsFunc) gts_object_reset_reserved, NULL); -} - -/* GtsWGraph */ - -static gfloat wgraph_weight (GtsGraph * g) -{ - return GTS_WGRAPH (g)->weight; -} - -static void wgraph_add (GtsContainer * g, GtsContainee * n) -{ - GtsWGraph * wg = GTS_WGRAPH (g); - gfloat w = gts_gnode_weight (GTS_GNODE (n)); - - wg->weight += w; - - (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_wgraph_class ())->parent_class)->add) (g, n); -} - -static void wgraph_remove (GtsContainer * g, GtsContainee * n) -{ - GTS_WGRAPH (g)->weight -= gts_gnode_weight (GTS_GNODE (n)); - - (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_wgraph_class ())->parent_class)->remove) (g, n); -} - -static void wgraph_class_init (GtsWGraphClass * klass) -{ - GTS_GRAPH_CLASS (klass)->weight = wgraph_weight; - - GTS_CONTAINER_CLASS (klass)->add = wgraph_add; - GTS_CONTAINER_CLASS (klass)->remove = wgraph_remove; -} - -static void wgraph_init (GtsWGraph * g) -{ - g->weight = 0.; -} - -/** - * gts_wgraph_class: - * - * Returns: the #GtsWGraphClass. - */ -GtsWGraphClass * gts_wgraph_class (void) -{ - static GtsWGraphClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo wgraph_info = { - "GtsWGraph", - sizeof (GtsWGraph), - sizeof (GtsWGraphClass), - (GtsObjectClassInitFunc) wgraph_class_init, - (GtsObjectInitFunc) wgraph_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_graph_class ()), - &wgraph_info); - } - - return klass; -} - -static void weight_max (GtsGNode * n, gfloat * wmax) -{ - gfloat w = gts_gnode_weight (n); - - if (w > *wmax) - *wmax = w; -} - -/** - * gts_wgraph_weight_max: - * @wg: a #GtsWGraph. - * - * Returns: the maximum weight of any vertices belonging to @g. - */ -gfloat gts_wgraph_weight_max (GtsWGraph * wg) -{ - gfloat wmax = - G_MAXFLOAT; - - g_return_val_if_fail (wg != NULL, 0.); - - gts_container_foreach (GTS_CONTAINER (wg), (GtsFunc) weight_max, &wmax); - - return wmax; -} - -/* Surface graph */ - -static void create_node (GtsFace * f, GtsGraph * graph) -{ - GtsFNode * fn = gts_fnode_new (gts_fnode_class (), f); - - gts_container_add (GTS_CONTAINER (graph), GTS_CONTAINEE (fn)); - GTS_OBJECT (f)->reserved = fn; -} - -static void create_edge (GtsEdge * e, GtsSurface * s) -{ - GSList * i = e->triangles; - - while (i) { - GtsFace * f = i->data; - if (GTS_IS_FACE (f) && gts_face_has_parent_surface (f, s)) { - GSList * j = i->next; - while (j) { - GtsFace * f1 = j->data; - if (GTS_IS_FACE (f1) && gts_face_has_parent_surface (f1, s)) - gts_pgedge_new (gts_pgedge_class (), - GTS_OBJECT (f)->reserved, - GTS_OBJECT (f1)->reserved, - e); - j = j->next; - } - } - i = i->next; - } -} - -/** - * gts_surface_graph_new: - * @klass: a #GtsGraphClass. - * @s: a #GtsSurface. - * - * Returns: a new #GtsGraph representing the connectivity of the faces - * of @s. This graph uses #GtsFGNode as nodes which allows to store - * the dependencies between nodes and faces of @s. - */ -GtsGraph * gts_surface_graph_new (GtsGraphClass * klass, - GtsSurface * s) -{ - GtsGraph * graph; - - g_return_val_if_fail (klass != NULL, NULL); - g_return_val_if_fail (s != NULL, NULL); - - graph = GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (klass))); - gts_surface_foreach_face (s, (GtsFunc) create_node, graph); - gts_surface_foreach_edge (s, (GtsFunc) create_edge, s); - gts_surface_foreach_face (s, (GtsFunc) gts_object_reset_reserved, NULL); - - return graph; -} - -static void create_segment_edge (GtsSegment * s, GtsGraph * graph) -{ - GtsGNode * n1 = GTS_OBJECT (s->v1)->reserved, * n2; - - if (n1 == NULL) { - n1 = GTS_GNODE (gts_pnode_new (gts_pnode_class (), s->v1)); - gts_container_add (GTS_CONTAINER (graph), GTS_CONTAINEE (n1)); - GTS_OBJECT (s->v1)->reserved = n1; - } - - n2 = GTS_OBJECT (s->v2)->reserved; - if (n2 == NULL) { - n2 = GTS_GNODE (gts_pnode_new (gts_pnode_class (), s->v2)); - gts_container_add (GTS_CONTAINER (graph), GTS_CONTAINEE (n2)); - GTS_OBJECT (s->v2)->reserved = n2; - } - - gts_pgedge_new (gts_pgedge_class (), n1, n2, s); -} - -static void reset_reserved (GtsSegment * s) -{ - GTS_OBJECT (s->v1)->reserved = GTS_OBJECT (s->v2)->reserved = NULL; -} - -/** - * gts_segments_graph_new: - * @klass: a #GtsGraphClass. - * @segments: a list of #GtsSegment. - * - * Returns: a new #GtsGraph representing the connectivity of the segments - * in @segments. - */ -GtsGraph * gts_segments_graph_new (GtsGraphClass * klass, - GSList * segments) -{ - GtsGraph * graph; - - g_return_val_if_fail (klass != NULL, NULL); - - graph = GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (klass))); - g_slist_foreach (segments, (GFunc) create_segment_edge, graph); - g_slist_foreach (segments, (GFunc) reset_reserved, NULL); - - return graph; -} - -static void add_to_surface (GtsGNode * n, GtsSurface * s) -{ - if (GTS_IS_FNODE (n)) - gts_surface_add_face (s, GTS_FNODE (n)->f); -} - -/** - * gts_surface_graph_surface: - * @surface_graph: a #GtsGraph using #GtsFGNode as nodes. - * @s: a #GtsSurface. - * - * Returns: a new #GtsSurface using the same classes as @s and - * composed of the faces defined by @surface_graph. - */ -GtsSurface * gts_surface_graph_surface (GtsGraph * surface_graph, - GtsSurface * s) -{ - GtsSurface * s1; - - g_return_val_if_fail (surface_graph != NULL, NULL); - g_return_val_if_fail (s != NULL, NULL); - - s1 = gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass), - s->face_class, - s->edge_class, - s->vertex_class); - gts_container_foreach (GTS_CONTAINER (surface_graph), - (GtsFunc) add_to_surface, s1); - return s1; -} - Index: trunk/src_3rd/gts/gts.h =================================================================== --- trunk/src_3rd/gts/gts.h (revision 6802) +++ trunk/src_3rd/gts/gts.h (nonexistent) @@ -1,2577 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GTS_H__ -#define __GTS_H__ - -#include -#include - -#define GTS_MAJOR_VERSION 0 -#define GTS_MINOR_VERSION 7 -#define GTS_MICRO_VERSION 6 - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Added based on glib.h by M J Loehr 01/01/01 */ -/* GTS version. - * we prefix variable declarations so they can - * properly get exported in windows dlls. - */ -#ifdef NATIVE_WIN32 -# ifdef GTS_COMPILATION -# define GTS_C_VAR __declspec(dllexport) -# else /* not GTS_COMPILATION */ -# define GTS_C_VAR extern __declspec(dllimport) -# endif /* not GTS_COMPILATION */ -#else /* not NATIVE_WIN32 */ -# define GTS_C_VAR extern -#endif /* not NATIVE_WIN32 */ - -GTS_C_VAR const guint gts_major_version; -GTS_C_VAR const guint gts_minor_version; -GTS_C_VAR const guint gts_micro_version; -GTS_C_VAR const guint gts_interface_age; -GTS_C_VAR const guint gts_binary_age; - -#define GTS_CHECK_VERSION(major,minor,micro) \ - (gts_major_version > (major) || \ - (gts_major_version == (major) && gts_minor_version > (minor)) || \ - (gts_major_version == (major) && gts_minor_version == (minor) && \ - gts_micro_version >= (micro))) - -#define GTS_COMMENTS "#!" -#define GTS_MAINTAINER "popinet@users.sourceforge.net" - - - - -void gts_predicates_init(); - - -/* Class declarations for base types */ - -typedef struct _GtsObjectClassInfo GtsObjectClassInfo; -typedef struct _GtsObject GtsObject; -typedef struct _GtsObjectClass GtsObjectClass; -typedef struct _GtsPoint GtsPoint; -typedef struct _GtsPointClass GtsPointClass; -typedef struct _GtsVertex GtsVertex; -typedef struct _GtsVertexClass GtsVertexClass; -typedef struct _GtsSegment GtsSegment; -typedef struct _GtsSegmentClass GtsSegmentClass; -typedef struct _GtsEdge GtsEdge; -typedef struct _GtsEdgeClass GtsEdgeClass; -typedef struct _GtsTriangle GtsTriangle; -typedef struct _GtsTriangleClass GtsTriangleClass; -typedef struct _GtsFace GtsFace; -typedef struct _GtsFaceClass GtsFaceClass; -typedef struct _GtsBBox GtsBBox; -typedef struct _GtsBBoxClass GtsBBoxClass; -typedef struct _GtsSurface GtsSurface; -typedef struct _GtsSurfaceClass GtsSurfaceClass; - -typedef void (*GtsObjectClassInitFunc) (GtsObjectClass * objclass); -typedef void (*GtsObjectInitFunc) (GtsObject * obj); -typedef void (*GtsArgSetFunc) (GtsObject * obj); -typedef void (*GtsArgGetFunc) (GtsObject * obj); - -typedef gdouble GtsVector[3]; -typedef gdouble GtsVector4[4]; -typedef GtsVector4 GtsMatrix; -/** - * GtsKeyFunc: - * @item: A pointer to an item to be stored in the heap. - * @data: User data passed to gts_eheap_new(). - * - * Returns: the value of the key for the given item. - */ -typedef gdouble (*GtsKeyFunc) (gpointer item, - gpointer data); -typedef enum -{ - GTS_OUT = -1, - GTS_ON = 0, - GTS_IN = 1 -} GtsIntersect; - -typedef struct _GtsColor GtsColor; - -struct _GtsColor { - gfloat r, g, b; -}; - -typedef gint (*GtsFunc) (gpointer item, - gpointer data); - -/* misc.c */ - -typedef struct _GtsFile GtsFile; - -typedef enum { - GTS_NONE = 1 << 8, - GTS_INT = 1 << 9, - GTS_UINT = 1 << 10, - GTS_FLOAT = 1 << 11, - GTS_DOUBLE = 1 << 12, - GTS_STRING = 1 << 13, - GTS_FILE = 1 << 14, - GTS_ERROR = 1 << 15 -} GtsTokenType; - -struct _GtsFile { - FILE * fp; - gchar * s, * s1; - guint line, pos; - GString * token; - GtsTokenType type; - gchar * error; - - guint curline, curpos; - guint scope, scope_max; - gint next_token; - gchar * delimiters; - gchar * comments; - gchar * tokens; -}; - -typedef struct _GtsFileVariable GtsFileVariable; - -struct _GtsFileVariable { - GtsTokenType type; - gchar name[30]; - gboolean unique; - gpointer data; - gboolean set; - guint line, pos; -}; - - -GtsFile * gts_file_new (FILE * fp); -GtsFile * gts_file_new_from_string (const gchar * s); -void gts_file_verror (GtsFile * f, - const gchar * format, - va_list args); -void gts_file_error (GtsFile * f, - const gchar * format, - ...); -gint gts_file_getc (GtsFile * f); -guint gts_file_read (GtsFile * f, - gpointer ptr, - guint size, - guint nmemb); -gint gts_file_getc_scope (GtsFile * f); -void gts_file_next_token (GtsFile * f); -void gts_file_first_token_after (GtsFile * f, - GtsTokenType type); -void gts_file_assign_start (GtsFile * f, - GtsFileVariable * vars); -GtsFileVariable * gts_file_assign_next (GtsFile * f, - GtsFileVariable * vars); -void gts_file_assign_variables (GtsFile * f, - GtsFileVariable * vars); -void gts_file_variable_error (GtsFile * f, - GtsFileVariable * vars, - const gchar * name, - const gchar * format, - ...); -void gts_file_destroy (GtsFile * f); - -/* Objects: object.c */ - -#ifdef GTS_CHECK_CASTS -# define GTS_OBJECT_CAST(obj, type, klass) ((type *) gts_object_check_cast (obj, klass)) -# define GTS_OBJECT_CLASS_CAST(objklass, type, klass) ((type *) gts_object_class_check_cast (objklass, klass)) -#else /* not GTS_CHECK_CASTS */ -# define GTS_OBJECT_CAST(obj, type, klass) ((type *) (obj)) -# define GTS_OBJECT_CLASS_CAST(objklass, type, klass) ((type *) (objklass)) -#endif /* not GTS_CHECK_CASTS */ - -#define GTS_CLASS_NAME_LENGTH 40 -#define GTS_OBJECT(obj) GTS_OBJECT_CAST (obj,\ - GtsObject,\ - gts_object_class ()) -#define GTS_OBJECT_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsObjectClass,\ - gts_object_class()) -#define GTS_IS_OBJECT(obj) (gts_object_is_from_class (obj,\ - gts_object_class ())) - -typedef enum -{ - GTS_DESTROYED = 1 << 0, - GTS_USER_FLAG = 1 /* user flags start from here */ -} GtsObjectFlags; - -#define GTS_OBJECT_FLAGS(obj) (GTS_OBJECT (obj)->flags) -#define GTS_OBJECT_DESTROYED(obj) ((GTS_OBJECT_FLAGS (obj) & GTS_DESTROYED) != 0) -#define GTS_OBJECT_SET_FLAGS(obj,flag) G_STMT_START{ (GTS_OBJECT_FLAGS (obj) |= (flag)); }G_STMT_END -#define GTS_OBJECT_UNSET_FLAGS(obj,flag) G_STMT_START{ (GTS_OBJECT_FLAGS (obj) &= ~(flag)); }G_STMT_END - -struct _GtsObjectClassInfo { - gchar name[GTS_CLASS_NAME_LENGTH]; - guint object_size; - guint class_size; - GtsObjectClassInitFunc class_init_func; - GtsObjectInitFunc object_init_func; - GtsArgSetFunc arg_set_func; - GtsArgGetFunc arg_get_func; -}; - -struct _GtsObject { - GtsObjectClass * klass; - - gpointer reserved; - guint32 flags; -}; - -struct _GtsObjectClass { - GtsObjectClassInfo info; - GtsObjectClass * parent_class; - - void (* clone) (GtsObject *, GtsObject *); - void (* destroy) (GtsObject *); - void (* read) (GtsObject **, GtsFile *); - void (* write) (GtsObject *, FILE *); - GtsColor (* color) (GtsObject *); - void (* attributes) (GtsObject *, GtsObject *); -}; - -gpointer gts_object_class_new (GtsObjectClass * parent_class, - GtsObjectClassInfo * info); -GtsObjectClass * gts_object_class (void); -gpointer gts_object_check_cast (gpointer object, - gpointer klass); -gpointer gts_object_class_check_cast (gpointer klass, - gpointer from); - -static inline -gpointer gts_object_is_from_class (gpointer object, - gpointer klass) -{ - GtsObjectClass * c; - - g_return_val_if_fail (klass != NULL, NULL); - - if (object == NULL) - return NULL; - - c = ((GtsObject *) object)->klass; - - g_return_val_if_fail (c != NULL, NULL); - - while (c) { - if (c == klass) - return object; - c = c->parent_class; - } - - return NULL; -} - -static inline -gpointer gts_object_class_is_from_class (gpointer klass, - gpointer from) -{ - GtsObjectClass * c; - - g_return_val_if_fail (klass != NULL, NULL); - g_return_val_if_fail (from != NULL, NULL); - - c = (GtsObjectClass *) klass; - while (c) { - if (c == from) - return klass; - c = c->parent_class; - } - - return NULL; -} - -GtsObjectClass * gts_object_class_from_name (const gchar * name); - -GtsObject * gts_object_new (GtsObjectClass * klass); -GtsObject * gts_object_clone (GtsObject * object); -void gts_object_attributes (GtsObject * object, - GtsObject * from); -void gts_object_init (GtsObject * object, - GtsObjectClass * klass); -void gts_object_reset_reserved (GtsObject * object); -void gts_object_destroy (GtsObject * object); -void gts_finalize (void); - -/* Ranges: surface.c */ -typedef struct _GtsRange GtsRange; - -struct _GtsRange { - gdouble min, max, sum, sum2, mean, stddev; - guint n; -}; - -void gts_range_init (GtsRange * r); -void gts_range_reset (GtsRange * r); -void gts_range_add_value (GtsRange * r, - gdouble val); -void gts_range_update (GtsRange * r); -void gts_range_print (GtsRange * r, - FILE * fptr); - -/* Points: point.c */ - -#define GTS_IS_POINT(obj) (gts_object_is_from_class (obj,\ - gts_point_class ())) -#define GTS_POINT(obj) GTS_OBJECT_CAST (obj,\ - GtsPoint,\ - gts_point_class ()) -#define GTS_POINT_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsPointClass,\ - gts_point_class ()) - -struct _GtsPoint { - GtsObject object; - - gdouble x, y, z; /* must be contiguous (cast to robust functions) */ -}; - -struct _GtsPointClass { - GtsObjectClass parent_class; - gboolean binary; -}; - -GtsPointClass * gts_point_class (void); -GtsPoint * gts_point_new (GtsPointClass * klass, - gdouble x, - gdouble y, - gdouble z); -void gts_point_set (GtsPoint * p, - gdouble x, - gdouble y, - gdouble z); -#define gts_point_is_in_rectangle(p, p1, p2) ((p)->x >= (p1)->x &&\ - (p)->x <= (p2)->x &&\ - (p)->y >= (p1)->y &&\ - (p)->y <= (p2)->y &&\ - (p)->z >= (p1)->z &&\ - (p)->z <= (p2)->z) -GtsPoint * gts_segment_triangle_intersection (GtsSegment * s, - GtsTriangle * t, - gboolean boundary, - GtsPointClass * klass); -void gts_point_transform (GtsPoint * p, - GtsMatrix * m); -gdouble gts_point_distance (GtsPoint * p1, - GtsPoint * p2); -gdouble gts_point_distance2 (GtsPoint * p1, - GtsPoint * p2); -gdouble gts_point_orientation_3d (GtsPoint * p1, - GtsPoint * p2, - GtsPoint * p3, - GtsPoint * p4); -gint gts_point_orientation_3d_sos (GtsPoint * p1, - GtsPoint * p2, - GtsPoint * p3, - GtsPoint * p4); -GtsIntersect gts_point_is_in_triangle (GtsPoint * p, - GtsTriangle * t); -gdouble gts_point_in_circle (GtsPoint * p, - GtsPoint * p1, - GtsPoint * p2, - GtsPoint * p3); -gdouble gts_point_in_sphere (GtsPoint * p, - GtsPoint * p1, - GtsPoint * p2, - GtsPoint * p3, - GtsPoint * p4); -gdouble gts_point_in_triangle_circle (GtsPoint * p, - GtsTriangle * t); -gdouble gts_point_orientation (GtsPoint * p1, - GtsPoint * p2, - GtsPoint * p3); -gint gts_point_orientation_sos (GtsPoint * p1, - GtsPoint * p2, - GtsPoint * p3); -gdouble gts_point_segment_distance2 (GtsPoint * p, - GtsSegment * s); -gdouble gts_point_segment_distance (GtsPoint * p, - GtsSegment * s); -void gts_point_segment_closest (GtsPoint * p, - GtsSegment * s, - GtsPoint * closest); -gdouble gts_point_triangle_distance2 (GtsPoint * p, - GtsTriangle * t); -gdouble gts_point_triangle_distance (GtsPoint * p, - GtsTriangle * t); -void gts_point_triangle_closest (GtsPoint * p, - GtsTriangle * t, - GtsPoint * closest); -gboolean gts_point_is_inside_surface (GtsPoint * p, - GNode * tree, - gboolean is_open); - -/* Vertices: vertex.c */ - -#define GTS_IS_VERTEX(obj) (gts_object_is_from_class (obj,\ - gts_vertex_class ())) -#define GTS_VERTEX(obj) GTS_OBJECT_CAST (obj,\ - GtsVertex,\ - gts_vertex_class ()) -#define GTS_VERTEX_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsVertexClass,\ - gts_vertex_class ()) -struct _GtsVertex { - GtsPoint p; - - GSList * segments; -}; - -struct _GtsVertexClass { - GtsPointClass parent_class; - - void (* intersection_attributes) (GtsVertex *, - GtsObject *, - GtsObject *); -}; - -GTS_C_VAR -gboolean gts_allow_floating_vertices; - -GtsVertexClass * gts_vertex_class (void); -GtsVertex * gts_vertex_new (GtsVertexClass * klass, - gdouble x, - gdouble y, - gdouble z); -void gts_vertex_replace (GtsVertex * v, - GtsVertex * with); -gboolean gts_vertex_is_unattached (GtsVertex * v); -GtsSegment * gts_vertices_are_connected (GtsVertex * v1, - GtsVertex * v2); -GSList * gts_vertex_triangles (GtsVertex * v, - GSList * list); -GSList * gts_vertex_faces (GtsVertex * v, - GtsSurface * surface, - GSList * list); -GSList * gts_vertex_neighbors (GtsVertex * v, - GSList * list, - GtsSurface * surface); -GSList * gts_vertices_from_segments (GSList * segments); -gboolean gts_vertex_is_boundary (GtsVertex * v, - GtsSurface * surface); -GList * gts_vertices_merge (GList * vertices, - gdouble epsilon, - gboolean (* check) (GtsVertex *, GtsVertex *)); -GSList * gts_vertex_fan_oriented (GtsVertex * v, - GtsSurface * surface); -guint gts_vertex_is_contact (GtsVertex * v, gboolean sever); - -/* GtsVertexNormal: Header */ - -typedef struct _GtsVertexNormal GtsVertexNormal; - -struct _GtsVertexNormal { - /*< private >*/ - GtsVertex parent; - - /*< public >*/ - GtsVector n; -}; - -#define GTS_VERTEX_NORMAL(obj) GTS_OBJECT_CAST (obj,\ - GtsVertexNormal,\ - gts_vertex_normal_class ()) -#define GTS_IS_VERTEX_NORMAL(obj) (gts_object_is_from_class (obj,\ - gts_vertex_normal_class ())) - -GtsVertexClass * gts_vertex_normal_class (void); - -/* GtsColorVertex: Header */ - -typedef struct _GtsColorVertex GtsColorVertex; - -struct _GtsColorVertex { - /*< private >*/ - GtsVertex parent; - - /*< public >*/ - GtsColor c; -}; - -#define GTS_COLOR_VERTEX(obj) GTS_OBJECT_CAST (obj,\ - GtsColorVertex,\ - gts_color_vertex_class ()) -#define GTS_IS_COLOR_VERTEX(obj) (gts_object_is_from_class (obj,\ - gts_color_vertex_class ())) - -GtsVertexClass * gts_color_vertex_class (void); - -/* Segments: segment.c */ - -#define GTS_IS_SEGMENT(obj) (gts_object_is_from_class (obj,\ - gts_segment_class ())) -#define GTS_SEGMENT(obj) GTS_OBJECT_CAST (obj,\ - GtsSegment,\ - gts_segment_class ()) -#define GTS_SEGMENT_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsSegmentClass,\ - gts_segment_class ()) - -struct _GtsSegment { - GtsObject object; - - GtsVertex * v1; - GtsVertex * v2; -}; - -struct _GtsSegmentClass { - GtsObjectClass parent_class; -}; - -GtsSegmentClass * gts_segment_class (void); -GtsSegment * gts_segment_new (GtsSegmentClass * klass, - GtsVertex * v1, - GtsVertex * v2); -#define gts_segment_connect(s, e1, e2) (((s)->v1 == e1 &&\ - (s)->v2 == e2) || \ - ((s)->v1 == e2 &&\ - (s)->v2 == e1)) -#define gts_segments_are_identical(s1, s2) (((s1)->v1 == (s2)->v1 &&\ - (s1)->v2 == (s2)->v2)\ - ||\ - ((s1)->v1 == (s2)->v2 &&\ - (s1)->v2 == (s2)->v1)) -#define gts_segments_touch(s1, s2) ((s1)->v1 == (s2)->v1 ||\ - (s1)->v1 == (s2)->v2 ||\ - (s1)->v2 == (s2)->v1 ||\ - (s1)->v2 == (s2)->v2) -GtsIntersect gts_segments_are_intersecting (GtsSegment * s1, - GtsSegment * s2); -GtsSegment * gts_segment_is_duplicate (GtsSegment * s); -GtsVertex * gts_segment_midvertex (GtsSegment * s, - GtsVertexClass * klass); -GSList * gts_segments_from_vertices (GSList * vertices); -gboolean gts_segment_is_ok (GtsSegment * s); - -/* Edges: edge.c */ - -#define GTS_IS_EDGE(obj) (gts_object_is_from_class (obj,\ - gts_edge_class ())) -#define GTS_EDGE(obj) GTS_OBJECT_CAST (obj,\ - GtsEdge,\ - gts_edge_class ()) -#define GTS_EDGE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsEdgeClass,\ - gts_edge_class ()) - -struct _GtsEdge { - GtsSegment segment; - - GSList * triangles; -}; - -struct _GtsEdgeClass { - GtsSegmentClass parent_class; -}; - -GTS_C_VAR -gboolean gts_allow_floating_edges; - -GtsEdgeClass * gts_edge_class (void); -GtsEdge * gts_edge_new (GtsEdgeClass * klass, - GtsVertex * v1, - GtsVertex * v2); -/** - * gts_edge_is_unattached: - * @s: a #GtsEdge. - * - * Evaluates to %TRUE if no triangles uses @s as an edge, %FALSE otherwise. - */ -#define gts_edge_is_unattached(s) ((s)->triangles == NULL ? TRUE : FALSE) -GtsFace * gts_edge_has_parent_surface (GtsEdge * e, - GtsSurface * surface); -GtsFace * gts_edge_has_any_parent_surface (GtsEdge * e); -GtsFace * gts_edge_is_boundary (GtsEdge * e, - GtsSurface * surface); -void gts_edge_replace (GtsEdge * e, - GtsEdge * with); -GSList * gts_edges_from_vertices (GSList * vertices, - GtsSurface * parent); -guint gts_edge_face_number (GtsEdge * e, - GtsSurface * s); -gboolean gts_edge_collapse_is_valid (GtsEdge * e); -gboolean gts_edge_collapse_creates_fold (GtsEdge * e, - GtsVertex * v, - gdouble max); -GtsEdge * gts_edge_is_duplicate (GtsEdge * e); -GList * gts_edges_merge (GList * edges); -gboolean gts_edge_belongs_to_tetrahedron (GtsEdge * e); -guint gts_edge_is_contact (GtsEdge * e); -void gts_edge_swap (GtsEdge * e, - GtsSurface * s); -gboolean gts_edge_manifold_faces (GtsEdge * e, - GtsSurface * s, - GtsFace ** f1, - GtsFace ** f2); - -/* Triangles: triangle.c */ - -#define GTS_IS_TRIANGLE(obj) (gts_object_is_from_class (obj,\ - gts_triangle_class ())) -#define GTS_TRIANGLE(obj) GTS_OBJECT_CAST (obj,\ - GtsTriangle,\ - gts_triangle_class ()) -#define GTS_TRIANGLE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsTriangleClass,\ - gts_triangle_class ()) - -struct _GtsTriangle { - GtsObject object; - - GtsEdge * e1; - GtsEdge * e2; - GtsEdge * e3; -}; - -struct _GtsTriangleClass { - GtsObjectClass parent_class; -}; - -GtsTriangleClass * gts_triangle_class (void); -void gts_triangle_set (GtsTriangle * triangle, - GtsEdge * e1, - GtsEdge * e2, - GtsEdge * e3); -GtsTriangle * gts_triangle_new (GtsTriangleClass * klass, - GtsEdge * e1, - GtsEdge * e2, - GtsEdge * e3); -#define gts_triangle_vertex(t) (GTS_SEGMENT (GTS_TRIANGLE (t)->e1)->v1 ==\ - GTS_SEGMENT (GTS_TRIANGLE (t)->e2)->v1 || \ - GTS_SEGMENT (GTS_TRIANGLE (t)->e1)->v2 ==\ - GTS_SEGMENT (GTS_TRIANGLE (t)->e2)->v1 ? \ - GTS_SEGMENT (GTS_TRIANGLE (t)->e2)->v2 :\ - GTS_SEGMENT (GTS_TRIANGLE (t)->e2)->v1) -GtsVertex * gts_triangle_vertex_opposite (GtsTriangle * t, - GtsEdge * e); -GtsEdge * gts_triangle_edge_opposite (GtsTriangle * t, - GtsVertex * v); -gdouble gts_triangles_angle (GtsTriangle * t1, - GtsTriangle * t2); -gboolean gts_triangles_are_compatible (GtsTriangle * t1, - GtsTriangle * t2, - GtsEdge * e); -gdouble gts_triangle_area (GtsTriangle * t); -gdouble gts_triangle_perimeter (GtsTriangle * t); -gdouble gts_triangle_quality (GtsTriangle * t); -void gts_triangle_normal (GtsTriangle * t, - gdouble * x, - gdouble * y, - gdouble * z); -gdouble gts_triangle_orientation (GtsTriangle * t); -void gts_triangle_revert (GtsTriangle * t); -GSList * gts_triangles_from_edges (GSList * edges); -void gts_triangle_vertices_edges (GtsTriangle * t, - GtsEdge * e, - GtsVertex ** v1, - GtsVertex ** v2, - GtsVertex ** v3, - GtsEdge ** e1, - GtsEdge ** e2, - GtsEdge ** e3); -GtsTriangle * gts_triangle_enclosing (GtsTriangleClass * klass, - GSList * points, - gdouble scale); -guint gts_triangle_neighbor_number (GtsTriangle * t); -GSList * gts_triangle_neighbors (GtsTriangle * t); -GtsEdge * gts_triangles_common_edge (GtsTriangle * t1, - GtsTriangle * t2); -GtsTriangle * gts_triangle_is_duplicate (GtsTriangle * t); -GtsTriangle * gts_triangle_use_edges (GtsEdge * e1, - GtsEdge * e2, - GtsEdge * e3); -gboolean gts_triangle_is_ok (GtsTriangle * t); -void gts_triangle_vertices (GtsTriangle * t, - GtsVertex ** v1, - GtsVertex ** v2, - GtsVertex ** v3); -GtsPoint * gts_triangle_circumcircle_center (GtsTriangle * t, - GtsPointClass * point_class); -gboolean gts_triangles_are_folded (GSList * triangles, - GtsVertex * A, GtsVertex * B, - gdouble max); -GtsObject * gts_triangle_is_stabbed (GtsTriangle * t, - GtsPoint * p, - gdouble * orientation); -void gts_triangle_interpolate_height (GtsTriangle * t, - GtsPoint * p); - -/* Faces: face.c */ - -#define GTS_IS_FACE(obj) (gts_object_is_from_class (obj,\ - gts_face_class ())) -#define GTS_FACE(obj) GTS_OBJECT_CAST (obj,\ - GtsFace,\ - gts_face_class ()) -#define GTS_FACE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsFaceClass,\ - gts_face_class ()) - -struct _GtsFace { - GtsTriangle triangle; - - GSList * surfaces; -}; - -struct _GtsFaceClass { - GtsTriangleClass parent_class; -}; - -GTS_C_VAR -gboolean gts_allow_floating_faces; - -GtsFaceClass * gts_face_class (void); -GtsFace * gts_face_new (GtsFaceClass * klass, - GtsEdge * e1, - GtsEdge * e2, - GtsEdge * e3); -gboolean gts_face_has_parent_surface (GtsFace * f, - GtsSurface * s); -GSList * gts_faces_from_edges (GSList * edges, - GtsSurface * s); -guint gts_face_neighbor_number (GtsFace * f, - GtsSurface * s); -GSList * gts_face_neighbors (GtsFace * f, - GtsSurface * s); -void gts_face_foreach_neighbor (GtsFace * f, - GtsSurface * s, - GtsFunc func, - gpointer data); -gboolean gts_face_is_compatible (GtsFace * f, - GtsSurface * s); - -/* Matrices: matrix.c */ - -#define gts_vector_cross(C,A,B) ((C)[0] = (A)[1]*(B)[2] - (A)[2]*(B)[1],\ - (C)[1] = (A)[2]*(B)[0] - (A)[0]*(B)[2],\ - (C)[2] = (A)[0]*(B)[1] - (A)[1]*(B)[0]) - -#define gts_vector_init(v, p1, p2) ((v)[0] = (p2)->x - (p1)->x,\ - (v)[1] = (p2)->y - (p1)->y,\ - (v)[2] = (p2)->z - (p1)->z) -#define gts_vector_scalar(v1, v2) ((v1)[0]*(v2)[0] +\ - (v1)[1]*(v2)[1] +\ - (v1)[2]*(v2)[2]) -#define gts_vector_norm(v) (sqrt ((v)[0]*(v)[0] +\ - (v)[1]*(v)[1] +\ - (v)[2]*(v)[2])) -#define gts_vector_normalize(v) {\ - gdouble __gts_n = gts_vector_norm (v);\ - if (__gts_n > 0.) {\ - (v)[0] /= __gts_n;\ - (v)[1] /= __gts_n;\ - (v)[2] /= __gts_n;\ - }\ -} -GtsMatrix * gts_matrix_new (gdouble a00, gdouble a01, gdouble a02, gdouble a03, - gdouble a10, gdouble a11, gdouble a12, gdouble a13, - gdouble a20, gdouble a21, gdouble a22, gdouble a23, - gdouble a30, gdouble a31, gdouble a32, gdouble a33); -void gts_matrix_assign (GtsMatrix * m, - gdouble a00, gdouble a01, gdouble a02, gdouble a03, - gdouble a10, gdouble a11, gdouble a12, gdouble a13, - gdouble a20, gdouble a21, gdouble a22, gdouble a23, - gdouble a30, gdouble a31, gdouble a32, gdouble a33); -GtsMatrix * gts_matrix_projection (GtsTriangle * t); -GtsMatrix * gts_matrix_transpose (GtsMatrix * m); -gdouble gts_matrix_determinant (GtsMatrix * m); -GtsMatrix * gts_matrix_inverse (GtsMatrix * m); -GtsMatrix * gts_matrix3_inverse (GtsMatrix * m); -void gts_matrix_print (GtsMatrix * m, - FILE * fptr); -guint gts_matrix_compatible_row (GtsMatrix * A, - GtsVector b, - guint n, - GtsVector A1, - gdouble b1); -guint gts_matrix_quadratic_optimization (GtsMatrix * A, - GtsVector b, - guint n, - GtsMatrix * H, - GtsVector c); -GtsMatrix * gts_matrix_product (GtsMatrix * m1, - GtsMatrix * m2); -GtsMatrix * gts_matrix_zero (GtsMatrix * m); -GtsMatrix * gts_matrix_identity (GtsMatrix * m); -GtsMatrix * gts_matrix_scale (GtsMatrix * m, - GtsVector s); -GtsMatrix * gts_matrix_translate (GtsMatrix * m, - GtsVector t); -GtsMatrix * gts_matrix_rotate (GtsMatrix * m, - GtsVector r, - gdouble angle); -void gts_matrix_destroy (GtsMatrix * m); -void gts_vector_print (GtsVector v, - FILE * fptr); -void gts_vector4_print (GtsVector4 v, - FILE * fptr); - -/* Kdtrees: kdtree.c */ - -#define gts_kdtree_destroy(tree) g_node_destroy(tree) - -GNode * gts_kdtree_new (GPtrArray * points, - int (*compare) - (const void *, - const void *)); -GSList * gts_kdtree_range (GNode * tree, - GtsBBox * bbox, - int (*compare) - (const void *, - const void *)); - -/* Bboxtrees: bbtree.c */ - -/** - * GtsBBTreeTraverseFunc: - * @bb1: a #GtsBBox. - * @bb2: another #GtsBBox. - * @data: user data passed to the function. - * - * User function called for each pair of overlapping bounding - * boxes. See gts_bb_tree_traverse_overlapping(). - */ -typedef void (*GtsBBTreeTraverseFunc) (GtsBBox * bb1, - GtsBBox * bb2, - gpointer data); -/** - * GtsBBoxDistFunc: - * @p: a #GtsPoint. - * @bounded: an object bounded by a #GtsBBox. - * - * User function returning the (minimum) distance between the object - * defined by @bounded and point @p. - * - * Returns: the distance between @p and @bounded. - */ -typedef gdouble (*GtsBBoxDistFunc) (GtsPoint * p, - gpointer bounded); -/** - * GtsBBoxClosestFunc: - * @p: a #GtsPoint. - * @bounded: an object bounded by a #GtsBBox. - * - * User function returning a #GtsPoint belonging to the object defined - * by @bounded and closest to @p. - * - * Returns: a #GtsPoint. - */ -typedef GtsPoint * (*GtsBBoxClosestFunc) (GtsPoint * p, - gpointer bounded); - -/** - * GTS_IS_BBOX: - * @obj: a #GtsObject. - * - * Evaluates to %TRUE if @obj is a #GtsBBox, %FALSE otherwise. - */ -#define GTS_IS_BBOX(obj) (gts_object_is_from_class (obj,\ - gts_bbox_class ())) -/** - * GTS_BBOX: - * @obj: a #GtsObject. - * - * Casts @obj to #GtsBBox. - */ -#define GTS_BBOX(obj) GTS_OBJECT_CAST (obj,\ - GtsBBox,\ - gts_bbox_class ()) -/** - * GTS_BBOX_CLASS: - * @klass: a descendant of #GtsBBoxClass. - * - * Casts @klass to #GtsBBoxClass. - */ -#define GTS_BBOX_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsBBoxClass,\ - gts_bbox_class ()) - -struct _GtsBBox { - GtsObject object; - gpointer bounded; - gdouble x1, y1, z1; - gdouble x2, y2, z2; -}; - -struct _GtsBBoxClass { - GtsObjectClass parent_class; -}; - -GtsBBoxClass * gts_bbox_class (void); -GtsBBox * gts_bbox_new (GtsBBoxClass * klass, - gpointer bounded, - gdouble x1, - gdouble y1, - gdouble z1, - gdouble x2, - gdouble y2, - gdouble z2); -void gts_bbox_set (GtsBBox * bbox, - gpointer bounded, - gdouble x1, - gdouble y1, - gdouble z1, - gdouble x2, - gdouble y2, - gdouble z2); -GtsBBox * gts_bbox_segment (GtsBBoxClass * klass, - GtsSegment * s); -GtsBBox * gts_bbox_triangle (GtsBBoxClass * klass, - GtsTriangle * t); -GtsBBox * gts_bbox_surface (GtsBBoxClass * klass, - GtsSurface * surface); -GtsBBox * gts_bbox_bboxes (GtsBBoxClass * klass, - GSList * bboxes); -GtsBBox * gts_bbox_points (GtsBBoxClass * klass, - GSList * points); -/** - * gts_bbox_point_is_inside: - * @bbox: a #GtsBBox. - * @p: a #GtsPoint. - * - * Evaluates to %TRUE if @p is inside (or on the boundary) of @bbox, %FALSE otherwise. - */ -#define gts_bbox_point_is_inside(bbox, p) ((p)->x >= (bbox)->x1 &&\ - (p)->y >= (bbox)->y1 &&\ - (p)->z >= (bbox)->z1 &&\ - (p)->x <= (bbox)->x2 &&\ - (p)->y <= (bbox)->y2 &&\ - (p)->z <= (bbox)->z2) -gboolean gts_bboxes_are_overlapping (GtsBBox * bb1, - GtsBBox * bb2); -void gts_bbox_draw (GtsBBox * bb, - FILE * fptr); -gdouble gts_bbox_diagonal2 (GtsBBox * bb); -void gts_bbox_point_distance2 (GtsBBox * bb, - GtsPoint * p, - gdouble * min, - gdouble * max); -gboolean gts_bbox_is_stabbed (GtsBBox * bb, - GtsPoint * p); -gboolean gts_bbox_overlaps_triangle (GtsBBox * bb, - GtsTriangle * t); -gboolean gts_bbox_overlaps_segment (GtsBBox * bb, - GtsSegment * s); - -GNode * gts_bb_tree_new (GSList * bboxes); -GNode * gts_bb_tree_surface (GtsSurface * s); -GSList * gts_bb_tree_stabbed (GNode * tree, - GtsPoint * p); -GSList * gts_bb_tree_overlap (GNode * tree, - GtsBBox * bbox); -gboolean gts_bb_tree_is_overlapping (GNode * tree, - GtsBBox * bbox); -void gts_bb_tree_traverse_overlapping (GNode * tree1, - GNode * tree2, - GtsBBTreeTraverseFunc func, - gpointer data); -void gts_bb_tree_draw (GNode * tree, - guint depth, - FILE * fptr); -GSList * gts_bb_tree_point_closest_bboxes (GNode * tree, - GtsPoint * p); -gdouble gts_bb_tree_point_distance (GNode * tree, - GtsPoint * p, - GtsBBoxDistFunc distance, - GtsBBox ** bbox); -GtsPoint * gts_bb_tree_point_closest (GNode * tree, - GtsPoint * p, - GtsBBoxClosestFunc closest, - gdouble * distance); -void gts_bb_tree_segment_distance (GNode * tree, - GtsSegment * s, - GtsBBoxDistFunc distance, - gdouble delta, - GtsRange * range); -void gts_bb_tree_triangle_distance (GNode * tree, - GtsTriangle * t, - GtsBBoxDistFunc distance, - gdouble delta, - GtsRange * range); -void gts_bb_tree_surface_distance (GNode * tree, - GtsSurface * s, - GtsBBoxDistFunc distance, - gdouble delta, - GtsRange * range); -void gts_bb_tree_surface_boundary_distance - (GNode * tree, - GtsSurface * s, - GtsBBoxDistFunc distance, - gdouble delta, - GtsRange * range); -void gts_bb_tree_destroy (GNode * tree, - gboolean free_leaves); - -/* Surfaces: surface.c */ - -typedef struct _GtsSurfaceStats GtsSurfaceStats; -typedef struct _GtsSurfaceQualityStats GtsSurfaceQualityStats; -typedef GtsVertex * (*GtsRefineFunc) (GtsEdge * e, - GtsVertexClass * klass, - gpointer data); -typedef GtsVertex * (*GtsCoarsenFunc) (GtsEdge * e, - GtsVertexClass * klass, - gpointer data); -typedef gboolean (*GtsStopFunc) (gdouble cost, - guint nedge, - gpointer data); - -struct _GtsSurfaceStats { - guint n_faces; - guint n_incompatible_faces; - guint n_duplicate_faces; - guint n_duplicate_edges; - guint n_boundary_edges; - guint n_non_manifold_edges; - GtsRange edges_per_vertex, faces_per_edge; - GtsSurface * parent; -}; - -struct _GtsSurfaceQualityStats { - GtsRange face_quality; - GtsRange face_area; - GtsRange edge_length; - GtsRange edge_angle; - GtsSurface * parent; -}; - -struct _GtsSurface { - GtsObject object; - -#ifdef USE_SURFACE_BTREE - GTree * faces; -#else /* not USE_SURFACE_BTREE */ - GHashTable * faces; -#endif /* not USE_SURFACE_BTREE */ - GtsFaceClass * face_class; - GtsEdgeClass * edge_class; - GtsVertexClass * vertex_class; - gboolean keep_faces; -}; - -struct _GtsSurfaceClass { - GtsObjectClass parent_class; - - void (* add_face) (GtsSurface *, GtsFace *); - void (* remove_face) (GtsSurface *, GtsFace *); -}; - -#define GTS_IS_SURFACE(obj) (gts_object_is_from_class (obj,\ - gts_surface_class ())) -#define GTS_SURFACE(obj) GTS_OBJECT_CAST (obj,\ - GtsSurface,\ - gts_surface_class ()) -#define GTS_SURFACE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsSurfaceClass,\ - gts_surface_class ()) - -GtsSurfaceClass * gts_surface_class (void); -GtsSurface * gts_surface_new (GtsSurfaceClass * klass, - GtsFaceClass * face_class, - GtsEdgeClass * edge_class, - GtsVertexClass * vertex_class); -void gts_surface_add_face (GtsSurface * s, - GtsFace * f); -void gts_surface_remove_face (GtsSurface * s, - GtsFace * f); -guint gts_surface_read (GtsSurface * surface, - GtsFile * f); -gdouble gts_surface_area (GtsSurface * s); -void gts_surface_stats (GtsSurface * s, - GtsSurfaceStats * stats); -void gts_surface_quality_stats (GtsSurface * s, - GtsSurfaceQualityStats * stats); -void gts_surface_print_stats (GtsSurface * s, - FILE * fptr); -void gts_surface_write (GtsSurface * s, - FILE * fptr); -void gts_surface_write_oogl (GtsSurface * s, - FILE * fptr); -void gts_surface_write_vtk (GtsSurface * s, - FILE * fptr); -void gts_surface_write_oogl_boundary (GtsSurface * s, - FILE * fptr); -void gts_surface_foreach_vertex (GtsSurface * s, - GtsFunc func, - gpointer data); -void gts_surface_foreach_edge (GtsSurface * s, - GtsFunc func, - gpointer data); -void gts_surface_foreach_face (GtsSurface * s, - GtsFunc func, - gpointer data); -guint gts_surface_foreach_face_remove (GtsSurface * s, - GtsFunc func, - gpointer data); -typedef struct _GtsSurfaceTraverse GtsSurfaceTraverse; -GtsSurfaceTraverse * gts_surface_traverse_new (GtsSurface * s, - GtsFace * f); -GtsFace * gts_surface_traverse_next (GtsSurfaceTraverse * t, - guint * level); -void gts_surface_traverse_destroy (GtsSurfaceTraverse * t); -void gts_surface_refine (GtsSurface * surface, - GtsKeyFunc cost_func, - gpointer cost_data, - GtsRefineFunc refine_func, - gpointer refine_data, - GtsStopFunc stop_func, - gpointer stop_data); -gboolean gts_edge_collapse_is_valid (GtsEdge * e); -void gts_surface_coarsen (GtsSurface * surface, - GtsKeyFunc cost_func, - gpointer cost_data, - GtsCoarsenFunc coarsen_func, - gpointer coarsen_data, - GtsStopFunc stop_func, - gpointer stop_data, - gdouble minangle); -gboolean gts_coarsen_stop_number (gdouble cost, - guint nedge, - guint * min_number); -gboolean gts_coarsen_stop_cost (gdouble cost, - guint nedge, - gdouble * max_cost); -void gts_surface_tessellate (GtsSurface * s, - GtsRefineFunc refine_func, - gpointer refine_data); -GtsSurface * gts_surface_generate_sphere (GtsSurface * s, - guint geodesation_order); -GtsSurface * gts_surface_copy (GtsSurface * s1, - GtsSurface * s2); -void gts_surface_merge (GtsSurface * s, - GtsSurface * with); -gboolean gts_surface_is_manifold (GtsSurface * s); -gboolean gts_surface_is_closed (GtsSurface * s); -gboolean gts_surface_is_orientable (GtsSurface * s); -gdouble gts_surface_volume (GtsSurface * s); -gdouble gts_surface_center_of_mass (GtsSurface * s, - GtsVector cm); -gdouble gts_surface_center_of_area (GtsSurface * s, - GtsVector cm); -guint gts_surface_vertex_number (GtsSurface * s); -guint gts_surface_edge_number (GtsSurface * s); -guint gts_surface_face_number (GtsSurface * s); -void gts_surface_distance (GtsSurface * s1, - GtsSurface * s2, - gdouble delta, - GtsRange * face_range, - GtsRange * boundary_range); -GSList * gts_surface_boundary (GtsSurface * surface); -GSList * gts_surface_split (GtsSurface * s); - -/* Discrete differential operators: curvature.c */ - -gboolean gts_vertex_mean_curvature_normal (GtsVertex * v, - GtsSurface * s, - GtsVector Kh); -gboolean gts_vertex_gaussian_curvature (GtsVertex * v, - GtsSurface * s, - gdouble * Kg); -void gts_vertex_principal_curvatures (gdouble Kh, - gdouble Kg, - gdouble * K1, - gdouble * K2); -void gts_vertex_principal_directions (GtsVertex * v, - GtsSurface * s, - GtsVector Kh, - gdouble Kg, - GtsVector e1, - GtsVector e2); - -/* Volume optimization: vopt.c */ -typedef struct _GtsVolumeOptimizedParams GtsVolumeOptimizedParams; - -struct _GtsVolumeOptimizedParams { - gdouble volume_weight; - gdouble boundary_weight; - gdouble shape_weight; -}; - -GtsVertex * gts_volume_optimized_vertex (GtsEdge * edge, - GtsVertexClass * klass, - GtsVolumeOptimizedParams * params); -gdouble gts_volume_optimized_cost (GtsEdge * e, - GtsVolumeOptimizedParams * params); - -/* bool operations: boolean.c */ - -GSList * gts_surface_intersection (GtsSurface * s1, - GtsSurface * s2, - GNode * faces_tree1, - GNode * faces_tree2); - -typedef struct _GtsSurfaceInter GtsSurfaceInter; -typedef struct _GtsSurfaceInterClass GtsSurfaceInterClass; -/** - * GtsBooleanOperation: - * @GTS_1_OUT_2: identifies the part of the first surface which lies - * outside the second surface. - * @GTS_1_IN_2: identifies the part of the first surface which lies - * inside the second surface. - * @GTS_2_OUT_1: identifies the part of the second surface which lies - * outside the first surface. - * @GTS_2_IN_1: identifies the part of the second surface which lies - * inside the first surface. - */ -typedef enum { GTS_1_OUT_2, - GTS_1_IN_2, - GTS_2_OUT_1, - GTS_2_IN_1 } GtsBooleanOperation; - -/** - * GTS_IS_SURFACE_INTER: - * @obj: a #GtsObject. - * - * Evaluates to %TRUE if @obj is a #GtsSurfaceInter, %FALSE otherwise. - */ -#define GTS_IS_SURFACE_INTER(obj) (gts_object_is_from_class (obj,\ - gts_surface_inter_class ())) -/** - * GTS_SURFACE_INTER: - * @obj: a descendant of #GtsSurfaceInter. - * - * Casts @obj to #GtsSurfaceInter. - */ -#define GTS_SURFACE_INTER(obj) GTS_OBJECT_CAST (obj,\ - GtsSurfaceInter,\ - gts_surface_inter_class ()) -/** - * GTS_SURFACE_INTER_CLASS: - * @klass: a descendant of #GtsSurfaceInterClass. - * - * Casts @klass to #GtsSurfaceInterClass. - */ -#define GTS_SURFACE_INTER_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsSurfaceInterClass,\ - gts_surface_inter_class ()) - -struct _GtsSurfaceInter { - GtsObject object; - - GtsSurface * s1; - GtsSurface * s2; - GSList * edges; -}; - -struct _GtsSurfaceInterClass { - GtsObjectClass parent_class; -}; - -GtsSurfaceInterClass * -gts_surface_inter_class (void); -GtsSurfaceInter * -gts_surface_inter_new (GtsSurfaceInterClass * klass, - GtsSurface * s1, - GtsSurface * s2, - GNode * faces_tree1, - GNode * faces_tree2, - gboolean is_open1, - gboolean is_open2); -gboolean -gts_surface_inter_check (GtsSurfaceInter * si, - gboolean * closed); -void -gts_surface_inter_boolean (GtsSurfaceInter * si, - GtsSurface * surface, - GtsBooleanOperation op); -gboolean gts_surface_foreach_intersecting_face (GtsSurface * s, - GtsBBTreeTraverseFunc func, - gpointer data); -GtsSurface * -gts_surface_is_self_intersecting (GtsSurface * s); - -/* Binary Heap: heap.c */ - -typedef struct _GtsHeap GtsHeap; - -GtsHeap * gts_heap_new (GCompareFunc compare_func); -void gts_heap_insert (GtsHeap * heap, gpointer p); -gpointer gts_heap_remove_top (GtsHeap * heap); -gpointer gts_heap_top (GtsHeap * heap); -void gts_heap_thaw (GtsHeap * heap); -void gts_heap_foreach (GtsHeap * heap, - GFunc func, - gpointer user_data); -void gts_heap_freeze (GtsHeap * heap); -guint gts_heap_size (GtsHeap * heap); -void gts_heap_destroy (GtsHeap * heap); - -/* Extended Binary Heap: eheap.c */ - -typedef struct _GtsEHeap GtsEHeap; -typedef struct _GtsEHeapPair GtsEHeapPair; - -struct _GtsEHeap { - GPtrArray * elts; - GtsKeyFunc func; - gpointer data; - gboolean frozen, randomized; -}; - -/** - * _GtsEHeapPair: - * @data: Points to the item stored in the heap. - * @key: Value of the key for this item. - * @pos: Private field. - */ -struct _GtsEHeapPair { - gpointer data; - gdouble key; - guint pos; -}; - -GtsEHeap * gts_eheap_new (GtsKeyFunc key_func, - gpointer data); -GtsEHeapPair * gts_eheap_insert (GtsEHeap * heap, - gpointer p); -GtsEHeapPair * gts_eheap_insert_with_key (GtsEHeap * heap, - gpointer p, - gdouble key); -gpointer gts_eheap_remove_top (GtsEHeap * heap, - gdouble * key); -gpointer gts_eheap_top (GtsEHeap * heap, - gdouble * key); -void gts_eheap_thaw (GtsEHeap * heap); -void gts_eheap_foreach (GtsEHeap * heap, - GFunc func, - gpointer data); -gpointer gts_eheap_remove (GtsEHeap * heap, - GtsEHeapPair * p); -void gts_eheap_decrease_key (GtsEHeap * heap, - GtsEHeapPair * p, - gdouble new_key); -void gts_eheap_freeze (GtsEHeap * heap); -guint gts_eheap_size (GtsEHeap * heap); -void gts_eheap_update (GtsEHeap * heap); -gdouble gts_eheap_key (GtsEHeap * heap, - gpointer p); -void gts_eheap_randomized (GtsEHeap * heap, - gboolean randomized); -void gts_eheap_destroy (GtsEHeap * heap); - -/* FIFO queues: fifo.c */ - -typedef struct _GtsFifo GtsFifo; - -GtsFifo * gts_fifo_new (void); -void gts_fifo_write (GtsFifo * fifo, - FILE * fp); -void gts_fifo_push (GtsFifo * fifo, - gpointer data); -gpointer gts_fifo_pop (GtsFifo * fifo); -gpointer gts_fifo_top (GtsFifo * fifo); -guint gts_fifo_size (GtsFifo * fifo); -gboolean gts_fifo_is_empty (GtsFifo * fifo); -void gts_fifo_foreach (GtsFifo * fifo, - GtsFunc func, - gpointer data); -void gts_fifo_reverse (GtsFifo * fifo); -void gts_fifo_destroy (GtsFifo * fifo); - -/* Progressive surfaces */ - -/* split.c */ - -typedef struct _GtsSplit GtsSplit; -typedef struct _GtsSplitClass GtsSplitClass; -typedef struct _GtsSplitCFace GtsSplitCFace; - -struct _GtsSplit { - GtsObject object; - - GtsVertex * v; - GtsObject * v1; - GtsObject * v2; - GtsSplitCFace * cfaces; - guint ncf; -}; - -struct _GtsSplitClass { - GtsObjectClass parent_class; -}; - -#define GTS_IS_SPLIT(obj) (gts_object_is_from_class (obj,\ - gts_split_class ())) -#define GTS_SPLIT(obj) GTS_OBJECT_CAST (obj,\ - GtsSplit,\ - gts_split_class ()) -#define GTS_SPLIT_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsSplitClass,\ - gts_split_class ()) -#define GTS_SPLIT_V1(vs) (GTS_IS_SPLIT ((vs)->v1) ?\ - GTS_SPLIT ((vs)->v1)->v :\ - GTS_VERTEX ((vs)->v1)) -#define GTS_SPLIT_V2(vs) (GTS_IS_SPLIT ((vs)->v2) ?\ - GTS_SPLIT ((vs)->v2)->v :\ - GTS_VERTEX ((vs)->v2)) - -GtsSplitClass * gts_split_class (void); -GtsSplit * gts_split_new (GtsSplitClass * klass, - GtsVertex * v, - GtsObject * o1, - GtsObject * o2); -void gts_split_collapse (GtsSplit * vs, - GtsEdgeClass * klass, - GtsEHeap * heap); -void gts_split_expand (GtsSplit * vs, - GtsSurface * s, - GtsEdgeClass * klass); -typedef gboolean (*GtsSplitTraverseFunc) (GtsSplit * vs, - gpointer data); -void gts_split_traverse (GtsSplit * root, - GTraverseType order, - gint depth, - GtsSplitTraverseFunc func, - gpointer data); -guint gts_split_height (GtsSplit * root); - -/* psurface.c */ - -typedef struct _GtsPSurface GtsPSurface; -typedef struct _GtsPSurfaceClass GtsPSurfaceClass; - -struct _GtsPSurface { - GtsObject object; - - GtsSurface * s; - GPtrArray * split; - GtsSplitClass * split_class; - guint pos, min; - - GPtrArray * vertices; - GPtrArray * faces; -}; - -struct _GtsPSurfaceClass { - GtsObjectClass parent_class; -}; - -#define GTS_IS_PSURFACE(obj) (gts_object_is_from_class (obj,\ - gts_psurface_class ())) -#define GTS_PSURFACE(obj) GTS_OBJECT_CAST (obj,\ - GtsPSurface,\ - gts_psurface_class ()) -#define GTS_PSURFACE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsPSurfaceClass,\ - gts_psurface_class ()) -#define GTS_PSURFACE_IS_CLOSED(ps) (!(ps)->vertices) - -GtsPSurfaceClass * gts_psurface_class (void); -GtsPSurface * gts_psurface_new (GtsPSurfaceClass * klass, - GtsSurface * surface, - GtsSplitClass * split_class, - GtsKeyFunc cost_func, - gpointer cost_data, - GtsCoarsenFunc coarsen_func, - gpointer coarsen_data, - GtsStopFunc stop_func, - gpointer stop_data, - gdouble minangle); -GtsSplit * gts_psurface_add_vertex (GtsPSurface * ps); -GtsSplit * gts_psurface_remove_vertex (GtsPSurface * ps); -guint gts_psurface_max_vertex_number (GtsPSurface * ps); -guint gts_psurface_min_vertex_number (GtsPSurface * ps); -void gts_psurface_set_vertex_number (GtsPSurface * ps, - guint n); -guint gts_psurface_get_vertex_number (GtsPSurface * ps); -void gts_psurface_write (GtsPSurface * ps, - FILE * fptr); -GtsPSurface * gts_psurface_open (GtsPSurfaceClass * klass, - GtsSurface * s, - GtsSplitClass * split_class, - GtsFile * f); -GtsSplit * gts_psurface_read_vertex (GtsPSurface * ps, - GtsFile * fp); -void gts_psurface_close (GtsPSurface * ps); -void gts_psurface_foreach_vertex (GtsPSurface * ps, - GtsFunc func, - gpointer data); - -/* hsurface.c */ - -typedef struct _GtsHSplit GtsHSplit; -typedef struct _GtsHSplitClass GtsHSplitClass; -typedef struct _GtsHSurface GtsHSurface; -typedef struct _GtsHSurfaceClass GtsHSurfaceClass; - -struct _GtsHSplit { - GtsSplit split; - - GtsEHeapPair * index; - GtsHSplit * parent; - guint nchild; -}; - -struct _GtsHSplitClass { - GtsSplitClass parent_class; -}; - -#define GTS_IS_HSPLIT(obj) (gts_object_is_from_class (obj,\ - gts_hsplit_class ())) -#define GTS_HSPLIT(obj) GTS_OBJECT_CAST (obj,\ - GtsHSplit,\ - gts_hsplit_class ()) -#define GTS_HSPLIT_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsHSplitClass,\ - gts_hsplit_class ()) - -GtsHSplitClass * gts_hsplit_class (void); -GtsHSplit * gts_hsplit_new (GtsHSplitClass * klass, - GtsSplit * vs); -void gts_hsplit_collapse (GtsHSplit * hs, - GtsHSurface * hsurface); -void gts_hsplit_expand (GtsHSplit * hs, - GtsHSurface * hsurface); -void gts_hsplit_force_expand (GtsHSplit * hs, - GtsHSurface * hsurface); - -struct _GtsHSurface { - GtsObject object; - - GtsSurface * s; - GSList * roots; - GtsEHeap * expandable; - GtsEHeap * collapsable; - GPtrArray * split; - guint nvertex; -}; - -struct _GtsHSurfaceClass { - GtsObjectClass parent_class; -}; - -#define GTS_IS_HSURFACE(obj) (gts_object_is_from_class (obj,\ - gts_hsurface_class ())) -#define GTS_HSURFACE(obj) GTS_OBJECT_CAST (obj,\ - GtsHSurface,\ - gts_hsurface_class ()) -#define GTS_HSURFACE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsHSurfaceClass,\ - gts_hsurface_class ()) - -GtsHSurfaceClass * gts_hsurface_class (void); -GtsHSurface * gts_hsurface_new (GtsHSurfaceClass * klass, - GtsHSplitClass * hsplit_class, - GtsPSurface * psurface, - GtsKeyFunc expand_key, - gpointer expand_data, - GtsKeyFunc collapse_key, - gpointer collapse_data); -void gts_hsurface_traverse (GtsHSurface * hsurface, - GTraverseType order, - gint depth, - GtsSplitTraverseFunc func, - gpointer data); -void gts_hsurface_foreach (GtsHSurface * hsurface, - GTraverseType order, - GtsFunc func, - gpointer data); -guint gts_hsurface_height (GtsHSurface * hsurface); - -/* Constrained Delaunay triangulation: cdt.c */ - -/** - * GTS_IS_CONSTRAINT: - * @obj: a #GtsObject. - * - * Evaluates to %TRUE if @obj is a #GtsConstraint, %FALSE otherwise. - */ -#define GTS_IS_CONSTRAINT(obj) (gts_object_is_from_class (obj,\ - gts_constraint_class ())) -/** - * GTS_CONSTRAINT: - * @obj: a descendant of #GtsConstraint. - * - * Casts @obj to #GtsConstraint. - */ -#define GTS_CONSTRAINT(obj) GTS_OBJECT_CAST (obj,\ - GtsConstraint,\ - gts_constraint_class ()) -/** - * GTS_CONSTRAINT_CLASS: - * @klass: a desscendant of #GtsConstraintClass. - * - * Casts @klass to #GtsConstraintClass. - */ -#define GTS_CONSTRAINT_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsConstraintClass,\ - gts_constraint_class ()) - -struct _GtsConstraint { - GtsEdge edge; -}; - -struct _GtsConstraintClass { - GtsEdgeClass parent_class; -}; - -typedef struct _GtsConstraint GtsConstraint; -typedef struct _GtsConstraintClass GtsConstraintClass; - -GtsConstraintClass * gts_constraint_class (void); - -GtsFace * gts_point_locate (GtsPoint * p, - GtsSurface * surface, - GtsFace * guess); -GtsVertex * gts_delaunay_add_vertex_to_face (GtsSurface * surface, - GtsVertex * v, - GtsFace * f); -GtsVertex * gts_delaunay_add_vertex (GtsSurface * surface, - GtsVertex * v, - GtsFace * guess); -void gts_delaunay_remove_vertex (GtsSurface * surface, - GtsVertex * v); -GtsFace * gts_delaunay_check (GtsSurface * surface); -GSList * gts_delaunay_add_constraint (GtsSurface * surface, - GtsConstraint * c); -void gts_delaunay_remove_hull (GtsSurface * surface); - -/* GtsListFace: Header */ - -typedef struct _GtsListFace GtsListFace; - -struct _GtsListFace { - /*< private >*/ - GtsFace parent; - - /*< public >*/ - GSList * points; -}; - -#define GTS_LIST_FACE(obj) GTS_OBJECT_CAST (obj,\ - GtsListFace,\ - gts_list_face_class ()) -#define GTS_IS_LIST_FACE(obj) (gts_object_is_from_class (obj,\ - gts_list_face_class ())) - -GtsFaceClass * gts_list_face_class (void); - -/* Constrained Delaunay refinement: refine.c */ - -typedef gboolean (* GtsEncroachFunc) (GtsVertex * v, - GtsEdge * e, - GtsSurface * s, - gpointer data); - -gboolean gts_vertex_encroaches_edge (GtsVertex * v, - GtsEdge * e); -GtsVertex * gts_edge_is_encroached (GtsEdge * e, - GtsSurface * s, - GtsEncroachFunc encroaches, - gpointer data); -guint gts_delaunay_conform (GtsSurface * surface, - gint steiner_max, - GtsEncroachFunc encroaches, - gpointer data); -guint gts_delaunay_refine (GtsSurface * surface, - gint steiner_max, - GtsEncroachFunc encroaches, - gpointer encroach_data, - GtsKeyFunc cost, - gpointer cost_data); - -/* Isosurfaces (marching cubes): iso.c */ - -typedef struct _GtsGridPlane GtsGridPlane; -typedef struct _GtsIsoSlice GtsIsoSlice; -typedef struct _GtsCartesianGrid GtsCartesianGrid; - -struct _GtsGridPlane { - GtsPoint ** p; - guint nx, ny; -}; - -struct _GtsCartesianGrid { - guint nx, ny, nz; - gdouble x, dx, y, dy, z, dz; -}; - -typedef void (*GtsIsoCartesianFunc) (gdouble ** a, - GtsCartesianGrid g, - guint i, - gpointer data); - -GtsGridPlane * gts_grid_plane_new (guint nx, - guint ny); -void gts_grid_plane_destroy (GtsGridPlane * g); -GtsIsoSlice * gts_iso_slice_new (guint nx, guint ny); -void gts_iso_slice_fill (GtsIsoSlice * slice, - GtsGridPlane * plane1, - GtsGridPlane * plane2, - gdouble ** f1, - gdouble ** f2, - gdouble iso, - GtsVertexClass * klass); -void gts_iso_slice_fill_cartesian (GtsIsoSlice * slice, - GtsCartesianGrid g, - gdouble ** f1, - gdouble ** f2, - gdouble iso, - GtsVertexClass * klass); -void gts_iso_slice_destroy (GtsIsoSlice * slice); -void gts_isosurface_slice (GtsIsoSlice * slice1, - GtsIsoSlice * slice2, - GtsSurface * surface); -void gts_isosurface_cartesian (GtsSurface * surface, - GtsCartesianGrid g, - GtsIsoCartesianFunc f, - gpointer data, - gdouble iso); - -/* Isosurfaces (marching tetrahedra): isotetra.c */ - -void gts_isosurface_tetra (GtsSurface * surface, - GtsCartesianGrid g, - GtsIsoCartesianFunc f, - gpointer data, - gdouble iso); -void gts_isosurface_tetra_bcl (GtsSurface * surface, - GtsCartesianGrid g, - GtsIsoCartesianFunc f, - gpointer data, - gdouble iso); -void gts_isosurface_tetra_bounded (GtsSurface * surface, - GtsCartesianGrid g, - GtsIsoCartesianFunc f, - gpointer data, - gdouble iso); - -/* Named vertices, edges and triangles: named.c */ - -#define GTS_NAME_LENGTH 40 - -#define GTS_NVERTEX(obj) GTS_OBJECT_CAST (obj,\ - GtsNVertex,\ - gts_nvertex_class ()) -#define GTS_NVERTEX_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsNVertexClass,\ - gts_nvertex_class()) -#define GTS_IS_NVERTEX(obj) (gts_object_is_from_class (obj,\ - gts_nvertex_class ())) - -typedef struct _GtsNVertex GtsNVertex; -typedef struct _GtsNVertexClass GtsNVertexClass; - -struct _GtsNVertex { - GtsVertex parent; - char name[GTS_NAME_LENGTH]; -}; - -struct _GtsNVertexClass { - GtsVertexClass parent_class; -}; - -GtsNVertexClass * gts_nvertex_class (void); - -#define GTS_NEDGE(obj) GTS_OBJECT_CAST (obj,\ - GtsNEdge,\ - gts_nedge_class ()) -#define GTS_NEDGE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsNEdgeClass,\ - gts_nedge_class()) -#define GTS_IS_NEDGE(obj) (gts_object_is_from_class (obj,\ - gts_nedge_class ())) - -typedef struct _GtsNEdge GtsNEdge; -typedef struct _GtsNEdgeClass GtsNEdgeClass; - -struct _GtsNEdge { - GtsEdge parent; - char name[GTS_NAME_LENGTH]; -}; - -struct _GtsNEdgeClass { - GtsEdgeClass parent_class; -}; - -GtsNEdgeClass * gts_nedge_class (void); - -#define GTS_NFACE(obj) GTS_OBJECT_CAST (obj,\ - GtsNFace,\ - gts_nface_class ()) -#define GTS_NFACE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsNFaceClass,\ - gts_nface_class()) -#define GTS_IS_NFACE(obj) (gts_object_is_from_class (obj,\ - gts_nface_class ())) - -typedef struct _GtsNFace GtsNFace; -typedef struct _GtsNFaceClass GtsNFaceClass; - -struct _GtsNFace { - GtsFace parent; - char name[GTS_NAME_LENGTH]; -}; - -struct _GtsNFaceClass { - GtsFaceClass parent_class; -}; - -GtsNFaceClass * gts_nface_class (void); - -/* Cluster object for out-of-core simplification: oocs.c */ - -#define GTS_CLUSTER(obj) GTS_OBJECT_CAST (obj,\ - GtsCluster,\ - gts_cluster_class ()) -#define GTS_CLUSTER_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsClusterClass,\ - gts_cluster_class()) -#define GTS_IS_CLUSTER(obj) (gts_object_is_from_class (obj,\ - gts_cluster_class ())) - -typedef struct _GtsCluster GtsCluster; -typedef struct _GtsClusterClass GtsClusterClass; -typedef struct _GtsClusterId GtsClusterId; - -struct _GtsClusterId { - guint x, y, z; -}; - -struct _GtsCluster { - GtsObject parent; - - GtsClusterId id; - GtsVertex * v; - guint n; -}; - -struct _GtsClusterClass { - GtsObjectClass parent_class; - - void (* add) (GtsCluster * c, GtsPoint * p, gpointer data); - void (* update) (GtsCluster * c); -}; - -GtsClusterClass * gts_cluster_class (void); -GtsCluster * gts_cluster_new (GtsClusterClass * klass, - GtsClusterId id, - GtsVertexClass * vklass); -void gts_cluster_add (GtsCluster * c, - GtsPoint * p, - gpointer data); -void gts_cluster_update (GtsCluster * c); - -/* Cluster group object for out-of-core simplification: oocs.c */ - -#define GTS_CLUSTER_GRID(obj) GTS_OBJECT_CAST (obj,\ - GtsClusterGrid,\ - gts_cluster_grid_class ()) -#define GTS_CLUSTER_GRID_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsClusterGridClass,\ - gts_cluster_grid_class()) -#define GTS_IS_CLUSTER_GRID(obj) (gts_object_is_from_class (obj,\ - gts_cluster_grid_class ())) - -typedef struct _GtsClusterGrid GtsClusterGrid; -typedef struct _GtsClusterGridClass GtsClusterGridClass; - -struct _GtsClusterGrid { - GtsObject parent; - - GtsSurface * surface; - GtsBBox * bbox; - GtsVector size; - - GtsClusterClass * cluster_class; - GHashTable * clusters; -}; - -struct _GtsClusterGridClass { - GtsObjectClass parent_class; -}; - -GtsClusterGridClass * gts_cluster_grid_class (void); -GtsClusterGrid * gts_cluster_grid_new (GtsClusterGridClass * klass, - GtsClusterClass * cluster_class, - GtsSurface * s, - GtsBBox * bbox, - gdouble delta); -void gts_cluster_grid_add_triangle (GtsClusterGrid * cluster_grid, - GtsPoint * p1, - GtsPoint * p2, - GtsPoint * p3, - gpointer data); -GtsRange gts_cluster_grid_update (GtsClusterGrid * cluster_grid); - -/* Triangle strip generation: stripe.c */ -GSList * gts_surface_strip (GtsSurface * s); - -/* GtsContainee: container.c */ - -typedef struct _GtsContainee GtsContainee; -typedef struct _GtsContaineeClass GtsContaineeClass; -typedef struct _GtsContainer GtsContainer; -typedef struct _GtsContainerClass GtsContainerClass; - -struct _GtsContainee { - GtsObject object; -}; - -struct _GtsContaineeClass { - GtsObjectClass parent_class; - - void (* add_container) (GtsContainee *, GtsContainer *); - void (* remove_container) (GtsContainee *, GtsContainer *); - void (* foreach) (GtsContainee *, GtsFunc, gpointer); - gboolean (* is_contained) (GtsContainee *, GtsContainer *); - void (* replace) (GtsContainee *, GtsContainee *); -}; - -#define GTS_CONTAINEE(obj) GTS_OBJECT_CAST (obj,\ - GtsContainee,\ - gts_containee_class ()) -#define GTS_CONTAINEE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsContaineeClass,\ - gts_containee_class()) -#define GTS_IS_CONTAINEE(obj) (gts_object_is_from_class (obj,\ - gts_containee_class ())) - -GtsContaineeClass * gts_containee_class (void); -GtsContainee * gts_containee_new (GtsContaineeClass * klass); -gboolean gts_containee_is_contained (GtsContainee * item, - GtsContainer * c); -void gts_containee_replace (GtsContainee * item, - GtsContainee * with); - -/* GtsSListContainee: container.c */ - -typedef struct _GtsSListContainee GtsSListContainee; -typedef struct _GtsSListContaineeClass GtsSListContaineeClass; - -struct _GtsSListContainee { - GtsContainee containee; - - GSList * containers; -}; - -struct _GtsSListContaineeClass { - GtsContaineeClass parent_class; -}; - -#define GTS_SLIST_CONTAINEE(obj) GTS_OBJECT_CAST (obj,\ - GtsSListContainee,\ - gts_slist_containee_class ()) -#define GTS_SLIST_CONTAINEE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsSListContaineeClass,\ - gts_slist_containee_class()) -#define GTS_IS_SLIST_CONTAINEE(obj) (gts_object_is_from_class (obj,\ - gts_slist_containee_class ())) - -GtsSListContaineeClass * gts_slist_containee_class (void); - -/* GtsContainer: container.c */ - -struct _GtsContainer { - GtsSListContainee object; -}; - -struct _GtsContainerClass { - GtsSListContaineeClass parent_class; - - void (* add) (GtsContainer *, GtsContainee *); - void (* remove) (GtsContainer *, GtsContainee *); - void (* foreach) (GtsContainer *, GtsFunc, gpointer); - guint (* size) (GtsContainer *); -}; - -#define GTS_CONTAINER(obj) GTS_OBJECT_CAST (obj,\ - GtsContainer,\ - gts_container_class ()) -#define GTS_CONTAINER_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsContainerClass,\ - gts_container_class()) -#define GTS_IS_CONTAINER(obj) (gts_object_is_from_class (obj,\ - gts_container_class ())) - -GtsContainerClass * gts_container_class (void); -GtsContainer * gts_container_new (GtsContainerClass * klass); -void gts_container_add (GtsContainer * c, - GtsContainee * item); -void gts_container_remove (GtsContainer * c, - GtsContainee * item); -void gts_container_foreach (GtsContainer * c, - GtsFunc func, - gpointer data); -guint gts_container_size (GtsContainer * c); - -/* GtsHashContainer: container.c */ - -typedef struct _GtsHashContainer GtsHashContainer; -typedef struct _GtsHashContainerClass GtsHashContainerClass; - -struct _GtsHashContainer { - GtsContainer c; - - GHashTable * items; - gboolean frozen; -}; - -struct _GtsHashContainerClass { - GtsContainerClass parent_class; -}; - -#define GTS_HASH_CONTAINER(obj) GTS_OBJECT_CAST (obj,\ - GtsHashContainer,\ - gts_hash_container_class ()) -#define GTS_HASH_CONTAINER_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsHashContainerClass,\ - gts_hash_container_class()) -#define GTS_IS_HASH_CONTAINER(obj) (gts_object_is_from_class (obj,\ - gts_hash_container_class ())) - -GtsHashContainerClass * gts_hash_container_class (void); - -/* GtsSListContainer: container.c */ - -typedef struct _GtsSListContainer GtsSListContainer; -typedef struct _GtsSListContainerClass GtsSListContainerClass; - -struct _GtsSListContainer { - GtsContainer c; - - GSList * items; - gboolean frozen; -}; - -struct _GtsSListContainerClass { - GtsContainerClass parent_class; -}; - -#define GTS_SLIST_CONTAINER(obj) GTS_OBJECT_CAST (obj,\ - GtsSListContainer,\ - gts_slist_container_class ()) -#define GTS_SLIST_CONTAINER_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsSListContainerClass,\ - gts_slist_container_class()) -#define GTS_IS_SLIST_CONTAINER(obj) (gts_object_is_from_class (obj,\ - gts_slist_container_class ())) - -GtsSListContainerClass * gts_slist_container_class (void); - -/* GtsGNode: graph.c */ - -typedef struct _GtsGNode GtsGNode; -typedef struct _GtsGNodeClass GtsGNodeClass; -typedef struct _GtsGraph GtsGraph; -typedef struct _GtsGraphClass GtsGraphClass; - -struct _GtsGNode { - GtsSListContainer container; - - guint level; -}; - -struct _GtsGNodeClass { - GtsSListContainerClass parent_class; - - gfloat (* weight) (GtsGNode *); - void (* write) (GtsGNode *, FILE *); -}; - -#define GTS_GNODE(obj) GTS_OBJECT_CAST (obj,\ - GtsGNode,\ - gts_gnode_class ()) -#define GTS_GNODE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsGNodeClass,\ - gts_gnode_class()) -#define GTS_IS_GNODE(obj) (gts_object_is_from_class (obj,\ - gts_gnode_class ())) -#define GTS_GNODE_NEIGHBOR(n,e) (GTS_GEDGE (e)->n1 == n ? GTS_GEDGE (e)->n2 : GTS_GEDGE (e)->n2 == n ? GTS_GEDGE (e)->n1 : NULL) - -GtsGNodeClass * gts_gnode_class (void); -GtsGNode * gts_gnode_new (GtsGNodeClass * klass); -void gts_gnode_foreach_neighbor (GtsGNode * n, - GtsGraph * g, - GtsFunc func, - gpointer data); -void gts_gnode_foreach_edge (GtsGNode * n, - GtsGraph * g, - GtsFunc func, - gpointer data); -guint gts_gnode_degree (GtsGNode * n, - GtsGraph * g); -gfloat gts_gnode_move_cost (GtsGNode * n, - GtsGraph * src, - GtsGraph * dst); -gfloat gts_gnode_weight (GtsGNode * n); - -GTS_C_VAR -gboolean gts_allow_floating_gnodes; - -/* GtsNGNode: graph.c */ - -typedef struct _GtsNGNode GtsNGNode; -typedef struct _GtsNGNodeClass GtsNGNodeClass; - -struct _GtsNGNode { - GtsGNode node; - - guint id; -}; - -struct _GtsNGNodeClass { - GtsGNodeClass parent_class; -}; - -#define GTS_NGNODE(obj) GTS_OBJECT_CAST (obj,\ - GtsNGNode,\ - gts_ngnode_class ()) -#define GTS_NGNODE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsNGNodeClass,\ - gts_ngnode_class()) -#define GTS_IS_NGNODE(obj) (gts_object_is_from_class (obj,\ - gts_ngnode_class ())) - -GtsNGNodeClass * gts_ngnode_class (void); -GtsNGNode * gts_ngnode_new (GtsNGNodeClass * klass, - guint id); - -/* GtsWGNode: graph.c */ - -typedef struct _GtsWGNode GtsWGNode; -typedef struct _GtsWGNodeClass GtsWGNodeClass; - -struct _GtsWGNode { - GtsGNode node; - - gfloat weight; -}; - -struct _GtsWGNodeClass { - GtsGNodeClass parent_class; -}; - -#define GTS_WGNODE(obj) GTS_OBJECT_CAST (obj,\ - GtsWGNode,\ - gts_wgnode_class ()) -#define GTS_WGNODE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsWGNodeClass,\ - gts_wgnode_class()) -#define GTS_IS_WGNODE(obj) (gts_object_is_from_class (obj,\ - gts_wgnode_class ())) - -GtsWGNodeClass * gts_wgnode_class (void); -GtsWGNode * gts_wgnode_new (GtsWGNodeClass * klass, - gfloat weight); - -/* GtsPNode */ - -typedef struct _GtsPNode GtsPNode; -typedef struct _GtsPNodeClass GtsPNodeClass; - -struct _GtsPNode { - GtsGNode node; - - gpointer data; -}; - -struct _GtsPNodeClass { - GtsGNodeClass parent_class; -}; - -#define GTS_PNODE(obj) GTS_OBJECT_CAST (obj,\ - GtsPNode,\ - gts_pnode_class ()) -#define GTS_PNODE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsPNodeClass,\ - gts_pnode_class()) -#define GTS_IS_PNODE(obj) (gts_object_is_from_class (obj,\ - gts_pnode_class ())) - -GtsPNodeClass * gts_pnode_class (void); -GtsPNode * gts_pnode_new (GtsPNodeClass * klass, - gpointer data); - -/* GtsFNode */ - -typedef struct _GtsFNode GtsFNode; -typedef struct _GtsFNodeClass GtsFNodeClass; - -struct _GtsFNode { - GtsGNode node; - - GtsFace * f; -}; - -struct _GtsFNodeClass { - GtsGNodeClass parent_class; -}; - -#define GTS_FNODE(obj) GTS_OBJECT_CAST (obj,\ - GtsFNode,\ - gts_fnode_class ()) -#define GTS_FNODE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsFNodeClass,\ - gts_fnode_class()) -#define GTS_IS_FNODE(obj) (gts_object_is_from_class (obj,\ - gts_fnode_class ())) - -GtsFNodeClass * gts_fnode_class (void); -GtsFNode * gts_fnode_new (GtsFNodeClass * klass, - GtsFace * f); - -/* GtsGEdge: graph.c */ - -typedef struct _GtsGEdge GtsGEdge; -typedef struct _GtsGEdgeClass GtsGEdgeClass; - -struct _GtsGEdge { - GtsContainee containee; - - GtsGNode * n1; - GtsGNode * n2; -}; - -struct _GtsGEdgeClass { - GtsContaineeClass parent_class; - - GtsGEdge * (* link) (GtsGEdge * e, GtsGNode * n1, GtsGNode * n2); - gfloat (* weight) (GtsGEdge * e); - void (* write) (GtsGEdge * e, FILE * fp); -}; - -#define GTS_GEDGE(obj) GTS_OBJECT_CAST (obj,\ - GtsGEdge,\ - gts_gedge_class ()) -#define GTS_GEDGE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsGEdgeClass,\ - gts_gedge_class()) -#define GTS_IS_GEDGE(obj) (gts_object_is_from_class (obj,\ - gts_gedge_class ())) - -GtsGEdgeClass * gts_gedge_class (void); -GtsGEdge * gts_gedge_new (GtsGEdgeClass * klass, - GtsGNode * n1, - GtsGNode * n2); -gfloat gts_gedge_weight (GtsGEdge * e); -#define gts_gedge_connects(e, a1, a2)\ - (((e)->n1 == a1 && (e)->n2 == a2) || ((e)->n1 == a2 && (e)->n2 == a1)) - -/* GtsPGEdge: graph.c */ - -typedef struct _GtsPGEdge GtsPGEdge; -typedef struct _GtsPGEdgeClass GtsPGEdgeClass; - -struct _GtsPGEdge { - GtsGEdge gedge; - - gpointer data; -}; - -struct _GtsPGEdgeClass { - GtsGEdgeClass parent_class; -}; - -#define GTS_PGEDGE(obj) GTS_OBJECT_CAST (obj,\ - GtsPGEdge,\ - gts_pgedge_class ()) -#define GTS_PGEDGE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsPGEdgeClass,\ - gts_pgedge_class()) -#define GTS_IS_PGEDGE(obj) (gts_object_is_from_class (obj,\ - gts_pgedge_class ())) - -GtsPGEdgeClass * gts_pgedge_class (void); -GtsPGEdge * gts_pgedge_new (GtsPGEdgeClass * klass, - GtsGNode * n1, - GtsGNode * n2, - gpointer data); - -/* GtsWGEdge: graph.c */ - -typedef struct _GtsWGEdge GtsWGEdge; -typedef struct _GtsWGEdgeClass GtsWGEdgeClass; - -struct _GtsWGEdge { - GtsGEdge gedge; - - gfloat weight; -}; - -struct _GtsWGEdgeClass { - GtsGEdgeClass parent_class; -}; - -#define GTS_WGEDGE(obj) GTS_OBJECT_CAST (obj,\ - GtsWGEdge,\ - gts_wgedge_class ()) -#define GTS_WGEDGE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsWGEdgeClass,\ - gts_wgedge_class()) -#define GTS_IS_WGEDGE(obj) (gts_object_is_from_class (obj,\ - gts_wgedge_class ())) - -GtsWGEdgeClass * gts_wgedge_class (void); -GtsWGEdge * gts_wgedge_new (GtsWGEdgeClass * klass, - GtsGNode * n1, - GtsGNode * n2, - gfloat weight); - -/* GtsGraph: graph.c */ - -struct _GtsGraph { - GtsHashContainer object; - - GtsGraphClass * graph_class; - GtsGNodeClass * node_class; - GtsGEdgeClass * edge_class; -}; - -struct _GtsGraphClass { - GtsHashContainerClass parent_class; - - gfloat (* weight) (GtsGraph *); -}; - -#define GTS_GRAPH(obj) GTS_OBJECT_CAST (obj,\ - GtsGraph,\ - gts_graph_class ()) -#define GTS_GRAPH_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsGraphClass,\ - gts_graph_class()) -#define GTS_IS_GRAPH(obj) (gts_object_is_from_class (obj,\ - gts_graph_class ())) - -GtsGraphClass * gts_graph_class (void); -GtsGraph * gts_graph_new (GtsGraphClass * klass, - GtsGNodeClass * node_class, - GtsGEdgeClass * edge_class); -void gts_graph_print_stats (GtsGraph * g, - FILE * fp); -typedef struct _GtsGraphTraverse GtsGraphTraverse; -typedef enum { GTS_BREADTH_FIRST - } GtsTraverseType; -GtsGraphTraverse * gts_graph_traverse_new (GtsGraph * g, - GtsGNode * n, - GtsTraverseType type, - gboolean reinit); -GtsGNode * gts_graph_traverse_next (GtsGraphTraverse * t); -GtsGNode * gts_graph_traverse_what_next (GtsGraphTraverse * t); -void gts_graph_traverse_destroy (GtsGraphTraverse * t); -void gts_graph_foreach_edge (GtsGraph * g, - GtsFunc func, - gpointer data); -gfloat gts_graph_weight (GtsGraph * g); -guint gts_graph_distance_sum (GtsGraph * g, - GtsGNode * center); -GtsGNode * gts_graph_farthest (GtsGraph * g, - GSList * gnodes); -guint gts_graph_edges_cut (GtsGraph * g); -gfloat gts_graph_edges_cut_weight (GtsGraph * g); -void gts_graph_write (GtsGraph * g, - FILE * fp); -void gts_graph_write_dot (GtsGraph * g, - FILE * fp); -GtsGraph * gts_graph_read (GtsFile * fp); -guint gts_graph_read_jostle (GtsGraph * g, - GtsFile * fp); - -/* GtsWGraph: graph.c */ - -typedef struct _GtsWGraph GtsWGraph; -typedef struct _GtsWGraphClass GtsWGraphClass; - -struct _GtsWGraph { - GtsGraph graph; - - gfloat weight; -}; - -struct _GtsWGraphClass { - GtsGraphClass parent_class; -}; - -#define GTS_WGRAPH(obj) GTS_OBJECT_CAST (obj,\ - GtsWGraph,\ - gts_wgraph_class ()) -#define GTS_WGRAPH_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsWGraphClass,\ - gts_wgraph_class()) -#define GTS_IS_WGRAPH(obj) (gts_object_is_from_class (obj,\ - gts_wgraph_class ())) - -GtsWGraphClass * gts_wgraph_class (void); -gfloat gts_wgraph_weight_max (GtsWGraph * wg); - -/* Surface graph: graph.c */ - -GtsGraph * gts_surface_graph_new (GtsGraphClass * klass, - GtsSurface * s); -GtsSurface * gts_surface_graph_surface (GtsGraph * surface_graph, - GtsSurface * s); - -/* Segments graph: graph.c */ - -GtsGraph * gts_segments_graph_new (GtsGraphClass * klass, - GSList * segments); - -/* GtsGNodeSplit: pgraph.c */ - -typedef struct _GtsGNodeSplit GtsGNodeSplit; -typedef struct _GtsGNodeSplitClass GtsGNodeSplitClass; - -struct _GtsGNodeSplit { - GtsObject object; - - GtsGNode * n; - GtsObject * n1; - GtsObject * n2; -}; - -struct _GtsGNodeSplitClass { - GtsObjectClass parent_class; -}; - -#define GTS_GNODE_SPLIT(obj) GTS_OBJECT_CAST (obj,\ - GtsGNodeSplit,\ - gts_gnode_split_class ()) -#define GTS_GNODE_SPLIT_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsGNodeSplitClass,\ - gts_gnode_split_class()) -#define GTS_IS_GNODE_SPLIT(obj) (gts_object_is_from_class (obj,\ - gts_gnode_split_class ())) -#define GTS_GNODE_SPLIT_N1(ns) (GTS_IS_GNODE_SPLIT ((ns)->n1) ? GTS_GNODE_SPLIT ((ns)->n1)->n : GTS_GNODE ((ns)->n1)) -#define GTS_GNODE_SPLIT_N2(ns) (GTS_IS_GNODE_SPLIT ((ns)->n2) ? GTS_GNODE_SPLIT ((ns)->n2)->n : GTS_GNODE ((ns)->n2)) - -GtsGNodeSplitClass * gts_gnode_split_class (void); -GtsGNodeSplit * gts_gnode_split_new (GtsGNodeSplitClass * klass, - GtsGNode * n, - GtsObject * n1, - GtsObject * n2); -void gts_gnode_split_collapse (GtsGNodeSplit * ns, - GtsGraph * g, - GtsWGEdgeClass * klass); -void gts_gnode_split_expand (GtsGNodeSplit * ns, - GtsGraph * g); - -/* GtsPGraph: pgraph.c */ - -typedef struct _GtsPGraph GtsPGraph; -typedef struct _GtsPGraphClass GtsPGraphClass; - -struct _GtsPGraph { - GtsObject object; - - GtsGraph * g; - GPtrArray * split; - GArray * levels; - GtsGNodeSplitClass * split_class; - GtsWGEdgeClass * edge_class; - guint pos, min, level; -}; - -struct _GtsPGraphClass { - GtsObjectClass parent_class; -}; - -#define GTS_PGRAPH(obj) GTS_OBJECT_CAST (obj,\ - GtsPGraph,\ - gts_pgraph_class ()) -#define GTS_PGRAPH_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ - GtsPGraphClass,\ - gts_pgraph_class()) -#define GTS_IS_PGRAPH(obj) (gts_object_is_from_class (obj,\ - gts_pgraph_class ())) - -GtsPGraphClass * gts_pgraph_class (void); -GtsPGraph * gts_pgraph_new (GtsPGraphClass * klass, - GtsGraph * g, - GtsGNodeSplitClass * split_class, - GtsWGNodeClass * node_class, - GtsWGEdgeClass * edge_class, - guint min); -GtsGNodeSplit * gts_pgraph_add_node (GtsPGraph * pg); -GtsGNodeSplit * gts_pgraph_remove_node (GtsPGraph * pg); -void gts_pgraph_set_node_number (GtsPGraph *pg, - guint n); -guint gts_pgraph_get_node_number (GtsPGraph *pg); -guint gts_pgraph_min_node_number (GtsPGraph *pg); -guint gts_pgraph_max_node_number (GtsPGraph *pg); -void gts_pgraph_foreach_node (GtsPGraph *pg, - GtsFunc func, - gpointer data); -gboolean gts_pgraph_down (GtsPGraph * pg, - GtsFunc func, - gpointer data); -/* Graph partition: partition.c */ - -GSList * gts_graph_bubble_partition (GtsGraph * g, - guint np, - guint niter, - GtsFunc step_info, - gpointer data); -guint gts_graph_partition_edges_cut (GSList * partition); -gfloat gts_graph_partition_edges_cut_weight (GSList * partition); -void gts_graph_partition_print_stats (GSList * partition, - FILE * fp); -gfloat gts_graph_partition_balance (GSList * partition); -GSList * gts_graph_partition_clone (GSList * partition); -GSList * gts_graph_recursive_bisection (GtsWGraph * wg, - guint n, - guint ntry, - guint mmax, - guint nmin, - gfloat imbalance); -void gts_graph_partition_destroy (GSList * partition); - -/* Graph bisection: partition.c */ - -typedef struct _GtsGraphBisection GtsGraphBisection; - -struct _GtsGraphBisection { - GtsGraph * g; - GtsGraph * g1; - GtsGraph * g2; - GHashTable * bg1; - GHashTable * bg2; -}; - -gboolean gts_graph_bisection_check (GtsGraphBisection * bg); -GtsGraphBisection * gts_graph_ggg_bisection (GtsGraph * g, - guint ntry); -GtsGraphBisection * gts_graph_bfgg_bisection (GtsGraph * g, - guint ntry); -gdouble gts_graph_bisection_kl_refine (GtsGraphBisection * bg, - guint mmax); -gdouble gts_graph_bisection_bkl_refine (GtsGraphBisection * bg, - guint mmax, - gfloat imbalance); -GtsGraphBisection * gts_graph_bisection_new (GtsWGraph * wg, - guint ntry, - guint mmax, - guint nmin, - gfloat imbalance); -void gts_graph_bisection_destroy (GtsGraphBisection * bg, - gboolean destroy_graphs); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __GTS_H__ */ Index: trunk/src_3rd/gts/bbtree.c =================================================================== --- trunk/src_3rd/gts/bbtree.c (revision 6802) +++ trunk/src_3rd/gts/bbtree.c (nonexistent) @@ -1,1289 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include "gts.h" - -static void bbox_init (GtsBBox * bbox) -{ - bbox->bounded = NULL; -} - -/** - * gts_bbox_class: - * - * Returns: the #GtsBBoxClass. - */ -GtsBBoxClass * gts_bbox_class (void) -{ - static GtsBBoxClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo bbox_info = { - "GtsBBox", - sizeof (GtsBBox), - sizeof (GtsBBoxClass), - (GtsObjectClassInitFunc) NULL, - (GtsObjectInitFunc) bbox_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (gts_object_class (), &bbox_info); - } - - return klass; -} - -/** - * gts_bbox_set: - * @bbox: a #GtsBBox. - * @bounded: the object to be bounded. - * @x1: x-coordinate of the lower left corner. - * @y1: y-coordinate of the lower left corner. - * @z1: z-coordinate of the lower left corner. - * @x2: x-coordinate of the upper right corner. - * @y2: y-coordinate of the upper right corner. - * @z2: z-coordinate of the upper right corner. - * - * Sets fields of @bbox. - */ -void gts_bbox_set (GtsBBox * bbox, - gpointer bounded, - gdouble x1, gdouble y1, gdouble z1, - gdouble x2, gdouble y2, gdouble z2) -{ - g_return_if_fail (bbox != NULL); - g_return_if_fail (x2 >= x1 && y2 >= y1 && z2 >= z1); - - bbox->x1 = x1; bbox->y1 = y1; bbox->z1 = z1; - bbox->x2 = x2; bbox->y2 = y2; bbox->z2 = z2; - bbox->bounded = bounded; -} - -/** - * gts_bbox_new: - * @klass: a #GtsBBoxClass. - * @bounded: the object to be bounded. - * @x1: x-coordinate of the lower left corner. - * @y1: y-coordinate of the lower left corner. - * @z1: z-coordinate of the lower left corner. - * @x2: x-coordinate of the upper right corner. - * @y2: y-coordinate of the upper right corner. - * @z2: z-coordinate of the upper right corner. - * - * Returns: a new #GtsBBox. - */ -GtsBBox * gts_bbox_new (GtsBBoxClass * klass, - gpointer bounded, - gdouble x1, gdouble y1, gdouble z1, - gdouble x2, gdouble y2, gdouble z2) -{ - GtsBBox * bbox; - - g_return_val_if_fail (klass != NULL, NULL); - - bbox = GTS_BBOX (gts_object_new (GTS_OBJECT_CLASS (klass))); - gts_bbox_set (bbox, bounded, x1, y1, z1, x2, y2, z2); - return bbox; -} - -/** - * gts_bbox_triangle: - * @klass: a #GtsBBoxClass. - * @t: a #GtsTriangle. - * - * Returns: a new #GtsBBox bounding box of @t. - */ -GtsBBox * gts_bbox_triangle (GtsBBoxClass * klass, - GtsTriangle * t) -{ - GtsBBox * bbox; - GtsPoint * p; - - g_return_val_if_fail (t != NULL, NULL); - g_return_val_if_fail (klass != NULL, NULL); - - p = GTS_POINT (GTS_SEGMENT (t->e1)->v1); - bbox = gts_bbox_new (klass, t, p->x, p->y, p->z, p->x, p->y, p->z); - - p = GTS_POINT (GTS_SEGMENT (t->e1)->v2); - if (p->x > bbox->x2) bbox->x2 = p->x; - if (p->x < bbox->x1) bbox->x1 = p->x; - if (p->y > bbox->y2) bbox->y2 = p->y; - if (p->y < bbox->y1) bbox->y1 = p->y; - if (p->z > bbox->z2) bbox->z2 = p->z; - if (p->z < bbox->z1) bbox->z1 = p->z; - p = GTS_POINT (gts_triangle_vertex (t)); - if (p->x > bbox->x2) bbox->x2 = p->x; - if (p->x < bbox->x1) bbox->x1 = p->x; - if (p->y > bbox->y2) bbox->y2 = p->y; - if (p->y < bbox->y1) bbox->y1 = p->y; - if (p->z > bbox->z2) bbox->z2 = p->z; - if (p->z < bbox->z1) bbox->z1 = p->z; - - return bbox; -} - -/** - * gts_bbox_segment: - * @klass: a #GtsBBoxClass. - * @s: a #GtsSegment. - * - * Returns: a new #GtsBBox bounding box of @s. - */ -GtsBBox * gts_bbox_segment (GtsBBoxClass * klass, GtsSegment * s) -{ - GtsBBox * bbox; - GtsPoint * p1, * p2; - - g_return_val_if_fail (s != NULL, NULL); - g_return_val_if_fail (klass != NULL, NULL); - - bbox = gts_bbox_new (klass, s, 0., 0., 0., 0., 0., 0.); - - p1 = GTS_POINT (s->v1); - p2 = GTS_POINT (s->v2); - if (p1->x > p2->x) { - bbox->x2 = p1->x; bbox->x1 = p2->x; - } - else { - bbox->x1 = p1->x; bbox->x2 = p2->x; - } - if (p1->y > p2->y) { - bbox->y2 = p1->y; bbox->y1 = p2->y; - } - else { - bbox->y1 = p1->y; bbox->y2 = p2->y; - } - if (p1->z > p2->z) { - bbox->z2 = p1->z; bbox->z1 = p2->z; - } - else { - bbox->z1 = p1->z; bbox->z2 = p2->z; - } - - return bbox; -} - -static void bbox_foreach_vertex (GtsPoint * p, GtsBBox * bb) -{ - if (p->x < bb->x1) bb->x1 = p->x; - if (p->y < bb->y1) bb->y1 = p->y; - if (p->z < bb->z1) bb->z1 = p->z; - if (p->x > bb->x2) bb->x2 = p->x; - if (p->y > bb->y2) bb->y2 = p->y; - if (p->z > bb->z2) bb->z2 = p->z; -} - -/** - * gts_bbox_surface: - * @klass: a #GtsBBoxClass. - * @surface: a #GtsSurface. - * - * Returns: a new #GtsBBox bounding box of @surface. - */ -GtsBBox * gts_bbox_surface (GtsBBoxClass * klass, GtsSurface * surface) -{ - GtsBBox * bbox; - - g_return_val_if_fail (klass != NULL, NULL); - g_return_val_if_fail (surface != NULL, NULL); - - bbox = gts_bbox_new (klass, surface, 0., 0., 0., 0., 0., 0.); - bbox->x1 = bbox->y1 = bbox->z1 = G_MAXDOUBLE; - bbox->x2 = bbox->y2 = bbox->z2 = -G_MAXDOUBLE; - - gts_surface_foreach_vertex (surface, (GtsFunc) bbox_foreach_vertex, bbox); - - return bbox; -} - -/** - * gts_bbox_bboxes: - * @klass: a #GtsBBoxClass. - * @bboxes: a list of #GtsBBox. - * - * Returns: a new #GtsBBox bounding box of all the bounding boxes in - * @bboxes. - */ -GtsBBox * gts_bbox_bboxes (GtsBBoxClass * klass, GSList * bboxes) -{ - GtsBBox * bbox; - GtsBBox * bb; - - g_return_val_if_fail (bboxes != NULL, NULL); - g_return_val_if_fail (klass != NULL, NULL); - - bb = bboxes->data; - bbox = gts_bbox_new (klass, bboxes, - bb->x1, bb->y1, bb->z1, bb->x2, bb->y2, bb->z2); - bboxes = bboxes->next; - while (bboxes) { - bb = bboxes->data; - if (bb->x1 < bbox->x1) bbox->x1 = bb->x1; - if (bb->y1 < bbox->y1) bbox->y1 = bb->y1; - if (bb->z1 < bbox->z1) bbox->z1 = bb->z1; - if (bb->x2 > bbox->x2) bbox->x2 = bb->x2; - if (bb->y2 > bbox->y2) bbox->y2 = bb->y2; - if (bb->z2 > bbox->z2) bbox->z2 = bb->z2; - bboxes = bboxes->next; - } - - return bbox; -} - -/** - * gts_bbox_points: - * @klass: a #GtsBBoxClass. - * @points: a list of #GtsPoint. - * - * Returns: a new #GtsBBox bounding box of @points. - */ -GtsBBox * gts_bbox_points (GtsBBoxClass * klass, GSList * points) -{ - GtsPoint * p; - GtsBBox * bbox; - GSList * i; - - if (points == NULL) - return NULL; - - p = points->data; - bbox = gts_bbox_new (klass, points, p->x, p->y, p->z, p->x, p->y, p->z); - - i = points->next; - while (i) { - p = i->data; - if (p->x > bbox->x2) - bbox->x2 = p->x; - else if (p->x < bbox->x1) - bbox->x1 = p->x; - if (p->y > bbox->y2) - bbox->y2 = p->y; - else if (p->y < bbox->y1) - bbox->y1 = p->y; - if (p->z > bbox->z2) - bbox->z2 = p->z; - else if (p->z < bbox->z1) - bbox->z1 = p->z; - i = i->next; - } - - return bbox; -} - -/** - * gts_bboxes_are_overlapping: - * @bb1: a #GtsBBox. - * @bb2: a #GtsBBox. - * - * Returns: %TRUE if the bounding boxes @bb1 and @bb2 are overlapping - * (including just touching), %FALSE otherwise. - */ -gboolean gts_bboxes_are_overlapping (GtsBBox * bb1, GtsBBox * bb2) -{ - if (bb1 == bb2) - return TRUE; - if (bb1->x1 > bb2->x2) - return FALSE; - if (bb2->x1 > bb1->x2) - return FALSE; - if (bb1->y1 > bb2->y2) - return FALSE; - if (bb2->y1 > bb1->y2) - return FALSE; - if (bb1->z1 > bb2->z2) - return FALSE; - if (bb2->z1 > bb1->z2) - return FALSE; - return TRUE; -} - -#define bbox_volume(bb) (((bb)->x2 -\ - (bb)->x1)*\ - ((bb)->y2 -\ - (bb)->y1)*\ - ((bb)->z2 -\ - (bb)->z1)) - -/** - * gts_bbox_diagonal2: - * @bb: a #GtsBBox. - * - * Returns: the squared length of the diagonal of @bb. - */ -gdouble gts_bbox_diagonal2 (GtsBBox * bb) -{ - gdouble x, y, z; - - g_return_val_if_fail (bb != NULL, 0.); - - x = bb->x2 - bb->x1; - y = bb->y2 - bb->y1; - z = bb->z2 - bb->z1; - - return x*x + y*y + z*z; -} - -/** - * gts_bbox_draw: - * @bb: a #GtsBBox. - * @fptr: a file pointer. - * - * Writes in file @fptr an OOGL (Geomview) description of @bb. - */ -void gts_bbox_draw (GtsBBox * bb, FILE * fptr) -{ - g_return_if_fail (bb != NULL); - - fprintf (fptr, "OFF 8 6 12\n"); - fprintf (fptr, "%g %g %g\n", - bb->x1, bb->y1, bb->z1); - fprintf (fptr, "%g %g %g\n", - bb->x2, bb->y1, bb->z1); - fprintf (fptr, "%g %g %g\n", - bb->x2, bb->y2, bb->z1); - fprintf (fptr, "%g %g %g\n", - bb->x1, bb->y2, bb->z1); - fprintf (fptr, "%g %g %g\n", - bb->x1, bb->y1, bb->z2); - fprintf (fptr, "%g %g %g\n", - bb->x2, bb->y1, bb->z2); - fprintf (fptr, "%g %g %g\n", - bb->x2, bb->y2, bb->z2); - fprintf (fptr, "%g %g %g\n", - bb->x1, bb->y2, bb->z2); - fputs ("4 3 2 1 0\n" - "4 4 5 6 7\n" - "4 2 3 7 6\n" - "4 0 1 5 4\n" - "4 0 4 7 3\n" - "4 1 2 6 5\n", - fptr); -} - -#define MINMAX(x1, x2, xmin, xmax) { if (x1 < x2) { xmin = x1; xmax = x2; }\ - else { xmin = x2; xmax = x1; } } - -/** - * gts_bbox_point_distance2: - * @bb: a #GtsBBox. - * @p: a #GtsPoint. - * @min: a pointer on a gdouble. - * @max: a pointer on a gdouble. - * - * Sets @min and @max to lower and upper bounds for the square of the - * Euclidean distance between the object contained in @bb and @p. For these - * bounds to make any sense the bounding box must be "tight" i.e. each of the - * 6 faces of the box must at least be touched by one point of the bounded - * object. - */ -void gts_bbox_point_distance2 (GtsBBox * bb, GtsPoint * p, - gdouble * min, gdouble * max) -{ - gdouble x1, y1, z1, x2, y2, z2, x, y, z; - gdouble dmin, dmax, xd1, xd2, yd1, yd2, zd1, zd2; - gdouble mx, Mx, my, My, mz, Mz; - - g_return_if_fail (bb != NULL); - g_return_if_fail (p != NULL); - g_return_if_fail (min != NULL); - g_return_if_fail (max != NULL); - - x1 = bb->x1; y1 = bb->y1; z1 = bb->z1; - x2 = bb->x2; y2 = bb->y2; z2 = bb->z2; - x = p->x; y = p->y; z = p->z; - - xd1 = (x1 - x)*(x1 - x); - xd2 = (x - x2)*(x - x2); - yd1 = (y1 - y)*(y1 - y); - yd2 = (y - y2)*(y - y2); - zd1 = (z1 - z)*(z1 - z); - zd2 = (z - z2)*(z - z2); - - dmin = x < x1 ? xd1 : x > x2 ? xd2 : 0.0; - dmin += y < y1 ? yd1 : y > y2 ? yd2 : 0.0; - dmin += z < z1 ? zd1 : z > z2 ? zd2 : 0.0; - - MINMAX (xd1, xd2, mx, Mx); - MINMAX (yd1, yd2, my, My); - MINMAX (zd1, zd2, mz, Mz); - - dmax = mx + My + Mz; - dmax = MIN (dmax, Mx + my + Mz); - dmax = MIN (dmax, Mx + My + mz); - - *min = dmin; - *max = dmax; -} - -/** - * gts_bbox_is_stabbed: - * @bb: a #GtsBBox. - * @p: a #GtsPoint. - * - * Returns: %TRUE if the ray starting at @p and ending at (+infty, - * @p->y, @p->z) intersects with @bb, %FALSE otherwise. - */ -gboolean gts_bbox_is_stabbed (GtsBBox * bb, GtsPoint * p) -{ - g_return_val_if_fail (bb != NULL, FALSE); - g_return_val_if_fail (p != NULL, FALSE); - - if (p->x > bb->x2 || - p->y < bb->y1 || p->y > bb->y2 || - p->z < bb->z1 || p->z > bb->z2) - return FALSE; - return TRUE; -} - -extern int triBoxOverlap (double boxcenter[3], - double boxhalfsize[3], - double triverts[3][3]); - -/** - * gts_bbox_overlaps_triangle: - * @bb: a #GtsBBox. - * @t: a #GtsTriangle. - * - * This is a wrapper around the fast overlap test of Tomas - * Akenine-Moller (http://www.cs.lth.se/home/Tomas_Akenine_Moller/). - * - * Returns: %TRUE if @bb overlaps with @t, %FALSE otherwise. - */ -gboolean gts_bbox_overlaps_triangle (GtsBBox * bb, GtsTriangle * t) -{ - double bc[3], bh[3], tv[3][3]; - GtsPoint * p1, * p2, * p3; - - g_return_val_if_fail (bb != NULL, FALSE); - g_return_val_if_fail (t != NULL, FALSE); - - bc[0] = (bb->x2 + bb->x1)/2.; - bh[0] = (bb->x2 - bb->x1)/2.; - bc[1] = (bb->y2 + bb->y1)/2.; - bh[1] = (bb->y2 - bb->y1)/2.; - bc[2] = (bb->z2 + bb->z1)/2.; - bh[2] = (bb->z2 - bb->z1)/2.; - p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1); - p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); - p3 = GTS_POINT (gts_triangle_vertex (t)); - tv[0][0] = p1->x; tv[0][1] = p1->y; tv[0][2] = p1->z; - tv[1][0] = p2->x; tv[1][1] = p2->y; tv[1][2] = p2->z; - tv[2][0] = p3->x; tv[2][1] = p3->y; tv[2][2] = p3->z; - - return triBoxOverlap (bc, bh, tv); -} - -/** - * gts_bbox_overlaps_segment: - * @bb: a #GtsBBox. - * @s: a #GtsSegment. - * - * This functions uses gts_bbox_overlaps_triangle() with a degenerate - * triangle. - * - * Returns: %TRUE if @bb overlaps with @s, %FALSE otherwise. - */ -gboolean gts_bbox_overlaps_segment (GtsBBox * bb, GtsSegment * s) -{ - double bc[3], bh[3], tv[3][3]; - GtsPoint * p1, * p2, * p3; - - g_return_val_if_fail (bb != NULL, FALSE); - g_return_val_if_fail (s != NULL, FALSE); - - bc[0] = (bb->x2 + bb->x1)/2.; - bh[0] = (bb->x2 - bb->x1)/2.; - bc[1] = (bb->y2 + bb->y1)/2.; - bh[1] = (bb->y2 - bb->y1)/2.; - bc[2] = (bb->z2 + bb->z1)/2.; - bh[2] = (bb->z2 - bb->z1)/2.; - p1 = GTS_POINT (s->v1); - p2 = GTS_POINT (s->v2); - p3 = p1; - tv[0][0] = p1->x; tv[0][1] = p1->y; tv[0][2] = p1->z; - tv[1][0] = p2->x; tv[1][1] = p2->y; tv[1][2] = p2->z; - tv[2][0] = p3->x; tv[2][1] = p3->y; tv[2][2] = p3->z; - - return triBoxOverlap (bc, bh, tv); -} - -/** - * gts_bb_tree_new: - * @bboxes: a list of #GtsBBox. - * - * Builds a new hierarchy of bounding boxes for @bboxes. At each - * level, the GNode->data field contains a #GtsBBox bounding box of - * all the children. The tree is binary and is built by repeatedly - * cutting in two approximately equal halves the bounding boxes at - * each level until a leaf node (i.e. a bounding box given in @bboxes) - * is reached. In order to minimize the depth of the tree, the cutting - * direction is always chosen as perpendicular to the longest - * dimension of the bounding box. - * - * Returns: a new hierarchy of bounding boxes. - */ -GNode * gts_bb_tree_new (GSList * bboxes) -{ - GSList * i, * positive = NULL, * negative = NULL; - GNode * node; - GtsBBox * bbox; - guint dir, np = 0, nn = 0; - gdouble * p1, * p2; - gdouble cut; - - g_return_val_if_fail (bboxes != NULL, NULL); - - if (bboxes->next == NULL) /* leaf node */ - return g_node_new (bboxes->data); - - bbox = gts_bbox_bboxes (gts_bbox_class (), bboxes); - node = g_node_new (bbox); - - if (bbox->x2 - bbox->x1 > bbox->y2 - bbox->y1) { - if (bbox->z2 - bbox->z1 > bbox->x2 - bbox->x1) - dir = 2; - else - dir = 0; - } - else if (bbox->z2 - bbox->z1 > bbox->y2 - bbox->y1) - dir = 2; - else - dir = 1; - - p1 = (gdouble *) &bbox->x1; - p2 = (gdouble *) &bbox->x2; - cut = (p1[dir] + p2[dir])/2.; - i = bboxes; - while (i) { - bbox = i->data; - p1 = (gdouble *) &bbox->x1; - p2 = (gdouble *) &bbox->x2; - if ((p1[dir] + p2[dir])/2. > cut) { - positive = g_slist_prepend (positive, bbox); - np++; - } - else { - negative = g_slist_prepend (negative, bbox); - nn++; - } - i = i->next; - } - if (!positive) { - GSList * last = g_slist_nth (negative, (nn - 1)/2); - positive = last->next; - last->next = NULL; - } - else if (!negative) { - GSList * last = g_slist_nth (positive, (np - 1)/2); - negative = last->next; - last->next = NULL; - } - g_node_prepend (node, gts_bb_tree_new (positive)); - g_slist_free (positive); - g_node_prepend (node, gts_bb_tree_new (negative)); - g_slist_free (negative); - - return node; -} - -static void prepend_triangle_bbox (GtsTriangle * t, GSList ** bboxes) -{ - *bboxes = g_slist_prepend (*bboxes, - gts_bbox_triangle (gts_bbox_class (), t)); -} - -/** - * gts_bb_tree_surface: - * @s: a #GtsSurface. - * - * Returns: a new hierarchy of bounding boxes bounding the faces of @s. - */ -GNode * gts_bb_tree_surface (GtsSurface * s) -{ - GSList * bboxes = NULL; - GNode * tree; - - g_return_val_if_fail (s != NULL, NULL); - - gts_surface_foreach_face (s, (GtsFunc) prepend_triangle_bbox, &bboxes); - tree = gts_bb_tree_new (bboxes); - g_slist_free (bboxes); - - return tree; -} - -/** - * gts_bb_tree_stabbed: - * @tree: a bounding box tree. - * @p: a #GtsPoint. - * - * Returns: a list of bounding boxes, leaves of @tree which are - * stabbed by the ray defined by @p (see gts_bbox_is_stabbed()). - */ -GSList * gts_bb_tree_stabbed (GNode * tree, GtsPoint * p) -{ - GSList * list = NULL; - GtsBBox * bb; - GNode * i; - - g_return_val_if_fail (tree != NULL, NULL); - g_return_val_if_fail (p != NULL, NULL); - - bb = tree->data; - if (!gts_bbox_is_stabbed (bb, p)) - return NULL; - if (tree->children == NULL) /* leaf node */ - return g_slist_prepend (NULL, bb); - i = tree->children; - while (i) { - list = g_slist_concat (list, gts_bb_tree_stabbed (i, p)); - i = i->next; - } - return list; -} - -/** - * gts_bb_tree_overlap: - * @tree: a bounding box tree. - * @bbox: a #GtsBBox. - * - * Returns: a list of bounding boxes, leaves of @tree which overlap @bbox. - */ -GSList * gts_bb_tree_overlap (GNode * tree, GtsBBox * bbox) -{ - GSList * list = NULL; - GtsBBox * bb; - GNode * i; - - g_return_val_if_fail (tree != NULL, NULL); - g_return_val_if_fail (bbox != NULL, NULL); - - bb = tree->data; - if (!gts_bboxes_are_overlapping (bbox, bb)) - return NULL; - if (tree->children == NULL) /* leaf node */ - return g_slist_prepend (NULL, bb); - i = tree->children; - while (i) { - list = g_slist_concat (list, gts_bb_tree_overlap (i, bbox)); - i = i->next; - } - return list; -} - -/** - * gts_bb_tree_is_overlapping: - * @tree: a bounding box tree. - * @bbox: a #GtsBBox. - * - * Returns: %TRUE if any leaf of @tree overlaps @bbox, %FALSE otherwise. - */ -gboolean gts_bb_tree_is_overlapping (GNode * tree, GtsBBox * bbox) -{ - GtsBBox * bb; - GNode * i; - - g_return_val_if_fail (tree != NULL, FALSE); - g_return_val_if_fail (bbox != NULL, FALSE); - - bb = tree->data; - if (!gts_bboxes_are_overlapping (bbox, bb)) - return FALSE; - if (tree->children == NULL) /* leaf node */ - return TRUE; - i = tree->children; - while (i) { - if (gts_bb_tree_is_overlapping (i, bbox)) - return TRUE; - i = i->next; - } - return FALSE; -} - -/** - * gts_bb_tree_traverse_overlapping: - * @tree1: a bounding box tree. - * @tree2: a bounding box tree. - * @func: a #GtsBBTreeTraverseFunc. - * @data: user data to be passed to @func. - * - * Calls @func for each overlapping pair of leaves of @tree1 and @tree2. - */ -void gts_bb_tree_traverse_overlapping (GNode * tree1, GNode * tree2, - GtsBBTreeTraverseFunc func, - gpointer data) -{ - GtsBBox * bb1, * bb2; - - g_return_if_fail (tree1 != NULL && tree2 != NULL); - - bb1 = tree1->data; bb2 = tree2->data; - if (!gts_bboxes_are_overlapping (bb1, bb2)) - return; - - if (tree1->children == NULL && tree2->children == NULL) - (*func) (tree1->data, tree2->data, data); - else if (tree2->children == NULL || - (tree1->children != NULL && - bbox_volume (bb1) > bbox_volume (bb2))) { - GNode * i = tree1->children; - while (i) { - gts_bb_tree_traverse_overlapping (i, tree2, func, data); - i = i->next; - } - } - else { - GNode * i = tree2->children; - while (i) { - gts_bb_tree_traverse_overlapping (tree1, i, func, data); - i = i->next; - } - } -} - -/** - * gts_bb_tree_draw: - * @tree: a bounding box tree. - * @depth: a specified depth. - * @fptr: a file pointer. - * - * Write in @fptr an OOGL (Geomview) description of @tree for the - * depth specified by @depth. - */ -void gts_bb_tree_draw (GNode * tree, guint depth, FILE * fptr) -{ - guint d; - - g_return_if_fail (tree != NULL); - g_return_if_fail (fptr != NULL); - - d = g_node_depth (tree); - - if (d == 1) - fprintf (fptr, "{ LIST"); - - if (d == depth) - gts_bbox_draw (tree->data, fptr); - else if (d < depth) { - GNode * i = tree->children; - while (i) { - gts_bb_tree_draw (i, depth, fptr); - i = i->next; - } - } - - if (d == 1) - fprintf (fptr, "}\n"); -} - -static void bb_tree_free (GNode * tree, gboolean free_leaves) -{ - GNode * i; - - g_return_if_fail (tree != NULL); - - if (!free_leaves && tree->children == NULL) /* leaf node */ - return; - - gts_object_destroy (tree->data); - - i = tree->children; - while (i) { - bb_tree_free (i, free_leaves); - i = i->next; - } -} - -/** - * gts_bb_tree_destroy: - * @tree: a bounding box tree. - * @free_leaves: if %TRUE the bounding boxes given by the user are freed. - * - * Destroys all the bounding boxes created by @tree and destroys the - * tree itself. If @free_leaves is set to %TRUE, destroys boxes given - * by the user when creating the tree (i.e. leaves of the tree). - */ -void gts_bb_tree_destroy (GNode * tree, gboolean free_leaves) -{ - g_return_if_fail (tree != NULL); - - bb_tree_free (tree, free_leaves); - g_node_destroy (tree); -} - -static gdouble bb_tree_min_max (GNode * tree, - GtsPoint * p, - gdouble min_max, - GSList ** list) -{ - GNode * tree1, * tree2; - gdouble min1, max1, min2, max2; - - if (tree->children == NULL) { - *list = g_slist_prepend (*list, tree->data); - return min_max; - } - tree1 = tree->children; - gts_bbox_point_distance2 (tree1->data, p, &min1, &max1); - if (max1 < min_max) - min_max = max1; - - tree2 = tree1->next; - gts_bbox_point_distance2 (tree2->data, p, &min2, &max2); - if (max2 < min_max) - min_max = max2; - - if (min1 < min2) { - if (min1 <= min_max) { - min_max = bb_tree_min_max (tree1, p, min_max, list); - if (min2 <= min_max) - min_max = bb_tree_min_max (tree2, p, min_max, list); - } - } - else { - if (min2 <= min_max) { - min_max = bb_tree_min_max (tree2, p, min_max, list); - if (min1 <= min_max) - min_max = bb_tree_min_max (tree1, p, min_max, list); - } - } - - return min_max; -} - -/** - * gts_bb_tree_point_closest_bboxes: - * @tree: a bounding box tree. - * @p: a #GtsPoint. - * - * Returns: a list of #GtsBBox. One of the bounding boxes is assured to contain - * the object of @tree closest to @p. - */ -GSList * gts_bb_tree_point_closest_bboxes (GNode * tree, - GtsPoint * p) -{ - gdouble min, min_max; - GSList * list = NULL, * i, * prev = NULL; - - g_return_val_if_fail (tree != NULL, NULL); - g_return_val_if_fail (p != NULL, NULL); - - gts_bbox_point_distance2 (tree->data, p, &min, &min_max); - min_max = bb_tree_min_max (tree, p, min_max, &list); - - i = list; - while (i) { - GSList * next = i->next; - gdouble min, max; - - gts_bbox_point_distance2 (i->data, p, &min, &max); - - if (min > min_max) { - if (prev == NULL) - list = next; - else - prev->next = next; - g_slist_free_1 (i); - } - else - prev = i; - i = next; - } - - return list; -} - -/** - * gts_bb_tree_point_distance: - * @tree: a bounding box tree. - * @p: a #GtsPoint. - * @distance: a #GtsBBoxDistFunc. - * @bbox: if not %NULL is set to the bounding box containing the closest - * object. - * - * Returns: the distance as evaluated by @distance between @p and the closest - * object in @tree. - */ -gdouble gts_bb_tree_point_distance (GNode * tree, - GtsPoint * p, - GtsBBoxDistFunc distance, - GtsBBox ** bbox) -{ - GSList * list, * i; - gdouble dmin = G_MAXDOUBLE; - - g_return_val_if_fail (tree != NULL, dmin); - g_return_val_if_fail (p != NULL, dmin); - g_return_val_if_fail (distance != NULL, dmin); - - i = list = gts_bb_tree_point_closest_bboxes (tree, p); - while (i) { - gdouble d = (*distance) (p, GTS_BBOX (i->data)->bounded); - - if (fabs (d) < fabs (dmin)) { - dmin = d; - if (bbox) - *bbox = i->data; - } - i = i->next; - } - g_slist_free (list); - - return dmin; -} - -/** - * gts_bb_tree_point_closest: - * @tree: a bounding box tree. - * @p: a #GtsPoint. - * @closest: a #GtsBBoxClosestFunc. - * @distance: if not %NULL is set to the distance between @p and the - * new #GtsPoint. - * - * Returns: a new #GtsPoint, closest point to @p and belonging to an object of - * @tree. - */ -GtsPoint * gts_bb_tree_point_closest (GNode * tree, - GtsPoint * p, - GtsBBoxClosestFunc closest, - gdouble * distance) -{ - GSList * list, * i; - gdouble dmin = G_MAXDOUBLE; - GtsPoint * np = NULL; - - g_return_val_if_fail (tree != NULL, NULL); - g_return_val_if_fail (p != NULL, NULL); - g_return_val_if_fail (closest != NULL, NULL); - - i = list = gts_bb_tree_point_closest_bboxes (tree, p); - while (i) { - GtsPoint * tp = (*closest) (p, GTS_BBOX (i->data)->bounded); - gdouble d = gts_point_distance2 (tp, p); - - if (d < dmin) { - if (np) - gts_object_destroy (GTS_OBJECT (np)); - np = tp; - dmin = d; - } - else - gts_object_destroy (GTS_OBJECT (tp)); - i = i->next; - } - g_slist_free (list); - - if (distance) - *distance = dmin; - - return np; -} - -/** - * gts_bb_tree_triangle_distance: - * @tree: a bounding box tree. - * @t: a #GtsTriangle. - * @distance: a #GtsBBoxDistFunc. - * @delta: spatial scale of the sampling to be used. - * @range: a #GtsRange to be filled with the results. - * - * Given a triangle @t, points are sampled regularly on its surface - * using @delta as increment. The distance from each of these points - * to the closest object of @tree is computed using @distance and the - * gts_bb_tree_point_distance() function. The fields of @range are - * filled with the number of points sampled, the minimum, average and - * maximum value and the standard deviation. - */ -void gts_bb_tree_triangle_distance (GNode * tree, - GtsTriangle * t, - GtsBBoxDistFunc distance, - gdouble delta, - GtsRange * range) -{ - GtsPoint * p1, * p2, * p3, * p; - GtsVector p1p2, p1p3; - gdouble l1, t1, dt1; - guint i, n1; - - g_return_if_fail (tree != NULL); - g_return_if_fail (t != NULL); - g_return_if_fail (distance != NULL); - g_return_if_fail (delta > 0.); - g_return_if_fail (range != NULL); - - gts_triangle_vertices (t, - (GtsVertex **) &p1, - (GtsVertex **) &p2, - (GtsVertex **) &p3); - - gts_vector_init (p1p2, p1, p2); - gts_vector_init (p1p3, p1, p3); - gts_range_init (range); - p = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class ()))); - - l1 = sqrt (gts_vector_scalar (p1p2, p1p2)); - n1 = l1/delta + 1; - dt1 = 1.0/(gdouble) n1; - t1 = 0.0; - for (i = 0; i <= n1; i++, t1 += dt1) { - gdouble t2 = 1. - t1; - gdouble x = t2*p1p3[0]; - gdouble y = t2*p1p3[1]; - gdouble z = t2*p1p3[2]; - gdouble l2 = sqrt (x*x + y*y + z*z); - guint j, n2 = (guint) (l2/delta + 1); - gdouble dt2 = t2/(gdouble) n2; - - x = t2*p1->x + t1*p2->x; - y = t2*p1->y + t1*p2->y; - z = t2*p1->z + t1*p2->z; - - t2 = 0.0; - for (j = 0; j <= n2; j++, t2 += dt2) { - p->x = x + t2*p1p3[0]; - p->y = y + t2*p1p3[1]; - p->z = z + t2*p1p3[2]; - - gts_range_add_value (range, - gts_bb_tree_point_distance (tree, p, distance, NULL)); - } - } - - gts_object_destroy (GTS_OBJECT (p)); - gts_range_update (range); -} - -/** - * gts_bb_tree_segment_distance: - * @tree: a bounding box tree. - * @s: a #GtsSegment. - * @distance: a #GtsBBoxDistFunc. - * @delta: spatial scale of the sampling to be used. - * @range: a #GtsRange to be filled with the results. - * - * Given a segment @s, points are sampled regularly on its length - * using @delta as increment. The distance from each of these points - * to the closest object of @tree is computed using @distance and the - * gts_bb_tree_point_distance() function. The fields of @range are - * filled with the number of points sampled, the minimum, average and - * maximum value and the standard deviation. - */ -void gts_bb_tree_segment_distance (GNode * tree, - GtsSegment * s, - gdouble (*distance) (GtsPoint *, - gpointer), - gdouble delta, - GtsRange * range) -{ - GtsPoint * p1, * p2, * p; - GtsVector p1p2; - gdouble l, t, dt; - guint i, n; - - g_return_if_fail (tree != NULL); - g_return_if_fail (s != NULL); - g_return_if_fail (distance != NULL); - g_return_if_fail (delta > 0.); - g_return_if_fail (range != NULL); - - p1 = GTS_POINT (s->v1); - p2 = GTS_POINT (s->v2); - - gts_vector_init (p1p2, p1, p2); - gts_range_init (range); - p = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class()))); - - l = sqrt (gts_vector_scalar (p1p2, p1p2)); - n = (guint) (l/delta + 1); - dt = 1.0/(gdouble) n; - t = 0.0; - for (i = 0; i <= n; i++, t += dt) { - p->x = p1->x + t*p1p2[0]; - p->y = p1->y + t*p1p2[1]; - p->z = p1->z + t*p1p2[2]; - - gts_range_add_value (range, - gts_bb_tree_point_distance (tree, p, distance, NULL)); - } - - gts_object_destroy (GTS_OBJECT (p)); - gts_range_update (range); -} - -static void surface_distance_foreach_triangle (GtsTriangle * t, - gpointer * data) -{ - gdouble * delta = data[1]; - GtsRange * range = data[2]; - gdouble * total_area = data[3], area; - GtsRange range_triangle; - - gts_bb_tree_triangle_distance (data[0], t, data[4], *delta, &range_triangle); - - if (range_triangle.min < range->min) - range->min = range_triangle.min; - if (range_triangle.max > range->max) - range->max = range_triangle.max; - range->n += range_triangle.n; - - area = gts_triangle_area (t); - *total_area += area; - range->sum += area*range_triangle.mean; - range->sum2 += area*range_triangle.mean*range_triangle.mean; -} - -/** - * gts_bb_tree_surface_distance: - * @tree: a bounding box tree. - * @s: a #GtsSurface. - * @distance: a #GtsBBoxDistFunc. - * @delta: a sampling increment defined as the percentage of the diagonal - * of the root bounding box of @tree. - * @range: a #GtsRange to be filled with the results. - * - * Calls gts_bb_tree_triangle_distance() for each face of @s. The - * fields of @range are filled with the minimum, maximum and average - * distance. The average distance is defined as the sum of the average - * distances for each triangle weighthed by their area and divided by - * the total area of the surface. The standard deviation is defined - * accordingly. The @n field of @range is filled with the number of - * sampled points used. - */ -void gts_bb_tree_surface_distance (GNode * tree, - GtsSurface * s, - GtsBBoxDistFunc distance, - gdouble delta, - GtsRange * range) -{ - gpointer data[5]; - gdouble total_area = 0.; - - g_return_if_fail (tree != NULL); - g_return_if_fail (s != NULL); - g_return_if_fail (delta > 0. && delta < 1.); - g_return_if_fail (range != NULL); - - gts_range_init (range); - delta *= sqrt (gts_bbox_diagonal2 (tree->data)); - data[0] = tree; - data[1] = δ - data[2] = range; - data[3] = &total_area; - data[4] = distance; - - gts_surface_foreach_face (s, - (GtsFunc) surface_distance_foreach_triangle, - data); - - if (total_area > 0.) { - if (range->sum2 - range->sum*range->sum/total_area >= 0.) - range->stddev = sqrt ((range->sum2 - range->sum*range->sum/total_area) - /total_area); - else - range->stddev = 0.; - range->mean = range->sum/total_area; - } - else - range->min = range->max = range->mean = range->stddev = 0.; -} - -static void surface_distance_foreach_boundary (GtsEdge * e, - gpointer * data) -{ - gdouble * delta = data[1]; - GtsRange * range = data[2]; - gdouble * total_length = data[3], length; - GtsRange range_edge; - - if (gts_edge_is_boundary (e, NULL)) { - GtsSegment * s = GTS_SEGMENT (e); - - gts_bb_tree_segment_distance (data[0], s, data[4], *delta, &range_edge); - - if (range_edge.min < range->min) - range->min = range_edge.min; - if (range_edge.max > range->max) - range->max = range_edge.max; - range->n += range_edge.n; - - length = gts_point_distance (GTS_POINT (s->v1), GTS_POINT (s->v2)); - *total_length += length; - range->sum += length*range_edge.mean; - range->sum2 += length*range_edge.mean*range_edge.mean; - } -} - -/** - * gts_bb_tree_surface_boundary_distance: - * @tree: a bounding box tree. - * @s: a #GtsSurface. - * @distance: a #GtsBBoxDistFunc. - * @delta: a sampling increment defined as the percentage of the diagonal - * of the root bounding box of @tree. - * @range: a #GtsRange to be filled with the results. - * - * Calls gts_bb_tree_segment_distance() for each edge boundary of @s. - * The fields of @range are filled with the minimum, maximum and - * average distance. The average distance is defined as the sum of the - * average distances for each boundary edge weighthed by their length - * and divided by the total length of the boundaries. The standard - * deviation is defined accordingly. The @n field of @range is filled - * with the number of sampled points used. - */ -void gts_bb_tree_surface_boundary_distance (GNode * tree, - GtsSurface * s, - gdouble (*distance) (GtsPoint *, - gpointer), - gdouble delta, - GtsRange * range) -{ - gpointer data[5]; - gdouble total_length = 0.; - - g_return_if_fail (tree != NULL); - g_return_if_fail (s != NULL); - g_return_if_fail (delta > 0. && delta < 1.); - g_return_if_fail (range != NULL); - - gts_range_init (range); - delta *= sqrt (gts_bbox_diagonal2 (tree->data)); - data[0] = tree; - data[1] = δ - data[2] = range; - data[3] = &total_length; - data[4] = distance; - - gts_surface_foreach_edge (s, - (GtsFunc) surface_distance_foreach_boundary, - data); - - if (total_length > 0.) { - if (range->sum2 - range->sum*range->sum/total_length >= 0.) - range->stddev = sqrt ((range->sum2 - - range->sum*range->sum/total_length) - /total_length); - else - range->stddev = 0.; - range->mean = range->sum/total_length; - } - else - range->min = range->max = range->mean = range->stddev = 0.; -} Index: trunk/src_3rd/gts/Makefile.dep =================================================================== --- trunk/src_3rd/gts/Makefile.dep (revision 6802) +++ trunk/src_3rd/gts/Makefile.dep (nonexistent) @@ -1,36 +0,0 @@ -### Generated file, do not edit, run make dep ### - -bbtree.o: bbtree.c gts.h -boolean.o: boolean.c gts.h -cdt.o: cdt.c ../../config.h gts.h -container.o: container.c gts.h -curvature.o: curvature.c gts.h -edge.o: edge.c gts.h -eheap.o: eheap.c gts.h -face.o: face.c gts.h -fifo.o: fifo.c gts.h -graph.o: graph.c gts.h -heap.o: heap.c gts.h -hsurface.o: hsurface.c gts.h -iso.o: iso.c gts.h -isotetra.o: isotetra.c gts.h -kdtree.o: kdtree.c gts.h -matrix.o: matrix.c gts.h -misc.o: misc.c gts.h gts-private.h ../../config.h -named.o: named.c gts.h -object.o: object.c gts.h gts-private.h -oocs.o: oocs.c gts.h -partition.o: partition.c gts.h -pgraph.o: pgraph.c gts.h -point.o: point.c gts.h gts-private.h predicates.h -predicates.o: predicates.c predicates.h rounding.h ../../config.h -psurface.o: psurface.c gts.h -refine.o: refine.c gts.h -segment.o: segment.c gts.h -split.o: split.c gts.h -stripe.o: stripe.c gts.h -surface.o: surface.c gts.h gts-private.h -triangle.o: triangle.c gts.h -tribox3.o: tribox3.c -vertex.o: vertex.c gts.h -vopt.o: vopt.c gts.h Index: trunk/src_3rd/gts/edge.c =================================================================== --- trunk/src_3rd/gts/edge.c (revision 6802) +++ trunk/src_3rd/gts/edge.c (nonexistent) @@ -1,582 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "gts.h" - -gboolean gts_allow_floating_edges = FALSE; - -static void edge_destroy (GtsObject * object) -{ - GtsEdge * edge = GTS_EDGE (object); - GSList * i; - - i = edge->triangles; - while (i) { - GSList * next = i->next; - gts_object_destroy (i->data); - i = next; - } - g_assert (edge->triangles == NULL); - - (* GTS_OBJECT_CLASS (gts_edge_class ())->parent_class->destroy) (object); -} - -static void edge_clone (GtsObject * clone, GtsObject * object) -{ - (* GTS_OBJECT_CLASS (gts_edge_class ())->parent_class->clone) (clone, - object); - GTS_SEGMENT (clone)->v1 = GTS_SEGMENT (clone)->v2 = NULL; - GTS_EDGE (clone)->triangles = NULL; -} - -static void edge_class_init (GtsObjectClass * klass) -{ - klass->clone = edge_clone; - klass->destroy = edge_destroy; -} - -static void edge_init (GtsEdge * edge) -{ - edge->triangles = NULL; -} - -/** - * gts_edge_class: - * - * Returns: the #GtsEdgeClass. - */ -GtsEdgeClass * gts_edge_class (void) -{ - static GtsEdgeClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo edge_info = { - "GtsEdge", - sizeof (GtsEdge), - sizeof (GtsEdgeClass), - (GtsObjectClassInitFunc) edge_class_init, - (GtsObjectInitFunc) edge_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_segment_class ()), - &edge_info); - } - - return klass; -} - -/** - * gts_edge_new: - * @klass: a #GtsEdgeClass. - * @v1: a #GtsVertex. - * @v2: a #GtsVertex. - * - * Returns: a new #GtsEdge linking @v1 and @v2. - */ -GtsEdge * gts_edge_new (GtsEdgeClass * klass, - GtsVertex * v1, GtsVertex * v2) -{ - return GTS_EDGE (gts_segment_new (GTS_SEGMENT_CLASS (klass), v1, v2)); -} - -void gts_edge_remove(GtsEdge *edge) -{ - edge->segment.v1->segments = g_slist_remove(edge->segment.v1->segments, &edge->segment); - edge->segment.v2->segments = g_slist_remove(edge->segment.v2->segments, &edge->segment); - edge_destroy(GTS_OBJECT (edge)); -} - -/** - * gts_edge_replace: - * @e: a #GtsEdge. - * @with: a #GtsEdge. - * - * Replaces @e with @with. For each triangle which uses @e as an - * edge, @e is replaced with @with. The @with->triangles list is - * updated appropriately and the @e->triangles list is freed and set - * to %NULL. - */ -void gts_edge_replace (GtsEdge * e, GtsEdge * with) -{ - GSList * i; - - g_return_if_fail (e != NULL && with != NULL && e != with); - - i = e->triangles; - while (i) { - GtsTriangle * t = i->data; - if (t->e1 == e) t->e1 = with; - if (t->e2 == e) t->e2 = with; - if (t->e3 == e) t->e3 = with; - if (!g_slist_find (with->triangles, t)) - with->triangles = g_slist_prepend (with->triangles, t); - i = i->next; - } - g_slist_free (e->triangles); - e->triangles = NULL; -} - -/** - * gts_edge_has_parent_surface: - * @e: a #GtsEdge. - * @surface: a #GtsSurface. - * - * Returns: a #GtsFace of @surface having @e as an edge, %NULL otherwise. - */ -GtsFace * gts_edge_has_parent_surface (GtsEdge * e, GtsSurface * surface) -{ - GSList * i; - - g_return_val_if_fail (e != NULL, NULL); - - i = e->triangles; - while (i) { - if (GTS_IS_FACE (i->data) && - gts_face_has_parent_surface (i->data, surface)) - return i->data; - i = i->next; - } - return NULL; -} - -/** - * gts_edge_has_any_parent_surface: - * @e: a #GtsEdge. - * - * Returns: %NULL if @e is not an edge of any triangle or if all the - * faces having @e has an edge do not belong to any surface, - * a #GtsFace belonging to a surface and having @e as an edge. - */ -GtsFace * gts_edge_has_any_parent_surface (GtsEdge * e) -{ - GSList * i; - - g_return_val_if_fail (e != NULL, NULL); - - i = e->triangles; - while (i) { - GtsTriangle * t = i->data; - if (GTS_IS_FACE (t) && GTS_FACE (t)->surfaces != NULL) - return GTS_FACE (t); - i = i->next; - } - return NULL; -} - -/** - * gts_edge_is_boundary: - * @e: a #GtsEdge. - * @surface: a #GtsSurface or %NULL. - * - * Returns: the unique #GtsFace (which belongs to @surface) and which - * has @e as an edge (i.e. @e is a boundary edge (of @surface)) or %NULL - * if there is more than one or no faces (belonging to @surface) and - * with @e as an edge. - */ -GtsFace * gts_edge_is_boundary (GtsEdge * e, GtsSurface * surface) -{ - GSList * i; - GtsFace * f = NULL; - - g_return_val_if_fail (e != NULL, NULL); - - i = e->triangles; - while (i) { - if (GTS_IS_FACE (i->data)) { - if (!surface || gts_face_has_parent_surface (i->data, surface)) { - if (f != NULL) - return NULL; - f = i->data; - } - } - i = i->next; - } - return f; -} - -/** - * gts_edges_from_vertices: - * @vertices: a list of #GtsVertex. - * @parent: a #GtsSurface. - * - * Returns: a list of unique #GtsEdge which have one of their vertices in - * @vertices and are used by a face of @parent. - */ -GSList * gts_edges_from_vertices (GSList * vertices, GtsSurface * parent) -{ - GHashTable * hash; - GSList * edges = NULL, * i; - - g_return_val_if_fail (parent != NULL, NULL); - - hash = g_hash_table_new (NULL, NULL); - i = vertices; - while (i) { - GSList * j = GTS_VERTEX (i->data)->segments; - while (j) { - GtsSegment * s = j->data; - if (GTS_IS_EDGE (s) && - gts_edge_has_parent_surface (GTS_EDGE (s), parent) && - g_hash_table_lookup (hash, s) == NULL) { - edges = g_slist_prepend (edges, s); - g_hash_table_insert (hash, s, i); - } - j = j->next; - } - i = i->next; - } - g_hash_table_destroy (hash); - return edges; -} - -/** - * gts_edge_face_number: - * @e: a #GtsEdge. - * @s: a #GtsSurface. - * - * Returns: the number of faces using @e and belonging to @s. - */ -guint gts_edge_face_number (GtsEdge * e, GtsSurface * s) -{ - GSList * i; - guint nt = 0; - - g_return_val_if_fail (e != NULL, 0); - g_return_val_if_fail (s != NULL, 0); - - i = e->triangles; - while (i) { - if (GTS_IS_FACE (i->data) && - gts_face_has_parent_surface (GTS_FACE (i->data), s)) - nt++; - i = i->next; - } - return nt; -} - -/** - * gts_edge_is_duplicate: - * @e: a #GtsEdge. - * - * Returns: the first #GtsEdge different from @e which shares the - * same endpoints or %NULL if there is none. - */ -GtsEdge * gts_edge_is_duplicate (GtsEdge * e) -{ - GSList * i; - GtsVertex * v2; - - g_return_val_if_fail (e != NULL, NULL); - - v2 = GTS_SEGMENT (e)->v2; - i = GTS_SEGMENT (e)->v1->segments; - if (GTS_SEGMENT (e)->v1 == v2) /* e is degenerate: special treatment */ - while (i) { - GtsSegment * s = i->data; - if (s != GTS_SEGMENT (e) && - GTS_IS_EDGE (s) && - s->v1 == v2 && s->v2 == v2) - return GTS_EDGE (s); - i = i->next; - } - else /* e is not degenerate */ - while (i) { - GtsSegment * s = i->data; - if (s != GTS_SEGMENT (e) && - GTS_IS_EDGE (s) && - (s->v1 == v2 || s->v2 == v2)) - return GTS_EDGE (s); - i = i->next; - } - return NULL; -} - -/** - * gts_edges_merge: - * @edges: a list of #GtsEdge. - * - * For each edge in @edges check if it is duplicated (as - * returned by gts_edge_is_duplicate()). If it is replace it by its - * duplicate, destroy it and remove it from the list. - * - * Returns: the updated @edges list. - */ -GList * gts_edges_merge (GList * edges) -{ - GList * i = edges; - - /* we want to control edge destruction */ - gts_allow_floating_edges = TRUE; - while (i) { - GtsEdge * e = i->data; - GtsEdge * de = gts_edge_is_duplicate (e); - if (de) { - GList * next = i->next; - edges = g_list_remove_link (edges, i); - g_list_free_1 (i); - i = next; - gts_edge_replace (e, de); - gts_object_destroy (GTS_OBJECT (e)); - } - else - i = i->next; - } - gts_allow_floating_edges = FALSE;; - - return edges; -} - -static void triangle_vertices_edges (GtsTriangle * t, - GtsEdge * e, - GtsVertex ** v, - GtsEdge ** ee1, - GtsEdge ** ee2) -{ - GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3; - GtsVertex * v1 = GTS_SEGMENT (e)->v1; - - if (e1 == e) e1 = e3; - else if (e2 == e) e2 = e3; - else g_assert (e3 == e); - - if (GTS_SEGMENT (e2)->v1 == v1 || GTS_SEGMENT (e2)->v2 == v1) { - e3 = e1; e1 = e2; e2 = e3; - } - if (GTS_SEGMENT (e1)->v1 == v1) - *v = GTS_SEGMENT (e1)->v2; - else - *v = GTS_SEGMENT (e1)->v1; - *ee1 = e1; - *ee2 = e2; -} - -/** - * gts_edge_belongs_to_tetrahedron: - * @e: a #GtsEdge. - * - * Returns: %TRUE if @e is used by faces forming a tetrahedron, %FALSE - * otherwise. - */ -gboolean gts_edge_belongs_to_tetrahedron (GtsEdge * e) -{ - GSList * i; - - g_return_val_if_fail (e != NULL, FALSE); - - i = e->triangles; - while (i) { - GtsEdge * e1, * e2; - GtsVertex * vt1; - GSList * j = i->next; - triangle_vertices_edges (i->data, e, &vt1, &e1, &e2); - while (j) { - GtsSegment * s5; - GtsEdge * e3, * e4; - GtsVertex * vt2; - - triangle_vertices_edges (j->data, e, &vt2, &e3, &e4); - s5 = gts_vertices_are_connected (vt1, vt2); - if (GTS_IS_EDGE (s5) && - gts_triangle_use_edges (e1, e3, GTS_EDGE (s5)) && - gts_triangle_use_edges (e2, e4, GTS_EDGE (s5))) - return TRUE; - j = j->next; - } - i = i->next; - } - - return FALSE; -} - -#define edge_use_vertex(e, v) (GTS_SEGMENT(e)->v1 == v ||\ - GTS_SEGMENT(e)->v2 == v) - -static GtsEdge * next_edge (GtsTriangle * t, - GtsEdge * e1, - GtsEdge * e) -{ - GtsVertex * v1 = GTS_SEGMENT (e)->v1; - GtsVertex * v2 = GTS_SEGMENT (e)->v2; - - if (t->e1 != e1 && t->e1 != e && - (edge_use_vertex (t->e1, v1) || edge_use_vertex (t->e1, v2))) - return t->e1; - else if (t->e2 != e1 && t->e2 != e && - (edge_use_vertex (t->e2, v1) || edge_use_vertex (t->e2, v2))) - return t->e2; - else if (t->e3 != e1 && t->e3 != e && - (edge_use_vertex (t->e3, v1) || edge_use_vertex (t->e3, v2))) - return t->e3; - g_assert_not_reached (); - return NULL; -} - -static void triangle_next (GtsEdge * e1, GtsEdge * e) -{ - GSList * i; - - i = e1->triangles; - while (i) { - GtsTriangle * t = i->data; - if (GTS_OBJECT (t)->reserved) { - GTS_OBJECT (t)->reserved = NULL; - triangle_next (next_edge (t, e1, e), e); - } - i = i->next; - } -} - -/** - * gts_edge_is_contact: - * @e: a #GtsEdge. - * - * Returns: the number of sets of connected triangles sharing @e as a - * contact edge. - */ -guint gts_edge_is_contact (GtsEdge * e) -{ - GSList * i, * triangles; - guint ncomponent = 0; - - g_return_val_if_fail (e != NULL, 0); - - triangles = gts_vertex_triangles (GTS_SEGMENT (e)->v1, NULL); - i = triangles = gts_vertex_triangles (GTS_SEGMENT (e)->v2, triangles); - while (i) { - GTS_OBJECT (i->data)->reserved = i; - i = i->next; - } - - i = e->triangles; - while (i) { - GtsTriangle * t = i->data; - if (GTS_OBJECT (t)->reserved) { - GtsEdge * e1; - GTS_OBJECT (t)->reserved = NULL; - e1 = next_edge (t, NULL, e); - triangle_next (e1, e); - triangle_next (next_edge (t, e1, e), e); - ncomponent++; - } - i = i->next; - } - - g_slist_foreach (triangles, (GFunc) gts_object_reset_reserved, NULL); - g_slist_free (triangles); - - return ncomponent; -} - -/** - * 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_edge_manifold_faces: - * @e: a #GtsEdge. - * @s: a #GtsSurface. - * @f1: pointer for first face. - * @f2: pointer for second face. - * - * If @e is a manifold edge of surface @s, fills @f1 and @f2 with the - * faces belonging to @s and sharing @e. - * - * Returns: %TRUE if @e is a manifold edge, %FALSE otherwise. - */ -gboolean gts_edge_manifold_faces (GtsEdge * e, GtsSurface * s, - GtsFace ** f1, GtsFace ** f2) -{ - GSList * i; - - g_return_val_if_fail (e != NULL, FALSE); - g_return_val_if_fail (s != NULL, FALSE); - g_return_val_if_fail (f1 != NULL, FALSE); - g_return_val_if_fail (f2 != NULL, FALSE); - - *f1 = *f2 = NULL; - i = e->triangles; - while (i) { - if (GTS_IS_FACE (i->data) && gts_face_has_parent_surface (i->data, s)) { - if (!(*f1)) *f1 = i->data; - else if (!(*f2)) *f2 = i->data; - else return FALSE; - } - i = i->next; - } - - return (*f1 && *f2); -} Index: trunk/src_3rd/gts/matrix.c =================================================================== --- trunk/src_3rd/gts/matrix.c (revision 6802) +++ trunk/src_3rd/gts/matrix.c (nonexistent) @@ -1,725 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include "gts.h" - -/** - * gts_matrix_new: - * @a00: element [0][0]. - * @a01: element [0][1]. - * @a02: element [0][2]. - * @a03: element [0][3]. - * @a10: element [1][0]. - * @a11: element [1][1]. - * @a12: element [1][2]. - * @a13: element [1][3]. - * @a20: element [2][0]. - * @a21: element [2][1]. - * @a22: element [2][2]. - * @a23: element [2][3]. - * @a30: element [3][0]. - * @a31: element [3][1]. - * @a32: element [3][2]. - * @a33: element [3][3]. - * - * Allocates memory and initializes a new #GtsMatrix. - * - * Returns: a pointer to the newly created #GtsMatrix. - */ -GtsMatrix * gts_matrix_new (gdouble a00, gdouble a01, gdouble a02, gdouble a03, - gdouble a10, gdouble a11, gdouble a12, gdouble a13, - gdouble a20, gdouble a21, gdouble a22, gdouble a23, - gdouble a30, gdouble a31, gdouble a32, gdouble a33) -{ - GtsMatrix * m; - - m = g_malloc (4*sizeof (GtsVector4)); - - m[0][0] = a00; m[1][0] = a10; m[2][0] = a20; m[3][0] = a30; - m[0][1] = a01; m[1][1] = a11; m[2][1] = a21; m[3][1] = a31; - m[0][2] = a02; m[1][2] = a12; m[2][2] = a22; m[3][2] = a32; - m[0][3] = a03; m[1][3] = a13; m[2][3] = a23; m[3][3] = a33; - - return m; -} - -/** - * gts_matrix_assign: - * @m: a #GtsMatrix. - * @a00: element [0][0]. - * @a01: element [0][1]. - * @a02: element [0][2]. - * @a03: element [0][3]. - * @a10: element [1][0]. - * @a11: element [1][1]. - * @a12: element [1][2]. - * @a13: element [1][3]. - * @a20: element [2][0]. - * @a21: element [2][1]. - * @a22: element [2][2]. - * @a23: element [2][3]. - * @a30: element [3][0]. - * @a31: element [3][1]. - * @a32: element [3][2]. - * @a33: element [3][3]. - * - * Set values of matrix elements. - */ -void gts_matrix_assign (GtsMatrix * m, - gdouble a00, gdouble a01, gdouble a02, gdouble a03, - gdouble a10, gdouble a11, gdouble a12, gdouble a13, - gdouble a20, gdouble a21, gdouble a22, gdouble a23, - gdouble a30, gdouble a31, gdouble a32, gdouble a33) -{ - g_return_if_fail (m != NULL); - - m[0][0] = a00; m[1][0] = a10; m[2][0] = a20; m[3][0] = a30; - m[0][1] = a01; m[1][1] = a11; m[2][1] = a21; m[3][1] = a31; - m[0][2] = a02; m[1][2] = a12; m[2][2] = a22; m[3][2] = a32; - m[0][3] = a03; m[1][3] = a13; m[2][3] = a23; m[3][3] = a33; -} - -/** - * gts_matrix_projection: - * @t: a #GtsTriangle. - * - * Creates a new #GtsMatrix representing the projection onto a plane of normal - * given by @t. - * - * Returns: a pointer to the newly created #GtsMatrix. - */ -GtsMatrix * gts_matrix_projection (GtsTriangle * t) -{ - GtsVertex * v1, * v2, * v3; - GtsEdge * e1, * e2, * e3; - GtsMatrix * m; - gdouble x1, y1, z1, x2, y2, z2, x3, y3, z3, l; - - g_return_val_if_fail (t != NULL, NULL); - - m = g_malloc (4*sizeof (GtsVector4)); - gts_triangle_vertices_edges (t, NULL, &v1, &v2, &v3, &e1, &e2, &e3); - - x1 = GTS_POINT (v2)->x - GTS_POINT (v1)->x; - y1 = GTS_POINT (v2)->y - GTS_POINT (v1)->y; - z1 = GTS_POINT (v2)->z - GTS_POINT (v1)->z; - x2 = GTS_POINT (v3)->x - GTS_POINT (v1)->x; - y2 = GTS_POINT (v3)->y - GTS_POINT (v1)->y; - z2 = GTS_POINT (v3)->z - GTS_POINT (v1)->z; - x3 = y1*z2 - z1*y2; y3 = z1*x2 - x1*z2; z3 = x1*y2 - y1*x2; - x2 = y3*z1 - z3*y1; y2 = z3*x1 - x3*z1; z2 = x3*y1 - y3*x1; - - g_assert ((l = sqrt (x1*x1 + y1*y1 + z1*z1)) > 0.0); - m[0][0] = x1/l; m[1][0] = y1/l; m[2][0] = z1/l; m[3][0] = 0.; - g_assert ((l = sqrt (x2*x2 + y2*y2 + z2*z2)) > 0.0); - m[0][1] = x2/l; m[1][1] = y2/l; m[2][1] = z2/l; m[3][1] = 0.; - g_assert ((l = sqrt (x3*x3 + y3*y3 + z3*z3)) > 0.0); - m[0][2] = x3/l; m[1][2] = y3/l; m[2][2] = z3/l; m[3][2] = 0.; - m[0][3] = 0; m[1][3] = 0.; m[2][3] = 0.; m[3][3] = 1.; - - return m; -} - -/** - * gts_matrix_transpose: - * @m: a #GtsMatrix. - * - * Returns: a pointer to a newly created #GtsMatrix transposed of @m. - */ -GtsMatrix * gts_matrix_transpose (GtsMatrix * m) -{ - GtsMatrix * mi; - - g_return_val_if_fail (m != NULL, NULL); - - mi = g_malloc (4*sizeof (GtsVector4)); - - mi[0][0] = m[0][0]; mi[1][0] = m[0][1]; - mi[2][0] = m[0][2]; mi[3][0] = m[0][3]; - mi[0][1] = m[1][0]; mi[1][1] = m[1][1]; - mi[2][1] = m[1][2]; mi[3][1] = m[1][3]; - mi[0][2] = m[2][0]; mi[1][2] = m[2][1]; - mi[2][2] = m[2][2]; mi[3][2] = m[2][3]; - mi[0][3] = m[3][0]; mi[1][3] = m[3][1]; - mi[2][3] = m[3][2]; mi[3][3] = m[3][3]; - - return mi; -} - -/* - * calculate the determinant of a 2x2 matrix. - * - * Adapted from: - * Matrix Inversion - * by Richard Carling - * from "Graphics Gems", Academic Press, 1990 - */ -static gdouble det2x2 (gdouble a, gdouble b, gdouble c, gdouble d) -{ - gdouble ans2; - - ans2 = a*d - b*c; - return ans2; -} - -/* - * calculate the determinant of a 3x3 matrix - * in the form - * - * | a1, b1, c1 | - * | a2, b2, c2 | - * | a3, b3, c3 | - * - * Adapted from: - * Matrix Inversion - * by Richard Carling - * from "Graphics Gems", Academic Press, 1990 - */ -static gdouble det3x3 (gdouble a1, gdouble a2, gdouble a3, - gdouble b1, gdouble b2, gdouble b3, - gdouble c1, gdouble c2, gdouble c3) -{ - gdouble ans3; - - ans3 = a1 * det2x2( b2, b3, c2, c3 ) - - b1 * det2x2( a2, a3, c2, c3 ) - + c1 * det2x2( a2, a3, b2, b3 ); - return ans3; -} - -/** - * gts_matrix_determinant: - * @m: a #GtsMatrix. - * - * Returns: the value of det(@m). - */ -gdouble gts_matrix_determinant (GtsMatrix * m) -{ - gdouble ans4; - gdouble a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4; - - g_return_val_if_fail (m != NULL, 0.0); - - a1 = m[0][0]; b1 = m[0][1]; - c1 = m[0][2]; d1 = m[0][3]; - - a2 = m[1][0]; b2 = m[1][1]; - c2 = m[1][2]; d2 = m[1][3]; - - a3 = m[2][0]; b3 = m[2][1]; - c3 = m[2][2]; d3 = m[2][3]; - - a4 = m[3][0]; b4 = m[3][1]; - c4 = m[3][2]; d4 = m[3][3]; - - ans4 = a1 * det3x3 (b2, b3, b4, c2, c3, c4, d2, d3, d4) - - b1 * det3x3 (a2, a3, a4, c2, c3, c4, d2, d3, d4) - + c1 * det3x3 (a2, a3, a4, b2, b3, b4, d2, d3, d4) - - d1 * det3x3 (a2, a3, a4, b2, b3, b4, c2, c3, c4); - - return ans4; -} - -/* - * adjoint( original_matrix, inverse_matrix ) - * - * calculate the adjoint of a 4x4 matrix - * - * Let a denote the minor determinant of matrix A obtained by - * ij - * - * deleting the ith row and jth column from A. - * - * i+j - * Let b = (-1) a - * ij ji - * - * The matrix B = (b ) is the adjoint of A - * ij - */ -static GtsMatrix * adjoint (GtsMatrix * m) -{ - gdouble a1, a2, a3, a4, b1, b2, b3, b4; - gdouble c1, c2, c3, c4, d1, d2, d3, d4; - GtsMatrix * ma; - - a1 = m[0][0]; b1 = m[0][1]; - c1 = m[0][2]; d1 = m[0][3]; - - a2 = m[1][0]; b2 = m[1][1]; - c2 = m[1][2]; d2 = m[1][3]; - - a3 = m[2][0]; b3 = m[2][1]; - c3 = m[2][2]; d3 = m[2][3]; - - a4 = m[3][0]; b4 = m[3][1]; - c4 = m[3][2]; d4 = m[3][3]; - - ma = g_malloc (4*sizeof (GtsVector4)); - - /* row column labeling reversed since we transpose rows & columns */ - - ma[0][0] = det3x3 (b2, b3, b4, c2, c3, c4, d2, d3, d4); - ma[1][0] = - det3x3 (a2, a3, a4, c2, c3, c4, d2, d3, d4); - ma[2][0] = det3x3 (a2, a3, a4, b2, b3, b4, d2, d3, d4); - ma[3][0] = - det3x3 (a2, a3, a4, b2, b3, b4, c2, c3, c4); - - ma[0][1] = - det3x3 (b1, b3, b4, c1, c3, c4, d1, d3, d4); - ma[1][1] = det3x3 (a1, a3, a4, c1, c3, c4, d1, d3, d4); - ma[2][1] = - det3x3 (a1, a3, a4, b1, b3, b4, d1, d3, d4); - ma[3][1] = det3x3 (a1, a3, a4, b1, b3, b4, c1, c3, c4); - - ma[0][2] = det3x3 (b1, b2, b4, c1, c2, c4, d1, d2, d4); - ma[1][2] = - det3x3 (a1, a2, a4, c1, c2, c4, d1, d2, d4); - ma[2][2] = det3x3 (a1, a2, a4, b1, b2, b4, d1, d2, d4); - ma[3][2] = - det3x3 (a1, a2, a4, b1, b2, b4, c1, c2, c4); - - ma[0][3] = - det3x3 (b1, b2, b3, c1, c2, c3, d1, d2, d3); - ma[1][3] = det3x3 (a1, a2, a3, c1, c2, c3, d1, d2, d3); - ma[2][3] = - det3x3 (a1, a2, a3, b1, b2, b3, d1, d2, d3); - ma[3][3] = det3x3 (a1, a2, a3, b1, b2, b3, c1, c2, c3); - - return ma; -} - - -/** - * gts_matrix_inverse: - * @m: a #GtsMatrix. - * - * Returns: a pointer to a newly created #GtsMatrix inverse of @m or %NULL - * if @m is not invertible. - */ -GtsMatrix * gts_matrix_inverse (GtsMatrix * m) -{ - GtsMatrix * madj; - gdouble det; - gint i, j; - - g_return_val_if_fail (m != NULL, NULL); - - det = gts_matrix_determinant (m); - if (det == 0.) - return NULL; - - madj = adjoint (m); - for (i = 0; i < 4; i++) - for(j = 0; j < 4; j++) - madj[i][j] /= det; - - return madj; -} - -/** - * gts_matrix3_inverse: - * @m: a 3x3 #GtsMatrix. - * - * Returns: a pointer to a newly created 3x3 #GtsMatrix inverse of @m or %NULL - * if @m is not invertible. - */ -GtsMatrix * gts_matrix3_inverse (GtsMatrix * m) -{ - GtsMatrix * mi; - gdouble det; - - g_return_val_if_fail (m != NULL, NULL); - - det = (m[0][0]*(m[1][1]*m[2][2] - m[2][1]*m[1][2]) - - m[0][1]*(m[1][0]*m[2][2] - m[2][0]*m[1][2]) + - m[0][2]*(m[1][0]*m[2][1] - m[2][0]*m[1][1])); - if (det == 0.0) - return NULL; - - mi = g_malloc0 (4*sizeof (GtsVector)); - - mi[0][0] = (m[1][1]*m[2][2] - m[1][2]*m[2][1])/det; - mi[0][1] = (m[2][1]*m[0][2] - m[0][1]*m[2][2])/det; - mi[0][2] = (m[0][1]*m[1][2] - m[1][1]*m[0][2])/det; - mi[1][0] = (m[1][2]*m[2][0] - m[1][0]*m[2][2])/det; - mi[1][1] = (m[0][0]*m[2][2] - m[2][0]*m[0][2])/det; - mi[1][2] = (m[1][0]*m[0][2] - m[0][0]*m[1][2])/det; - mi[2][0] = (m[1][0]*m[2][1] - m[2][0]*m[1][1])/det; - mi[2][1] = (m[2][0]*m[0][1] - m[0][0]*m[2][1])/det; - mi[2][2] = (m[0][0]*m[1][1] - m[0][1]*m[1][0])/det; - - return mi; -} - -/** - * gts_matrix_print: - * @m: a #GtsMatrix. - * @fptr: a file descriptor. - * - * Print @m to file @fptr. - */ -void gts_matrix_print (GtsMatrix * m, FILE * fptr) -{ - g_return_if_fail (m != NULL); - g_return_if_fail (fptr != NULL); - - fprintf (fptr, - "[[%15.7g %15.7g %15.7g %15.7g]\n" - " [%15.7g %15.7g %15.7g %15.7g]\n" - " [%15.7g %15.7g %15.7g %15.7g]\n" - " [%15.7g %15.7g %15.7g %15.7g]]\n", - m[0][0], m[0][1], m[0][2], m[0][3], - m[1][0], m[1][1], m[1][2], m[1][3], - m[2][0], m[2][1], m[2][2], m[2][3], - m[3][0], m[3][1], m[3][2], m[3][3]); -} - -/** - * gts_vector_print: - * @v: a #GtsVector. - * @fptr: a file descriptor. - * - * Print @s to file @fptr. - */ -void gts_vector_print (GtsVector v, FILE * fptr) -{ - g_return_if_fail (fptr != NULL); - - fprintf (fptr, - "[%15.7g %15.7g %15.7g ]\n", - v[0], v[1], v[2]); -} - -/** - * gts_vector4_print: - * @v: a #GtsVector4. - * @fptr: a file descriptor. - * - * Print @v to file @fptr. - */ -void gts_vector4_print (GtsVector4 v, FILE * fptr) -{ - g_return_if_fail (fptr != NULL); - - fprintf (fptr, - "[%15.7g %15.7g %15.7g %15.7g]\n", - v[0], v[1], v[2], v[3]); -} - -/* [cos(alpha)]^2 */ -#define COSALPHA2 0.999695413509 /* alpha = 1 degree */ -/* [sin(alpha)]^2 */ -#define SINALPHA2 3.04586490453e-4 /* alpha = 1 degree */ - -/** - * gts_matrix_compatible_row: - * @A: a #GtsMatrix. - * @b: a #GtsVector. - * @n: the number of previous constraints of @A.x=@b. - * @A1: a #GtsMatrix. - * @b1: a #GtsVector. - * - * Given a system of @n constraints @A.x=@b adds to it the compatible - * constraints defined by @A1.x=@b1. The compatibility is determined - * by insuring that the resulting system is well-conditioned (see - * Lindstrom and Turk (1998, 1999)). - * - * Returns: the number of constraints of the resulting system. - */ -guint gts_matrix_compatible_row (GtsMatrix * A, - GtsVector b, - guint n, - GtsVector A1, - gdouble b1) -{ - gdouble na1; - - g_return_val_if_fail (A != NULL, 0); - - na1 = gts_vector_scalar (A1, A1); - if (na1 == 0.0) - return n; - - /* normalize row */ - na1 = sqrt (na1); - A1[0] /= na1; A1[1] /= na1; A1[2] /= na1; b1 /= na1; - - if (n == 1) { - gdouble a0a1 = gts_vector_scalar (A[0], A1); - if (a0a1*a0a1 >= COSALPHA2) - return 1; - } - else if (n == 2) { - GtsVector V; - gdouble s; - - gts_vector_cross (V, A[0], A[1]); - s = gts_vector_scalar (V, A1); - if (s*s <= gts_vector_scalar (V, V)*SINALPHA2) - return 2; - } - - A[n][0] = A1[0]; A[n][1] = A1[1]; A[n][2] = A1[2]; b[n] = b1; - return n + 1; -} - -/** - * gts_matrix_quadratic_optimization: - * @A: a #GtsMatrix. - * @b: a #GtsVector. - * @n: the number of constraints (must be smaller than 3). - * @H: a symmetric positive definite Hessian. - * @c: a #GtsVector. - * - * Solve a quadratic optimization problem: Given a quadratic objective function - * f which can be written as: f(x) = x^t.@H.x + @c^t.x + k, where @H is the - * symmetric positive definite Hessian of f and k is a constant, find the - * minimum of f subject to the set of @n prior linear constraints, defined by - * the first @n rows of @A and @b (@A.x = @b). The new constraints given by - * the minimization are added to @A and @b only if they are linearly - * independent as determined by gts_matrix_compatible_row(). - * - * Returns: the new number of constraints defined by @A and @b. - */ -guint gts_matrix_quadratic_optimization (GtsMatrix * A, - GtsVector b, - guint n, - GtsMatrix * H, - GtsVector c) -{ - g_return_val_if_fail (A != NULL, 0); - g_return_val_if_fail (b != NULL, 0); - g_return_val_if_fail (n < 3, 0); - g_return_val_if_fail (H != NULL, 0); - - switch (n) { - case 0: { - n = gts_matrix_compatible_row (A, b, n, H[0], - c[0]); - n = gts_matrix_compatible_row (A, b, n, H[1], - c[1]); - n = gts_matrix_compatible_row (A, b, n, H[2], - c[2]); - return n; - } - case 1: { - GtsVector Q0 = {0., 0., 0.}; - GtsVector Q1 = {0., 0., 0.}; - GtsVector A1; - gdouble max = A[0][0]*A[0][0]; - guint d = 0; - - /* build a vector orthogonal to the constraint */ - if (A[0][1]*A[0][1] > max) { max = A[0][1]*A[0][1]; d = 1; } - if (A[0][2]*A[0][2] > max) { max = A[0][2]*A[0][2]; d = 2; } - switch (d) { - case 0: Q0[0] = - A[0][2]/A[0][0]; Q0[2] = 1.0; break; - case 1: Q0[1] = - A[0][2]/A[0][1]; Q0[2] = 1.0; break; - case 2: Q0[2] = - A[0][0]/A[0][2]; Q0[0] = 1.0; break; - } - - /* build a second vector orthogonal to the first and to the constraint */ - gts_vector_cross (Q1, A[0], Q0); - - A1[0] = gts_vector_scalar (Q0, H[0]); - A1[1] = gts_vector_scalar (Q0, H[1]); - A1[2] = gts_vector_scalar (Q0, H[2]); - - n = gts_matrix_compatible_row (A, b, n, A1, - gts_vector_scalar (Q0, c)); - - A1[0] = gts_vector_scalar (Q1, H[0]); - A1[1] = gts_vector_scalar (Q1, H[1]); - A1[2] = gts_vector_scalar (Q1, H[2]); - - n = gts_matrix_compatible_row (A, b, n, A1, - gts_vector_scalar (Q1, c)); - - return n; - } - case 2: { - /* build a vector orthogonal to the two constraints */ - GtsVector A1, Q; - - gts_vector_cross (Q, A[0], A[1]); - A1[0] = gts_vector_scalar (Q, H[0]); - A1[1] = gts_vector_scalar (Q, H[1]); - A1[2] = gts_vector_scalar (Q, H[2]); - - n = gts_matrix_compatible_row (A, b, n, A1, - gts_vector_scalar (Q, c)); - - return n; - } - default: - g_assert_not_reached (); - } - return 0; -} - -/** - * gts_matrix_destroy: - * @m: a #GtsMatrix. - * - * Free all the memory allocated for @m. - */ -void gts_matrix_destroy (GtsMatrix * m) -{ - g_free (m); -} - -/** - * gts_matrix_product: - * @m1: a #GtsMatrix. - * @m2: another #GtsMatrix. - * - * Returns: a new #GtsMatrix, product of @m1 and @m2. - */ -GtsMatrix * gts_matrix_product (GtsMatrix * m1, GtsMatrix * m2) -{ - guint i, j; - GtsMatrix * m; - - g_return_val_if_fail (m1 != NULL, NULL); - g_return_val_if_fail (m2 != NULL, NULL); - g_return_val_if_fail (m1 != m2, NULL); - - m = g_malloc (4*sizeof (GtsVector4)); - - for (i = 0; i < 4; i++) - for (j = 0; j < 4; j++) - m[i][j] = m1[i][0]*m2[0][j] + m1[i][1]*m2[1][j] + - m1[i][2]*m2[2][j] + m1[i][3]*m2[3][j]; - return m; -} - -/** - * gts_matrix_zero: - * @m: a #GtsMatrix or $NULL. - * - * Initializes @m to zeros. Allocates a matrix if @m is %NULL. - * - * Returns: the zero'ed matrix. - */ -GtsMatrix * gts_matrix_zero (GtsMatrix * m) -{ - if (m == NULL) - m = g_malloc0 (4*sizeof (GtsVector4)); - else { - m[0][0] = m[1][0] = m[2][0] = m[3][0] = 0.; - m[0][1] = m[1][1] = m[2][1] = m[3][1] = 0.; - m[0][2] = m[1][2] = m[2][2] = m[3][2] = 0.; - m[0][3] = m[1][3] = m[2][3] = m[3][3] = 0.; - } - return m; -} - -/** - * gts_matrix_identity: - * @m: a #GtsMatrix or %NULL. - * - * Initializes @m to an identity matrix. Allocates a matrix if @m is %NULL. - * - * Returns: the identity matrix. - */ -GtsMatrix * gts_matrix_identity (GtsMatrix * m) -{ - m = gts_matrix_zero (m); - m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.; - return m; -} - -/** - * gts_matrix_scale: - * @m: a #GtsMatrix or %NULL. - * @s: the scaling vector. - * - * Initializes @m to a scaling matrix for @s. Allocates a matrix if @m - * is %NULL. - * - * Returns: the scaling matrix. - */ -GtsMatrix * gts_matrix_scale (GtsMatrix * m, GtsVector s) -{ - m = gts_matrix_zero (m); - m[0][0] = s[0]; - m[1][1] = s[1]; - m[2][2] = s[2]; - m[3][3] = 1.; - return m; -} - -/** - * gts_matrix_translate: - * @m: a #GtsMatrix or %NULL. - * @t: the translation vector. - * - * Initializes @m to a translation matrix for @t. Allocates a new - * matrix if @m is %NULL. - * - * Returns: the translation matix. - */ -GtsMatrix * gts_matrix_translate (GtsMatrix * m, GtsVector t) -{ - m = gts_matrix_zero (m); - m[0][3] = t[0]; - m[1][3] = t[1]; - m[2][3] = t[2]; - m[3][3] = 1.; - m[0][0] = m[1][1] = m[2][2] = 1.; - return m; -} - -/** - * gts_matrix_rotate: - * @m: a #GtsMatrix or %NULL. - * @r: the rotation axis. - * @angle: the angle (in radians) to rotate by. - * - * Initializes @m to a rotation matrix around @r by @angle. - * Allocates a new matrix if @m is %NULL. - * - * Returns: the rotation matrix. - */ -GtsMatrix * gts_matrix_rotate (GtsMatrix * m, - GtsVector r, - gdouble angle) -{ - gdouble c, c1, s; - - gts_vector_normalize (r); - - c = cos (angle); - c1 = 1. - c; - s = sin (angle); - - if (m == NULL) - m = g_malloc (4*sizeof (GtsVector4)); - - m[0][0] = r[0]*r[0]*c1 + c; - m[0][1] = r[0]*r[1]*c1 - r[2]*s; - m[0][2] = r[0]*r[2]*c1 + r[1]*s; - m[0][3] = 0.; - - m[1][0] = r[1]*r[0]*c1 + r[2]*s; - m[1][1] = r[1]*r[1]*c1 + c; - m[1][2] = r[1]*r[2]*c1 - r[0]*s; - m[1][3] = 0.; - - m[2][0] = r[2]*r[0]*c1 - r[1]*s; - m[2][1] = r[2]*r[1]*c1 + r[0]*s; - m[2][2] = r[2]*r[2]*c1 + c; - m[2][3] = 0.; - - m[3][0] = 0.; - m[3][1] = 0.; - m[3][2] = 0.; - m[3][3] = 1.; - - return m; -} Index: trunk/src_3rd/gts/psurface.c =================================================================== --- trunk/src_3rd/gts/psurface.c (revision 6802) +++ trunk/src_3rd/gts/psurface.c (nonexistent) @@ -1,471 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include -#include "gts.h" - -#define HEAP_INSERT_OBJECT(h, e) (GTS_OBJECT (e)->reserved =\ - gts_eheap_insert (h, e)) -#define HEAP_REMOVE_OBJECT(h, e) (gts_eheap_remove (h, GTS_OBJECT (e)->reserved),\ - GTS_OBJECT (e)->reserved = NULL) - -static void psurface_destroy (GtsObject * object) -{ - GtsPSurface * ps = GTS_PSURFACE (object); - guint i; - - if (!GTS_PSURFACE_IS_CLOSED (ps)) - gts_psurface_close (ps); - - for (i = 0; i < ps->split->len; i++) - if (g_ptr_array_index (ps->split, i)) - gts_object_destroy (GTS_OBJECT (g_ptr_array_index (ps->split, i))); - g_ptr_array_free (ps->split, TRUE); - - (* GTS_OBJECT_CLASS (gts_psurface_class ())->parent_class->destroy) (object); -} - -static void psurface_class_init (GtsObjectClass * klass) -{ - klass->destroy = psurface_destroy; -} - -static void psurface_init (GtsPSurface * psurface) -{ - psurface->s = NULL; - psurface->split = g_ptr_array_new (); - psurface->split_class = gts_split_class (); - psurface->pos = psurface->min = 0; - psurface->vertices = psurface->faces = NULL; -} - -/** - * gts_psurface_class: - * - * Returns: the #GtsPSurfaceClass. - */ -GtsPSurfaceClass * gts_psurface_class (void) -{ - static GtsPSurfaceClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo psurface_info = { - "GtsPSurface", - sizeof (GtsPSurface), - sizeof (GtsPSurfaceClass), - (GtsObjectClassInitFunc) psurface_class_init, - (GtsObjectInitFunc) psurface_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (gts_object_class (), - &psurface_info); - } - - return klass; -} - -static GtsVertex * edge_collapse (GtsPSurface * ps, - GtsEdge * e, - GtsEHeap * heap, - GtsCoarsenFunc coarsen_func, - gpointer coarsen_data, - gdouble maxcosine2) -{ - GtsVertex * v1 = GTS_SEGMENT (e)->v1, * v2 = GTS_SEGMENT (e)->v2, * mid; - GtsSplit * vs; - GtsObject * o1, * o2; - - /* if the edge is degenerate (i.e. v1 == v2), destroy and return */ - if (v1 == v2) { - gts_object_destroy (GTS_OBJECT (e)); - return NULL; - } - - if (!gts_edge_collapse_is_valid (e) || - /* check that a non-manifold edge is not a contact edge */ - (g_slist_length (e->triangles) > 2 && gts_edge_is_contact (e) > 1)) { - GTS_OBJECT (e)->reserved = - gts_eheap_insert_with_key (heap, e, G_MAXDOUBLE); - return NULL; - } - - mid = (*coarsen_func) (e, ps->s->vertex_class, coarsen_data); - - if (gts_edge_collapse_creates_fold (e, mid, maxcosine2)) { - GTS_OBJECT (e)->reserved = - gts_eheap_insert_with_key (heap, e, G_MAXDOUBLE); - gts_object_destroy (GTS_OBJECT (mid)); - return NULL; - } - - if (GTS_OBJECT (v1)->reserved) - o1 = GTS_OBJECT (v1)->reserved; - else - o1 = GTS_OBJECT (v1); - if (GTS_OBJECT (v2)->reserved) - o2 = GTS_OBJECT (v2)->reserved; - else - o2 = GTS_OBJECT (v2); - vs = gts_split_new (ps->split_class, mid, o1, o2); - gts_split_collapse (vs, ps->s->edge_class, heap); - GTS_OBJECT (vs->v)->reserved = vs; - g_ptr_array_add (ps->split, vs); - - return mid; -} - -static void update_2nd_closest_neighbors (GtsVertex * v, GtsEHeap * heap) -{ - GSList * i = v->segments; - GSList * list = NULL; - - while (i) { - GtsSegment * s = i->data; - if (GTS_IS_EDGE (s)) { - GtsVertex * v1 = s->v1 == v ? s->v2 : s->v1; - GSList * j = v1->segments; - while (j) { - GtsSegment * s1 = j->data; - if (GTS_IS_EDGE (s1) && !g_slist_find (list, s1)) - list = g_slist_prepend (list, s1); - j = j->next; - } - } - i = i->next; - } - - i = list; - while (i) { - GtsEdge * e = i->data; - if (GTS_OBJECT (e)->reserved) - HEAP_REMOVE_OBJECT (heap, e); - HEAP_INSERT_OBJECT (heap, e); - i = i->next; - } - - g_slist_free (list); -} - -static gdouble edge_length2 (GtsEdge * e) -{ - return gts_point_distance2 (GTS_POINT (GTS_SEGMENT (e)->v1), - GTS_POINT (GTS_SEGMENT (e)->v2)); -} - -static void create_heap_coarsen (GtsEdge * e, GtsEHeap * heap) -{ - HEAP_INSERT_OBJECT (heap, e); -} - -/* #define DEBUG_FOLD */ -/* #define DEBUG_CONTACT_VERTEX */ - -#ifdef DEBUG_FOLD -static void check_fold (GtsTriangle * t, gdouble * maxcosine2) -{ - GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3; - - - if (gts_triangles_are_folded (e1->triangles, - GTS_SEGMENT (e1)->v1, - GTS_SEGMENT (e1)->v2, - *maxcosine2) || - gts_triangles_are_folded (e2->triangles, - GTS_SEGMENT (e2)->v1, - GTS_SEGMENT (e2)->v2, - *maxcosine2) || - gts_triangles_are_folded (e3->triangles, - GTS_SEGMENT (e3)->v1, - GTS_SEGMENT (e3)->v2, - *maxcosine2)) { - fprintf (stderr, "triangle %p:(%p,%p,%p) is folded\n", t, e1, e2, e3); - g_assert_not_reached (); - } -} -#endif - -/** - * gts_psurface_new: - * @klass: a #GtsPSurfaceClass. - * @surface: a #GtsSurface. - * @split_class: a #GtsSplitClass to use for the new progressive surface. - * @cost_func: cost function for the edge collapse algorithm. - * @cost_data: data to pass to @cost_func. - * @coarsen_func: the function returning the vertex replacement for the edge - * collapse. - * @coarsen_data: data to pass to @coarsen_func. - * @stop_func: the function to call to decide whether to stop the coarsening - * process. - * @stop_data: data to pass to @stop_func. - * @minangle: the minimum angle allowable between two neighboring triangles. - * This is used to avoid introducing folds in the mesh during simplification. - * - * This function works in exactly the same way as the - * gts_surface_coarsen() function, except that the history of edge - * collapse is saved in an array of #GtsSplit objects. This allows for - * dynamic continuous multiresolution control of the input @surface. - * - * Returns: a new progressive surface. - */ -GtsPSurface * gts_psurface_new (GtsPSurfaceClass * klass, - GtsSurface * surface, - GtsSplitClass * split_class, - GtsKeyFunc cost_func, - gpointer cost_data, - GtsCoarsenFunc coarsen_func, - gpointer coarsen_data, - GtsStopFunc stop_func, - gpointer stop_data, - gdouble minangle) -{ - GtsPSurface * psurface; - GtsEHeap * heap; - GtsEdge * e; - gdouble top_cost, maxcosine2; - guint i; - - g_return_val_if_fail (klass != NULL, NULL); - g_return_val_if_fail (surface != NULL, NULL); - g_return_val_if_fail (split_class != NULL, NULL); - g_return_val_if_fail (stop_func != NULL, NULL); - - psurface = GTS_PSURFACE (gts_object_new (GTS_OBJECT_CLASS (klass))); - psurface->s = surface; - psurface->split_class = split_class; - - if (cost_func == NULL) - cost_func = (GtsKeyFunc) edge_length2; - if (coarsen_func == NULL) - coarsen_func = (GtsCoarsenFunc) gts_segment_midvertex; - - heap = gts_eheap_new (cost_func, cost_data); - maxcosine2 = cos (minangle); maxcosine2 *= maxcosine2; - - gts_eheap_freeze (heap); - gts_surface_foreach_edge (surface, (GtsFunc) create_heap_coarsen, heap); - gts_eheap_thaw (heap); - /* we want to control edge destruction manually */ - gts_allow_floating_edges = TRUE; - while ((e = gts_eheap_remove_top (heap, &top_cost)) && - (top_cost < G_MAXDOUBLE) && - !(*stop_func) (top_cost, gts_eheap_size (heap) - - gts_edge_face_number (e, surface), stop_data)) { - GtsVertex * v = edge_collapse (psurface, e, heap, - coarsen_func, coarsen_data, maxcosine2); - if (v != NULL) { - update_2nd_closest_neighbors (v, heap); -#ifdef DEBUG_FOLD - { - GSList * triangles = gts_vertex_triangles (v, NULL), * i; - fprintf (stderr, "\n---- Check for folds ----\n%p: ", v); - i = triangles; - while (i) { - GtsTriangle * t = i->data; - fprintf (stderr, "%p:(%p,%p,%p) ", t, t->e1, t->e2, t->e3); - i = i->next; - } - fprintf (stderr, "\n"); - g_slist_free (triangles); - gts_surface_foreach_face (surface, (GtsFunc) check_fold, &maxcosine2); - } -#endif -#ifdef DEBUG_CONTACT_VERTEX - if (gts_vertex_is_contact (v, FALSE) != 1) { - FILE * fptr = fopen ("after", "wt"); - GSList * triangles = gts_vertex_triangles (v, NULL), * i; - - fprintf (stderr, "collapse of %p created a contact vertex\n", e); - - fprintf (fptr, - "(geometry \"sphere\" { = SPHERE 0.1 0. 0. 0. })\n" - "(normalization \"sphere\" none)\n"); - i = triangles; - while (i) { - gts_write_triangle (i->data, GTS_POINT (v), fptr); - i = i->next; - } - g_assert_not_reached (); - } -#endif - } - } - gts_allow_floating_edges = FALSE; - - /* set reserved field of remaining edges back to NULL */ - if (e) GTS_OBJECT (e)->reserved = NULL; - gts_eheap_foreach (heap, (GFunc) gts_object_reset_reserved, NULL); - - gts_eheap_destroy (heap); - - psurface->pos = psurface->split->len; - psurface->min = gts_surface_vertex_number (psurface->s); - - /* set reserved field of vertices (used to build the hierarchy) - back to NULL */ - for (i = 0; i < psurface->split->len; i++) { - GtsSplit * vs = g_ptr_array_index (psurface->split, i); - gts_object_reset_reserved (GTS_OBJECT (vs->v)); - } - - return psurface; -} - -/** - * gts_psurface_add_vertex: - * @ps: a #GtsPSurface. - * - * Adds a vertex to the progressive surface @ps by expanding the next - * available #GtsSplit. - * - * Returns: the expanded #GtsSplit or %NULL if all the #GtsSplit have already - * been expanded. - */ -GtsSplit * gts_psurface_add_vertex (GtsPSurface * ps) -{ - GtsSplit * vs; - - g_return_val_if_fail (ps != NULL, NULL); - g_return_val_if_fail (GTS_PSURFACE_IS_CLOSED (ps), NULL); - - if (ps->pos == 0) - return NULL; - - vs = g_ptr_array_index (ps->split, --ps->pos); - gts_split_expand (vs, ps->s, ps->s->edge_class); - - return vs; -} - -/** - * gts_psurface_remove_vertex: - * @ps: a #GtsPSurface. - * - * Removes one vertex from the progressive surface @ps by collapsing the first - * available #GtsSplit. - * - * Returns: the collapsed #GtsSplit or %NULL if all the #GtsSplit have already - * been collapsed. - */ -GtsSplit * gts_psurface_remove_vertex (GtsPSurface * ps) -{ - GtsSplit * vs; - - g_return_val_if_fail (ps != NULL, NULL); - g_return_val_if_fail (GTS_PSURFACE_IS_CLOSED (ps), NULL); - - if (ps->pos == ps->split->len) - return NULL; - - vs = g_ptr_array_index (ps->split, ps->pos++); - gts_split_collapse (vs, ps->s->edge_class, NULL); - - return vs; -} - -/** - * gts_psurface_max_vertex_number: - * @ps: a #GtsPSurface. - * - * Returns: the maximum number of vertices of @ps i.e. the number of vertices - * if all the #GtsSplit were expanded. - */ -guint gts_psurface_max_vertex_number (GtsPSurface * ps) -{ - g_return_val_if_fail (ps != NULL, 0); - - return ps->min + ps->split->len; -} - -/** - * gts_psurface_min_vertex_number: - * @ps: a #GtsPSurface. - * - * Returns: the minimum number of vertices of @ps i.e. the number of vertices - * if all the #GtsSplit were collapsed. - */ -guint gts_psurface_min_vertex_number (GtsPSurface * ps) -{ - g_return_val_if_fail (ps != NULL, 0); - - return ps->min; -} - -/** - * gts_psurface_set_vertex_number: - * @ps: a #GtsPSurface. - * @n: a number of vertices. - * - * Performs the required number of collapses or expansions to set the number - * of vertices of @ps to @n. - */ -void gts_psurface_set_vertex_number (GtsPSurface * ps, guint n) -{ - g_return_if_fail (ps != NULL); - g_return_if_fail (GTS_PSURFACE_IS_CLOSED (ps)); - - n = ps->min + ps->split->len - n; - while (ps->pos > n && gts_psurface_add_vertex (ps)) - ; - while (ps->pos < n && gts_psurface_remove_vertex (ps)) - ; -} - -/** - * gts_psurface_get_vertex_number: - * @ps: a #GtsPSurface. - * - * Returns: the current number of vertices of @ps. - */ -guint gts_psurface_get_vertex_number (GtsPSurface * ps) -{ - g_return_val_if_fail (ps != NULL, 0); - - if (!GTS_PSURFACE_IS_CLOSED (ps)) - return ps->min + ps->pos; - else - return ps->min + ps->split->len - ps->pos; -} - -/** - * gts_psurface_foreach_vertex: - * @ps: a #GtsPSurface. - * @func: a function to call for each vertex of @ps. - * @data: data to be passed to @func. - * - * Calls @func for each (potential) vertex of @ps, whether actually used - * or not. The vertices are called in the order they were created during the - * edge collapse operation. - */ -void gts_psurface_foreach_vertex (GtsPSurface * ps, - GtsFunc func, - gpointer data) -{ - guint i; - - g_return_if_fail (ps != NULL); - g_return_if_fail (func != NULL); - g_return_if_fail (GTS_PSURFACE_IS_CLOSED (ps)); - - for (i = 0; i < ps->split->len; i++) { - GtsSplit * vs = g_ptr_array_index (ps->split, i); - (*func) (vs->v, data); - } -} Index: trunk/src_3rd/gts/partition.c =================================================================== --- trunk/src_3rd/gts/partition.c (revision 6802) +++ trunk/src_3rd/gts/partition.c (nonexistent) @@ -1,1219 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include - -#include "gts.h" - -/* #define DEBUG */ - -/* Graph partition */ - -/** - * gts_graph_partition_edges_cut: - * @partition: a list of @GtsGraph representing a partition. - * - * Returns: the number of edges cut by the partition. - */ -guint gts_graph_partition_edges_cut (GSList * partition) -{ - guint cuts = 0; - - while (partition) { - cuts += gts_graph_edges_cut (partition->data); - partition = partition->next; - } - - return cuts/2; -} - -/** - * gts_graph_partition_edges_cut_weight: - * @partition: a list of @GtsGraph representing a partition. - * - * Returns: the total weight of the edges cut by the partition. - */ -gfloat gts_graph_partition_edges_cut_weight (GSList * partition) -{ - gfloat weight = 0.; - - while (partition) { - weight += gts_graph_edges_cut_weight (partition->data); - partition = partition->next; - } - - return weight/2.; -} - -/** - * gts_graph_partition_print_stats: - * @partition: a list of @GtsGraph representing a partition. - * @fp: a file pointer. - * - * Writes to @fp a summary of the properties of @partition. - */ -void gts_graph_partition_print_stats (GSList * partition, - FILE * fp) -{ - GtsRange weight; - GSList * i; - - g_return_if_fail (partition != NULL); - g_return_if_fail (fp != NULL); - - gts_range_init (&weight); - i = partition; - while (i) { - gts_range_add_value (&weight, gts_graph_weight (i->data)); - i = i->next; - } - gts_range_update (&weight); - - fprintf (fp, - "# parts: %d\n" - "# edge cuts: %5d edge cuts weight: %5g\n" - "# weight: ", - g_slist_length (partition), - gts_graph_partition_edges_cut (partition), - gts_graph_partition_edges_cut_weight (partition)); - gts_range_print (&weight, fp); - fputc ('\n', fp); -} - -/** - * gts_graph_partition_balance: - * @partition: a list of @GtsGraph representing a partition. - * - * Returns: the difference between the maximum and the minimum weight - * of the graphs in @partition. - */ -gfloat gts_graph_partition_balance (GSList * partition) -{ - gfloat wmin = G_MAXFLOAT; - gfloat wmax = - G_MAXFLOAT; - - g_return_val_if_fail (partition != NULL, 0.); - - while (partition) { - gfloat weight = gts_graph_weight (partition->data); - if (weight < wmin) - wmin = weight; - if (weight > wmax) - wmax = weight; - partition = partition->next; - } - return wmax - wmin; -} - -/** - * gts_graph_partition_clone: - * @partition: a list of @GtsGraph representing a partition. - * - * Returns: a new partition clone of @partition (i.e. a list of new - * graphs clones of the graphs in @partition). - */ -GSList * gts_graph_partition_clone (GSList * partition) -{ - GSList * cparts = NULL; - - while (partition) { - cparts = - g_slist_prepend (cparts, - gts_object_clone (GTS_OBJECT (partition->data))); - partition = partition->next; - } - return cparts; -} - -/** - * gts_graph_partition_destroy: - * @partition: a list of @GtsGraph representing a partition. - * - * Destroys all the graphs in @partition and frees @partition. - */ -void gts_graph_partition_destroy (GSList * partition) -{ - GSList * i = partition; - - while (i) { - gts_object_destroy (GTS_OBJECT (i->data)); - i = i->next; - } - g_slist_free (partition); -} - -static void find_smallest_degree (GtsGNode * n, gpointer * data) -{ - GtsGNode ** nmin = data[0]; - GtsGraph * g = data[1]; - guint * min = data[2]; - guint degree = gts_gnode_degree (n, g); - - if (degree < *min) { - *min = degree; - *nmin = n; - } -} - -static gint graph_comp_weight (GtsGraph * g1, GtsGraph * g2) -{ - if (gts_graph_weight (g1) > gts_graph_weight (g2)) - return 1; - return -1; -} - -static void partition_update (GSList * list, GtsGraph * g) -{ - GSList * i; - GtsGraph * g1; - GtsHeap * size_heap; - gboolean reinit = TRUE; - - /* initialize traversals */ - i = list; - while (i) { - GtsGNode * seed = GTS_OBJECT (i->data)->reserved; - GTS_OBJECT (seed)->reserved = - gts_graph_traverse_new (g, seed, GTS_BREADTH_FIRST, reinit); - reinit = FALSE; - i = i->next; - } - - size_heap = gts_heap_new ((GCompareFunc) graph_comp_weight); - i = list; - while (i) { - gts_heap_insert (size_heap, i->data); - i = i->next; - } - while ((g1 = gts_heap_remove_top (size_heap))) { - GtsGraphTraverse * t = GTS_OBJECT (GTS_OBJECT (g1)->reserved)->reserved; - GtsGNode * n = gts_graph_traverse_next (t); - if (n) { - gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); - gts_heap_insert (size_heap, g1); - } - } - gts_heap_destroy (size_heap); - - /* destroy traversals */ - i = list; - while (i) { - GtsGNode * seed = GTS_OBJECT (i->data)->reserved; - gts_graph_traverse_destroy (GTS_OBJECT (seed)->reserved); - GTS_OBJECT (seed)->reserved = NULL; - i = i->next; - } -} - -static void better_seed (GtsGNode * n, gpointer * data) -{ - guint * sum = data[0]; - GtsGNode ** seed = data[1]; - GtsGraph * g = data[2]; - guint sum1 = gts_graph_distance_sum (g, n); - - if (sum1 < *sum) { - *sum = sum1; - *seed = n; - } -} - -static GtsGNode * graph_new_seed (GtsGraph * g, GtsGNode * seed) -{ - guint sum = gts_graph_distance_sum (g, seed); - gpointer data[3]; - GtsGNode * new_seed = seed; - - data[0] = ∑ - data[1] = &new_seed; - data[2] = g; - gts_gnode_foreach_neighbor (seed, g, (GtsFunc) better_seed, data); - - return new_seed; -} - -/** - * gts_graph_bubble_partition: - * @g: a #GtsGraph. - * @np: number of partitions. - * @niter: the maximum number of iterations. - * @step_info: a #GtsFunc or %NULL. - * @data: user data to pass to @step_info. - * - * An implementation of the "bubble partitioning algorithm" of - * Diekmann, Preis, Schlimbach and Walshaw (2000). The maximum number - * of iteration on the positions of the graph growing seeds is - * controlled by @niter. - * - * If not %NULL @step_info is called after each iteration on the seeds - * positions passing the partition (a GSList) as argument. - * - * Returns: a list of @np new #GtsGraph representing the partition. - */ -GSList * gts_graph_bubble_partition (GtsGraph * g, - guint np, - guint niter, - GtsFunc step_info, - gpointer data) -{ - GSList * list = NULL, * seeds = NULL; - GtsGNode * seed = NULL; - guint min = G_MAXINT/2 - 1; - gpointer info[3]; - GtsGraph * g1; - gboolean changed = TRUE; - - g_return_val_if_fail (g != NULL, NULL); - g_return_val_if_fail (np > 0, NULL); - - info[0] = &seed; - info[1] = g; - info[2] = &min; - gts_container_foreach (GTS_CONTAINER (g), - (GtsFunc) find_smallest_degree, - info); - if (seed == NULL) - return NULL; - - g1 = GTS_GRAPH (gts_object_new (GTS_OBJECT (g)->klass)); - gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed)); - list = g_slist_prepend (list, g1); - GTS_OBJECT (g1)->reserved = seed; - seeds = g_slist_prepend (seeds, seed); - - while (--np && seed) - if ((seed = gts_graph_farthest (g, seeds))) { - g1 = GTS_GRAPH (gts_object_new (GTS_OBJECT (g)->klass)); - gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed)); - list = g_slist_prepend (list, g1); - GTS_OBJECT (g1)->reserved = seed; - seeds = g_slist_prepend (seeds, seed); - } - g_slist_free (seeds); - - partition_update (list, g); - - while (changed && niter--) { - GSList * i; - - changed = FALSE; - i = list; - while (i) { - GtsGraph * g1 = i->data; - GtsGNode * seed = GTS_OBJECT (g1)->reserved; - GtsGNode * new_seed = graph_new_seed (g1, seed); - if (new_seed != seed) { - changed = TRUE; - GTS_OBJECT (g1)->reserved = new_seed; - } - i = i->next; - } - - if (changed) { - i = list; - while (i) { - GtsGraph * g1 = i->data; - GtsGNode * seed = GTS_OBJECT (g1)->reserved; - - gts_object_destroy (GTS_OBJECT (g1)); - i->data = g1 = GTS_GRAPH (gts_object_new (GTS_OBJECT (g)->klass)); - gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed)); - GTS_OBJECT (g1)->reserved = seed; - i = i->next; - } - partition_update (list, g); - if (step_info) - (* step_info) (list, data); - } - } - g_slist_foreach (list, (GFunc) gts_object_reset_reserved, NULL); - return list; -} - -/* Graph bisection */ - -static gdouble node_cost (GtsGNode * n, gpointer * data) -{ - GtsGraph * g = data[0]; - GtsGraph * g1 = data[1]; - GSList * i = GTS_SLIST_CONTAINER (n)->items; - gdouble cost = 0.; - - while (i) { - GtsGEdge * e = i->data; - GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, e); - - if (gts_containee_is_contained (GTS_CONTAINEE (n1), GTS_CONTAINER (g))) { - if (gts_containee_is_contained (GTS_CONTAINEE (n1), GTS_CONTAINER (g1))) - cost -= gts_gedge_weight (e); - else - cost += gts_gedge_weight (e); - } - i = i->next; - } - - return cost; -} - -static void add_neighbor (GtsGNode * n, GtsEHeap * heap) -{ - if (GTS_OBJECT (n)->reserved == n) - return; - if (GTS_OBJECT (n)->reserved) - gts_eheap_remove (heap, GTS_OBJECT (n)->reserved); - GTS_OBJECT (n)->reserved = gts_eheap_insert (heap, n); -} - -static void add_unused (GtsGNode * n, GtsGraph * g2) -{ - if (GTS_OBJECT (n)->reserved) - GTS_OBJECT (n)->reserved = NULL; - else - gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n)); -} - -static gdouble degree_cost (GtsGNode * n, GtsGraph * g) -{ - return gts_gnode_degree (n, g); -} - -static void add_seed (GtsGNode * n, GtsEHeap * heap) -{ - gts_eheap_insert (heap, n); -} - -static void boundary_node1 (GtsGNode * n, GtsGraphBisection * bg) -{ - GSList * i = GTS_SLIST_CONTAINER (n)->items; - - while (i) { - GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); - if (gts_containee_is_contained (GTS_CONTAINEE (n1), - GTS_CONTAINER (bg->g2))) { - g_hash_table_insert (bg->bg1, n, n1); - return; - } - i = i->next; - } -} - -static void boundary_node2 (GtsGNode * n, GtsGraphBisection * bg) -{ - GSList * i = GTS_SLIST_CONTAINER (n)->items; - - while (i) { - GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); - if (gts_containee_is_contained (GTS_CONTAINEE (n1), - GTS_CONTAINER (bg->g1))) { - g_hash_table_insert (bg->bg2, n, n1); - return; - } - i = i->next; - } -} - -static void check_bg (GtsGNode * n, gpointer * data) -{ - GHashTable * bg = data[0]; - GtsGraph * g = data[1]; - gboolean * ok = data[2]; - guint * nb = data[3]; - guint nn = gts_gnode_degree (n, g); - - if (nn > 0) - (*nb)++; - if ((nn > 0 && !g_hash_table_lookup (bg, n)) || - (nn == 0 && g_hash_table_lookup (bg, n))) { - g_warning ("nn: %d lookup: %p\n", - nn, g_hash_table_lookup (bg, n)); - *ok = FALSE; - } -} - -/** - * gts_graph_bisection_check: - * @bg: a #GtsGraphBisection. - * - * Checks that the boundary of @bg is correctly defined (used for - * debugging purposes). - * - * Returns: %TRUE if @bg is ok, %FALSE otherwise. - */ -gboolean gts_graph_bisection_check (GtsGraphBisection * bg) -{ - gboolean ok = TRUE; - guint nb; - gpointer data[4]; - - g_return_val_if_fail (bg != NULL, FALSE); - - nb = 0; - data[0] = bg->bg1; - data[1] = bg->g2; - data[2] = &ok; - data[3] = &nb; - gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) check_bg, data); - g_return_val_if_fail (g_hash_table_size (bg->bg1) == nb, FALSE); - - nb = 0; - data[0] = bg->bg2; - data[1] = bg->g1; - gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) check_bg, data); - g_return_val_if_fail (g_hash_table_size (bg->bg2) == nb, FALSE); - - return ok; -} - -/** - * gts_graph_ggg_bisection: - * @g: a #GtsGraph. - * @ntry: the number of randomly selected initial seeds. - * - * An implementation of the "Greedy Graph Growing" algorithm of - * Karypis and Kumar (1997). - * - * @ntry randomly chosen seeds are used and the best partition is retained. - * - * Returns: a new #GtsGraphBisection of @g. - */ -GtsGraphBisection * gts_graph_ggg_bisection (GtsGraph * g, guint ntry) -{ - gfloat size, bestcost = G_MAXFLOAT, smin; - GtsGraph * bestg1 = NULL, * bestg2 = NULL; - gboolean balanced = FALSE; - GtsEHeap * degree_heap; - GtsGNode * seed; - GtsGraphBisection * bg; - - g_return_val_if_fail (g != NULL, NULL); - - bg = g_malloc (sizeof (GtsGraphBisection)); - bg->g = g; - - size = gts_graph_weight (g)/2.; - smin = 0.9*size; - - degree_heap = gts_eheap_new ((GtsKeyFunc) degree_cost, g); - gts_eheap_freeze (degree_heap); - gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_seed, degree_heap); - gts_eheap_thaw (degree_heap); - - while (ntry && ((seed = gts_eheap_remove_top (degree_heap, NULL)))) { - GtsGraph * g1, * g2; - GtsGNode * n; - gdouble cost; - gpointer data[2]; - GtsEHeap * heap; - - g1 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass), - g->node_class, g->edge_class); - g2 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass), - g->node_class, g->edge_class); - - data[0] = g; - data[1] = g1; - heap = gts_eheap_new ((GtsKeyFunc) node_cost, data); - - gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed)); - GTS_OBJECT (seed)->reserved = seed; - gts_gnode_foreach_neighbor (seed, g, (GtsFunc) add_neighbor, heap); - - while ((n = gts_eheap_remove_top (heap, &cost))) - if (gts_graph_weight (g1) + gts_gnode_weight (n) <= size) { - gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); - GTS_OBJECT (n)->reserved = n; - gts_gnode_foreach_neighbor (n, g, (GtsFunc) add_neighbor, heap); - } - else - GTS_OBJECT (n)->reserved = NULL; - gts_eheap_destroy (heap); - - gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_unused, g2); - - cost = gts_graph_edges_cut_weight (g1); - if (!bestg1 || - (!balanced && gts_graph_weight (g1) >= smin) || - (cost < bestcost && gts_graph_weight (g1) >= smin)) { - if (bestg1) - bestcost = cost; - if (bestg1) - gts_object_destroy (GTS_OBJECT (bestg1)); - if (bestg2) - gts_object_destroy (GTS_OBJECT (bestg2)); - bestg1 = g1; - bestg2 = g2; - if (gts_graph_weight (g1) >= smin) - balanced = TRUE; - } - else { - gts_object_destroy (GTS_OBJECT (g1)); - gts_object_destroy (GTS_OBJECT (g2)); - } - - ntry--; - } - gts_eheap_destroy (degree_heap); - -#ifdef DEBUG - fprintf (stderr, "bestcost: %5g g1: %5g|%5d g2: %5g|%5d\n", - bestcost, - gts_graph_weight (bestg1), - gts_container_size (GTS_CONTAINER (bestg1)), - gts_graph_weight (bestg2), - gts_container_size (GTS_CONTAINER (bestg2))); -#endif - - g_assert (bestg1 != NULL); - bg->g1 = bestg1; - g_assert (bestg2 != NULL); - bg->g2 = bestg2; - - /* boundary nodes */ - bg->bg1 = g_hash_table_new (NULL, NULL); - gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) boundary_node1, bg); - bg->bg2 = g_hash_table_new (NULL, NULL); - gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) boundary_node2, bg); - - return bg; -} - -/** - * gts_graph_bfgg_bisection: - * @g: a #GtsGraph. - * @ntry: the number of randomly selected initial seeds. - * - * An implementation of a "Breadth-First Graph Growing" algorithm. - * - * @ntry randomly chosen seeds are used and the best partition is retained. - * - * Returns: a new #GtsGraphBisection of @g. - */ -GtsGraphBisection * gts_graph_bfgg_bisection (GtsGraph * g, guint ntry) -{ - gfloat size, bestcost = G_MAXFLOAT, smin; - GtsGraph * bestg1 = NULL, * bestg2 = NULL; - GtsEHeap * degree_heap; - GtsGNode * seed; - GtsGraphBisection * bg; - - g_return_val_if_fail (g != NULL, NULL); - - bg = g_malloc (sizeof (GtsGraphBisection)); - bg->g = g; - - size = gts_graph_weight (g)/2.; - smin = 0.9*size; - - degree_heap = gts_eheap_new ((GtsKeyFunc) degree_cost, g); - gts_eheap_freeze (degree_heap); - gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_seed, degree_heap); - gts_eheap_thaw (degree_heap); - - while (ntry && ((seed = gts_eheap_remove_top (degree_heap, NULL)))) { - GtsGraph * g1, * g2; - GtsGNode * n; - gdouble cost; - GtsGraphTraverse * t = gts_graph_traverse_new (g, seed, - GTS_BREADTH_FIRST, TRUE); - - g1 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass), - g->node_class, g->edge_class); - g2 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass), - g->node_class, g->edge_class); - - while ((n = gts_graph_traverse_next (t))) - if (gts_graph_weight (g1) + gts_gnode_weight (n) <= size) { - gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); - GTS_OBJECT (n)->reserved = n; - } - gts_graph_traverse_destroy (t); - - gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_unused, g2); - - cost = gts_graph_edges_cut_weight (g1); - if (!bestg1 || (cost < bestcost && gts_graph_weight (g1) >= smin)) { - if (bestg1) - bestcost = cost; - if (bestg1) - gts_object_destroy (GTS_OBJECT (bestg1)); - if (bestg2) - gts_object_destroy (GTS_OBJECT (bestg2)); - bestg1 = g1; - bestg2 = g2; - } - else { - gts_object_destroy (GTS_OBJECT (g1)); - gts_object_destroy (GTS_OBJECT (g2)); - } - - ntry--; - } - gts_eheap_destroy (degree_heap); - -#ifdef DEBUG - fprintf (stderr, "bestcost: %5g g1: %5g|%5d g2: %5g|%5d\n", - bestcost, - gts_graph_weight (bestg1), - gts_container_size (GTS_CONTAINER (bestg1)), - gts_graph_weight (bestg2), - gts_container_size (GTS_CONTAINER (bestg2))); -#endif - - bg->g1 = bestg1; - bg->g2 = bestg2; - - /* boundary nodes */ - bg->bg1 = g_hash_table_new (NULL, NULL); - gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) boundary_node1, bg); - bg->bg2 = g_hash_table_new (NULL, NULL); - gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) boundary_node2, bg); - - return bg; -} - -static gdouble node_move_cost1 (GtsGNode * n, GtsGraphBisection * bg) -{ - return gts_gnode_move_cost (n, bg->g1, bg->g2); -} - -static gdouble node_move_cost2 (GtsGNode * n, GtsGraphBisection * bg) -{ - return gts_gnode_move_cost (n, bg->g2, bg->g1); -} - -static void build_heap (GtsGNode * n, GtsEHeap * heap) -{ - GTS_OBJECT (n)->reserved = gts_eheap_insert (heap, n); -} - -/** - * gts_graph_bisection_kl_refine: - * @bg: a #GtsGraphBisection. - * @mmax: the maximum number of unsuccessful successive moves. - * - * An implementation of the simplified Kernighan-Lin algorithm for - * graph bisection refinement as described in Karypis and Kumar - * (1997). - * - * The algorithm stops if @mmax consecutive modes do not lead to a - * decrease in the number of edges cut. This last @mmax moves are - * undone. - * - * Returns: the decrease in the weight of the edges cut by the bisection. - */ -gdouble gts_graph_bisection_kl_refine (GtsGraphBisection * bg, - guint mmax) -{ - GtsEHeap * h1, * h2; - GtsGNode * n; - guint nm = 0, i; - GtsGNode ** moves; - gdouble bestcost = 0., totalcost = 0., best_balance; - - g_return_val_if_fail (bg != NULL, 0.); - g_return_val_if_fail (mmax > 0, 0.); - - h1 = gts_eheap_new ((GtsKeyFunc) node_move_cost1, bg); - gts_eheap_freeze (h1); - gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) build_heap, h1); - gts_eheap_thaw (h1); - - h2 = gts_eheap_new ((GtsKeyFunc) node_move_cost2, bg); - gts_eheap_freeze (h2); - gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) build_heap, h2); - gts_eheap_thaw (h2); - - moves = g_malloc (sizeof (GtsGNode *)*mmax); - best_balance = fabs (gts_graph_weight (bg->g1) - gts_graph_weight (bg->g2)); - - do { - GtsGraph * g1, * g2; - gdouble cost; - - if (gts_graph_weight (bg->g1) > gts_graph_weight (bg->g2)) { - n = gts_eheap_remove_top (h1, &cost); - g1 = bg->g1; - g2 = bg->g2; - } - else { - n = gts_eheap_remove_top (h2, &cost); - g1 = bg->g2; - g2 = bg->g1; - } - if (n) { - GSList * i; - - GTS_OBJECT (n)->reserved = NULL; - gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n)); - gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); - - totalcost += cost; - if (totalcost < bestcost) { - bestcost = totalcost; - nm = 0; - } - else if (totalcost == bestcost) { - gdouble balance = fabs (gts_graph_weight (g1) - gts_graph_weight (g2)); - - if (balance < best_balance) { - best_balance = balance; - nm = 0; - } - } - else - moves[nm++] = n; - - i = GTS_SLIST_CONTAINER (n)->items; - while (i) { - GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); - if (GTS_OBJECT (n1)->reserved && - gts_containee_is_contained (GTS_CONTAINEE (n1), - GTS_CONTAINER (bg->g))) { - GtsEHeap * h = - gts_containee_is_contained (GTS_CONTAINEE (n1), - GTS_CONTAINER (bg->g1)) ? h1 : h2; - gts_eheap_remove (h, GTS_OBJECT (n1)->reserved); - GTS_OBJECT (n1)->reserved = gts_eheap_insert (h, n1); - } - i = i->next; - } - } - } while (n && nm < mmax); - - gts_eheap_foreach (h1, (GFunc) gts_object_reset_reserved, NULL); - gts_eheap_foreach (h2, (GFunc) gts_object_reset_reserved, NULL); - gts_eheap_destroy (h1); - gts_eheap_destroy (h2); - - /* undo last nm moves */ - for (i = 0; i < nm; i++) { - GtsGNode * n = moves[i]; - GtsGraph * g1 = - gts_containee_is_contained (GTS_CONTAINEE (n), - GTS_CONTAINER (bg->g1)) ? bg->g1 : bg->g2; - GtsGraph * g2 = g1 == bg->g1 ? bg->g2 : bg->g1; - - gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n)); - gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); - } - g_free (moves); - - return bestcost; -} - -static void build_bheap (GtsGNode * n, GtsGNode * n1, GtsEHeap * heap) -{ - GTS_OBJECT (n)->reserved = gts_eheap_insert (heap, n); -} - -static void update_neighbors (GtsGNode * n, GtsGraphBisection * bg, - GtsEHeap * h1, GtsEHeap * h2) -{ - GSList * i; - - i = GTS_SLIST_CONTAINER (n)->items; - while (i) { - GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); - if (gts_containee_is_contained (GTS_CONTAINEE (n1), - GTS_CONTAINER (bg->g))) { - GtsEHeap * h; - GtsGraph /* * g1,*/ * g2; - GHashTable * bg1; - - if (gts_containee_is_contained (GTS_CONTAINEE (n1), - GTS_CONTAINER (bg->g1))) { - h = h1; - //g1 = bg->g1; - g2 = bg->g2; - bg1 = bg->bg1; - } - else { - h = h2; - //g1 = bg->g2; - g2 = bg->g1; - bg1 = bg->bg2; - } - g_hash_table_remove (bg1, n1); - if (h && GTS_OBJECT (n1)->reserved && GTS_OBJECT (n1)->reserved != n1) { - gts_eheap_remove (h, GTS_OBJECT (n1)->reserved); - GTS_OBJECT (n1)->reserved = NULL; - } - if (gts_gnode_degree (n1, g2)) { - g_hash_table_insert (bg1, n1, n1); - if (h && GTS_OBJECT (n1)->reserved != n1) - GTS_OBJECT (n1)->reserved = gts_eheap_insert (h, n1); - } - } - i = i->next; - } -} - -/** - * gts_graph_bisection_bkl_refine: - * @bg: a #GtsGraphBisection. - * @mmax: the maximum number of unsuccessful successive moves. - * @imbalance: the maximum relative imbalance allowed between the - * weights of both halves of the partition. - * - * An implementation of the simplified boundary Kernighan-Lin - * algorithm for graph bisection refinement as described in Karypis - * and Kumar (1997). - * - * The algorithm stops if @mmax consecutive modes do not lead to a - * decrease in the number of edges cut. This last @mmax moves are - * undone. - * - * Returns: the decrease in the weight of the edges cut by the bisection. - */ -gdouble gts_graph_bisection_bkl_refine (GtsGraphBisection * bg, - guint mmax, - gfloat imbalance) -{ - GtsEHeap * h1, * h2; - GtsGNode * n; - guint nm = 0, i; - GtsGNode ** moves; - gdouble bestcost = 0., totalcost = 0., best_balance; - gboolean balanced = FALSE; - - g_return_val_if_fail (bg != NULL, 0.); - g_return_val_if_fail (mmax > 0, 0.); - g_return_val_if_fail (imbalance >= 0. && imbalance <= 1., 0.); - - h1 = gts_eheap_new ((GtsKeyFunc) node_move_cost1, bg); - gts_eheap_freeze (h1); - g_hash_table_foreach (bg->bg1, (GHFunc) build_bheap, h1); - gts_eheap_thaw (h1); - - h2 = gts_eheap_new ((GtsKeyFunc) node_move_cost2, bg); - gts_eheap_freeze (h2); - g_hash_table_foreach (bg->bg2, (GHFunc) build_bheap, h2); - gts_eheap_thaw (h2); - - moves = g_malloc (sizeof (GtsGNode *)*mmax); - imbalance *= gts_graph_weight (bg->g); - best_balance = fabs (gts_graph_weight (bg->g1) - gts_graph_weight (bg->g2)); - if (best_balance <= imbalance) - balanced = TRUE; - - do { - GtsGraph * g1, * g2; - GHashTable * bg1, * bg2; - gdouble cost; - - if (gts_graph_weight (bg->g1) > gts_graph_weight (bg->g2)) { - n = gts_eheap_remove_top (h1, &cost); - g1 = bg->g1; - g2 = bg->g2; - bg1 = bg->bg1; - bg2 = bg->bg2; - } - else { - n = gts_eheap_remove_top (h2, &cost); - g1 = bg->g2; - g2 = bg->g1; - bg1 = bg->bg2; - bg2 = bg->bg1; - } - if (n) { - gdouble balance; - - GTS_OBJECT (n)->reserved = n; - gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n)); - gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); - g_hash_table_remove (bg1, n); - if (gts_gnode_degree (n, g1)) - g_hash_table_insert (bg2, n, n); - - update_neighbors (n, bg, h1, h2); - - totalcost += cost; - balance = fabs (gts_graph_weight (g1) - gts_graph_weight (g2)); - - if (!balanced && balance <= imbalance) { - bestcost = totalcost; - best_balance = balance; - balanced = TRUE; - nm = 0; - } - else if (totalcost < bestcost && - (balance < best_balance || balance <= imbalance)) { - bestcost = totalcost; - best_balance = balance; - nm = 0; - } - else if (totalcost == bestcost && balance < best_balance) { - best_balance = balance; - nm = 0; - } - else - moves[nm++] = n; - } - } while (n && nm < mmax); - - gts_container_foreach (GTS_CONTAINER (bg->g), - (GtsFunc) gts_object_reset_reserved, NULL); - gts_eheap_destroy (h1); - gts_eheap_destroy (h2); - - /* undo last nm moves */ - for (i = 0; i < nm; i++) { - GtsGNode * n = moves[i]; - GtsGraph * g1, * g2; - GHashTable * bg1, * bg2; - - if (gts_containee_is_contained (GTS_CONTAINEE (n), - GTS_CONTAINER (bg->g1))) { - g1 = bg->g1; - g2 = bg->g2; - bg1 = bg->bg1; - bg2 = bg->bg2; - } - else { - g1 = bg->g2; - g2 = bg->g1; - bg1 = bg->bg2; - bg2 = bg->bg1; - } - - gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n)); - gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); - g_hash_table_remove (bg1, n); - if (gts_gnode_degree (n, g1)) - g_hash_table_insert (bg2, n, n); - - update_neighbors (n, bg, NULL, NULL); - } - g_free (moves); - - return bestcost; -} - -/* Multilevel partitioning */ - -static void bisection_children (GtsGNodeSplit * ns, GtsGraphBisection * bg) -{ - GtsGraph * g, * g1; - GHashTable * bbg; - GtsGNode * n1 = GTS_GNODE_SPLIT_N1 (ns); - GtsGNode * n2 = GTS_GNODE_SPLIT_N2 (ns); - - if (gts_containee_is_contained (GTS_CONTAINEE (ns->n), - GTS_CONTAINER (bg->g1))) { - g = bg->g1; - g1 = bg->g2; - bbg = bg->bg1; - } - else { - g = bg->g2; - g1 = bg->g1; - bbg = bg->bg2; - } - - gts_allow_floating_gnodes = TRUE; - gts_container_remove (GTS_CONTAINER (g), GTS_CONTAINEE (ns->n)); - gts_allow_floating_gnodes = FALSE; - gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (n1)); - gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (n2)); - - if (g_hash_table_lookup (bbg, ns->n)) { - g_hash_table_remove (bbg, ns->n); - if (gts_gnode_degree (n1, g1) > 0) - g_hash_table_insert (bbg, n1, n1); - if (gts_gnode_degree (n2, g1) > 0) - g_hash_table_insert (bbg, n2, n2); - } -} - -/** - * gts_graph_bisection_new: - * @wg: a #GtsWGraph. - * @ntry: the number of tries for the graph growing algorithm. - * @mmax: the number of unsucessful moves for the refinement algorithm. - * @nmin: the minimum number of nodes of the coarsest graph. - * @imbalance: the maximum relative imbalance allowed between the - * weights of both halves of the partition. - * - * An implementation of a multilevel bisection algorithm as presented - * in Karypis and Kumar (1997). A multilevel hierarchy of graphs is - * created using the #GtsPGraph object. The bisection of the coarsest - * graph is created using the gts_graph_ggg_bisection() function. The - * graph is then uncoarsened using gts_pgraph_down() and at each level - * the bisection is refined using gts_graph_bisection_bkl_refine(). - * - * Returns: a new #GtsGraphBisection of @wg. - */ -GtsGraphBisection * gts_graph_bisection_new (GtsWGraph * wg, - guint ntry, - guint mmax, - guint nmin, - gfloat imbalance) -{ - GtsGraph * g; - GtsPGraph * pg; - GtsGraphBisection * bg; - gdouble cost; - - g_return_val_if_fail (wg != NULL, NULL); - - g = GTS_GRAPH (wg); - pg = gts_pgraph_new (gts_pgraph_class (), g, - gts_gnode_split_class (), - gts_wgnode_class (), - gts_wgedge_class (), - nmin); - - bg = gts_graph_ggg_bisection (g, ntry); -#ifdef DEBUG - fprintf (stderr, "before size: %5d weight: %5g cuts: %5d cweight: %5g\n", - gts_container_size (GTS_CONTAINER (bg->g1)), - gts_graph_weight (bg->g1), - gts_graph_edges_cut (bg->g1), - gts_graph_edges_cut_weight (bg->g1)); - g_assert (gts_graph_bisection_check (bg)); -#endif - while ((cost = gts_graph_bisection_bkl_refine (bg, mmax, imbalance))) { -#ifdef DEBUG - fprintf (stderr, " cost: %g\n", cost); - g_assert (gts_graph_bisection_check (bg)); -#endif - } -#ifdef DEBUG - fprintf (stderr, "after size: %5d weight: %5g cuts: %5d cweight: %5g\n", - gts_container_size (GTS_CONTAINER (bg->g1)), - gts_graph_weight (bg->g1), - gts_graph_edges_cut (bg->g1), - gts_graph_edges_cut_weight (bg->g1)); -#endif - while (gts_pgraph_down (pg, (GtsFunc) bisection_children, bg)) { -#ifdef DEBUG - fprintf (stderr, "before size: %5d weight: %5g cuts: %5d cweight: %5g\n", - gts_container_size (GTS_CONTAINER (bg->g1)), - gts_graph_weight (bg->g1), - gts_graph_edges_cut (bg->g1), - gts_graph_edges_cut_weight (bg->g1)); -#endif - while ((cost = gts_graph_bisection_bkl_refine (bg, mmax, imbalance))) { -#ifdef DEBUG - fprintf (stderr, " cost: %g\n", cost); - g_assert (gts_graph_bisection_check (bg)); -#endif - } -#ifdef DEBUG - fprintf (stderr, "after size: %5d weight: %5g cuts: %5d cweight: %5g\n", - gts_container_size (GTS_CONTAINER (bg->g1)), - gts_graph_weight (bg->g1), - gts_graph_edges_cut (bg->g1), - gts_graph_edges_cut_weight (bg->g1)); -#endif - } - gts_object_destroy (GTS_OBJECT (pg)); - - return bg; -} - -/** - * gts_graph_bisection_destroy: - * @bg: a #GtsGraphBisection. - * @destroy_graphs: controls graph destruction. - * - * Frees all the memory allocated for @bg. If @destroy_graphs is %TRUE - * the graphs created by @bg are destroyed. - */ -void gts_graph_bisection_destroy (GtsGraphBisection * bg, - gboolean destroy_graphs) -{ - g_return_if_fail (bg != NULL); - - g_hash_table_destroy (bg->bg1); - g_hash_table_destroy (bg->bg2); - - if (destroy_graphs) { - gts_object_destroy (GTS_OBJECT (bg->g1)); - gts_object_destroy (GTS_OBJECT (bg->g2)); - } - - g_free (bg); -} - -static void recursive_bisection (GtsWGraph * wg, - guint np, - guint ntry, - guint mmax, - guint nmin, - gfloat imbalance, - GSList ** list) -{ - if (np == 0) - *list = g_slist_prepend (*list, wg); - else { - GtsGraphBisection * bg = - gts_graph_bisection_new (wg, ntry, mmax, nmin, imbalance); - GtsGraph * g1 = bg->g1; - GtsGraph * g2 = bg->g2; - - gts_object_destroy (GTS_OBJECT (wg)); - gts_graph_bisection_destroy (bg, FALSE); - recursive_bisection (GTS_WGRAPH (g1), np - 1, ntry, mmax, nmin, imbalance, - list); - recursive_bisection (GTS_WGRAPH (g2), np - 1, ntry, mmax, nmin, imbalance, - list); - } -} - -/** - * gts_graph_recursive_bisection: - * @wg: a #GtsWGraph. - * @n: the number of bisection levels. - * @ntry: the number of tries for the graph growing algorithm. - * @mmax: the number of unsucessful moves for the refinement algorithm. - * @nmin: the minimum number of nodes of the coarsest graph. - * @imbalance: the maximum relative imbalance allowed between the - * weights of both halves of the partition. - * - * Calls gts_graph_bisection_new() recursively in order to obtain a - * 2^@n partition of @wg. - * - * Returns: a list of 2^@n new #GtsGraph representing the partition. - */ -GSList * gts_graph_recursive_bisection (GtsWGraph * wg, - guint n, - guint ntry, - guint mmax, - guint nmin, - gfloat imbalance) -{ - GtsGraphBisection * bg; - GtsGraph * g1, * g2; - GSList * list = NULL; - - g_return_val_if_fail (wg != NULL, NULL); - g_return_val_if_fail (n > 0, NULL); - - bg = gts_graph_bisection_new (wg, ntry, mmax, nmin, imbalance); - g1 = bg->g1; - g2 = bg->g2; - gts_graph_bisection_destroy (bg, FALSE); - recursive_bisection (GTS_WGRAPH (g1), n - 1, ntry, mmax, nmin, imbalance, - &list); - recursive_bisection (GTS_WGRAPH (g2), n - 1, ntry, mmax, nmin, imbalance, - &list); - - return list; -} Index: trunk/src_3rd/gts/gts-private.h =================================================================== --- trunk/src_3rd/gts/gts-private.h (revision 6802) +++ trunk/src_3rd/gts/gts-private.h (nonexistent) @@ -1,37 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GTS_PRIVATE_H__ -#define __GTS_PRIVATE_H__ - -/* Debugging flags */ - -/* #define DEBUG_FUNCTIONS */ - -#ifdef DEBUG_FUNCTIONS -/* #define DEBUG_LEAKS */ -#define DEBUG_IDENTITY -guint id (gpointer p); -void id_insert (gpointer p); -void id_remove (gpointer p); -void gts_write_triangle (GtsTriangle * t, GtsPoint * o, FILE * fptr); -void gts_write_segment (GtsSegment * s, GtsPoint * o, FILE * fptr); -#endif /* DEBUG_FUNCTIONS */ - -#endif /* __GTS_PRIVATE_H__ */ Index: trunk/src_3rd/gts/boolean.c =================================================================== --- trunk/src_3rd/gts/boolean.c (revision 6802) +++ trunk/src_3rd/gts/boolean.c (nonexistent) @@ -1,2048 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999--2002 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include "gts.h" - -/*#define DEBUG*/ -/*#define DEBUG_BOOLEAN*/ -/*#define CHECK_ORIENTED*/ - -#ifdef DEBUG -# include "gts-private.h" -#endif /* DEBUG */ - -static void surface_inter_destroy (GtsObject * object) -{ - GtsSurfaceInter * si = GTS_SURFACE_INTER (object); - - gts_object_destroy (GTS_OBJECT (si->s1)); - gts_object_destroy (GTS_OBJECT (si->s2)); - g_slist_free (si->edges); - - (* GTS_OBJECT_CLASS (gts_surface_inter_class ())->parent_class->destroy) - (object); -} - -static void surface_inter_class_init (GtsObjectClass * klass) -{ - klass->destroy = surface_inter_destroy; -} - -static void surface_inter_init (GtsSurfaceInter * si) -{ - si->s1 = si->s2 = NULL; - si->edges = NULL; -} - -/** - * gts_surface_inter_class: - * - * Returns: the #GtsSurfaceInterClass. - */ -GtsSurfaceInterClass * gts_surface_inter_class (void) -{ - static GtsSurfaceInterClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo surface_inter_info = { - "GtsSurfaceInter", - sizeof (GtsSurfaceInter), - sizeof (GtsSurfaceInterClass), - (GtsObjectClassInitFunc) surface_inter_class_init, - (GtsObjectInitFunc) surface_inter_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (gts_object_class (), &surface_inter_info); - } - - return klass; -} - -/* EdgeInter: Header */ - -typedef struct _EdgeInter EdgeInter; - -struct _EdgeInter { - GtsEdge parent; - - GtsTriangle * t1, * t2; -}; - -#define EDGE_INTER(obj) GTS_OBJECT_CAST (obj,\ - EdgeInter,\ - edge_inter_class ()) -#define IS_EDGE_INTER(obj) (gts_object_is_from_class (obj,\ - edge_inter_class ())) - -static GtsEdgeClass * edge_inter_class (void); -static EdgeInter * edge_inter_new (GtsVertex * v1, GtsVertex * v2, - GtsTriangle * t1, GtsTriangle * t2); - -/* EdgeInter: Object */ - -static GtsEdgeClass * edge_inter_class (void) -{ - static GtsEdgeClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo edge_inter_info = { - "EdgeInter", - sizeof (EdgeInter), - sizeof (GtsEdgeClass), - (GtsObjectClassInitFunc) NULL, - (GtsObjectInitFunc) NULL, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_constraint_class ()), - &edge_inter_info); - } - - return klass; -} - -static EdgeInter * edge_inter_new (GtsVertex * v1, GtsVertex * v2, - GtsTriangle * t1, GtsTriangle * t2) -{ - EdgeInter * object; - - object = EDGE_INTER (gts_edge_new (GTS_EDGE_CLASS (edge_inter_class ()), - v1, v2)); - object->t1 = t1; - object->t2 = t2; - - return object; -} - -#ifdef DEBUG -static void write_surface_graph (GtsSurface * s, FILE * fp) -{ - GSList * l = NULL; - GtsGraph * g; - static void add_to_list (gpointer data, GSList ** l) { - *l = g_slist_prepend (*l, data); - } - - gts_surface_foreach_vertex (s, (GtsFunc) gts_object_reset_reserved, NULL); - gts_surface_foreach_edge (s, (GtsFunc) gts_object_reset_reserved, NULL); - gts_surface_foreach_edge (s, (GtsFunc) add_to_list, &l); - g = gts_segments_graph_new (gts_graph_class (), l); - gts_graph_write_dot (g, fp); - gts_object_destroy (GTS_OBJECT (g)); - g_slist_free (l); -} -#endif /* DEBUG */ - -static GtsPoint * segment_triangle_intersection (GtsSegment * s, - GtsTriangle * t, - GtsPointClass * klass) -{ - GtsPoint * A, * B, * C, * D, * E; - gint ABCE, ABCD, ADCE, ABDE, BCDE; - GtsEdge * AB, * BC, * CA; - gdouble a, b, c; - - g_return_val_if_fail (s != NULL, NULL); - g_return_val_if_fail (t != NULL, NULL); - g_return_val_if_fail (klass != NULL, NULL); - - gts_triangle_vertices_edges (t, NULL, - (GtsVertex **) &A, - (GtsVertex **) &B, - (GtsVertex **) &C, - &AB, &BC, &CA); - D = GTS_POINT (s->v1); - E = GTS_POINT (s->v2); - - ABCE = gts_point_orientation_3d_sos (A, B, C, E); - ABCD = gts_point_orientation_3d_sos (A, B, C, D); - if (ABCE < 0 || ABCD > 0) { - GtsPoint * tmpp; - gint tmp; - - tmpp = E; E = D; D = tmpp; - tmp = ABCE; ABCE = ABCD; ABCD = tmp; - } - if (ABCE < 0 || ABCD > 0) - return NULL; - ADCE = gts_point_orientation_3d_sos (A, D, C, E); - if (ADCE < 0) - return NULL; - ABDE = gts_point_orientation_3d_sos (A, B, D, E); - if (ABDE < 0) - return NULL; - BCDE = gts_point_orientation_3d_sos (B, C, D, E); - if (BCDE < 0) - return NULL; - a = gts_point_orientation_3d (A, B, C, E); - b = gts_point_orientation_3d (A, B, C, D); - if (a != b) { - c = a/(a - b); - return gts_point_new (klass, - E->x + c*(D->x - E->x), - E->y + c*(D->y - E->y), - E->z + c*(D->z - E->z)); - } - /* D and E are contained within ABC */ -#ifdef DEBUG - fprintf (stderr, - "segment: %p:%s triangle: %p:%s intersection\n" - "D and E contained in ABC\n", - s, GTS_NEDGE (s)->name, t, GTS_NFACE (t)->name); -#endif /* DEBUG */ - g_assert (a == 0.); - return gts_point_new (klass, - (E->x + D->x)/2., - (E->y + D->y)/2., - (E->z + D->z)/2.); -} - -static gint triangle_triangle_orientation (GtsPoint * p1, - GtsPoint * p2, GtsPoint * p3, - GtsPoint * p4, GtsPoint * p5, - GtsPoint * p6) -{ - gint o4 = 0, o5 = 0, o6 = 0; - - if (p4 != p1 && p4 != p2 && p4 != p3) - o4 = gts_point_orientation_3d_sos (p1, p2, p3, p4); - if (p5 != p1 && p5 != p2 && p5 != p3) - o5 = gts_point_orientation_3d_sos (p1, p2, p3, p5); - if (o4*o5 < 0) - return 0; - if (p6 != p1 && p6 != p2 && p6 != p3) - o6 = gts_point_orientation_3d_sos (p1, p2, p3, p6); - if (o4*o6 < 0 || o5*o6 < 0) - return 0; - if (o4) return o4; - if (o5) return o5; - g_assert (o6); - return o6; -} - -static gint triangle_point_orientation (GtsTriangle * t1, - GtsTriangle * t2, - gint o1, - GtsPoint * p) -{ - GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (t1->e1)->v1); - GtsPoint * p2 = GTS_POINT (GTS_SEGMENT (t1->e1)->v2); - GtsPoint * p3 = GTS_POINT (gts_triangle_vertex (t1)); - GtsPoint * p4 = GTS_POINT (GTS_SEGMENT (t2->e1)->v1); - GtsPoint * p5 = GTS_POINT (GTS_SEGMENT (t2->e1)->v2); - GtsPoint * p6 = GTS_POINT (gts_triangle_vertex (t2)); - gint o = triangle_triangle_orientation (p1, p2, p3, p4, p5, p6); - - if (o != 0) - return o; - o = triangle_triangle_orientation (p4, p5, p6, p1, p2, p3); - if (o != 0) { - gint o2 = gts_point_orientation_3d_sos (p4, p5, p6, p); - - return - o*o1*o2; - } - return 0; -} - -static void add_edge_inter (GtsEdge * e, - GtsTriangle * t, - GtsVertex * v) -{ - GtsVertex * ev1 = GTS_SEGMENT (e)->v1, * ev2 = GTS_SEGMENT (e)->v2; - GList * i = GTS_OBJECT (e)->reserved; - - GTS_OBJECT (v)->reserved = t; - if (i == NULL) { - GTS_OBJECT (e)->reserved = g_list_prepend (NULL, v); -#ifdef DEBUG - fprintf (stderr, "add_edge_inter: inserting %p (%p,%p)\n", v, e, t); -#endif /* DEBUG */ - } - else { - GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1); - GtsPoint * p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); - GtsPoint * p3 = GTS_POINT (gts_triangle_vertex (t)); - gint o1, oref = gts_point_orientation_3d_sos (p1, p2, p3, GTS_POINT (ev1)); - - o1 = oref; - while (i) { - gint o2 = triangle_point_orientation (t, GTS_OBJECT (i->data)->reserved, - oref, GTS_POINT (ev1)); - - if (o2 == 0) { -#ifdef DEBUG - g_warning ("add_edge_inter: safe sign evaluation failed\n"); -#endif /* DEBUG */ - o2 = gts_point_orientation_3d_sos (p1, p2, p3, i->data); - } - - if (o1*o2 < 0) - break; - ev1 = i->data; - o1 = o2; - i = i->next; - } - if (i != NULL) { - GList * n = g_list_prepend (NULL, v); - - ev2 = i->data; - n->next = i; - n->prev = i->prev; - i->prev = n; - if (n->prev == NULL) - GTS_OBJECT (e)->reserved = n; - else - n->prev->next = n; - } - else { - g_assert (o1*gts_point_orientation_3d_sos (p1, p2, p3, GTS_POINT (ev2)) - < 0); - GTS_OBJECT (e)->reserved = g_list_append (GTS_OBJECT (e)->reserved, v); - } -#ifdef DEBUG - fprintf (stderr, - "add_edge_inter: inserting %p (%p,%p) between %p and %p\n", - v, e, t, ev1, ev2); - i = GTS_OBJECT (e)->reserved; - while (i) { - fprintf (stderr, " %p", i->data); - i = i->next; - } - fprintf (stderr, "\n"); -#endif /* DEBUG */ - } -} - -static GtsVertex * intersects (GtsEdge * e, - GtsTriangle * t, - GtsSurface * s) -{ - GList * i = GTS_OBJECT (e)->reserved; - GtsVertex * v; - - while (i) { - if (GTS_OBJECT (i->data)->reserved == t) - return i->data; - i = i->next; - } - - v = GTS_VERTEX (segment_triangle_intersection (GTS_SEGMENT (e), t, - GTS_POINT_CLASS (s->vertex_class))); - if (v != NULL) { -#ifdef DEBUG - if (GTS_IS_NVERTEX (v) && GTS_IS_NEDGE (e) && GTS_IS_NFACE (t) && - GTS_NVERTEX (v)->name[0] == '\0') - g_snprintf (GTS_NVERTEX (v)->name, GTS_NAME_LENGTH, "%s|%s", - GTS_NEDGE (e)->name, GTS_NFACE (t)->name); -#endif /* DEBUG */ - if (s->vertex_class->intersection_attributes) - (*s->vertex_class->intersection_attributes) - (v, GTS_OBJECT (e), GTS_OBJECT (t)); - add_edge_inter (e, t, v); - } - return v; -} - -/* see figure misc/orientation.fig */ -static gint intersection_orientation (GtsTriangle * t1, - GtsEdge * e, - GtsTriangle * t2) -{ - GtsVertex * v1, * v2, * v3; - GtsEdge * e2, * e3; - GtsVertex * v4, * v5, * v6; - - gts_triangle_vertices_edges (t1, e, &v1, &v2, &v3, &e, &e2, &e3); - gts_triangle_vertices (t2, &v4, &v5, &v6); - - return gts_point_orientation_3d_sos (GTS_POINT (v4), - GTS_POINT (v5), - GTS_POINT (v6), - GTS_POINT (v2)); -} - -#define UPDATE_ORIENTATION if (o > 0) { vi2 = v; /* e2 = e; */ } else { vi2 = vi1;\ - /* e2 = e1; */\ - vi1 = v;\ - /* e1 = e; */ } - -static void intersect_edges (GtsBBox * bb1, GtsBBox * bb2, - GtsSurfaceInter * si) -{ - GtsSurface * s1 = GTS_OBJECT (si->s1)->reserved; - GtsTriangle * t1 = GTS_TRIANGLE (bb1->bounded); - GtsTriangle * t2 = GTS_TRIANGLE (bb2->bounded); - GtsVertex * v, * vi1 = NULL, * vi2 = NULL; - //GtsEdge * e1 = NULL, * e2 = NULL, * e; - - vi1 = intersects (t2->e1, t1, s1); - //e1 = t2->e1; - v = intersects (t2->e2, t1, s1); - //e = t2->e2; - if (!vi1) { - vi1 = v; - //e1 = e; - } - else if (v) { - gint o = intersection_orientation (t2, t2->e2, t1); - UPDATE_ORIENTATION; - } - if (!vi2) { - v = intersects (t2->e3, t1, s1); - //e = t2->e3; - if (!vi1) { - vi1 = v; - //e1 = e; - } - else if (v) { - gint o = intersection_orientation (t2, t2->e3, t1); - UPDATE_ORIENTATION; - } - } - if (!vi2) { - v = intersects (t1->e1, t2, s1); - //e = t1->e1; - if (!vi1) { - vi1 = v; - //e1 = e; - } - else if (v) { - gint o = - intersection_orientation (t1, t1->e1, t2); - UPDATE_ORIENTATION; - } - } - if (!vi2) { - v = intersects (t1->e2, t2, s1); - //e = t1->e2; - if (!vi1) { - vi1 = v; - //e1 = e; - } - else if (v) { - gint o = - intersection_orientation (t1, t1->e2, t2); - UPDATE_ORIENTATION; - } - } - if (!vi2) { - v = intersects (t1->e3, t2, s1); - //e = t1->e3; - if (!vi1) { - vi1 = v; - //e1 = e; - } - else if (v) { - gint o = - intersection_orientation (t1, t1->e3, t2); - UPDATE_ORIENTATION; - } - } - - g_assert ((!vi1 && !vi2) || (vi1 && vi2)); - if (vi1) { - GtsEdge * e = GTS_EDGE (edge_inter_new (vi1, vi2, t1, t2)); - -#ifdef DEBUG - fprintf (stderr, "creating constraint %p: %p->%p: %p/%p\n", - e, vi1, vi2, t1, t2); -#endif /* DEBUG */ - gts_surface_add_face (si->s1, GTS_FACE (t1)); - gts_surface_add_face (si->s2, GTS_FACE (t2)); - si->edges = g_slist_prepend (si->edges, e); - GTS_OBJECT (t1)->reserved = g_slist_prepend (GTS_OBJECT (t1)->reserved, e); - GTS_OBJECT (t2)->reserved = g_slist_prepend (GTS_OBJECT (t2)->reserved, e); - } -} - -static GtsSurfaceInter * surface_inter_new (GtsSurfaceInterClass * klass, - GtsSurface * s1, - GtsSurface * s2, - GNode * faces_tree1, - GNode * faces_tree2) -{ - GtsSurfaceInter * si; - - si = GTS_SURFACE_INTER (gts_object_new (GTS_OBJECT_CLASS (klass))); - si->s1 = gts_surface_new (gts_surface_class (), - s1->face_class, - s1->edge_class, - s1->vertex_class); - GTS_OBJECT (si->s1)->reserved = s1; - si->s2 = gts_surface_new (gts_surface_class (), - s2->face_class, - s2->edge_class, - s2->vertex_class); - GTS_OBJECT (si->s2)->reserved = s2; - gts_bb_tree_traverse_overlapping (faces_tree1, faces_tree2, - (GtsBBTreeTraverseFunc) intersect_edges, - si); - - return si; -} - -static void free_slist (GtsObject * o) -{ - g_slist_free (o->reserved); - o->reserved = NULL; -} - -static void free_glist (GtsObject * o) -{ - g_list_foreach (o->reserved, (GFunc) gts_object_reset_reserved, NULL); - g_list_free (o->reserved); - o->reserved = NULL; -} - -/** - * gts_surface_intersection: - * @s1: a #GtsSurface. - * @s2: a #GtsSurface. - * @faces_tree1: a bounding box tree (see gts_bb_tree_new()) for - * the faces of @s1. - * @faces_tree2: a bounding box tree for the faces of @s2. - * - * Returns: a list of #GtsEdge defining the curve intersection of the - * two surfaces. - */ -GSList * gts_surface_intersection (GtsSurface * s1, - GtsSurface * s2, - GNode * faces_tree1, - GNode * faces_tree2) -{ - GtsSurfaceInter * si; - GSList * inter; - - g_return_val_if_fail (s1 != NULL, NULL); - g_return_val_if_fail (s2 != NULL, NULL); - g_return_val_if_fail (faces_tree1 != NULL, NULL); - g_return_val_if_fail (faces_tree2 != NULL, NULL); - - si = surface_inter_new (gts_surface_inter_class (), - s1, s2, faces_tree1, faces_tree2); - - gts_surface_foreach_face (si->s1, (GtsFunc) free_slist, NULL); - gts_surface_foreach_face (si->s2, (GtsFunc) free_slist, NULL); - gts_surface_foreach_edge (si->s1, (GtsFunc) free_glist, NULL); - gts_surface_foreach_edge (si->s2, (GtsFunc) free_glist, NULL); - inter = si->edges; - si->edges = NULL; - gts_object_destroy (GTS_OBJECT (si)); - - return inter; -} - -typedef enum { - INTERIOR = 1 << (GTS_USER_FLAG), - RELEVANT = 1 << (GTS_USER_FLAG + 1) -} CurveFlag; - -#define IS_SET(s, f) ((GTS_OBJECT_FLAGS (s) & (f)) != 0) -#define SET(s, f) (GTS_OBJECT_FLAGS (s) |= (f)) -#define UNSET(s, f) (GTS_OBJECT_FLAGS (s) &= ~(f)) -#define NEXT(s) (GTS_OBJECT (s)->reserved) - -#ifdef DEBUG -static void print_segment (GtsSegment * s) -{ - fprintf (stderr, "%p: %s->%s ", s, - GTS_NVERTEX (s->v1)->name, - GTS_NVERTEX (s->v2)->name); - if (NEXT (s)) { - GtsSegment * next = NEXT (s); - - fprintf (stderr, "next %p: %s->%s\n", next, - GTS_NVERTEX (next->v1)->name, - GTS_NVERTEX (next->v2)->name); - } - else - fprintf (stderr, "next NULL\n"); -} - -static void write_nodes (GSList * i, GHashTable * hash, guint * nn, - FILE * fp) -{ - while (i) { - GtsSegment * s = i->data; - - if (!g_hash_table_lookup (hash, s->v1)) { - fprintf (fp, " %u [ label = \"%p\" ];\n", *nn, s->v1); - g_hash_table_insert (hash, s->v1, GUINT_TO_POINTER ((*nn)++)); - } - if (!g_hash_table_lookup (hash, s->v2)) { - fprintf (fp, " %u [ label = \"%p\" ];\n", *nn, s->v2); - g_hash_table_insert (hash, s->v2, GUINT_TO_POINTER ((*nn)++)); - } - i = i->next; - } -} - -static void write_edges (GSList * i, GHashTable * hash, - GtsSurface * surface, - FILE * fp) -{ - while (i) { - GtsSegment * s = i->data; - - fprintf (fp, " %u -> %u [ label = \"%p:%d\" ];\n", - GPOINTER_TO_UINT (g_hash_table_lookup (hash, s->v1)), - GPOINTER_TO_UINT (g_hash_table_lookup (hash, s->v2)), - s, - gts_edge_face_number (GTS_EDGE (s), surface)); - i = i->next; - } -} - -static void write_graph (GSList * boundary, GSList * interior, - GtsSurface * surface, - FILE * fp) -{ - GHashTable * hash = g_hash_table_new (NULL, NULL); - guint nn = 1; - - fprintf (fp, "digraph oriented_curve {\n"); - write_nodes (boundary, hash, &nn, fp); - write_nodes (interior, hash, &nn, fp); - write_edges (boundary, hash, surface, fp); - fprintf (fp, " edge [ color = red ];\n"); - write_edges (interior, hash, surface, fp); - fprintf (fp, "}\n"); - g_hash_table_destroy (hash); -} - -static void write_graph1 (GtsSegment * start, GSList * i, - GtsSurface * surface, - FILE * fp) -{ - GSList * boundary = NULL, * interior = NULL; - GtsSegment * s = start; - - do { - boundary = g_slist_prepend (boundary, s); - s = NEXT (s); - } while (s != start); - while (i) { - if (IS_SET (i->data, INTERIOR)) - interior = g_slist_prepend (interior, i->data); - i = i->next; - } - write_graph (boundary, interior, surface, fp); - g_slist_free (boundary); - g_slist_free (interior); -} - -static void print_loop (GtsSegment * start, FILE * fp) -{ - GtsSegment * s = start; - - do { - fprintf (fp, " %p: %p:%s -> %p:%s\n", - s, - s->v1, GTS_NVERTEX (s->v1)->name, - s->v2, GTS_NVERTEX (s->v2)->name); - s = NEXT (s); - } while (s != start && s != NULL); -} - -static void draw_vector (GtsPoint * p1, GtsPoint * p2, FILE * fp) -{ - gdouble x = p2->x - p1->x; - gdouble y = p2->y - p1->y; - gdouble z = p2->z - p1->z; - - fprintf (fp, "VECT 1 3 0 3 0 %g %g %g %g %g %g %g %g %g\n", - p1->x + x - (x - y/2.)/5., - p1->y + y - (x/2. + y)/5., - p1->z + z - (x/2. + z)/5., - p1->x + x, - p1->y + y, - p1->z + z, - p1->x + x - (x + y/2.)/5., - p1->y + y + (x/2. - y)/5., - p1->z + z + (x/2. - z)/5.); - fprintf (fp, "VECT 1 2 0 2 0 %g %g %g %g %g %g\n", - p1->x, p1->y, p1->z, - p1->x + x, - p1->y + y, - p1->z + z); -} - -static void draw_vector1 (GtsPoint * p1, GtsPoint * p2, GtsPoint * o, - FILE * fp) -{ - gdouble x1 = o->x + 0.9*(p1->x - o->x); - gdouble y1 = o->y + 0.9*(p1->y - o->y); - gdouble z1 = o->z + 0.9*(p1->z - o->z); - gdouble x2 = o->x + 0.9*(p2->x - o->x); - gdouble y2 = o->y + 0.9*(p2->y - o->y); - gdouble z2 = o->z + 0.9*(p2->z - o->z); - gdouble x = x2 - x1; - gdouble y = y2 - y1; - gdouble z = z2 - z1; - - fprintf (fp, "VECT 1 3 0 3 0 %g %g %g %g %g %g %g %g %g\n", - x1 + x - (x - y/2.)/5., - y1 + y - (x/2. + y)/5., - z1 + z - (x/2. + z)/5., - x1 + x, - y1 + y, - z1 + z, - x1 + x - (x + y/2.)/5., - y1 + y + (x/2. - y)/5., - z1 + z + (x/2. - z)/5.); - fprintf (fp, "VECT 1 2 0 2 0 %g %g %g %g %g %g\n", - x1, y1, z1, - x1 + x, - y1 + y, - z1 + z); -} - -static void write_segments (GSList * boundary, GSList * interior, - FILE * fp) -{ - GSList * i = boundary; - - fprintf (fp, "LIST {\n"); - while (i) { - GSList * inext = i->next; - GtsSegment * s = i->data; - GtsSegment * next = inext ? inext->data : boundary->data; - GtsVertex * v1, * v2; - - if (s->v1 != next->v1 && s->v1 != next->v2) { - v1 = s->v1; - v2 = s->v2; - } - else { - v1 = s->v2; - v2 = s->v1; - } - draw_vector (GTS_POINT (v1), GTS_POINT (v2), fp); - i = inext; - } - i = interior; - while (i) { - GtsSegment * s = i->data; - - draw_vector (GTS_POINT (s->v1), GTS_POINT (s->v2), fp); - i = i->next; - } - fprintf (fp, "}\n"); -} - -static void write_loops (GSList * i, FILE * fp) -{ - guint nl = 0; - - while (i) { - GtsSegment * start = i->data, * s; - GtsPoint os; - guint n = 0; - - fprintf (fp, "(geometry \"loop%d\" = LIST {\n", nl++); - - os.x = os.y = os.z = 0.; - s = start; - do { - GtsSegment * next = NEXT (s); - GtsPoint * p; - - if (s->v1 != next->v1 && s->v1 != next->v2) - p = GTS_POINT (s->v1); - else - p = GTS_POINT (s->v2); - os.x += p->x; os.y += p->y; os.z += p->z; n++; - s = next; - } while (s != start); - os.x /= n; os.y /= n; os.z /= n; - - s = start; - do { - GtsSegment * next = NEXT (s); - - if (s->v1 != next->v1 && s->v1 != next->v2) - draw_vector1 (GTS_POINT (s->v1), GTS_POINT (s->v2), &os, fp); - else - draw_vector1 (GTS_POINT (s->v2), GTS_POINT (s->v1), &os, fp); - s = next; - } while (s != start); - - fprintf (fp, "})\n"); - - i = i->next; - } -} - -#define NAME(v) (GTS_IS_NVERTEX (v) ? GTS_NVERTEX (v)->name : "") -#endif /* DEBUG */ - -static GtsSegment * prev_flag (GtsSegment * s, CurveFlag flag) -{ - GSList * i = s->v1->segments; - - while (i) { - if (i->data != s && IS_SET (i->data, flag)) - return i->data; - i = i->next; - } - return NULL; -} - -static GtsSegment * next_flag (GtsSegment * s, CurveFlag flag) -{ - GSList * i = s->v2->segments; - - while (i) { - if (i->data != s && IS_SET (i->data, flag)) - return i->data; - i = i->next; - } - return NULL; -} - -static GtsSegment * next_interior (GtsVertex * v) -{ - GSList * i = v->segments; - - while (i) { - GtsSegment * s = i->data; - - if (s->v1 == v && IS_SET (s, INTERIOR)) - return s; - i = i->next; - } - return NULL; -} - -static GtsSegment * prev_interior (GtsVertex * v) -{ - GSList * i = v->segments; - - while (i) { - GtsSegment * s = i->data; - - if (s->v2 == v && IS_SET (s, INTERIOR)) - return s; - i = i->next; - } - return NULL; -} - -static GtsSegment * reverse (GtsSegment * start, - gboolean interior, - gboolean * isloop) -{ - GtsSegment * s = start, * prev = NULL, * rprev = NULL; - GtsSegment * rstart = NULL, * rstart1 = NULL; - - do { - GtsSegment * rs; - - g_assert (IS_EDGE_INTER (s)); - rs = GTS_SEGMENT (edge_inter_new (s->v2, s->v1, - EDGE_INTER (s)->t1, EDGE_INTER (s)->t2)); - - if (rstart == NULL) - rstart = rs; - else if (rstart1 == NULL) - rstart1 = rs; - if (interior) - SET (rs, INTERIOR); - NEXT (rs) = rprev; - rprev = rs; - prev = s; - s = NEXT (s); - } while (s != NULL && s != start); - if (s == start) { - NEXT (rstart) = rprev; - *isloop = TRUE; - } - else { - NEXT (rstart) = start; - NEXT (prev) = rprev; - *isloop = FALSE; - } - return rstart1; -} - -static GSList * interior_loops (GSList * interior) -{ - GSList * i = interior; - GSList * loops = NULL; - - i = interior; - while (i) { - GtsSegment * s = i->data; - - if (IS_SET (s, RELEVANT)) { - GtsSegment * start = s, * end; - - do { - GtsSegment * next = next_flag (s, INTERIOR); - - UNSET (s, RELEVANT); - end = s; - s = NEXT (s) = next; - } while (s != NULL && s != start); - - if (s == start) - loops = g_slist_prepend (loops, start); - else { - GtsSegment * next, * prev; - gboolean isloop; - - s = prev_flag (start, INTERIOR); - while (s) { - UNSET (s, RELEVANT); - NEXT (s) = start; - start = s; - s = prev_flag (s, INTERIOR); - } - next = next_flag (end, RELEVANT); - prev = prev_flag (start, RELEVANT); - if (prev != NULL) - SET (start->v1, INTERIOR); - if (next != NULL) - SET (end->v2, INTERIOR); - if (next == NULL && prev == NULL) - loops = g_slist_prepend (loops, start); - else - reverse (start, TRUE, &isloop); - } - } - i = i->next; - } - return loops; -} - -#define ORIENTATION(p1,p2,p3,o) (gts_point_orientation_3d (p1, p2, o, p3)) -#define ORIENTATION_SOS(p1,p2,p3,o) (gts_point_orientation_3d_sos (p1, p2, o, p3)) - -#define ORIENTED_VERTICES(s,next,w1,w2) {\ - if ((s)->v1 == (next)->v1 || (s)->v1 == (next)->v2) {\ - w1 = (s)->v2;\ - w2 = (s)->v1;\ - }\ - else {\ - w1 = (s)->v1;\ - w2 = (s)->v2;\ - }\ -} - -#if 0 -static GtsSegment * segment_intersects (GtsPoint * p1, GtsPoint * p2, - GSList * i, - GtsPoint * o) -{ - while (i) { - GtsSegment * s = i->data; - GtsPoint * p3 = GTS_POINT (s->v1); - GtsPoint * p4 = GTS_POINT (s->v2); - - if (p3 != p1 && p3 != p2 && p4 != p1 && p4 != p2) { - gdouble o1 = ORIENTATION (p3, p4, p1, o); - gdouble o2 = ORIENTATION (p3, p4, p2, o); - - if ((o1 < 0. && o2 > 0.) || (o1 > 0. && o2 < 0.)) { - o1 = ORIENTATION (p1, p2, p3, o); - o2 = ORIENTATION (p1, p2, p4, o); - - if ((o1 <= 0. && o2 >= 0.) || (o1 >= 0. && o2 <= 0.)) - return s; - } - } - i = i->next; - } - return NULL; -} -#else -static GtsSegment * segment_intersects (GtsPoint * p1, GtsPoint * p2, - GSList * i, - GtsPoint * o) -{ - while (i) { - GtsSegment * s = i->data; - GtsPoint * p3 = GTS_POINT (s->v1); - GtsPoint * p4 = GTS_POINT (s->v2); - - if (p3 != p1 && p3 != p2 && p4 != p1 && p4 != p2) { - gint o1 = ORIENTATION_SOS (p3, p4, p1, o); - gint o2 = ORIENTATION_SOS (p3, p4, p2, o); - - if (o1*o2 < 0) { - o1 = ORIENTATION_SOS (p1, p2, p3, o); - o2 = ORIENTATION_SOS (p1, p2, p4, o); - - if (o1*o2 < 0) - return s; - } - } - i = i->next; - } - return NULL; -} -#endif - -static gboolean is_inside_wedge (GtsSegment * s1, GtsSegment * s2, - GtsPoint * p, GtsPoint * o) -{ - GtsVertex * v1, * v2, * v3; - - ORIENTED_VERTICES (s1, s2, v1, v2); - v3 = s2->v1 != v2 ? s2->v1 : s2->v2; - - if (ORIENTATION (GTS_POINT (v1), GTS_POINT (v2), - GTS_POINT (v3), o) >= 0.) { - if (ORIENTATION (GTS_POINT (v1), GTS_POINT (v2), p, o) <= 0. || - ORIENTATION (GTS_POINT (v2), GTS_POINT (v3), p, o) <= 0.) - return FALSE; - } - else if (ORIENTATION (GTS_POINT (v1), GTS_POINT (v2), p, o) <= 0. && - ORIENTATION (GTS_POINT (v2), GTS_POINT (v3), p, o) <= 0.) - return FALSE; - return TRUE; -} - -static GtsSegment * connection (GtsPoint * p, - GSList * interior, - GSList * bloops, - GtsPoint * o) -{ - while (bloops) { - GtsSegment * start = bloops->data, * s = start; - - do { - GtsSegment * next = NEXT (s); - GtsVertex * v2 = s->v1 == next->v1 || s->v1 == next->v2 ? s->v1 : s->v2; - - if (is_inside_wedge (s, next, p, o) && - !segment_intersects (p, GTS_POINT (v2), interior, o)) - return s; - s = next; - } while (s != start); - bloops = bloops->next; - } - return NULL; -} - -static gdouble loop_orientation (GtsSegment * start, - GtsPoint * p, GtsPoint * o) -{ - GtsSegment * s = start; - gdouble or = 0.; - - do { - GtsSegment * next = NEXT (s); - GtsVertex * v1, * v2; - - ORIENTED_VERTICES (s, next, v1, v2); - or += ORIENTATION (p, GTS_POINT (v1), GTS_POINT (v2), o); - s = next; - } while (s != start); - -#ifdef DEBUG - fprintf (stderr, "loop orientation: %g\n", or); -#endif /* DEBUG */ - - return or; -} - -static void connect_interior_loop (GtsSegment * start, - GSList ** interior, - GSList ** bloops, - GtsSurface * surface, - GtsPoint * o) -{ - GtsSegment * s = start, * c = NULL, * next, * s1, * rs1, * rs; - GtsVertex * v, * cv; - gboolean isloop; - - do { - if (!(c = connection (GTS_POINT (s->v2), *interior, *bloops, o))) - s = NEXT (s); - } while (s != start && !c); - g_assert (c); - next = NEXT (c); - v = c->v1 == next->v1 || c->v1 == next->v2 ? c->v1 : c->v2; - cv = s->v2; -#ifdef DEBUG - fprintf (stderr, "connecting %p:%s with %p:%s\n", - cv, NAME (cv), v, NAME (v)); - fprintf (stderr, " c: %p: %p:%s %p:%s\n", c, - c->v1, NAME (c->v1), - c->v2, NAME (c->v2)); - fprintf (stderr, " next: %p: %p:%s %p:%s\n", next, - next->v1, NAME (next->v1), - next->v2, NAME (next->v2)); -#endif /* DEBUG */ - rs = reverse (s, FALSE, &isloop); - if (isloop) { - if (loop_orientation (rs, GTS_POINT (v), o) < 0.) { - GtsSegment * tmp = s; - s = rs; - rs = tmp; - } - *bloops = g_slist_prepend (*bloops, rs); - } - s1 = GTS_SEGMENT (gts_edge_new (surface->edge_class, v, cv)); - rs1 = GTS_SEGMENT (gts_edge_new (surface->edge_class, cv, v)); - NEXT (c) = s1; - NEXT (rs1) = next; - *interior = g_slist_prepend (*interior, s1); - NEXT (s1) = NEXT (s); - NEXT (s) = rs1; -} - -static GSList * boundary_loops (GSList * boundary) -{ - GSList * i = boundary; - GtsSegment * start = i->data; - GSList * loops = NULL; - - while (i) { - GtsSegment * s = i->data; - GSList * inext = i->next; - GtsSegment * next = inext ? inext->data : start; - GtsVertex * v = s->v1 == next->v1 || s->v1 == next->v2 ? s->v1 : s->v2; - - if (IS_SET (v, INTERIOR)) { - GtsSegment * intprev = prev_interior (v); - - NEXT (intprev) = next; - NEXT (s) = next_interior (v); - UNSET (v, INTERIOR); - } - else - NEXT (s) = next; - i = inext; - } - - i = boundary; - while (i) { - start = i->data; - - if (IS_SET (start, RELEVANT)) { - GtsSegment * s = start; - - do { - UNSET (s, RELEVANT); - UNSET (s, INTERIOR); - s = NEXT (s); - } while (s != start); - loops = g_slist_prepend (loops, start); - } - i = i->next; - } - - return loops; -} - -typedef struct _Ear Ear; - -struct _Ear { - GtsVertex * v1, * v2, * v3; - GtsSegment * s1, * s2, * s3; -}; - -static gboolean point_in_wedge (GtsPoint * p1, GtsPoint * p2, GtsPoint * p3, - GtsPoint * p, gboolean closed, GtsPoint * o) -{ - gdouble o1; - - if (p == p2 || p == p3) - return FALSE; - o1 = ORIENTATION (p1, p2, p, o); - if ((closed && o1 < 0.) || (!closed && o1 <= 0.)) return FALSE; - o1 = ORIENTATION (p3, p1, p, o); - if ((closed && o1 < 0.) || (!closed && o1 <= 0.)) return FALSE; - return TRUE; -} - -#if 0 -static gboolean segment_intersects1 (GtsPoint * p1, GtsPoint * p2, - GtsPoint * p3, GtsPoint * p4, - gboolean closed, GtsPoint * o) -{ - gdouble o1 = ORIENTATION (p3, p4, p1, o); - gdouble o2 = ORIENTATION (p3, p4, p2, o); - gdouble o3, o4; - - if ((closed && ((o1 > 0. && o2 > 0.) || (o1 < 0. && o2 < 0.))) || - (!closed && ((o1 >= 0. && o2 >= 0.) || (o1 <= 0. && o2 <= 0.)))) - return FALSE; - o3 = ORIENTATION (p1, p2, p3, o); - o4 = ORIENTATION (p1, p2, p4, o); - if ((o3 > 0. && o4 > 0.) || (o3 < 0. && o4 < 0.)) - return FALSE; - if (closed) return TRUE; - if ((o3 == 0. && o4 > 0.) || (o4 == 0. && o3 > 0.)) - return TRUE; - return FALSE; -} -#else -static gboolean segment_intersects1 (GtsPoint * p1, GtsPoint * p2, - GtsPoint * p3, GtsPoint * p4, - gboolean closed, GtsPoint * o) -{ - gint o1, o2; - - o1 = ORIENTATION_SOS (p3, p4, p1, o); - o2 = ORIENTATION_SOS (p3, p4, p2, o); - if (o1*o2 > 0) - return FALSE; - o1 = ORIENTATION_SOS (p1, p2, p3, o); - o2 = ORIENTATION_SOS (p1, p2, p4, o); - if (o1*o2 > 0) - return FALSE; - return TRUE; -} -#endif - -static GtsSegment * triangle_intersects_segments (GtsPoint * p1, - GtsPoint * p2, - GtsPoint * p3, - gboolean closed, - GtsSegment * start, - GtsPoint * o) -{ - GtsSegment * s = start; - - do { - GtsPoint * p4 = GTS_POINT (s->v1); - GtsPoint * p5 = GTS_POINT (s->v2); - - if (p4 == p1) { - if (point_in_wedge (p1, p2, p3, p5, closed, o)) - return s; - } - else if (p4 == p2) { - if (point_in_wedge (p2, p3, p1, p5, closed, o)) - return s; - } - else if (p4 == p3) { - if (point_in_wedge (p3, p1, p2, p5, closed, o)) - return s; - } - else if (p5 == p1) { - if (point_in_wedge (p1, p2, p3, p4, closed, o)) - return s; - } - else if (p5 == p2) { - if (point_in_wedge (p2, p3, p1, p4, closed, o)) - return s; - } - else if (p5 == p3) { - if (point_in_wedge (p3, p1, p2, p4, closed, o)) - return s; - } - else if (segment_intersects1 (p1, p2, p4, p5, closed, o) || - segment_intersects1 (p2, p3, p4, p5, closed, o) || - segment_intersects1 (p3, p1, p4, p5, closed, o)) - return s; - s = NEXT (s); - } while (s != start); - return NULL; -} - -static gboolean new_ear (GtsSegment * s, - Ear * e, - GtsSegment * start, - guint sloppy, - GtsPoint * o) -{ - gdouble or; - - e->s1 = s; - e->s2 = NEXT (s); - - g_return_val_if_fail (e->s2, FALSE); - g_return_val_if_fail (e->s2 != e->s1, FALSE); - - ORIENTED_VERTICES (e->s1, e->s2, e->v1, e->v2); - e->v3 = e->s2->v1 != e->v2 ? e->s2->v1 : e->s2->v2; - if (e->v3 == e->v1) - return FALSE; - e->s3 = NEXT (e->s2); - if (gts_segment_connect (e->s3, e->v1, e->v3)) { - if (NEXT (e->s3) != e->s1) - return FALSE; - } - else if (gts_vertices_are_connected (e->v1, e->v3)) - return FALSE; - else - e->s3 = NULL; - or = ORIENTATION (GTS_POINT (e->v1), GTS_POINT (e->v2), GTS_POINT (e->v3),o); - switch (sloppy) { - case 0: - if (or <= 0. || - triangle_intersects_segments (GTS_POINT (e->v1), GTS_POINT (e->v2), - GTS_POINT (e->v3), TRUE, start, o)) - return FALSE; - break; - case 1: - if (or < 0. || - (or > 0. && - triangle_intersects_segments (GTS_POINT (e->v1), GTS_POINT (e->v2), - GTS_POINT (e->v3), FALSE, start, o))) - return FALSE; - break; - case 2: - if ((or > 0. && - triangle_intersects_segments (GTS_POINT (e->v1), GTS_POINT (e->v2), - GTS_POINT (e->v3), FALSE, start, o)) || - (or < 0. && - triangle_intersects_segments (GTS_POINT (e->v2), GTS_POINT (e->v1), - GTS_POINT (e->v3), FALSE, start, o))) - return FALSE; - break; - case 3: - if (or < 0.) - return FALSE; - break; - } -#ifdef DEBUG - if (or <= 0.) - fprintf (stderr, "or: %g\n", or); -#endif /* DEBUG */ - g_assert (or > -1e-6); - return TRUE; -} - -static void triangulate_loop (GtsSegment * start, - GtsSurface * surface, - GtsPoint * o) -{ - GtsSegment * prev = start, * s; - guint sloppy = 0; -#ifdef DEBUG - guint nt = 0; -#endif /* DEBUG */ - - s = NEXT (start); - while (NEXT (s) != s) { - GtsSegment * next = NEXT (s); - Ear e; - -#ifdef DEBUG - fprintf (stderr, "prev: %p s: %p next: %p\n", prev, s, next); -#endif /* DEBUG */ - - if (!new_ear (s, &e, start, sloppy, o)) { - if (s == start) { - sloppy++; -#ifdef DEBUG - fprintf (stderr, "sloppy: %u\n", sloppy); -#endif /* DEBUG */ - } - prev = s; - s = next; - } - else { - GtsFace * f; - - if (!GTS_IS_EDGE (e.s3)) - e.s3 = GTS_SEGMENT (gts_edge_new (surface->edge_class, e.v1, e.v3)); - f = gts_face_new (surface->face_class, - GTS_EDGE (e.s1), GTS_EDGE (e.s2), GTS_EDGE (e.s3)); - gts_surface_add_face (surface, f); - UNSET (e.s1, RELEVANT); - UNSET (e.s1, INTERIOR); - UNSET (e.s2, RELEVANT); - UNSET (e.s2, INTERIOR); - NEXT (prev) = e.s3; - NEXT (e.s3) = NEXT (e.s2); - NEXT (e.s1) = NEXT (e.s2) = NULL; - start = prev; - s = NEXT (prev); - sloppy = 0; -#ifdef DEBUG - { - gchar name[80]; - FILE * fp; - - fprintf (stderr, " t.%u: (%p:%s,%p:%s,%p:%s)\n", - nt, - e.v1, NAME (e.v1), - e.v2, NAME (e.v2), - e.v3, NAME (e.v3)); - sprintf (name, "/tmp/t.%u", nt++); - fp = fopen (name, "wt"); - // gts_surface_write (surface, fp); - gts_write_triangle (GTS_TRIANGLE (f), NULL, fp); - // write_graph1 (start, interior, surface, fp); - fclose (fp); - print_loop (start, stderr); - } -#endif /* DEBUG */ - } - } - UNSET (s, RELEVANT); - UNSET (s, INTERIOR); - NEXT (s) = NULL; -} - -#ifdef CHECK_ORIENTED -static void check_object (GtsObject * o) -{ - g_assert (o->reserved == NULL); - g_assert (o->flags == 0); -} - -static void check_boundary (GtsEdge * e, GtsSurface * s) -{ - check_object (GTS_OBJECT (e)); - check_object (GTS_OBJECT (GTS_SEGMENT (e)->v1)); - check_object (GTS_OBJECT (GTS_SEGMENT (e)->v2)); - g_assert (gts_edge_face_number (e, s) == 1); -} - -static void check_interior (GtsEdge * e, GtsSurface * s) -{ - guint n; - check_object (GTS_OBJECT (e)); - check_object (GTS_OBJECT (GTS_SEGMENT (e)->v1)); - check_object (GTS_OBJECT (GTS_SEGMENT (e)->v2)); - - n = gts_edge_face_number (e, s); -#ifdef DEBUG - if (n != 2) - gts_surface_print_stats (s, stderr); -#endif /* DEBUG */ - g_assert (n == 2); -} - -static void check_boundary_interior_triangulation (GSList * boundary, - GSList * interior, - GtsSurface * surface) -{ - g_slist_foreach (boundary, (GFunc) check_boundary, surface); - g_slist_foreach (interior, (GFunc) check_interior, surface); -} -#endif /*ifdef CHECK_ORIENTED */ - -static void merge_duplicate (GtsEdge * e) -{ - GtsEdge * dup = gts_edge_is_duplicate (e); - - g_assert (dup); - gts_edge_replace (dup, e); - gts_object_destroy (GTS_OBJECT (dup)); -} - -static void triangulate_boundary_interior (GSList * boundary, - GSList * interior, - GtsSurface * s, - GtsPoint * o) -{ - GSList * iloops, * bloops, * i; - - i = boundary; - while (i) { - SET (i->data, RELEVANT); - i = i->next; - } - i = interior; - while (i) { - SET (i->data, RELEVANT); - SET (i->data, INTERIOR); - i = i->next; - } - - iloops = interior_loops (interior); - bloops = boundary_loops (boundary); - - i = iloops; - while (i) { -#ifdef DEBUG - fprintf (stderr, "--- interior loop ---\n"); - print_loop (i->data, stderr); -#endif /* DEBUG */ - connect_interior_loop (i->data, &interior, &bloops, s, o); - i = i->next; - } - -#ifdef DEBUG - { - FILE * fp = fopen ("/tmp/bloops", "w"); - write_loops (bloops, fp); - fclose (fp); - } -#endif /* DEBUG */ - - i = bloops; - while (i) { -#ifdef DEBUG - fprintf (stderr, "--- boundary loop ---\n"); - print_loop (i->data, stderr); -#endif /* DEBUG */ - triangulate_loop (i->data, s, o); - i = i->next; - } - - g_slist_foreach (interior, (GFunc) merge_duplicate, NULL); - g_slist_free (iloops); - g_slist_free (bloops); - -#ifdef CHECK_ORIENTED - check_boundary_interior_triangulation (boundary, interior, s); -#endif /* CHECK_ORIENTED */ -} - -static void create_edges (GtsSegment * s, GtsSurface * surface) -{ - if (GTS_OBJECT (s)->reserved) { - GList * i = GTS_OBJECT (s)->reserved; - GtsVertex * v1 = i->data; - - GTS_OBJECT (s)->reserved = g_list_prepend (i, - gts_edge_new (surface->edge_class, s->v1, v1)); - while (i) { - GList * next = i->next; - GtsVertex * v2 = next ? next->data : s->v2; - - GTS_OBJECT (i->data)->reserved = NULL; - i->data = gts_edge_new (surface->edge_class, v1, v2); - v1 = v2; - i = next; - } - } -} - -static void add_boundary (GtsSegment * s, GtsSegment * next, - GSList ** boundary) -{ - if (GTS_OBJECT (s)->reserved == NULL) - *boundary = g_slist_prepend (*boundary, s); - else { - if (s->v2 == next->v2 || s->v2 == next->v1) { - GList * i = g_list_last (GTS_OBJECT (s)->reserved); - - while (i) { - *boundary = g_slist_prepend (*boundary, i->data); - i = i->prev; - } - } - else { - GList * i = GTS_OBJECT (s)->reserved; - - while (i) { - *boundary = g_slist_prepend (*boundary, i->data); - i = i->next; - } - } - } -} - -static void triangulate_face (GtsTriangle * t, GtsSurface * surface) -{ - GSList * interior = GTS_OBJECT (t)->reserved; - GSList * boundary = NULL; - GtsSurface * s = gts_surface_new (gts_surface_class (), - surface->face_class, - surface->edge_class, - surface->vertex_class); - gdouble x, y, z; - GtsPoint * p = GTS_POINT (GTS_SEGMENT (t->e1)->v1); - GtsPoint * o; - - GTS_OBJECT (t)->reserved = NULL; - gts_triangle_normal (t, &x, &y, &z); - g_assert (x != 0. || y != 0. || z != 0.); - o = gts_point_new (gts_point_class (), p->x + x, p->y + y, p->z + z); - add_boundary (GTS_SEGMENT (t->e3), GTS_SEGMENT (t->e1), &boundary); - add_boundary (GTS_SEGMENT (t->e2), GTS_SEGMENT (t->e3), &boundary); - add_boundary (GTS_SEGMENT (t->e1), GTS_SEGMENT (t->e2), &boundary); -#ifdef DEBUG - { - static guint nt = 0; - char name[80]; - FILE * fp; - - fprintf (stderr, "%u: triangulating %p\n", nt, t); -if (nt == 28) - fprintf (stderr, "tintin!!!!\n"); - sprintf (name, "/tmp/oc.%u", nt++); - fp = fopen (name, "wt"); - // write_graph (boundary, interior, s, fp); - write_segments (boundary, interior, fp); - fclose (fp); - } -#endif /* DEBUG */ - triangulate_boundary_interior (boundary, interior, s, o); - g_slist_free (interior); - g_slist_free (boundary); - if (GTS_OBJECT (t)->klass->attributes) - gts_surface_foreach_face (s, (GtsFunc) gts_object_attributes, t); - gts_surface_merge (surface, s); - gts_object_destroy (GTS_OBJECT (s)); - gts_object_destroy (GTS_OBJECT (o)); -} - -static void free_edge_list (GtsObject * o) -{ - g_list_free (o->reserved); - o->reserved = NULL; -} - -/** - * gts_surface_inter_new: - * @klass: a #GtsSurfaceInterClass. - * @s1: a #GtsSurface. - * @s2: a #GtsSurface. - * @faces_tree1: a bounding box tree (see gts_bb_tree_new()) for - * the faces of @s1. - * @faces_tree2: a bounding box tree for the faces of @s2. - * @is_open1: whether @s1 is an "open" surface. - * @is_open2: whether @s2 is an "open" surface. - * - * When triangulating the cut faces, the new faces inherit the - * attributes of these original faces through their attributes() - * method. - * - * Returns: a new #GtsSurfaceInter describing the intersection of @s1 - * and @s2. - */ -GtsSurfaceInter * gts_surface_inter_new (GtsSurfaceInterClass * klass, - GtsSurface * s1, - GtsSurface * s2, - GNode * faces_tree1, - GNode * faces_tree2, - gboolean is_open1, - gboolean is_open2) -{ - GtsSurfaceInter * si; - GtsSurface * s; - - g_return_val_if_fail (klass != NULL, NULL); - g_return_val_if_fail (s1 != NULL, NULL); - g_return_val_if_fail (s2 != NULL, NULL); - g_return_val_if_fail (faces_tree1 != NULL, NULL); - g_return_val_if_fail (faces_tree2 != NULL, NULL); - - si = surface_inter_new (klass, s1, s2, faces_tree1, faces_tree2); - - gts_surface_foreach_edge (si->s1, (GtsFunc) create_edges, si->s1); - gts_surface_foreach_edge (si->s2, (GtsFunc) create_edges, si->s2); - -#ifdef DEBUG - fprintf (stderr, "====== triangulating s1 ======\n"); -#endif /* DEBUG */ - s = gts_surface_new (gts_surface_class (), - s1->face_class, - s1->edge_class, - s1->vertex_class); - gts_surface_foreach_face (si->s1, (GtsFunc) triangulate_face, s); - gts_surface_foreach_edge (si->s1, (GtsFunc) free_edge_list, NULL); - gts_object_destroy (GTS_OBJECT (si->s1)); - si->s1 = s; - GTS_OBJECT (si->s1)->reserved = s1; - -#ifdef DEBUG - fprintf (stderr, "====== triangulating s2 ======\n"); -#endif /* DEBUG */ - s = gts_surface_new (gts_surface_class (), - s2->face_class, - s2->edge_class, - s2->vertex_class); - gts_surface_foreach_face (si->s2, (GtsFunc) triangulate_face, s); - gts_surface_foreach_edge (si->s2, (GtsFunc) free_edge_list, NULL); - gts_object_destroy (GTS_OBJECT (si->s2)); - si->s2 = s; - GTS_OBJECT (si->s2)->reserved = s2; - - return si; -} - -static void check_surface_edge (GtsEdge * e, gpointer * data) -{ - gboolean * ok = data[0]; - GtsSurface * s = data[1]; - GtsSurface * bs = GTS_OBJECT (s)->reserved; - guint nf = gts_edge_face_number (e, s); - - if (nf < 1 || nf > 2) { - *ok = FALSE; - g_return_if_fail (nf >= 1 && nf <= 2); - } - if (nf == 1 && gts_edge_face_number (e, bs) == 0) { - *ok = FALSE; - g_return_if_fail (gts_edge_face_number (e, bs) > 0); - } -} - -static void mark_edge (GtsObject * o, gpointer data) -{ - o->reserved = data; -} - -static gint triangle_orientation (GtsTriangle * t, GtsEdge * e) -{ - GtsSegment * s = GTS_SEGMENT (t->e1 == e ? t->e2 - : - t->e2 == e ? t->e3 - : - t->e1); - GtsVertex * v2 = GTS_SEGMENT (e)->v2; - - if (s->v1 == v2 || s->v2 == v2) - return 1; - return -1; -} - -static gboolean check_orientation (GtsEdge * e, GtsSurface * s) -{ - GtsTriangle * t1 = NULL, * t2 = NULL; - GSList * i = e->triangles; - gint o1 = 0, o2 = 0; - - while (i) { - if (GTS_IS_FACE (i->data) && - gts_face_has_parent_surface (i->data, s)) { - if (t1 == NULL) { - t1 = i->data; - o1 = triangle_orientation (t1, e); - } - else if (t2 == NULL) { - t2 = i->data; - o2 = triangle_orientation (t2, e); - g_return_val_if_fail (o1*o2 < 0, FALSE); - } - else - g_assert_not_reached (); - } - i = i->next; - } - g_return_val_if_fail (t1 && t2, FALSE); - return TRUE; -} - -static void check_edge (GtsSegment * s, gpointer * data) -{ - gboolean * ok = data[0]; - GtsSurfaceInter * si = data[1]; - gboolean * closed = data[2]; - GSList * j; - guint nn = 0; - - j = s->v1->segments; - while (j && *ok) { - GtsSegment * s1 = j->data; - - if (s1 != s && GTS_OBJECT (s1)->reserved == si) { - if (s1->v2 != s->v1) - *ok = FALSE; - nn++; - } - j = j->next; - } - j = s->v2->segments; - while (j && *ok) { - GtsSegment * s1 = j->data; - - if (s1 != s && GTS_OBJECT (s1)->reserved == si) { - if (s1->v1 != s->v2) - *ok = FALSE; - nn++; - } - j = j->next; - } - if (nn != 2) - *closed = FALSE; - - if (!check_orientation (GTS_EDGE (s), si->s1)) - *ok = FALSE; - if (!check_orientation (GTS_EDGE (s), si->s2)) - *ok = FALSE; -} - -/** - * gts_surface_inter_check: - * @si: a #GtsSurfaceInter. - * @closed: is set to %TRUE if @si->edges is a closed curve, %FALSE - * otherwise. - * - * Returns: %TRUE if the curve described by @si is an orientable - * manifold, %FALSE otherwise. - */ -gboolean gts_surface_inter_check (GtsSurfaceInter * si, - gboolean * closed) -{ - gboolean ok = TRUE; - gpointer data[3]; - - g_return_val_if_fail (si != NULL, FALSE); - g_return_val_if_fail (closed != NULL, FALSE); - - *closed = si->edges ? TRUE : FALSE; - - /* mark edges as used by si */ - g_slist_foreach (si->edges, (GFunc) mark_edge, si); - - data[0] = &ok; - data[1] = si; - data[2] = closed; - g_slist_foreach (si->edges, (GFunc) check_edge, data); - g_slist_foreach (si->edges, (GFunc) gts_object_reset_reserved, NULL); - - /* check connectivity of the faces of @si */ - if (*closed) { - gpointer data[2]; - - data[0] = &ok; - data[1] = si->s1; - gts_surface_foreach_edge (si->s1, (GtsFunc) check_surface_edge, data); - data[1] = si->s2; - gts_surface_foreach_edge (si->s2, (GtsFunc) check_surface_edge, data); - } - - return ok; -} - -/* Given @e and @f returns a #GtsFace compatible with @f and belonging to - @s1 or @s2 */ -static GtsFace * next_compatible_face (GtsEdge * e, - GtsFace * f, - GtsSurface * s1, - GtsSurface * s2) -{ - GSList * i = e->triangles; - GtsFace * f2 = NULL, * f3 = NULL; - - while (i) { - GtsFace * f1 = i->data; - - if (f1 != f && GTS_IS_FACE (f1)) { - if (gts_face_has_parent_surface (f1, s1)) - return f1; - if (gts_face_has_parent_surface (f1, s2)) { - if (f2 == NULL) f2 = f1; - else if (f3 == NULL) f3 = f1; - else g_assert_not_reached (); /* s2 is a non-manifold surface */ - } - } - i = i->next; - } - if (f3 == NULL) { - if (gts_edge_is_boundary (e, s2)) - return NULL; - return f2; - } - g_assert (gts_face_has_parent_surface (f, s1)); - if (gts_triangles_are_compatible (GTS_TRIANGLE (f), GTS_TRIANGLE (f2), e)) - return f2; - return f3; -} - -static void walk_faces (GtsEdge * e, GtsFace * f, - GtsSurface * s1, - GtsSurface * s2, - GtsSurface * s) -{ - GtsFifo * faces = gts_fifo_new (); - GtsFifo * edges = gts_fifo_new (); - - gts_fifo_push (faces, f); - gts_fifo_push (edges, e); - while ((f = gts_fifo_pop (faces)) && (e = gts_fifo_pop (edges))) { - if (!GTS_OBJECT (f)->reserved) { - GtsTriangle * t = GTS_TRIANGLE (f); - GtsFace * f1; - - gts_surface_add_face (s, f); - GTS_OBJECT (f)->reserved = s; - if (t->e1 != e && !GTS_OBJECT (t->e1)->reserved && - (f1 = next_compatible_face (t->e1, f, s1, s2))) { - gts_fifo_push (faces, f1); - gts_fifo_push (edges, t->e1); - } - if (t->e2 != e && !GTS_OBJECT (t->e2)->reserved && - (f1 = next_compatible_face (t->e2, f, s1, s2))) { - gts_fifo_push (faces, f1); - gts_fifo_push (edges, t->e2); - } - if (t->e3 != e && !GTS_OBJECT (t->e3)->reserved && - (f1 = next_compatible_face (t->e3, f, s1, s2))) { - gts_fifo_push (faces, f1); - gts_fifo_push (edges, t->e3); - } - } - } - gts_fifo_destroy (faces); - gts_fifo_destroy (edges); -} - -/** - * gts_surface_inter_boolean: - * @si: a #GtsSurfaceInter. - * @surface: a #GtsSurface. - * @op: a #GtsBooleanOperation. - * - * Adds to @surface the part of the surface described by @si and @op. - */ -void gts_surface_inter_boolean (GtsSurfaceInter * si, - GtsSurface * surface, - GtsBooleanOperation op) -{ - GtsSurface * s = NULL; - gint orient = 1; - GSList * i; - - g_return_if_fail (si != NULL); - g_return_if_fail (surface != NULL); - - switch (op) { - case GTS_1_OUT_2: s = si->s1; orient = 1; break; - case GTS_1_IN_2: s = si->s1; orient = -1; break; - case GTS_2_OUT_1: s = si->s2; orient = -1; break; - case GTS_2_IN_1: s = si->s2; orient = 1; break; - default: g_assert_not_reached (); - } - - /* mark edges as belonging to intersection */ - g_slist_foreach (si->edges, (GFunc) mark_edge, si); - - i = si->edges; - while (i) { - GtsEdge * e = i->data; - GSList * j = e->triangles; - - while (j) { - if (gts_face_has_parent_surface (j->data, s) && - orient*triangle_orientation (j->data, e) > 0) { -#ifdef DEBUG_BOOLEAN - GtsFace * boundary = gts_edge_is_boundary (e, surface); - - g_assert (!boundary || boundary == j->data); -#endif /* DEBUG_BOOLEAN */ - walk_faces (e, j->data, s, GTS_OBJECT (s)->reserved, surface); - break; - } - j = j->next; - } - i = i->next; - } - g_slist_foreach (si->edges, (GFunc) gts_object_reset_reserved, NULL); - gts_surface_foreach_face (surface, - (GtsFunc) gts_object_reset_reserved, NULL); -} - -static void self_intersecting (GtsBBox * bb1, GtsBBox * bb2, - gpointer * d) -{ - GtsTriangle * t1 = bb1->bounded; - GtsTriangle * t2 = bb2->bounded; - - if (t1 != t2) { - GtsSegment * s1 = GTS_SEGMENT (t1->e1); - GtsSegment * s2 = GTS_SEGMENT (t1->e2); - GtsSegment * s3 = GTS_SEGMENT (t1->e3); - GtsSegment * s4 = GTS_SEGMENT (t2->e1); - GtsSegment * s5 = GTS_SEGMENT (t2->e2); - GtsSegment * s6 = GTS_SEGMENT (t2->e3); - GtsPoint * pi; - - if ((!gts_segments_touch (s4, s1) && - !gts_segments_touch (s4, s2) && - !gts_segments_touch (s4, s3) && - (pi = segment_triangle_intersection (s4, t1, gts_point_class ())) - != NULL) || - (!gts_segments_touch (s5, s1) && - !gts_segments_touch (s5, s2) && - !gts_segments_touch (s5, s3) && - (pi = segment_triangle_intersection (s5, t1, gts_point_class ())) - != NULL) || - (!gts_segments_touch (s6, s1) && - !gts_segments_touch (s6, s2) && - !gts_segments_touch (s6, s3) && - (pi = segment_triangle_intersection (s6, t1, gts_point_class ())) - != NULL)) { - GtsBBTreeTraverseFunc func = d[0]; - gpointer data = d[1]; - gboolean * self_inter = d[2]; - - gts_object_destroy (GTS_OBJECT (pi)); - *self_inter = TRUE; - (* func) (bb1, bb2, data); - } - } -} - -/** - * gts_surface_foreach_intersecting_face: - * @s: a #GtsSurface. - * @func: a #GtsBBTreeTraverseFunc. - * @data: user data to pass to @func. - * - * Calls @func for each intersecting pair of faces of @s. - * - * Returns: %TRUE if @func was called at least once, %FALSE otherwise. - */ -gboolean gts_surface_foreach_intersecting_face (GtsSurface * s, - GtsBBTreeTraverseFunc func, - gpointer data) -{ - GNode * tree; - gpointer d[3]; - gboolean self_inter = FALSE; - - g_return_val_if_fail (s != NULL, FALSE); - g_return_val_if_fail (func != NULL, FALSE); - - tree = gts_bb_tree_surface (s); - d[0] = func; - d[1] = data; - d[2] = &self_inter; - gts_bb_tree_traverse_overlapping (tree, tree, - (GtsBBTreeTraverseFunc) self_intersecting, - d); - gts_bb_tree_destroy (tree, TRUE); - - return self_inter; -} - -static void add_intersecting (GtsBBox * bb1, GtsBBox * bb2, - GtsSurface * intersected) -{ - gts_surface_add_face (intersected, bb1->bounded); - gts_surface_add_face (intersected, bb2->bounded); -} - -/** - * gts_surface_is_self_intersecting: - * @s: a #GtsSurface. - * - * Returns: a new #GtsSurface containing the faces of @s which are - * self-intersecting or %NULL if no faces of @s are self-intersecting. - */ -GtsSurface * gts_surface_is_self_intersecting (GtsSurface * s) -{ - GtsSurface * intersected; - - g_return_val_if_fail (s != NULL, NULL); - - intersected = gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass), - s->face_class, - s->edge_class, - s->vertex_class); - if (!gts_surface_foreach_intersecting_face (s, - (GtsBBTreeTraverseFunc) add_intersecting, intersected)) { - gts_object_destroy (GTS_OBJECT (intersected)); - intersected = NULL; - } - return intersected; -} Index: trunk/src_3rd/gts/container.c =================================================================== --- trunk/src_3rd/gts/container.c (revision 6802) +++ trunk/src_3rd/gts/container.c (nonexistent) @@ -1,493 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "gts.h" - -/* GtsContainee */ - -static void containee_class_init (GtsContaineeClass * klass) -{ - klass->remove_container = NULL; - klass->add_container = NULL; - klass->foreach = NULL; - klass->is_contained = NULL; - klass->replace = NULL; -} - -GtsContaineeClass * gts_containee_class (void) -{ - static GtsContaineeClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo containee_info = { - "GtsContainee", - sizeof (GtsContainee), - sizeof (GtsContaineeClass), - (GtsObjectClassInitFunc) containee_class_init, - (GtsObjectInitFunc) NULL, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (gts_object_class (), - &containee_info); - } - - return klass; -} - -GtsContainee * gts_containee_new (GtsContaineeClass * klass) -{ - GtsContainee * object; - - object = GTS_CONTAINEE (gts_object_new (GTS_OBJECT_CLASS (klass))); - - return object; -} - -gboolean gts_containee_is_contained (GtsContainee * item, - GtsContainer * c) -{ - g_return_val_if_fail (item != NULL, FALSE); - g_return_val_if_fail (c != NULL, FALSE); - - if (GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->is_contained) - return - (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->is_contained) - (item, c); - return FALSE; -} - -void gts_containee_replace (GtsContainee * item, - GtsContainee * with) -{ - if (GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->replace) - (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->replace) (item, with); - if (GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->foreach) { - (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->foreach) - (item, (GtsFunc) gts_container_add, with); - (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->foreach) - (item, (GtsFunc) gts_container_remove, item); - } -} - -/* GtsSListContainee */ - -static void slist_containee_destroy (GtsObject * object) -{ - GtsSListContainee * item = GTS_SLIST_CONTAINEE (object); - GSList * i; - - i = item->containers; - while (i) { - GSList * next = i->next; - - gts_container_remove (i->data, GTS_CONTAINEE (item)); - i = next; - } - g_assert (item->containers == NULL); - - (* GTS_OBJECT_CLASS (gts_slist_containee_class ())->parent_class->destroy) - (object); -} - -static void slist_containee_remove_container (GtsContainee * i, - GtsContainer * c) -{ - GtsSListContainee * item = GTS_SLIST_CONTAINEE (i); - item->containers = g_slist_remove (item->containers, c); -} - -static void slist_containee_add_container (GtsContainee * i, - GtsContainer * c) -{ - GtsSListContainee * item = GTS_SLIST_CONTAINEE (i); - if (!g_slist_find (item->containers, c)) - item->containers = g_slist_prepend (item->containers, c); -} - -static void slist_containee_foreach (GtsContainee * c, - GtsFunc func, - gpointer data) -{ - GSList * i = GTS_SLIST_CONTAINEE (c)->containers; - - while (i) { - GSList * next = i->next; - - (* func) (i->data, data); - i = next; - } -} - -static gboolean slist_containee_is_contained (GtsContainee * i, - GtsContainer * c) -{ - return g_slist_find (GTS_SLIST_CONTAINEE (i)->containers, c) ? TRUE : FALSE; -} - -static void slist_containee_class_init (GtsSListContaineeClass * klass) -{ - GTS_CONTAINEE_CLASS (klass)->remove_container = - slist_containee_remove_container; - GTS_CONTAINEE_CLASS (klass)->add_container = - slist_containee_add_container; - GTS_CONTAINEE_CLASS (klass)->foreach = - slist_containee_foreach; - GTS_CONTAINEE_CLASS (klass)->is_contained = - slist_containee_is_contained; - - GTS_OBJECT_CLASS (klass)->destroy = slist_containee_destroy; -} - -static void slist_containee_init (GtsSListContainee * object) -{ - object->containers = NULL; -} - -GtsSListContaineeClass * gts_slist_containee_class (void) -{ - static GtsSListContaineeClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo slist_containee_info = { - "GtsSListContainee", - sizeof (GtsSListContainee), - sizeof (GtsSListContaineeClass), - (GtsObjectClassInitFunc) slist_containee_class_init, - (GtsObjectInitFunc) slist_containee_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_containee_class ()), - &slist_containee_info); - } - - return klass; -} - -/* GtsContainer */ - -static void remove_container (GtsContainee * item, GtsContainer * c) -{ - if (GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->remove_container) - (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->remove_container) - (item, c); -} - -static void container_destroy (GtsObject * object) -{ - GtsContainer * c = GTS_CONTAINER (object); - - gts_container_foreach (c, (GtsFunc) remove_container, c); - - (* GTS_OBJECT_CLASS (gts_container_class ())->parent_class->destroy) - (object); -} - -static void container_add (GtsContainer * c, GtsContainee * item) -{ - if (GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->add_container) - (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->add_container) - (item, c); -} - -static void container_remove (GtsContainer * c, GtsContainee * item) -{ - if (GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->remove_container) - (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->remove_container) - (item, c); -} - -static void container_clone_add (GtsContainee * item, GtsContainer * clone) -{ - gts_container_add (clone, item); -} - -static void container_clone (GtsObject * clone, GtsObject * object) -{ - gts_object_init (clone, object->klass); - gts_container_foreach (GTS_CONTAINER (object), - (GtsFunc) container_clone_add, clone); -} - -static void container_class_init (GtsContainerClass * klass) -{ - klass->add = container_add; - klass->remove = container_remove; - klass->foreach = NULL; - klass->size = NULL; - - GTS_OBJECT_CLASS (klass)->destroy = container_destroy; - GTS_OBJECT_CLASS (klass)->clone = container_clone; -} - -GtsContainerClass * gts_container_class (void) -{ - static GtsContainerClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo container_info = { - "GtsContainer", - sizeof (GtsContainer), - sizeof (GtsContainerClass), - (GtsObjectClassInitFunc) container_class_init, - (GtsObjectInitFunc) NULL, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = - gts_object_class_new (GTS_OBJECT_CLASS (gts_slist_containee_class ()), - &container_info); - } - - return klass; -} - -GtsContainer * gts_container_new (GtsContainerClass * klass) -{ - GtsContainer * object; - - object = GTS_CONTAINER (gts_object_new (GTS_OBJECT_CLASS (klass))); - - return object; -} - -void gts_container_add (GtsContainer * c, - GtsContainee * item) -{ - g_return_if_fail (c != NULL); - g_return_if_fail (item != NULL); - - g_assert (GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->add); - (* GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->add) (c, item); -} - -void gts_container_remove (GtsContainer * c, - GtsContainee * item) -{ - g_return_if_fail (c != NULL); - g_return_if_fail (item != NULL); - - g_assert (GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->remove); - (* GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->remove) (c, item); -} - -void gts_container_foreach (GtsContainer * c, - GtsFunc func, - gpointer data) -{ - g_return_if_fail (c != NULL); - g_return_if_fail (func != NULL); - - if (GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->foreach) - (* GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->foreach) (c, func, data); -} - -guint gts_container_size (GtsContainer * c) -{ - g_return_val_if_fail (c != NULL, 0); - - if (GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->size) - return (* GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->size) (c); - return 0; -} - -/* GtsHashContainer */ - -static void hash_container_destroy (GtsObject * object) -{ - GHashTable * items = GTS_HASH_CONTAINER (object)->items; - - (* GTS_OBJECT_CLASS (gts_hash_container_class ())->parent_class->destroy) - (object); - - g_hash_table_destroy (items); -} - -static void hash_container_add (GtsContainer * c, GtsContainee * item) -{ - g_return_if_fail (GTS_HASH_CONTAINER (c)->frozen == FALSE); - - g_hash_table_insert (GTS_HASH_CONTAINER (c)->items, item, NULL); - - (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_hash_container_class ())->parent_class)->add) (c, item); -} - -static void hash_container_remove (GtsContainer * c, GtsContainee * item) -{ - g_return_if_fail (GTS_HASH_CONTAINER (c)->frozen == FALSE); - - g_hash_table_remove (GTS_HASH_CONTAINER (c)->items, item); - - (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_hash_container_class ())->parent_class)->remove) (c, item); -} - -static void hash_foreach (GtsContainee * item, - gpointer item_data, - gpointer * info) -{ - (* ((GtsFunc) info[0])) (item, info[1]); -} - -static void hash_container_foreach (GtsContainer * c, - GtsFunc func, - gpointer data) -{ - gpointer info[2]; - - info[0] = func; - info[1] = data; - /* prevent removing or adding items */ - GTS_HASH_CONTAINER (c)->frozen = TRUE; - g_hash_table_foreach (GTS_HASH_CONTAINER (c)->items, - (GHFunc) hash_foreach, info); - GTS_HASH_CONTAINER (c)->frozen = FALSE; -} - -static guint hash_container_size (GtsContainer * c) -{ - return g_hash_table_size (GTS_HASH_CONTAINER (c)->items); -} - -static void hash_container_class_init (GtsHashContainerClass * klass) -{ - GTS_CONTAINER_CLASS (klass)->add = hash_container_add; - GTS_CONTAINER_CLASS (klass)->remove = hash_container_remove; - GTS_CONTAINER_CLASS (klass)->foreach = hash_container_foreach; - GTS_CONTAINER_CLASS (klass)->size = hash_container_size; - - GTS_OBJECT_CLASS (klass)->destroy = hash_container_destroy; -} - -static void hash_container_init (GtsHashContainer * object) -{ - object->items = g_hash_table_new (NULL, NULL); - object->frozen = FALSE; -} - -GtsHashContainerClass * gts_hash_container_class (void) -{ - static GtsHashContainerClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo hash_container_info = { - "GtsHashContainer", - sizeof (GtsHashContainer), - sizeof (GtsHashContainerClass), - (GtsObjectClassInitFunc) hash_container_class_init, - (GtsObjectInitFunc) hash_container_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_container_class ()), - &hash_container_info); - } - - return klass; -} - -/* GtsSListContainer */ - -static void slist_container_destroy (GtsObject * object) -{ - GSList * items = GTS_SLIST_CONTAINER (object)->items; - - (* GTS_OBJECT_CLASS (gts_slist_container_class ())->parent_class->destroy) - (object); - - g_slist_free (items); -} - -static void slist_container_add (GtsContainer * c, GtsContainee * item) -{ - g_return_if_fail (GTS_SLIST_CONTAINER (c)->frozen == FALSE); - - if (!g_slist_find (GTS_SLIST_CONTAINER (c)->items, item)) - GTS_SLIST_CONTAINER (c)->items = - g_slist_prepend (GTS_SLIST_CONTAINER (c)->items, item); - - (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_slist_container_class ())->parent_class)->add) (c, item); -} - -static void slist_container_remove (GtsContainer * c, GtsContainee * item) -{ - g_return_if_fail (GTS_SLIST_CONTAINER (c)->frozen == FALSE); - - GTS_SLIST_CONTAINER (c)->items = - g_slist_remove (GTS_SLIST_CONTAINER (c)->items, item); - - (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_slist_container_class ())->parent_class)->remove) (c, item); -} - -static void slist_container_foreach (GtsContainer * c, - GtsFunc func, - gpointer data) -{ - GSList * i; - - i = GTS_SLIST_CONTAINER (c)->items; - while (i) { - GSList * next = i->next; - - (* func) (i->data, data); - i = next; - } -} - -static guint slist_container_size (GtsContainer * c) -{ - return g_slist_length (GTS_SLIST_CONTAINER (c)->items); -} - -static void slist_container_class_init (GtsSListContainerClass * klass) -{ - GTS_CONTAINER_CLASS (klass)->add = slist_container_add; - GTS_CONTAINER_CLASS (klass)->remove = slist_container_remove; - GTS_CONTAINER_CLASS (klass)->foreach = slist_container_foreach; - GTS_CONTAINER_CLASS (klass)->size = slist_container_size; - - GTS_OBJECT_CLASS (klass)->destroy = slist_container_destroy; -} - -static void slist_container_init (GtsSListContainer * object) -{ - object->items = NULL; - object->frozen = FALSE; -} - -GtsSListContainerClass * gts_slist_container_class (void) -{ - static GtsSListContainerClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo slist_container_info = { - "GtsSListContainer", - sizeof (GtsSListContainer), - sizeof (GtsSListContainerClass), - (GtsObjectClassInitFunc) slist_container_class_init, - (GtsObjectInitFunc) slist_container_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_container_class ()), - &slist_container_info); - } - - return klass; -} Index: trunk/src_3rd/gts/eheap.c =================================================================== --- trunk/src_3rd/gts/eheap.c (revision 6802) +++ trunk/src_3rd/gts/eheap.c (nonexistent) @@ -1,461 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include "gts.h" - -#define PARENT(i) ((i) >= 2 ? (i)/2 : 0) -#define LEFT_CHILD(i) (2*(i)) -#define RIGHT_CHILD(i) (2*(i) + 1) - - -/** - * gts_eheap_new: - * @key_func: a #GtsKeyFunc or %NULL. - * @data: user data to be passed to @key_func. - * - * Returns: a new #GtsEHeap using @key_func as key. - */ -GtsEHeap * gts_eheap_new (GtsKeyFunc key_func, - gpointer data) -{ - GtsEHeap * heap; - - heap = g_malloc (sizeof(GtsEHeap)); - heap->elts = g_ptr_array_new (); - heap->func = key_func; - heap->data = data; - heap->frozen = FALSE; - heap->randomized = FALSE; - return heap; -} - -static void sift_up (GtsEHeap * heap, guint i) -{ - GtsEHeapPair * parent, * child; - guint p; - gpointer * pdata = heap->elts->pdata; - gdouble key; - - child = pdata[i - 1]; - key = child->key; - while ((p = PARENT (i))) { - parent = pdata[p - 1]; - if (parent->key > key || - (heap->randomized && parent->key == key && rand () < RAND_MAX/2)) { - pdata[p - 1] = child; - pdata[i - 1] = parent; - child->pos = p; - parent->pos = i; - i = p; - } - else - i = 0; - } -} - -/** - * gts_eheap_insert: - * @heap: a #GtsEHeap. - * @p: a pointer to add to the heap. - * - * Inserts a new element @p in the heap. - * - * Returns: a #GtsEHeapPair describing the position of the element in the heap. - * This pointer is necessary for gts_eheap_remove() and - * gts_eheap_decrease_key(). - */ -GtsEHeapPair * gts_eheap_insert (GtsEHeap * heap, gpointer p) -{ - GtsEHeapPair * pair; - GPtrArray * elts; - - g_return_val_if_fail (heap != NULL, NULL); - g_return_val_if_fail (heap->func != NULL, NULL); - - elts = heap->elts; - pair = g_malloc (sizeof (GtsEHeapPair)); - g_ptr_array_add (elts, pair); - pair->data = p; - pair->pos = elts->len; - pair->key = (*heap->func) (p, heap->data); - if (!heap->frozen) - sift_up (heap, elts->len); - return pair; -} - -/** - * gts_eheap_insert_with_key: - * @heap: a #GtsEHeap. - * @p: a pointer to add to the heap. - * @key: the value of the key associated to @p. - * - * Inserts a new element @p in the heap. - * - * Returns: a #GtsEHeapPair describing the position of the element in the heap. - * This pointer is necessary for gts_eheap_remove() and - * gts_eheap_decrease_key(). - */ -GtsEHeapPair * gts_eheap_insert_with_key (GtsEHeap * heap, - gpointer p, - gdouble key) -{ - GtsEHeapPair * pair; - GPtrArray * elts; - - g_return_val_if_fail (heap != NULL, NULL); - - elts = heap->elts; - pair = g_malloc (sizeof (GtsEHeapPair)); - g_ptr_array_add (elts, pair); - pair->data = p; - pair->pos = elts->len; - pair->key = key; - if (!heap->frozen) - sift_up (heap, elts->len); - return pair; -} - -static void sift_down (GtsEHeap * heap, guint i) -{ - GtsEHeapPair * left_child, * right_child, * child, * parent; - guint lc, rc, c; - gpointer * pdata = heap->elts->pdata; - guint len = heap->elts->len; - gdouble key; - - lc = LEFT_CHILD (i); - rc = RIGHT_CHILD (i); - left_child = lc <= len ? pdata[lc - 1] : NULL; - right_child = rc <= len ? pdata[rc - 1] : NULL; - - parent = pdata[i - 1]; - key = parent->key; - while (left_child != NULL) { - if (right_child == NULL || left_child->key < right_child->key) { - child = left_child; - c = lc; - } - else { - child = right_child; - c = rc; - } - if (key > child->key) { - pdata[i - 1] = child; - child->pos = i; - pdata[c - 1] = parent; - parent->pos = c; - i = c; - lc = LEFT_CHILD (i); - rc = RIGHT_CHILD (i); - left_child = lc <= len ? pdata[lc - 1] : NULL; - right_child = rc <= len ? pdata[rc - 1] : NULL; - } - else - left_child = NULL; - } -} - -/** - * gts_eheap_remove_top: - * @heap: a #GtsEHeap. - * @key: a pointer on a gdouble or %NULL. - * - * Removes the element at the top of the heap and optionally (if @key is not - * %NULL) returns the value of its key. - * - * Returns: the element at the top of the heap. - */ -gpointer gts_eheap_remove_top (GtsEHeap * heap, gdouble * key) -{ - gpointer root; - GPtrArray * elts; - guint len; - GtsEHeapPair * pair; - - g_return_val_if_fail (heap != NULL, NULL); - - elts = heap->elts; - len = elts->len; - - if (len == 0) - return NULL; - if (len == 1) { - pair = g_ptr_array_remove_index (elts, 0); - root = pair->data; - if (key) - *key = pair->key; - g_free (pair); - return root; - } - - pair = elts->pdata[0]; - root = pair->data; - if (key) - *key = pair->key; - g_free (pair); - pair = g_ptr_array_remove_index (elts, len - 1); - elts->pdata[0] = pair; - pair->pos = 1; - sift_down (heap, 1); - return root; -} - -/** - * gts_eheap_top: - * @heap: a #GtsEHeap. - * @key: a pointer on a gdouble or %NULL. - * - * Returns: the element at the top of the heap and optionally (if @key is not - * %NULL) its key. - */ -gpointer gts_eheap_top (GtsEHeap * heap, gdouble * key) -{ - GtsEHeapPair * pair; - GPtrArray * elts; - - g_return_val_if_fail (heap != NULL, NULL); - - elts = heap->elts; - - if (elts->len == 0) - return NULL; - - pair = elts->pdata[0]; - if (key) - *key = pair->key; - return pair->data; -} - -/** - * gts_eheap_destroy: - * @heap: a #GtsEHeap. - * - * Free all the memory allocated for @heap. - */ -void gts_eheap_destroy (GtsEHeap * heap) -{ - guint i; - - g_return_if_fail (heap != NULL); - - for (i = 0; i < heap->elts->len; i++) - g_free (heap->elts->pdata[i]); - g_ptr_array_free (heap->elts, TRUE); - g_free (heap); -} - -/** - * gts_eheap_thaw: - * @heap: a #GtsEHeap. - * - * If @heap has been frozen previously using gts_eheap_freeze(), reorder it - * in O(n) time and unfreeze it. - */ -void gts_eheap_thaw (GtsEHeap * heap) -{ - guint i; - - g_return_if_fail (heap != NULL); - - if (!heap->frozen) - return; - - for (i = heap->elts->len/2; i > 0; i--) - sift_down (heap, i); - - heap->frozen = FALSE; -} - -/** - * gts_eheap_foreach: - * @heap: a #GtsEHeap. - * @func: the function to call for each element in the heap. - * @data: to pass to @func. - */ -void gts_eheap_foreach (GtsEHeap * heap, - GFunc func, - gpointer data) -{ - guint i; - GPtrArray * elts; - - g_return_if_fail (heap != NULL); - g_return_if_fail (func != NULL); - - elts = heap->elts; - for (i = 0; i < elts->len; i++) - (*func) (((GtsEHeapPair *) elts->pdata[i])->data, data); -} - -/** - * gts_eheap_remove: - * @heap: a #GtsEHeap. - * @p: a #GtsEHeapPair. - * - * Removes element corresponding to @p from @heap in O(log n). - * - * Returns: the element just removed from @heap. - */ -gpointer gts_eheap_remove (GtsEHeap * heap, GtsEHeapPair * p) -{ - GtsEHeapPair ** pdata; - GtsEHeapPair * parent; - guint i, par; - gpointer data; - - g_return_val_if_fail (heap != NULL, NULL); - g_return_val_if_fail (p != NULL, NULL); - - pdata = (GtsEHeapPair **)heap->elts->pdata; - i = p->pos; - data = p->data; - - g_return_val_if_fail (i > 0 && i <= heap->elts->len, NULL); - g_return_val_if_fail (p == pdata[i - 1], NULL); - - /* move element to the top */ - while ((par = PARENT (i))) { - parent = pdata[par - 1]; - pdata[par - 1] = p; - pdata[i - 1] = parent; - p->pos = par; - parent->pos = i; - i = par; - } - - gts_eheap_remove_top (heap, NULL); - - return data; -} - -/** - * gts_eheap_decrease_key: - * @heap: a #GtsEHeap. - * @p: a #GtsEHeapPair. - * @new_key: the new value of the key for this element. Must be smaller than - * the current key. - * - * Decreases the value of the key of the element at position @p. - */ -void gts_eheap_decrease_key (GtsEHeap * heap, - GtsEHeapPair * p, - gdouble new_key) -{ - guint i; - - g_return_if_fail (heap != NULL); - g_return_if_fail (p != NULL); - - i = p->pos; - g_return_if_fail (i > 0 && i <= heap->elts->len); - g_return_if_fail (p == heap->elts->pdata[i - 1]); - - g_return_if_fail (new_key <= p->key); - - p->key = new_key; - if (!heap->frozen) - sift_up (heap, i); -} - -/** - * gts_eheap_freeze: - * @heap: a #GtsEHeap. - * - * Freezes the heap. Any subsequent operation will not preserve the heap - * property. Used in conjunction with gts_eheap_insert() and gts_eheap_thaw() - * to create a heap in O(n) time. - */ -void gts_eheap_freeze (GtsEHeap * heap) -{ - g_return_if_fail (heap != NULL); - - heap->frozen = TRUE; -} - -/** - * gts_eheap_size: - * @heap: a #GtsEHeap. - * - * Returns: the number of items in @heap. - */ -guint gts_eheap_size (GtsEHeap * heap) -{ - g_return_val_if_fail (heap != NULL, 0); - - return heap->elts->len; -} - -/** - * gts_eheap_update: - * @heap: a #GtsEHeap. - * - * Updates the key of each element of @heap and reorders it. - */ -void gts_eheap_update (GtsEHeap * heap) -{ - guint i, len; - GtsEHeapPair ** pairs; - gpointer data; - GtsKeyFunc func; - - g_return_if_fail (heap != NULL); - g_return_if_fail (heap->func != NULL); - - heap->frozen = TRUE; - - len = heap->elts->len; - pairs = (GtsEHeapPair **) heap->elts->pdata; - data = heap->data; - func = heap->func; - - for (i = 0; i < len; i++) { - GtsEHeapPair * pair = pairs[i]; - pair->key = (*func) (pair->data, data); - } - - gts_eheap_thaw (heap); -} - -/** - * gts_eheap_key: - * @heap: a #GtsEHeap. - * @p: a pointer to be tested; - * - * Returns: the value of the key for pointer @p. - */ -gdouble gts_eheap_key (GtsEHeap * heap, gpointer p) -{ - g_return_val_if_fail (heap != NULL, 0.); - g_return_val_if_fail (heap->func != NULL, 0.); - - return (* heap->func) (p, heap->data); -} - -/** - * gts_eheap_randomized: - * @heap: a #GtsEHeap. - * @randomized: whether @heap should be randomized. - */ -void gts_eheap_randomized (GtsEHeap * heap, gboolean randomized) -{ - g_return_if_fail (heap != NULL); - - heap->randomized = randomized; -} Index: trunk/src_3rd/gts/fifo.c =================================================================== --- trunk/src_3rd/gts/fifo.c (revision 6802) +++ trunk/src_3rd/gts/fifo.c (nonexistent) @@ -1,192 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "gts.h" - -struct _GtsFifo { - GList * head; - GList * tail; -}; - -/** - * gts_fifo_new: - * - * Returns: a new #GtsFifo. - */ -GtsFifo * gts_fifo_new () -{ - GtsFifo * fifo = g_malloc (sizeof (GtsFifo)); - - fifo->head = fifo->tail = NULL; - return fifo; -} - -/** - * gts_fifo_write: - * @fifo: a #GtsFifo. - * @fp: a file pointer. - * - * Writes the content of @fifo in @fp. - */ -void gts_fifo_write (GtsFifo * fifo, FILE * fp) -{ - GList * i; - - g_return_if_fail (fifo != NULL); - g_return_if_fail (fp != NULL); - - fprintf (fp, "["); - i = fifo->head; - while (i) { - fprintf (fp, "%p ", i->data); - i = i->next; - } - fprintf (fp, "]"); -} - -/** - * gts_fifo_push: - * @fifo: a #GtsFifo. - * @data: data to add to @fifo. - * - * Push @data into @fifo. - */ -void gts_fifo_push (GtsFifo * fifo, gpointer data) -{ - g_return_if_fail (fifo != NULL); - - fifo->head = g_list_prepend (fifo->head, data); - if (fifo->tail == NULL) - fifo->tail = fifo->head; -} - -/** - * gts_fifo_pop: - * @fifo: a #GtsFifo. - * - * Removes the first element from @fifo. - * - * Returns: the first element in @fifo or %NULL if @fifo is empty. - */ -gpointer gts_fifo_pop (GtsFifo * fifo) -{ - gpointer data; - GList * tail; - - g_return_val_if_fail (fifo != NULL, NULL); - - if (fifo->tail == NULL) - return NULL; - tail = fifo->tail->prev; - data = fifo->tail->data; - fifo->head = g_list_remove_link (fifo->head, fifo->tail); - g_list_free_1 (fifo->tail); - fifo->tail = tail; - return data; -} - -/** - * gts_fifo_top: - * @fifo: a #GtsFifo. - * - * Returns: the first element in @fifo or %NULL if @fifo is empty. - */ -gpointer gts_fifo_top (GtsFifo * fifo) -{ - g_return_val_if_fail (fifo != NULL, NULL); - - if (fifo->tail == NULL) - return NULL; - return fifo->tail->data; -} - -/** - * gts_fifo_size: - * @fifo: a #GtsFifo. - * - * Returns: the number of elements in @fifo. - */ -guint gts_fifo_size (GtsFifo * fifo) -{ - g_return_val_if_fail (fifo != NULL, 0); - - return g_list_length (fifo->head); -} - -/** - * gts_fifo_destroy: - * @fifo: a #GtsFifo. - * - * Frees all the memory allocated for @fifo. - */ -void gts_fifo_destroy (GtsFifo * fifo) -{ - g_return_if_fail (fifo != NULL); - g_list_free (fifo->head); - g_free (fifo); -} - -/** - * gts_fifo_is_empty: - * @fifo: a #GtsFifo. - * - * Returns: %TRUE if @fifo is empty, %FALSE otherwise. - */ -gboolean gts_fifo_is_empty (GtsFifo * fifo) -{ - g_return_val_if_fail (fifo != NULL, TRUE); - - return (fifo->head == NULL); -} - -/** - * gts_fifo_foreach: - * @fifo: a #GtsFifo. - * @func: a #GtsFunc. - * @data: user data to be passed to @func. - * - * Calls @func in order for each item in @fifo, passing @data. - */ -void gts_fifo_foreach (GtsFifo * fifo, GtsFunc func, gpointer data) -{ - GList * i; - - g_return_if_fail (fifo != NULL); - g_return_if_fail (func != NULL); - - i = fifo->tail; - while (i) { - (* func) (i->data, data); - i = i->prev; - } -} - -/** - * gts_fifo_reverse: - * @fifo: a #GtsFifo. - * - * Reverses the order of elements in @fifo. - */ -void gts_fifo_reverse (GtsFifo * fifo) -{ - g_return_if_fail (fifo != NULL); - - fifo->tail = fifo->head; - fifo->head = g_list_reverse (fifo->head); -} Index: trunk/src_3rd/gts/predicates.c =================================================================== --- trunk/src_3rd/gts/predicates.c (revision 6802) +++ trunk/src_3rd/gts/predicates.c (nonexistent) @@ -1,2742 +0,0 @@ -/*****************************************************************************/ -/* */ -/* Routines for Arbitrary Precision Floating-point Arithmetic */ -/* and Fast Robust Geometric Predicates */ -/* (predicates.c) */ -/* */ -/* May 18, 1996 */ -/* */ -/* Placed in the public domain by */ -/* Jonathan Richard Shewchuk */ -/* School of Computer Science */ -/* Carnegie Mellon University */ -/* 5000 Forbes Avenue */ -/* Pittsburgh, Pennsylvania 15213-3891 */ -/* jrs@cs.cmu.edu */ -/* */ -/* This file contains C implementation of algorithms for exact addition */ -/* and multiplication of floating-point numbers, and predicates for */ -/* robustly performing the orientation and incircle tests used in */ -/* computational geometry. The algorithms and underlying theory are */ -/* described in Jonathan Richard Shewchuk. "Adaptive Precision Floating- */ -/* Point Arithmetic and Fast Robust Geometric Predicates." Technical */ -/* Report CMU-CS-96-140, School of Computer Science, Carnegie Mellon */ -/* University, Pittsburgh, Pennsylvania, May 1996. (Submitted to */ -/* Discrete & Computational Geometry.) */ -/* */ -/* This file, the paper listed above, and other information are available */ -/* from the Web page http://www.cs.cmu.edu/~quake/robust.html . */ -/* */ -/*****************************************************************************/ - -/*****************************************************************************/ -/* */ -/* Using this code: */ -/* */ -/* First, read the short or long version of the paper (from the Web page */ -/* above). */ -/* */ -/* Be sure to call exactinit() once, before calling any of the arithmetic */ -/* functions or geometric predicates. Also be sure to turn on the */ -/* optimizer when compiling this file. */ -/* */ -/* */ -/* Several geometric predicates are defined. Their parameters are all */ -/* points. Each point is an array of two or three floating-point */ -/* numbers. The geometric predicates, described in the papers, are */ -/* */ -/* orient2d(pa, pb, pc) */ -/* orient2dfast(pa, pb, pc) */ -/* orient3d(pa, pb, pc, pd) */ -/* orient3dfast(pa, pb, pc, pd) */ -/* incircle(pa, pb, pc, pd) */ -/* incirclefast(pa, pb, pc, pd) */ -/* insphere(pa, pb, pc, pd, pe) */ -/* inspherefast(pa, pb, pc, pd, pe) */ -/* */ -/* Those with suffix "fast" are approximate, non-robust versions. Those */ -/* without the suffix are adaptive precision, robust versions. There */ -/* are also versions with the suffices "exact" and "slow", which are */ -/* non-adaptive, exact arithmetic versions, which I use only for timings */ -/* in my arithmetic papers. */ -/* */ -/* */ -/* An expansion is represented by an array of floating-point numbers, */ -/* sorted from smallest to largest magnitude (possibly with interspersed */ -/* zeros). The length of each expansion is stored as a separate integer, */ -/* and each arithmetic function returns an integer which is the length */ -/* of the expansion it created. */ -/* */ -/* Several arithmetic functions are defined. Their parameters are */ -/* */ -/* e, f Input expansions */ -/* elen, flen Lengths of input expansions (must be >= 1) */ -/* h Output expansion */ -/* b Input scalar */ -/* */ -/* The arithmetic functions are */ -/* */ -/* grow_expansion(elen, e, b, h) */ -/* grow_expansion_zeroelim(elen, e, b, h) */ -/* expansion_sum(elen, e, flen, f, h) */ -/* expansion_sum_zeroelim1(elen, e, flen, f, h) */ -/* expansion_sum_zeroelim2(elen, e, flen, f, h) */ -/* fast_expansion_sum(elen, e, flen, f, h) */ -/* fast_expansion_sum_zeroelim(elen, e, flen, f, h) */ -/* linear_expansion_sum(elen, e, flen, f, h) */ -/* linear_expansion_sum_zeroelim(elen, e, flen, f, h) */ -/* scale_expansion(elen, e, b, h) */ -/* scale_expansion_zeroelim(elen, e, b, h) */ -/* compress(elen, e, h) */ -/* */ -/* All of these are described in the long version of the paper; some are */ -/* described in the short version. All return an integer that is the */ -/* length of h. Those with suffix _zeroelim perform zero elimination, */ -/* and are recommended over their counterparts. The procedure */ -/* fast_expansion_sum_zeroelim() (or linear_expansion_sum_zeroelim() on */ -/* processors that do not use the round-to-even tiebreaking rule) is */ -/* recommended over expansion_sum_zeroelim(). Each procedure has a */ -/* little note next to it (in the code below) that tells you whether or */ -/* not the output expansion may be the same array as one of the input */ -/* expansions. */ -/* */ -/* */ -/* If you look around below, you'll also find macros for a bunch of */ -/* simple unrolled arithmetic operations, and procedures for printing */ -/* expansions (commented out because they don't work with all C */ -/* compilers) and for generating random floating-point numbers whose */ -/* significand bits are all random. Most of the macros have undocumented */ -/* requirements that certain of their parameters should not be the same */ -/* variable; for safety, better to make sure all the parameters are */ -/* distinct variables. Feel free to send email to jrs@cs.cmu.edu if you */ -/* have questions. */ -/* */ -/*****************************************************************************/ - -#include -#include -#include -#include "predicates.h" - -/* Use header file generated automatically by predicates_init. */ -//#define USE_PREDICATES_INIT - -#ifdef USE_PREDICATES_INIT -#include "predicates_init.h" -#endif /* USE_PREDICATES_INIT */ - -/* FPU control. We MUST have only double precision (not extended precision) */ -#include "rounding.h" - -/* On some machines, the exact arithmetic routines might be defeated by the */ -/* use of internal extended precision floating-point registers. Sometimes */ -/* this problem can be fixed by defining certain values to be volatile, */ -/* thus forcing them to be stored to memory and rounded off. This isn't */ -/* a great solution, though, as it slows the arithmetic down. */ -/* */ -/* To try this out, write "#define INEXACT volatile" below. Normally, */ -/* however, INEXACT should be defined to be nothing. ("#define INEXACT".) */ - -#define INEXACT /* Nothing */ -/* #define INEXACT volatile */ - -#define REAL double /* float or double */ -#define REALPRINT doubleprint -#define REALRAND doublerand -#define NARROWRAND narrowdoublerand -#define UNIFORMRAND uniformdoublerand - -/* Which of the following two methods of finding the absolute values is */ -/* fastest is compiler-dependent. A few compilers can inline and optimize */ -/* the fabs() call; but most will incur the overhead of a function call, */ -/* which is disastrously slow. A faster way on IEEE machines might be to */ -/* mask the appropriate bit, but that's difficult to do in C. */ - -#define Absolute(a) ((a) >= 0.0 ? (a) : -(a)) -/* #define Absolute(a) fabs(a) */ - -/* Many of the operations are broken up into two pieces, a main part that */ -/* performs an approximate operation, and a "tail" that computes the */ -/* roundoff error of that operation. */ -/* */ -/* The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(), */ -/* Split(), and Two_Product() are all implemented as described in the */ -/* reference. Each of these macros requires certain variables to be */ -/* defined in the calling routine. The variables `bvirt', `c', `abig', */ -/* `_i', `_j', `_k', `_l', `_m', and `_n' are declared `INEXACT' because */ -/* they store the result of an operation that may incur roundoff error. */ -/* The input parameter `x' (or the highest numbered `x_' parameter) must */ -/* also be declared `INEXACT'. */ - -#define Fast_Two_Sum_Tail(a, b, x, y) \ - bvirt = x - a; \ - y = b - bvirt - -#define Fast_Two_Sum(a, b, x, y) \ - x = (REAL) (a + b); \ - Fast_Two_Sum_Tail(a, b, x, y) - -#define Fast_Two_Diff_Tail(a, b, x, y) \ - bvirt = a - x; \ - y = bvirt - b - -#define Fast_Two_Diff(a, b, x, y) \ - x = (REAL) (a - b); \ - Fast_Two_Diff_Tail(a, b, x, y) - -#define Two_Sum_Tail(a, b, x, y) \ - bvirt = (REAL) (x - a); \ - avirt = x - bvirt; \ - bround = b - bvirt; \ - around = a - avirt; \ - y = around + bround - -#define Two_Sum(a, b, x, y) \ - x = (REAL) (a + b); \ - Two_Sum_Tail(a, b, x, y) - -#define Two_Diff_Tail(a, b, x, y) \ - bvirt = (REAL) (a - x); \ - avirt = x + bvirt; \ - bround = bvirt - b; \ - around = a - avirt; \ - y = around + bround - -#define Two_Diff(a, b, x, y) \ - x = (REAL) (a - b); \ - Two_Diff_Tail(a, b, x, y) - -#define Split(a, ahi, alo) \ - c = (REAL) (splitter * a); \ - abig = (REAL) (c - a); \ - ahi = c - abig; \ - alo = a - ahi - -#define Two_Product_Tail(a, b, x, y) \ - Split(a, ahi, alo); \ - Split(b, bhi, blo); \ - err1 = x - (ahi * bhi); \ - err2 = err1 - (alo * bhi); \ - err3 = err2 - (ahi * blo); \ - y = (alo * blo) - err3 - -#define Two_Product(a, b, x, y) \ - x = (REAL) (a * b); \ - Two_Product_Tail(a, b, x, y) - -/* Two_Product_Presplit() is Two_Product() where one of the inputs has */ -/* already been split. Avoids redundant splitting. */ - -#define Two_Product_Presplit(a, b, bhi, blo, x, y) \ - x = (REAL) (a * b); \ - Split(a, ahi, alo); \ - err1 = x - (ahi * bhi); \ - err2 = err1 - (alo * bhi); \ - err3 = err2 - (ahi * blo); \ - y = (alo * blo) - err3 - -/* Two_Product_2Presplit() is Two_Product() where both of the inputs have */ -/* already been split. Avoids redundant splitting. */ - -#define Two_Product_2Presplit(a, ahi, alo, b, bhi, blo, x, y) \ - x = (REAL) (a * b); \ - err1 = x - (ahi * bhi); \ - err2 = err1 - (alo * bhi); \ - err3 = err2 - (ahi * blo); \ - y = (alo * blo) - err3 - -/* Square() can be done more quickly than Two_Product(). */ - -#define Square_Tail(a, x, y) \ - Split(a, ahi, alo); \ - err1 = x - (ahi * ahi); \ - err3 = err1 - ((ahi + ahi) * alo); \ - y = (alo * alo) - err3 - -#define Square(a, x, y) \ - x = (REAL) (a * a); \ - Square_Tail(a, x, y) - -/* Macros for summing expansions of various fixed lengths. These are all */ -/* unrolled versions of Expansion_Sum(). */ - -#define Two_One_Sum(a1, a0, b, x2, x1, x0) \ - Two_Sum(a0, b , _i, x0); \ - Two_Sum(a1, _i, x2, x1) - -#define Two_One_Diff(a1, a0, b, x2, x1, x0) \ - Two_Diff(a0, b , _i, x0); \ - Two_Sum( a1, _i, x2, x1) - -#define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \ - Two_One_Sum(a1, a0, b0, _j, _0, x0); \ - Two_One_Sum(_j, _0, b1, x3, x2, x1) - -#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \ - Two_One_Diff(a1, a0, b0, _j, _0, x0); \ - Two_One_Diff(_j, _0, b1, x3, x2, x1) - -#define Four_One_Sum(a3, a2, a1, a0, b, x4, x3, x2, x1, x0) \ - Two_One_Sum(a1, a0, b , _j, x1, x0); \ - Two_One_Sum(a3, a2, _j, x4, x3, x2) - -#define Four_Two_Sum(a3, a2, a1, a0, b1, b0, x5, x4, x3, x2, x1, x0) \ - Four_One_Sum(a3, a2, a1, a0, b0, _k, _2, _1, _0, x0); \ - Four_One_Sum(_k, _2, _1, _0, b1, x5, x4, x3, x2, x1) - -#define Four_Four_Sum(a3, a2, a1, a0, b4, b3, b1, b0, x7, x6, x5, x4, x3, x2, \ - x1, x0) \ - Four_Two_Sum(a3, a2, a1, a0, b1, b0, _l, _2, _1, _0, x1, x0); \ - Four_Two_Sum(_l, _2, _1, _0, b4, b3, x7, x6, x5, x4, x3, x2) - -#define Eight_One_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b, x8, x7, x6, x5, x4, \ - x3, x2, x1, x0) \ - Four_One_Sum(a3, a2, a1, a0, b , _j, x3, x2, x1, x0); \ - Four_One_Sum(a7, a6, a5, a4, _j, x8, x7, x6, x5, x4) - -#define Eight_Two_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0, x9, x8, x7, \ - x6, x5, x4, x3, x2, x1, x0) \ - Eight_One_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b0, _k, _6, _5, _4, _3, _2, \ - _1, _0, x0); \ - Eight_One_Sum(_k, _6, _5, _4, _3, _2, _1, _0, b1, x9, x8, x7, x6, x5, x4, \ - x3, x2, x1) - -#define Eight_Four_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b4, b3, b1, b0, x11, \ - x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0) \ - Eight_Two_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0, _l, _6, _5, _4, _3, \ - _2, _1, _0, x1, x0); \ - Eight_Two_Sum(_l, _6, _5, _4, _3, _2, _1, _0, b4, b3, x11, x10, x9, x8, \ - x7, x6, x5, x4, x3, x2) - -/* Macros for multiplying expansions of various fixed lengths. */ - -#define Two_One_Product(a1, a0, b, x3, x2, x1, x0) \ - Split(b, bhi, blo); \ - Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \ - Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \ - Two_Sum(_i, _0, _k, x1); \ - Fast_Two_Sum(_j, _k, x3, x2) - -#define Four_One_Product(a3, a2, a1, a0, b, x7, x6, x5, x4, x3, x2, x1, x0) \ - Split(b, bhi, blo); \ - Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \ - Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \ - Two_Sum(_i, _0, _k, x1); \ - Fast_Two_Sum(_j, _k, _i, x2); \ - Two_Product_Presplit(a2, b, bhi, blo, _j, _0); \ - Two_Sum(_i, _0, _k, x3); \ - Fast_Two_Sum(_j, _k, _i, x4); \ - Two_Product_Presplit(a3, b, bhi, blo, _j, _0); \ - Two_Sum(_i, _0, _k, x5); \ - Fast_Two_Sum(_j, _k, x7, x6) - -#define Two_Two_Product(a1, a0, b1, b0, x7, x6, x5, x4, x3, x2, x1, x0) \ - Split(a0, a0hi, a0lo); \ - Split(b0, bhi, blo); \ - Two_Product_2Presplit(a0, a0hi, a0lo, b0, bhi, blo, _i, x0); \ - Split(a1, a1hi, a1lo); \ - Two_Product_2Presplit(a1, a1hi, a1lo, b0, bhi, blo, _j, _0); \ - Two_Sum(_i, _0, _k, _1); \ - Fast_Two_Sum(_j, _k, _l, _2); \ - Split(b1, bhi, blo); \ - Two_Product_2Presplit(a0, a0hi, a0lo, b1, bhi, blo, _i, _0); \ - Two_Sum(_1, _0, _k, x1); \ - Two_Sum(_2, _k, _j, _1); \ - Two_Sum(_l, _j, _m, _2); \ - Two_Product_2Presplit(a1, a1hi, a1lo, b1, bhi, blo, _j, _0); \ - Two_Sum(_i, _0, _n, _0); \ - Two_Sum(_1, _0, _i, x2); \ - Two_Sum(_2, _i, _k, _1); \ - Two_Sum(_m, _k, _l, _2); \ - Two_Sum(_j, _n, _k, _0); \ - Two_Sum(_1, _0, _j, x3); \ - Two_Sum(_2, _j, _i, _1); \ - Two_Sum(_l, _i, _m, _2); \ - Two_Sum(_1, _k, _i, x4); \ - Two_Sum(_2, _i, _k, x5); \ - Two_Sum(_m, _k, x7, x6) - -/* An expansion of length two can be squared more quickly than finding the */ -/* product of two different expansions of length two, and the result is */ -/* guaranteed to have no more than six (rather than eight) components. */ - -#define Two_Square(a1, a0, x5, x4, x3, x2, x1, x0) \ - Square(a0, _j, x0); \ - _0 = a0 + a0; \ - Two_Product(a1, _0, _k, _1); \ - Two_One_Sum(_k, _1, _j, _l, _2, x1); \ - Square(a1, _j, _1); \ - Two_Two_Sum(_j, _1, _l, _2, x5, x4, x3, x2) - -#ifndef USE_PREDICATES_INIT - -static REAL splitter; /* = 2^ceiling(p / 2) + 1. Used to split floats in half. */ -/* A set of coefficients used to calculate maximum roundoff errors. */ -static REAL resulterrbound; -static REAL ccwerrboundA, ccwerrboundB, ccwerrboundC; -static REAL o3derrboundA, o3derrboundB, o3derrboundC; -static REAL iccerrboundA, iccerrboundB, iccerrboundC; -static REAL isperrboundA, isperrboundB, isperrboundC; - -void -gts_predicates_init() -{ - double half = 0.5; - double check = 1.0, lastcheck; - int every_other = 1; - /* epsilon = 2^(-p). Used to estimate roundoff errors. */ - double epsilon = 1.0; - - FPU_ROUND_DOUBLE; - - splitter = 1.; - - /* Repeatedly divide `epsilon' by two until it is too small to add to */ - /* one without causing roundoff. (Also check if the sum is equal to */ - /* the previous sum, for machines that round up instead of using exact */ - /* rounding. Not that this library will work on such machines anyway). */ - do { - lastcheck = check; - epsilon *= half; - if (every_other) { - splitter *= 2.0; - } - every_other = !every_other; - check = 1.0 + epsilon; - } while ((check != 1.0) && (check != lastcheck)); - splitter += 1.0; - /* Error bounds for orientation and incircle tests. */ - resulterrbound = (3.0 + 8.0 * epsilon) * epsilon; - ccwerrboundA = (3.0 + 16.0 * epsilon) * epsilon; - ccwerrboundB = (2.0 + 12.0 * epsilon) * epsilon; - ccwerrboundC = (9.0 + 64.0 * epsilon) * epsilon * epsilon; - o3derrboundA = (7.0 + 56.0 * epsilon) * epsilon; - o3derrboundB = (3.0 + 28.0 * epsilon) * epsilon; - o3derrboundC = (26.0 + 288.0 * epsilon) * epsilon * epsilon; - iccerrboundA = (10.0 + 96.0 * epsilon) * epsilon; - iccerrboundB = (4.0 + 48.0 * epsilon) * epsilon; - iccerrboundC = (44.0 + 576.0 * epsilon) * epsilon * epsilon; - isperrboundA = (16.0 + 224.0 * epsilon) * epsilon; - isperrboundB = (5.0 + 72.0 * epsilon) * epsilon; - isperrboundC = (71.0 + 1408.0 * epsilon) * epsilon * epsilon; - - - FPU_RESTORE; -} - -#endif /* USE_PREDICATES_INIT */ - -/*****************************************************************************/ -/* */ -/* doubleprint() Print the bit representation of a double. */ -/* */ -/* Useful for debugging exact arithmetic routines. */ -/* */ -/*****************************************************************************/ - -/* -void doubleprint(number) -double number; -{ - unsigned long long no; - unsigned long long sign, expo; - int exponent; - int i, bottomi; - - no = *(unsigned long long *) &number; - sign = no & 0x8000000000000000ll; - expo = (no >> 52) & 0x7ffll; - exponent = (int) expo; - exponent = exponent - 1023; - if (sign) { - printf("-"); - } else { - printf(" "); - } - if (exponent == -1023) { - printf( - "0.0000000000000000000000000000000000000000000000000000_ ( )"); - } else { - printf("1."); - bottomi = -1; - for (i = 0; i < 52; i++) { - if (no & 0x0008000000000000ll) { - printf("1"); - bottomi = i; - } else { - printf("0"); - } - no <<= 1; - } - printf("_%d (%d)", exponent, exponent - 1 - bottomi); - } -} -*/ - -/*****************************************************************************/ -/* */ -/* floatprint() Print the bit representation of a float. */ -/* */ -/* Useful for debugging exact arithmetic routines. */ -/* */ -/*****************************************************************************/ - -/* -void floatprint(number) -float number; -{ - unsigned no; - unsigned sign, expo; - int exponent; - int i, bottomi; - - no = *(unsigned *) &number; - sign = no & 0x80000000; - expo = (no >> 23) & 0xff; - exponent = (int) expo; - exponent = exponent - 127; - if (sign) { - printf("-"); - } else { - printf(" "); - } - if (exponent == -127) { - printf("0.00000000000000000000000_ ( )"); - } else { - printf("1."); - bottomi = -1; - for (i = 0; i < 23; i++) { - if (no & 0x00400000) { - printf("1"); - bottomi = i; - } else { - printf("0"); - } - no <<= 1; - } - printf("_%3d (%3d)", exponent, exponent - 1 - bottomi); - } -} -*/ - -/*****************************************************************************/ -/* */ -/* expansion_print() Print the bit representation of an expansion. */ -/* */ -/* Useful for debugging exact arithmetic routines. */ -/* */ -/*****************************************************************************/ - -/* -void expansion_print(elen, e) -int elen; -REAL *e; -{ - int i; - - for (i = elen - 1; i >= 0; i--) { - REALPRINT(e[i]); - if (i > 0) { - printf(" +\n"); - } else { - printf("\n"); - } - } -} -*/ - -/*****************************************************************************/ -/* */ -/* doublerand() Generate a double with random 53-bit significand and a */ -/* random exponent in [0, 511]. */ -/* */ -/*****************************************************************************/ - -/* -static double doublerand() -{ - double result; - double expo; - long a, b, c; - long i; - - a = random(); - b = random(); - c = random(); - result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8); - for (i = 512, expo = 2; i <= 131072; i *= 2, expo = expo * expo) { - if (c & i) { - result *= expo; - } - } - return result; -} -*/ - -/*****************************************************************************/ -/* */ -/* narrowdoublerand() Generate a double with random 53-bit significand */ -/* and a random exponent in [0, 7]. */ -/* */ -/*****************************************************************************/ - -/* -static double narrowdoublerand() -{ - double result; - double expo; - long a, b, c; - long i; - - a = random(); - b = random(); - c = random(); - result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8); - for (i = 512, expo = 2; i <= 2048; i *= 2, expo = expo * expo) { - if (c & i) { - result *= expo; - } - } - return result; -} -*/ - -/*****************************************************************************/ -/* */ -/* uniformdoublerand() Generate a double with random 53-bit significand. */ -/* */ -/*****************************************************************************/ - -/* -static double uniformdoublerand() -{ - double result; - long a, b; - - a = random(); - b = random(); - result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8); - return result; -} -*/ - -/*****************************************************************************/ -/* */ -/* floatrand() Generate a float with random 24-bit significand and a */ -/* random exponent in [0, 63]. */ -/* */ -/*****************************************************************************/ - -/* -static float floatrand() -{ - float result; - float expo; - long a, c; - long i; - - a = random(); - c = random(); - result = (float) ((a - 1073741824) >> 6); - for (i = 512, expo = 2; i <= 16384; i *= 2, expo = expo * expo) { - if (c & i) { - result *= expo; - } - } - return result; -} -*/ - -/*****************************************************************************/ -/* */ -/* narrowfloatrand() Generate a float with random 24-bit significand and */ -/* a random exponent in [0, 7]. */ -/* */ -/*****************************************************************************/ - -/* -static float narrowfloatrand() -{ - float result; - float expo; - long a, c; - long i; - - a = random(); - c = random(); - result = (float) ((a - 1073741824) >> 6); - for (i = 512, expo = 2; i <= 2048; i *= 2, expo = expo * expo) { - if (c & i) { - result *= expo; - } - } - return result; -} -*/ - -/*****************************************************************************/ -/* */ -/* uniformfloatrand() Generate a float with random 24-bit significand. */ -/* */ -/*****************************************************************************/ - -/* -static float uniformfloatrand() -{ - float result; - long a; - - a = random(); - result = (float) ((a - 1073741824) >> 6); - return result; -} -*/ - -/*****************************************************************************/ -/* */ -/* fast_expansion_sum_zeroelim() Sum two expansions, eliminating zero */ -/* components from the output expansion. */ -/* */ -/* Sets h = e + f. See the long version of my paper for details. */ -/* */ -/* If round-to-even is used (as with IEEE 754), maintains the strongly */ -/* nonoverlapping property. (That is, if e is strongly nonoverlapping, h */ -/* will be also.) Does NOT maintain the nonoverlapping or nonadjacent */ -/* properties. */ -/* */ -/*****************************************************************************/ - -static int fast_expansion_sum_zeroelim(int elen, REAL *e, - int flen, REAL *f, REAL *h) - /* h cannot be e or f. */ -{ - REAL Q; - INEXACT REAL Qnew; - INEXACT REAL hh; - INEXACT REAL bvirt; - REAL avirt, bround, around; - int eindex, findex, hindex; - REAL enow, fnow; - - enow = e[0]; - fnow = f[0]; - eindex = findex = 0; - if ((fnow > enow) == (fnow > -enow)) { - Q = enow; - enow = e[++eindex]; - } else { - Q = fnow; - fnow = f[++findex]; - } - hindex = 0; - if ((eindex < elen) && (findex < flen)) { - if ((fnow > enow) == (fnow > -enow)) { - Fast_Two_Sum(enow, Q, Qnew, hh); - enow = e[++eindex]; - } else { - Fast_Two_Sum(fnow, Q, Qnew, hh); - fnow = f[++findex]; - } - Q = Qnew; - if (hh != 0.0) { - h[hindex++] = hh; - } - while ((eindex < elen) && (findex < flen)) { - if ((fnow > enow) == (fnow > -enow)) { - Two_Sum(Q, enow, Qnew, hh); - enow = e[++eindex]; - } else { - Two_Sum(Q, fnow, Qnew, hh); - fnow = f[++findex]; - } - Q = Qnew; - if (hh != 0.0) { - h[hindex++] = hh; - } - } - } - while (eindex < elen) { - Two_Sum(Q, enow, Qnew, hh); - enow = e[++eindex]; - Q = Qnew; - if (hh != 0.0) { - h[hindex++] = hh; - } - } - while (findex < flen) { - Two_Sum(Q, fnow, Qnew, hh); - fnow = f[++findex]; - Q = Qnew; - if (hh != 0.0) { - h[hindex++] = hh; - } - } - if ((Q != 0.0) || (hindex == 0)) { - h[hindex++] = Q; - } - return hindex; -} - -/*****************************************************************************/ -/* */ -/* scale_expansion_zeroelim() Multiply an expansion by a scalar, */ -/* eliminating zero components from the */ -/* output expansion. */ -/* */ -/* Sets h = be. See either version of my paper for details. */ -/* */ -/* Maintains the nonoverlapping property. If round-to-even is used (as */ -/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ -/* properties as well. (That is, if e has one of these properties, so */ -/* will h.) */ -/* */ -/*****************************************************************************/ - -static int scale_expansion_zeroelim(int elen, REAL *e, REAL b, REAL *h) - /* e and h cannot be the same. */ -{ - INEXACT REAL Q, sum; - REAL hh; - INEXACT REAL product1; - REAL product0; - int eindex, hindex; - REAL enow; - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - - Split(b, bhi, blo); - Two_Product_Presplit(e[0], b, bhi, blo, Q, hh); - hindex = 0; - if (hh != 0) { - h[hindex++] = hh; - } - for (eindex = 1; eindex < elen; eindex++) { - enow = e[eindex]; - Two_Product_Presplit(enow, b, bhi, blo, product1, product0); - Two_Sum(Q, product0, sum, hh); - if (hh != 0) { - h[hindex++] = hh; - } - Fast_Two_Sum(product1, sum, Q, hh); - if (hh != 0) { - h[hindex++] = hh; - } - } - if ((Q != 0.0) || (hindex == 0)) { - h[hindex++] = Q; - } - return hindex; -} - -/*****************************************************************************/ -/* */ -/* estimate() Produce a one-word estimate of an expansion's value. */ -/* */ -/* See either version of my paper for details. */ -/* */ -/*****************************************************************************/ - -static REAL estimate(int elen, REAL *e) -{ - REAL Q; - int eindex; - - Q = e[0]; - for (eindex = 1; eindex < elen; eindex++) { - Q += e[eindex]; - } - return Q; -} - -/*****************************************************************************/ -/* */ -/* orient2dfast() Approximate 2D orientation test. Nonrobust. */ -/* orient2dexact() Exact 2D orientation test. Robust. */ -/* orient2dslow() Another exact 2D orientation test. Robust. */ -/* orient2d() Adaptive exact 2D orientation test. Robust. */ -/* */ -/* Return a positive value if the points pa, pb, and pc occur */ -/* in counterclockwise order; a negative value if they occur */ -/* in clockwise order; and zero if they are collinear. The */ -/* result is also a rough approximation of twice the signed */ -/* area of the triangle defined by the three points. */ -/* */ -/* Only the first and last routine should be used; the middle two are for */ -/* timings. */ -/* */ -/* The last three use exact arithmetic to ensure a correct answer. The */ -/* result returned is the determinant of a matrix. In orient2d() only, */ -/* this determinant is computed adaptively, in the sense that exact */ -/* arithmetic is used only to the degree it is needed to ensure that the */ -/* returned value has the correct sign. Hence, orient2d() is usually quite */ -/* fast, but will run more slowly when the input points are collinear or */ -/* nearly so. */ -/* */ -/*****************************************************************************/ - -static REAL orient2dadapt(REAL *pa, REAL *pb, REAL *pc, REAL detsum) -{ - INEXACT REAL acx, acy, bcx, bcy; - REAL acxtail, acytail, bcxtail, bcytail; - INEXACT REAL detleft, detright; - REAL detlefttail, detrighttail; - REAL det, errbound; - REAL B[4], C1[8], C2[12], D[16]; - INEXACT REAL B3; - int C1length, C2length, Dlength; - REAL u[4]; - INEXACT REAL u3; - INEXACT REAL s1, t1; - REAL s0, t0; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j; - REAL _0; - - acx = (REAL) (pa[0] - pc[0]); - bcx = (REAL) (pb[0] - pc[0]); - acy = (REAL) (pa[1] - pc[1]); - bcy = (REAL) (pb[1] - pc[1]); - - Two_Product(acx, bcy, detleft, detlefttail); - Two_Product(acy, bcx, detright, detrighttail); - - Two_Two_Diff(detleft, detlefttail, detright, detrighttail, - B3, B[2], B[1], B[0]); - B[3] = B3; - - det = estimate(4, B); - errbound = ccwerrboundB * detsum; - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - Two_Diff_Tail(pa[0], pc[0], acx, acxtail); - Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail); - Two_Diff_Tail(pa[1], pc[1], acy, acytail); - Two_Diff_Tail(pb[1], pc[1], bcy, bcytail); - - if ((acxtail == 0.0) && (acytail == 0.0) - && (bcxtail == 0.0) && (bcytail == 0.0)) { - return det; - } - - errbound = ccwerrboundC * detsum + resulterrbound * Absolute(det); - det += (acx * bcytail + bcy * acxtail) - - (acy * bcxtail + bcx * acytail); - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - Two_Product(acxtail, bcy, s1, s0); - Two_Product(acytail, bcx, t1, t0); - Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); - u[3] = u3; - C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1); - - Two_Product(acx, bcytail, s1, s0); - Two_Product(acy, bcxtail, t1, t0); - Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); - u[3] = u3; - C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2); - - Two_Product(acxtail, bcytail, s1, s0); - Two_Product(acytail, bcxtail, t1, t0); - Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); - u[3] = u3; - Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D); - - return(D[Dlength - 1]); -} - -REAL orient2d(pa, pb, pc) -REAL *pa; -REAL *pb; -REAL *pc; -{ - REAL detleft, detright, det; - REAL detsum, errbound; - REAL orient; - - FPU_ROUND_DOUBLE; - - detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]); - detright = (pa[1] - pc[1]) * (pb[0] - pc[0]); - det = detleft - detright; - - if (detleft > 0.0) { - if (detright <= 0.0) { - FPU_RESTORE; - return det; - } else { - detsum = detleft + detright; - } - } else if (detleft < 0.0) { - if (detright >= 0.0) { - FPU_RESTORE; - return det; - } else { - detsum = -detleft - detright; - } - } else { - FPU_RESTORE; - return det; - } - - errbound = ccwerrboundA * detsum; - if ((det >= errbound) || (-det >= errbound)) { - FPU_RESTORE; - return det; - } - - orient = orient2dadapt(pa, pb, pc, detsum); - FPU_RESTORE; - return orient; -} - -/*****************************************************************************/ -/* */ -/* orient3dfast() Approximate 3D orientation test. Nonrobust. */ -/* orient3dexact() Exact 3D orientation test. Robust. */ -/* orient3dslow() Another exact 3D orientation test. Robust. */ -/* orient3d() Adaptive exact 3D orientation test. Robust. */ -/* */ -/* Return a positive value if the point pd lies below the */ -/* plane passing through pa, pb, and pc; "below" is defined so */ -/* that pa, pb, and pc appear in counterclockwise order when */ -/* viewed from above the plane. Returns a negative value if */ -/* pd lies above the plane. Returns zero if the points are */ -/* coplanar. The result is also a rough approximation of six */ -/* times the signed volume of the tetrahedron defined by the */ -/* four points. */ -/* */ -/* Only the first and last routine should be used; the middle two are for */ -/* timings. */ -/* */ -/* The last three use exact arithmetic to ensure a correct answer. The */ -/* result returned is the determinant of a matrix. In orient3d() only, */ -/* this determinant is computed adaptively, in the sense that exact */ -/* arithmetic is used only to the degree it is needed to ensure that the */ -/* returned value has the correct sign. Hence, orient3d() is usually quite */ -/* fast, but will run more slowly when the input points are coplanar or */ -/* nearly so. */ -/* */ -/*****************************************************************************/ - -static REAL orient3dadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, - REAL permanent) -{ - INEXACT REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz; - REAL det, errbound; - - INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; - REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; - REAL bc[4], ca[4], ab[4]; - INEXACT REAL bc3, ca3, ab3; - REAL adet[8], bdet[8], cdet[8]; - int alen, blen, clen; - REAL abdet[16]; - int ablen; - REAL *finnow, *finother, *finswap; - REAL fin1[192], fin2[192]; - int finlength; - - REAL adxtail, bdxtail, cdxtail; - REAL adytail, bdytail, cdytail; - REAL adztail, bdztail, cdztail; - INEXACT REAL at_blarge, at_clarge; - INEXACT REAL bt_clarge, bt_alarge; - INEXACT REAL ct_alarge, ct_blarge; - REAL at_b[4], at_c[4], bt_c[4], bt_a[4], ct_a[4], ct_b[4]; - int at_blen, at_clen, bt_clen, bt_alen, ct_alen, ct_blen; - INEXACT REAL bdxt_cdy1, cdxt_bdy1, cdxt_ady1; - INEXACT REAL adxt_cdy1, adxt_bdy1, bdxt_ady1; - REAL bdxt_cdy0, cdxt_bdy0, cdxt_ady0; - REAL adxt_cdy0, adxt_bdy0, bdxt_ady0; - INEXACT REAL bdyt_cdx1, cdyt_bdx1, cdyt_adx1; - INEXACT REAL adyt_cdx1, adyt_bdx1, bdyt_adx1; - REAL bdyt_cdx0, cdyt_bdx0, cdyt_adx0; - REAL adyt_cdx0, adyt_bdx0, bdyt_adx0; - REAL bct[8], cat[8], abt[8]; - int bctlen, catlen, abtlen; - INEXACT REAL bdxt_cdyt1, cdxt_bdyt1, cdxt_adyt1; - INEXACT REAL adxt_cdyt1, adxt_bdyt1, bdxt_adyt1; - REAL bdxt_cdyt0, cdxt_bdyt0, cdxt_adyt0; - REAL adxt_cdyt0, adxt_bdyt0, bdxt_adyt0; - REAL u[4], v[12], w[16]; - INEXACT REAL u3; - int vlength, wlength; - REAL negate; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j, _k; - REAL _0; - - adx = (REAL) (pa[0] - pd[0]); - bdx = (REAL) (pb[0] - pd[0]); - cdx = (REAL) (pc[0] - pd[0]); - ady = (REAL) (pa[1] - pd[1]); - bdy = (REAL) (pb[1] - pd[1]); - cdy = (REAL) (pc[1] - pd[1]); - adz = (REAL) (pa[2] - pd[2]); - bdz = (REAL) (pb[2] - pd[2]); - cdz = (REAL) (pc[2] - pd[2]); - - Two_Product(bdx, cdy, bdxcdy1, bdxcdy0); - Two_Product(cdx, bdy, cdxbdy1, cdxbdy0); - Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]); - bc[3] = bc3; - alen = scale_expansion_zeroelim(4, bc, adz, adet); - - Two_Product(cdx, ady, cdxady1, cdxady0); - Two_Product(adx, cdy, adxcdy1, adxcdy0); - Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]); - ca[3] = ca3; - blen = scale_expansion_zeroelim(4, ca, bdz, bdet); - - Two_Product(adx, bdy, adxbdy1, adxbdy0); - Two_Product(bdx, ady, bdxady1, bdxady0); - Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]); - ab[3] = ab3; - clen = scale_expansion_zeroelim(4, ab, cdz, cdet); - - ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); - finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1); - - det = estimate(finlength, fin1); - errbound = o3derrboundB * permanent; - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - Two_Diff_Tail(pa[0], pd[0], adx, adxtail); - Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); - Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); - Two_Diff_Tail(pa[1], pd[1], ady, adytail); - Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); - Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); - Two_Diff_Tail(pa[2], pd[2], adz, adztail); - Two_Diff_Tail(pb[2], pd[2], bdz, bdztail); - Two_Diff_Tail(pc[2], pd[2], cdz, cdztail); - - if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) - && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0) - && (adztail == 0.0) && (bdztail == 0.0) && (cdztail == 0.0)) { - return det; - } - - errbound = o3derrboundC * permanent + resulterrbound * Absolute(det); - det += (adz * ((bdx * cdytail + cdy * bdxtail) - - (bdy * cdxtail + cdx * bdytail)) - + adztail * (bdx * cdy - bdy * cdx)) - + (bdz * ((cdx * adytail + ady * cdxtail) - - (cdy * adxtail + adx * cdytail)) - + bdztail * (cdx * ady - cdy * adx)) - + (cdz * ((adx * bdytail + bdy * adxtail) - - (ady * bdxtail + bdx * adytail)) - + cdztail * (adx * bdy - ady * bdx)); - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - finnow = fin1; - finother = fin2; - - if (adxtail == 0.0) { - if (adytail == 0.0) { - at_b[0] = 0.0; - at_blen = 1; - at_c[0] = 0.0; - at_clen = 1; - } else { - negate = -adytail; - Two_Product(negate, bdx, at_blarge, at_b[0]); - at_b[1] = at_blarge; - at_blen = 2; - Two_Product(adytail, cdx, at_clarge, at_c[0]); - at_c[1] = at_clarge; - at_clen = 2; - } - } else { - if (adytail == 0.0) { - Two_Product(adxtail, bdy, at_blarge, at_b[0]); - at_b[1] = at_blarge; - at_blen = 2; - negate = -adxtail; - Two_Product(negate, cdy, at_clarge, at_c[0]); - at_c[1] = at_clarge; - at_clen = 2; - } else { - Two_Product(adxtail, bdy, adxt_bdy1, adxt_bdy0); - Two_Product(adytail, bdx, adyt_bdx1, adyt_bdx0); - Two_Two_Diff(adxt_bdy1, adxt_bdy0, adyt_bdx1, adyt_bdx0, - at_blarge, at_b[2], at_b[1], at_b[0]); - at_b[3] = at_blarge; - at_blen = 4; - Two_Product(adytail, cdx, adyt_cdx1, adyt_cdx0); - Two_Product(adxtail, cdy, adxt_cdy1, adxt_cdy0); - Two_Two_Diff(adyt_cdx1, adyt_cdx0, adxt_cdy1, adxt_cdy0, - at_clarge, at_c[2], at_c[1], at_c[0]); - at_c[3] = at_clarge; - at_clen = 4; - } - } - if (bdxtail == 0.0) { - if (bdytail == 0.0) { - bt_c[0] = 0.0; - bt_clen = 1; - bt_a[0] = 0.0; - bt_alen = 1; - } else { - negate = -bdytail; - Two_Product(negate, cdx, bt_clarge, bt_c[0]); - bt_c[1] = bt_clarge; - bt_clen = 2; - Two_Product(bdytail, adx, bt_alarge, bt_a[0]); - bt_a[1] = bt_alarge; - bt_alen = 2; - } - } else { - if (bdytail == 0.0) { - Two_Product(bdxtail, cdy, bt_clarge, bt_c[0]); - bt_c[1] = bt_clarge; - bt_clen = 2; - negate = -bdxtail; - Two_Product(negate, ady, bt_alarge, bt_a[0]); - bt_a[1] = bt_alarge; - bt_alen = 2; - } else { - Two_Product(bdxtail, cdy, bdxt_cdy1, bdxt_cdy0); - Two_Product(bdytail, cdx, bdyt_cdx1, bdyt_cdx0); - Two_Two_Diff(bdxt_cdy1, bdxt_cdy0, bdyt_cdx1, bdyt_cdx0, - bt_clarge, bt_c[2], bt_c[1], bt_c[0]); - bt_c[3] = bt_clarge; - bt_clen = 4; - Two_Product(bdytail, adx, bdyt_adx1, bdyt_adx0); - Two_Product(bdxtail, ady, bdxt_ady1, bdxt_ady0); - Two_Two_Diff(bdyt_adx1, bdyt_adx0, bdxt_ady1, bdxt_ady0, - bt_alarge, bt_a[2], bt_a[1], bt_a[0]); - bt_a[3] = bt_alarge; - bt_alen = 4; - } - } - if (cdxtail == 0.0) { - if (cdytail == 0.0) { - ct_a[0] = 0.0; - ct_alen = 1; - ct_b[0] = 0.0; - ct_blen = 1; - } else { - negate = -cdytail; - Two_Product(negate, adx, ct_alarge, ct_a[0]); - ct_a[1] = ct_alarge; - ct_alen = 2; - Two_Product(cdytail, bdx, ct_blarge, ct_b[0]); - ct_b[1] = ct_blarge; - ct_blen = 2; - } - } else { - if (cdytail == 0.0) { - Two_Product(cdxtail, ady, ct_alarge, ct_a[0]); - ct_a[1] = ct_alarge; - ct_alen = 2; - negate = -cdxtail; - Two_Product(negate, bdy, ct_blarge, ct_b[0]); - ct_b[1] = ct_blarge; - ct_blen = 2; - } else { - Two_Product(cdxtail, ady, cdxt_ady1, cdxt_ady0); - Two_Product(cdytail, adx, cdyt_adx1, cdyt_adx0); - Two_Two_Diff(cdxt_ady1, cdxt_ady0, cdyt_adx1, cdyt_adx0, - ct_alarge, ct_a[2], ct_a[1], ct_a[0]); - ct_a[3] = ct_alarge; - ct_alen = 4; - Two_Product(cdytail, bdx, cdyt_bdx1, cdyt_bdx0); - Two_Product(cdxtail, bdy, cdxt_bdy1, cdxt_bdy0); - Two_Two_Diff(cdyt_bdx1, cdyt_bdx0, cdxt_bdy1, cdxt_bdy0, - ct_blarge, ct_b[2], ct_b[1], ct_b[0]); - ct_b[3] = ct_blarge; - ct_blen = 4; - } - } - - bctlen = fast_expansion_sum_zeroelim(bt_clen, bt_c, ct_blen, ct_b, bct); - wlength = scale_expansion_zeroelim(bctlen, bct, adz, w); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, - finother); - finswap = finnow; finnow = finother; finother = finswap; - - catlen = fast_expansion_sum_zeroelim(ct_alen, ct_a, at_clen, at_c, cat); - wlength = scale_expansion_zeroelim(catlen, cat, bdz, w); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, - finother); - finswap = finnow; finnow = finother; finother = finswap; - - abtlen = fast_expansion_sum_zeroelim(at_blen, at_b, bt_alen, bt_a, abt); - wlength = scale_expansion_zeroelim(abtlen, abt, cdz, w); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, - finother); - finswap = finnow; finnow = finother; finother = finswap; - - if (adztail != 0.0) { - vlength = scale_expansion_zeroelim(4, bc, adztail, v); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (bdztail != 0.0) { - vlength = scale_expansion_zeroelim(4, ca, bdztail, v); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (cdztail != 0.0) { - vlength = scale_expansion_zeroelim(4, ab, cdztail, v); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - - if (adxtail != 0.0) { - if (bdytail != 0.0) { - Two_Product(adxtail, bdytail, adxt_bdyt1, adxt_bdyt0); - Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdz, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - if (cdztail != 0.0) { - Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdztail, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - if (cdytail != 0.0) { - negate = -adxtail; - Two_Product(negate, cdytail, adxt_cdyt1, adxt_cdyt0); - Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdz, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - if (bdztail != 0.0) { - Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdztail, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - } - if (bdxtail != 0.0) { - if (cdytail != 0.0) { - Two_Product(bdxtail, cdytail, bdxt_cdyt1, bdxt_cdyt0); - Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adz, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - if (adztail != 0.0) { - Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adztail, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - if (adytail != 0.0) { - negate = -bdxtail; - Two_Product(negate, adytail, bdxt_adyt1, bdxt_adyt0); - Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdz, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - if (cdztail != 0.0) { - Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdztail, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - } - if (cdxtail != 0.0) { - if (adytail != 0.0) { - Two_Product(cdxtail, adytail, cdxt_adyt1, cdxt_adyt0); - Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdz, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - if (bdztail != 0.0) { - Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdztail, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - if (bdytail != 0.0) { - negate = -cdxtail; - Two_Product(negate, bdytail, cdxt_bdyt1, cdxt_bdyt0); - Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adz, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - if (adztail != 0.0) { - Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adztail, u3, u[2], u[1], u[0]); - u[3] = u3; - finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - } - - if (adztail != 0.0) { - wlength = scale_expansion_zeroelim(bctlen, bct, adztail, w); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (bdztail != 0.0) { - wlength = scale_expansion_zeroelim(catlen, cat, bdztail, w); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (cdztail != 0.0) { - wlength = scale_expansion_zeroelim(abtlen, abt, cdztail, w); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, - finother); - finswap = finnow; finnow = finother; finother = finswap; - } - - return finnow[finlength - 1]; -} - -REAL orient3d(pa, pb, pc, pd) -REAL *pa; -REAL *pb; -REAL *pc; -REAL *pd; -{ - REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz; - REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; - REAL det; - REAL permanent, errbound; - REAL orient; - - FPU_ROUND_DOUBLE; - - adx = pa[0] - pd[0]; - bdx = pb[0] - pd[0]; - cdx = pc[0] - pd[0]; - ady = pa[1] - pd[1]; - bdy = pb[1] - pd[1]; - cdy = pc[1] - pd[1]; - adz = pa[2] - pd[2]; - bdz = pb[2] - pd[2]; - cdz = pc[2] - pd[2]; - - bdxcdy = bdx * cdy; - cdxbdy = cdx * bdy; - - cdxady = cdx * ady; - adxcdy = adx * cdy; - - adxbdy = adx * bdy; - bdxady = bdx * ady; - - det = adz * (bdxcdy - cdxbdy) - + bdz * (cdxady - adxcdy) - + cdz * (adxbdy - bdxady); - - permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * Absolute(adz) - + (Absolute(cdxady) + Absolute(adxcdy)) * Absolute(bdz) - + (Absolute(adxbdy) + Absolute(bdxady)) * Absolute(cdz); - errbound = o3derrboundA * permanent; - if ((det > errbound) || (-det > errbound)) { - FPU_RESTORE; - return det; - } - - orient = orient3dadapt(pa, pb, pc, pd, permanent); - FPU_RESTORE; - return orient; -} - -/*****************************************************************************/ -/* */ -/* incirclefast() Approximate 2D incircle test. Nonrobust. */ -/* incircleexact() Exact 2D incircle test. Robust. */ -/* incircleslow() Another exact 2D incircle test. Robust. */ -/* incircle() Adaptive exact 2D incircle test. Robust. */ -/* */ -/* Return a positive value if the point pd lies inside the */ -/* circle passing through pa, pb, and pc; a negative value if */ -/* it lies outside; and zero if the four points are cocircular.*/ -/* The points pa, pb, and pc must be in counterclockwise */ -/* order, or the sign of the result will be reversed. */ -/* */ -/* Only the first and last routine should be used; the middle two are for */ -/* timings. */ -/* */ -/* The last three use exact arithmetic to ensure a correct answer. The */ -/* result returned is the determinant of a matrix. In incircle() only, */ -/* this determinant is computed adaptively, in the sense that exact */ -/* arithmetic is used only to the degree it is needed to ensure that the */ -/* returned value has the correct sign. Hence, incircle() is usually quite */ -/* fast, but will run more slowly when the input points are cocircular or */ -/* nearly so. */ -/* */ -/*****************************************************************************/ - -static REAL incircleadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, - REAL permanent) -{ - INEXACT REAL adx, bdx, cdx, ady, bdy, cdy; - REAL det, errbound; - - INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; - REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; - REAL bc[4], ca[4], ab[4]; - INEXACT REAL bc3, ca3, ab3; - REAL axbc[8], axxbc[16], aybc[8], ayybc[16], adet[32]; - int axbclen, axxbclen, aybclen, ayybclen, alen; - REAL bxca[8], bxxca[16], byca[8], byyca[16], bdet[32]; - int bxcalen, bxxcalen, bycalen, byycalen, blen; - REAL cxab[8], cxxab[16], cyab[8], cyyab[16], cdet[32]; - int cxablen, cxxablen, cyablen, cyyablen, clen; - REAL abdet[64]; - int ablen; - REAL fin1[1152], fin2[1152]; - REAL *finnow, *finother, *finswap; - int finlength; - - REAL adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail; - INEXACT REAL adxadx1, adyady1, bdxbdx1, bdybdy1, cdxcdx1, cdycdy1; - REAL adxadx0, adyady0, bdxbdx0, bdybdy0, cdxcdx0, cdycdy0; - REAL aa[4], bb[4], cc[4]; - INEXACT REAL aa3, bb3, cc3; - INEXACT REAL ti1, tj1; - REAL ti0, tj0; - REAL u[4], v[4]; - INEXACT REAL u3, v3; - REAL temp8[8], temp16a[16], temp16b[16], temp16c[16]; - REAL temp32a[32], temp32b[32], temp48[48], temp64[64]; - int temp8len, temp16alen, temp16blen, temp16clen; - int temp32alen, temp32blen, temp48len, temp64len; - REAL axtbb[8], axtcc[8], aytbb[8], aytcc[8]; - int axtbblen, axtcclen, aytbblen, aytcclen; - REAL bxtaa[8], bxtcc[8], bytaa[8], bytcc[8]; - int bxtaalen, bxtcclen, bytaalen, bytcclen; - REAL cxtaa[8], cxtbb[8], cytaa[8], cytbb[8]; - int cxtaalen, cxtbblen, cytaalen, cytbblen; - REAL axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8]; - int axtbclen = 0, aytbclen = 0; - int bxtcalen = 0, bytcalen = 0; - int cxtablen = 0, cytablen = 0; - REAL axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16]; - int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen; - REAL axtbctt[8], aytbctt[8], bxtcatt[8]; - REAL bytcatt[8], cxtabtt[8], cytabtt[8]; - int axtbcttlen, aytbcttlen, bxtcattlen, bytcattlen, cxtabttlen, cytabttlen; - REAL abt[8], bct[8], cat[8]; - int abtlen, bctlen, catlen; - REAL abtt[4], bctt[4], catt[4]; - int abttlen, bcttlen, cattlen; - INEXACT REAL abtt3, bctt3, catt3; - REAL negate; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j; - REAL _0; - - adx = (REAL) (pa[0] - pd[0]); - bdx = (REAL) (pb[0] - pd[0]); - cdx = (REAL) (pc[0] - pd[0]); - ady = (REAL) (pa[1] - pd[1]); - bdy = (REAL) (pb[1] - pd[1]); - cdy = (REAL) (pc[1] - pd[1]); - - Two_Product(bdx, cdy, bdxcdy1, bdxcdy0); - Two_Product(cdx, bdy, cdxbdy1, cdxbdy0); - Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]); - bc[3] = bc3; - axbclen = scale_expansion_zeroelim(4, bc, adx, axbc); - axxbclen = scale_expansion_zeroelim(axbclen, axbc, adx, axxbc); - aybclen = scale_expansion_zeroelim(4, bc, ady, aybc); - ayybclen = scale_expansion_zeroelim(aybclen, aybc, ady, ayybc); - alen = fast_expansion_sum_zeroelim(axxbclen, axxbc, ayybclen, ayybc, adet); - - Two_Product(cdx, ady, cdxady1, cdxady0); - Two_Product(adx, cdy, adxcdy1, adxcdy0); - Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]); - ca[3] = ca3; - bxcalen = scale_expansion_zeroelim(4, ca, bdx, bxca); - bxxcalen = scale_expansion_zeroelim(bxcalen, bxca, bdx, bxxca); - bycalen = scale_expansion_zeroelim(4, ca, bdy, byca); - byycalen = scale_expansion_zeroelim(bycalen, byca, bdy, byyca); - blen = fast_expansion_sum_zeroelim(bxxcalen, bxxca, byycalen, byyca, bdet); - - Two_Product(adx, bdy, adxbdy1, adxbdy0); - Two_Product(bdx, ady, bdxady1, bdxady0); - Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]); - ab[3] = ab3; - cxablen = scale_expansion_zeroelim(4, ab, cdx, cxab); - cxxablen = scale_expansion_zeroelim(cxablen, cxab, cdx, cxxab); - cyablen = scale_expansion_zeroelim(4, ab, cdy, cyab); - cyyablen = scale_expansion_zeroelim(cyablen, cyab, cdy, cyyab); - clen = fast_expansion_sum_zeroelim(cxxablen, cxxab, cyyablen, cyyab, cdet); - - ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); - finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1); - - det = estimate(finlength, fin1); - errbound = iccerrboundB * permanent; - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - Two_Diff_Tail(pa[0], pd[0], adx, adxtail); - Two_Diff_Tail(pa[1], pd[1], ady, adytail); - Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); - Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); - Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); - Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); - if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) - && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0)) { - return det; - } - - errbound = iccerrboundC * permanent + resulterrbound * Absolute(det); - det += ((adx * adx + ady * ady) * ((bdx * cdytail + cdy * bdxtail) - - (bdy * cdxtail + cdx * bdytail)) - + 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx)) - + ((bdx * bdx + bdy * bdy) * ((cdx * adytail + ady * cdxtail) - - (cdy * adxtail + adx * cdytail)) - + 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx)) - + ((cdx * cdx + cdy * cdy) * ((adx * bdytail + bdy * adxtail) - - (ady * bdxtail + bdx * adytail)) - + 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx)); - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - finnow = fin1; - finother = fin2; - - if ((bdxtail != 0.0) || (bdytail != 0.0) - || (cdxtail != 0.0) || (cdytail != 0.0)) { - Square(adx, adxadx1, adxadx0); - Square(ady, adyady1, adyady0); - Two_Two_Sum(adxadx1, adxadx0, adyady1, adyady0, aa3, aa[2], aa[1], aa[0]); - aa[3] = aa3; - } - if ((cdxtail != 0.0) || (cdytail != 0.0) - || (adxtail != 0.0) || (adytail != 0.0)) { - Square(bdx, bdxbdx1, bdxbdx0); - Square(bdy, bdybdy1, bdybdy0); - Two_Two_Sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0, bb3, bb[2], bb[1], bb[0]); - bb[3] = bb3; - } - if ((adxtail != 0.0) || (adytail != 0.0) - || (bdxtail != 0.0) || (bdytail != 0.0)) { - Square(cdx, cdxcdx1, cdxcdx0); - Square(cdy, cdycdy1, cdycdy0); - Two_Two_Sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0, cc3, cc[2], cc[1], cc[0]); - cc[3] = cc3; - } - - if (adxtail != 0.0) { - axtbclen = scale_expansion_zeroelim(4, bc, adxtail, axtbc); - temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, 2.0 * adx, - temp16a); - - axtcclen = scale_expansion_zeroelim(4, cc, adxtail, axtcc); - temp16blen = scale_expansion_zeroelim(axtcclen, axtcc, bdy, temp16b); - - axtbblen = scale_expansion_zeroelim(4, bb, adxtail, axtbb); - temp16clen = scale_expansion_zeroelim(axtbblen, axtbb, -cdy, temp16c); - - temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (adytail != 0.0) { - aytbclen = scale_expansion_zeroelim(4, bc, adytail, aytbc); - temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, 2.0 * ady, - temp16a); - - aytbblen = scale_expansion_zeroelim(4, bb, adytail, aytbb); - temp16blen = scale_expansion_zeroelim(aytbblen, aytbb, cdx, temp16b); - - aytcclen = scale_expansion_zeroelim(4, cc, adytail, aytcc); - temp16clen = scale_expansion_zeroelim(aytcclen, aytcc, -bdx, temp16c); - - temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (bdxtail != 0.0) { - bxtcalen = scale_expansion_zeroelim(4, ca, bdxtail, bxtca); - temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, 2.0 * bdx, - temp16a); - - bxtaalen = scale_expansion_zeroelim(4, aa, bdxtail, bxtaa); - temp16blen = scale_expansion_zeroelim(bxtaalen, bxtaa, cdy, temp16b); - - bxtcclen = scale_expansion_zeroelim(4, cc, bdxtail, bxtcc); - temp16clen = scale_expansion_zeroelim(bxtcclen, bxtcc, -ady, temp16c); - - temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (bdytail != 0.0) { - bytcalen = scale_expansion_zeroelim(4, ca, bdytail, bytca); - temp16alen = scale_expansion_zeroelim(bytcalen, bytca, 2.0 * bdy, - temp16a); - - bytcclen = scale_expansion_zeroelim(4, cc, bdytail, bytcc); - temp16blen = scale_expansion_zeroelim(bytcclen, bytcc, adx, temp16b); - - bytaalen = scale_expansion_zeroelim(4, aa, bdytail, bytaa); - temp16clen = scale_expansion_zeroelim(bytaalen, bytaa, -cdx, temp16c); - - temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (cdxtail != 0.0) { - cxtablen = scale_expansion_zeroelim(4, ab, cdxtail, cxtab); - temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, 2.0 * cdx, - temp16a); - - cxtbblen = scale_expansion_zeroelim(4, bb, cdxtail, cxtbb); - temp16blen = scale_expansion_zeroelim(cxtbblen, cxtbb, ady, temp16b); - - cxtaalen = scale_expansion_zeroelim(4, aa, cdxtail, cxtaa); - temp16clen = scale_expansion_zeroelim(cxtaalen, cxtaa, -bdy, temp16c); - - temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (cdytail != 0.0) { - cytablen = scale_expansion_zeroelim(4, ab, cdytail, cytab); - temp16alen = scale_expansion_zeroelim(cytablen, cytab, 2.0 * cdy, - temp16a); - - cytaalen = scale_expansion_zeroelim(4, aa, cdytail, cytaa); - temp16blen = scale_expansion_zeroelim(cytaalen, cytaa, bdx, temp16b); - - cytbblen = scale_expansion_zeroelim(4, bb, cdytail, cytbb); - temp16clen = scale_expansion_zeroelim(cytbblen, cytbb, -adx, temp16c); - - temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - - if ((adxtail != 0.0) || (adytail != 0.0)) { - if ((bdxtail != 0.0) || (bdytail != 0.0) - || (cdxtail != 0.0) || (cdytail != 0.0)) { - Two_Product(bdxtail, cdy, ti1, ti0); - Two_Product(bdx, cdytail, tj1, tj0); - Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); - u[3] = u3; - negate = -bdy; - Two_Product(cdxtail, negate, ti1, ti0); - negate = -bdytail; - Two_Product(cdx, negate, tj1, tj0); - Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); - v[3] = v3; - bctlen = fast_expansion_sum_zeroelim(4, u, 4, v, bct); - - Two_Product(bdxtail, cdytail, ti1, ti0); - Two_Product(cdxtail, bdytail, tj1, tj0); - Two_Two_Diff(ti1, ti0, tj1, tj0, bctt3, bctt[2], bctt[1], bctt[0]); - bctt[3] = bctt3; - bcttlen = 4; - } else { - bct[0] = 0.0; - bctlen = 1; - bctt[0] = 0.0; - bcttlen = 1; - } - - if (adxtail != 0.0) { - temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, adxtail, temp16a); - axtbctlen = scale_expansion_zeroelim(bctlen, bct, adxtail, axtbct); - temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, 2.0 * adx, - temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - if (bdytail != 0.0) { - temp8len = scale_expansion_zeroelim(4, cc, adxtail, temp8); - temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, - temp16a); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, - temp16a, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (cdytail != 0.0) { - temp8len = scale_expansion_zeroelim(4, bb, -adxtail, temp8); - temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, - temp16a); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, - temp16a, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - - temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, adxtail, - temp32a); - axtbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adxtail, axtbctt); - temp16alen = scale_expansion_zeroelim(axtbcttlen, axtbctt, 2.0 * adx, - temp16a); - temp16blen = scale_expansion_zeroelim(axtbcttlen, axtbctt, adxtail, - temp16b); - temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32b); - temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, - temp64, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (adytail != 0.0) { - temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, adytail, temp16a); - aytbctlen = scale_expansion_zeroelim(bctlen, bct, adytail, aytbct); - temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, 2.0 * ady, - temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - - - temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, adytail, - temp32a); - aytbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adytail, aytbctt); - temp16alen = scale_expansion_zeroelim(aytbcttlen, aytbctt, 2.0 * ady, - temp16a); - temp16blen = scale_expansion_zeroelim(aytbcttlen, aytbctt, adytail, - temp16b); - temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32b); - temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, - temp64, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - if ((bdxtail != 0.0) || (bdytail != 0.0)) { - if ((cdxtail != 0.0) || (cdytail != 0.0) - || (adxtail != 0.0) || (adytail != 0.0)) { - Two_Product(cdxtail, ady, ti1, ti0); - Two_Product(cdx, adytail, tj1, tj0); - Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); - u[3] = u3; - negate = -cdy; - Two_Product(adxtail, negate, ti1, ti0); - negate = -cdytail; - Two_Product(adx, negate, tj1, tj0); - Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); - v[3] = v3; - catlen = fast_expansion_sum_zeroelim(4, u, 4, v, cat); - - Two_Product(cdxtail, adytail, ti1, ti0); - Two_Product(adxtail, cdytail, tj1, tj0); - Two_Two_Diff(ti1, ti0, tj1, tj0, catt3, catt[2], catt[1], catt[0]); - catt[3] = catt3; - cattlen = 4; - } else { - cat[0] = 0.0; - catlen = 1; - catt[0] = 0.0; - cattlen = 1; - } - - if (bdxtail != 0.0) { - temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, bdxtail, temp16a); - bxtcatlen = scale_expansion_zeroelim(catlen, cat, bdxtail, bxtcat); - temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, 2.0 * bdx, - temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - if (cdytail != 0.0) { - temp8len = scale_expansion_zeroelim(4, aa, bdxtail, temp8); - temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, - temp16a); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, - temp16a, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (adytail != 0.0) { - temp8len = scale_expansion_zeroelim(4, cc, -bdxtail, temp8); - temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, - temp16a); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, - temp16a, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - - temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, bdxtail, - temp32a); - bxtcattlen = scale_expansion_zeroelim(cattlen, catt, bdxtail, bxtcatt); - temp16alen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, 2.0 * bdx, - temp16a); - temp16blen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, bdxtail, - temp16b); - temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32b); - temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, - temp64, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (bdytail != 0.0) { - temp16alen = scale_expansion_zeroelim(bytcalen, bytca, bdytail, temp16a); - bytcatlen = scale_expansion_zeroelim(catlen, cat, bdytail, bytcat); - temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, 2.0 * bdy, - temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - - - temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, bdytail, - temp32a); - bytcattlen = scale_expansion_zeroelim(cattlen, catt, bdytail, bytcatt); - temp16alen = scale_expansion_zeroelim(bytcattlen, bytcatt, 2.0 * bdy, - temp16a); - temp16blen = scale_expansion_zeroelim(bytcattlen, bytcatt, bdytail, - temp16b); - temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32b); - temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, - temp64, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - if ((cdxtail != 0.0) || (cdytail != 0.0)) { - if ((adxtail != 0.0) || (adytail != 0.0) - || (bdxtail != 0.0) || (bdytail != 0.0)) { - Two_Product(adxtail, bdy, ti1, ti0); - Two_Product(adx, bdytail, tj1, tj0); - Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); - u[3] = u3; - negate = -ady; - Two_Product(bdxtail, negate, ti1, ti0); - negate = -adytail; - Two_Product(bdx, negate, tj1, tj0); - Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); - v[3] = v3; - abtlen = fast_expansion_sum_zeroelim(4, u, 4, v, abt); - - Two_Product(adxtail, bdytail, ti1, ti0); - Two_Product(bdxtail, adytail, tj1, tj0); - Two_Two_Diff(ti1, ti0, tj1, tj0, abtt3, abtt[2], abtt[1], abtt[0]); - abtt[3] = abtt3; - abttlen = 4; - } else { - abt[0] = 0.0; - abtlen = 1; - abtt[0] = 0.0; - abttlen = 1; - } - - if (cdxtail != 0.0) { - temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, cdxtail, temp16a); - cxtabtlen = scale_expansion_zeroelim(abtlen, abt, cdxtail, cxtabt); - temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, 2.0 * cdx, - temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - if (adytail != 0.0) { - temp8len = scale_expansion_zeroelim(4, bb, cdxtail, temp8); - temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, - temp16a); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, - temp16a, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (bdytail != 0.0) { - temp8len = scale_expansion_zeroelim(4, aa, -cdxtail, temp8); - temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, - temp16a); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, - temp16a, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - - temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, cdxtail, - temp32a); - cxtabttlen = scale_expansion_zeroelim(abttlen, abtt, cdxtail, cxtabtt); - temp16alen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, 2.0 * cdx, - temp16a); - temp16blen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, cdxtail, - temp16b); - temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32b); - temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, - temp64, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - if (cdytail != 0.0) { - temp16alen = scale_expansion_zeroelim(cytablen, cytab, cdytail, temp16a); - cytabtlen = scale_expansion_zeroelim(abtlen, abt, cdytail, cytabt); - temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, 2.0 * cdy, - temp32a); - temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp32alen, temp32a, temp48); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, - temp48, finother); - finswap = finnow; finnow = finother; finother = finswap; - - - temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, cdytail, - temp32a); - cytabttlen = scale_expansion_zeroelim(abttlen, abtt, cdytail, cytabtt); - temp16alen = scale_expansion_zeroelim(cytabttlen, cytabtt, 2.0 * cdy, - temp16a); - temp16blen = scale_expansion_zeroelim(cytabttlen, cytabtt, cdytail, - temp16b); - temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, - temp16blen, temp16b, temp32b); - temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, - temp32blen, temp32b, temp64); - finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, - temp64, finother); - finswap = finnow; finnow = finother; finother = finswap; - } - } - - return finnow[finlength - 1]; -} - -REAL incircle(pa, pb, pc, pd) -REAL *pa; -REAL *pb; -REAL *pc; -REAL *pd; -{ - REAL adx, bdx, cdx, ady, bdy, cdy; - REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; - REAL alift, blift, clift; - REAL det; - REAL permanent, errbound; - REAL inc; - - FPU_ROUND_DOUBLE; - - adx = pa[0] - pd[0]; - bdx = pb[0] - pd[0]; - cdx = pc[0] - pd[0]; - ady = pa[1] - pd[1]; - bdy = pb[1] - pd[1]; - cdy = pc[1] - pd[1]; - - bdxcdy = bdx * cdy; - cdxbdy = cdx * bdy; - alift = adx * adx + ady * ady; - - cdxady = cdx * ady; - adxcdy = adx * cdy; - blift = bdx * bdx + bdy * bdy; - - adxbdy = adx * bdy; - bdxady = bdx * ady; - clift = cdx * cdx + cdy * cdy; - - det = alift * (bdxcdy - cdxbdy) - + blift * (cdxady - adxcdy) - + clift * (adxbdy - bdxady); - - permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift - + (Absolute(cdxady) + Absolute(adxcdy)) * blift - + (Absolute(adxbdy) + Absolute(bdxady)) * clift; - errbound = iccerrboundA * permanent; - if ((det > errbound) || (-det > errbound)) { - FPU_RESTORE; - return det; - } - - inc = incircleadapt(pa, pb, pc, pd, permanent); - FPU_RESTORE; - return inc; -} - -/*****************************************************************************/ -/* */ -/* inspherefast() Approximate 3D insphere test. Nonrobust. */ -/* insphereexact() Exact 3D insphere test. Robust. */ -/* insphereslow() Another exact 3D insphere test. Robust. */ -/* insphere() Adaptive exact 3D insphere test. Robust. */ -/* */ -/* Return a positive value if the point pe lies inside the */ -/* sphere passing through pa, pb, pc, and pd; a negative value */ -/* if it lies outside; and zero if the five points are */ -/* cospherical. The points pa, pb, pc, and pd must be ordered */ -/* so that they have a positive orientation (as defined by */ -/* orient3d()), or the sign of the result will be reversed. */ -/* */ -/* Only the first and last routine should be used; the middle two are for */ -/* timings. */ -/* */ -/* The last three use exact arithmetic to ensure a correct answer. The */ -/* result returned is the determinant of a matrix. In insphere() only, */ -/* this determinant is computed adaptively, in the sense that exact */ -/* arithmetic is used only to the degree it is needed to ensure that the */ -/* returned value has the correct sign. Hence, insphere() is usually quite */ -/* fast, but will run more slowly when the input points are cospherical or */ -/* nearly so. */ -/* */ -/*****************************************************************************/ - -static REAL insphereexact(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) -{ - INEXACT REAL axby1, bxcy1, cxdy1, dxey1, exay1; - INEXACT REAL bxay1, cxby1, dxcy1, exdy1, axey1; - INEXACT REAL axcy1, bxdy1, cxey1, dxay1, exby1; - INEXACT REAL cxay1, dxby1, excy1, axdy1, bxey1; - REAL axby0, bxcy0, cxdy0, dxey0, exay0; - REAL bxay0, cxby0, dxcy0, exdy0, axey0; - REAL axcy0, bxdy0, cxey0, dxay0, exby0; - REAL cxay0, dxby0, excy0, axdy0, bxey0; - REAL ab[4], bc[4], cd[4], de[4], ea[4]; - REAL ac[4], bd[4], ce[4], da[4], eb[4]; - REAL temp8a[8], temp8b[8], temp16[16]; - int temp8alen, temp8blen, temp16len; - REAL abc[24], bcd[24], cde[24], dea[24], eab[24]; - REAL abd[24], bce[24], cda[24], deb[24], eac[24]; - int abclen, bcdlen, cdelen, dealen, eablen; - int abdlen, bcelen, cdalen, deblen, eaclen; - REAL temp48a[48], temp48b[48]; - int temp48alen, temp48blen; - REAL abcd[96], bcde[96], cdea[96], deab[96], eabc[96]; - int abcdlen, bcdelen, cdealen, deablen, eabclen; - REAL temp192[192]; - REAL det384x[384], det384y[384], det384z[384]; - int xlen, ylen, zlen; - REAL detxy[768]; - int xylen; - REAL adet[1152], bdet[1152], cdet[1152], ddet[1152], edet[1152]; - int alen, blen, clen, dlen, elen; - REAL abdet[2304], cddet[2304], cdedet[3456]; - int ablen, cdlen; - REAL deter[5760]; - int deterlen; - int i; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j; - REAL _0; - - Two_Product(pa[0], pb[1], axby1, axby0); - Two_Product(pb[0], pa[1], bxay1, bxay0); - Two_Two_Diff(axby1, axby0, bxay1, bxay0, ab[3], ab[2], ab[1], ab[0]); - - Two_Product(pb[0], pc[1], bxcy1, bxcy0); - Two_Product(pc[0], pb[1], cxby1, cxby0); - Two_Two_Diff(bxcy1, bxcy0, cxby1, cxby0, bc[3], bc[2], bc[1], bc[0]); - - Two_Product(pc[0], pd[1], cxdy1, cxdy0); - Two_Product(pd[0], pc[1], dxcy1, dxcy0); - Two_Two_Diff(cxdy1, cxdy0, dxcy1, dxcy0, cd[3], cd[2], cd[1], cd[0]); - - Two_Product(pd[0], pe[1], dxey1, dxey0); - Two_Product(pe[0], pd[1], exdy1, exdy0); - Two_Two_Diff(dxey1, dxey0, exdy1, exdy0, de[3], de[2], de[1], de[0]); - - Two_Product(pe[0], pa[1], exay1, exay0); - Two_Product(pa[0], pe[1], axey1, axey0); - Two_Two_Diff(exay1, exay0, axey1, axey0, ea[3], ea[2], ea[1], ea[0]); - - Two_Product(pa[0], pc[1], axcy1, axcy0); - Two_Product(pc[0], pa[1], cxay1, cxay0); - Two_Two_Diff(axcy1, axcy0, cxay1, cxay0, ac[3], ac[2], ac[1], ac[0]); - - Two_Product(pb[0], pd[1], bxdy1, bxdy0); - Two_Product(pd[0], pb[1], dxby1, dxby0); - Two_Two_Diff(bxdy1, bxdy0, dxby1, dxby0, bd[3], bd[2], bd[1], bd[0]); - - Two_Product(pc[0], pe[1], cxey1, cxey0); - Two_Product(pe[0], pc[1], excy1, excy0); - Two_Two_Diff(cxey1, cxey0, excy1, excy0, ce[3], ce[2], ce[1], ce[0]); - - Two_Product(pd[0], pa[1], dxay1, dxay0); - Two_Product(pa[0], pd[1], axdy1, axdy0); - Two_Two_Diff(dxay1, dxay0, axdy1, axdy0, da[3], da[2], da[1], da[0]); - - Two_Product(pe[0], pb[1], exby1, exby0); - Two_Product(pb[0], pe[1], bxey1, bxey0); - Two_Two_Diff(exby1, exby0, bxey1, bxey0, eb[3], eb[2], eb[1], eb[0]); - - temp8alen = scale_expansion_zeroelim(4, bc, pa[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, ac, -pb[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, ab, pc[2], temp8a); - abclen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - abc); - - temp8alen = scale_expansion_zeroelim(4, cd, pb[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, bd, -pc[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, bc, pd[2], temp8a); - bcdlen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - bcd); - - temp8alen = scale_expansion_zeroelim(4, de, pc[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, ce, -pd[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, cd, pe[2], temp8a); - cdelen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - cde); - - temp8alen = scale_expansion_zeroelim(4, ea, pd[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, da, -pe[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, de, pa[2], temp8a); - dealen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - dea); - - temp8alen = scale_expansion_zeroelim(4, ab, pe[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, eb, -pa[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, ea, pb[2], temp8a); - eablen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - eab); - - temp8alen = scale_expansion_zeroelim(4, bd, pa[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, da, pb[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, ab, pd[2], temp8a); - abdlen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - abd); - - temp8alen = scale_expansion_zeroelim(4, ce, pb[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, eb, pc[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, bc, pe[2], temp8a); - bcelen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - bce); - - temp8alen = scale_expansion_zeroelim(4, da, pc[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, ac, pd[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, cd, pa[2], temp8a); - cdalen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - cda); - - temp8alen = scale_expansion_zeroelim(4, eb, pd[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, bd, pe[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, de, pb[2], temp8a); - deblen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - deb); - - temp8alen = scale_expansion_zeroelim(4, ac, pe[2], temp8a); - temp8blen = scale_expansion_zeroelim(4, ce, pa[2], temp8b); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, - temp16); - temp8alen = scale_expansion_zeroelim(4, ea, pc[2], temp8a); - eaclen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, - eac); - - temp48alen = fast_expansion_sum_zeroelim(cdelen, cde, bcelen, bce, temp48a); - temp48blen = fast_expansion_sum_zeroelim(deblen, deb, bcdlen, bcd, temp48b); - for (i = 0; i < temp48blen; i++) { - temp48b[i] = -temp48b[i]; - } - bcdelen = fast_expansion_sum_zeroelim(temp48alen, temp48a, - temp48blen, temp48b, bcde); - xlen = scale_expansion_zeroelim(bcdelen, bcde, pa[0], temp192); - xlen = scale_expansion_zeroelim(xlen, temp192, pa[0], det384x); - ylen = scale_expansion_zeroelim(bcdelen, bcde, pa[1], temp192); - ylen = scale_expansion_zeroelim(ylen, temp192, pa[1], det384y); - zlen = scale_expansion_zeroelim(bcdelen, bcde, pa[2], temp192); - zlen = scale_expansion_zeroelim(zlen, temp192, pa[2], det384z); - xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); - alen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, adet); - - temp48alen = fast_expansion_sum_zeroelim(dealen, dea, cdalen, cda, temp48a); - temp48blen = fast_expansion_sum_zeroelim(eaclen, eac, cdelen, cde, temp48b); - for (i = 0; i < temp48blen; i++) { - temp48b[i] = -temp48b[i]; - } - cdealen = fast_expansion_sum_zeroelim(temp48alen, temp48a, - temp48blen, temp48b, cdea); - xlen = scale_expansion_zeroelim(cdealen, cdea, pb[0], temp192); - xlen = scale_expansion_zeroelim(xlen, temp192, pb[0], det384x); - ylen = scale_expansion_zeroelim(cdealen, cdea, pb[1], temp192); - ylen = scale_expansion_zeroelim(ylen, temp192, pb[1], det384y); - zlen = scale_expansion_zeroelim(cdealen, cdea, pb[2], temp192); - zlen = scale_expansion_zeroelim(zlen, temp192, pb[2], det384z); - xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); - blen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, bdet); - - temp48alen = fast_expansion_sum_zeroelim(eablen, eab, deblen, deb, temp48a); - temp48blen = fast_expansion_sum_zeroelim(abdlen, abd, dealen, dea, temp48b); - for (i = 0; i < temp48blen; i++) { - temp48b[i] = -temp48b[i]; - } - deablen = fast_expansion_sum_zeroelim(temp48alen, temp48a, - temp48blen, temp48b, deab); - xlen = scale_expansion_zeroelim(deablen, deab, pc[0], temp192); - xlen = scale_expansion_zeroelim(xlen, temp192, pc[0], det384x); - ylen = scale_expansion_zeroelim(deablen, deab, pc[1], temp192); - ylen = scale_expansion_zeroelim(ylen, temp192, pc[1], det384y); - zlen = scale_expansion_zeroelim(deablen, deab, pc[2], temp192); - zlen = scale_expansion_zeroelim(zlen, temp192, pc[2], det384z); - xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); - clen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, cdet); - - temp48alen = fast_expansion_sum_zeroelim(abclen, abc, eaclen, eac, temp48a); - temp48blen = fast_expansion_sum_zeroelim(bcelen, bce, eablen, eab, temp48b); - for (i = 0; i < temp48blen; i++) { - temp48b[i] = -temp48b[i]; - } - eabclen = fast_expansion_sum_zeroelim(temp48alen, temp48a, - temp48blen, temp48b, eabc); - xlen = scale_expansion_zeroelim(eabclen, eabc, pd[0], temp192); - xlen = scale_expansion_zeroelim(xlen, temp192, pd[0], det384x); - ylen = scale_expansion_zeroelim(eabclen, eabc, pd[1], temp192); - ylen = scale_expansion_zeroelim(ylen, temp192, pd[1], det384y); - zlen = scale_expansion_zeroelim(eabclen, eabc, pd[2], temp192); - zlen = scale_expansion_zeroelim(zlen, temp192, pd[2], det384z); - xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); - dlen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, ddet); - - temp48alen = fast_expansion_sum_zeroelim(bcdlen, bcd, abdlen, abd, temp48a); - temp48blen = fast_expansion_sum_zeroelim(cdalen, cda, abclen, abc, temp48b); - for (i = 0; i < temp48blen; i++) { - temp48b[i] = -temp48b[i]; - } - abcdlen = fast_expansion_sum_zeroelim(temp48alen, temp48a, - temp48blen, temp48b, abcd); - xlen = scale_expansion_zeroelim(abcdlen, abcd, pe[0], temp192); - xlen = scale_expansion_zeroelim(xlen, temp192, pe[0], det384x); - ylen = scale_expansion_zeroelim(abcdlen, abcd, pe[1], temp192); - ylen = scale_expansion_zeroelim(ylen, temp192, pe[1], det384y); - zlen = scale_expansion_zeroelim(abcdlen, abcd, pe[2], temp192); - zlen = scale_expansion_zeroelim(zlen, temp192, pe[2], det384z); - xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); - elen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, edet); - - ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); - cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); - cdelen = fast_expansion_sum_zeroelim(cdlen, cddet, elen, edet, cdedet); - deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdelen, cdedet, deter); - - return deter[deterlen - 1]; -} - -static REAL insphereadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe, - REAL permanent) -{ - INEXACT REAL aex, bex, cex, dex, aey, bey, cey, dey, aez, bez, cez, dez; - REAL det, errbound; - - INEXACT REAL aexbey1, bexaey1, bexcey1, cexbey1; - INEXACT REAL cexdey1, dexcey1, dexaey1, aexdey1; - INEXACT REAL aexcey1, cexaey1, bexdey1, dexbey1; - REAL aexbey0, bexaey0, bexcey0, cexbey0; - REAL cexdey0, dexcey0, dexaey0, aexdey0; - REAL aexcey0, cexaey0, bexdey0, dexbey0; - REAL ab[4], bc[4], cd[4], da[4], ac[4], bd[4]; - INEXACT REAL ab3, bc3, cd3, da3, ac3, bd3; - REAL abeps, bceps, cdeps, daeps, aceps, bdeps; - REAL temp8a[8], temp8b[8], temp8c[8], temp16[16], temp24[24], temp48[48]; - int temp8alen, temp8blen, temp8clen, temp16len, temp24len, temp48len; - REAL xdet[96], ydet[96], zdet[96], xydet[192]; - int xlen, ylen, zlen, xylen; - REAL adet[288], bdet[288], cdet[288], ddet[288]; - int alen, blen, clen, dlen; - REAL abdet[576], cddet[576]; - int ablen, cdlen; - REAL fin1[1152]; - int finlength; - - REAL aextail, bextail, cextail, dextail; - REAL aeytail, beytail, ceytail, deytail; - REAL aeztail, beztail, ceztail, deztail; - - INEXACT REAL bvirt; - REAL avirt, bround, around; - INEXACT REAL c; - INEXACT REAL abig; - REAL ahi, alo, bhi, blo; - REAL err1, err2, err3; - INEXACT REAL _i, _j; - REAL _0; - - aex = (REAL) (pa[0] - pe[0]); - bex = (REAL) (pb[0] - pe[0]); - cex = (REAL) (pc[0] - pe[0]); - dex = (REAL) (pd[0] - pe[0]); - aey = (REAL) (pa[1] - pe[1]); - bey = (REAL) (pb[1] - pe[1]); - cey = (REAL) (pc[1] - pe[1]); - dey = (REAL) (pd[1] - pe[1]); - aez = (REAL) (pa[2] - pe[2]); - bez = (REAL) (pb[2] - pe[2]); - cez = (REAL) (pc[2] - pe[2]); - dez = (REAL) (pd[2] - pe[2]); - - Two_Product(aex, bey, aexbey1, aexbey0); - Two_Product(bex, aey, bexaey1, bexaey0); - Two_Two_Diff(aexbey1, aexbey0, bexaey1, bexaey0, ab3, ab[2], ab[1], ab[0]); - ab[3] = ab3; - - Two_Product(bex, cey, bexcey1, bexcey0); - Two_Product(cex, bey, cexbey1, cexbey0); - Two_Two_Diff(bexcey1, bexcey0, cexbey1, cexbey0, bc3, bc[2], bc[1], bc[0]); - bc[3] = bc3; - - Two_Product(cex, dey, cexdey1, cexdey0); - Two_Product(dex, cey, dexcey1, dexcey0); - Two_Two_Diff(cexdey1, cexdey0, dexcey1, dexcey0, cd3, cd[2], cd[1], cd[0]); - cd[3] = cd3; - - Two_Product(dex, aey, dexaey1, dexaey0); - Two_Product(aex, dey, aexdey1, aexdey0); - Two_Two_Diff(dexaey1, dexaey0, aexdey1, aexdey0, da3, da[2], da[1], da[0]); - da[3] = da3; - - Two_Product(aex, cey, aexcey1, aexcey0); - Two_Product(cex, aey, cexaey1, cexaey0); - Two_Two_Diff(aexcey1, aexcey0, cexaey1, cexaey0, ac3, ac[2], ac[1], ac[0]); - ac[3] = ac3; - - Two_Product(bex, dey, bexdey1, bexdey0); - Two_Product(dex, bey, dexbey1, dexbey0); - Two_Two_Diff(bexdey1, bexdey0, dexbey1, dexbey0, bd3, bd[2], bd[1], bd[0]); - bd[3] = bd3; - - temp8alen = scale_expansion_zeroelim(4, cd, bez, temp8a); - temp8blen = scale_expansion_zeroelim(4, bd, -cez, temp8b); - temp8clen = scale_expansion_zeroelim(4, bc, dez, temp8c); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, - temp8blen, temp8b, temp16); - temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, - temp16len, temp16, temp24); - temp48len = scale_expansion_zeroelim(temp24len, temp24, aex, temp48); - xlen = scale_expansion_zeroelim(temp48len, temp48, -aex, xdet); - temp48len = scale_expansion_zeroelim(temp24len, temp24, aey, temp48); - ylen = scale_expansion_zeroelim(temp48len, temp48, -aey, ydet); - temp48len = scale_expansion_zeroelim(temp24len, temp24, aez, temp48); - zlen = scale_expansion_zeroelim(temp48len, temp48, -aez, zdet); - xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); - alen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, adet); - - temp8alen = scale_expansion_zeroelim(4, da, cez, temp8a); - temp8blen = scale_expansion_zeroelim(4, ac, dez, temp8b); - temp8clen = scale_expansion_zeroelim(4, cd, aez, temp8c); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, - temp8blen, temp8b, temp16); - temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, - temp16len, temp16, temp24); - temp48len = scale_expansion_zeroelim(temp24len, temp24, bex, temp48); - xlen = scale_expansion_zeroelim(temp48len, temp48, bex, xdet); - temp48len = scale_expansion_zeroelim(temp24len, temp24, bey, temp48); - ylen = scale_expansion_zeroelim(temp48len, temp48, bey, ydet); - temp48len = scale_expansion_zeroelim(temp24len, temp24, bez, temp48); - zlen = scale_expansion_zeroelim(temp48len, temp48, bez, zdet); - xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); - blen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, bdet); - - temp8alen = scale_expansion_zeroelim(4, ab, dez, temp8a); - temp8blen = scale_expansion_zeroelim(4, bd, aez, temp8b); - temp8clen = scale_expansion_zeroelim(4, da, bez, temp8c); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, - temp8blen, temp8b, temp16); - temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, - temp16len, temp16, temp24); - temp48len = scale_expansion_zeroelim(temp24len, temp24, cex, temp48); - xlen = scale_expansion_zeroelim(temp48len, temp48, -cex, xdet); - temp48len = scale_expansion_zeroelim(temp24len, temp24, cey, temp48); - ylen = scale_expansion_zeroelim(temp48len, temp48, -cey, ydet); - temp48len = scale_expansion_zeroelim(temp24len, temp24, cez, temp48); - zlen = scale_expansion_zeroelim(temp48len, temp48, -cez, zdet); - xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); - clen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, cdet); - - temp8alen = scale_expansion_zeroelim(4, bc, aez, temp8a); - temp8blen = scale_expansion_zeroelim(4, ac, -bez, temp8b); - temp8clen = scale_expansion_zeroelim(4, ab, cez, temp8c); - temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, - temp8blen, temp8b, temp16); - temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, - temp16len, temp16, temp24); - temp48len = scale_expansion_zeroelim(temp24len, temp24, dex, temp48); - xlen = scale_expansion_zeroelim(temp48len, temp48, dex, xdet); - temp48len = scale_expansion_zeroelim(temp24len, temp24, dey, temp48); - ylen = scale_expansion_zeroelim(temp48len, temp48, dey, ydet); - temp48len = scale_expansion_zeroelim(temp24len, temp24, dez, temp48); - zlen = scale_expansion_zeroelim(temp48len, temp48, dez, zdet); - xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); - dlen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, ddet); - - ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); - cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); - finlength = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, fin1); - - det = estimate(finlength, fin1); - errbound = isperrboundB * permanent; - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - Two_Diff_Tail(pa[0], pe[0], aex, aextail); - Two_Diff_Tail(pa[1], pe[1], aey, aeytail); - Two_Diff_Tail(pa[2], pe[2], aez, aeztail); - Two_Diff_Tail(pb[0], pe[0], bex, bextail); - Two_Diff_Tail(pb[1], pe[1], bey, beytail); - Two_Diff_Tail(pb[2], pe[2], bez, beztail); - Two_Diff_Tail(pc[0], pe[0], cex, cextail); - Two_Diff_Tail(pc[1], pe[1], cey, ceytail); - Two_Diff_Tail(pc[2], pe[2], cez, ceztail); - Two_Diff_Tail(pd[0], pe[0], dex, dextail); - Two_Diff_Tail(pd[1], pe[1], dey, deytail); - Two_Diff_Tail(pd[2], pe[2], dez, deztail); - if ((aextail == 0.0) && (aeytail == 0.0) && (aeztail == 0.0) - && (bextail == 0.0) && (beytail == 0.0) && (beztail == 0.0) - && (cextail == 0.0) && (ceytail == 0.0) && (ceztail == 0.0) - && (dextail == 0.0) && (deytail == 0.0) && (deztail == 0.0)) { - return det; - } - - errbound = isperrboundC * permanent + resulterrbound * Absolute(det); - abeps = (aex * beytail + bey * aextail) - - (aey * bextail + bex * aeytail); - bceps = (bex * ceytail + cey * bextail) - - (bey * cextail + cex * beytail); - cdeps = (cex * deytail + dey * cextail) - - (cey * dextail + dex * ceytail); - daeps = (dex * aeytail + aey * dextail) - - (dey * aextail + aex * deytail); - aceps = (aex * ceytail + cey * aextail) - - (aey * cextail + cex * aeytail); - bdeps = (bex * deytail + dey * bextail) - - (bey * dextail + dex * beytail); - det += (((bex * bex + bey * bey + bez * bez) - * ((cez * daeps + dez * aceps + aez * cdeps) - + (ceztail * da3 + deztail * ac3 + aeztail * cd3)) - + (dex * dex + dey * dey + dez * dez) - * ((aez * bceps - bez * aceps + cez * abeps) - + (aeztail * bc3 - beztail * ac3 + ceztail * ab3))) - - ((aex * aex + aey * aey + aez * aez) - * ((bez * cdeps - cez * bdeps + dez * bceps) - + (beztail * cd3 - ceztail * bd3 + deztail * bc3)) - + (cex * cex + cey * cey + cez * cez) - * ((dez * abeps + aez * bdeps + bez * daeps) - + (deztail * ab3 + aeztail * bd3 + beztail * da3)))) - + 2.0 * (((bex * bextail + bey * beytail + bez * beztail) - * (cez * da3 + dez * ac3 + aez * cd3) - + (dex * dextail + dey * deytail + dez * deztail) - * (aez * bc3 - bez * ac3 + cez * ab3)) - - ((aex * aextail + aey * aeytail + aez * aeztail) - * (bez * cd3 - cez * bd3 + dez * bc3) - + (cex * cextail + cey * ceytail + cez * ceztail) - * (dez * ab3 + aez * bd3 + bez * da3))); - if ((det >= errbound) || (-det >= errbound)) { - return det; - } - - return insphereexact(pa, pb, pc, pd, pe); -} - -REAL insphere(pa, pb, pc, pd, pe) -REAL *pa; -REAL *pb; -REAL *pc; -REAL *pd; -REAL *pe; -{ - REAL aex, bex, cex, dex; - REAL aey, bey, cey, dey; - REAL aez, bez, cez, dez; - REAL aexbey, bexaey, bexcey, cexbey, cexdey, dexcey, dexaey, aexdey; - REAL aexcey, cexaey, bexdey, dexbey; - REAL alift, blift, clift, dlift; - REAL ab, bc, cd, da, ac, bd; - REAL abc, bcd, cda, dab; - REAL aezplus, bezplus, cezplus, dezplus; - REAL aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus; - REAL cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus; - REAL aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus; - REAL det; - REAL permanent, errbound; - REAL ins; - - FPU_ROUND_DOUBLE; - - aex = pa[0] - pe[0]; - bex = pb[0] - pe[0]; - cex = pc[0] - pe[0]; - dex = pd[0] - pe[0]; - aey = pa[1] - pe[1]; - bey = pb[1] - pe[1]; - cey = pc[1] - pe[1]; - dey = pd[1] - pe[1]; - aez = pa[2] - pe[2]; - bez = pb[2] - pe[2]; - cez = pc[2] - pe[2]; - dez = pd[2] - pe[2]; - - aexbey = aex * bey; - bexaey = bex * aey; - ab = aexbey - bexaey; - bexcey = bex * cey; - cexbey = cex * bey; - bc = bexcey - cexbey; - cexdey = cex * dey; - dexcey = dex * cey; - cd = cexdey - dexcey; - dexaey = dex * aey; - aexdey = aex * dey; - da = dexaey - aexdey; - - aexcey = aex * cey; - cexaey = cex * aey; - ac = aexcey - cexaey; - bexdey = bex * dey; - dexbey = dex * bey; - bd = bexdey - dexbey; - - abc = aez * bc - bez * ac + cez * ab; - bcd = bez * cd - cez * bd + dez * bc; - cda = cez * da + dez * ac + aez * cd; - dab = dez * ab + aez * bd + bez * da; - - alift = aex * aex + aey * aey + aez * aez; - blift = bex * bex + bey * bey + bez * bez; - clift = cex * cex + cey * cey + cez * cez; - dlift = dex * dex + dey * dey + dez * dez; - - det = (dlift * abc - clift * dab) + (blift * cda - alift * bcd); - - aezplus = Absolute(aez); - bezplus = Absolute(bez); - cezplus = Absolute(cez); - dezplus = Absolute(dez); - aexbeyplus = Absolute(aexbey); - bexaeyplus = Absolute(bexaey); - bexceyplus = Absolute(bexcey); - cexbeyplus = Absolute(cexbey); - cexdeyplus = Absolute(cexdey); - dexceyplus = Absolute(dexcey); - dexaeyplus = Absolute(dexaey); - aexdeyplus = Absolute(aexdey); - aexceyplus = Absolute(aexcey); - cexaeyplus = Absolute(cexaey); - bexdeyplus = Absolute(bexdey); - dexbeyplus = Absolute(dexbey); - permanent = ((cexdeyplus + dexceyplus) * bezplus - + (dexbeyplus + bexdeyplus) * cezplus - + (bexceyplus + cexbeyplus) * dezplus) - * alift - + ((dexaeyplus + aexdeyplus) * cezplus - + (aexceyplus + cexaeyplus) * dezplus - + (cexdeyplus + dexceyplus) * aezplus) - * blift - + ((aexbeyplus + bexaeyplus) * dezplus - + (bexdeyplus + dexbeyplus) * aezplus - + (dexaeyplus + aexdeyplus) * bezplus) - * clift - + ((bexceyplus + cexbeyplus) * aezplus - + (cexaeyplus + aexceyplus) * bezplus - + (aexbeyplus + bexaeyplus) * cezplus) - * dlift; - errbound = isperrboundA * permanent; - if ((det > errbound) || (-det > errbound)) { - FPU_RESTORE; - return det; - } - - ins = insphereadapt(pa, pb, pc, pd, pe, permanent); - FPU_RESTORE; - return ins; -} Index: trunk/src_3rd/gts/surface.c =================================================================== --- trunk/src_3rd/gts/surface.c (revision 6802) +++ trunk/src_3rd/gts/surface.c (nonexistent) @@ -1,2743 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include -#include -#include "gts.h" - -#include "gts-private.h" - -static void destroy_foreach_face (GtsFace * f, GtsSurface * s) -{ - f->surfaces = g_slist_remove (f->surfaces, s); - if (!GTS_OBJECT_DESTROYED (f) && - !gts_allow_floating_faces && f->surfaces == NULL) - gts_object_destroy (GTS_OBJECT (f)); -} - -static void surface_destroy (GtsObject * object) -{ - GtsSurface * surface = GTS_SURFACE (object); - - gts_surface_foreach_face (surface, (GtsFunc) destroy_foreach_face, surface); -#ifdef USE_SURFACE_BTREE - g_tree_destroy (surface->faces); -#else /* not USE_SURFACE_BTREE */ - g_hash_table_destroy (surface->faces); -#endif /* not USE_SURFACE_BTREE */ - - (* GTS_OBJECT_CLASS (gts_surface_class ())->parent_class->destroy) (object); -} - -static void surface_write (GtsObject * object, FILE * fptr) -{ - fprintf (fptr, " %s %s %s %s", - object->klass->info.name, - GTS_OBJECT_CLASS (GTS_SURFACE (object)->face_class)->info.name, - GTS_OBJECT_CLASS (GTS_SURFACE (object)->edge_class)->info.name, - GTS_POINT_CLASS (GTS_SURFACE (object)->vertex_class)->binary ? - "GtsVertexBinary" : - GTS_OBJECT_CLASS (GTS_SURFACE (object)->vertex_class)->info.name); -} - -static void surface_class_init (GtsSurfaceClass * klass) -{ - GTS_OBJECT_CLASS (klass)->destroy = surface_destroy; - GTS_OBJECT_CLASS (klass)->write = surface_write; - klass->add_face = NULL; - klass->remove_face = NULL; -} - -#ifdef USE_SURFACE_BTREE -static gint compare_pointers (gconstpointer a, gconstpointer b) -{ - if (GPOINTER_TO_UINT (a) < GPOINTER_TO_UINT (b)) - return -1; - if (GPOINTER_TO_UINT (a) > GPOINTER_TO_UINT (b)) - return 1; - return 0; -} -#endif /* USE_SURFACE_BTREE */ - -static void surface_init (GtsSurface * surface) -{ -#ifdef USE_SURFACE_BTREE - surface->faces = g_tree_new (compare_pointers); -#else /* not USE_SURFACE_BTREE */ - surface->faces = g_hash_table_new (NULL, NULL); -#endif /* not USE_SURFACE_BTREE */ - surface->vertex_class = gts_vertex_class (); - surface->edge_class = gts_edge_class (); - surface->face_class = gts_face_class (); - surface->keep_faces = FALSE; -} - -/** - * gts_surface_class: - * - * Returns: the #GtsSurfaceClass. - */ -GtsSurfaceClass * gts_surface_class (void) -{ - static GtsSurfaceClass * klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo surface_info = { - "GtsSurface", - sizeof (GtsSurface), - sizeof (GtsSurfaceClass), - (GtsObjectClassInitFunc) surface_class_init, - (GtsObjectInitFunc) surface_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = gts_object_class_new (gts_object_class (), &surface_info); - } - - return klass; -} - -/** - * gts_surface_new: - * @klass: a #GtsSurfaceClass. - * @face_class: a #GtsFaceClass. - * @edge_class: a #GtsEdgeClass. - * @vertex_class: a #GtsVertexClass. - * - * Returns: a new empty #GtsSurface. - */ -GtsSurface * gts_surface_new (GtsSurfaceClass * klass, - GtsFaceClass * face_class, - GtsEdgeClass * edge_class, - GtsVertexClass * vertex_class) -{ - GtsSurface * s; - - s = GTS_SURFACE (gts_object_new (GTS_OBJECT_CLASS (klass))); - s->vertex_class = vertex_class; - s->edge_class = edge_class; - s->face_class = face_class; - - return s; -} - -/** - * gts_surface_add_face: - * @s: a #GtsSurface. - * @f: a #GtsFace. - * - * Adds face @f to surface @s. - */ -void gts_surface_add_face (GtsSurface * s, GtsFace * f) -{ - g_return_if_fail (s != NULL); - g_return_if_fail (f != NULL); - - g_assert (s->keep_faces == FALSE); - -#ifdef USE_SURFACE_BTREE - if (!g_tree_lookup (s->faces, f)) { - f->surfaces = g_slist_prepend (f->surfaces, s); - g_tree_insert (s->faces, f, f); - } -#else /* not USE_SURFACE_BTREE */ - if (!g_hash_table_lookup (s->faces, f)) { - f->surfaces = g_slist_prepend (f->surfaces, s); - g_hash_table_insert (s->faces, f, f); - } -#endif /* not USE_SURFACE_BTREE */ - - if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->add_face) - (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->add_face) (s, f); -} - -/** - * gts_surface_remove_face: - * @s: a #GtsSurface. - * @f: a #GtsFace. - * - * Removes face @f from surface @s. - */ -void gts_surface_remove_face (GtsSurface * s, - GtsFace * f) -{ - g_return_if_fail (s != NULL); - g_return_if_fail (f != NULL); - - g_assert (s->keep_faces == FALSE); - -#ifdef USE_SURFACE_BTREE - g_tree_remove (s->faces, f); -#else /* not USE_SURFACE_BTREE */ - g_hash_table_remove (s->faces, f); -#endif /* not USE_SURFACE_BTREE */ - - f->surfaces = g_slist_remove (f->surfaces, s); - - if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face) - (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face) (s, f); - - if (!GTS_OBJECT_DESTROYED (f) && - !gts_allow_floating_faces && - f->surfaces == NULL) - gts_object_destroy (GTS_OBJECT (f)); -} - -/** - * gts_surface_read: - * @surface: a #GtsSurface. - * @f: a #GtsFile. - * - * Add to @surface the data read from @f. The format of the file pointed to - * by @f is as described in gts_surface_write(). - * - * Returns: 0 if successful or the line number at which the parsing - * stopped in case of error (in which case the @error field of @f is - * set to a description of the error which occured). - */ -/* Update split.c/surface_read() if modifying this function */ -guint gts_surface_read (GtsSurface * surface, GtsFile * f) -{ - GtsVertex ** vertices; - GtsEdge ** edges; - guint n, nv, ne, nf; - - g_return_val_if_fail (surface != NULL, 1); - g_return_val_if_fail (f != NULL, 1); - - if (f->type != GTS_INT) { - gts_file_error (f, "expecting an integer (number of vertices)"); - return f->line; - } - nv = atoi (f->token->str); - - gts_file_next_token (f); - if (f->type != GTS_INT) { - gts_file_error (f, "expecting an integer (number of edges)"); - return f->line; - } - ne = atoi (f->token->str); - - gts_file_next_token (f); - if (f->type != GTS_INT) { - gts_file_error (f, "expecting an integer (number of faces)"); - return f->line; - } - nf = atoi (f->token->str); - - gts_file_next_token (f); - if (f->type == GTS_STRING) { - if (f->type != GTS_STRING) { - gts_file_error (f, "expecting a string (GtsSurfaceClass)"); - return f->line; - } - gts_file_next_token (f); - if (f->type != GTS_STRING) { - gts_file_error (f, "expecting a string (GtsFaceClass)"); - return f->line; - } - gts_file_next_token (f); - if (f->type != GTS_STRING) { - gts_file_error (f, "expecting a string (GtsEdgeClass)"); - return f->line; - } - gts_file_next_token (f); - if (f->type != GTS_STRING) { - gts_file_error (f, "expecting a string (GtsVertexClass)"); - return f->line; - } - if (!strcmp (f->token->str, "GtsVertexBinary")) - GTS_POINT_CLASS (surface->vertex_class)->binary = TRUE; - else { - GTS_POINT_CLASS (surface->vertex_class)->binary = FALSE; - gts_file_first_token_after (f, '\n'); - } - } - else - gts_file_first_token_after (f, '\n'); - - if (nf <= 0) - return 0; - - /* allocate nv + 1 just in case nv == 0 */ - vertices = g_malloc ((nv + 1)*sizeof (GtsVertex *)); - edges = g_malloc ((ne + 1)*sizeof (GtsEdge *)); - - n = 0; - while (n < nv && f->type != GTS_ERROR) { - GtsObject * new_vertex = - gts_object_new (GTS_OBJECT_CLASS (surface->vertex_class)); - - (* GTS_OBJECT_CLASS (surface->vertex_class)->read) (&new_vertex, f); - if (f->type != GTS_ERROR) { - if (!GTS_POINT_CLASS (surface->vertex_class)->binary) - gts_file_first_token_after (f, '\n'); - vertices[n++] = GTS_VERTEX (new_vertex); - } - else - gts_object_destroy (new_vertex); - } - if (f->type == GTS_ERROR) - nv = n; - if (GTS_POINT_CLASS (surface->vertex_class)->binary) - gts_file_first_token_after (f, '\n'); - - n = 0; - while (n < ne && f->type != GTS_ERROR) { - guint p1, p2; - - if (f->type != GTS_INT) - gts_file_error (f, "expecting an integer (first vertex index)"); - else { - p1 = atoi (f->token->str); - if (p1 == 0 || p1 > nv) - gts_file_error (f, "vertex index `%d' is out of range `[1,%d]'", - p1, nv); - else { - gts_file_next_token (f); - if (f->type != GTS_INT) - gts_file_error (f, "expecting an integer (second vertex index)"); - else { - p2 = atoi (f->token->str); - if (p2 == 0 || p2 > nv) - gts_file_error (f, "vertex index `%d' is out of range `[1,%d]'", - p2, nv); - else { - GtsEdge * new_edge = - gts_edge_new (surface->edge_class, - vertices[p1 - 1], vertices[p2 - 1]); - - gts_file_next_token (f); - if (f->type != '\n') - if (GTS_OBJECT_CLASS (surface->edge_class)->read) - (*GTS_OBJECT_CLASS (surface->edge_class)->read) - ((GtsObject **) &new_edge, f); - gts_file_first_token_after (f, '\n'); - edges[n++] = new_edge; - } - } - } - } - } - if (f->type == GTS_ERROR) - ne = n; - - n = 0; - while (n < nf && f->type != GTS_ERROR) { - guint s1, s2, s3; - - if (f->type != GTS_INT) - gts_file_error (f, "expecting an integer (first edge index)"); - else { - s1 = atoi (f->token->str); - if (s1 == 0 || s1 > ne) - gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", - s1, ne); - else { - gts_file_next_token (f); - if (f->type != GTS_INT) - gts_file_error (f, "expecting an integer (second edge index)"); - else { - s2 = atoi (f->token->str); - if (s2 == 0 || s2 > ne) - gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", - s2, ne); - else { - gts_file_next_token (f); - if (f->type != GTS_INT) - gts_file_error (f, "expecting an integer (third edge index)"); - else { - s3 = atoi (f->token->str); - if (s3 == 0 || s3 > ne) - gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", - s3, ne); - else { - GtsFace * new_face = gts_face_new (surface->face_class, - edges[s1 - 1], - edges[s2 - 1], - edges[s3 - 1]); - - gts_file_next_token (f); - if (f->type != '\n') - if (GTS_OBJECT_CLASS (surface->face_class)->read) - (*GTS_OBJECT_CLASS (surface->face_class)->read) - ((GtsObject **) &new_face, f); - gts_file_first_token_after (f, '\n'); - gts_surface_add_face (surface, new_face); - n++; - } - } - } - } - } - } - } - - if (f->type == GTS_ERROR) { - gts_allow_floating_vertices = TRUE; - while (nv) - gts_object_destroy (GTS_OBJECT (vertices[nv-- - 1])); - gts_allow_floating_vertices = FALSE; - } - - g_free (vertices); - g_free (edges); - - if (f->type == GTS_ERROR) - return f->line; - return 0; -} - -static void sum_area (GtsFace * f, gdouble * area) { - *area += gts_triangle_area (GTS_TRIANGLE (f)); -} - -/** - * gts_surface_area: - * @s: a #GtsSurface. - * - * Returns: the area of @s obtained as the sum of the signed areas of its - * faces. - */ -gdouble gts_surface_area (GtsSurface * s) -{ - gdouble area = 0.0; - gts_surface_foreach_face (s, (GtsFunc)sum_area, &area); - return area; -} - -/** - * gts_range_init: - * @r: a #GtsRange. - * - * Initializes a #GtsRange. - */ -void gts_range_init (GtsRange * r) -{ - g_return_if_fail (r != NULL); - - r->max = - G_MAXDOUBLE; - r->min = G_MAXDOUBLE; - r->sum = r->sum2 = 0.0; - r->n = 0; -} - -/** - * gts_range_reset: - * @r: a #GtsRange. - * - * Sets all the fields of @r to 0. - */ -void gts_range_reset (GtsRange * r) -{ - g_return_if_fail (r != NULL); - - r->max = 0.0; - r->min = 0.0; - r->sum = r->sum2 = 0.0; - r->n = 0; -} - -/** - * gts_range_add_value: - * @r: a #GtsRange. - * @val: a value to add to @r. - * - * Adds @val to @r. - */ -void gts_range_add_value (GtsRange * r, gdouble val) -{ - g_return_if_fail (r != NULL); - - if (val < r->min) r->min = val; - if (val > r->max) r->max = val; - r->sum += val; - r->sum2 += val*val; - r->n++; -} - -/** - * gts_range_update: - * @r: a #GtsRange. - * - * Updates the fields of @r. - */ -void gts_range_update (GtsRange * r) -{ - g_return_if_fail (r != NULL); - - if (r->n > 0) { - if (r->sum2 - r->sum*r->sum/(gdouble) r->n >= 0.) - r->stddev = sqrt ((r->sum2 - r->sum*r->sum/(gdouble) r->n) - /(gdouble) r->n); - else - r->stddev = 0.; - r->mean = r->sum/(gdouble) r->n; - } - else - r->min = r->max = r->mean = r->stddev = 0.; -} - -/** - * gts_range_print: - * @r: a #GtsRange. - * @fptr: a file pointer. - * - * Writes a text representation of @r in @fptr. - */ -void gts_range_print (GtsRange * r, FILE * fptr) -{ - g_return_if_fail (r != NULL); - g_return_if_fail (fptr != NULL); - fprintf (fptr, "min: %g mean: %g | %g max: %g", - r->min, r->mean, r->stddev, r->max); -} - -static void stats_foreach_vertex (GtsVertex * v, GtsSurfaceStats * stats) -{ - GSList * i = v->segments; - guint nedges = 0; - - while (i) { - if (GTS_IS_EDGE (i->data) && - gts_edge_has_parent_surface (i->data, stats->parent)) - nedges++; - i = i->next; - } - gts_range_add_value (&stats->edges_per_vertex, nedges); -} - -static void stats_foreach_edge (GtsEdge * e, GtsSurfaceStats * stats) -{ - guint nt = gts_edge_face_number (e, stats->parent); - - if (gts_segment_is_duplicate (GTS_SEGMENT (e))) - stats->n_duplicate_edges++; - if (nt == 1) - stats->n_boundary_edges++; - else if (nt > 2) - stats->n_non_manifold_edges++; - gts_range_add_value (&stats->faces_per_edge, nt); -} - -static void stats_foreach_face (GtsTriangle * t, GtsSurfaceStats * stats) -{ - if (!gts_face_is_compatible (GTS_FACE (t), stats->parent)) - stats->n_incompatible_faces++; - if (gts_triangle_is_duplicate (t)) - stats->n_duplicate_faces++; - stats->n_faces++; -} - -/** - * gts_surface_stats: - * @s: a #GtsSurface. - * @stats: a #GtsSurfaceStats. - * - * Fills @stats with the statistics relevant to surface @s. - */ -void gts_surface_stats (GtsSurface * s, GtsSurfaceStats * stats) -{ - g_return_if_fail (s != NULL); - g_return_if_fail (stats != NULL); - - stats->parent = s; - stats->n_faces = 0; - stats->n_incompatible_faces = 0; - stats->n_duplicate_faces = 0; - stats->n_duplicate_edges = 0; - stats->n_boundary_edges = 0; - stats->n_non_manifold_edges = 0; - gts_range_init (&stats->edges_per_vertex); - gts_range_init (&stats->faces_per_edge); - - gts_surface_foreach_vertex (s, (GtsFunc) stats_foreach_vertex, stats); - gts_surface_foreach_edge (s, (GtsFunc) stats_foreach_edge, stats); - gts_surface_foreach_face (s, (GtsFunc) stats_foreach_face, stats); - - gts_range_update (&stats->edges_per_vertex); - gts_range_update (&stats->faces_per_edge); -} - -static void quality_foreach_edge (GtsSegment * s, - GtsSurfaceQualityStats * stats) -{ - GSList * i = GTS_EDGE (s)->triangles; - - gts_range_add_value (&stats->edge_length, - gts_point_distance (GTS_POINT (s->v1), - GTS_POINT (s->v2))); - while (i) { - GSList * j = i->next; - while (j) { - gts_range_add_value (&stats->edge_angle, - fabs (gts_triangles_angle (i->data, j->data))); - j = j->next; - } - i = i->next; - } -} - -static void quality_foreach_face (GtsTriangle * t, - GtsSurfaceQualityStats * stats) -{ - gts_range_add_value (&stats->face_quality, gts_triangle_quality (t)); - gts_range_add_value (&stats->face_area, gts_triangle_area (t)); -} - -/** - * gts_surface_quality_stats: - * @s: a #GtsSurface. - * @stats: a #GtsSurfaceQualityStats. - * - * Fills @stats with quality statistics relevant to surface @s. - */ -void gts_surface_quality_stats (GtsSurface * s, GtsSurfaceQualityStats * stats) -{ - g_return_if_fail (s != NULL); - g_return_if_fail (stats != NULL); - - stats->parent = s; - gts_range_init (&stats->face_quality); - gts_range_init (&stats->face_area); - gts_range_init (&stats->edge_length); - gts_range_init (&stats->edge_angle); - - gts_surface_foreach_edge (s, (GtsFunc) quality_foreach_edge, stats); - gts_surface_foreach_face (s, (GtsFunc) quality_foreach_face, stats); - - gts_range_update (&stats->face_quality); - gts_range_update (&stats->face_area); - gts_range_update (&stats->edge_length); - gts_range_update (&stats->edge_angle); -} - -/** - * gts_surface_print_stats: - * @s: a #GtsSurface. - * @fptr: a file pointer. - * - * Writes in the file pointed to by @fptr the statistics for surface @s. - */ -void gts_surface_print_stats (GtsSurface * s, FILE * fptr) -{ - GtsSurfaceStats stats; - GtsSurfaceQualityStats qstats; - - g_return_if_fail (s != NULL); - g_return_if_fail (fptr != NULL); - - gts_surface_stats (s, &stats); - gts_surface_quality_stats (s, &qstats); - - fprintf (fptr, - "# vertices: %u edges: %u faces: %u\n" - "# Connectivity statistics\n" - "# incompatible faces: %u\n" - "# duplicate faces: %u\n" - "# boundary edges: %u\n" - "# duplicate edges: %u\n" - "# non-manifold edges: %u\n", - stats.edges_per_vertex.n, - stats.faces_per_edge.n, - stats.n_faces, - stats.n_incompatible_faces, - stats.n_duplicate_faces, - stats.n_boundary_edges, - stats.n_duplicate_edges, - stats.n_non_manifold_edges); - fputs ("# edges per vertex: ", fptr); - gts_range_print (&stats.edges_per_vertex, fptr); - fputs ("\n# faces per edge: ", fptr); - gts_range_print (&stats.faces_per_edge, fptr); - fputs ("\n# Geometric statistics\n# face quality: ", fptr); - gts_range_print (&qstats.face_quality, fptr); - fputs ("\n# face area : ", fptr); - gts_range_print (&qstats.face_area, fptr); - fputs ("\n# edge length : ", fptr); - gts_range_print (&qstats.edge_length, fptr); - fputc ('\n', fptr); -} - -static void write_vertex (GtsPoint * p, gpointer * data) -{ - (*GTS_OBJECT (p)->klass->write) (GTS_OBJECT (p), (FILE *) data[0]); - if (!GTS_POINT_CLASS (GTS_OBJECT (p)->klass)->binary) - fputc ('\n', (FILE *) data[0]); - g_hash_table_insert (data[2], p, - GUINT_TO_POINTER (++(*((guint *) data[1])))); -} - -static void write_edge (GtsSegment * s, gpointer * data) -{ - fprintf ((FILE *) data[0], "%u %u", - GPOINTER_TO_UINT (g_hash_table_lookup (data[2], s->v1)), - GPOINTER_TO_UINT (g_hash_table_lookup (data[2], s->v2))); - if (GTS_OBJECT (s)->klass->write) - (*GTS_OBJECT (s)->klass->write) (GTS_OBJECT (s), (FILE *) data[0]); - fputc ('\n', (FILE *) data[0]); - g_hash_table_insert (data[3], s, - GUINT_TO_POINTER (++(*((guint *) data[1])))); -} - -static void write_face (GtsTriangle * t, gpointer * data) -{ - fprintf (data[0], "%u %u %u", - GPOINTER_TO_UINT (g_hash_table_lookup (data[3], t->e1)), - GPOINTER_TO_UINT (g_hash_table_lookup (data[3], t->e2)), - GPOINTER_TO_UINT (g_hash_table_lookup (data[3], t->e3))); - if (GTS_OBJECT (t)->klass->write) - (*GTS_OBJECT (t)->klass->write) (GTS_OBJECT (t), data[0]); - fputc ('\n', data[0]); -} - -/** - * gts_surface_write: - * @s: a #GtsSurface. - * @fptr: a file pointer. - * - * Writes in the file @fptr an ASCII representation of @s. The file - * format is as follows. - * - * All the lines beginning with #GTS_COMMENTS are ignored. The first line - * contains three unsigned integers separated by spaces. The first - * integer is the number of vertices, nv, the second is the number of - * edges, ne and the third is the number of faces, nf. - * - * Follows nv lines containing the x, y and z coordinates of the - * vertices. Follows ne lines containing the two indices (starting - * from one) of the vertices of each edge. Follows nf lines containing - * the three ordered indices (also starting from one) of the edges of - * each face. - * - * The format described above is the least common denominator to all - * GTS files. Consistent with an object-oriented approach, the GTS - * file format is extensible. Each of the lines of the file can be - * extended with user-specific attributes accessible through the - * read() and write() virtual methods of each of the objects written - * (surface, vertices, edges or faces). When read with different - * object classes, these extra attributes are just ignored. - */ -void gts_surface_write (GtsSurface * s, FILE * fptr) -{ - guint n; - gpointer data[4]; - GHashTable * vindex, * eindex; - GtsSurfaceStats stats; - - g_return_if_fail (s != NULL); - g_return_if_fail (fptr != NULL); - - data[0] = fptr; - data[1] = &n; - data[2] = vindex = g_hash_table_new (NULL, NULL); - data[3] = eindex = g_hash_table_new (NULL, NULL); - - gts_surface_stats (s, &stats); - fprintf (fptr, "%u %u %u", - stats.edges_per_vertex.n, - stats.faces_per_edge.n, - stats.n_faces); - if (GTS_OBJECT (s)->klass->write) - (*GTS_OBJECT (s)->klass->write) (GTS_OBJECT (s), fptr); - fputc ('\n', fptr); - n = 0; - gts_surface_foreach_vertex (s, (GtsFunc) write_vertex, data); - n = 0; - if (GTS_POINT_CLASS (s->vertex_class)->binary) - fputc ('\n', fptr); - gts_surface_foreach_edge (s, (GtsFunc) write_edge, data); - gts_surface_foreach_face (s, (GtsFunc) write_face, data); - g_hash_table_destroy (vindex); - g_hash_table_destroy (eindex); -} - -static void write_vertex_oogl (GtsPoint * p, gpointer * data) -{ - FILE * fp = data[0]; - - fprintf (fp, "%g %g %g", p->x, p->y, p->z); - if (GTS_OBJECT (p)->klass->color) { - GtsColor c = (* GTS_OBJECT (p)->klass->color) (GTS_OBJECT (p)); - fprintf (fp, " %g %g %g 1.0\n", c.r, c.g, c.b); - } - else - fputc ('\n', fp); - GTS_OBJECT (p)->reserved = GUINT_TO_POINTER ((*((guint *) data[1]))++); -} - -static void write_face_oogl (GtsTriangle * t, FILE * fp) -{ - GtsVertex * v1, * v2, * v3; - gts_triangle_vertices (t, &v1, &v2, &v3); - fprintf (fp, "3 %u %u %u", - GPOINTER_TO_UINT (GTS_OBJECT (v1)->reserved), - GPOINTER_TO_UINT (GTS_OBJECT (v2)->reserved), - GPOINTER_TO_UINT (GTS_OBJECT (v3)->reserved)); - if (GTS_OBJECT (t)->klass->color) { - GtsColor c = (* GTS_OBJECT (t)->klass->color) (GTS_OBJECT (t)); - fprintf (fp, " %g %g %g\n", c.r, c.g, c.b); - } - else - fputc ('\n', fp); -} - -/** - * gts_surface_write_oogl: - * @s: a #GtsSurface. - * @fptr: a file pointer. - * - * Writes in the file @fptr an OOGL (Geomview) representation of @s. - */ -void gts_surface_write_oogl (GtsSurface * s, FILE * fptr) -{ - guint n = 0; - gpointer data[2]; - GtsSurfaceStats stats; - - g_return_if_fail (s != NULL); - g_return_if_fail (fptr != NULL); - - data[0] = fptr; - data[1] = &n; - - gts_surface_stats (s, &stats); - if (GTS_OBJECT_CLASS (s->vertex_class)->color) - fputs ("COFF ", fptr); - else - fputs ("OFF ", fptr); - fprintf (fptr, "%u %u %u\n", - stats.edges_per_vertex.n, - stats.n_faces, - stats.faces_per_edge.n); - gts_surface_foreach_vertex (s, (GtsFunc) write_vertex_oogl, data); - gts_surface_foreach_face (s, (GtsFunc) write_face_oogl, fptr); - gts_surface_foreach_vertex (s, (GtsFunc) gts_object_reset_reserved, NULL); -} - -static void write_vertex_vtk (GtsPoint * p, gpointer * data) -{ - FILE * fp = data[0]; - - fprintf (fp, "%g %g %g\n", p->x, p->y, p->z); - GTS_OBJECT (p)->reserved = GUINT_TO_POINTER ((*((guint *) data[1]))++); -} - -static void write_face_vtk (GtsTriangle * t, FILE * fp) -{ - GtsVertex * v1, * v2, * v3; - gts_triangle_vertices (t, &v1, &v2, &v3); - fprintf (fp, "3 %u %u %u\n", - GPOINTER_TO_UINT (GTS_OBJECT (v1)->reserved), - GPOINTER_TO_UINT (GTS_OBJECT (v2)->reserved), - GPOINTER_TO_UINT (GTS_OBJECT (v3)->reserved)); -} - -/** - * gts_surface_write_vtk: - * @s: a #GtsSurface. - * @fptr: a file pointer. - * - * Writes in the file @fptr a VTK representation of @s. - */ -void gts_surface_write_vtk (GtsSurface * s, FILE * fptr) -{ - guint n = 0; - gpointer data[2]; - GtsSurfaceStats stats; - - g_return_if_fail (s != NULL); - g_return_if_fail (fptr != NULL); - - data[0] = fptr; - data[1] = &n; - - gts_surface_stats (s, &stats); - fprintf (fptr, - "# vtk DataFile Version 2.0\n" - "Generated by GTS\n" - "ASCII\n" - "DATASET POLYDATA\n" - "POINTS %u float\n", - stats.edges_per_vertex.n); - gts_surface_foreach_vertex (s, (GtsFunc) write_vertex_vtk, data); - fprintf (fptr, - "POLYGONS %u %u\n", - stats.n_faces, stats.n_faces*4); - gts_surface_foreach_face (s, (GtsFunc) write_face_vtk, fptr); - gts_surface_foreach_vertex (s, (GtsFunc) gts_object_reset_reserved, NULL); -} - -static void write_edge_oogl_boundary (GtsSegment * s, gpointer * data) -{ - if (!gts_edge_is_boundary (GTS_EDGE (s), data[1])) - return; - - if (GTS_OBJECT (s)->klass->color) { - GtsColor c = (* GTS_OBJECT (s)->klass->color) (GTS_OBJECT (s)); - fprintf (data[0], "VECT 1 2 1 2 1 %g %g %g %g %g %g %g %g %g 1.\n", - GTS_POINT (s->v1)->x, GTS_POINT (s->v1)->y, GTS_POINT (s->v1)->z, - GTS_POINT (s->v2)->x, GTS_POINT (s->v2)->y, GTS_POINT (s->v2)->z, - c.r, c.g, c.b); - } - else - fprintf (data[0], "VECT 1 2 0 2 0 %g %g %g %g %g %g\n", - GTS_POINT (s->v1)->x, GTS_POINT (s->v1)->y, GTS_POINT (s->v1)->z, - GTS_POINT (s->v2)->x, GTS_POINT (s->v2)->y, GTS_POINT (s->v2)->z); -} - -/** - * gts_surface_write_oogl_boundary: - * @s: a #GtsSurface. - * @fptr: a file pointer. - * - * Writes in the file @fptr an OOGL (Geomview) representation of the - * boundary of @s. - */ -void gts_surface_write_oogl_boundary (GtsSurface * s, FILE * fptr) -{ - gpointer data[2]; - - g_return_if_fail (s != NULL); - g_return_if_fail (fptr != NULL); - - data[0] = fptr; - data[1] = s; - fputs ("LIST {\n", fptr); - gts_surface_foreach_edge (s, (GtsFunc) write_edge_oogl_boundary, data); - fputs ("}\n", fptr); -} - -#ifdef USE_SURFACE_BTREE -static gint vertex_foreach_face (GtsTriangle * t, - gpointer t_data, - gpointer * info) -#else /* not USE_SURFACE_BTREE */ -static void vertex_foreach_face (GtsTriangle * t, - gpointer t_data, - gpointer * info) -#endif /* not USE_SURFACE_BTREE */ -{ - GHashTable * hash = info[0]; - gpointer data = info[1]; - GtsFunc func = (GtsFunc) info[2]; - GtsSegment - * s1 = GTS_SEGMENT (t->e1); - - if (!g_hash_table_lookup (hash, s1->v1)) { - (*func) (s1->v1, data); - g_hash_table_insert (hash, s1->v1, GINT_TO_POINTER (-1)); - } - if (!g_hash_table_lookup (hash, s1->v2)) { - (*func) (s1->v2, data); - g_hash_table_insert (hash, s1->v2, GINT_TO_POINTER (-1)); - } - if (!g_hash_table_lookup (hash, gts_triangle_vertex (t))) { - (*func) (gts_triangle_vertex (t), data); - g_hash_table_insert (hash, gts_triangle_vertex (t), - GINT_TO_POINTER (-1)); - } -#ifdef USE_SURFACE_BTREE - return FALSE; -#endif /* USE_SURFACE_BTREE */ -} - -/** - * gts_surface_foreach_vertex: - * @s: a #GtsSurface. - * @func: a #GtsFunc. - * @data: user data to be passed to @func. - * - * Calls @func once for each vertex of @s. - */ -void gts_surface_foreach_vertex (GtsSurface * s, GtsFunc func, gpointer data) -{ - gpointer info[3]; - - g_return_if_fail (s != NULL); - g_return_if_fail (func != NULL); - - /* forbid removal of faces */ - s->keep_faces = TRUE; - info[0] = g_hash_table_new (NULL, NULL); - info[1] = data; - info[2] = func; -#ifdef USE_SURFACE_BTREE - g_tree_traverse (s->faces, (GTraverseFunc) vertex_foreach_face, G_IN_ORDER, - info); -#else /* not USE_SURFACE_BTREE */ - g_hash_table_foreach (s->faces, (GHFunc) vertex_foreach_face, info); -#endif /* not USE_SURFACE_BTREE */ - g_hash_table_destroy (info[0]); - /* allow removal of faces */ - s->keep_faces = FALSE; -} - -#ifdef USE_SURFACE_BTREE -static gint edge_foreach_face (GtsTriangle * t, - gpointer t_data, - gpointer * info) -#else /* not USE_SURFACE_BTREE */ -static void edge_foreach_face (GtsTriangle * t, - gpointer t_data, - gpointer * info) -#endif /* not USE_SURFACE_BTREE */ -{ - GHashTable * hash = info[0]; - gpointer data = info[1]; - GtsFunc func = (GtsFunc) info[2]; - - if (!g_hash_table_lookup (hash, t->e1)) { - (*func) (t->e1, data); - g_hash_table_insert (hash, t->e1, GINT_TO_POINTER (-1)); - } - if (!g_hash_table_lookup (hash, t->e2)) { - (*func) (t->e2, data); - g_hash_table_insert (hash, t->e2, GINT_TO_POINTER (-1)); - } - if (!g_hash_table_lookup (hash, t->e3)) { - (*func) (t->e3, data); - g_hash_table_insert (hash, t->e3, GINT_TO_POINTER (-1)); - } -#ifdef USE_SURFACE_BTREE - return FALSE; -#endif /* not USE_SURFACE_BTREE */ -} - -/** - * gts_surface_foreach_edge: - * @s: a #GtsSurface. - * @func: a #GtsFunc. - * @data: user data to be passed to @func. - * - * Calls @func once for each edge of @s. - */ -void gts_surface_foreach_edge (GtsSurface * s, GtsFunc func, gpointer data) -{ - gpointer info[3]; - - g_return_if_fail (s != NULL); - g_return_if_fail (func != NULL); - - /* forbid removal of faces */ - s->keep_faces = TRUE; - info[0] = g_hash_table_new (NULL, NULL); - info[1] = data; - info[2] = func; -#ifdef USE_SURFACE_BTREE - g_tree_traverse (s->faces, (GTraverseFunc) edge_foreach_face, G_IN_ORDER, - info); -#else /* not USE_SURFACE_BTREE */ - g_hash_table_foreach (s->faces, (GHFunc) edge_foreach_face, info); -#endif /* not USE_SURFACE_BTREE */ - g_hash_table_destroy (info[0]); - /* allow removal of faces */ - s->keep_faces = FALSE; -} - -#ifdef USE_SURFACE_BTREE -static gint foreach_face (GtsFace * f, - gpointer t_data, - gpointer * info) -#else /* not USE_SURFACE_BTREE */ -static void foreach_face (GtsFace * f, - gpointer t_data, - gpointer * info) -#endif /* not USE_SURFACE_BTREE */ -{ - (*((GtsFunc) info[0])) (f, info[1]); -#ifdef USE_SURFACE_BTREE - return FALSE; -#endif /* USE_SURFACE_BTREE */ -} - -/** - * gts_surface_foreach_face: - * @s: a #GtsSurface. - * @func: a #GtsFunc. - * @data: user data to be passed to @func. - * - * Calls @func once for each face of @s. - */ -void gts_surface_foreach_face (GtsSurface * s, - GtsFunc func, - gpointer data) -{ - gpointer info[2]; - - g_return_if_fail (s != NULL); - g_return_if_fail (func != NULL); - - /* forbid removal of faces */ - s->keep_faces = TRUE; - info[0] = func; - info[1] = data; -#ifdef USE_SURFACE_BTREE - g_tree_traverse (s->faces, (GTraverseFunc) foreach_face, G_IN_ORDER, - info); -#else /* not USE_SURFACE_BTREE */ - g_hash_table_foreach (s->faces, (GHFunc) foreach_face, info); -#endif /* not USE_SURFACE_BTREE */ - /* allow removal of faces */ - s->keep_faces = FALSE; -} - -#ifdef USE_SURFACE_BTREE -static gint foreach_face_remove (GtsFace * f, - gpointer t_data, - gpointer * info) -{ - if ((*((GtsFunc) info[0])) (f, info[1])) { - GtsSurface * s = info[2]; - guint * n = info[3]; - - f->surfaces = g_slist_remove (f->surfaces, s); - if (!GTS_OBJECT_DESTROYED (f) && - !gts_allow_floating_faces && - f->surfaces == NULL) - gts_object_destroy (GTS_OBJECT (f)); - - if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face) - (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face) (s, f); - - g_tree_remove (s->faces, f); - (*n)++; - } - return FALSE; -} -#else /* not USE_SURFACE_BTREE */ -static gboolean foreach_face_remove (GtsFace * f, - gpointer t_data, - gpointer * info) -{ - if ((*((GtsFunc) info[0])) (f, info[1])) { - GtsSurface * s = info[2]; - - f->surfaces = g_slist_remove (f->surfaces, s); - if (!GTS_OBJECT_DESTROYED (f) && - !gts_allow_floating_faces && - f->surfaces == NULL) - gts_object_destroy (GTS_OBJECT (f)); - - if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face) - (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face) (s, f); - - return TRUE; - } - return FALSE; -} -#endif /* not USE_SURFACE_BTREE */ - -/** - * gts_surface_foreach_face_remove: - * @s: a #GtsSurface. - * @func: a #GtsFunc. - * @data: user data to be passed to @func. - * - * Calls @func once for each face of @s. If @func returns %TRUE the - * corresponding face is removed from @s (and destroyed if it does not - * belong to any other surface and #gts_allow_floating_faces is set to - * %FALSE). - * - * Returns: the number of faces removed from @s. - */ -guint gts_surface_foreach_face_remove (GtsSurface * s, - GtsFunc func, - gpointer data) -{ - gpointer info[4]; - guint n = 0; - - g_return_val_if_fail (s != NULL, 0); - g_return_val_if_fail (func != NULL, 0); - - /* forbid removal of faces */ - s->keep_faces = TRUE; - info[0] = func; - info[1] = data; - info[2] = s; -#ifdef USE_SURFACE_BTREE - info[3] = &n; - g_tree_traverse (s->faces, (GTraverseFunc) foreach_face_remove, G_PRE_ORDER, - info); -#else /* not USE_SURFACE_BTREE */ - n = g_hash_table_foreach_remove (s->faces, - (GHRFunc) foreach_face_remove, - info); -#endif /* not USE_SURFACE_BTREE */ - /* allow removal of faces */ - s->keep_faces = FALSE; - - return n; -} - -static void midvertex_insertion (GtsEdge * e, - GtsSurface * surface, - GtsEHeap * heap, - GtsRefineFunc refine_func, - gpointer refine_data, - GtsVertexClass * vertex_class, - GtsEdgeClass * edge_class) -{ - GtsVertex * midvertex; - GtsEdge * e1, * e2; - GSList * i; - - midvertex = (*refine_func) (e, vertex_class, refine_data); - e1 = gts_edge_new (edge_class, GTS_SEGMENT (e)->v1, midvertex); - gts_eheap_insert (heap, e1); - e2 = gts_edge_new (edge_class, GTS_SEGMENT (e)->v2, midvertex); - gts_eheap_insert (heap, e2); - - /* creates new faces and modifies old ones */ - i = e->triangles; - while (i) { - GtsTriangle * t = i->data; - GtsVertex * v1, * v2, * v3; - GtsEdge * te2, * te3, * ne, * tmp; - - gts_triangle_vertices_edges (t, e, &v1, &v2, &v3, &e, &te2, &te3); - ne = gts_edge_new (edge_class, midvertex, v3); - gts_eheap_insert (heap, ne); - if (GTS_SEGMENT (e1)->v1 == v2) { - tmp = e1; e1 = e2; e2 = tmp; - } - e1->triangles = g_slist_prepend (e1->triangles, t); - ne->triangles = g_slist_prepend (ne->triangles, t); - te2->triangles = g_slist_remove (te2->triangles, t); - t->e1 = e1; t->e2 = ne; t->e3 = te3; - gts_surface_add_face (surface, - gts_face_new (surface->face_class, e2, te2, ne)); - i = i->next; - } - /* destroys edge */ - g_slist_free (e->triangles); - e->triangles = NULL; - gts_object_destroy (GTS_OBJECT (e)); -} - -static gdouble edge_length2_inverse (GtsSegment * s) -{ - return - gts_point_distance2 (GTS_POINT (s->v1), GTS_POINT (s->v2)); -} - -static void create_heap_refine (GtsEdge * e, GtsEHeap * heap) -{ - gts_eheap_insert (heap, e); -} - -/** - * gts_surface_refine: - * @surface: a #GtsSurface. - * @cost_func: a function returning the cost for a given edge. - * @cost_data: user data to be passed to @cost_func. - * @refine_func: a #GtsRefineFunc. - * @refine_data: user data to be passed to @refine_func. - * @stop_func: a #GtsStopFunc. - * @stop_data: user data to be passed to @stop_func. - * - * Refine @surface using a midvertex insertion technique. All the - * edges of @surface are ordered according to @cost_func. The edges - * are then processed in order until @stop_func returns %TRUE. Each - * edge is split in two and new edges and faces are created. - * - * If @cost_func is set to %NULL, the edges are sorted according - * to their length squared (the longest is on top). - * - * If @refine_func is set to %NULL gts_segment_midvertex() is used. - * - */ -void gts_surface_refine (GtsSurface * surface, - GtsKeyFunc cost_func, - gpointer cost_data, - GtsRefineFunc refine_func, - gpointer refine_data, - GtsStopFunc stop_func, - gpointer stop_data) -{ - GtsEHeap * heap; - GtsEdge * e; - gdouble top_cost; - - g_return_if_fail (surface != NULL); - g_return_if_fail (stop_func != NULL); - - if (cost_func == NULL) - cost_func = (GtsKeyFunc) edge_length2_inverse; - if (refine_func == NULL) - refine_func = (GtsRefineFunc) gts_segment_midvertex; - - heap = gts_eheap_new (cost_func, cost_data); - gts_eheap_freeze (heap); - gts_surface_foreach_edge (surface, (GtsFunc) create_heap_refine, heap); - gts_eheap_thaw (heap); - while ((e = gts_eheap_remove_top (heap, &top_cost)) && - !(*stop_func) (top_cost, - gts_eheap_size (heap) + - gts_edge_face_number (e, surface) + 2, - stop_data)) - midvertex_insertion (e, surface, heap, refine_func, refine_data, - surface->vertex_class, surface->edge_class); - gts_eheap_destroy (heap); -} - -static GSList * edge_triangles (GtsEdge * e1, GtsEdge * e) -{ - GSList * i = e1->triangles; - GSList * triangles = NULL; - - while (i) { - GtsTriangle * t = i->data; - if (t->e1 == e || t->e2 == e || t->e3 == e) { - GtsEdge * e2; - GSList * j; - if (t->e1 == e) { - if (t->e2 == e1) - e2 = t->e3; - else - e2 = t->e2; - } - else if (t->e2 == e) { - if (t->e3 == e1) - e2 = t->e1; - else - e2 = t->e3; - } - else { - if (t->e2 == e1) - e2 = t->e1; - else - e2 = t->e2; - } - j = e2->triangles; - while (j) { - GtsTriangle * t = j->data; - if (t->e1 != e && t->e2 != e && t->e3 != e) - triangles = g_slist_prepend (triangles, t); - j = j->next; - } - } - else - triangles = g_slist_prepend (triangles, t); - i = i->next; - } - return triangles; -} - -static void replace_vertex (GSList * i, GtsVertex * v1, GtsVertex * v) -{ - while (i) { - GtsSegment * s = i->data; - if (s->v1 == v1) - s->v1 = v; - else - s->v2 = v; - i = i->next; - } -} - -/** - * gts_edge_collapse_creates_fold: - * @e: a #GtsEdge. - * @v: a #GtsVertex. - * @max: the maximum value of the square of the cosine of the angle between - * two triangles. - * - * Returns: %TRUE if collapsing edge @e to vertex @v would create - * faces making an angle the cosine squared of which would be larger than max, - * %FALSE otherwise. - */ -gboolean gts_edge_collapse_creates_fold (GtsEdge * e, - GtsVertex * v, - gdouble max) -{ - GtsVertex * v1, * v2; - GtsSegment * s; - GSList * i; - gboolean folded = FALSE; - - g_return_val_if_fail (e != NULL, TRUE); - g_return_val_if_fail (v != NULL, TRUE); - - s = GTS_SEGMENT (e); - v1 = s->v1; - v2 = s->v2; - replace_vertex (v1->segments, v1, v); - replace_vertex (v2->segments, v2, v); - - i = v1->segments; - while (i && !folded) { - GtsSegment * s = i->data; - if (GTS_IS_EDGE (s)) { - GtsEdge * e1 = GTS_EDGE (s); - if (e1 != e) { - GSList * triangles = edge_triangles (e1, e); - folded = gts_triangles_are_folded (triangles, s->v1, s->v2, max); - g_slist_free (triangles); - } - } - i = i->next; - } - - i = v2->segments; - while (i && !folded) { - GtsSegment * s = i->data; - if (GTS_IS_EDGE (s)) { - GtsEdge * e1 = GTS_EDGE (s); - if (e1 != e) { - GSList * triangles = edge_triangles (e1, e); - folded = gts_triangles_are_folded (triangles, s->v1, s->v2, max); - g_slist_free (triangles); - } - } - i = i->next; - } -#if 1 - if (!folded) { - GSList * triangles = gts_vertex_triangles (v1, NULL); - i = triangles = gts_vertex_triangles (v2, triangles); - while (i && !folded) { - GtsTriangle * t = i->data; - if (t->e1 != e && t->e2 != e && t->e3 != e) { - GtsEdge * e1 = gts_triangle_edge_opposite (t, v); - g_assert (e1); - folded = gts_triangles_are_folded (e1->triangles, - GTS_SEGMENT (e1)->v1, - GTS_SEGMENT (e1)->v2, - max); - } - i = i->next; - } - g_slist_free (triangles); - } -#endif - replace_vertex (v1->segments, v, v1); - replace_vertex (v2->segments, v, v2); - return folded; -} - -/** - * gts_edge_collapse_is_valid: - * @e: a #GtsEdge. - * - * An implementation of the topological constraints described in the - * "Mesh Optimization" article of Hoppe et al (1993). - * - * Returns: %TRUE if @e can be collapsed without violation of the topological - * constraints, %FALSE otherwise. - */ -gboolean gts_edge_collapse_is_valid (GtsEdge * e) -{ - GSList * i; - - g_return_val_if_fail (e != NULL, FALSE); - - i = GTS_SEGMENT (e)->v1->segments; - while (i) { - GtsEdge * e1 = i->data; - if (e1 != e && GTS_IS_EDGE (e1)) { - GtsEdge * e2 = NULL; - GSList * j = GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e)->v1 ? - GTS_SEGMENT (e1)->v2->segments : GTS_SEGMENT (e1)->v1->segments; - while (j && !e2) { - GtsEdge * e1 = j->data; - if (GTS_IS_EDGE (e1) && - (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e)->v2 || - GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e)->v2)) - e2 = e1; - j = j->next; - } - if (e2 && !gts_triangle_use_edges (e, e1, e2)) - return FALSE; - } - i = i->next; - } - - if (gts_edge_is_boundary (e, NULL)) { - GtsTriangle * t = e->triangles->data; - if (gts_edge_is_boundary (t->e1, NULL) && - gts_edge_is_boundary (t->e2, NULL) && - gts_edge_is_boundary (t->e3, NULL)) - return FALSE; - } - else { - if (gts_vertex_is_boundary (GTS_SEGMENT (e)->v1, NULL) && - gts_vertex_is_boundary (GTS_SEGMENT (e)->v2, NULL)) - return FALSE; - if (gts_edge_belongs_to_tetrahedron (e)) - return FALSE; - } - - return TRUE; -} - -#define HEAP_INSERT_EDGE(h, e) (GTS_OBJECT (e)->reserved = gts_eheap_insert (h, e)) -#define HEAP_REMOVE_EDGE(h, e) (gts_eheap_remove (h, GTS_OBJECT (e)->reserved),\ - GTS_OBJECT (e)->reserved = NULL) - -static GtsVertex * edge_collapse (GtsEdge * e, - GtsEHeap * heap, - GtsCoarsenFunc coarsen_func, - gpointer coarsen_data, - GtsVertexClass * klass, - gdouble maxcosine2) -{ - GSList * i; - GtsVertex * v1 = GTS_SEGMENT (e)->v1, * v2 = GTS_SEGMENT (e)->v2, * mid; - - /* if the edge is degenerate (i.e. v1 == v2), destroy and return */ - if (v1 == v2) { - gts_object_destroy (GTS_OBJECT (e)); - return NULL; - } - - if (!gts_edge_collapse_is_valid (e)) { - GTS_OBJECT (e)->reserved = - gts_eheap_insert_with_key (heap, e, G_MAXDOUBLE); - return NULL; - } - - mid = (*coarsen_func) (e, klass, coarsen_data); - - if (gts_edge_collapse_creates_fold (e, mid, maxcosine2)) { - GTS_OBJECT (e)->reserved = - gts_eheap_insert_with_key (heap, e, G_MAXDOUBLE); - gts_object_destroy (GTS_OBJECT (mid)); - return NULL; - } - - gts_object_destroy (GTS_OBJECT (e)); - - gts_vertex_replace (v1, mid); - gts_object_destroy (GTS_OBJECT (v1)); - gts_vertex_replace (v2, mid); - gts_object_destroy (GTS_OBJECT (v2)); - - /* destroy duplicate edges */ - i = mid->segments; - while (i) { - GtsEdge * e1 = i->data; - GtsEdge * duplicate; - while ((duplicate = gts_edge_is_duplicate (e1))) { - gts_edge_replace (duplicate, GTS_EDGE (e1)); - HEAP_REMOVE_EDGE (heap, duplicate); - gts_object_destroy (GTS_OBJECT (duplicate)); - } - i = i->next; - if (!e1->triangles) { - /* e1 is the result of the collapse of one edge of a pair of identical - faces (it should not happen unless duplicate triangles are present in - the initial surface) */ - g_warning ("file %s: line %d (%s): probably duplicate triangle.", - __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION); - HEAP_REMOVE_EDGE (heap, e1); - gts_object_destroy (GTS_OBJECT (e1)); - if (i == NULL) /* mid has been destroyed */ - mid = NULL; - } - } - - return mid; -} - -/* - * I don't see where this code is ever used, but keep it for a bit - * in case it is needed for debugging - */ -#ifdef GTS_NEED_UPDATE_CLOSEST_NEIGHBORS -static void update_closest_neighbors (GtsVertex * v, GtsEHeap * heap) -{ - GSList * i = v->segments; - - while (i) { - GtsSegment * s = i->data; - if (GTS_IS_EDGE (s)) { - HEAP_REMOVE_EDGE (heap, GTS_EDGE (s)); - HEAP_INSERT_EDGE (heap, GTS_EDGE (s)); - } - i = i->next; - } -} -#endif - -static void update_2nd_closest_neighbors (GtsVertex * v, GtsEHeap * heap) -{ - GSList * i = v->segments; - GSList * list = NULL; - - while (i) { - GtsSegment * s = i->data; - if (GTS_IS_EDGE (s)) { - GtsVertex * v1 = s->v1 == v ? s->v2 : s->v1; - GSList * j = v1->segments; - while (j) { - GtsSegment * s1 = j->data; - if (GTS_IS_EDGE (s1) && !g_slist_find (list, s1)) - list = g_slist_prepend (list, s1); - j = j->next; - } - } - i = i->next; - } - - i = list; - while (i) { - GtsEdge * e = i->data; - HEAP_REMOVE_EDGE (heap, e); - HEAP_INSERT_EDGE (heap, e); - i = i->next; - } - - g_slist_free (list); -} - -static gdouble edge_length2 (GtsEdge * e) -{ - return gts_point_distance2 (GTS_POINT (GTS_SEGMENT (e)->v1), - GTS_POINT (GTS_SEGMENT (e)->v2)); -} - -static void create_heap_coarsen (GtsEdge * e, GtsEHeap * heap) -{ - HEAP_INSERT_EDGE (heap, e); -} - -/** - * gts_surface_coarsen: - * @surface: a #GtsSurface. - * @cost_func: a function returning the cost for a given edge. - * @cost_data: user data to be passed to @cost_func. - * @coarsen_func: a #GtsCoarsenVertexFunc. - * @coarsen_data: user data to be passed to @coarsen_func. - * @stop_func: a #GtsStopFunc. - * @stop_data: user data to be passed to @stop_func. - * @minangle: minimum angle between two neighboring triangles. - * - * The edges of @surface are sorted according to @cost_func to - * create a priority heap (a #GtsEHeap). The edges are extracted in - * turn from the top of the heap and collapsed (i.e. the vertices are - * replaced by the vertex returned by the @coarsen_func function) - * until the @stop_func functions returns %TRUE. - * - * If @cost_func is set to %NULL, the edges are sorted according - * to their length squared (the shortest is on top). - * - * If @coarsen_func is set to %NULL gts_segment_midvertex() is used. - * - * The minimum angle is used to avoid introducing faces which would be folded. - */ -void gts_surface_coarsen (GtsSurface * surface, - GtsKeyFunc cost_func, - gpointer cost_data, - GtsCoarsenFunc coarsen_func, - gpointer coarsen_data, - GtsStopFunc stop_func, - gpointer stop_data, - gdouble minangle) -{ - GtsEHeap * heap; - GtsEdge * e; - gdouble top_cost; - gdouble maxcosine2; - - g_return_if_fail (surface != NULL); - g_return_if_fail (stop_func != NULL); - - if (cost_func == NULL) - cost_func = (GtsKeyFunc) edge_length2; - if (coarsen_func == NULL) - coarsen_func = (GtsCoarsenFunc) gts_segment_midvertex; - - heap = gts_eheap_new (cost_func, cost_data); - maxcosine2 = cos (minangle); maxcosine2 *= maxcosine2; - - gts_eheap_freeze (heap); - gts_surface_foreach_edge (surface, (GtsFunc) create_heap_coarsen, heap); - gts_eheap_thaw (heap); - /* we want to control edge destruction manually */ - gts_allow_floating_edges = TRUE; - while ((e = gts_eheap_remove_top (heap, &top_cost)) && - (top_cost < G_MAXDOUBLE) && - !(*stop_func) (top_cost, gts_eheap_size (heap) - - gts_edge_face_number (e, surface), stop_data)) - { - GtsVertex * v = edge_collapse (e, heap, coarsen_func, coarsen_data, - surface->vertex_class, maxcosine2); - if (v != NULL) - update_2nd_closest_neighbors (v, heap); - } - gts_allow_floating_edges = FALSE; - - /* set reserved field of remaining edges back to NULL */ - if (e) GTS_OBJECT (e)->reserved = NULL; - gts_eheap_foreach (heap, (GFunc) gts_object_reset_reserved, NULL); - - gts_eheap_destroy (heap); -} - -/** - * gts_coarsen_stop_number: - * @cost: the cost of the edge collapse considered. - * @nedge: the current number of edges of the surface being simplified. - * @min_number: a pointer to the minimum number of edges desired for the - * surface being simplified. - * - * This function is to be used as the @stop_func argument of - * gts_surface_coarsen() or gts_psurface_new(). - * - * Returns: %TRUE if the edge collapse would create a surface with a smaller - * number of edges than given by @min_number, %FALSE otherwise. - */ -gboolean gts_coarsen_stop_number (gdouble cost, - guint nedge, - guint * min_number) -{ - g_return_val_if_fail (min_number != NULL, TRUE); - - if (nedge < *min_number) - return TRUE; - return FALSE; -} - -/** - * gts_coarsen_stop_cost: - * @cost: the cost of the edge collapse considered. - * @nedge: the current number of edges of the surface being simplified. - * @max_cost: a pointer to the maximum cost allowed for an edge collapse. - * - * This function is to be used as the @stop_func argument of - * gts_surface_coarsen() or gts_psurface_new(). - * - * Returns: %TRUE if the cost of the edge collapse considered is larger than - * given by @max_cost, %FALSE otherwise. - */ -gboolean gts_coarsen_stop_cost (gdouble cost, - guint nedge, - gdouble * max_cost) -{ - g_return_val_if_fail (max_cost != NULL, TRUE); - - if (cost > *max_cost) - return TRUE; - return FALSE; -} - -#define GTS_M_ICOSAHEDRON_X /* sqrt(sqrt(5)+1)/sqrt(2*sqrt(5)) */ \ - 0.850650808352039932181540497063011072240401406 -#define GTS_M_ICOSAHEDRON_Y /* sqrt(2)/sqrt(5+sqrt(5)) */ \ - 0.525731112119133606025669084847876607285497935 -#define GTS_M_ICOSAHEDRON_Z 0.0 - -static guint generate_icosahedron (GtsSurface * s) -{ - GtsVertex * v01 = gts_vertex_new (s->vertex_class, - +GTS_M_ICOSAHEDRON_Z, +GTS_M_ICOSAHEDRON_X, -GTS_M_ICOSAHEDRON_Y); - GtsVertex * v02 = gts_vertex_new (s->vertex_class, - +GTS_M_ICOSAHEDRON_X, +GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z); - GtsVertex * v03 = gts_vertex_new (s->vertex_class, - +GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z, -GTS_M_ICOSAHEDRON_X); - GtsVertex * v04 = gts_vertex_new (s->vertex_class, - +GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z, +GTS_M_ICOSAHEDRON_X); - GtsVertex * v05 = gts_vertex_new (s->vertex_class, - +GTS_M_ICOSAHEDRON_X, -GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z); - GtsVertex * v06 = gts_vertex_new (s->vertex_class, - +GTS_M_ICOSAHEDRON_Z, +GTS_M_ICOSAHEDRON_X, +GTS_M_ICOSAHEDRON_Y); - GtsVertex * v07 = gts_vertex_new (s->vertex_class, - -GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z, +GTS_M_ICOSAHEDRON_X); - GtsVertex * v08 = gts_vertex_new (s->vertex_class, - +GTS_M_ICOSAHEDRON_Z, -GTS_M_ICOSAHEDRON_X, -GTS_M_ICOSAHEDRON_Y); - GtsVertex * v09 = gts_vertex_new (s->vertex_class, - -GTS_M_ICOSAHEDRON_X, +GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z); - GtsVertex * v10 = gts_vertex_new (s->vertex_class, - -GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z, -GTS_M_ICOSAHEDRON_X); - GtsVertex * v11 = gts_vertex_new (s->vertex_class, - -GTS_M_ICOSAHEDRON_X, -GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z); - GtsVertex * v12 = gts_vertex_new (s->vertex_class, - +GTS_M_ICOSAHEDRON_Z, -GTS_M_ICOSAHEDRON_X, +GTS_M_ICOSAHEDRON_Y); - - GtsEdge * e01 = gts_edge_new (s->edge_class, v01, v02); - GtsEdge * e02 = gts_edge_new (s->edge_class, v03, v02); - GtsEdge * e03 = gts_edge_new (s->edge_class, v01, v03); - GtsEdge * e04 = gts_edge_new (s->edge_class, v04, v05); - GtsEdge * e05 = gts_edge_new (s->edge_class, v02, v05); - GtsEdge * e06 = gts_edge_new (s->edge_class, v04, v02); - GtsEdge * e07 = gts_edge_new (s->edge_class, v06, v07); - GtsEdge * e08 = gts_edge_new (s->edge_class, v04, v07); - GtsEdge * e09 = gts_edge_new (s->edge_class, v06, v04); - GtsEdge * e10 = gts_edge_new (s->edge_class, v08, v03); - GtsEdge * e11 = gts_edge_new (s->edge_class, v03, v05); - GtsEdge * e12 = gts_edge_new (s->edge_class, v08, v05); - GtsEdge * e13 = gts_edge_new (s->edge_class, v06, v09); - GtsEdge * e14 = gts_edge_new (s->edge_class, v07, v09); - GtsEdge * e15 = gts_edge_new (s->edge_class, v08, v10); - GtsEdge * e16 = gts_edge_new (s->edge_class, v03, v10); - GtsEdge * e17 = gts_edge_new (s->edge_class, v06, v01); - GtsEdge * e18 = gts_edge_new (s->edge_class, v01, v09); - GtsEdge * e19 = gts_edge_new (s->edge_class, v08, v11); - GtsEdge * e20 = gts_edge_new (s->edge_class, v10, v11); - GtsEdge * e21 = gts_edge_new (s->edge_class, v06, v02); - GtsEdge * e22 = gts_edge_new (s->edge_class, v12, v11); - GtsEdge * e23 = gts_edge_new (s->edge_class, v12, v08); - GtsEdge * e24 = gts_edge_new (s->edge_class, v12, v07); - GtsEdge * e25 = gts_edge_new (s->edge_class, v07, v11); - GtsEdge * e26 = gts_edge_new (s->edge_class, v12, v04); - GtsEdge * e27 = gts_edge_new (s->edge_class, v09, v11); - GtsEdge * e28 = gts_edge_new (s->edge_class, v10, v09); - GtsEdge * e29 = gts_edge_new (s->edge_class, v12, v05); - GtsEdge * e30 = gts_edge_new (s->edge_class, v01, v10); - - gts_surface_add_face (s, gts_face_new (s->face_class, e01, e02, e03)); - gts_surface_add_face (s, gts_face_new (s->face_class, e04, e05, e06)); - gts_surface_add_face (s, gts_face_new (s->face_class, e07, e08, e09)); - gts_surface_add_face (s, gts_face_new (s->face_class, e10, e11, e12)); - gts_surface_add_face (s, gts_face_new (s->face_class, e13, e14, e07)); - gts_surface_add_face (s, gts_face_new (s->face_class, e15, e16, e10)); - gts_surface_add_face (s, gts_face_new (s->face_class, e17, e18, e13)); - gts_surface_add_face (s, gts_face_new (s->face_class, e19, e20, e15)); - gts_surface_add_face (s, gts_face_new (s->face_class, e21, e01, e17)); - gts_surface_add_face (s, gts_face_new (s->face_class, e22, e19, e23)); - gts_surface_add_face (s, gts_face_new (s->face_class, e09, e06, e21)); - gts_surface_add_face (s, gts_face_new (s->face_class, e24, e25, e22)); - gts_surface_add_face (s, gts_face_new (s->face_class, e26, e08, e24)); - gts_surface_add_face (s, gts_face_new (s->face_class, e20, e27, e28)); - gts_surface_add_face (s, gts_face_new (s->face_class, e29, e04, e26)); - gts_surface_add_face (s, gts_face_new (s->face_class, e14, e27, e25)); - gts_surface_add_face (s, gts_face_new (s->face_class, e23, e12, e29)); - gts_surface_add_face (s, gts_face_new (s->face_class, e02, e05, e11)); - gts_surface_add_face (s, gts_face_new (s->face_class, e30, e28, e18)); - gts_surface_add_face (s, gts_face_new (s->face_class, e03, e16, e30)); - - return 0; -} - -static GtsVertex * unit_sphere_arc_midvertex (GtsSegment * s, - GtsVertexClass * vertex_class) -{ - GtsPoint * p1, * p2; - gdouble x, y, z, norm; - - p1 = GTS_POINT (s->v1); p2 = GTS_POINT (s->v2); - - x = 0.5*(p1->x + p2->x); - y = 0.5*(p1->y + p2->y); - z = 0.5*(p1->z + p2->z); - - norm = x*x + y*y + z*z; - norm = sqrt (norm); - - x /= norm; y /= norm; z /= norm; - - return gts_vertex_new (vertex_class, x, y, z); -} - -static void tessellate_face (GtsFace * f, - GtsSurface * s, - GtsRefineFunc refine_func, - gpointer refine_data, - GtsVertexClass * vertex_class, - GtsEdgeClass * edge_class) -{ - GtsTriangle * t; - GtsEdge * e1, * e2, * e3; /* former edges */ - GtsVertex * v1, * v2, * v3; /* initial vertices */ - GtsVertex * v4, * v5, * v6; /* new vertices */ - GtsEdge * e56, * e64, * e45; /* new inside edges */ - GtsEdge * e24, * e34, * e35, * e15, * e16, * e26; /* new border edges */ - GSList * dum; - GtsEdge * edum; - - t = GTS_TRIANGLE (f); - e1 = t->e1; e2 = t->e2; e3 = t->e3; - - if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v1) { - v1 = GTS_SEGMENT (e2)->v2; - v2 = GTS_SEGMENT (e1)->v1; - v3 = GTS_SEGMENT (e1)->v2; - } - else if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v2) { - v1 = GTS_SEGMENT (e2)->v1; - v2 = GTS_SEGMENT (e1)->v1; - v3 = GTS_SEGMENT (e1)->v2; - } - else if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v1) { - v1 = GTS_SEGMENT (e2)->v2; - v2 = GTS_SEGMENT (e1)->v2; - v3 = GTS_SEGMENT (e1)->v1; - } - else if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v2) { - v1 = GTS_SEGMENT (e2)->v1; - v2 = GTS_SEGMENT (e1)->v2; - v3 = GTS_SEGMENT (e1)->v1; - } - else { - v1 = v2 = v3 = NULL; - g_assert_not_reached (); - } - - e1->triangles = g_slist_remove (e1->triangles, t); - e2->triangles = g_slist_remove (e2->triangles, t); - e3->triangles = g_slist_remove (e3->triangles, t); - - if (GTS_OBJECT (e1)->reserved) { - dum = (GTS_OBJECT (e1)->reserved); - e24 = dum->data; - e34 = dum->next->data; - v4 = GTS_SEGMENT (e24)->v2; - if (GTS_SEGMENT (e24)->v1 == v3) { - edum = e34; e34 = e24; e24 = edum; - } - } - else { - v4 = (*refine_func) (e1, vertex_class, refine_data); - e24 = gts_edge_new (edge_class, v2, v4); - e34 = gts_edge_new (edge_class, v3, v4); - dum = g_slist_append (NULL, e24); - dum = g_slist_append (dum, e34); - GTS_OBJECT (e1)->reserved = dum; - } - if (GTS_OBJECT (e2)->reserved) { - dum = (GTS_OBJECT (e2)->reserved); - e35 = dum->data; - e15 = dum->next->data; - v5 = GTS_SEGMENT (e35)->v2; - if (GTS_SEGMENT (e35)->v1 == v1) { - edum = e15; e15 = e35; e35 = edum; - } - } - else { - v5 = (*refine_func) (e2, vertex_class, refine_data); - e35 = gts_edge_new (edge_class, v3, v5); - e15 = gts_edge_new (edge_class, v1, v5); - dum = g_slist_append (NULL, e35); - dum = g_slist_append (dum, e15); - GTS_OBJECT (e2)->reserved = dum; - } - if (GTS_OBJECT (e3)->reserved) { - dum = (GTS_OBJECT (e3)->reserved); - e16 = dum->data; - e26 = dum->next->data; - v6 = GTS_SEGMENT (e16)->v2; - if (GTS_SEGMENT (e16)->v1 == v2) { - edum = e16; e16 = e26; e26 = edum; - } - } - else { - v6 = (*refine_func) (e3, vertex_class, refine_data); - e16 = gts_edge_new (edge_class, v1, v6); - e26 = gts_edge_new (edge_class, v2, v6); - dum = g_slist_append (NULL, e16); - dum = g_slist_append (dum, e26); - GTS_OBJECT (e3)->reserved = dum; - } - - if (e1->triangles == NULL) { - g_slist_free (GTS_OBJECT (e1)->reserved); - GTS_OBJECT (e1)->reserved = NULL; - gts_object_destroy (GTS_OBJECT (e1)); - e1 = NULL; - } - if (e2->triangles == NULL) { - g_slist_free (GTS_OBJECT (e2)->reserved); - GTS_OBJECT (e2)->reserved = NULL; - gts_object_destroy (GTS_OBJECT (e2)); - e2 = NULL; - } - if (e3->triangles == NULL) { - g_slist_free (GTS_OBJECT (e3)->reserved); - GTS_OBJECT (e3)->reserved = NULL; - gts_object_destroy (GTS_OBJECT (e3)); - e3 = NULL; - } - - e56 = gts_edge_new (edge_class, v5, v6); - e64 = gts_edge_new (edge_class, v6, v4); - e45 = gts_edge_new (edge_class, v4, v5); - t->e1 = e56; e56->triangles = g_slist_prepend (e56->triangles, t); - t->e2 = e64; e64->triangles = g_slist_prepend (e64->triangles, t); - t->e3 = e45; e45->triangles = g_slist_prepend (e45->triangles, t); - - gts_surface_add_face (s, gts_face_new (s->face_class, e16, e56, e15)); - gts_surface_add_face (s, gts_face_new (s->face_class, e26, e24, e64)); - gts_surface_add_face (s, gts_face_new (s->face_class, e45, e34, e35)); -} - -static void create_array_tessellate (GtsFace * f, GPtrArray * array) -{ - g_ptr_array_add (array, f); -} - -/** - * gts_surface_tessellate: - * @s: a #GtsSurface. - * @refine_func: a #GtsRefineFunc. - * @refine_data: user data to be passed to @refine_func. - * - * Tessellate each triangle of @s with 4 triangles: - * the number of triangles is increased by a factor of 4. - * http://mathworld.wolfram.com/GeodesicDome.html - * - * If @refine_func is set to %NULL a mid arc function is used: if - * the surface is a polyhedron with the unit sphere as circum sphere, - * then gts_surface_tessellate() corresponds to a geodesation step - * (see gts_surface_generate_sphere()). - * - */ -void gts_surface_tessellate (GtsSurface * s, - GtsRefineFunc refine_func, - gpointer refine_data) -{ - GPtrArray * array; - guint i; - - g_return_if_fail (s != NULL); - - if (refine_func == NULL) /* tessellate_surface == geodesate_surface */ - refine_func = (GtsRefineFunc) unit_sphere_arc_midvertex; - - array = g_ptr_array_new (); - gts_surface_foreach_face (s, (GtsFunc) create_array_tessellate, array); - for(i = 0; i < array->len; i++) - tessellate_face (g_ptr_array_index (array, i), - s, refine_func, refine_data, - s->vertex_class, s->edge_class); - g_ptr_array_free (array, TRUE); -} - -/** - * gts_surface_generate_sphere: - * @s: a #GtsSurface. - * @geodesation_order: a #guint. - * - * Add a triangulated unit sphere generated by recursive subdivision to @s. - * First approximation is an isocahedron; each level of refinement - * (@geodesation_order) increases the number of triangles by a factor of 4. - * http://mathworld.wolfram.com/GeodesicDome.html - * - * Returns: @s. - */ -GtsSurface * gts_surface_generate_sphere (GtsSurface * s, - guint geodesation_order) -{ - guint cgo; - - g_return_val_if_fail (s != NULL, NULL); - g_return_val_if_fail (geodesation_order != 0, NULL); - - generate_icosahedron (s); - - for (cgo = 1; cgo < geodesation_order; cgo++) - gts_surface_tessellate (s, NULL, NULL); - - return s; -} - -static void foreach_vertex_copy (GtsPoint * p, GtsVertexClass * klass) -{ - GTS_OBJECT (p)->reserved = gts_vertex_new (klass, p->x, p->y, p->z); -} - -static void foreach_edge_copy (GtsSegment * s, GtsEdgeClass * klass) -{ - GTS_OBJECT (s)->reserved = gts_edge_new (klass, - GTS_OBJECT (s->v1)->reserved, - GTS_OBJECT (s->v2)->reserved); -} - -static void foreach_face_copy (GtsTriangle * t, - GtsSurface * s) -{ - gts_surface_add_face (s, gts_face_new (s->face_class, - GTS_OBJECT (t->e1)->reserved, - GTS_OBJECT (t->e2)->reserved, - GTS_OBJECT (t->e3)->reserved)); -} - -/** - * gts_surface_copy: - * @s1: a #GtsSurface. - * @s2: a #GtsSurface. - * - * Add a copy of all the faces, edges and vertices of @s2 to @s1. - * - * Returns: @s1. - */ -GtsSurface * gts_surface_copy (GtsSurface * s1, GtsSurface * s2) -{ - g_return_val_if_fail (s1 != NULL, NULL); - g_return_val_if_fail (s2 != NULL, NULL); - - gts_surface_foreach_vertex (s2, (GtsFunc) foreach_vertex_copy, - s1->vertex_class); - gts_surface_foreach_edge (s2, (GtsFunc) foreach_edge_copy, s1->edge_class); - gts_surface_foreach_face (s2, (GtsFunc) foreach_face_copy, s1); - - gts_surface_foreach_vertex (s2, (GtsFunc) gts_object_reset_reserved, NULL); - gts_surface_foreach_edge (s2, (GtsFunc) gts_object_reset_reserved, NULL); - - return s1; -} - -static void merge_foreach_face (GtsFace * f, - GtsSurface * s) -{ - gts_surface_add_face (s, f); -} - -/** - * gts_surface_merge: - * @s: a #GtsSurface. - * @with: another #GtsSurface. - * - * Adds all the faces of @with which do not already belong to @s - * to @s. - */ -void gts_surface_merge (GtsSurface * s, GtsSurface * with) -{ - g_return_if_fail (s != NULL); - g_return_if_fail (with != NULL); - - gts_surface_foreach_face (with, (GtsFunc) merge_foreach_face, s); -} - -static void manifold_foreach_edge (GtsEdge * e, gpointer * data) -{ - gboolean * is_manifold = data[0]; - - if (*is_manifold) { - if (gts_edge_face_number (e, data[1]) > 2) - *is_manifold = FALSE; - } -} - -/** - * gts_surface_is_manifold: - * @s: a #GtsSurface. - * - * Returns: %TRUE if the surface is a manifold, %FALSE otherwise. - */ -gboolean gts_surface_is_manifold (GtsSurface * s) -{ - gboolean is_manifold = TRUE; - gpointer data[2]; - - g_return_val_if_fail (s != NULL, FALSE); - - data[0] = &is_manifold; - data[1] = s; - gts_surface_foreach_edge (s, (GtsFunc) manifold_foreach_edge, data); - return is_manifold; -} - -static void closed_foreach_edge (GtsEdge * e, gpointer * data) -{ - gboolean * is_closed = data[0]; - - if (*is_closed) { - if (gts_edge_face_number (e, data[1]) != 2) - *is_closed = FALSE; - } -} - -/** - * gts_surface_is_closed: - * @s: a #GtsSurface. - * - * Returns: %TRUE if @s is a closed surface, %FALSE otherwise. Note that a - * closed surface is also a manifold. - */ -gboolean gts_surface_is_closed (GtsSurface * s) -{ - gboolean is_closed = TRUE; - gpointer data[2]; - - g_return_val_if_fail (s != NULL, FALSE); - - data[0] = &is_closed; - data[1] = s; - gts_surface_foreach_edge (s, (GtsFunc) closed_foreach_edge, data); - return is_closed; -} - -static void orientable_foreach_edge (GtsEdge * e, gpointer * data) -{ - gboolean * is_orientable = data[0]; - - if (*is_orientable) { - GtsSurface * surface = data[1]; - GtsFace * f1 = NULL, * f2 = NULL; - GSList * i = e->triangles; - while (i && *is_orientable) { - GtsFace * f = i->data; - if (GTS_IS_FACE (f) && gts_face_has_parent_surface (f, surface)) { - if (!f1) f1 = f; - else if (!f2) f2 = f; - else *is_orientable = FALSE; - } - i = i->next; - } - if (f1 && f2 && !gts_triangles_are_compatible (GTS_TRIANGLE (f1), - GTS_TRIANGLE (f2), e)) - *is_orientable = FALSE; - } -} - -/** - * gts_surface_is_orientable: - * @s: a #GtsSurface. - * - * Returns: %TRUE if all the faces of @s have compatible orientation - * as checked by gts_faces_are_compatible(), %FALSE otherwise. Note that - * an orientable surface is also a manifold. - */ -gboolean gts_surface_is_orientable (GtsSurface * s) -{ - gboolean is_orientable = TRUE; - gpointer data[2]; - - g_return_val_if_fail (s != NULL, FALSE); - - data[0] = &is_orientable; - data[1] = s; - gts_surface_foreach_edge (s, (GtsFunc) orientable_foreach_edge, data); - return is_orientable; -} - -static void volume_foreach_face (GtsTriangle * t, - gdouble * volume) -{ - GtsVertex * va, * vb, * vc; - GtsPoint * pa, * pb, * pc; - - gts_triangle_vertices (t, &va, &vb, &vc); - pa = GTS_POINT (va); - pb = GTS_POINT (vb); - pc = GTS_POINT (vc); - - *volume += (pa->x * (pb->y * pc->z - pb->z * pc->y) + - pb->x * (pc->y * pa->z - pc->z * pa->y) + - pc->x * (pa->y * pb->z - pa->z * pb->y)); -} - -/** - * gts_surface_volume: - * @s: a #GtsSurface. - * - * Returns: the signed volume of the domain bounded by the surface @s. It - * makes sense only if @s is a closed and orientable manifold. - */ -gdouble gts_surface_volume (GtsSurface * s) -{ - gdouble volume = 0.0; - - g_return_val_if_fail (s != NULL, 0.0); - - gts_surface_foreach_face (s, (GtsFunc) volume_foreach_face, &volume); - - return volume/6.; -} - -static void center_of_mass_foreach_face (GtsTriangle * t, - gpointer * data) -{ - GtsVertex * v1, * v2, * v3; - GtsPoint * p1, * p2, * p3; - gdouble x1, y1, z1, x2, y2, z2, nx, ny, nz; - gdouble * volume = data[0]; - gdouble * cm = data[1]; - - gts_triangle_vertices (t, &v1, &v2, &v3); - p1 = GTS_POINT (v1); - p2 = GTS_POINT (v2); - p3 = GTS_POINT (v3); - - x1 = p2->x - p1->x; - y1 = p2->y - p1->y; - z1 = p2->z - p1->z; - - x2 = p3->x - p1->x; - y2 = p3->y - p1->y; - z2 = p3->z - p1->z; - - nx = y1*z2 - z1*y2; - ny = z1*x2 - x1*z2; - nz = x1*y2 - y1*x2; - - cm[0] += nx*(p1->x*p1->x + p2->x*p2->x + p3->x*p3->x + - p1->x*p2->x + p1->x*p3->x + p2->x*p3->x); - cm[1] += ny*(p1->y*p1->y + p2->y*p2->y + p3->y*p3->y + - p1->y*p2->y + p1->y*p3->y + p2->y*p3->y); - cm[2] += nz*(p1->z*p1->z + p2->z*p2->z + p3->z*p3->z + - p1->z*p2->z + p1->z*p3->z + p2->z*p3->z); - - *volume += nx*(p1->x + p2->x + p3->x); -} - - -/** - * gts_surface_center_of_mass: - * @s: a #GtsSurface. - * @cm: a #GtsVector. - * - * Fills @cm with the coordinates of the center of mass of @s. - * - * Returns: the signed volume of the domain bounded by the surface @s. - */ -gdouble gts_surface_center_of_mass (GtsSurface * s, - GtsVector cm) -{ - gdouble volume = 0.; - gpointer data[2]; - - g_return_val_if_fail (s != NULL, 0.0); - - data[0] = &volume; - data[1] = &(cm[0]); - cm[0] = cm[1] = cm[2] = 0.; - gts_surface_foreach_face (s, (GtsFunc) center_of_mass_foreach_face, data); - - if (volume != 0.) { - cm[0] /= 4.*volume; - cm[1] /= 4.*volume; - cm[2] /= 4.*volume; - } - - return volume/6.; -} - -static void center_of_area_foreach_face (GtsTriangle * t, - gpointer * data) -{ - GtsVertex * v1, * v2, * v3; - GtsPoint * p1, * p2, * p3; - gdouble a; - gdouble * area = data[0]; - gdouble * cm = data[1]; - - gts_triangle_vertices (t, &v1, &v2, &v3); - p1 = GTS_POINT (v1); - p2 = GTS_POINT (v2); - p3 = GTS_POINT (v3); - - a = gts_triangle_area (t); - cm[0] += a*(p1->x + p2->x + p3->x); - cm[1] += a*(p1->y + p2->y + p3->y); - cm[2] += a*(p1->z + p2->z + p3->z); - *area += a; -} - - -/** - * gts_surface_center_of_area: - * @s: a #GtsSurface. - * @cm: a #GtsVector. - * - * Fills @cm with the coordinates of the center of area of @s. - * - * Returns: the area of surface @s. - */ -gdouble gts_surface_center_of_area (GtsSurface * s, - GtsVector cm) -{ - gdouble area = 0.; - gpointer data[2]; - - g_return_val_if_fail (s != NULL, 0.0); - - data[0] = &area; - data[1] = &(cm[0]); - cm[0] = cm[1] = cm[2] = 0.; - gts_surface_foreach_face (s, (GtsFunc) center_of_area_foreach_face, data); - - if (area != 0.) { - cm[0] /= 3.*area; - cm[1] /= 3.*area; - cm[2] /= 3.*area; - } - - return area; -} - -static void number_foreach (gpointer data, guint * n) -{ - (*n)++; -} - -/** - * gts_surface_vertex_number: - * @s: a #GtsSurface. - * - * Returns: the number of vertices of @s. - */ -guint gts_surface_vertex_number (GtsSurface * s) -{ - guint n = 0; - - g_return_val_if_fail (s != NULL, 0); - - gts_surface_foreach_vertex (s, (GtsFunc) number_foreach, &n); - - return n; -} - -/** - * gts_surface_edge_number: - * @s: a #GtsSurface. - * - * Returns: the number of edges of @s. - */ -guint gts_surface_edge_number (GtsSurface * s) -{ - guint n = 0; - - g_return_val_if_fail (s != NULL, 0); - - gts_surface_foreach_edge (s, (GtsFunc) number_foreach, &n); - - return n; -} - -/** - * gts_surface_face_number: - * @s: a #GtsSurface. - * - * Returns: the number of faces of @s - */ -guint gts_surface_face_number (GtsSurface * s) -{ - g_return_val_if_fail (s != NULL, 0); - -#ifdef USE_SURFACE_BTREE - return g_tree_nnodes (s->faces); -#else /* not USE_SURFACE_BTREE */ - return g_hash_table_size (s->faces); -#endif /* not USE_SURFACE_BTREE */ -} - -static void build_list_face (GtsTriangle * t, GSList ** list) -{ - *list = g_slist_prepend (*list, gts_bbox_triangle (gts_bbox_class (), t)); -} - -static void build_list_boundary (GtsEdge * e, GSList ** list) -{ - if (gts_edge_is_boundary (e, NULL)) - *list = g_slist_prepend (*list, gts_bbox_segment (gts_bbox_class (), - GTS_SEGMENT (e))); -} - -/** - * gts_surface_distance: - * @s1: a #GtsSurface. - * @s2: a #GtsSurface. - * @delta: a spatial increment defined as the percentage of the diagonal - * of the bounding box of @s2. - * @face_range: a #GtsRange. - * @boundary_range: a #GtsRange. - * - * Using the gts_bb_tree_surface_distance() and - * gts_bb_tree_surface_boundary_distance() functions fills @face_range - * and @boundary_range with the min, max and average Euclidean - * (minimum) distances between the faces of @s1 and the faces of @s2 - * and between the boundary edges of @s1 and @s2. - */ -void gts_surface_distance (GtsSurface * s1, GtsSurface * s2, gdouble delta, - GtsRange * face_range, GtsRange * boundary_range) -{ - GNode * face_tree, * boundary_tree; - GSList * bboxes; - - g_return_if_fail (s1 != NULL); - g_return_if_fail (s2 != NULL); - g_return_if_fail (delta > 0. && delta < 1.); - g_return_if_fail (face_range != NULL); - g_return_if_fail (boundary_range != NULL); - - bboxes = NULL; - gts_surface_foreach_face (s2, (GtsFunc) build_list_face, &bboxes); - if (bboxes != NULL) { - face_tree = gts_bb_tree_new (bboxes); - g_slist_free (bboxes); - - gts_bb_tree_surface_distance (face_tree, s1, - (GtsBBoxDistFunc) gts_point_triangle_distance, - delta, face_range); - gts_bb_tree_destroy (face_tree, TRUE); - - bboxes = NULL; - gts_surface_foreach_edge (s2, (GtsFunc) build_list_boundary, &bboxes); - if (bboxes != NULL) { - boundary_tree = gts_bb_tree_new (bboxes); - g_slist_free (bboxes); - - gts_bb_tree_surface_boundary_distance (boundary_tree, - s1, - (GtsBBoxDistFunc) gts_point_segment_distance, - delta, boundary_range); - gts_bb_tree_destroy (boundary_tree, TRUE); - } - else - gts_range_reset (boundary_range); - } - else { - gts_range_reset (face_range); - gts_range_reset (boundary_range); - } -} - -static void surface_boundary (GtsEdge * e, gpointer * data) -{ - GSList ** list = data[0]; - - if (gts_edge_is_boundary (e, data[1])) - *list = g_slist_prepend (*list, e); -} - -/** - * gts_surface_boundary: - * @surface: a #GtsSurface. - * - * Returns: a list of #GtsEdge boundary of @surface. - */ -GSList * gts_surface_boundary (GtsSurface * surface) -{ - GSList * list = NULL; - gpointer data[2]; - - g_return_val_if_fail (surface != NULL, NULL); - - data[0] = &list; - data[1] = surface; - gts_surface_foreach_edge (surface, (GtsFunc) surface_boundary, data); - - return list; -} - -struct _GtsSurfaceTraverse { - GtsFifo * q; - GtsSurface * s; -}; - -/** - * gts_surface_traverse_new: - * @s: a #GtsSurface. - * @f: a #GtsFace belonging to @s. - * - * Returns: a new #GtsSurfaceTraverse, initialized to start traversing - * from face @f of surface @s. - */ -GtsSurfaceTraverse * gts_surface_traverse_new (GtsSurface * s, - GtsFace * f) -{ - GtsSurfaceTraverse * t; - - g_return_val_if_fail (s != NULL, NULL); - g_return_val_if_fail (f != NULL, NULL); - g_return_val_if_fail (gts_face_has_parent_surface (f, s), NULL); - - t = g_malloc (sizeof (GtsSurfaceTraverse)); - t->q = gts_fifo_new (); - t->s = s; - GTS_OBJECT (f)->reserved = GUINT_TO_POINTER (1); - gts_fifo_push (t->q, f); - return t; -} - -static void push_neighbor (GtsFace * v, gpointer * data) -{ - if (!GTS_OBJECT (v)->reserved) { - GTS_OBJECT (v)->reserved = - GUINT_TO_POINTER (GPOINTER_TO_UINT (GTS_OBJECT (data[1])->reserved) + 1); - gts_fifo_push (data[0], v); - } -} - -/** - * gts_surface_traverse_next: - * @t: a #GtsSurfaceTraverse. - * @level: a pointer to a guint or %NULL. - * - * Returns: the next face of the traversal in breadth-first order or - * %NULL if no faces are left. If @level if not %NULL, it is filled - * with the level of the returned face (0 for the initial face, 1 for - * its neighbors and so on). - */ -GtsFace * gts_surface_traverse_next (GtsSurfaceTraverse * t, - guint * level) -{ - GtsFace * u; - - g_return_val_if_fail (t != NULL, NULL); - - u = gts_fifo_pop (t->q); - if (u) { - gpointer data[2]; - - if (level) - *level = GPOINTER_TO_UINT (GTS_OBJECT (u)->reserved); - data[0] = t->q; - data[1] = u; - gts_face_foreach_neighbor (u, t->s, (GtsFunc) push_neighbor, data); - } - return u; -} - -/** - * gts_surface_traverse_destroy: - * @t: a #GtsSurfaceTraverse. - * - * Frees all the memory allocated for @t. - */ -void gts_surface_traverse_destroy (GtsSurfaceTraverse * t) -{ - g_return_if_fail (t != NULL); - - gts_surface_foreach_face (t->s, (GtsFunc) gts_object_reset_reserved, NULL); - gts_fifo_destroy (t->q); - g_free (t); -} - -static void traverse_manifold (GtsTriangle * t, GtsSurface * s) -{ - if (g_slist_length (GTS_FACE (t)->surfaces) > 1) - return; - - gts_surface_add_face (s, GTS_FACE (t)); - if (g_slist_length (t->e1->triangles) == 2) { - if (t->e1->triangles->data != t) - traverse_manifold (t->e1->triangles->data, s); - else - traverse_manifold (t->e1->triangles->next->data, s); - } - if (g_slist_length (t->e2->triangles) == 2) { - if (t->e2->triangles->data != t) - traverse_manifold (t->e2->triangles->data, s); - else - traverse_manifold (t->e2->triangles->next->data, s); - } - if (g_slist_length (t->e3->triangles) == 2) { - if (t->e3->triangles->data != t) - traverse_manifold (t->e3->triangles->data, s); - else - traverse_manifold (t->e3->triangles->next->data, s); - } -} - -static void non_manifold_edges (GtsEdge * e, gpointer * data) -{ - GtsSurface * s = data[0]; - GSList ** non_manifold = data[1]; - - if (gts_edge_face_number (e, s) > 2) { - GSList * i = e->triangles; - - while (i) { - if (gts_face_has_parent_surface (i->data, s) && - !g_slist_find (*non_manifold, i->data)) - *non_manifold = g_slist_prepend (*non_manifold, i->data); - i = i->next; - } - } -} - -static void traverse_boundary (GtsEdge * e, gpointer * data) -{ - GtsSurface * orig = data[0]; - GSList ** components = data[1]; - GtsFace * f = gts_edge_is_boundary (e, orig); - - if (f != NULL && g_slist_length (f->surfaces) == 1) { - GtsSurface * s = - gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (orig)->klass), - orig->face_class, - orig->edge_class, - orig->vertex_class); - GSList * non_manifold = NULL, * i; - gpointer data[2]; - - *components = g_slist_prepend (*components, s); - data[0] = s; - data[1] = &non_manifold; - traverse_manifold (GTS_TRIANGLE (f), s); - - gts_surface_foreach_edge (s, (GtsFunc) non_manifold_edges, data); - i = non_manifold; - while (i) { - gts_surface_remove_face (s, i->data); - i = i->next; - } - g_slist_free (non_manifold); - } -} - -static void traverse_remaining (GtsFace * f, gpointer * data) -{ - GtsSurface * orig = data[0]; - GSList ** components = data[1]; - - if (g_slist_length (f->surfaces) == 1) { - GtsSurface * s = - gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (orig)->klass), - orig->face_class, - orig->edge_class, - orig->vertex_class); - GSList * non_manifold = NULL, * i; - gpointer data[2]; - - *components = g_slist_prepend (*components, s); - data[0] = s; - data[1] = &non_manifold; - traverse_manifold (GTS_TRIANGLE (f), s); - - gts_surface_foreach_edge (s, (GtsFunc) non_manifold_edges, data); - i = non_manifold; - while (i) { - gts_surface_remove_face (s, i->data); - i = i->next; - } - g_slist_free (non_manifold); - } -} - -/** - * gts_surface_split: - * @s: a #GtsSurface. - * - * Splits a surface into connected and manifold components. - * - * Returns: a list of new #GtsSurface. - */ -GSList * gts_surface_split (GtsSurface * s) -{ - gpointer data[2]; - GSList * components = NULL; - - g_return_val_if_fail (s != NULL, NULL); - - data[0] = s; - data[1] = &components; - - /* boundary components */ - gts_surface_foreach_edge (s, (GtsFunc) traverse_boundary, data); - - /* remaining components */ - gts_surface_foreach_face (s, (GtsFunc) traverse_remaining, data); - - return components; -} Index: trunk/src_3rd/gts/predicates.h =================================================================== --- trunk/src_3rd/gts/predicates.h (revision 6802) +++ trunk/src_3rd/gts/predicates.h (nonexistent) @@ -1,41 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ -/* Header file for robust predicates by Jonathan Richard Shewchuk */ - -#ifndef __PREDICATES_H__ -#define __PREDICATES_H__ - -double orient2d (double * pa, - double * pb, - double * pc); -double orient3d (double * pa, - double * pb, - double * pc, - double * pd); -double incircle (double * pa, - double * pb, - double * pc, - double * pd); -double insphere (double * pa, - double * pb, - double * pc, - double * pd, - double * pe); - -#endif /* __PREDICATES_H__ */ Index: trunk/src_3rd/gts/iso.c =================================================================== --- trunk/src_3rd/gts/iso.c (revision 6802) +++ trunk/src_3rd/gts/iso.c (nonexistent) @@ -1,455 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "gts.h" - -typedef enum { LEFT = 0, RIGHT = 1 } Orientation; - -typedef struct { - GtsVertex * v; - Orientation orientation; -} OrientedVertex; - -struct _GtsIsoSlice { - OrientedVertex *** vertices; - guint nx, ny; -}; - -/* coordinates of the edges of the cube (see doc/isocube.fig) */ -static guint c[12][4] = { - {0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 1}, {0, 0, 1, 0}, - {1, 0, 0, 0}, {1, 0, 0, 1}, {1, 1, 0, 1}, {1, 1, 0, 0}, - {2, 0, 0, 0}, {2, 1, 0, 0}, {2, 1, 1, 0}, {2, 0, 1, 0}}; - -/* first index is the edge number, second index is the edge orientation - (RIGHT or LEFT), third index are the edges which this edge may connect to - in order */ -static guint edge[12][2][3] = { - {{9, 1, 8}, {4, 3, 7}}, /* 0 */ - {{6, 2, 5}, {8, 0, 9}}, /* 1 */ - {{10, 3, 11}, {5, 1, 6}}, /* 2 */ - {{7, 0, 4}, {11, 2, 10}}, /* 3 */ - {{3, 7, 0}, {8, 5, 11}}, /* 4 */ - {{11, 4, 8}, {1, 6, 2}}, /* 5 */ - {{2, 5, 1}, {9, 7, 10}}, /* 6 */ - {{10, 6, 9}, {0, 4, 3}}, /* 7 */ - {{5, 11, 4}, {0, 9, 1}}, /* 8 */ - {{1, 8, 0}, {7, 10, 6}}, /* 9 */ - {{6, 9, 7}, {3, 11, 2}}, /* 10 */ - {{2, 10, 3}, {4, 8, 5}} /* 11 */ -}; - -static void ** malloc2D (guint nx, guint ny, gulong size) -{ - void ** m = g_malloc (nx*sizeof (void *)); - guint i; - - for (i = 0; i < nx; i++) - m[i] = g_malloc0 (ny*size); - - return m; -} - -static void free2D (void ** m, guint nx) -{ - guint i; - - g_return_if_fail (m != NULL); - - for (i = 0; i < nx; i++) - g_free (m[i]); - g_free (m); -} - -/** - * gts_grid_plane_new: - * @nx: - * @ny: - * - * Returns: - */ -GtsGridPlane * gts_grid_plane_new (guint nx, guint ny) -{ - GtsGridPlane * g = g_malloc (sizeof (GtsGridPlane)); - - g->p = (GtsPoint **) malloc2D (nx, ny, sizeof (GtsPoint)); - g->nx = nx; - g->ny = ny; - - return g; -} - -/** - * gts_grid_plane_destroy: - * @g: - * - */ -void gts_grid_plane_destroy (GtsGridPlane * g) -{ - g_return_if_fail (g != NULL); - - free2D ((void **) g->p, g->nx); - g_free (g); -} - -/** - * gts_iso_slice_new: - * @nx: number of vertices in the x direction. - * @ny: number of vertices in the y direction. - * - * Returns: a new #GtsIsoSlice. - */ -GtsIsoSlice * gts_iso_slice_new (guint nx, guint ny) -{ - GtsIsoSlice * slice; - - g_return_val_if_fail (nx > 1, NULL); - g_return_val_if_fail (ny > 1, NULL); - - slice = g_malloc (sizeof (GtsIsoSlice)); - - slice->vertices = g_malloc (3*sizeof (OrientedVertex **)); - slice->vertices[0] = - (OrientedVertex **) malloc2D (nx, ny, sizeof (OrientedVertex)); - slice->vertices[1] = - (OrientedVertex **) malloc2D (nx - 1, ny, sizeof (OrientedVertex)); - slice->vertices[2] = - (OrientedVertex **) malloc2D (nx, ny - 1, sizeof (OrientedVertex)); - slice->nx = nx; - slice->ny = ny; - - return slice; -} - -/** - * gts_iso_slice_fill: - * @slice: a #GtsIsoSlice. - * @plane1: a #GtsGridPlane. - * @plane2: another #GtsGridPlane. - * @f1: values of the function corresponding to @plane1. - * @f2: values of the function corresponding to @plane2. - * @iso: isosurface value. - * @klass: a #GtsVertexClass or one of its descendant to be used for the - * new vertices. - * - * Fill @slice with the coordinates of the vertices defined by - * f1 (x,y,z) = @iso and f2 (x, y, z) = @iso. - */ -void gts_iso_slice_fill (GtsIsoSlice * slice, - GtsGridPlane * plane1, - GtsGridPlane * plane2, - gdouble ** f1, - gdouble ** f2, - gdouble iso, - GtsVertexClass * klass) -{ - OrientedVertex *** vertices; - GtsPoint ** p1, ** p2 = NULL; - guint i, j, nx, ny; - - g_return_if_fail (slice != NULL); - g_return_if_fail (plane1 != NULL); - g_return_if_fail (f1 != NULL); - g_return_if_fail (f2 == NULL || plane2 != NULL); - - p1 = plane1->p; - if (plane2) - p2 = plane2->p; - vertices = slice->vertices; - nx = slice->nx; - ny = slice->ny; - - if (f2) - for (i = 0; i < nx; i++) - for (j = 0; j < ny; j++) { - gdouble v1 = f1[i][j] - iso; - gdouble v2 = f2[i][j] - iso; - if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) { - gdouble c2 = v1/(v1 - v2), c1 = 1. - c2; - vertices[0][i][j].v = - gts_vertex_new (klass, - c1*p1[i][j].x + c2*p2[i][j].x, - c1*p1[i][j].y + c2*p2[i][j].y, - c1*p1[i][j].z + c2*p2[i][j].z); - vertices[0][i][j].orientation = v2 >= 0. ? RIGHT : LEFT; - } - else - vertices[0][i][j].v = NULL; - } - for (i = 0; i < nx - 1; i++) - for (j = 0; j < ny; j++) { - gdouble v1 = f1[i][j] - iso; - gdouble v2 = f1[i+1][j] - iso; - if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) { - gdouble c2 = v1/(v1 - v2), c1 = 1. - c2; - vertices[1][i][j].v = - gts_vertex_new (klass, - c1*p1[i][j].x + c2*p1[i+1][j].x, - c1*p1[i][j].y + c2*p1[i+1][j].y, - c1*p1[i][j].z + c2*p1[i+1][j].z); - vertices[1][i][j].orientation = v2 >= 0. ? RIGHT : LEFT; - } - else - vertices[1][i][j].v = NULL; - } - for (i = 0; i < nx; i++) - for (j = 0; j < ny - 1; j++) { - gdouble v1 = f1[i][j] - iso; - gdouble v2 = f1[i][j+1] - iso; - if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) { - gdouble c2 = v1/(v1 - v2), c1 = 1. - c2; - vertices[2][i][j].v = - gts_vertex_new (klass, - c1*p1[i][j].x + c2*p1[i][j+1].x, - c1*p1[i][j].y + c2*p1[i][j+1].y, - c1*p1[i][j].z + c2*p1[i][j+1].z); - vertices[2][i][j].orientation = v2 >= 0. ? RIGHT : LEFT; - } - else - vertices[2][i][j].v = NULL; - } -} - -/** - * gts_iso_slice_fill_cartesian: - * @slice: a #GtsIsoSlice. - * @g: a #GtsCartesianGrid. - * @f1: values of the function for plane z = @g.z. - * @f2: values of the function for plane z = @g.z + @g.dz. - * @iso: isosurface value. - * @klass: a #GtsVertexClass. - * - * Fill @slice with the coordinates of the vertices defined by - * f1 (x,y,z) = @iso and f2 (x, y, z) = @iso. - */ -void gts_iso_slice_fill_cartesian (GtsIsoSlice * slice, - GtsCartesianGrid g, - gdouble ** f1, - gdouble ** f2, - gdouble iso, - GtsVertexClass * klass) -{ - OrientedVertex *** vertices; - guint i, j; - gdouble x, y; - - g_return_if_fail (slice != NULL); - g_return_if_fail (f1 != NULL); - - vertices = slice->vertices; - - if (f2) - for (i = 0, x = g.x; i < g.nx; i++, x += g.dx) - for (j = 0, y = g.y; j < g.ny; j++, y += g.dy) { - gdouble v1 = f1[i][j] - iso; - gdouble v2 = f2[i][j] - iso; - if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) { - vertices[0][i][j].v = - gts_vertex_new (klass, - x, y, g.z + g.dz*v1/(v1 - v2)); - vertices[0][i][j].orientation = v2 >= 0. ? RIGHT : LEFT; - } - else - vertices[0][i][j].v = NULL; - } - for (i = 0, x = g.x; i < g.nx - 1; i++, x += g.dx) - for (j = 0, y = g.y; j < g.ny; j++, y += g.dy) { - gdouble v1 = f1[i][j] - iso; - gdouble v2 = f1[i+1][j] - iso; - if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) { - vertices[1][i][j].v = - gts_vertex_new (klass, x + g.dx*v1/(v1 - v2), y, g.z); - vertices[1][i][j].orientation = v2 >= 0. ? RIGHT : LEFT; - } - else - vertices[1][i][j].v = NULL; - } - for (i = 0, x = g.x; i < g.nx; i++, x += g.dx) - for (j = 0, y = g.y; j < g.ny - 1; j++, y += g.dy) { - gdouble v1 = f1[i][j] - iso; - gdouble v2 = f1[i][j+1] - iso; - if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) { - vertices[2][i][j].v = - gts_vertex_new (klass, x, y + g.dy*v1/(v1 - v2), g.z); - vertices[2][i][j].orientation = v2 >= 0. ? RIGHT : LEFT; - } - else - vertices[2][i][j].v = NULL; - } -} - -/** - * gts_iso_slice_destroy: - * @slice: a #GtsIsoSlice. - * - * Free all memory allocated for @slice. - */ -void gts_iso_slice_destroy (GtsIsoSlice * slice) -{ - g_return_if_fail (slice != NULL); - - free2D ((void **) slice->vertices[0], slice->nx); - free2D ((void **) slice->vertices[1], slice->nx - 1); - free2D ((void **) slice->vertices[2], slice->nx); - g_free (slice->vertices); - g_free (slice); -} - -/** - * gts_isosurface_slice: - * @slice1: a #GtsIsoSlice. - * @slice2: another #GtsIsoSlice. - * @surface: a #GtsSurface. - * - * Given two successive slices @slice1 and @slice2 link their vertices with - * segments and triangles which are added to @surface. - */ -void gts_isosurface_slice (GtsIsoSlice * slice1, - GtsIsoSlice * slice2, - GtsSurface * surface) -{ - guint j, k, l, nx, ny; - OrientedVertex *** vertices[2]; - GtsVertex * va[12]; - - g_return_if_fail (slice1 != NULL); - g_return_if_fail (slice2 != NULL); - g_return_if_fail (surface != NULL); - g_return_if_fail (slice1->nx == slice2->nx && slice1->ny == slice2->ny); - - vertices[0] = slice1->vertices; - vertices[1] = slice2->vertices; - nx = slice1->nx; - ny = slice1->ny; - - /* link vertices with segments and triangles */ - for (j = 0; j < nx - 1; j++) - for (k = 0; k < ny - 1; k++) { - gboolean cube_is_cut = FALSE; - for (l = 0; l < 12; l++) { - guint nv = 0, e = l; - OrientedVertex ov = - vertices[c[e][1]][c[e][0]][j + c[e][2]][k + c[e][3]]; - while (ov.v && !GTS_OBJECT (ov.v)->reserved) { - guint m = 0, * ne = edge[e][ov.orientation]; - va[nv++] = ov.v; - GTS_OBJECT (ov.v)->reserved = surface; - ov.v = NULL; - while (m < 3 && !ov.v) { - e = ne[m++]; - ov = vertices[c[e][1]][c[e][0]][j + c[e][2]][k + c[e][3]]; - } - } - /* create edges and faces */ - if (nv > 2) { - GtsEdge * e1, * e2, * e3; - guint m; - if (!(e1 = GTS_EDGE (gts_vertices_are_connected (va[0], va[1])))) - e1 = gts_edge_new (surface->edge_class, va[0], va[1]); - for (m = 1; m < nv - 1; m++) { - if (!(e2 = GTS_EDGE (gts_vertices_are_connected (va[m], va[m+1])))) - e2 = gts_edge_new (surface->edge_class, va[m], va[m+1]); - if (!(e3 = GTS_EDGE (gts_vertices_are_connected (va[m+1], va[0])))) - e3 = gts_edge_new (surface->edge_class, va[m+1], va[0]); - gts_surface_add_face (surface, - gts_face_new (surface->face_class, - e1, e2, e3)); - e1 = e3; - } - } - if (nv > 0) - cube_is_cut = TRUE; - } - if (cube_is_cut) - for (l = 0; l < 12; l++) { - GtsVertex * v = - vertices[c[l][1]][c[l][0]][j + c[l][2]][k + c[l][3]].v; - if (v) - GTS_OBJECT (v)->reserved = NULL; - } - } -} - -#define SWAP(s1, s2, tmp) (tmp = s1, s1 = s2, s2 = tmp) - -/** - * gts_isosurface_cartesian: - * @surface: a #GtsSurface. - * @g: a #GtsCartesianGrid. - * @f: a #GtsIsoCartesianFunc. - * @data: user data to be passed to @f. - * @iso: isosurface value. - * - * Adds to @surface new faces defining the isosurface f(x,y,z) = @iso. By - * convention, the normals to the surface are pointing toward the positive - * values of f(x,y,z) - @iso. - * - * The user function @f is called successively for each value of the z - * coordinate defined by @g. It must fill the corresponding (x,y) plane with - * the values of the function for which the isosurface is to be computed. - */ -void gts_isosurface_cartesian (GtsSurface * surface, - GtsCartesianGrid g, - GtsIsoCartesianFunc f, - gpointer data, - gdouble iso) -{ - void * tmp; - gdouble ** f1, ** f2; - GtsIsoSlice * slice1, * slice2; - guint i; - - g_return_if_fail (surface != NULL); - g_return_if_fail (f != NULL); - g_return_if_fail (g.nx > 1); - g_return_if_fail (g.ny > 1); - g_return_if_fail (g.nz > 1); - - slice1 = gts_iso_slice_new (g.nx, g.ny); - slice2 = gts_iso_slice_new (g.nx, g.ny); - f1 = (gdouble **) malloc2D (g.nx, g.ny, sizeof (gdouble)); - f2 = (gdouble **) malloc2D (g.nx, g.ny, sizeof (gdouble)); - - (*f) (f1, g, 0, data); - g.z += g.dz; - (*f) (f2, g, 1, data); - g.z -= g.dz; - gts_iso_slice_fill_cartesian (slice1, g, f1, f2, iso, - surface->vertex_class); - g.z += g.dz; - for (i = 2; i < g.nz; i++) { - g.z += g.dz; - (*f) (f1, g, i, data); - SWAP (f1, f2, tmp); - g.z -= g.dz; - gts_iso_slice_fill_cartesian (slice2, g, f1, f2, iso, - surface->vertex_class); - g.z += g.dz; - gts_isosurface_slice (slice1, slice2, surface); - SWAP (slice1, slice2, tmp); - } - gts_iso_slice_fill_cartesian (slice2, g, f2, NULL, iso, - surface->vertex_class); - gts_isosurface_slice (slice1, slice2, surface); - - gts_iso_slice_destroy (slice1); - gts_iso_slice_destroy (slice2); - free2D ((void **) f1, g.nx); - free2D ((void **) f2, g.nx); -} Index: trunk/src_3rd/gts/misc.c =================================================================== --- trunk/src_3rd/gts/misc.c (revision 6802) +++ trunk/src_3rd/gts/misc.c (nonexistent) @@ -1,692 +0,0 @@ -/* GTS - Library for the manipulation of triangulated surfaces - * Copyright (C) 1999 Stéphane Popinet - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include -#include - -#include "gts.h" -#include "gts-private.h" -#include "config.h" - -const guint gts_major_version = GTS_MAJOR_VERSION; -const guint gts_minor_version = GTS_MINOR_VERSION; -const guint gts_micro_version = GTS_MICRO_VERSION; -const guint gts_interface_age = 1; -const guint gts_binary_age = 1; - -static gboolean char_in_string (char c, const char * s) -{ - while (*s != '\0') - if (*(s++) == c) - return TRUE; - return FALSE; -} - -static GtsFile * file_new (void) -{ - GtsFile * f; - - f = g_malloc (sizeof (GtsFile)); - f->fp = NULL; - f->s = f->s1 = NULL; - f->curline = 1; - f->curpos = 1; - f->token = g_string_new (""); - f->type = '\0'; - f->error = NULL; - f->next_token = '\0'; - - f->scope = f->scope_max = 0; - f->delimiters = g_strdup (" \t"); - f->comments = g_strdup (GTS_COMMENTS); - f->tokens = g_strdup ("\n{}()="); - - return f; -} - -/** - * gts_file_new: - * @fp: a file pointer. - * - * Returns: a new #GtsFile. - */ -GtsFile * gts_file_new (FILE * fp) -{ - GtsFile * f; - - g_return_val_if_fail (fp != NULL, NULL); - - f = file_new (); - f->fp = fp; - gts_file_next_token (f); - - return f; -} - -/** - * gts_file_new_from_string: - * @s: a string. - * - * Returns: a new #GtsFile. - */ -GtsFile * gts_file_new_from_string (const gchar * s) -{ - GtsFile * f; - - g_return_val_if_fail (s != NULL, NULL); - - f = file_new (); - f->s1 = f->s = g_strdup (s); - gts_file_next_token (f); - - return f; -} - -/** - * gts_file_destroy: - * @f: a #GtsFile. - * - * Frees all the memory allocated for @f. - */ -void gts_file_destroy (GtsFile * f) -{ - g_return_if_fail (f != NULL); - - g_free (f->delimiters); - g_free (f->comments); - g_free (f->tokens); - if (f->error) - g_free (f->error); - if (f->s1) - g_free (f->s1); - g_string_free (f->token, TRUE); - g_free (f); -} - -/** - * gts_file_verror: - * @f: a @GtsFile. - * @format: the standard sprintf() format string. - * @args: the list of parameters to insert into the format string. - * - * Sets the @error field of @f using g_strdup_vprintf(). - * - * This function can be called only once and disables any other - * operation on @f (gts_file_close() excepted). - */ -void gts_file_verror (GtsFile * f, - const gchar * format, - va_list args) -{ - g_return_if_fail (f != NULL); - g_return_if_fail (format != NULL); - - g_assert (f->type != GTS_ERROR); - f->error = g_strdup_vprintf (format, args); - f->type = GTS_ERROR; -} - -/** - * gts_file_error: - * @f: a @GtsFile. - * @format: the standard sprintf() format string. - * @...: the parameters to insert into the format string. - * - * Sets the @error field of @f using gts_file_verror(). - * - * This function can be called only once and disables any other - * operation on @f (gts_file_close() excepted). - */ -void gts_file_error (GtsFile * f, - const gchar * format, - ...) -{ - va_list args; - - g_return_if_fail (f != NULL); - g_return_if_fail (format != NULL); - - va_start (args, format); - gts_file_verror (f, format, args); - va_end (args); -} - -static gint next_char (GtsFile * f) -{ - if (f->fp) - return fgetc (f->fp); - else if (*f->s == '\0') - return EOF; - return *(f->s++); -} - -/** - * gts_file_getc : - * @f: a #GtsFile. - * - * Returns: the next character in @f or EOF if the end of the file is - * reached or if an error occured. - */ -gint gts_file_getc (GtsFile * f) -{ - gint c; - - g_return_val_if_fail (f != NULL, EOF); - - if (f->type == GTS_ERROR) - return EOF; - - c = next_char (f); - f->curpos++; - while (char_in_string (c, f->comments)) { - while (c != EOF && c != '\n') - c = next_char (f); - if (c == '\n') { - f->curline++; - f->curpos = 1; - c = next_char (f); - } - } - switch (c) { - case '\n': - f->curline++; - f->curpos = 1; - break; - case '{': - f->scope++; - break; - case '}': - if (f->scope == 0) { - f->line = f->curline; - f->pos = f->curpos - 1; - gts_file_error (f, "no matching opening brace"); - c = EOF; - } - else - f->scope--; - } - return c; -} - -/** - * gts_file_read: - * @f: a #GtsFile. - * @ptr: a pointer. - * @size: size of an element. - * @nmemb: number of elements. - * - * Reads @nmemb elements of data, each @size bytes long, from @f, - * storing them at the location given by @ptr. - * - * Returns: the number of elements read. - */ -guint gts_file_read (GtsFile * f, gpointer ptr, guint size, guint nmemb) -{ - guint i, n; - gchar * p; - - g_return_val_if_fail (f != NULL, 0); - g_return_val_if_fail (ptr != NULL, 0); - g_return_val_if_fail (f->fp != NULL, 0); - - if (f->type == GTS_ERROR) - return 0; - - n = fread (ptr, size, nmemb, f->fp); - for (i = 0, p = ptr; i < n*size; i++, p++) { - f->curpos++; - if (*p == '\n') { - f->curline++; - f->curpos = 1; - } - } - return n; -} - -/** - * gts_file_getc_scope : - * @f: a #GtsFile. - * - * Returns: the next character in @f in the scope defined by - * @f->scope_max or EOF if the end of the file is reached or if an - * error occured. - */ -gint gts_file_getc_scope (GtsFile * f) -{ - gint c; - - g_return_val_if_fail (f != NULL, EOF); - - if (f->type == GTS_ERROR) - return EOF; - - if (f->scope <= f->scope_max) - c = gts_file_getc (f); - else { - c = gts_file_getc (f); - while (c != EOF && f->scope > f->scope_max) - c = gts_file_getc (f); - } - return c; -} - -/** - * gts_file_next_token: - * @f: a #GtsFile. - * - * Reads next token from @f and updates its @token and @delim fields. - */ -void gts_file_next_token (GtsFile * f) -{ - gint c; - gboolean in_string = FALSE; - - g_return_if_fail (f != NULL); - - if (f->type == GTS_ERROR) - return; - f->token->str[0] = '\0'; - f->token->len = 0; - if (f->next_token != '\0') { - if (char_in_string (f->next_token, f->tokens)) { - f->line = f->curline; - f->pos = f->curpos - 1; - g_string_append_c (f->token, f->next_token); - f->type = f->next_token; - f->next_token = '\0'; - return; - } - else { - c = f->next_token; - f->next_token = '\0'; - } - } - else - c = gts_file_getc_scope (f); - f->type = GTS_NONE; - while (c != EOF && (!in_string || !char_in_string (c, f->delimiters))) { - if (in_string) { - if (char_in_string (c, f->tokens)) { - f->next_token = c; - break; - } - g_string_append_c (f->token, c); - } - else if (!char_in_string (c, f->delimiters)) { - in_string = TRUE; - f->line = f->curline; - f->pos = f->curpos - 1; - g_string_append_c (f->token, c); - if (char_in_string (c, f->tokens)) { - f->type = c; - break; - } - } - c = gts_file_getc_scope (f); - } - if (f->type == GTS_NONE && f->token->len > 0) { - gchar * a; - - a = f->token->str; - while (*a != '\0' && char_in_string (*a, "+-")) a++; - if (*a == '\0') { - f->type = GTS_STRING; - return; - } - a = f->token->str; - while (*a != '\0' && char_in_string (*a, "+-0123456789")) a++; - if (*a == '\0') { - f->type = GTS_INT; - return; - } - a = f->token->str; - while (*a != '\0' && char_in_string (*a, "+-eE.")) a++; - if (*a == '\0') { - f->type = GTS_STRING; - return; - } - a = f->token->str; - while (*a != '\0' && char_in_string (*a, "+-0123456789eE.")) a++; - if (*a == '\0') { - f->type = GTS_FLOAT; - return; - } - a = f->token->str; - if (!strncmp (a, "0x", 2) || - !strncmp (a, "-0x", 3) || - !strncmp (a, "+0x", 3)) { - while (*a != '\0' && char_in_string (*a, "+-0123456789abcdefx")) a++; - if (*a == '\0') { - f->type = GTS_INT; - return; - } - a = f->token->str; - while (*a != '\0' && char_in_string (*a, "+-0123456789abcdefx.p")) a++; - if (*a == '\0') { - f->type = GTS_FLOAT; - return; - } - } - f->type = GTS_STRING; - } -} - -/** - * gts_file_first_token_after: - * @f: a #GtsFile. - * @type: a #GtsTokenType. - * - * Finds and sets the first token of a type different from @type - * occuring after a token of type @type. - */ -void gts_file_first_token_after (GtsFile * f, GtsTokenType type) -{ - g_return_if_fail (f != NULL); - - while (f->type != GTS_ERROR && - f->type != GTS_NONE && - f->type != type) - gts_file_next_token (f); - while (f->type == type) - gts_file_next_token (f); -} - -/** - * gts_file_assign_start: - * @f: a #GtsFile. - * @vars: a %GTS_NONE terminated array of #GtsFileVariable. - * - * Opens a block delimited by braces to read a list of optional - * arguments specified by @vars. - * - * If an error is encountered the @error field of @f is set. - */ -void gts_file_assign_start (GtsFile * f, GtsFileVariable * vars) -{ - GtsFileVariable * var; - - g_return_if_fail (f != NULL); - g_return_if_fail (vars != NULL); - - var = vars; - while (var->type != GTS_NONE) - (var++)->set = FALSE; - - if (f->type != '{') { - gts_file_error (f, "expecting an opening brace"); - return; - } - - f->scope_max++; - gts_file_next_token (f); -} - -/** - * gts_file_assign_next: - * @f: a #GtsFile. - * @vars: a %GTS_NONE terminated array of #GtsFileVariable. - * - * Assigns the next optional argument of @vars read from @f. - * - * Returns: the variable of @vars which has been assigned or %NULL if - * no variable has been assigned (if an error has been encountered the - * @error field of @f is set). - */ -GtsFileVariable * gts_file_assign_next (GtsFile * f, GtsFileVariable * vars) -{ - GtsFileVariable * var; - gboolean found = FALSE; - - g_return_val_if_fail (f != NULL, NULL); - g_return_val_if_fail (vars != NULL, NULL); - - while (f->type == '\n') - gts_file_next_token (f); - if (f->type == '}') { - f->scope_max--; - gts_file_next_token (f); - return NULL; - } - if (f->type == GTS_ERROR) - return NULL; - - var = vars; - while (f->type != GTS_ERROR && var->type != GTS_NONE && !found) { - if (!strcmp (var->name, f->token->str)) { - found = TRUE; - if (var->unique && var->set) - gts_file_error (f, "variable `%s' was already set at line %d:%d", - var->name, var->line, var->pos); - else { - var->line = f->line; - var->pos = f->pos; - gts_file_next_token (f); - if (f->type != '=') - gts_file_error (f, "expecting `='"); - else { - var->set = TRUE; - switch (var->type) { - case GTS_FILE: - break; - case GTS_INT: - gts_file_next_token (f); - if (f->type != GTS_INT) { - gts_file_error (f, "expecting an integer"); - var->set = FALSE; - } - else if (var->data) - *((gint *) var->data) = atoi (f->token->str); - break; - case GTS_UINT: - gts_file_next_token (f); - if (f->type != GTS_INT) { - gts_file_error (f, "expecting an integer"); - var->set = FALSE; - } - else if (var->data) - *((guint *) var->data) = atoi (f->token->str); - break; - case GTS_FLOAT: - gts_file_next_token (f); - if (f->type != GTS_INT && f->type != GTS_FLOAT) { - gts_file_error (f, "expecting a number"); - var->set = FALSE; - } - else if (var->data) - *((gfloat *) var->data) = atof (f->token->str); - break; - case GTS_DOUBLE: - gts_file_next_token (f); - if (f->type != GTS_INT && f->type != GTS_FLOAT) { - gts_file_error (f, "expecting a number"); - var->set = FALSE; - } - else if (var->data) - *((gdouble *) var->data) = atof (f->token->str); - break; - case GTS_STRING: - gts_file_next_token (f); - if (f->type != GTS_INT && - f->type != GTS_FLOAT && - f->type != GTS_STRING) { - gts_file_error (f, "expecting a string"); - var->set = FALSE; - } - else if (var->data) - *((gchar **) var->data) = g_strdup (f->token->str); - break; - default: - g_assert_not_reached (); - } - } - } - } - else - var++; - } - if (!found) - gts_file_error (f, "unknown identifier `%s'", f->token->str); - else if (f->type != GTS_ERROR) { - g_assert (var->set); - gts_file_next_token (f); - return var; - } - return NULL; -} - -/** - * gts_file_assign_variables: - * @f: a #GtsFile. - * @vars: an array of #GtsFileVariable. - * - * Assigns all the variables belonging to @vars found in @f. - * - * If an error is encountered the @error field of @f is set. - */ -void gts_file_assign_variables (GtsFile * f, GtsFileVariable * vars) -{ - g_return_if_fail (f != NULL); - g_return_if_fail (vars != NULL); - - gts_file_assign_start (f, vars); - while (gts_file_assign_next (f, vars)) - ; -} - -/** - * gts_file_variable_error: - * @f: a #GtsFile. - * @vars: an array of #GtsFileVariable. - * @name: the name of a variable in @vars. - * @format: the standard sprintf() format string. - * @...: the parameters to insert into the format string. - * - * Sets the @error field of @f using gts_file_verror(). - * - * String @name must match one of the variable names in @vars. - * - * If variable @name has been assigned (using gts_file_assign_variables()) - * sets the @line and @pos fields of @f to the line and position where - * it has been assigned. - */ -void gts_file_variable_error (GtsFile * f, - GtsFileVariable * vars, - const gchar * name, - const gchar * format, - ...) -{ - va_list args; - GtsFileVariable * var; - - g_return_if_fail (f != NULL); - g_return_if_fail (vars != NULL); - g_return_if_fail (name != NULL); - g_return_if_fail (format != NULL); - - var = vars; - while (var->type != GTS_NONE && strcmp (var->name, name)) - var++; - - g_return_if_fail (var->type != GTS_NONE); /* @name not found in @vars */ - - if (var->set) { - f->line = var->line; - f->pos = var->pos; - } - - va_start (args, format); - gts_file_verror (f, format, args); - va_end (args); -} - -#ifdef DEBUG_FUNCTIONS -static GHashTable * ids = NULL; -static guint next_id = 1; - -guint id (gpointer p) -{ - g_return_val_if_fail (p != NULL, 0); - g_return_val_if_fail (ids != NULL, 0); - g_assert (g_hash_table_lookup (ids, p)); - return GPOINTER_TO_UINT (g_hash_table_lookup (ids, p)); -} - -void id_insert (gpointer p) -{ - g_return_if_fail (p != NULL); - if (ids == NULL) ids = g_hash_table_new (NULL, NULL); - g_assert (g_hash_table_lookup (ids, p) == NULL); - g_hash_table_insert (ids, p, GUINT_TO_POINTER (next_id++)); -} - -void id_remove (gpointer p) -{ - g_assert (g_hash_table_lookup (ids, p)); - g_hash_table_remove (ids, p); -} - -void gts_write_triangle (GtsTriangle * t, - GtsPoint * o, - FILE * fptr) -{ - gdouble xo = o ? o->x : 0.0; - gdouble yo = o ? o->y : 0.0; - gdouble zo = o ? o->z : 0.0; - - g_return_if_fail (t != NULL && fptr != NULL); - - fprintf (fptr, "(hdefine geometry \"t%d\" { =\n", id (t)); - fprintf (fptr, "OFF 3 1 0\n" - "%g %g %g\n%g %g %g\n%g %g %g\n3 0 1 2\n})\n" - "(geometry \"t%d\" { : \"t%d\"})\n" - "(normalization \"t%d\" none)\n", - GTS_POINT (GTS_SEGMENT (t->e1)->v1)->x - xo, - GTS_POINT (GTS_SEGMENT (t->e1)->v1)->y - yo, - GTS_POINT (GTS_SEGMENT (t->e1)->v1)->z - zo, - GTS_POINT (GTS_SEGMENT (t->e1)->v2)->x - xo, - GTS_POINT (GTS_SEGMENT (t->e1)->v2)->y - yo, - GTS_POINT (GTS_SEGMENT (t->e1)->v2)->z - zo, - GTS_POINT (gts_triangle_vertex (t))->x - xo, - GTS_POINT (gts_triangle_vertex (t))->y - yo, - GTS_POINT (gts_triangle_vertex (t))->z - zo, - id (t), id (t), id (t)); -} - -void gts_write_segment (GtsSegment * s, - GtsPoint * o, - FILE * fptr) -{ - gdouble xo = o ? o->x : 0.0; - gdouble yo = o ? o->y : 0.0; - gdouble zo = o ? o->z : 0.0; - - g_return_if_fail (s != NULL && fptr != NULL); - - fprintf (fptr, "(geometry \"s%d\" { =\n", id (s)); - fprintf (fptr, "VECT 1 2 0 2 0 %g %g %g %g %g %g })\n" - "(normalization \"s%d\" none)\n", - GTS_POINT (s->v1)->x - xo, - GTS_POINT (s->v1)->y - yo, - GTS_POINT (s->v1)->z - zo, - GTS_POINT (s->v2)->x - xo, - GTS_POINT (s->v2)->y - yo, - GTS_POINT (s->v2)->z - zo, - id (s)); -} -#endif /* DEBUG_FUNCTIONS */ Index: trunk/src_plugins/toporouter/toporouter.c =================================================================== --- trunk/src_plugins/toporouter/toporouter.c (revision 6802) +++ trunk/src_plugins/toporouter/toporouter.c (nonexistent) @@ -1,8249 +0,0 @@ -/* - * COPYRIGHT - * - * Topological Autorouter for - * PCB, interactive printed circuit board design - * Copyright (C) 2009 Anthony Blake - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Contact addresses for email: - * Anthony Blake, tonyb33@gmail.com - * - * - * - * This is *EXPERIMENTAL* code. - * - * As the code is experimental, the algorithms and code - * are likely to change. Which means it isn't documented - * or optimized. If you would like to learn about Topological - * Autorouters, the following papers are good starting points: - * - * This file implements a topological autorouter, and uses techniques from the - * following publications: - * - * Dayan, T. and Dai, W.W.M., "Layer Assignment for a Rubber Band Router" Tech - * Report UCSC-CRL-92-50, Univ. of California, Santa Cruz, 1992. - * - * Dai, W.W.M and Dayan, T. and Staepelaere, D., "Topological Routing in SURF: - * Generating a Rubber-Band Sketch" Proc. 28th ACM/IEEE Design Automation - * Conference, 1991, pp. 39-44. - * - * David Staepelaere, Jeffrey Jue, Tal Dayan, Wayne Wei-Ming Dai, "SURF: - * Rubber-Band Routing System for Multichip Modules," IEEE Design and Test of - * Computers ,vol. 10, no. 4, pp. 18-26, October/December, 1993. - * - * Dayan, T., "Rubber-band based topological router" PhD Thesis, Univ. of - * California, Santa Cruz, 1997. - * - * David Staepelaere, "Geometric transformations for a rubber-band sketch" - * Master's thesis, Univ. of California, Santa Cruz, September 1992. - * - */ - -#include "config.h" -#include "toporouter.h" -#include "pcb-printf.h" -#include "compat_nls.h" - -static void toporouter_edge_init(toporouter_edge_t * edge) -{ - edge->routing = NULL; - edge->flags = 0; -} - -toporouter_edge_class_t *toporouter_edge_class(void) -{ - static toporouter_edge_class_t *klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo constraint_info = { - "toporouter_edge_t", - sizeof(toporouter_edge_t), - sizeof(toporouter_edge_class_t), - (GtsObjectClassInitFunc) NULL, - (GtsObjectInitFunc) toporouter_edge_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = (toporouter_edge_class_t *) gts_object_class_new(GTS_OBJECT_CLASS(gts_edge_class()), &constraint_info); - } - - return klass; -} - -static void toporouter_bbox_init(toporouter_bbox_t * box) -{ - box->data = NULL; - box->type = OTHER; - box->constraints = NULL; - box->cluster = NULL; -} - -toporouter_bbox_class_t *toporouter_bbox_class(void) -{ - static toporouter_bbox_class_t *klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo constraint_info = { - "toporouter_bbox_t", - sizeof(toporouter_bbox_t), - sizeof(toporouter_bbox_class_t), - (GtsObjectClassInitFunc) NULL, - (GtsObjectInitFunc) toporouter_bbox_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = (toporouter_bbox_class_t *) gts_object_class_new(GTS_OBJECT_CLASS(gts_bbox_class()), &constraint_info); - } - - return klass; -} - -static void toporouter_vertex_class_init(toporouter_vertex_class_t * klass) -{ - -} - -static void toporouter_vertex_init(toporouter_vertex_t * vertex) -{ - vertex->bbox = NULL; - vertex->parent = NULL; - vertex->child = NULL; - vertex->flags = 0; - vertex->routingedge = NULL; - vertex->arc = NULL; - vertex->oproute = NULL; - vertex->route = NULL; - - vertex->gcost = 0.; - vertex->hcost = 0.; - vertex->gn = 0; -} - -toporouter_vertex_class_t *toporouter_vertex_class(void) -{ - static toporouter_vertex_class_t *klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo constraint_info = { - "toporouter_vertex_t", - sizeof(toporouter_vertex_t), - sizeof(toporouter_vertex_class_t), - (GtsObjectClassInitFunc) toporouter_vertex_class_init, - (GtsObjectInitFunc) toporouter_vertex_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = (toporouter_vertex_class_t *) gts_object_class_new(GTS_OBJECT_CLASS(gts_vertex_class()), &constraint_info); - } - - return klass; -} - -static void toporouter_constraint_class_init(toporouter_constraint_class_t * klass) -{ - -} - -static void toporouter_constraint_init(toporouter_constraint_t * constraint) -{ - constraint->box = NULL; - constraint->routing = NULL; -} - -toporouter_constraint_class_t *toporouter_constraint_class(void) -{ - static toporouter_constraint_class_t *klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo constraint_info = { - "toporouter_constraint_t", - sizeof(toporouter_constraint_t), - sizeof(toporouter_constraint_class_t), - (GtsObjectClassInitFunc) toporouter_constraint_class_init, - (GtsObjectInitFunc) toporouter_constraint_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = (toporouter_constraint_class_t *) gts_object_class_new(GTS_OBJECT_CLASS(gts_constraint_class()), &constraint_info); - } - - return klass; -} - -static void toporouter_arc_init(toporouter_arc_t * arc) -{ - arc->x0 = -1.; - arc->y0 = -1.; - arc->x1 = -1.; - arc->y1 = -1.; - arc->centre = NULL; - arc->v = NULL; - arc->v1 = NULL; - arc->v2 = NULL; - arc->r = -1.; - arc->dir = 31337; - arc->clearance = NULL; - arc->oproute = NULL; -} - -toporouter_arc_class_t *toporouter_arc_class(void) -{ - static toporouter_arc_class_t *klass = NULL; - - if (klass == NULL) { - GtsObjectClassInfo constraint_info = { - "toporouter_arc_t", - sizeof(toporouter_arc_t), - sizeof(toporouter_arc_class_t), - (GtsObjectClassInitFunc) NULL, - (GtsObjectInitFunc) toporouter_arc_init, - (GtsArgSetFunc) NULL, - (GtsArgGetFunc) NULL - }; - klass = (toporouter_arc_class_t *) gts_object_class_new(GTS_OBJECT_CLASS(gts_constraint_class()), &constraint_info); - } - - return klass; -} - -#define MARGIN 10.0f - -drawing_context_t *toporouter_output_init(int w, int h, char *filename) -{ - drawing_context_t *dc; - - dc = (drawing_context_t *) malloc(sizeof(drawing_context_t)); - - dc->iw = w; - dc->ih = h; - dc->filename = filename; - - /* Calculate scaling to maintain aspect ratio */ - if (PCB->MaxWidth > PCB->MaxHeight) { - /* Scale board width to match image width minus 2xMARGIN */ - dc->s = ((double) dc->iw - (2 * MARGIN)) / (double) PCB->MaxWidth; - dc->ih = (double) PCB->MaxHeight * dc->s + (2 * MARGIN); - } - else { - /* Scale board height to match image height minus 2xMARGIN */ - dc->s = ((double) dc->ih - (2 * MARGIN)) / (double) PCB->MaxHeight; - dc->iw = (double) PCB->MaxWidth * dc->s + (2 * MARGIN); - } - -#if TOPO_OUTPUT_ENABLED - dc->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, dc->iw, dc->ih); - dc->cr = cairo_create(dc->surface); - - cairo_rectangle(dc->cr, 0, 0, dc->iw, dc->ih); - cairo_set_source_rgb(dc->cr, 0, 0, 0); - cairo_fill(dc->cr); - -#endif - - return dc; -} - -void toporouter_output_close(drawing_context_t * dc) -{ -#if TOPO_OUTPUT_ENABLED - cairo_surface_write_to_png(dc->surface, dc->filename); - cairo_destroy(dc->cr); - cairo_surface_destroy(dc->surface); -#endif -} - -gdouble lookup_clearance(char *name) -{ - if (name) { - int idx = pcb_route_style_lookup(&PCB->RouteStyle, 0, 0, 0, 0, menu->Style); - if (idx >= 0) - return PCB->RouteStyle.array[idx].Clearance; - } - return Settings.Clearance; -} - -gdouble lookup_thickness(char *name) -{ - if (name) { - int idx = pcb_route_style_lookup(&PCB->RouteStyle, 0, 0, 0, 0, menu->Style); - if (idx >= 0) - return PCB->RouteStyle.array[idx].Thick; - } - return Settings.LineThickness; -} - -static inline gdouble cluster_clearance(toporouter_cluster_t * cluster) -{ - if (cluster) - return lookup_clearance(cluster->netlist->style); - return lookup_clearance(NULL); -} - -static inline gdouble cluster_thickness(toporouter_cluster_t * cluster) -{ - if (cluster) - return lookup_thickness(cluster->netlist->style); - return lookup_thickness(NULL); -} - -gint toporouter_draw_vertex(gpointer item, gpointer data) -{ -#if TOPO_OUTPUT_ENABLED - drawing_context_t *dc = (drawing_context_t *) data; - toporouter_vertex_t *tv; - pcb_pin_t *pin; - pcb_pad_t *pad; - gdouble blue; - - if (TOPOROUTER_IS_VERTEX((GtsObject *) item)) { - tv = TOPOROUTER_VERTEX((GtsObject *) item); - - if (tv->flags & VERTEX_FLAG_RED) { - cairo_set_source_rgba(dc->cr, 1., 0., 0., 0.8f); - cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - - } - else if (tv->flags & VERTEX_FLAG_GREEN) { - cairo_set_source_rgba(dc->cr, 0., 1., 0., 0.8f); - cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - - } - else if (tv->flags & VERTEX_FLAG_BLUE) { - cairo_set_source_rgba(dc->cr, 0., 0., 1., 0.8f); - cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - - - } - /* printf("tv->type = %d\n", tv->type); */ - if (!dc->mode) { - if (tv->bbox) { - pin = (pcb_pin_t *) tv->bbox->data; - pad = (pcb_pad_t *) tv->bbox->data; - - blue = 0.0f; - switch (tv->bbox->type) { - case PIN: - cairo_set_source_rgba(dc->cr, 1.0f, 0., 0.0f, 0.2f); - cairo_arc(dc->cr, - tv->v.p.x * dc->s + MARGIN, - tv->v.p.y * dc->s + MARGIN, - (((gdouble) pin->Thickness / 2.0f) + (gdouble) lookup_clearance(pin->Name)) * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - - cairo_set_source_rgba(dc->cr, 1.0f, 0., 0., 0.4f); - cairo_arc(dc->cr, - tv->v.p.x * dc->s + MARGIN, - tv->v.p.y * dc->s + MARGIN, (gdouble) (pin->Thickness) / 2.0f * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - - break; - case VIA: - cairo_set_source_rgba(dc->cr, 0.0f, 0., 1., 0.2f); - cairo_arc(dc->cr, - tv->v.p.x * dc->s + MARGIN, - tv->v.p.y * dc->s + MARGIN, - (((gdouble) pin->Thickness / 2.0f) + (gdouble) lookup_clearance(pin->Name)) * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - - cairo_set_source_rgba(dc->cr, 0.0f, 0., 1., 0.4f); - cairo_arc(dc->cr, - tv->v.p.x * dc->s + MARGIN, - tv->v.p.y * dc->s + MARGIN, (gdouble) (pin->Thickness) / 2.0f * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - - break; - case PAD: - cairo_set_source_rgba(dc->cr, 0.0f, 1., 0., 0.5f); - cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 400. * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - - break; - default: - break; - } - } - } - else { - if (tv->flags & VERTEX_FLAG_BLUE) { - cairo_set_source_rgba(dc->cr, 0., 0., 1., 0.8f); - cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - } - else if (tv->flags & VERTEX_FLAG_RED) { - cairo_set_source_rgba(dc->cr, 1., 0., 0., 0.8f); - cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - - } - else if (tv->flags & VERTEX_FLAG_GREEN) { - cairo_set_source_rgba(dc->cr, 0., 1., 0., 0.8f); - cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - } - - } - } - else { - fprintf(stderr, "Unknown data passed to toporouter_draw_vertex, aborting foreach\n"); - return -1; - } - return 0; -#else - return -1; -#endif -} - -gint toporouter_draw_edge(gpointer item, gpointer data) -{ -#if TOPO_OUTPUT_ENABLED - drawing_context_t *dc = (drawing_context_t *) data; - toporouter_edge_t *te; - toporouter_constraint_t *tc; - - if (TOPOROUTER_IS_EDGE((GtsObject *) item)) { - te = TOPOROUTER_EDGE((GtsObject *) item); - cairo_set_source_rgba(dc->cr, 1.0f, 1.0f, 1.0f, 0.5f); - cairo_move_to(dc->cr, te->e.segment.v1->p.x * dc->s + MARGIN, te->e.segment.v1->p.y * dc->s + MARGIN); - cairo_line_to(dc->cr, te->e.segment.v2->p.x * dc->s + MARGIN, te->e.segment.v2->p.y * dc->s + MARGIN); - cairo_stroke(dc->cr); - } - else if (TOPOROUTER_IS_CONSTRAINT((GtsObject *) item)) { - tc = TOPOROUTER_CONSTRAINT((GtsObject *) item); - if (tc->box) { - switch (tc->box->type) { - case BOARD: - cairo_set_source_rgba(dc->cr, 1.0f, 0.0f, 1.0f, 0.9f); - cairo_move_to(dc->cr, tc->c.edge.segment.v1->p.x * dc->s + MARGIN, tc->c.edge.segment.v1->p.y * dc->s + MARGIN); - cairo_line_to(dc->cr, tc->c.edge.segment.v2->p.x * dc->s + MARGIN, tc->c.edge.segment.v2->p.y * dc->s + MARGIN); - cairo_stroke(dc->cr); - break; - case PIN: - case PAD: - cairo_set_source_rgba(dc->cr, 1.0f, 0.0f, 0.0f, 0.9f); - cairo_move_to(dc->cr, tc->c.edge.segment.v1->p.x * dc->s + MARGIN, tc->c.edge.segment.v1->p.y * dc->s + MARGIN); - cairo_line_to(dc->cr, tc->c.edge.segment.v2->p.x * dc->s + MARGIN, tc->c.edge.segment.v2->p.y * dc->s + MARGIN); - cairo_stroke(dc->cr); - break; - case LINE: - cairo_set_source_rgba(dc->cr, 0.0f, 1.0f, 0.0f, 0.9f); - cairo_move_to(dc->cr, tc->c.edge.segment.v1->p.x * dc->s + MARGIN, tc->c.edge.segment.v1->p.y * dc->s + MARGIN); - cairo_line_to(dc->cr, tc->c.edge.segment.v2->p.x * dc->s + MARGIN, tc->c.edge.segment.v2->p.y * dc->s + MARGIN); - cairo_stroke(dc->cr); - break; - - default: - cairo_set_source_rgba(dc->cr, 1.0f, 1.0f, 0.0f, 0.9f); - cairo_move_to(dc->cr, tc->c.edge.segment.v1->p.x * dc->s + MARGIN, tc->c.edge.segment.v1->p.y * dc->s + MARGIN); - cairo_line_to(dc->cr, tc->c.edge.segment.v2->p.x * dc->s + MARGIN, tc->c.edge.segment.v2->p.y * dc->s + MARGIN); - cairo_stroke(dc->cr); - break; - } - } - else { - printf("CONSTRAINT without box\n"); - - } - } - else { - fprintf(stderr, "Unknown data passed to toporouter_draw_edge, aborting foreach\n"); - return -1; - } - - return 0; -#else - return -1; -#endif -} - - -/*#define vertex_bbox(v) (v->bbox)*/ -toporouter_bbox_t *vertex_bbox(toporouter_vertex_t * v) -{ - return v ? v->bbox : NULL; -} - - -char *vertex_netlist(toporouter_vertex_t * v) -{ - toporouter_bbox_t *box = vertex_bbox(v); - - if (box && box->cluster) - return box->cluster->netlist->netlist; - - return NULL; -} - -char *constraint_netlist(toporouter_constraint_t * c) -{ - toporouter_bbox_t *box = c->box; - - if (box && box->cluster) - return box->cluster->netlist->netlist; - - return NULL; -} - -static inline guint epsilon_equals(gdouble a, gdouble b) -{ - if (a > b - EPSILON && a < b + EPSILON) - return 1; - return 0; -} - -void print_bbox(toporouter_bbox_t * box) -{ - printf("[BBOX "); - switch (box->type) { - case PAD: - printf("PAD "); - break; - case PIN: - printf("PIN "); - break; - case VIA: - printf("VIA "); - break; - case LINE: - printf("LINE "); - break; - case BOARD: - printf("BOARD "); - break; - case POLYGON: - printf("POLYGON "); - break; - default: - printf("UNKNOWN "); - break; - } - - if (box->point) - printf("P: %f,%f,%f ", vx(box->point), vy(box->point), vz(box->point)); - else - printf("P: NONE "); - - printf("LAYER: %d ", box->layer); - printf("CLUSTER: %d]\n", box->cluster ? box->cluster->c : -1); - -} - -void print_vertex(toporouter_vertex_t * v) -{ - if (v) - printf("[V %f,%f,%f ", vx(v), vy(v), vz(v)); - else - printf("[V (null) "); - - printf("%s ", vertex_netlist(v)); - if (v->route && v->route->netlist) - printf("%s ", v->route->netlist->netlist); - - if (v->routingedge) { - guint n = g_list_length(edge_routing(v->routingedge)); - guint pos = g_list_index(edge_routing(v->routingedge), v); - - if (TOPOROUTER_IS_CONSTRAINT(v->routingedge)) - printf("[CONST "); - else - printf("[EDGE "); - - printf("%d/%d] ", pos, n); - - } - - - if (v->flags & VERTEX_FLAG_TEMP) - printf("TEMP "); - if (v->flags & VERTEX_FLAG_ROUTE) - printf("ROUTE "); - if (v->flags & VERTEX_FLAG_SPECCUT) - printf("SPECCUT "); - if (v->flags & VERTEX_FLAG_FAKE) - printf("FAKE "); - - printf("]\n"); - -} - -gdouble vertex_net_thickness(toporouter_vertex_t * v) -{ - toporouter_bbox_t *box = vertex_bbox(v); - - if (!box) { - - while (v && (v->flags & VERTEX_FLAG_TEMP || v->flags & VERTEX_FLAG_ROUTE)) { - v = v->parent; - } - - box = vertex_bbox(v); - - } - else { - if (box->type == PIN || box->type == VIA) { - pcb_pin_t *pin = (pcb_pin_t *) box->data; - if (PCB_FLAG_TEST(PCB_FLAG_SQUARE, pin) || PCB_FLAG_TEST(PCB_FLAG_OCTAGON, pin)) { - return 0.; - } -/* return ((pcb_pin_t *)box->data)->Thickness + 1.;*/ - return ((pcb_pin_t *) box->data)->Thickness; - } - else if (box->type == PAD) { - pcb_pad_t *pad = (pcb_pad_t *) box->data; - if (pad->Point1.X == pad->Point2.X && pad->Point1.Y == pad->Point2.Y && !PCB_FLAG_TEST(PCB_FLAG_SQUARE, pad)) { - return pad->Thickness; - } - return 0.; - } - else if (box->type == BOARD) { - return 0.; - } - else if (box->type == LINE) { - pcb_line_t *line = (pcb_line_t *) box->data; - return line->Thickness; - } - else if (box->type == POLYGON) { - return 0.; - } - - printf("Unrecognized type in thickness lookup..\n"); - } - -/* if(!box || !box->cluster) return Settings.LineThickness + 1.;*/ - if (!box || !box->cluster) - return Settings.LineThickness; - - return cluster_thickness(box->cluster); -} - -gdouble vertex_net_clearance(toporouter_vertex_t * v) -{ - toporouter_bbox_t *box = vertex_bbox(v); - if (!box) { - - while (v && (v->flags & VERTEX_FLAG_TEMP || v->flags & VERTEX_FLAG_ROUTE)) { - v = v->parent; - } - box = vertex_bbox(v); - } - else { - /* if(box->type == PIN || box->type == VIA) - return ((pcb_pin_t *)box->data)->Clearance; - else if(box->type == PAD) - return ((pcb_pad_t *)box->data)->Clearance; */ - - } - -/* if(!box || !box->cluster) return Settings.Clearance + 1.; */ - if (!box || !box->cluster) - return Settings.Clearance; - return cluster_clearance(box->cluster); -} - -/* -void -print_trace (void) -{ - void *array[10]; - size_t size; - char **strings; - size_t i; - - size = backtrace (array, 10); - strings = backtrace_symbols (array, size); - - printf ("Obtained %zd stack frames.\n", size); - - for (i = 0; i < size; i++) - printf ("%s\n", strings[i]); - - free (strings); -} -*/ -/* fills in x and y with coordinates of point from a towards b of distance d */ -void point_from_point_to_point(toporouter_vertex_t * a, toporouter_vertex_t * b, gdouble d, gdouble * x, gdouble * y) -{ - gdouble dx = vx(b) - vx(a); - gdouble dy = vy(b) - vy(a); - gdouble theta = atan(fabs(dy / dx)); - -/*#ifdef DEBUG_EXPORT */ - if (!finite(theta)) { -/* printf("!finte(theta): a = %f,%f b = %f,%f d = %f\n", vx(a), vy(a), vx(b), vy(b), d); - print_trace(); */ - /*TODO: this shouldn't happen, fix the hack */ - *x = vx(a); - *y = vy(a); - return; - } -/*#endif*/ - - g_assert(finite(theta)); - - *x = vx(a); - *y = vy(a); - - if (dx >= 0.) { - - if (dy >= 0.) { - *x += d * cos(theta); - *y += d * sin(theta); - } - else { - *x += d * cos(theta); - *y -= d * sin(theta); - } - - } - else { - - if (dy >= 0.) { - *x -= d * cos(theta); - *y += d * sin(theta); - } - else { - *x -= d * cos(theta); - *y -= d * sin(theta); - } - - } -} - - -static inline gint coord_wind(gdouble ax, gdouble ay, gdouble bx, gdouble by, gdouble cx, gdouble cy) -{ - gdouble rval, dx1, dx2, dy1, dy2; - dx1 = bx - ax; - dy1 = by - ay; - dx2 = cx - bx; - dy2 = cy - by; - rval = (dx1 * dy2) - (dy1 * dx2); - return (rval > EPSILON) ? 1 : ((rval < -EPSILON) ? -1 : 0); -} - -/* wind_v: - * returns 1,0,-1 for counterclockwise, collinear or clockwise, respectively. - */ -int point_wind(GtsPoint * a, GtsPoint * b, GtsPoint * c) -{ - gdouble rval, dx1, dx2, dy1, dy2; - dx1 = b->x - a->x; - dy1 = b->y - a->y; - dx2 = c->x - b->x; - dy2 = c->y - b->y; - rval = (dx1 * dy2) - (dy1 * dx2); - return (rval > EPSILON) ? 1 : ((rval < -EPSILON) ? -1 : 0); -} - -static inline int vertex_wind(GtsVertex * a, GtsVertex * b, GtsVertex * c) -{ - return point_wind(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c)); -} - -static inline int tvertex_wind(toporouter_vertex_t * a, toporouter_vertex_t * b, toporouter_vertex_t * c) -{ - return point_wind(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c)); -} - -int sloppy_point_wind(GtsPoint * a, GtsPoint * b, GtsPoint * c) -{ - gdouble rval, dx1, dx2, dy1, dy2; - dx1 = b->x - a->x; - dy1 = b->y - a->y; - dx2 = c->x - b->x; - dy2 = c->y - b->y; - rval = (dx1 * dy2) - (dy1 * dx2); - return (rval > 10.) ? 1 : ((rval < -10.) ? -1 : 0); -} - -static inline int sloppy_vertex_wind(GtsVertex * a, GtsVertex * b, GtsVertex * c) -{ - return point_wind(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c)); -} - -/* moves vertex v d units in the direction of vertex p */ -void coord_move_towards_coord_values(gdouble ax, gdouble ay, gdouble px, gdouble py, gdouble d, gdouble * x, gdouble * y) -{ - gdouble dx = px - ax; - gdouble dy = py - ay; - gdouble theta = atan(fabs(dy / dx)); - - - if (!finite(theta)) { - printf("!finite(theta) a = %f,%f p = %f,%f d = %f\n", ax, ay, px, py, d); - - } - - g_assert(finite(theta)); - - if (dx >= 0.) { - - if (dy >= 0.) { - *x = ax + (d * cos(theta)); - *y = ay + (d * sin(theta)); - } - else { - *x = ax + (d * cos(theta)); - *y = ay - (d * sin(theta)); - } - - } - else { - - if (dy >= 0.) { - *x = ax - (d * cos(theta)); - *y = ay + (d * sin(theta)); - } - else { - *x = ax - (d * cos(theta)); - *y = ay - (d * sin(theta)); - } - - } - -} - -/* moves vertex v d units in the direction of vertex p */ -void vertex_move_towards_point_values(GtsVertex * v, gdouble px, gdouble py, gdouble d, gdouble * x, gdouble * y) -{ - gdouble dx = px - GTS_POINT(v)->x; - gdouble dy = py - GTS_POINT(v)->y; - gdouble theta = atan(fabs(dy / dx)); - - g_assert(finite(theta)); - - if (dx >= 0.) { - - if (dy >= 0.) { - *x = GTS_POINT(v)->x + (d * cos(theta)); - *y = GTS_POINT(v)->y + (d * sin(theta)); - } - else { - *x = GTS_POINT(v)->x + (d * cos(theta)); - *y = GTS_POINT(v)->y - (d * sin(theta)); - } - - } - else { - - if (dy >= 0.) { - *x = GTS_POINT(v)->x - (d * cos(theta)); - *y = GTS_POINT(v)->y + (d * sin(theta)); - } - else { - *x = GTS_POINT(v)->x - (d * cos(theta)); - *y = GTS_POINT(v)->y - (d * sin(theta)); - } - - } - -} - -/* moves vertex v d units in the direction of vertex p */ -void vertex_move_towards_vertex_values(GtsVertex * v, GtsVertex * p, gdouble d, gdouble * x, gdouble * y) -{ - gdouble dx = GTS_POINT(p)->x - GTS_POINT(v)->x; - gdouble dy = GTS_POINT(p)->y - GTS_POINT(v)->y; - gdouble theta = atan(fabs(dy / dx)); - - g_assert(finite(theta)); - - if (dx >= 0.) { - - if (dy >= 0.) { - *x = GTS_POINT(v)->x + (d * cos(theta)); - *y = GTS_POINT(v)->y + (d * sin(theta)); - } - else { - *x = GTS_POINT(v)->x + (d * cos(theta)); - *y = GTS_POINT(v)->y - (d * sin(theta)); - } - - } - else { - - if (dy >= 0.) { - *x = GTS_POINT(v)->x - (d * cos(theta)); - *y = GTS_POINT(v)->y + (d * sin(theta)); - } - else { - *x = GTS_POINT(v)->x - (d * cos(theta)); - *y = GTS_POINT(v)->y - (d * sin(theta)); - } - - } - -} - -#define tv_on_layer(v,l) (l == TOPOROUTER_BBOX(TOPOROUTER_VERTEX(v)->boxes->data)->layer) - -static inline gdouble min_spacing(toporouter_vertex_t * v1, toporouter_vertex_t * v2) -{ - - gdouble v1halfthick, v2halfthick, v1clearance, v2clearance, ms; -/* toporouter_edge_t *e = v1->routingedge;*/ - - v1halfthick = vertex_net_thickness(TOPOROUTER_VERTEX(v1)) / 2.; - v2halfthick = vertex_net_thickness(TOPOROUTER_VERTEX(v2)) / 2.; - - v1clearance = vertex_net_clearance(TOPOROUTER_VERTEX(v1)); - v2clearance = vertex_net_clearance(TOPOROUTER_VERTEX(v2)); - - ms = v1halfthick + v2halfthick + MAX(v1clearance, v2clearance); - -#ifdef SPACING_DEBUG - printf("v1halfthick = %f v2halfthick = %f v1clearance = %f v2clearance = %f ms = %f\n", - v1halfthick, v2halfthick, v1clearance, v2clearance, ms); -#endif - - return ms; -} - -/* v1 is a vertex in the CDT, and v2 is a net... other way around?*/ -static inline gdouble min_vertex_net_spacing(toporouter_vertex_t * v1, toporouter_vertex_t * v2) -{ - - gdouble v1halfthick, v2halfthick, v1clearance, v2clearance, ms; - - v1halfthick = vertex_net_thickness(TOPOROUTER_VERTEX(v1)) / 2.; - v2halfthick = cluster_thickness(vertex_bbox(v2)->cluster) / 2.; - - v1clearance = vertex_net_clearance(TOPOROUTER_VERTEX(v1)); - v2clearance = cluster_clearance(vertex_bbox(v2)->cluster); - - ms = v1halfthick + v2halfthick + MAX(v1clearance, v2clearance); - - return ms; -} - -static inline gdouble min_oproute_vertex_spacing(toporouter_oproute_t * oproute, toporouter_vertex_t * v2) -{ - - gdouble v1halfthick, v2halfthick, v1clearance, v2clearance, ms; - - v1halfthick = lookup_thickness(oproute->style) / 2.; - v2halfthick = vertex_net_thickness(v2) / 2.; - - v1clearance = lookup_clearance(oproute->style); - v2clearance = vertex_net_clearance(v2); - - ms = v1halfthick + v2halfthick + MAX(v1clearance, v2clearance); - - return ms; -} - -gdouble min_oproute_net_spacing(toporouter_oproute_t * oproute, toporouter_vertex_t * v2) -{ - - gdouble v1halfthick, v2halfthick, v1clearance, v2clearance, ms; - - v1halfthick = lookup_thickness(oproute->style) / 2.; - v2halfthick = cluster_thickness(v2->route->src) / 2.; - - v1clearance = lookup_clearance(oproute->style); - v2clearance = cluster_clearance(v2->route->src); - - ms = v1halfthick + v2halfthick + MAX(v1clearance, v2clearance); - - return ms; -} - -gdouble min_net_net_spacing(toporouter_vertex_t * v1, toporouter_vertex_t * v2) -{ - - gdouble v1halfthick, v2halfthick, v1clearance, v2clearance, ms; - - v1halfthick = cluster_thickness(v1->route->src) / 2.; - v2halfthick = cluster_thickness(v2->route->src) / 2.; - - v1clearance = cluster_clearance(v1->route->src); - v2clearance = cluster_clearance(v2->route->src); - - ms = v1halfthick + v2halfthick + MAX(v1clearance, v2clearance); - - return ms; -} - -void -toporouter_draw_cluster(toporouter_t * r, drawing_context_t * dc, toporouter_cluster_t * cluster, gdouble red, gdouble green, - gdouble blue, guint layer) -{ -#if TOPO_OUTPUT_ENABLED -/*GList *i = cluster->i; - - while(i) { - toporouter_bbox_t *box = TOPOROUTER_BBOX(i->data); - - if(box->point && vz(box->point) == layer) { - cairo_set_source_rgba(dc->cr, red, green, blue, 0.8f); - cairo_arc(dc->cr, vx(box->point) * dc->s + MARGIN, vy(box->point) * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - } - - i = i->next; - } -*/ -#endif -} - -void -toporouter_draw_surface(toporouter_t * r, GtsSurface * s, char *filename, int w, int h, int mode, GList * datas, int layer, - GList * candidatepoints) -{ -#if TOPO_OUTPUT_ENABLED - drawing_context_t *dc; - GList *i; - toporouter_vertex_t *tv, *tv2 = NULL; - - dc = toporouter_output_init(w, h, filename); - dc->mode = mode; - dc->data = NULL; - - gts_surface_foreach_edge(s, toporouter_draw_edge, dc); - gts_surface_foreach_vertex(s, toporouter_draw_vertex, dc); - - i = r->routednets; - while (i) { - GList *j = TOPOROUTER_ROUTE(i->data)->path; - tv2 = NULL; - while (j) { - tv = TOPOROUTER_VERTEX(j->data); - if (GTS_POINT(tv)->z == layer) { - if (tv && tv2) { - cairo_set_source_rgba(dc->cr, 0.0f, 1.0f, 0.0f, 0.8f); - cairo_move_to(dc->cr, GTS_POINT(tv)->x * dc->s + MARGIN, GTS_POINT(tv)->y * dc->s + MARGIN); - cairo_line_to(dc->cr, GTS_POINT(tv2)->x * dc->s + MARGIN, GTS_POINT(tv2)->y * dc->s + MARGIN); - cairo_stroke(dc->cr); - } - - if (tv->flags & VERTEX_FLAG_RED) { - cairo_set_source_rgba(dc->cr, 1., 0., 0., 0.8f); - cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - - } - else if (tv->flags & VERTEX_FLAG_GREEN) { - cairo_set_source_rgba(dc->cr, 0., 1., 0., 0.8f); - cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - - } - else if (tv->flags & VERTEX_FLAG_BLUE) { - cairo_set_source_rgba(dc->cr, 0., 0., 1., 0.8f); - cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - - } - else { - - cairo_set_source_rgba(dc->cr, 1., 1., 1., 0.8f); - cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - - - } - - if (tv->routingedge && !TOPOROUTER_IS_CONSTRAINT(tv->routingedge)) { - gdouble tempx, tempy, nms, pms; - GList *i = g_list_find(edge_routing(tv->routingedge), tv); - toporouter_vertex_t *nextv, *prevv; - - nextv = edge_routing_next(tv->routingedge, i); - prevv = edge_routing_prev(tv->routingedge, i); - - nms = min_spacing(tv, nextv); - pms = min_spacing(tv, prevv); - - g_assert(finite(nms)); - g_assert(finite(pms)); - - point_from_point_to_point(tv, nextv, nms, &tempx, &tempy); - - cairo_set_source_rgba(dc->cr, 0.0f, 1.0f, 1.0f, 0.8f); - cairo_move_to(dc->cr, vx(tv) * dc->s + MARGIN, vy(tv) * dc->s + MARGIN); - cairo_line_to(dc->cr, tempx * dc->s + MARGIN, tempy * dc->s + MARGIN); - cairo_stroke(dc->cr); - - point_from_point_to_point(tv, prevv, pms, &tempx, &tempy); - - cairo_move_to(dc->cr, vx(tv) * dc->s + MARGIN, vy(tv) * dc->s + MARGIN); - cairo_line_to(dc->cr, tempx * dc->s + MARGIN, tempy * dc->s + MARGIN); - cairo_stroke(dc->cr); - - - - - } - - - } - tv2 = tv; - j = j->next; - } - i = i->next; - } - - while (datas) { - toporouter_route_t *routedata = (toporouter_route_t *) datas->data; - - GList *i; /*, *k; */ - - toporouter_draw_cluster(r, dc, routedata->src, 1., 0., 0., layer); - toporouter_draw_cluster(r, dc, routedata->dest, 0., 0., 1., layer); - - tv2 = NULL; - i = routedata->path; - while (i) { - tv = TOPOROUTER_VERTEX(i->data); - if (GTS_POINT(tv)->z == layer) { - if (tv && tv2) { - cairo_set_source_rgba(dc->cr, 0.0f, 1.0f, 0.0f, 0.8f); - cairo_move_to(dc->cr, GTS_POINT(tv)->x * dc->s + MARGIN, GTS_POINT(tv)->y * dc->s + MARGIN); - cairo_line_to(dc->cr, GTS_POINT(tv2)->x * dc->s + MARGIN, GTS_POINT(tv2)->y * dc->s + MARGIN); - cairo_stroke(dc->cr); - } - } - tv2 = tv; - i = i->next; - } - - - if (routedata->alltemppoints) { - GList *i, *j; - i = j = g_hash_table_get_keys(routedata->alltemppoints); - while (i) { - toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data); - - if (GTS_POINT(tv)->z != layer) { - i = i->next; - continue; - } - if (tv->flags & VERTEX_FLAG_BLUE) { - cairo_set_source_rgba(dc->cr, 0., 0., 1., 0.8f); - cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - } - else if (tv->flags & VERTEX_FLAG_RED) { - cairo_set_source_rgba(dc->cr, 1., 0., 0., 0.8f); - cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - - } - else if (tv->flags & VERTEX_FLAG_GREEN) { - cairo_set_source_rgba(dc->cr, 0., 1., 0., 0.8f); - cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - } - else { - cairo_set_source_rgba(dc->cr, 1., 1., 1., 0.8f); - cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); - cairo_fill(dc->cr); - } - i = i->next; - } - g_list_free(j); - } - datas = datas->next; - } - toporouter_output_close(dc); -#endif -} - - -void toporouter_layer_free(toporouter_layer_t * l) -{ - g_list_free(l->vertices); - g_list_free(l->constraints); - -} - -guint groupcount(void) -{ - int group; - guint count = 0; - - for (group = 0; group < pcb_max_group; group++) { - if (PCB->LayerGroups.Number[group] > 0) - count++; - } - - return count; -} - -void toporouter_free(toporouter_t * r) -{ - struct timeval endtime; - int secs, usecs; - - int i; - for (i = 0; i < groupcount(); i++) { - toporouter_layer_free(&r->layers[i]); - } - - - gettimeofday(&endtime, NULL); - - secs = (int) (endtime.tv_sec - r->starttime.tv_sec); - usecs = (int) ((endtime.tv_usec - r->starttime.tv_usec) / 1000); - - if (usecs < 0) { - secs -= 1; - usecs += 1000; - } - - pcb_message(PCB_MSG_INFO, _("Elapsed time: %d.%02d seconds\n"), secs, usecs); - free(r->layers); - free(r); - -} - -/* wind: - * returns 1,0,-1 for counterclockwise, collinear or clockwise, respectively. - */ -int wind(toporouter_spoint_t * p1, toporouter_spoint_t * p2, toporouter_spoint_t * p3) -{ - double rval, dx1, dx2, dy1, dy2; - dx1 = p2->x - p1->x; - dy1 = p2->y - p1->y; - dx2 = p3->x - p2->x; - dy2 = p3->y - p2->y; - rval = (dx1 * dy2) - (dy1 * dx2); - return (rval > 0.0001) ? 1 : ((rval < -0.0001) ? -1 : 0); -} - -/* wind_double: - * returns 1,0,-1 for counterclockwise, collinear or clockwise, respectively. - */ -int wind_double(gdouble p1_x, gdouble p1_y, gdouble p2_x, gdouble p2_y, gdouble p3_x, gdouble p3_y) -{ - double rval, dx1, dx2, dy1, dy2; - dx1 = p2_x - p1_x; - dy1 = p2_y - p1_y; - dx2 = p3_x - p2_x; - dy2 = p3_y - p2_y; - rval = (dx1 * dy2) - (dy1 * dx2); - return (rval > 0.0001) ? 1 : ((rval < -0.0001) ? -1 : 0); -} - -static inline void print_toporouter_constraint(toporouter_constraint_t * tc) -{ - printf("%f,%f -> %f,%f ", - tc->c.edge.segment.v1->p.x, tc->c.edge.segment.v1->p.y, tc->c.edge.segment.v2->p.x, tc->c.edge.segment.v2->p.y); -} - -static inline void print_toporouter_vertex(toporouter_vertex_t * tv) -{ - printf("%f,%f ", tv->v.p.x, tv->v.p.y); -} - - -/** - * vertices_on_line: - * Given vertex a, gradient m, and radius r: - * - * Return vertices on line of a & m at r from a - */ -void vertices_on_line(toporouter_spoint_t * a, gdouble m, gdouble r, toporouter_spoint_t * b0, toporouter_spoint_t * b1) -{ - - gdouble c, temp; - - if (m == INFINITY || m == -INFINITY) { - b0->y = a->y + r; - b1->y = a->y - r; - - b0->x = a->x; - b1->x = a->x; - - return; - } - - c = a->y - (m * a->x); - - temp = sqrt(pow(r, 2) / (1 + pow(m, 2))); - - b0->x = a->x + temp; - b1->x = a->x - temp; - - b0->y = b0->x * m + c; - b1->y = b1->x * m + c; - -} - -/** - * vertices_on_line: - * Given vertex a, gradient m, and radius r: - * - * Return vertices on line of a & m at r from a - */ -void coords_on_line(gdouble ax, gdouble ay, gdouble m, gdouble r, gdouble * b0x, gdouble * b0y, gdouble * b1x, gdouble * b1y) -{ - - gdouble c, temp; - - if (m == INFINITY || m == -INFINITY) { - *b0y = ay + r; - *b1y = ay - r; - - *b0x = ax; - *b1x = ax; - - return; - } - - c = ay - (m * ax); - - temp = sqrt(pow(r, 2) / (1 + pow(m, 2))); - - *b0x = ax + temp; - *b1x = ax - temp; - - *b0y = *b0x * m + c; - *b1y = *b1x * m + c; - -} - -/** - * vertices_on_line: - * Given vertex a, gradient m, and radius r: - * - * Return vertices on line of a & m at r from a - */ -void points_on_line(GtsPoint * a, gdouble m, gdouble r, GtsPoint * b0, GtsPoint * b1) -{ - - gdouble c, temp; - - if (m == INFINITY || m == -INFINITY) { - b0->y = a->y + r; - b1->y = a->y - r; - - b0->x = a->x; - b1->x = a->x; - - return; - } - - c = a->y - (m * a->x); - - temp = sqrt(pow(r, 2) / (1 + pow(m, 2))); - - b0->x = a->x + temp; - b1->x = a->x - temp; - - b0->y = b0->x * m + c; - b1->y = b1->x * m + c; - -} - -/* - * Returns gradient of segment given by a & b - */ -gdouble vertex_gradient(toporouter_spoint_t * a, toporouter_spoint_t * b) -{ - if (a->x == b->x) - return INFINITY; - - return ((b->y - a->y) / (b->x - a->x)); -} - -/* - * Returns gradient of segment given by (x0,y0) & (x1,y1) - */ -static inline gdouble cartesian_gradient(gdouble x0, gdouble y0, gdouble x1, gdouble y1) -{ - if (epsilon_equals(x0, x1)) - return INFINITY; - - return ((y1 - y0) / (x1 - x0)); -} - -/* - * Returns gradient of segment given by (x0,y0) & (x1,y1) - */ -static inline gdouble point_gradient(GtsPoint * a, GtsPoint * b) -{ - return cartesian_gradient(a->x, a->y, b->x, b->y); -} - -gdouble segment_gradient(GtsSegment * s) -{ - return cartesian_gradient(GTS_POINT(s->v1)->x, GTS_POINT(s->v1)->y, GTS_POINT(s->v2)->x, GTS_POINT(s->v2)->y); -} - -/* - * Returns gradient perpendicular to m - */ -gdouble perpendicular_gradient(gdouble m) -{ - if (isinf(m)) - return 0.0f; - if (m < EPSILON && m > -EPSILON) - return INFINITY; - return -1.0f / m; -} - -/* - * Returns the distance between two vertices in the x-y plane - */ -gdouble vertices_plane_distance(toporouter_spoint_t * a, toporouter_spoint_t * b) -{ - return sqrt(pow(a->x - b->x, 2) + pow(a->y - b->y, 2)); -} - -/* - * Finds the point p distance r away from a on the line segment of a & b - */ -static inline void vertex_outside_segment(toporouter_spoint_t * a, toporouter_spoint_t * b, gdouble r, toporouter_spoint_t * p) -{ - toporouter_spoint_t temp[2]; - - vertices_on_line(a, vertex_gradient(a, b), r, &temp[0], &temp[1]); - - if (vertices_plane_distance(&temp[0], b) > vertices_plane_distance(&temp[1], b)) { - p->x = temp[0].x; - p->y = temp[0].y; - } - else { - p->x = temp[1].x; - p->y = temp[1].y; - } - -} - -/* proper intersection: - * AB and CD must share a point interior to both segments. - * returns TRUE if AB properly intersects CD. - */ -gint coord_intersect_prop(gdouble ax, gdouble ay, gdouble bx, gdouble by, gdouble cx, gdouble cy, gdouble dx, gdouble dy) -{ - gint wind_abc = coord_wind(ax, ay, bx, by, cx, cy); - gint wind_abd = coord_wind(ax, ay, bx, by, dx, dy); - gint wind_cda = coord_wind(cx, cy, dx, dy, ax, ay); - gint wind_cdb = coord_wind(cx, cy, dx, dy, bx, by); - - if (!wind_abc || !wind_abd || !wind_cda || !wind_cdb) - return 0; - - return (wind_abc ^ wind_abd) && (wind_cda ^ wind_cdb); -} - -/* proper intersection: - * AB and CD must share a point interior to both segments. - * returns TRUE if AB properly intersects CD. - */ -int point_intersect_prop(GtsPoint * a, GtsPoint * b, GtsPoint * c, GtsPoint * d) -{ - - if (point_wind(a, b, c) == 0 || point_wind(a, b, d) == 0 || point_wind(c, d, a) == 0 || point_wind(c, d, b) == 0) - return 0; - - return (point_wind(a, b, c) ^ point_wind(a, b, d)) && (point_wind(c, d, a) ^ point_wind(c, d, b)); -} - -static inline int vertex_intersect_prop(GtsVertex * a, GtsVertex * b, GtsVertex * c, GtsVertex * d) -{ - return point_intersect_prop(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c), GTS_POINT(d)); -} - -static inline int -tvertex_intersect_prop(toporouter_vertex_t * a, toporouter_vertex_t * b, toporouter_vertex_t * c, toporouter_vertex_t * d) -{ - return point_intersect_prop(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c), GTS_POINT(d)); -} - -/* -static inline int -tvertex_intersect(toporouter_vertex_t *a, toporouter_vertex_t *b, toporouter_vertex_t *c, toporouter_vertex_t *d) -{ - if( !point_wind(GTS_POINT(a), GTS_POINT(d), GTS_POINT(b)) || !point_wind(GTS_POINT(a), GTS_POINT(c), GTS_POINT(b)) ) return 1; - - return - ( point_wind(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c)) ^ point_wind(GTS_POINT(a), GTS_POINT(b), GTS_POINT(d)) ) && - ( point_wind(GTS_POINT(c), GTS_POINT(d), GTS_POINT(a)) ^ point_wind(GTS_POINT(c), GTS_POINT(d), GTS_POINT(b)) ); -} -*/ - -/* intersection vertex: - * AB and CD must share a point interior to both segments. - * returns vertex at intersection of AB and CD. - */ -GtsVertex *vertex_intersect(GtsVertex * a, GtsVertex * b, GtsVertex * c, GtsVertex * d) -{ - GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class()); - GtsVertex *rval; - gdouble ua_top, ua_bot, ua, rx, ry; - - /* TODO: this could be done more efficiently without duplicating computation */ - if (!vertex_intersect_prop(a, b, c, d)) - return NULL; - - ua_top = ((d->p.x - c->p.x) * (a->p.y - c->p.y)) - ((d->p.y - c->p.y) * (a->p.x - c->p.x)); - ua_bot = ((d->p.y - c->p.y) * (b->p.x - a->p.x)) - ((d->p.x - c->p.x) * (b->p.y - a->p.y)); - ua = ua_top / ua_bot; - rx = a->p.x + (ua * (b->p.x - a->p.x)); - ry = a->p.y + (ua * (b->p.y - a->p.y)); - - rval = gts_vertex_new(vertex_class, rx, ry, 0.0f); - - return rval; -} - -/* intersection vertex: - * AB and CD must share a point interior to both segments. - * returns vertex at intersection of AB and CD. - */ -void -coord_intersect(gdouble ax, gdouble ay, gdouble bx, gdouble by, gdouble cx, gdouble cy, gdouble dx, gdouble dy, gdouble * rx, - gdouble * ry) -{ - gdouble ua_top, ua_bot, ua; - - ua_top = ((dx - cx) * (ay - cy)) - ((dy - cy) * (ax - cx)); - ua_bot = ((dy - cy) * (bx - ax)) - ((dx - cx) * (by - ay)); - ua = ua_top / ua_bot; - *rx = ax + (ua * (bx - ax)); - *ry = ay + (ua * (by - ay)); - -} - - -/* - * returns true if c is between a and b - */ -int point_between(GtsPoint * a, GtsPoint * b, GtsPoint * c) -{ - if (point_wind(a, b, c) != 0) - return 0; - - if (a->x != b->x) { - return ((a->x <= c->x) && (c->x <= b->x)) || ((a->x >= c->x) && (c->x >= b->x)); - } - return ((a->y <= c->y) && (c->y <= b->y)) || ((a->y >= c->y) && (c->y >= b->y)); -} - -static inline int vertex_between(GtsVertex * a, GtsVertex * b, GtsVertex * c) -{ - return point_between(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c)); -} - -void delaunay_create_from_vertices(GList * vertices, GtsSurface ** surface, GtsTriangle ** t) -{ - GList *i = vertices; - GtsVertex *v1, *v2, *v3; - GSList *vertices_slist = NULL; - - while (i) { - vertices_slist = g_slist_prepend(vertices_slist, i->data); - i = i->next; - } - - /* TODO: just work this out from the board outline */ - *t = gts_triangle_enclosing(gts_triangle_class(), vertices_slist, 100000.0f); - gts_triangle_vertices(*t, &v1, &v2, &v3); - - *surface = gts_surface_new(gts_surface_class(), gts_face_class(), - GTS_EDGE_CLASS(toporouter_edge_class()), GTS_VERTEX_CLASS(toporouter_vertex_class())); - - gts_surface_add_face(*surface, gts_face_new(gts_face_class(), (*t)->e1, (*t)->e2, (*t)->e3)); - - i = vertices; - while (i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(gts_delaunay_add_vertex(*surface, (GtsVertex *) i->data, NULL)); - - if (v) { - printf("ERROR: vertex could not be added to CDT "); - print_vertex(v); - } - - i = i->next; - } - - gts_allow_floating_vertices = TRUE; - gts_object_destroy(GTS_OBJECT(v1)); - gts_object_destroy(GTS_OBJECT(v2)); - gts_object_destroy(GTS_OBJECT(v3)); - gts_allow_floating_vertices = FALSE; - - g_slist_free(vertices_slist); -/* return surface;*/ -} - -GSList *list_to_slist(GList * i) -{ - GSList *rval = NULL; - while (i) { - rval = g_slist_prepend(rval, i->data); - i = i->next; - } - return rval; -} - -toporouter_bbox_t *toporouter_bbox_create_from_points(int layer, GList * vertices, toporouter_term_t type, gpointer data) -{ - toporouter_bbox_t *bbox; - GSList *vertices_slist = list_to_slist(vertices); - -/* delaunay_create_from_vertices(vertices, &s, &t);*/ - bbox = TOPOROUTER_BBOX(gts_bbox_points(GTS_BBOX_CLASS(toporouter_bbox_class()), vertices_slist)); - bbox->type = type; - bbox->data = data; - - bbox->surface = NULL; - bbox->enclosing = NULL; - - bbox->layer = layer; - - bbox->point = NULL; - bbox->realpoint = NULL; - - g_slist_free(vertices_slist); - return bbox; -} - -toporouter_bbox_t *toporouter_bbox_create(int layer, GList * vertices, toporouter_term_t type, gpointer data) -{ - toporouter_bbox_t *bbox; - GtsSurface *s; - GtsTriangle *t; - - delaunay_create_from_vertices(vertices, &s, &t); - bbox = TOPOROUTER_BBOX(gts_bbox_surface(GTS_BBOX_CLASS(toporouter_bbox_class()), s)); - bbox->type = type; - bbox->data = data; - - bbox->surface = s; - bbox->enclosing = t; - - bbox->layer = layer; - - return bbox; -} - -GtsVertex *insert_vertex(toporouter_t * r, toporouter_layer_t * l, gdouble x, gdouble y, toporouter_bbox_t * box) -{ - GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class()); - GtsVertex *v; - GList *i; - - i = l->vertices; - while (i) { - v = (GtsVertex *) i->data; - if (v->p.x == x && v->p.y == y) { - TOPOROUTER_VERTEX(v)->bbox = box; - return v; - } - i = i->next; - } - - v = gts_vertex_new(vertex_class, x, y, l - r->layers); - TOPOROUTER_VERTEX(v)->bbox = box; - l->vertices = g_list_prepend(l->vertices, v); - - return v; -} - -GList *insert_constraint_edge(toporouter_t * r, toporouter_layer_t * l, gdouble x1, gdouble y1, guint flags1, - gdouble x2, gdouble y2, guint flags2, toporouter_bbox_t * box) -{ - GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class()); - GtsEdgeClass *edge_class = GTS_EDGE_CLASS(toporouter_constraint_class()); - GtsVertex *p[2]; - GtsVertex *v; - GList *i; - GtsEdge *e; - - p[0] = p[1] = NULL; - - /* insert or find points */ - - i = l->vertices; - while (i) { - v = (GtsVertex *) i->data; - if (v->p.x == x1 && v->p.y == y1) - p[0] = v; - if (v->p.x == x2 && v->p.y == y2) - p[1] = v; - i = i->next; - } - - if (p[0] == NULL) { - p[0] = gts_vertex_new(vertex_class, x1, y1, l - r->layers); - TOPOROUTER_VERTEX(p[0])->bbox = box; - l->vertices = g_list_prepend(l->vertices, p[0]); - } - if (p[1] == NULL) { - p[1] = gts_vertex_new(vertex_class, x2, y2, l - r->layers); - TOPOROUTER_VERTEX(p[1])->bbox = box; - l->vertices = g_list_prepend(l->vertices, p[1]); - } - - TOPOROUTER_VERTEX(p[0])->flags = flags1; - TOPOROUTER_VERTEX(p[1])->flags = flags2; - - e = gts_edge_new(edge_class, p[0], p[1]); - TOPOROUTER_CONSTRAINT(e)->box = box; - l->constraints = g_list_prepend(l->constraints, e); -/* return insert_constraint_edge_rec(r, l, p, box);*/ - return g_list_prepend(NULL, e); - -} - -void insert_constraints_from_list(toporouter_t * r, toporouter_layer_t * l, GList * vlist, toporouter_bbox_t * box) -{ - GList *i = vlist; - toporouter_vertex_t *pv = NULL, *v; - - while (i) { - v = TOPOROUTER_VERTEX(i->data); - - if (pv) { - box->constraints = - g_list_concat(box->constraints, insert_constraint_edge(r, l, vx(v), vy(v), v->flags, vx(pv), vy(pv), pv->flags, box)); - } - - pv = v; - i = i->next; - } - - v = TOPOROUTER_VERTEX(vlist->data); - box->constraints = - g_list_concat(box->constraints, insert_constraint_edge(r, l, vx(v), vy(v), v->flags, vx(pv), vy(pv), pv->flags, box)); - -} - -void insert_centre_point(toporouter_t * r, toporouter_layer_t * l, gdouble x, gdouble y) -{ - GList *i; - GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class()); - - i = l->vertices; - while (i) { - GtsPoint *p = GTS_POINT(i->data); - if (p->x == x && p->y == y) - return; - i = i->next; - } - - l->vertices = g_list_prepend(l->vertices, gts_vertex_new(vertex_class, x, y, 0.0f)); -} - -GtsPoint *midpoint(GtsPoint * a, GtsPoint * b) -{ - return gts_point_new(gts_point_class(), (a->x + b->x) / 2., (a->y + b->y) / 2., 0.); -} - -static inline gdouble pad_rad(pcb_pad_t * pad) -{ - return (lookup_thickness(pad->Name) / 2.) + lookup_clearance(pad->Name); -} - -static inline gdouble pin_rad(pcb_pin_t * pin) -{ - return (lookup_thickness(pin->Name) / 2.) + lookup_clearance(pin->Name); -} - -GList *rect_with_attachments(gdouble rad, - gdouble x0, gdouble y0, - gdouble x1, gdouble y1, gdouble x2, gdouble y2, gdouble x3, gdouble y3, gdouble z) -{ - GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class()); - GList *r = NULL, *rr = NULL, *i; - toporouter_vertex_t *curpoint, *temppoint; - - - curpoint = TOPOROUTER_VERTEX(gts_vertex_new(vertex_class, x0, y0, z)); - - r = g_list_prepend(NULL, curpoint); - r = g_list_prepend(r, gts_vertex_new(vertex_class, x1, y1, z)); - r = g_list_prepend(r, gts_vertex_new(vertex_class, x2, y2, z)); - r = g_list_prepend(r, gts_vertex_new(vertex_class, x3, y3, z)); - - i = r; - while (i) { - temppoint = TOPOROUTER_VERTEX(i->data); - rr = g_list_prepend(rr, curpoint); - - curpoint = temppoint; - i = i->next; - } - - g_list_free(r); - - return rr; -} - -#define VERTEX_CENTRE(x) TOPOROUTER_VERTEX( vertex_bbox(x)->point ) - -/* - * Read pad data from layer into toporouter_layer_t struct - * - * Inserts points and constraints into GLists - */ -int read_pads(toporouter_t * r, toporouter_layer_t * l, guint layer) -{ - toporouter_spoint_t p[2], rv[5]; - gdouble x[2], y[2], t, m; - - GList *vlist = NULL; - toporouter_bbox_t *bbox = NULL; - - back = front = -1; - if (pcb_layer_group_list(PCB_LYT_BOTTOM | PCB_LYT_COPPER, &back, 1) <= 0) - return -1; - if (pcb_layer_group_list(PCB_LYT_TOP | PCB_LYT_COPPER, &front, 1) <= 0) - return -1; - -/* printf("read_pads: front = %d back = %d layer = %d\n", - front, back, layer);*/ - - /* If its not the top or bottom layer, there are no pads to read */ - if (l - r->layers != front && l - r->layers != back) - return 0; - - PCB_ELEMENT_LOOP(PCB->Data); - { - PCB_PAD_LOOP(element); - { - if ((l - r->layers == back && PCB_FLAG_TEST(PCB_FLAG_ONSOLDER, pad)) || (l - r->layers == front && !PCB_FLAG_TEST(PCB_FLAG_ONSOLDER, pad))) { - - t = (gdouble) pad->Thickness / 2.0f; - x[0] = pad->Point1.X; - x[1] = pad->Point2.X; - y[0] = pad->Point1.Y; - y[1] = pad->Point2.Y; - - - if (PCB_FLAG_TEST(PCB_FLAG_SQUARE, pad)) { - /* Square or oblong pad. Four points and four constraint edges are - * used */ - - if (x[0] == x[1] && y[0] == y[1]) { - /* Pad is square */ - -/* vlist = g_list_prepend(NULL, gts_vertex_new (vertex_class, x[0]-t, y[0]-t, 0.)); - vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, x[0]-t, y[0]+t, 0.)); - vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, x[0]+t, y[0]+t, 0.)); - vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, x[0]+t, y[0]-t, 0.)); */ - vlist = rect_with_attachments(pad_rad(pad), - x[0] - t, y[0] - t, - x[0] - t, y[0] + t, x[0] + t, y[0] + t, x[0] + t, y[0] - t, l - r->layers); - bbox = toporouter_bbox_create(l - r->layers, vlist, PAD, pad); - r->bboxes = g_slist_prepend(r->bboxes, bbox); - insert_constraints_from_list(r, l, vlist, bbox); - g_list_free(vlist); - - /*bbox->point = GTS_POINT( gts_vertex_new(vertex_class, x[0], y[0], 0.) ); */ - bbox->point = GTS_POINT(insert_vertex(r, l, x[0], y[0], bbox)); - g_assert(TOPOROUTER_VERTEX(bbox->point)->bbox == bbox); - } - else { - /* Pad is diagonal oblong or othogonal oblong */ - - m = cartesian_gradient(x[0], y[0], x[1], y[1]); - - p[0].x = x[0]; - p[0].y = y[0]; - p[1].x = x[1]; - p[1].y = y[1]; - - vertex_outside_segment(&p[0], &p[1], t, &rv[0]); - vertices_on_line(&rv[0], perpendicular_gradient(m), t, &rv[1], &rv[2]); - - vertex_outside_segment(&p[1], &p[0], t, &rv[0]); - vertices_on_line(&rv[0], perpendicular_gradient(m), t, &rv[3], &rv[4]); - - if (wind(&rv[1], &rv[2], &rv[3]) != wind(&rv[2], &rv[3], &rv[4])) { - rv[0].x = rv[3].x; - rv[0].y = rv[3].y; - rv[3].x = rv[4].x; - rv[3].y = rv[4].y; - rv[4].x = rv[0].x; - rv[4].y = rv[0].y; - } - -/* vlist = g_list_prepend(NULL, gts_vertex_new (vertex_class, rv[1].x, rv[1].y, 0.)); - vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, rv[2].x, rv[2].y, 0.)); - vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, rv[3].x, rv[3].y, 0.)); - vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, rv[4].x, rv[4].y, 0.));*/ - vlist = rect_with_attachments(pad_rad(pad), - rv[1].x, rv[1].y, - rv[2].x, rv[2].y, rv[3].x, rv[3].y, rv[4].x, rv[4].y, l - r->layers); - bbox = toporouter_bbox_create(l - r->layers, vlist, PAD, pad); - r->bboxes = g_slist_prepend(r->bboxes, bbox); - insert_constraints_from_list(r, l, vlist, bbox); - g_list_free(vlist); - - /*bbox->point = GTS_POINT( gts_vertex_new(vertex_class, (x[0] + x[1]) / 2., (y[0] + y[1]) / 2., 0.) ); */ - bbox->point = GTS_POINT(insert_vertex(r, l, (x[0] + x[1]) / 2., (y[0] + y[1]) / 2., bbox)); - g_assert(TOPOROUTER_VERTEX(bbox->point)->bbox == bbox); - - } - - } - else { - /* Either round pad or pad with curved edges */ - - if (x[0] == x[1] && y[0] == y[1]) { - /* One point */ - - /* bounding box same as square pad */ - vlist = rect_with_attachments(pad_rad(pad), - x[0] - t, y[0] - t, - x[0] - t, y[0] + t, x[0] + t, y[0] + t, x[0] + t, y[0] - t, l - r->layers); - bbox = toporouter_bbox_create(l - r->layers, vlist, PAD, pad); - r->bboxes = g_slist_prepend(r->bboxes, bbox); - g_list_free(vlist); - - /*bbox->point = GTS_POINT( insert_vertex(r, l, x[0], y[0], bbox) ); */ - bbox->point = GTS_POINT(insert_vertex(r, l, x[0], y[0], bbox)); - - } - else { - /* Two points and one constraint edge */ - - /* the rest is just for bounding box */ - m = cartesian_gradient(x[0], y[0], x[1], y[1]); - - p[0].x = x[0]; - p[0].y = y[0]; - p[1].x = x[1]; - p[1].y = y[1]; - - vertex_outside_segment(&p[0], &p[1], t, &rv[0]); - vertices_on_line(&rv[0], perpendicular_gradient(m), t, &rv[1], &rv[2]); - - vertex_outside_segment(&p[1], &p[0], t, &rv[0]); - vertices_on_line(&rv[0], perpendicular_gradient(m), t, &rv[3], &rv[4]); - - if (wind(&rv[1], &rv[2], &rv[3]) != wind(&rv[2], &rv[3], &rv[4])) { - rv[0].x = rv[3].x; - rv[0].y = rv[3].y; - rv[3].x = rv[4].x; - rv[3].y = rv[4].y; - rv[4].x = rv[0].x; - rv[4].y = rv[0].y; - } - - vlist = rect_with_attachments(pad_rad(pad), - rv[1].x, rv[1].y, - rv[2].x, rv[2].y, rv[3].x, rv[3].y, rv[4].x, rv[4].y, l - r->layers); - bbox = toporouter_bbox_create(l - r->layers, vlist, PAD, pad); - r->bboxes = g_slist_prepend(r->bboxes, bbox); - insert_constraints_from_list(r, l, vlist, bbox); - g_list_free(vlist); - - /*bbox->point = GTS_POINT( gts_vertex_new(vertex_class, (x[0] + x[1]) / 2., (y[0] + y[1]) / 2., 0.) ); */ - bbox->point = GTS_POINT(insert_vertex(r, l, (x[0] + x[1]) / 2., (y[0] + y[1]) / 2., bbox)); - - /*bbox->constraints = g_list_concat(bbox->constraints, insert_constraint_edge(r, l, x[0], y[0], x[1], y[1], bbox)); */ - - } - - - } - - } - } - PCB_END_LOOP; - } - PCB_END_LOOP; - - return 0; -} - -/* - * Read points data (all layers) into GList - * - * Inserts pin and via points - */ -int read_points(toporouter_t * r, toporouter_layer_t * l, int layer) -{ - gdouble x, y, t; - - GList *vlist = NULL; - toporouter_bbox_t *bbox = NULL; - - PCB_ELEMENT_LOOP(PCB->Data); - { - PCB_PIN_LOOP(element); - { - - t = (gdouble) pin->Thickness / 2.0f; - x = pin->X; - y = pin->Y; - - if (PCB_FLAG_TEST(PCB_FLAG_SQUARE, pin)) { - - vlist = rect_with_attachments(pin_rad(pin), x - t, y - t, x - t, y + t, x + t, y + t, x + t, y - t, l - r->layers); - bbox = toporouter_bbox_create(l - r->layers, vlist, PIN, pin); - r->bboxes = g_slist_prepend(r->bboxes, bbox); - insert_constraints_from_list(r, l, vlist, bbox); - g_list_free(vlist); - bbox->point = GTS_POINT(insert_vertex(r, l, x, y, bbox)); - - } - else if (PCB_FLAG_TEST(PCB_FLAG_OCTAGON, pin)) { - /* TODO: Handle octagon pins */ - fprintf(stderr, "No support for octagon pins yet\n"); - } - else { - vlist = rect_with_attachments(pin_rad(pin), x - t, y - t, x - t, y + t, x + t, y + t, x + t, y - t, l - r->layers); - bbox = toporouter_bbox_create(l - r->layers, vlist, PIN, pin); - r->bboxes = g_slist_prepend(r->bboxes, bbox); - g_list_free(vlist); - bbox->point = GTS_POINT(insert_vertex(r, l, x, y, bbox)); - } - } - PCB_END_LOOP; - } - PCB_END_LOOP; - - PCB_VIA_LOOP(PCB->Data); - { - - t = (gdouble) via->Thickness / 2.0f; - x = via->X; - y = via->Y; - - if (PCB_FLAG_TEST(PCB_FLAG_SQUARE, via)) { - - vlist = rect_with_attachments(pin_rad((pcb_pin_t *) via), - x - t, y - t, x - t, y + t, x + t, y + t, x + t, y - t, l - r->layers); - bbox = toporouter_bbox_create(l - r->layers, vlist, VIA, via); - r->bboxes = g_slist_prepend(r->bboxes, bbox); - insert_constraints_from_list(r, l, vlist, bbox); - g_list_free(vlist); - bbox->point = GTS_POINT(insert_vertex(r, l, x, y, bbox)); - - } - else if (PCB_FLAG_TEST(PCB_FLAG_OCTAGON, via)) { - /* TODO: Handle octagon vias */ - fprintf(stderr, "No support for octagon vias yet\n"); - } - else { - - vlist = rect_with_attachments(pin_rad((pcb_pin_t *) via), - x - t, y - t, x - t, y + t, x + t, y + t, x + t, y - t, l - r->layers); - bbox = toporouter_bbox_create(l - r->layers, vlist, VIA, via); - r->bboxes = g_slist_prepend(r->bboxes, bbox); - g_list_free(vlist); - - bbox->point = GTS_POINT(insert_vertex(r, l, x, y, bbox)); - - } - } - PCB_END_LOOP; - return 0; -} - -/* - * Read line data from layer into toporouter_layer_t struct - * - * Inserts points and constraints into GLists - */ -int read_lines(toporouter_t * r, toporouter_layer_t * l, pcb_layer_t * layer, int ln) -{ - gdouble xs[2], ys[2]; - - GList *vlist = NULL; - toporouter_bbox_t *bbox = NULL; - - GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class()); - - PCB_LINE_LOOP(layer); - { - xs[0] = line->Point1.X; - xs[1] = line->Point2.X; - ys[0] = line->Point1.Y; - ys[1] = line->Point2.Y; - if (!(xs[0] == xs[1] && ys[0] == ys[1])) { - vlist = g_list_prepend(NULL, gts_vertex_new(vertex_class, xs[0], ys[0], l - r->layers)); - vlist = g_list_prepend(vlist, gts_vertex_new(vertex_class, xs[1], ys[1], l - r->layers)); - /* TODO: replace this with surface version */ - bbox = toporouter_bbox_create_from_points(pcb_layer_get_group(ln), vlist, LINE, line); - r->bboxes = g_slist_prepend(r->bboxes, bbox); - /*new;; - //insert_constraints_from_list(r, l, vlist, bbox); */ - g_list_free(vlist); -/* bbox->point = GTS_POINT( insert_vertex(r, l, (xs[0]+xs[1])/2., (ys[0]+ys[1])/2., bbox) );*/ - - bbox->constraints = - g_list_concat(bbox->constraints, insert_constraint_edge(r, l, xs[0], ys[0], 0, xs[1], ys[1], 0, bbox)); - } - } - PCB_END_LOOP; - - return 0; -} - -void create_board_edge(gdouble x0, gdouble y0, gdouble x1, gdouble y1, gdouble max, gint layer, GList ** vlist) -{ - GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class()); - gdouble d = sqrt(pow(x0 - x1, 2) + pow(y0 - y1, 2)); - guint n = d / max, count = 1; - gdouble inc = n ? d / n : d; - gdouble x = x0, y = y0; - - *vlist = g_list_prepend(*vlist, gts_vertex_new(vertex_class, x0, y0, layer)); - - while (count < n) { - coord_move_towards_coord_values(x0, y0, x1, y1, inc, &x, &y); - *vlist = g_list_prepend(*vlist, gts_vertex_new(vertex_class, x, y, layer)); - - x0 = x; - y0 = y; - count++; - } - -} - - -int read_board_constraints(toporouter_t * r, toporouter_layer_t * l, int layer) -{ -/* GtsVertexClass *vertex_class = GTS_VERTEX_CLASS (toporouter_vertex_class ());*/ - GList *vlist = NULL; - toporouter_bbox_t *bbox = NULL; - - /* Add points for corners of board, and constrain those edges */ -/* vlist = g_list_prepend(NULL, gts_vertex_new (vertex_class, 0., 0., layer)); - vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, PCB->MaxWidth, 0., layer)); - vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, PCB->MaxWidth, PCB->MaxHeight, layer)); - vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, 0., PCB->MaxHeight, layer));*/ - - create_board_edge(0., 0., PCB->MaxWidth, 0., 10000., layer, &vlist); - create_board_edge(PCB->MaxWidth, 0., PCB->MaxWidth, PCB->MaxHeight, 10000., layer, &vlist); - create_board_edge(PCB->MaxWidth, PCB->MaxHeight, 0., PCB->MaxHeight, 10000., layer, &vlist); - create_board_edge(0., PCB->MaxHeight, 0., 0., 10000., layer, &vlist); - - bbox = toporouter_bbox_create(layer, vlist, BOARD, NULL); - r->bboxes = g_slist_prepend(r->bboxes, bbox); - insert_constraints_from_list(r, l, vlist, bbox); - g_list_free(vlist); - - return 0; -} - -gdouble triangle_cost(GtsTriangle * t, gpointer * data) -{ - - gdouble *min_quality = (gdouble *) data[0]; - gdouble *max_area = (gdouble *) data[1]; - gdouble quality = gts_triangle_quality(t); - gdouble area = gts_triangle_area(t); - - if (quality < *min_quality || area > *max_area) - return quality; - return 0.0; -} - - -void print_constraint(toporouter_constraint_t * e) -{ - printf("CONSTRAINT:\n"); - print_vertex(tedge_v1(e)); - print_vertex(tedge_v2(e)); -} - -void print_edge(toporouter_edge_t * e) -{ - GList *i = edge_routing(e); - - printf("EDGE:\n"); - - print_vertex(tedge_v1(e)); - - while (i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); - print_vertex(v); - i = i->next; - } - - print_vertex(tedge_v2(e)); -} - -static void pick_first_face(GtsFace * f, GtsFace ** first) -{ - if (*first == NULL) - *first = f; -} - -void unconstrain(toporouter_layer_t * l, toporouter_constraint_t * c) -{ - toporouter_edge_t *e; - - gts_allow_floating_vertices = TRUE; - e = TOPOROUTER_EDGE(gts_edge_new(GTS_EDGE_CLASS(toporouter_edge_class()), GTS_SEGMENT(c)->v1, GTS_SEGMENT(c)->v2)); - gts_edge_replace(GTS_EDGE(c), GTS_EDGE(e)); - l->constraints = g_list_remove(l->constraints, c); - c->box->constraints = g_list_remove(c->box->constraints, c); - c->box = NULL; - gts_object_destroy(GTS_OBJECT(c)); - gts_allow_floating_vertices = FALSE; -} - -void build_cdt(toporouter_t * r, toporouter_layer_t * l) -{ - /* TODO: generalize into surface *cdt_create(vertices, constraints) */ - GList *i; - /*GtsEdge *temp; - GtsVertex *v; */ - GtsTriangle *t; - GtsVertex *v1, *v2, *v3; - GSList *vertices_slist; - - vertices_slist = list_to_slist(l->vertices); - - if (l->surface) { - GtsFace *first = NULL; - gts_surface_foreach_face(l->surface, (GtsFunc) pick_first_face, &first); - gts_surface_traverse_destroy(gts_surface_traverse_new(l->surface, first)); - } - - t = gts_triangle_enclosing(gts_triangle_class(), vertices_slist, 1000.0f); - gts_triangle_vertices(t, &v1, &v2, &v3); - - g_slist_free(vertices_slist); - - l->surface = gts_surface_new(gts_surface_class(), gts_face_class(), - GTS_EDGE_CLASS(toporouter_edge_class()), GTS_VERTEX_CLASS(toporouter_vertex_class())); - - gts_surface_add_face(l->surface, gts_face_new(gts_face_class(), t->e1, t->e2, t->e3)); - - -/* fprintf(stderr, "ADDED VERTICES\n");*/ -/* - GtsFace *debugface; - - if((debugface = gts_delaunay_check(l->surface))) { - fprintf(stderr, "WARNING: Delaunay check failed\n"); - fprintf(stderr, "\tViolating triangle:\n"); - fprintf(stderr, "\t%f,%f %f,%f\n", - debugface->triangle.e1->segment.v1->p.x, - debugface->triangle.e1->segment.v1->p.y, - debugface->triangle.e1->segment.v2->p.x, - debugface->triangle.e1->segment.v2->p.y - ); - fprintf(stderr, "\t%f,%f %f,%f\n", - debugface->triangle.e2->segment.v1->p.x, - debugface->triangle.e2->segment.v1->p.y, - debugface->triangle.e2->segment.v2->p.x, - debugface->triangle.e2->segment.v2->p.y - ); - fprintf(stderr, "\t%f,%f %f,%f\n", - debugface->triangle.e3->segment.v1->p.x, - debugface->triangle.e3->segment.v1->p.y, - debugface->triangle.e3->segment.v2->p.x, - debugface->triangle.e3->segment.v2->p.y - ); -/* toporouter_draw_surface(r, l->surface, "debug.png", 4096, 4096); */ - { - int i; - for (i = 0; i < groupcount(); i++) { - char buffer[256]; - sprintf(buffer, "debug-%d.png", i); - toporouter_draw_surface(r, r->layers[i].surface, buffer, 2048, 2048, 2, NULL, i, NULL); - } - } - -/* }*/ - -check_cons_continuation: - i = l->constraints; - while (i) { - toporouter_constraint_t *c1 = TOPOROUTER_CONSTRAINT(i->data); - GList *j = i->next; - /* printf("adding cons: "); print_constraint(c1); */ - - while (j) { - toporouter_constraint_t *c2 = TOPOROUTER_CONSTRAINT(j->data); - guint rem = 0; - GList *temp; - - /* printf("\tconflict: "); print_constraint(c2); */ - toporouter_bbox_t *c1box = c1->box, *c2box = c2->box; - toporouter_vertex_t *c1v1 = tedge_v1(c1); - toporouter_vertex_t *c1v2 = tedge_v2(c1); - toporouter_vertex_t *c2v1 = tedge_v1(c2); - toporouter_vertex_t *c2v2 = tedge_v2(c2); - - if (gts_segments_are_intersecting(GTS_SEGMENT(c1), GTS_SEGMENT(c2)) == GTS_IN) { - toporouter_vertex_t *v; - unconstrain(l, c1); - unconstrain(l, c2); - rem = 1; - /* proper intersection */ - v = TOPOROUTER_VERTEX(vertex_intersect(GTS_VERTEX(c1v1), GTS_VERTEX(c1v2), GTS_VERTEX(c2v1), GTS_VERTEX(c2v2))); - - /* remove both constraints - replace with 4x constraints - insert new intersection vertex */ - GTS_POINT(v)->z = vz(c1v1); - - l->vertices = g_list_prepend(l->vertices, v); -/* gts_delaunay_add_vertex (l->surface, GTS_VERTEX(v), NULL); */ - - v->bbox = c1box; - - temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(v), vy(v), 0, c1box); - c1box->constraints = g_list_concat(c1box->constraints, temp); - - temp = insert_constraint_edge(r, l, vx(c1v2), vy(c1v2), 0, vx(v), vy(v), 0, c1box); - c1box->constraints = g_list_concat(c1box->constraints, temp); - - temp = insert_constraint_edge(r, l, vx(c2v1), vy(c2v1), 0, vx(v), vy(v), 0, c2box); - c2box->constraints = g_list_concat(c2box->constraints, temp); - - temp = insert_constraint_edge(r, l, vx(c2v2), vy(c2v2), 0, vx(v), vy(v), 0, c2box); - c2box->constraints = g_list_concat(c2box->constraints, temp); - - } - else if (gts_segments_are_intersecting(GTS_SEGMENT(c1), GTS_SEGMENT(c2)) == GTS_ON || - gts_segments_are_intersecting(GTS_SEGMENT(c2), GTS_SEGMENT(c1)) == GTS_ON) { - - if (vertex_between(edge_v1(c2), edge_v2(c2), edge_v1(c1)) && vertex_between(edge_v1(c2), edge_v2(c2), edge_v2(c1))) { - unconstrain(l, c1); - unconstrain(l, c2); - rem = 1; - /* remove c1 */ - temp = insert_constraint_edge(r, l, vx(c2v1), vy(c2v1), 0, vx(c2v2), vy(c2v2), 0, c2box); - c2box->constraints = g_list_concat(c2box->constraints, temp); - - } - else if (vertex_between(edge_v1(c1), edge_v2(c1), edge_v1(c2)) && vertex_between(edge_v1(c1), edge_v2(c1), edge_v2(c2))) { - unconstrain(l, c1); - unconstrain(l, c2); - rem = 1; - /* remove c2 */ - temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c1v2), vy(c1v2), 0, c1box); - c1box->constraints = g_list_concat(c1box->constraints, temp); - - /*}else if(!vertex_wind(edge_v1(c1), edge_v2(c1), edge_v1(c2)) && !vertex_wind(edge_v1(c1), edge_v2(c1), edge_v2(c2))) { */ - /* }else if(vertex_between(edge_v1(c1), edge_v2(c1), edge_v1(c2)) || vertex_between(edge_v1(c1), edge_v2(c1), edge_v2(c2))) { - unconstrain(l, c1); unconstrain(l, c2); - rem = 1; - printf("all colinear\n"); - // exit(1); - temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c1v2), vy(c1v2), 0, c1box); - c1box->constraints = g_list_concat(c1box->constraints, temp); - - if(vertex_between(GTS_VERTEX(c1v1), GTS_VERTEX(c1v2), GTS_VERTEX(c2v2))) { - // v2 of c2 is inner - if(vertex_between(GTS_VERTEX(c2v1), GTS_VERTEX(c2v2), GTS_VERTEX(c1v2))) { - // v2 of c1 is inner - // c2 = c1.v2 -> c2.v1 - temp = insert_constraint_edge(r, l, vx(c1v2), vy(c1v2), 0, vx(c2v1), vy(c2v1), 0, c2box); - c2box->constraints = g_list_concat(c2box->constraints, temp); - }else{ - // v1 of c1 is inner - // c2 = c1.v1 -> c2.v1 - temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c2v1), vy(c2v1), 0, c2box); - c2box->constraints = g_list_concat(c2box->constraints, temp); - } - }else{ - // v1 of c2 is inner - if(vertex_between(GTS_VERTEX(c2v1), GTS_VERTEX(c2v2), GTS_VERTEX(c1v2))) { - // v2 of c1 is inner - // c2 = c1.v2 -> c2.v2 - temp = insert_constraint_edge(r, l, vx(c1v2), vy(c1v2), 0, vx(c2v2), vy(c2v2), 0, c2box); - c2box->constraints = g_list_concat(c2box->constraints, temp); - }else{ - // v1 of c1 is inner - // c2 = c1.v1 -> c2.v2 - temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c2v2), vy(c2v2), 0, c2box); - c2box->constraints = g_list_concat(c2box->constraints, temp); - } - } */ - } - else if (vertex_between(edge_v1(c2), edge_v2(c2), edge_v1(c1)) && c1v1 != c2v1 && c1v1 != c2v2) { - unconstrain(l, c1); - unconstrain(l, c2); - rem = 1; - /*v1 of c1 is on c2 */ - printf("v1 of c1 on c2\n"); - - /* replace with 2x constraints */ - temp = insert_constraint_edge(r, l, vx(c2v1), vy(c2v1), 0, vx(c1v1), vy(c1v1), 0, c2box); - c2box->constraints = g_list_concat(c2box->constraints, temp); - temp = insert_constraint_edge(r, l, vx(c2v2), vy(c2v2), 0, vx(c1v1), vy(c1v1), 0, c2box); - c2box->constraints = g_list_concat(c2box->constraints, temp); - - temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c1v2), vy(c1v2), 0, c1box); - c1box->constraints = g_list_concat(c1box->constraints, temp); - - /* restore c1 - temp = insert_constraint_edge(r, l, vx(tedge_v2(c1)), vy(tedge_v2(c1)), 0, vx(tedge_v1(c1)), vy(tedge_v1(c1)), 0, c1->box); - c2->box->constraints = g_list_concat(c2->box->constraints, temp); */ - - } - else if (vertex_between(edge_v1(c2), edge_v2(c2), edge_v2(c1)) && c1v2 != c2v1 && c1v2 != c2v2) { - unconstrain(l, c1); - unconstrain(l, c2); - rem = 1; - /*v2 of c1 is on c2 */ - printf("v2 of c1 on c2\n"); - - /* replace with 2x constraints */ - temp = insert_constraint_edge(r, l, vx(c2v1), vy(c2v1), 0, vx(c1v2), vy(c1v2), 0, c2box); - c2box->constraints = g_list_concat(c2box->constraints, temp); - temp = insert_constraint_edge(r, l, vx(c2v2), vy(c2v2), 0, vx(c1v2), vy(c1v2), 0, c2box); - c2box->constraints = g_list_concat(c2box->constraints, temp); - - temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c1v2), vy(c1v2), 0, c1box); - c1box->constraints = g_list_concat(c1box->constraints, temp); - - } - else if (vertex_between(edge_v1(c1), edge_v2(c1), edge_v1(c2)) && c2v1 != c1v1 && c2v1 != c1v2) { - unconstrain(l, c1); - unconstrain(l, c2); - rem = 1; - /*v1 of c2 is on c1 */ - printf("v1 of c2 on c1\n"); - - /* replace with 2x constraints */ - temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c2v1), vy(c2v1), 0, c1box); - c1box->constraints = g_list_concat(c1box->constraints, temp); - temp = insert_constraint_edge(r, l, vx(c1v2), vy(c1v2), 0, vx(c2v1), vy(c2v1), 0, c1box); - c1box->constraints = g_list_concat(c1box->constraints, temp); - - temp = insert_constraint_edge(r, l, vx(c2v1), vy(c2v1), 0, vx(c2v2), vy(c2v2), 0, c2box); - c2box->constraints = g_list_concat(c2box->constraints, temp); - } - else if (vertex_between(edge_v1(c1), edge_v2(c1), edge_v2(c2)) && c2v2 != c1v1 && c2v2 != c1v2) { - unconstrain(l, c1); - unconstrain(l, c2); - rem = 1; - /*v2 of c2 is on c1 */ - printf("v2 of c2 on c1\n"); - - /* replace with 2x constraints */ - temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c2v2), vy(c2v2), 0, c1box); - c1box->constraints = g_list_concat(c1box->constraints, temp); - temp = insert_constraint_edge(r, l, vx(c1v2), vy(c1v2), 0, vx(c2v2), vy(c2v2), 0, c1box); - c1box->constraints = g_list_concat(c1box->constraints, temp); - - temp = insert_constraint_edge(r, l, vx(c2v1), vy(c2v1), 0, vx(c2v2), vy(c2v2), 0, c2box); - c2box->constraints = g_list_concat(c2box->constraints, temp); - } - } - if (rem) - goto check_cons_continuation; - - j = j->next; - } - - i = i->next; - } - - i = l->vertices; - while (i) { - /*v = i->data; - if(r->flags & TOPOROUTER_FLAG_DEBUG_CDTS) - fprintf(stderr, "\tadding vertex %f,%f\n", v->p.x, v->p.y); */ - toporouter_vertex_t *v = TOPOROUTER_VERTEX(gts_delaunay_add_vertex(l->surface, (GtsVertex *) i->data, NULL)); - if (v) { - printf("conflict: "); - print_vertex(v); - } - - i = i->next; - } - i = l->constraints; - while (i) { - - /* toporouter_constraint_t *c1 = TOPOROUTER_CONSTRAINT(i->data); - printf("adding cons: "); print_constraint(c1); */ - - GSList *conflicts = gts_delaunay_add_constraint(l->surface, (GtsConstraint *) i->data); - GSList *j = conflicts; - while (j) { - if (TOPOROUTER_IS_CONSTRAINT(j->data)) { - toporouter_constraint_t *c2 = TOPOROUTER_CONSTRAINT(j->data); - - printf("\tconflict: "); - print_constraint(c2); - - } - j = j->next; - } - g_slist_free(conflicts); - - i = i->next; - } - -/* if(rerun) - goto build_cdt_continuation; - fprintf(stderr, "ADDED CONSTRAINTS\n");*/ - gts_allow_floating_vertices = TRUE; - gts_object_destroy(GTS_OBJECT(v1)); - gts_object_destroy(GTS_OBJECT(v2)); - gts_object_destroy(GTS_OBJECT(v3)); - gts_allow_floating_vertices = FALSE; - -/* - { - gpointer data[2]; - gdouble quality = 0.50, area = G_MAXDOUBLE; - guint num = gts_delaunay_conform(l->surface, -1, (GtsEncroachFunc) gts_vertex_encroaches_edge, NULL); - - if (num == 0){ - data[0] = &quality; - data[1] = &area; - num = gts_delaunay_refine(l->surface, -1, (GtsEncroachFunc) gts_vertex_encroaches_edge, NULL, (GtsKeyFunc) triangle_cost, data); - } - } -*/ -#ifdef DEBUG_IMPORT - gts_surface_print_stats(l->surface, stderr); -#endif - -#if 0 - { - char buffer[64]; - FILE *fout2; - sprintf(buffer, "surface%d.gts", l - r->layers); - fout2 = fopen(buffer, "w"); - gts_surface_write(l->surface, fout2); - } -#endif - -} - -gint visited_cmp(gconstpointer a, gconstpointer b) -{ - if (a < b) - return -1; - if (a > b) - return 1; - return 0; -} - -gdouble coord_xangle(gdouble ax, gdouble ay, gdouble bx, gdouble by) -{ - gdouble dx, dy, theta; - - dx = fabs(ax - bx); - dy = fabs(ay - by); - - if (dx < EPSILON) { - theta = M_PI / 2.; - } - else - theta = atan(dy / dx); - - if (by <= ay) { - if (bx < ax) - theta = M_PI - theta; - } - else { - if (bx < ax) - theta += M_PI; - else - theta = (2 * M_PI) - theta; - } - - return theta; -} - -gdouble point_xangle(GtsPoint * a, GtsPoint * b) -{ - gdouble dx, dy, theta; - - dx = fabs(a->x - b->x); - dy = fabs(a->y - b->y); - - if (dx < EPSILON) { - theta = M_PI / 2.; - } - else - theta = atan(dy / dx); - - if (b->y >= a->y) { - if (b->x < a->x) - theta = M_PI - theta; - } - else { - if (b->x < a->x) - theta += M_PI; - else - theta = (2 * M_PI) - theta; - } - - return theta; -} - - -GList *cluster_vertices(toporouter_t * r, toporouter_cluster_t * c) -{ - GList *rval = NULL; - - if (!c) - return NULL; - - FOREACH_CLUSTER(c->netlist->clusters) { - if ((r->flags & TOPOROUTER_FLAG_AFTERRUBIX && cluster->c == c->c) - || (!(r->flags & TOPOROUTER_FLAG_AFTERRUBIX) && cluster == c)) { - FOREACH_BBOX(cluster->boxes) { - if (box->type == LINE) { - g_assert(box->constraints->data); - rval = g_list_prepend(rval, tedge_v1(box->constraints->data)); - rval = g_list_prepend(rval, tedge_v2(box->constraints->data)); - } - else if (box->point) { - rval = g_list_prepend(rval, TOPOROUTER_VERTEX(box->point)); - /*g_assert(vertex_bbox(TOPOROUTER_VERTEX(box->point)) == box); */ - } - else { - printf("WARNING: cluster_vertices: unhandled bbox type\n"); - } - - } - FOREACH_END; - - - } - - } - FOREACH_END; - - return rval; -} - -void print_cluster(toporouter_cluster_t * c) -{ - - if (!c) { - printf("[CLUSTER (NULL)]\n"); - return; - } - - printf("CLUSTER %d: NETLIST = %s STYLE = %s\n", c->c, c->netlist->netlist, c->netlist->style); - - FOREACH_BBOX(c->boxes) { - print_bbox(box); - } - FOREACH_END; -} - - -toporouter_cluster_t *cluster_create(toporouter_t * r, toporouter_netlist_t * netlist) -{ - toporouter_cluster_t *c = (toporouter_cluster_t *) malloc(sizeof(toporouter_cluster_t)); - - c->c = c->pc = netlist->clusters->len; - g_ptr_array_add(netlist->clusters, c); - c->netlist = netlist; - c->boxes = g_ptr_array_new(); - - return c; -} - -toporouter_bbox_t *toporouter_bbox_locate(toporouter_t * r, toporouter_term_t type, void *data, gdouble x, gdouble y, - guint layergroup) -{ - GtsPoint *p = gts_point_new(gts_point_class(), x, y, layergroup); - GSList *boxes = gts_bb_tree_stabbed(r->bboxtree, p), *i = boxes; - - gts_object_destroy(GTS_OBJECT(p)); - - while (i) { - toporouter_bbox_t *box = TOPOROUTER_BBOX(i->data); - - if (box->type == type && box->data == data) { - g_slist_free(boxes); - return box; - } - - i = i->next; - } - - g_slist_free(boxes); - return NULL; -} - -void cluster_join_bbox(toporouter_cluster_t * cluster, toporouter_bbox_t * box) -{ - if (box) { - g_ptr_array_add(cluster->boxes, box); - box->cluster = cluster; - } -} - -toporouter_netlist_t *netlist_create(toporouter_t * r, char *netlist, char *style) -{ - toporouter_netlist_t *nl = (toporouter_netlist_t *) malloc(sizeof(toporouter_netlist_t)); - nl->netlist = netlist; - nl->style = style; - nl->clusters = g_ptr_array_new(); - nl->routes = g_ptr_array_new(); - nl->routed = NULL; - nl->pair = NULL; - g_ptr_array_add(r->netlists, nl); - return nl; -} - -void import_clusters(toporouter_t * r) -{ - pcb_netlist_list_t nets; - pcb_reset_conns(pcb_false); - nets = pcb_rat_collect_subnets(pcb_false); - PCB_NETLIST_LOOP(&nets); - { - if (netlist->NetN > 0) { - toporouter_netlist_t *nl = netlist_create(r, netlist->Net->Connection->menu->Name, netlist->Net->Connection->menu->Style); - - PCB_NET_LOOP(netlist); - { - - toporouter_cluster_t *cluster = cluster_create(r, nl); -#ifdef DEBUG_MERGING - printf("NET:\n"); -#endif - PCB_CONNECTION_LOOP(net); - { - - if (connection->type == PCB_TYPE_LINE) { - pcb_line_t *line = (pcb_line_t *) connection->ptr2; - toporouter_bbox_t *box = toporouter_bbox_locate(r, LINE, line, connection->X, connection->Y, connection->group); - cluster_join_bbox(cluster, box); - -#ifdef DEBUG_MERGING - pcb_printf("\tLINE %#mD\n", connection->X, connection->Y); -#endif - } - else if (connection->type == PCB_TYPE_PAD) { - pcb_pad_t *pad = (pcb_pad_t *) connection->ptr2; - toporouter_bbox_t *box = toporouter_bbox_locate(r, PAD, pad, connection->X, connection->Y, connection->group); - cluster_join_bbox(cluster, box); - -#ifdef DEBUG_MERGING - pcb_printf("\tPAD %#mD\n", connection->X, connection->Y); -#endif - } - else if (connection->type == PCB_TYPE_PIN) { - guint m; - for (m = 0; m < groupcount(); m++) { - pcb_pin_t *pin = (pcb_pin_t *) connection->ptr2; - toporouter_bbox_t *box = toporouter_bbox_locate(r, PIN, pin, connection->X, connection->Y, m); - cluster_join_bbox(cluster, box); - } - -#ifdef DEBUG_MERGING - pcb_printf("\tPIN %#mD\n", connection->X, connection->Y); -#endif - } - else if (connection->type == PCB_TYPE_VIA) { - guint m; - for (m = 0; m < groupcount(); m++) { - pcb_pin_t *pin = (pcb_pin_t *) connection->ptr2; - toporouter_bbox_t *box = toporouter_bbox_locate(r, VIA, pin, connection->X, connection->Y, m); - cluster_join_bbox(cluster, box); - } - -#ifdef DEBUG_MERGING - pcb_printf("\tVIA %#mD\n", connection->X, connection->Y); -#endif - } - else if (connection->type == PCB_TYPE_POLYGON) { - pcb_polygon_t *polygon = (pcb_polygon_t *) connection->ptr2; - toporouter_bbox_t *box = - toporouter_bbox_locate(r, POLYGON, polygon, connection->X, connection->Y, connection->group); - cluster_join_bbox(cluster, box); - -#ifdef DEBUG_MERGING - pcb_printf("\tPOLYGON %#mD\n", connection->X, connection->Y); -#endif - - } - } - PCB_END_LOOP; -#ifdef DEBUG_MERGING - printf("\n"); -#endif - } - PCB_END_LOOP; - - } - } - PCB_END_LOOP; - pcb_netlist_list_free(&nets); -} - -void import_geometry(toporouter_t * r) -{ - toporouter_layer_t *cur_layer; - - int group; - -#ifdef DEBUG_IMPORT - for (group = 0; group < pcb_max_group; group++) { - printf("Group %d: Number %d:\n", group, PCB->LayerGroups.Number[group]); - - for (int entry = 0; entry < PCB->LayerGroups.Number[group]; entry++) { - printf("\tEntry %d\n", PCB->LayerGroups.Entries[group][entry]); - } - } -#endif - /* Allocate space for per layer struct */ - cur_layer = r->layers = (toporouter_layer_t *) malloc(groupcount() * sizeof(toporouter_layer_t)); - - /* Foreach layer, read in pad vertices and constraints, and build CDT */ - for (group = 0; group < pcb_max_group; group++) { -#ifdef DEBUG_IMPORT - printf("*** LAYER GROUP %d ***\n", group); -#endif - if (PCB->LayerGroups.Number[group] > 0) { - cur_layer->vertices = NULL; - cur_layer->constraints = NULL; - -#ifdef DEBUG_IMPORT - printf("reading board constraints from layer %d into group %d\n", PCB->LayerGroups.Entries[group][0], group); -#endif - read_board_constraints(r, cur_layer, PCB->LayerGroups.Entries[group][0]); -#ifdef DEBUG_IMPORT - printf("reading points from layer %d into group %d \n", PCB->LayerGroups.Entries[group][0], group); -#endif - read_points(r, cur_layer, PCB->LayerGroups.Entries[group][0]); - -/*#ifdef DEBUG_IMPORT - printf("reading pads from layer %d into group %d\n", number, group); - #endif*/ - read_pads(r, cur_layer, group); - - PCB_COPPER_GROUP_LOOP(PCB->Data, group) { - -#ifdef DEBUG_IMPORT - printf("reading lines from layer %d into group %d\n", number, group); -#endif - read_lines(r, cur_layer, layer, number); - - } - PCB_END_LOOP; - - - -#ifdef DEBUG_IMPORT - printf("building CDT\n"); -#endif - build_cdt(r, cur_layer); - printf("finished\n"); -/* { - int i; - for(i=0;ilayers[i].surface, buffer, 2048, 2048, 2, NULL, i, NULL); - } - }*/ -#ifdef DEBUG_IMPORT - printf("finished building CDT\n"); -#endif - cur_layer++; - } - } - - r->bboxtree = gts_bb_tree_new(r->bboxes); - - import_clusters(r); - -#ifdef DEBUG_IMPORT - printf("finished import!\n"); -#endif -} - - -gint compare_points(gconstpointer a, gconstpointer b) -{ - GtsPoint *i = GTS_POINT(a); - GtsPoint *j = GTS_POINT(b); - - if (i->x == j->x) { - if (i->y == j->y) - return 0; - if (i->y < j->y) - return -1; - return 1; - } - if (i->x < j->x) - return -1; - return 1; -} - -gint compare_segments(gconstpointer a, gconstpointer b) -{ - if (a == b) - return 0; - if (a < b) - return -1; - return 1; -} - -#define DEBUG_CLUSTER_FIND 1 -toporouter_cluster_t *cluster_find(toporouter_t * r, gdouble x, gdouble y, gdouble z) -{ - GtsPoint *p = gts_point_new(gts_point_class(), x, y, z); - GSList *hits = gts_bb_tree_stabbed(r->bboxtree, p); - toporouter_cluster_t *rval = NULL; - -#ifdef DEBUG_CLUSTER_FIND - printf("FINDING %f,%f,%f\n\n", x, y, z); -#endif - - while (hits) { - toporouter_bbox_t *box = TOPOROUTER_BBOX(hits->data); - -#ifdef DEBUG_CLUSTER_FIND - printf("HIT BOX: "); - print_bbox(box); -#endif - - if (box->layer == (int) z) { - if (box->type != BOARD) { - if (box->type == LINE) { - pcb_line_t *line = (pcb_line_t *) box->data; - gint linewind = coord_wind(line->Point1.X, line->Point1.Y, x, y, line->Point2.X, line->Point2.Y); - - if (line->Point1.X > x - EPSILON && line->Point1.X < x + EPSILON && - line->Point1.Y > y - EPSILON && line->Point1.Y < y + EPSILON) { - rval = box->cluster; - /* break; */ - } - if (line->Point2.X > x - EPSILON && line->Point2.X < x + EPSILON && - line->Point2.Y > y - EPSILON && line->Point2.Y < y + EPSILON) { - rval = box->cluster; - /* break; */ - } - if (!linewind) { - rval = box->cluster; - /* break; */ - } - - } - else if (box->surface) { - - if (gts_point_locate(p, box->surface, NULL)) { - rval = box->cluster; - break; - } - - } - } - } - hits = hits->next; - } - - gts_object_destroy(GTS_OBJECT(p)); - - -#ifdef DEBUG_CLUSTER_FIND - printf("cluster_find: %f,%f,%f: ", x, y, z); - print_cluster(rval); -#endif - - return rval; -} - -gdouble simple_h_cost(toporouter_t * r, toporouter_vertex_t * curpoint, toporouter_vertex_t * destpoint) -{ - gdouble layerpenalty = (vz(curpoint) == vz(destpoint)) ? 0. : r->viacost; - - return gts_point_distance(GTS_POINT(curpoint), GTS_POINT(destpoint)) + layerpenalty; -} - -#define FCOST(x) (x->gcost + x->hcost) -gdouble route_heap_cmp(gpointer item, gpointer data) -{ - return FCOST(TOPOROUTER_VERTEX(item)); -} - -#define closelist_insert(p) closelist = g_list_prepend(closelist, p) - -typedef struct { - toporouter_vertex_t *key; - toporouter_vertex_t *result; -} toporouter_heap_search_data_t; - -void toporouter_heap_search(gpointer data, gpointer user_data) -{ - toporouter_vertex_t *v = TOPOROUTER_VERTEX(data); - toporouter_heap_search_data_t *heap_search_data = (toporouter_heap_search_data_t *) user_data; - if (v == heap_search_data->key) - heap_search_data->result = v; -} - -/* -void -toporouter_heap_color(gpointer data, gpointer user_data) -{ - toporouter_vertex_t *v = TOPOROUTER_VERTEX(data); - v->flags |= (guint) user_data; -} -*/ -static inline gdouble angle_span(gdouble a1, gdouble a2) -{ - if (a1 > a2) - return ((2 * M_PI) - a1 + a2); - return a2 - a1; -} - -gdouble region_span(toporouter_vertex_region_t * region) -{ - gdouble a1, a2; - - g_assert(region->v1 != NULL); - g_assert(region->v2 != NULL); - g_assert(region->origin != NULL); - - a1 = point_xangle(GTS_POINT(region->origin), GTS_POINT(region->v1)); - a2 = point_xangle(GTS_POINT(region->origin), GTS_POINT(region->v2)); - - return angle_span(a1, a2); -} - -gdouble edge_capacity(toporouter_edge_t * e) -{ - return gts_point_distance(GTS_POINT(edge_v1(e)), GTS_POINT(edge_v2(e))); -} - -gdouble edge_flow(toporouter_edge_t * e, toporouter_vertex_t * v1, toporouter_vertex_t * v2, toporouter_vertex_t * dest) -{ - GList *i = edge_routing(e); - toporouter_vertex_t *pv = tedge_v1(e), *v = NULL; - gdouble flow = 0.; - guint waiting = 1; - - if ((pv == v1 || pv == v2) && waiting) { - flow += min_vertex_net_spacing(pv, dest); - pv = dest; - waiting = 0; - } - - g_assert(v1 != v2); - - while (i) { - v = TOPOROUTER_VERTEX(i->data); - - - if (pv == dest) - flow += min_vertex_net_spacing(v, pv); - else - flow += min_spacing(v, pv); - - if ((v == v1 || v == v2) && waiting) { - flow += min_vertex_net_spacing(v, dest); - pv = dest; - waiting = 0; - } - else { - pv = v; - } - i = i->next; - } - - if (pv == dest) - flow += min_vertex_net_spacing(tedge_v2(e), pv); - else - flow += min_spacing(tedge_v2(e), pv); - - return flow; -} - -void print_path(GList * path) -{ - GList *i = path; - - printf("PATH:\n"); - while (i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); -/* printf("[V %f,%f,%f]\n", vx(v), vy(v), vz(v));*/ - print_vertex(v); - - if (v->child && !g_list_find(path, v->child)) - printf("\t CHILD NOT IN LIST\n"); - if (v->parent && !g_list_find(path, v->parent)) - printf("\t parent NOT IN LIST\n"); - i = i->next; - } - - -} - -GList *split_path(GList * path) -{ - toporouter_vertex_t *pv = NULL; - GList *curpath = NULL, *i, *paths = NULL; -#ifdef DEBUG_ROUTE - printf("PATH:\n"); -#endif - i = path; - while (i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); - -#ifdef DEBUG_ROUTE - printf("v = %f,%f ", vx(v), vy(v)); - if (v->parent) - printf("parent = %f,%f ", vx(v->parent), vy(v->parent)); - if (v->child) - printf("child = %f,%f ", vx(v->child), vy(v->child)); - printf("\n"); -#endif -/* printf("***\n"); - if(v) printf("v = %f,%f\n", GTS_POINT(v)->x, GTS_POINT(v)->y); - if(pv) printf("pv = %f,%f\n", GTS_POINT(pv)->x, GTS_POINT(pv)->y);*/ - - - if (pv) - if (GTS_POINT(v)->x == GTS_POINT(pv)->x && GTS_POINT(v)->y == GTS_POINT(pv)->y) { - if (g_list_length(curpath) > 1) - paths = g_list_prepend(paths, curpath); - curpath = NULL; - - pv->child = NULL; - v->parent = NULL; - } - - curpath = g_list_append(curpath, v); - - pv = v; - i = i->next; - } - - if (g_list_length(curpath) > 1) - paths = g_list_prepend(paths, curpath); - - return paths; -} - - - -#define edge_gradient(e) (cartesian_gradient(GTS_POINT(GTS_SEGMENT(e)->v1)->x, GTS_POINT(GTS_SEGMENT(e)->v1)->y, \ - GTS_POINT(GTS_SEGMENT(e)->v2)->x, GTS_POINT(GTS_SEGMENT(e)->v2)->y)) - - -/* sorting into ascending distance from v1 */ -gint routing_edge_insert(gconstpointer a, gconstpointer b, gpointer user_data) -{ - GtsPoint *v1 = GTS_POINT(edge_v1(user_data)); - - if (gts_point_distance2(v1, GTS_POINT(a)) < gts_point_distance2(v1, GTS_POINT(b)) - EPSILON) - return -1; - if (gts_point_distance2(v1, GTS_POINT(a)) > gts_point_distance2(v1, GTS_POINT(b)) + EPSILON) - return 1; -/* - printf("a = %x b = %x\n", (int) a, (int) b); - - printf("WARNING: routing_edge_insert() with same points..\n \ - v1 @ %f,%f\n\ - a @ %f,%f\n\ - b @ %f,%f\n", - v1->x, v1->y, - vx(a), vy(a), - vx(a), vy(b)); - printf("A: "); print_vertex(TOPOROUTER_VERTEX(a)); - printf("B: "); print_vertex(TOPOROUTER_VERTEX(b)); - - TOPOROUTER_VERTEX(a)->flags |= VERTEX_FLAG_RED; - TOPOROUTER_VERTEX(b)->flags |= VERTEX_FLAG_RED; -*/ - return 0; -} - - -toporouter_vertex_t *new_temp_toporoutervertex(gdouble x, gdouble y, toporouter_edge_t * e) -{ - GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class()); - GList *i = edge_routing(e); - toporouter_vertex_t *r; - - while (i) { - r = TOPOROUTER_VERTEX(i->data); - if (epsilon_equals(vx(r), x) && epsilon_equals(vy(r), y)) { - if (r->flags & VERTEX_FLAG_TEMP) - return r; - } - i = i->next; - } - - r = TOPOROUTER_VERTEX(gts_vertex_new(vertex_class, x, y, vz(edge_v1(e)))); - r->flags |= VERTEX_FLAG_TEMP; - r->routingedge = e; - - if (TOPOROUTER_IS_CONSTRAINT(e)) - TOPOROUTER_CONSTRAINT(e)->routing = g_list_insert_sorted_with_data(edge_routing(e), r, routing_edge_insert, e); - else - e->routing = g_list_insert_sorted_with_data(edge_routing(e), r, routing_edge_insert, e); - - return r; -} - - -/* create vertex on edge e at radius r from v, closest to ref */ -toporouter_vertex_t *new_temp_toporoutervertex_in_segment(toporouter_edge_t * e, toporouter_vertex_t * v, gdouble r, - toporouter_vertex_t * ref) -{ - gdouble m = edge_gradient(e); - toporouter_spoint_t p, np1, np2; -/* toporouter_vertex_t *b = TOPOROUTER_VERTEX((GTS_VERTEX(v) == edge_v1(e)) ? edge_v2(e) : edge_v1(e)); */ - toporouter_vertex_t *rval = NULL; - p.x = vx(v); - p.y = vy(v); - - vertices_on_line(&p, m, r, &np1, &np2); - - if ((pow(np1.x - vx(ref), 2) + pow(np1.y - vy(ref), 2)) < (pow(np2.x - vx(ref), 2) + pow(np2.y - vy(ref), 2))) - rval = new_temp_toporoutervertex(np1.x, np1.y, e); - else - rval = new_temp_toporoutervertex(np2.x, np2.y, e); - - return rval; -} - -gint vertex_keepout_test(toporouter_t * r, toporouter_vertex_t * v) -{ - GList *i = r->keepoutlayers; - while (i) { - gdouble keepout = *((double *) i->data); - if (vz(v) == keepout) - return 1; - i = i->next; - } - return 0; -} - -void -closest_cluster_pair(toporouter_t * r, GList * src_vertices, GList * dest_vertices, toporouter_vertex_t ** a, - toporouter_vertex_t ** b) -{ - GList *i = src_vertices, *j = dest_vertices; - - gdouble min = 0.; - *a = NULL; - *b = NULL; - - i = src_vertices; - while (i) { - toporouter_vertex_t *v1 = TOPOROUTER_VERTEX(i->data); - - if (vertex_keepout_test(r, v1)) { - i = i->next; - continue; - } - - j = dest_vertices; - while (j) { - toporouter_vertex_t *v2 = TOPOROUTER_VERTEX(j->data); - if (vertex_keepout_test(r, v2) || vz(v2) != vz(v1)) { - j = j->next; - continue; - } - - if (!*a) { - *a = v1; - *b = v2; - min = simple_h_cost(r, *a, *b); - } - else { - gdouble tempd = simple_h_cost(r, v1, v2); - if (r->flags & TOPOROUTER_FLAG_GOFAR && tempd > min) { - *a = v1; - *b = v2; - min = tempd; - } - else if (tempd < min) { - *a = v1; - *b = v2; - min = tempd; - } - } - - j = j->next; - } - - i = i->next; - } - -/* g_list_free(src_vertices); - g_list_free(dest_vertices);*/ -} - - -toporouter_vertex_t *closest_dest_vertex(toporouter_t * r, toporouter_vertex_t * v, toporouter_route_t * routedata) -{ - GList /* *vertices = cluster_vertices(r, routedata->dest), */ - * i = routedata->destvertices; - toporouter_vertex_t *closest = NULL; - gdouble closest_distance = 0.; - -/* if(routedata->flags & TOPOROUTER_FLAG_FLEX) i = r->destboxes; */ - - while (i) { - toporouter_vertex_t *cv = TOPOROUTER_VERTEX(i->data); - - if (vz(cv) != vz(v)) { - i = i->next; - continue; - } - - if (!closest) { - closest = cv; - closest_distance = simple_h_cost(r, v, closest); - } - else { - gdouble tempd = simple_h_cost(r, v, cv); - if (r->flags & TOPOROUTER_FLAG_GOFAR && tempd > closest_distance) { - closest = cv; - closest_distance = tempd; - } - else if (tempd < closest_distance) { - closest = cv; - closest_distance = tempd; - } - } - i = i->next; - } - -/* g_list_free(vertices); */ - -#ifdef DEBUG_ROUTE - printf("CLOSEST = %f,%f,%f\n", vx(closest), vy(closest), vz(closest)); -#endif - return closest; -} - -#define toporouter_edge_gradient(e) (cartesian_gradient(vx(edge_v1(e)), vy(edge_v1(e)), vx(edge_v2(e)), vy(edge_v2(e)))) - - -/* returns the capacity of the triangle cut through v */ -gdouble triangle_interior_capacity(GtsTriangle * t, toporouter_vertex_t * v) -{ - toporouter_edge_t *e = TOPOROUTER_EDGE(gts_triangle_edge_opposite(t, GTS_VERTEX(v))); - gdouble x, y, m1, m2, c2, c1; -#ifdef DEBUG_ROUTE - gdouble len; -#endif - - g_assert(e); - - m1 = toporouter_edge_gradient(e); - m2 = perpendicular_gradient(m1); - c2 = (isinf(m2)) ? vx(v) : vy(v) - (m2 * vx(v)); - c1 = (isinf(m1)) ? vx(edge_v1(e)) : vy(edge_v1(e)) - (m1 * vx(edge_v1(e))); - - if (isinf(m2)) - x = vx(v); - else if (isinf(m1)) - x = vx(edge_v1(e)); - else - x = (c2 - c1) / (m1 - m2); - - y = (isinf(m2)) ? vy(edge_v1(e)) : (m2 * x) + c2; - -#ifdef DEBUG_ROUTE - len = gts_point_distance2(GTS_POINT(edge_v1(e)), GTS_POINT(edge_v2(e))); - printf("%f,%f len = %f v = %f,%f\n", x, y, len, vx(v), vy(v)); -#endif - - if (epsilon_equals(x, vx(edge_v1(e))) && epsilon_equals(y, vy(edge_v1(e)))) - return INFINITY; - if (epsilon_equals(x, vx(edge_v2(e))) && epsilon_equals(y, vy(edge_v2(e)))) - return INFINITY; - - if (x >= MIN(vx(edge_v1(e)), vx(edge_v2(e))) && - x <= MAX(vx(edge_v1(e)), vx(edge_v2(e))) && - y >= MIN(vy(edge_v1(e)), vy(edge_v2(e))) && y <= MAX(vy(edge_v1(e)), vy(edge_v2(e)))) - -/* if( (pow(vx(edge_v1(e)) - x, 2) + pow(vy(edge_v1(e)) - y, 2)) < len && (pow(vx(edge_v2(e)) - x, 2) + pow(vy(edge_v2(e)) - y, 2)) < len ) */ - return sqrt(pow(vx(v) - x, 2) + pow(vy(v) - y, 2)); - - return INFINITY; -} - -static inline toporouter_vertex_t *segment_common_vertex(GtsSegment * s1, GtsSegment * s2) -{ - if (!s1 || !s2) - return NULL; - if (s1->v1 == s2->v1) - return TOPOROUTER_VERTEX(s1->v1); - if (s1->v2 == s2->v1) - return TOPOROUTER_VERTEX(s1->v2); - if (s1->v1 == s2->v2) - return TOPOROUTER_VERTEX(s1->v1); - if (s1->v2 == s2->v2) - return TOPOROUTER_VERTEX(s1->v2); - return NULL; -} - -static inline toporouter_vertex_t *route_vertices_common_vertex(toporouter_vertex_t * v1, toporouter_vertex_t * v2) -{ - return segment_common_vertex(GTS_SEGMENT(v1->routingedge), GTS_SEGMENT(v2->routingedge)); -} - - -static inline guint edges_third_edge(GtsSegment * s1, GtsSegment * s2, toporouter_vertex_t ** v1, toporouter_vertex_t ** v2) -{ - if (!s1 || !s2) - return 0; - if (s1->v1 == s2->v1) { - *v1 = TOPOROUTER_VERTEX(s1->v2); - *v2 = TOPOROUTER_VERTEX(s2->v2); - return 1; - } - if (s1->v2 == s2->v1) { - *v1 = TOPOROUTER_VERTEX(s1->v1); - *v2 = TOPOROUTER_VERTEX(s2->v2); - return 1; - } - if (s1->v1 == s2->v2) { - *v1 = TOPOROUTER_VERTEX(s1->v2); - *v2 = TOPOROUTER_VERTEX(s2->v1); - return 1; - } - if (s1->v2 == s2->v2) { - *v1 = TOPOROUTER_VERTEX(s1->v1); - *v2 = TOPOROUTER_VERTEX(s2->v1); - return 1; - } - return 0; -} - -/* returns the flow from e1 to e2, and the flow from the vertex oppisate e1 to - * e1 and the vertex oppisate e2 to e2 */ -gdouble -flow_from_edge_to_edge(GtsTriangle * t, toporouter_edge_t * e1, toporouter_edge_t * e2, - toporouter_vertex_t * common_v, toporouter_vertex_t * curpoint) -{ - gdouble r = 0.; - toporouter_vertex_t *pv = common_v, *v; - toporouter_edge_t *op_edge; - - GList *i = edge_routing(e1); - while (i) { - v = TOPOROUTER_VERTEX(i->data); - - if (v == curpoint) { - r += min_spacing(v, pv); - pv = v; - i = i->next; - continue; - } -/* if(!(v->flags & VERTEX_FLAG_TEMP)) { */ - if ((v->flags & VERTEX_FLAG_ROUTE)) { - if (v->parent) - if (v->parent->routingedge == e2) { - r += min_spacing(v, pv); - pv = v; - i = i->next; - continue; - } - - if (v->child) - if (v->child->routingedge == e2) { - r += min_spacing(v, pv); - pv = v; - i = i->next; - continue; - } - } - i = i->next; - } - - op_edge = TOPOROUTER_EDGE(gts_triangle_edge_opposite(t, GTS_VERTEX(common_v))); - - g_assert(op_edge); - g_assert(e1); - g_assert(e2); - - v = segment_common_vertex(GTS_SEGMENT(e2), GTS_SEGMENT(op_edge)); - g_assert(v); - - /*v = TOPOROUTER_VERTEX(gts_triangle_vertex_opposite(t, GTS_EDGE(e1))); */ - if (v->flags & VERTEX_FLAG_ROUTE && v->parent && v->parent->routingedge) { - if (v->parent->routingedge == e1) - r += min_spacing(v, pv); - } - - v = segment_common_vertex(GTS_SEGMENT(e1), GTS_SEGMENT(op_edge)); - g_assert(v); - - /*v = TOPOROUTER_VERTEX(gts_triangle_vertex_opposite(t, GTS_EDGE(e2))); */ - if (v->flags & VERTEX_FLAG_ROUTE && v->parent && v->parent->routingedge) { - if (v->parent->routingedge == e1) - r += min_spacing(v, pv); - } - - if (TOPOROUTER_IS_CONSTRAINT(op_edge)) { - toporouter_bbox_t *box = vertex_bbox(TOPOROUTER_VERTEX(edge_v1(op_edge))); - r += vertex_net_thickness(v) / 2.; - if (box) { - r += MAX(vertex_net_clearance(v), cluster_clearance(box->cluster)); - r += cluster_thickness(box->cluster) / 2.; - } - else { - r += vertex_net_clearance(v); - - } - } - - return r; -} - - - -guint -check_triangle_interior_capacity(GtsTriangle * t, toporouter_vertex_t * v, toporouter_vertex_t * curpoint, - toporouter_edge_t * op_edge, toporouter_edge_t * adj_edge1, toporouter_edge_t * adj_edge2) -{ - gdouble ic = triangle_interior_capacity(t, v); - gdouble flow = flow_from_edge_to_edge(t, adj_edge1, adj_edge2, v, curpoint); - - if (TOPOROUTER_IS_CONSTRAINT(adj_edge1) || TOPOROUTER_IS_CONSTRAINT(adj_edge2)) - return 1; - - - if (flow > ic) { -#ifdef DEBUG_ROUTE - printf("fail interior capacity flow = %f ic = %f\n", flow, ic); -#endif - return 0; - } - - return 1; -} - -toporouter_vertex_t *edge_routing_next_not_temp(toporouter_edge_t * e, GList * list) -{ - if (!TOPOROUTER_IS_CONSTRAINT(e)) { - while (list) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(list->data); - if (!(v->flags & VERTEX_FLAG_TEMP)) - return v; - - list = list->next; - } - } - return tedge_v2(e); -} - -toporouter_vertex_t *edge_routing_prev_not_temp(toporouter_edge_t * e, GList * list) -{ - if (!TOPOROUTER_IS_CONSTRAINT(e)) { - while (list) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(list->data); - if (!(v->flags & VERTEX_FLAG_TEMP)) - return v; - - list = list->prev; - } - } - return tedge_v1(e); -} - -void -edge_adjacent_vertices(toporouter_edge_t * e, toporouter_vertex_t * v, toporouter_vertex_t ** v1, toporouter_vertex_t ** v2) -{ - GList *r = g_list_find(edge_routing(e), v); - - if (v == tedge_v1(e)) { - *v1 = NULL; - *v2 = edge_routing_next_not_temp(e, edge_routing(e)); - } - else if (v == tedge_v2(e)) { - *v1 = edge_routing_prev_not_temp(e, g_list_last(edge_routing(e))); - *v2 = NULL; - } - else { -/* r = g_list_find(r, v);*/ - *v1 = edge_routing_prev_not_temp(e, r); - *v2 = edge_routing_next_not_temp(e, r); - - } - -} - - -GList *candidate_vertices(toporouter_vertex_t * v1, toporouter_vertex_t * v2, toporouter_vertex_t * dest, toporouter_edge_t * e) -{ - gdouble totald, v1ms, v2ms, flow, capacity, ms; - GList *vs = NULL; - - g_assert(v1); - g_assert(v2); - g_assert(dest); - - g_assert(!(v1->flags & VERTEX_FLAG_TEMP)); - g_assert(!(v2->flags & VERTEX_FLAG_TEMP)); -#ifdef DEBUG_ROUTE - printf("starting candidate vertices\n"); - printf("v1 = %f,%f v2 = %f,%f dest = %f,%f\n", vx(v1), vy(v1), vx(v2), vy(v2), vx(dest), vy(dest)); -#endif - totald = gts_point_distance(GTS_POINT(v1), GTS_POINT(v2)); - v1ms = min_spacing(v1, dest); - v2ms = min_spacing(v2, dest); - ms = min_spacing(dest, dest); - flow = TOPOROUTER_IS_CONSTRAINT(e) ? 0. : edge_flow(e, v1, v2, dest); - capacity = edge_capacity(e); - -#ifdef DEBUG_ROUTE - g_assert(totald > 0); - - printf("v1ms = %f v2ms = %f totald = %f ms = %f capacity = %f flow = %f\n", v1ms, v2ms, totald, ms, capacity, flow); -#endif - - if (flow >= capacity) - return NULL; - - - if (v1ms + v2ms + ms >= totald) { - vs = g_list_prepend(vs, new_temp_toporoutervertex((vx(v1) + vx(v2)) / 2., (vy(v1) + vy(v2)) / 2., e)); - } - else { - gdouble x0, y0, x1, y1, d; - - vertex_move_towards_vertex_values(GTS_VERTEX(v1), GTS_VERTEX(v2), v1ms, &x0, &y0); - - vs = g_list_prepend(vs, new_temp_toporoutervertex(x0, y0, e)); - - vertex_move_towards_vertex_values(GTS_VERTEX(v2), GTS_VERTEX(v1), v2ms, &x1, &y1); - - vs = g_list_prepend(vs, new_temp_toporoutervertex(x1, y1, e)); - - d = sqrt(pow(x0 - x1, 2) + pow(y0 - y1, 2)); - - if (ms < d) { -/* guint nint = d / ms; - gdouble dif = d / (nint + 1); */ - gdouble dif = d / 2; - -/* for(guint j=0;jdata); - if (!(v->flags & VERTEX_FLAG_TEMP)) - return i; - - i = i->next; - } - - return NULL; -} - -GList *edge_routing_last_not_temp(toporouter_edge_t * e) -{ - GList *i = edge_routing(e), *last = NULL; - toporouter_vertex_t *v; - - while (i) { - v = TOPOROUTER_VERTEX(i->data); - if (!(v->flags & VERTEX_FLAG_TEMP)) - last = i; - - i = i->next; - } - - return last; -} - -void delete_vertex(toporouter_vertex_t * v) -{ - - if (v->flags & VERTEX_FLAG_TEMP) { - if (v->routingedge) { - if (TOPOROUTER_IS_CONSTRAINT(v->routingedge)) - TOPOROUTER_CONSTRAINT(v->routingedge)->routing = g_list_remove(TOPOROUTER_CONSTRAINT(v->routingedge)->routing, v); - else - v->routingedge->routing = g_list_remove(v->routingedge->routing, v); - } - - gts_object_destroy(GTS_OBJECT(v)); - } -} - -#define edge_is_blocked(e) (TOPOROUTER_IS_EDGE(e) ? (e->flags & EDGE_FLAG_DIRECTCONNECTION) : 0) - -GList *triangle_candidate_points_from_vertex(GtsTriangle * t, toporouter_vertex_t * v, toporouter_vertex_t * dest, - toporouter_route_t * routedata) -{ - toporouter_edge_t *op_e = TOPOROUTER_EDGE(gts_triangle_edge_opposite(t, GTS_VERTEX(v))); - toporouter_vertex_t *vv1, *vv2, *constraintv = NULL; - toporouter_edge_t *e1, *e2; - GList *i; - GList *rval = NULL; - -#ifdef DEBUG_ROUTE - printf("\tTRIANGLE CAND POINT FROM VERTEX\n"); - - g_assert(op_e); -#endif - - e1 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(v), edge_v1(op_e))); - e2 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(v), edge_v2(op_e))); - - - if (TOPOROUTER_IS_CONSTRAINT(op_e)) { - if (TOPOROUTER_CONSTRAINT(op_e)->box->type == BOARD) { -#ifdef DEBUG_ROUTE - printf("BOARD constraint\n"); -#endif - return NULL; - } - if (constraint_netlist(TOPOROUTER_CONSTRAINT(op_e)) != vertex_netlist(dest)) { /* || TOPOROUTER_CONSTRAINT(op_e)->routing) { */ -#ifdef DEBUG_ROUTE - printf("op_e routing:\n"); - print_edge(op_e); -#endif - return NULL; - } -#ifdef DEBUG_ROUTE - printf("RETURNING CONSTRAINT POING\n"); -#endif - constraintv = new_temp_toporoutervertex_in_segment(op_e, TOPOROUTER_VERTEX(edge_v1(op_e)), - gts_point_distance(GTS_POINT(edge_v1(op_e)), - GTS_POINT(edge_v2(op_e))) / 2., - TOPOROUTER_VERTEX(edge_v2(op_e))); -/* return g_list_prepend(NULL, vv1); */ - - - } - - if (edge_is_blocked(op_e)) { - goto triangle_candidate_points_from_vertex_exit; - } -/* v1 = tedge_v1(op_e); - v2 = tedge_v2(op_e);*/ - - if (v == tedge_v1(e1)) { - i = edge_routing_first_not_temp(e1); - } - else { - i = edge_routing_last_not_temp(e1); - } - - if (i) { - toporouter_vertex_t *temp = TOPOROUTER_VERTEX(i->data); - - if (temp->parent == tedge_v2(op_e) || temp->child == tedge_v2(op_e)) { -#ifdef DEBUG_ROUTE - printf("temp -> op_e->v2\n"); -#endif - goto triangle_candidate_points_from_vertex_exit; - } - if (temp->parent->routingedge == op_e) { - vv1 = temp->parent; -#ifdef DEBUG_ROUTE - printf("vv1->parent\n"); -#endif - - } - else if (temp->child->routingedge == op_e) { - vv1 = temp->child; -#ifdef DEBUG_ROUTE - printf("vv1->child\n"); -#endif - - } - else { - /* must be to e2 */ -#ifdef DEBUG_ROUTE - printf("temp -> e2?\n"); - printf("op_e = %f,%f\t\t%f,%f\n", vx(edge_v1(op_e)), vy(edge_v1(op_e)), vx(edge_v2(op_e)), vy(edge_v2(op_e))); - if (temp->parent->routingedge) - printf("temp->parent->routingedge = %f,%f \t\t %f,%f\n", - vx(edge_v1(temp->parent->routingedge)), vy(edge_v1(temp->parent->routingedge)), - vx(edge_v2(temp->parent->routingedge)), vy(edge_v2(temp->parent->routingedge)) - ); - else - printf("temp->parent->routingedge = NULL\n"); - - if (temp->child->routingedge) - printf("temp->child->routingedge = %f,%f \t\t %f,%f\n", - vx(edge_v1(temp->child->routingedge)), vy(edge_v1(temp->child->routingedge)), - vx(edge_v2(temp->child->routingedge)), vy(edge_v2(temp->child->routingedge)) - ); - else - printf("temp->child->routingedge = NULL\n"); -#endif - goto triangle_candidate_points_from_vertex_exit; - } - - } - else { - vv1 = tedge_v1(op_e); -#ifdef DEBUG_ROUTE - printf("nothing on e1\n"); -#endif - } - - if (v == tedge_v1(e2)) { - i = edge_routing_first_not_temp(e2); - } - else { - i = edge_routing_last_not_temp(e2); - } - - if (i) { - toporouter_vertex_t *temp = TOPOROUTER_VERTEX(i->data); - - if (temp->parent == tedge_v1(op_e) || temp->child == tedge_v1(op_e)) { -#ifdef DEBUG_ROUTE - printf("temp -> op_e->v2\n"); -#endif - goto triangle_candidate_points_from_vertex_exit; - } - - if (temp->parent->routingedge == op_e) { - vv2 = temp->parent; -#ifdef DEBUG_ROUTE - printf("vv2->parent\n"); -#endif - } - else if (temp->child->routingedge == op_e) { - vv2 = temp->child; -#ifdef DEBUG_ROUTE - printf("vv2->child\n"); -#endif - - } - else { - /* must be to e1 */ -#ifdef DEBUG_ROUTE - printf("temp -> e1?\n"); - printf("op_e = %f,%f\t\t%f,%f\n", vx(edge_v1(op_e)), vy(edge_v1(op_e)), vx(edge_v2(op_e)), vy(edge_v2(op_e))); - if (temp->parent->routingedge) - printf("temp->parent->routingedge = %f,%f \t\t %f,%f\n", - vx(edge_v1(temp->parent->routingedge)), vy(edge_v1(temp->parent->routingedge)), - vx(edge_v2(temp->parent->routingedge)), vy(edge_v2(temp->parent->routingedge)) - ); - else - printf("temp->parent->routingedge = NULL\n"); - - if (temp->child->routingedge) - printf("temp->child->routingedge = %f,%f \t\t %f,%f\n", - vx(edge_v1(temp->child->routingedge)), vy(edge_v1(temp->child->routingedge)), - vx(edge_v2(temp->child->routingedge)), vy(edge_v2(temp->child->routingedge)) - ); - else - printf("temp->child->routingedge = NULL\n"); -#endif - goto triangle_candidate_points_from_vertex_exit; - } - - } - else { - vv2 = tedge_v2(op_e); -#ifdef DEBUG_ROUTE - printf("nothing on e2\n"); -#endif - } - -#ifdef DEBUG_ROUTE - printf("size of e1 routing = %d e2 routing = %d op_e routing = %d\n", - g_list_length(edge_routing(e1)), g_list_length(edge_routing(e2)), g_list_length(edge_routing(op_e))); -#endif - - if (constraintv) { -#ifdef DEBUG_ROUTE - print_vertex(constraintv); - printf("constraintv %f,%f returning\n", vx(constraintv), vy(constraintv)); -#endif - return g_list_prepend(NULL, constraintv); - } - - i = edge_routing(op_e); - while (i) { - toporouter_vertex_t *temp = TOPOROUTER_VERTEX(i->data); - - if (temp->parent == v || temp->child == v) { - rval = g_list_concat(rval, candidate_vertices(vv1, temp, dest, op_e)); - vv1 = temp; - } - - i = i->next; - } - - rval = g_list_concat(rval, candidate_vertices(vv1, vv2, dest, op_e)); - - return rval; - - - -triangle_candidate_points_from_vertex_exit: - if (constraintv) /*delete_vertex(constraintv); */ - g_hash_table_insert(routedata->alltemppoints, constraintv, constraintv); - - g_list_free(rval); - - return NULL; -} - -void routedata_insert_temppoints(toporouter_route_t * data, GList * temppoints) -{ - GList *j = temppoints; - while (j) { - g_hash_table_insert(data->alltemppoints, j->data, j->data); - j = j->next; - } -} - - -static inline gint constraint_route_test(toporouter_constraint_t * c, toporouter_route_t * routedata) -{ - if (c->box->cluster && c->box->cluster->netlist == routedata->src->netlist) { - if (c->box->cluster->c == routedata->dest->c || c->box->cluster->c == routedata->src->c) - return 1; - } - return 0; -} - -GList *all_candidates_on_edge(toporouter_edge_t * e, toporouter_route_t * routedata) -{ - GList *rval = NULL; - if (edge_is_blocked(e)) - return NULL; - - if (!TOPOROUTER_IS_CONSTRAINT(e)) { - GList *i = edge_routing(e); - toporouter_vertex_t *pv = tedge_v1(e); - - while (i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); - if (!(v->flags & VERTEX_FLAG_TEMP)) { - rval = g_list_concat(rval, candidate_vertices(pv, v, TOPOROUTER_VERTEX(routedata->destvertices->data), e)); - pv = v; - } - i = i->next; - } - - rval = g_list_concat(rval, candidate_vertices(pv, tedge_v2(e), TOPOROUTER_VERTEX(routedata->destvertices->data), e)); - } - else if (TOPOROUTER_CONSTRAINT(e)->box->type == BOARD) { - return NULL; - } - else if (constraint_route_test(TOPOROUTER_CONSTRAINT(e), routedata)) { - toporouter_vertex_t *consv = - new_temp_toporoutervertex_in_segment(e, tedge_v1(e), tvdistance(tedge_v1(e), tedge_v2(e)) / 2., tedge_v2(e)); - rval = g_list_prepend(rval, consv); -/* g_hash_table_insert(routedata->alltemppoints, consv, consv); */ - } - - return rval; -} - -GList *triangle_all_candidate_points_from_vertex(GtsTriangle * t, toporouter_vertex_t * v, toporouter_route_t * routedata) -{ - toporouter_edge_t *op_e = TOPOROUTER_EDGE(gts_triangle_edge_opposite(t, GTS_VERTEX(v))); - return all_candidates_on_edge(op_e, routedata); -} - -GList *triangle_all_candidate_points_from_edge(toporouter_t * r, GtsTriangle * t, toporouter_edge_t * e, - toporouter_route_t * routedata, toporouter_vertex_t ** dest, - toporouter_vertex_t * curpoint) -{ - toporouter_vertex_t *op_v; - toporouter_edge_t *e1, *e2; - GList *i, *rval = NULL, *rval2 = NULL; - toporouter_vertex_t *boxpoint = NULL; - guint e1intcap, e2intcap; - - op_v = TOPOROUTER_VERTEX(gts_triangle_vertex_opposite(t, GTS_EDGE(e))); - - - if (vertex_bbox(op_v)) - boxpoint = TOPOROUTER_VERTEX(vertex_bbox(op_v)->point); - - if (g_list_find(routedata->destvertices, op_v)) { - rval = g_list_prepend(rval, op_v); - *dest = op_v; - return rval; - } - else if (g_list_find(routedata->destvertices, boxpoint)) { - *dest = boxpoint; - } - else if (g_list_find(routedata->srcvertices, op_v)) { - rval = g_list_prepend(rval, op_v); - } - - e1 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(op_v), edge_v1(e))); - e2 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(op_v), edge_v2(e))); - - rval = g_list_concat(rval, all_candidates_on_edge(e1, routedata)); - rval = g_list_concat(rval, all_candidates_on_edge(e2, routedata)); - - e1intcap = check_triangle_interior_capacity(t, tedge_v1(e), curpoint, e2, e, e1); - e2intcap = check_triangle_interior_capacity(t, tedge_v2(e), curpoint, e1, e, e2); - - i = rval; - while (i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); - - if (!v->routingedge) - rval2 = g_list_prepend(rval2, v); - else if (v->routingedge == e1 && !(!TOPOROUTER_IS_CONSTRAINT(e1) && !e1intcap)) - rval2 = g_list_prepend(rval2, v); - else if (v->routingedge == e2 && !(!TOPOROUTER_IS_CONSTRAINT(e2) && !e2intcap)) - rval2 = g_list_prepend(rval2, v); - - i = i->next; - } - g_list_free(rval); - - return rval2; -} - -GList *triangle_candidate_points_from_edge(toporouter_t * r, GtsTriangle * t, toporouter_edge_t * e, toporouter_vertex_t * v, - toporouter_vertex_t ** dest, toporouter_route_t * routedata) -{ - toporouter_vertex_t *v1, *v2, *op_v, *vv = NULL, *e1constraintv = NULL, *e2constraintv = NULL; - toporouter_edge_t *e1, *e2; - GList *e1cands = NULL, *e2cands = NULL, *rval = NULL; - guint noe1 = 0, noe2 = 0; - - op_v = TOPOROUTER_VERTEX(gts_triangle_vertex_opposite(t, GTS_EDGE(e))); - - e1 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(op_v), edge_v1(e))); - e2 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(op_v), edge_v2(e))); - - g_assert(*dest); - - /* v1 is prev dir, v2 is next dir */ - edge_adjacent_vertices(e, v, &v1, &v2); - - if (TOPOROUTER_IS_CONSTRAINT(e1)) { - GList *i = edge_routing(e1); - - if (TOPOROUTER_CONSTRAINT(e1)->box->type == BOARD) { - noe1 = 1; - } - else if (!constraint_route_test(TOPOROUTER_CONSTRAINT(e1), routedata)) { - noe1 = 1; -#ifdef DEBUG_ROUTE - printf("noe1 netlist\n"); -#endif - } - else - if (v1 == tedge_v1(e) || - (v1->parent->routingedge && v1->parent->routingedge == e1) || - (v1->child->routingedge && v1->child->routingedge == e1)) { - e1constraintv = - new_temp_toporoutervertex_in_segment(e1, tedge_v1(e1), - gts_point_distance(GTS_POINT(edge_v1(e1)), GTS_POINT(edge_v2(e1))) / 2., - tedge_v2(e1)); - } - - while (i) { - toporouter_vertex_t *temp = TOPOROUTER_VERTEX(i->data); - - if ((temp->child == tedge_v2(e) || temp->parent == tedge_v2(e)) && !(temp->flags & VERTEX_FLAG_TEMP)) - noe2 = 1; - - i = i->next; - } - - goto triangle_candidate_points_e2; - } - - if (edge_is_blocked(e1)) { - noe1 = 1; - goto triangle_candidate_points_e2; - } - - if (v1 == tedge_v1(e)) { - /* continue up e1 */ - toporouter_vertex_t *vv1, *vv2; - edge_adjacent_vertices(e1, v1, &vv1, &vv2); - -#ifdef DEBUG_ROUTE - printf("v1 == e->v1\n"); -#endif - - if (vv1) { - /* candidates from v1 until vv1 */ - vv = vv1; - } - else { - /* candidates from v1 until vv2 */ - vv = vv2; - } - - if (!e1constraintv) - e1cands = candidate_vertices(v1, vv, *dest, e1); - - if (vv != op_v) { - if (vv->parent == tedge_v2(e) || vv->child == tedge_v2(e)) { -#ifdef DEBUG_ROUTE - printf("noe2 0\n"); -#endif - noe2 = 1; - } - } - - } - else if (v1->parent != op_v && v1->child != op_v) { - toporouter_vertex_t *vv1 = NULL, *vv2 = NULL; - -#ifdef DEBUG_ROUTE - printf("v1 != e->v1\n"); -#endif - - if (v1->parent->routingedge == e1) { - vv1 = v1->parent; -#ifdef DEBUG_ROUTE - printf("v1 parent = e1\n"); -#endif - if (op_v == tedge_v1(e1)) { - /* candidates from v1->parent until prev vertex */ - vv2 = edge_routing_prev_not_temp(e1, g_list_find(edge_routing(e1), v1->parent)->prev); - } - else { - /* candidates from v1->parent until next vertex */ - vv2 = edge_routing_next_not_temp(e1, g_list_find(edge_routing(e1), v1->parent)->next); - } - - } - else if (v1->child->routingedge == e1) { - vv1 = v1->child; -#ifdef DEBUG_ROUTE - printf("v1 child = e1\n"); -#endif - if (op_v == tedge_v1(e1)) { - /* candidates from v1->child until prev vertex */ - vv2 = edge_routing_prev_not_temp(e1, g_list_find(edge_routing(e1), v1->child)->prev); - } - else { - /* candidates from v1->child until next vertex */ - vv2 = edge_routing_next_not_temp(e1, g_list_find(edge_routing(e1), v1->child)->next); - } - - } - else { -#ifdef DEBUG_ROUTE - printf("v1 ? \n"); -#endif - goto triangle_candidate_points_e2; - } - - if (vv1 && vv2) { - if (vv2->parent == tedge_v2(e) || vv2->child == tedge_v2(e)) { -#ifdef DEBUG_ROUTE - printf("noe2 1\n"); -#endif - noe2 = 1; - } - - if (!e1constraintv) - e1cands = candidate_vertices(vv1, vv2, *dest, e1); - - vv = vv2; - } - } - - if (vv && vv == op_v) { - toporouter_vertex_t *boxpoint = NULL; - - if (vertex_bbox(op_v)) - boxpoint = TOPOROUTER_VERTEX(vertex_bbox(op_v)->point); - - if (g_list_find(routedata->destvertices, op_v)) { - rval = g_list_prepend(rval, op_v); - *dest = op_v; - } - else if (g_list_find(routedata->destvertices, boxpoint)) { - *dest = boxpoint; - } - else if (g_list_find(routedata->srcvertices, op_v)) { - rval = g_list_prepend(rval, op_v); - } - } - -triangle_candidate_points_e2: - - if (noe2) { -/* printf("noe2\n"); */ - goto triangle_candidate_points_finish; - } - - if (TOPOROUTER_IS_CONSTRAINT(e2)) { - GList *i = edge_routing(e2); - - if (TOPOROUTER_CONSTRAINT(e2)->box->type == BOARD) { - noe2 = 1; -/* goto triangle_candidate_points_finish; */ - } - else if (!constraint_route_test(TOPOROUTER_CONSTRAINT(e2), routedata)) { -#ifdef DEBUG_ROUTE - printf("noe2 netlist\n"); -#endif - noe2 = 1; -/* goto triangle_candidate_points_finish; */ - } - else if (v2 == tedge_v2(e) || - (v2->parent->routingedge && v2->parent->routingedge == e2) || - (v2->child->routingedge && v2->child->routingedge == e2)) { - - e2constraintv = - new_temp_toporoutervertex_in_segment(e2, tedge_v1(e2), - gts_point_distance(GTS_POINT(edge_v1(e2)), GTS_POINT(edge_v2(e2))) / 2., - tedge_v2(e2)); - - } - - while (i) { - toporouter_vertex_t *temp = TOPOROUTER_VERTEX(i->data); - - if ((temp->child == tedge_v1(e) || temp->parent == tedge_v1(e)) && !(temp->flags & VERTEX_FLAG_TEMP)) - noe1 = 1; - - i = i->next; - } - - - - goto triangle_candidate_points_finish; - } - - if (edge_is_blocked(e2)) { - noe2 = 1; - goto triangle_candidate_points_finish; - } - - if (v2 == tedge_v2(e)) { - /* continue up e2 */ - toporouter_vertex_t *vv1 = NULL, *vv2 = NULL; - edge_adjacent_vertices(e2, v2, &vv1, &vv2); - -#ifdef DEBUG_ROUTE - printf("v2 == e->v2\n"); -#endif - - if (vv1) { - /* candidates from v2 until vv1 */ - vv = vv1; - } - else { - /* candidates from v2 until vv2 */ - vv = vv2; - } - - if (!e2constraintv) - e2cands = candidate_vertices(v2, vv, *dest, e2); - - if (vv != op_v) { - if (vv->parent == tedge_v1(e) || vv->child == tedge_v1(e)) { -#ifdef DEBUG_ROUTE - printf("noe1 0\n"); -#endif - noe1 = 1; - } - } - - } - else if (v2->parent != op_v && v2->child != op_v) { - toporouter_vertex_t *vv1 = NULL, *vv2 = NULL; - -#ifdef DEBUG_ROUTE - printf("v2 == e->v2\n"); -#endif - - if (v2->parent->routingedge == e2) { - vv1 = v2->parent; - if (op_v == tedge_v1(e2)) { - /* candidates from v2->parent until prev vertex */ - vv2 = edge_routing_prev_not_temp(e2, g_list_find(edge_routing(e2), vv1)->prev); - } - else { - /* candidates from v2->parent until next vertex */ - vv2 = edge_routing_next_not_temp(e2, g_list_find(edge_routing(e2), vv1)->next); - } - - } - else if (v2->child->routingedge == e2) { - vv1 = v2->child; - if (op_v == tedge_v1(e2)) { - /* candidates from v2->child until prev vertex */ - vv2 = edge_routing_prev_not_temp(e2, g_list_find(edge_routing(e2), vv1)->prev); - } - else { - /* candidates from v2->child until next vertex */ - vv2 = edge_routing_next_not_temp(e2, g_list_find(edge_routing(e2), vv1)->next); - } - - } - else { - goto triangle_candidate_points_finish; - } - - if (vv1 && vv2) { - if (vv2->parent == tedge_v1(e) || vv2->child == tedge_v1(e)) { -#ifdef DEBUG_ROUTE - printf("noe1 1\n"); -#endif - noe1 = 1; - } - - if (!e2constraintv) - e2cands = candidate_vertices(vv1, vv2, *dest, e2); - } - } - -triangle_candidate_points_finish: - - v1 = segment_common_vertex(GTS_SEGMENT(e), GTS_SEGMENT(e1)); - v2 = segment_common_vertex(GTS_SEGMENT(e), GTS_SEGMENT(e2)); - - if (noe1 || !check_triangle_interior_capacity(t, v1, v, e2, e, e1)) { -#ifdef DEBUG_ROUTE - printf("freeing e1cands\n"); -#endif - routedata_insert_temppoints(routedata, e1cands); - g_list_free(e1cands); - e1cands = NULL; - } - - if (noe2 || !check_triangle_interior_capacity(t, v2, v, e1, e, e2)) { -#ifdef DEBUG_ROUTE - printf("freeing e2cands\n"); -#endif - routedata_insert_temppoints(routedata, e2cands); - g_list_free(e2cands); - e2cands = NULL; - } - - if (!noe1 && e1constraintv) { - e1cands = g_list_prepend(e1cands, e1constraintv); - } - else if (e1constraintv) { - g_hash_table_insert(routedata->alltemppoints, e1constraintv, e1constraintv); -/* delete_vertex(e1constraintv); */ - } - - if (!noe2 && e2constraintv) { - e2cands = g_list_prepend(e2cands, e2constraintv); - } - else if (e2constraintv) { - g_hash_table_insert(routedata->alltemppoints, e2constraintv, e2constraintv); -/* delete_vertex(e2constraintv); */ - } - - if (!noe1 && !noe2) - return g_list_concat(rval, g_list_concat(e1cands, e2cands)); - - return g_list_concat(e1cands, e2cands); -} - -GList *compute_candidate_points(toporouter_t * tr, toporouter_layer_t * l, toporouter_vertex_t * curpoint, - toporouter_route_t * data, toporouter_vertex_t ** closestdest) -{ - GList *r = NULL, *j; - toporouter_edge_t *edge = curpoint->routingedge, *tempedge; - - if (vertex_keepout_test(tr, curpoint)) - goto compute_candidate_points_finish; - - /* direct connection */ -/* if(curpoint == TOPOROUTER_VERTEX(data->src->point)) */ - if ((tempedge = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(curpoint), GTS_VERTEX(*closestdest))))) { - - if (TOPOROUTER_IS_CONSTRAINT(tempedge)) { - goto compute_candidate_points_finish; - } - else { - if (!tempedge->routing) { - r = g_list_prepend(NULL, *closestdest); - tempedge->flags |= EDGE_FLAG_DIRECTCONNECTION; - goto compute_candidate_points_finish; - } - else { -#ifdef DEBUG_ROUTE - printf("Direct connection, but has routing\n"); -#endif - } - - } - /* if we get to here, there is routing blocking the direct connection, - * continue as per normal */ - } - - /* a real point origin */ - if (!(curpoint->flags & VERTEX_FLAG_TEMP)) { - GSList *triangles, *i; - i = triangles = gts_vertex_triangles(GTS_VERTEX(curpoint), NULL); -#ifdef DEBUG_ROUTE - printf("triangle count = %d\n", g_slist_length(triangles)); -#endif - while (i) { - GtsTriangle *t = GTS_TRIANGLE(i->data); - GList *temppoints; - - if (tr->flags & TOPOROUTER_FLAG_LEASTINVALID) - temppoints = triangle_all_candidate_points_from_vertex(t, curpoint, data); - else - temppoints = triangle_candidate_points_from_vertex(t, curpoint, *closestdest, data); - -#ifdef DEBUG_ROUTE - printf("\treturned %d points\n", g_list_length(temppoints)); -#endif - routedata_insert_temppoints(data, temppoints); - - r = g_list_concat(r, temppoints); - i = i->next; - } - g_slist_free(triangles); - } - else { /* a temp point */ - - int prevwind = vertex_wind(GTS_SEGMENT(edge)->v1, GTS_SEGMENT(edge)->v2, GTS_VERTEX(curpoint->parent)); -/* printf("tempoint\n"); */ - - GSList *i = GTS_EDGE(edge)->triangles; - - while (i) { - GtsVertex *oppv = gts_triangle_vertex_opposite(GTS_TRIANGLE(i->data), GTS_EDGE(edge)); - if (prevwind != vertex_wind(GTS_SEGMENT(edge)->v1, GTS_SEGMENT(edge)->v2, oppv)) { - GList *temppoints; - - if (tr->flags & TOPOROUTER_FLAG_LEASTINVALID) - temppoints = triangle_all_candidate_points_from_edge(tr, GTS_TRIANGLE(i->data), edge, data, closestdest, curpoint); - else - temppoints = triangle_candidate_points_from_edge(tr, GTS_TRIANGLE(i->data), edge, curpoint, closestdest, data); - - j = temppoints; - while (j) { - toporouter_vertex_t *tempj = TOPOROUTER_VERTEX(j->data); - if (tempj->flags & VERTEX_FLAG_TEMP) - g_hash_table_insert(data->alltemppoints, j->data, j->data); -#ifdef DEBUG_ROUTE - else - printf("got cand not a temp\n"); -#endif - j = j->next; - } - r = g_list_concat(r, temppoints); - - break; - } - i = i->next; - } - } - -compute_candidate_points_finish: - - if (vertex_bbox(curpoint) && vertex_bbox(curpoint)->cluster) { - if (vertex_bbox(curpoint)->cluster->c == data->src->c) { - r = g_list_concat(r, g_list_copy(data->srcvertices)); - } - } - - return r; -} - -gboolean temp_point_clean(gpointer key, gpointer value, gpointer user_data) -{ - toporouter_vertex_t *tv = TOPOROUTER_VERTEX(value); - if (tv->flags & VERTEX_FLAG_TEMP) { - if (TOPOROUTER_IS_CONSTRAINT(tv->routingedge)) - TOPOROUTER_CONSTRAINT(tv->routingedge)->routing = g_list_remove(TOPOROUTER_CONSTRAINT(tv->routingedge)->routing, tv); - else - tv->routingedge->routing = g_list_remove(tv->routingedge->routing, tv); - gts_object_destroy(GTS_OBJECT(tv)); - } - return TRUE; -} - -void clean_routing_edges(toporouter_t * r, toporouter_route_t * data) -{ - g_hash_table_foreach_remove(data->alltemppoints, temp_point_clean, NULL); - g_hash_table_destroy(data->alltemppoints); - data->alltemppoints = NULL; -} - -gdouble path_score(toporouter_t * r, GList * path) -{ - gdouble score = 0.; - toporouter_vertex_t *pv = NULL; - toporouter_vertex_t *v0 = NULL; - - if (!path) - return INFINITY; - - v0 = TOPOROUTER_VERTEX(path->data); - - while (path) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(path->data); - - if (pv) { - score += gts_point_distance(GTS_POINT(pv), GTS_POINT(v)); - if (pv != v0 && vz(pv) != vz(v)) - if (path->next) - score += r->viacost; - - } - - pv = v; - path = path->next; - } - - return score; -} - -void print_vertices(GList * vertices) -{ - while (vertices) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(vertices->data); - print_vertex(v); - print_bbox(vertex_bbox(v)); - if (vertex_bbox(v)) { - printf("has bbox\n"); - if (vertex_bbox(v)->cluster) - printf("has cluster\n"); - else - printf("no cluster\n"); - } - else - printf("no bbox\n"); - vertices = vertices->next; - } -} - -gint space_edge(gpointer item, gpointer data) -{ - toporouter_edge_t *e = TOPOROUTER_EDGE(item); - GList *i; - gdouble *forces; - guint j; - - if (TOPOROUTER_IS_CONSTRAINT(e)) - return 0; - - if (!edge_routing(e) || !g_list_length(edge_routing(e))) - return 0; - - forces = (gdouble *) malloc(sizeof(double) * g_list_length(edge_routing(e))); - - for (j = 0; j < 100; j++) { - guint k = 0; - guint equilibrium = 1; - - i = edge_routing(e); - while (i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); - gdouble ms, d; - - if (i->prev) { -/* ms = min_net_net_spacing(TOPOROUTER_VERTEX(i->prev->data), v); */ - ms = min_spacing(TOPOROUTER_VERTEX(i->prev->data), v); - d = gts_point_distance(GTS_POINT(i->prev->data), GTS_POINT(v)); - } - else { -/* ms = min_vertex_net_spacing(v, tedge_v1(e)); */ - ms = min_spacing(v, tedge_v1(e)); - d = gts_point_distance(GTS_POINT(edge_v1(e)), GTS_POINT(v)); - } - - if (d < ms) - forces[k] = ms - d; - else - forces[k] = 0.; - - if (i->next) { -/* ms = min_net_net_spacing(TOPOROUTER_VERTEX(i->next->data), v); */ - ms = min_spacing(TOPOROUTER_VERTEX(i->next->data), v); - d = gts_point_distance(GTS_POINT(i->next->data), GTS_POINT(v)); - } - else { -/* ms = min_vertex_net_spacing(v, tedge_v2(e)); */ - ms = min_spacing(v, tedge_v2(e)); - d = gts_point_distance(GTS_POINT(edge_v2(e)), GTS_POINT(v)); - } - - if (d < ms) - forces[k] += d - ms; - - k++; - i = i->next; - } - - k = 0; - i = edge_routing(e); - while (i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); - if (forces[k] > EPSILON || forces[k] < -EPSILON) - equilibrium = 0; - vertex_move_towards_vertex_values(GTS_VERTEX(v), edge_v2(e), forces[k] * 0.1, &(GTS_POINT(v)->x), &(GTS_POINT(v)->y)); - k++; - i = i->next; - } - - if (equilibrium) { -/* printf("reached equilibriium at %d\n", j); */ - break; - } - - } - - free(forces); - return 0; -} - -void swap_vertices(toporouter_vertex_t ** v1, toporouter_vertex_t ** v2) -{ - toporouter_vertex_t *tempv = *v1; - *v1 = *v2; - *v2 = tempv; -} - -void split_edge_routing(toporouter_vertex_t * v, GList ** l1, GList ** l2) -{ - GList *base, *i; - - g_assert(v); - g_assert(v->routingedge); - - base = g_list_find(vrouting(v), v); - - *l1 = g_list_prepend(*l1, tedge_v1(v->routingedge)); - *l2 = g_list_prepend(*l2, tedge_v2(v->routingedge)); - - g_assert(base); - - i = base->next; - while (i) { - if (!(TOPOROUTER_VERTEX(i->data)->flags & VERTEX_FLAG_TEMP)) - *l2 = g_list_prepend(*l2, i->data); - i = i->next; - } - - i = base->prev; - while (i) { - if (!(TOPOROUTER_VERTEX(i->data)->flags & VERTEX_FLAG_TEMP)) - *l1 = g_list_prepend(*l1, i->data); - i = i->prev; - } -} - -GList *vertices_routing_conflicts(toporouter_vertex_t * v, toporouter_vertex_t * pv) -{ - toporouter_edge_t *e; - GList *rval = NULL, *l1 = NULL, *l2 = NULL, *i; - - if (vz(v) != vz(pv)) - return NULL; - g_assert(v != pv); - - if (!v->routingedge && !pv->routingedge) { - e = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(v), GTS_VERTEX(pv))); - if (!e) - return NULL; - i = edge_routing(e); - while (i) { - rval = g_list_prepend(rval, TOPOROUTER_VERTEX(i->data)->route); - i = i->next; - } - return rval; - } - - if (TOPOROUTER_IS_CONSTRAINT(v->routingedge) && TOPOROUTER_IS_CONSTRAINT(pv->routingedge)) - return NULL; - - if (TOPOROUTER_IS_CONSTRAINT(pv->routingedge)) - swap_vertices(&pv, &v); - - if (!v->routingedge) - swap_vertices(&pv, &v); - - e = v->routingedge; - - split_edge_routing(v, &l1, &l2); - g_assert(l2); - g_assert(l1); - - if (!pv->routingedge) { - toporouter_edge_t *e1, *e2; - e1 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(pv), edge_v1(e))); - e2 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(pv), edge_v2(e))); - - l1 = g_list_concat(l1, g_list_copy(edge_routing(e1))); - l2 = g_list_concat(l2, g_list_copy(edge_routing(e2))); - - } - else { - GList *pvlist1 = NULL, *pvlist2 = NULL; - toporouter_vertex_t *commonv = route_vertices_common_vertex(v, pv); - - g_assert(commonv); - - split_edge_routing(pv, &pvlist1, &pvlist2); - - if (commonv == tedge_v1(e)) { - toporouter_edge_t *ope; - - if (commonv == tedge_v1(pv->routingedge)) { - l1 = g_list_concat(l1, pvlist1); - l2 = g_list_concat(l2, pvlist2); - ope = TOPOROUTER_EDGE(gts_vertices_are_connected(edge_v2(e), edge_v2(pv->routingedge))); - } - else { - l1 = g_list_concat(l1, pvlist2); - l2 = g_list_concat(l2, pvlist1); - ope = TOPOROUTER_EDGE(gts_vertices_are_connected(edge_v2(e), edge_v1(pv->routingedge))); - } - g_assert(ope); - l2 = g_list_concat(l2, g_list_copy(edge_routing(ope))); - - } - else { - toporouter_edge_t *ope; - if (commonv == tedge_v1(pv->routingedge)) { - l1 = g_list_concat(l1, pvlist2); - l2 = g_list_concat(l2, pvlist1); - ope = TOPOROUTER_EDGE(gts_vertices_are_connected(edge_v1(e), edge_v2(pv->routingedge))); - } - else { - l1 = g_list_concat(l1, pvlist1); - l2 = g_list_concat(l2, pvlist2); - ope = TOPOROUTER_EDGE(gts_vertices_are_connected(edge_v1(e), edge_v1(pv->routingedge))); - } - g_assert(ope); - l1 = g_list_concat(l1, g_list_copy(edge_routing(ope))); - } - } - - i = l1; - while (i) { - toporouter_vertex_t *curv = TOPOROUTER_VERTEX(i->data); - - if (curv->flags & VERTEX_FLAG_ROUTE && (g_list_find(l2, curv->parent) || g_list_find(l2, curv->child))) { - if (!g_list_find(rval, curv->route)) - rval = g_list_prepend(rval, curv->route); - } - i = i->next; - } - i = l2; - while (i) { - toporouter_vertex_t *curv = TOPOROUTER_VERTEX(i->data); - - if (curv->flags & VERTEX_FLAG_ROUTE && (g_list_find(l1, curv->parent) || g_list_find(l1, curv->child))) { - if (!g_list_find(rval, curv->route)) - rval = g_list_prepend(rval, curv->route); - } - i = i->next; - } - - g_list_free(l1); - g_list_free(l2); - - return rval; -} - -gdouble vertices_routing_conflict_cost(toporouter_t * r, toporouter_vertex_t * v, toporouter_vertex_t * pv, guint * n) -{ - GList *conflicts = vertices_routing_conflicts(v, pv), *i; - gdouble penalty = 0.; - - i = conflicts; - while (i) { - (*n) += 1; - penalty += TOPOROUTER_ROUTE(i->data)->score; - i = i->next; - } - g_list_free(conflicts); -/* if(penalty > 0.) printf("conflict penalty of %f with %f,%f %f,%f\n", penalty, vx(v), vy(v), vx(pv), vy(pv)); */ - return penalty; -} - -gdouble -gcost(toporouter_t * r, toporouter_route_t * data, toporouter_vertex_t * srcv, toporouter_vertex_t * v, - toporouter_vertex_t * pv, guint * n, toporouter_netlist_t * pair) -{ - gdouble cost = 0., segcost; - - *n = pv->gn; - - if (g_list_find(data->srcvertices, v)) - return 0.; - - segcost = tvdistance(pv, v); - - if (pair && !TOPOROUTER_IS_CONSTRAINT(v->routingedge) && v->routingedge) { - GList *list = g_list_find(v->routingedge->routing, v); - toporouter_vertex_t *pv = edge_routing_prev_not_temp(v->routingedge, list); - toporouter_vertex_t *nv = edge_routing_next_not_temp(v->routingedge, list); - - if (pv->route && pv->route->netlist == pair) { - } - else if (nv->route && nv->route->netlist == pair) { - } - else { - segcost *= 10.; - } - } - - cost = pv->gcost + segcost; - - if (r->flags & TOPOROUTER_FLAG_LEASTINVALID) { - gdouble conflictcost = 0.; - - if (pv && v != pv && vz(v) == vz(pv)) - conflictcost = vertices_routing_conflict_cost(r, v, pv, n); - - if (!(r->flags & TOPOROUTER_FLAG_DETOUR && *n == 1)) { - cost += conflictcost * (pow(*n, 2)); - } - } - - return cost; -} - -#define vlayer(x) (&r->layers[(int)vz(x)]) - -guint candidate_is_available(toporouter_vertex_t * pv, toporouter_vertex_t * v) -{ - /* TODO: still needed? */ - while (pv) { - if (pv == v) - return 0; - pv = pv->parent; - } - - return 1; -} - -GList *route(toporouter_t * r, toporouter_route_t * data, guint debug) -{ - GtsEHeap *openlist = gts_eheap_new(route_heap_cmp, NULL); - GList *closelist = NULL; - GList *i, *rval = NULL; - toporouter_netlist_t *pair = NULL; - gint count = 0; - - toporouter_vertex_t *srcv = NULL, *destv = NULL, *curpoint = NULL; - toporouter_layer_t *cur_layer; /*, *dest_layer; */ - - g_assert(data->src->c != data->dest->c); - - if (data->destvertices) - g_list_free(data->destvertices); - if (data->srcvertices) - g_list_free(data->srcvertices); - - data->destvertices = cluster_vertices(r, data->dest); - data->srcvertices = cluster_vertices(r, data->src); - - closest_cluster_pair(r, data->srcvertices, data->destvertices, &curpoint, &destv); - - if (!curpoint || !destv) - goto routing_return; - - srcv = curpoint; - cur_layer = vlayer(curpoint); - /*dest_layer = vlayer(destv); */ - - data->path = NULL; - - data->alltemppoints = g_hash_table_new(g_direct_hash, g_direct_equal); - - curpoint->parent = NULL; - curpoint->child = NULL; - curpoint->gcost = 0.; - curpoint->gn = 0; - curpoint->hcost = simple_h_cost(r, curpoint, destv); - - if (data->netlist && data->netlist->pair) { - GList *i = r->routednets; - while (i) { - toporouter_route_t *curroute = TOPOROUTER_ROUTE(i->data); - if (curroute->netlist == data->netlist->pair) { - pair = data->netlist->pair; - break; - } - i = i->next; - } - } - - gts_epcb_heap_insert(openlist, curpoint); - - while (gts_epcb_heap_size(openlist) > 0) { - GList *candidatepoints; - data->curpoint = curpoint; - /*draw_route_status(r, closelist, openlist, curpoint, data, count++); */ - - curpoint = TOPOROUTER_VERTEX(gts_eheap_remove_top(openlist, NULL)); - if (curpoint->parent && !(curpoint->flags & VERTEX_FLAG_TEMP)) { - if (vz(curpoint) != vz(destv)) { - toporouter_vertex_t *tempv; - cur_layer = vlayer(curpoint); /*&r->layers[(int)vz(curpoint)]; */ - tempv = closest_dest_vertex(r, curpoint, data); - if (tempv) { - destv = tempv; - /*dest_layer = vlayer(destv);//&r->layers[(int)vz(destv)]; */ - - } - } - } - -/* destpoint = closest_dest_vertex(r, curpoint, data); - dest_layer = &r->layers[(int)vz(destpoint)];*/ - - if (g_list_find(data->destvertices, curpoint)) { - toporouter_vertex_t *temppoint = curpoint; - srcv = NULL; - destv = curpoint; - - data->path = NULL; - - while (temppoint) { - data->path = g_list_prepend(data->path, temppoint); - if (g_list_find(data->srcvertices, temppoint)) { - srcv = temppoint; - if (r->flags & TOPOROUTER_FLAG_AFTERORDER) - break; - } - temppoint = temppoint->parent; - } - rval = data->path; - data->score = path_score(r, data->path); -#ifdef DEBUG_ROUTE - printf("ROUTE: path score = %f computation cost = %d\n", data->score, count); -#endif - - if (srcv->bbox->cluster != data->src) { - data->src = srcv->bbox->cluster; - } - - if (destv->bbox->cluster != data->dest) { - data->dest = destv->bbox->cluster; - } - goto route_finish; - } - closelist_insert(curpoint); -#ifdef DEBUG_ROUTE - printf("\n\n\n*** ROUTE COUNT = %d\n", count); -#endif - candidatepoints = compute_candidate_points(r, cur_layer, curpoint, data, &destv); - -/*#ifdef DEBUG_ROUTE */ - /********************* - if(debug && !strcmp(data->dest->netlist, " unnamed_net2")) - { - unsigned int mask = ~(VERTEX_FLAG_RED | VERTEX_FLAG_GREEN | VERTEX_FLAG_BLUE); - char buffer[256]; - int j; - - for(j=0;jlayers[j].vertices; - while(i) { - TOPOROUTER_VERTEX(i->data)->flags &= mask; - i = i->next; - } - } - - i = candidatepoints; - while(i) { - TOPOROUTER_VERTEX(i->data)->flags |= VERTEX_FLAG_GREEN; -// printf("flagged a candpoint @ %f,%f\n", -// vx(i->data), vy(i->data)); - i = i->next; - } - - curpoint->flags |= VERTEX_FLAG_BLUE; - if(curpoint->parent) - curpoint->parent->flags |= VERTEX_FLAG_RED; - - - for(j=0;jlayers[j].surface, buffer, 1024, 1024, 2, datas, j, candidatepoints); - g_list_free(datas); - } - } -//#endif - *********************/ - count++; -/* if(count > 100) exit(0);*/ - i = candidatepoints; - while (i) { - toporouter_vertex_t *temppoint = TOPOROUTER_VERTEX(i->data); - if (!g_list_find(closelist, temppoint) && candidate_is_available(curpoint, temppoint)) { /*&& temppoint != curpoint) { */ - toporouter_heap_search_data_t heap_search_data = { temppoint, NULL }; - - guint temp_gn; - gdouble temp_g_cost = gcost(r, data, srcv, temppoint, curpoint, &temp_gn, pair); - - - gts_eheap_foreach(openlist, toporouter_heap_search, &heap_search_data); - - if (heap_search_data.result) { - if (temp_g_cost < temppoint->gcost) { - - temppoint->gcost = temp_g_cost; - temppoint->gn = temp_gn; - - temppoint->parent = curpoint; - curpoint->child = temppoint; - - gts_eheap_update(openlist); - } - } - else { - temppoint->parent = curpoint; - curpoint->child = temppoint; - - temppoint->gcost = temp_g_cost; - temppoint->gn = temp_gn; - - temppoint->hcost = simple_h_cost(r, temppoint, destv); -/* if(cur_layer != dest_layer) temppoint->hcost += r->viacost;*/ - gts_epcb_heap_insert(openlist, temppoint); - } - - } - i = i->next; - } - g_list_free(candidatepoints); - - } -#ifdef DEBUG_ROUTE - printf("ROUTE: could not find path!\n"); -#endif - - data->score = INFINITY; - clean_routing_edges(r, data); - - data->path = NULL; - /*TOPOROUTER_VERTEX(data->src->point)->parent = NULL; - TOPOROUTER_VERTEX(data->src->point)->child = NULL; */ - goto routing_return; - -/* - { - int i; - for(i=0;iroutecount, i); - toporouter_draw_surface(r, r->layers[i].surface, buffer, 1280, 1280, 2, data, i, NULL); - } - r->routecount++; - } - exit(0); -*/ -route_finish: -/* printf(" * finished a*\n");*/ -/* - { - int i; - for(i=0;iroutecount); - toporouter_draw_surface(r, r->layers[i].surface, buffer, 1024, 1024, 2, data, i, NULL); - } - r->routecount++; - } -*/ -/* { - i = data->path; - while(i) { - toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data); - - if(tv->routingedge) { - GList *list = g_list_find(edge_routing(tv->routingedge), tv); - toporouter_vertex_t *restartv = NULL, *boxpoint; - - g_assert(list); - - if(!list->next) { - if(vertex_bbox(tedge_v2(tv->routingedge))) - boxpoint = TOPOROUTER_VERTEX(vertex_bbox(tedge_v2(tv->routingedge))->point); - else - boxpoint = NULL; - - if(tedge_v2(tv->routingedge) != srcv && g_list_find(data->srcvertices, tedge_v2(tv->routingedge))) - restartv = tedge_v2(tv->routingedge); - else if(boxpoint != srcv && g_list_find(data->srcvertices, boxpoint)) - restartv = boxpoint; - } - - if(!list->prev) { - if(vertex_bbox(tedge_v1(tv->routingedge))) - boxpoint = TOPOROUTER_VERTEX(vertex_bbox(tedge_v1(tv->routingedge))->point); - else - boxpoint = NULL; - - if(tedge_v1(tv->routingedge) != srcv && g_list_find(data->srcvertices, tedge_v1(tv->routingedge))) - restartv = tedge_v1(tv->routingedge); - else if(boxpoint != srcv && g_list_find(data->srcvertices, boxpoint)) - restartv = boxpoint; - - } - - if(restartv) { - clean_routing_edges(r, data); - gts_epcb_heap_destroy(openlist); - g_list_free(closelist); - openlist = gts_eheap_new(route_heap_cmp, NULL); - closelist = NULL; - g_list_free(data->path); - printf("ROUTING RESTARTING with new src %f,%f,%f\n", vx(restartv), vy(restartv), vz(restartv)); - curpoint = restartv; - goto route_begin; - } - } - - i = i->next; - } - }*/ - - { - toporouter_vertex_t *pv = NULL; - GList *i = data->path; - while (i) { - toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data); - - if (pv && g_list_find(data->srcvertices, tv)) { - GList *temp = g_list_copy(i); - g_list_free(data->path); - data->path = temp; - i = data->path; - } - pv = tv; - i = i->next; - } - } - - { - toporouter_vertex_t *pv = NULL; - GList *i = data->path; - while (i) { - toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data); - if (tv->flags & VERTEX_FLAG_TEMP) { - tv->flags ^= VERTEX_FLAG_TEMP; - tv->flags |= VERTEX_FLAG_ROUTE; - } - if (pv) - pv->child = tv; - - if (tv->routingedge) - tv->route = data; - -/* if(tv->routingedge && !TOPOROUTER_IS_CONSTRAINT(tv->routingedge)) space_edge(tv->routingedge, NULL);*/ - - pv = tv; - i = i->next; - } - } - - { - toporouter_vertex_t *pv = NULL, *v = NULL; - - GList *i = data->path; - while (i) { - v = TOPOROUTER_VERTEX(i->data); - - if (pv) { - v->parent = pv; - pv->child = v; - } - else { - v->parent = NULL; - } - - pv = v; - i = i->next; - } - - if (v) - v->child = NULL; - } - - clean_routing_edges(r, data); - { - GList *i = data->path; - while (i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); - - if (v->routingedge && !TOPOROUTER_IS_CONSTRAINT(v->routingedge)) - space_edge(v->routingedge, NULL); - i = i->next; - } - } -routing_return: - - g_list_free(data->destvertices); - g_list_free(data->srcvertices); - data->destvertices = NULL; - data->srcvertices = NULL; - gts_epcb_heap_destroy(openlist); - g_list_free(closelist); - - data->alltemppoints = NULL; - - return rval; -} - -/* moves vertex v d units in the direction of vertex p */ -void vertex_move_towards_point(GtsVertex * v, gdouble px, gdouble py, gdouble d) -{ - gdouble dx = px - GTS_POINT(v)->x; - gdouble dy = py - GTS_POINT(v)->y; - gdouble theta = atan(fabs(dy / dx)); - - g_assert(finite(theta)); - - if (dx >= 0.) { - - if (dy >= 0.) { - GTS_POINT(v)->x += d * cos(theta); - GTS_POINT(v)->y += d * sin(theta); - } - else { - GTS_POINT(v)->x += d * cos(theta); - GTS_POINT(v)->y -= d * sin(theta); - } - - } - else { - - if (dy >= 0.) { - GTS_POINT(v)->x -= d * cos(theta); - GTS_POINT(v)->y += d * sin(theta); - } - else { - GTS_POINT(v)->x -= d * cos(theta); - GTS_POINT(v)->y -= d * sin(theta); - } - - } - -} - -/* moves vertex v d units in the direction of vertex p */ -void vertex_move_towards_vertex(GtsVertex * v, GtsVertex * p, gdouble d) -{ - gdouble dx = GTS_POINT(p)->x - GTS_POINT(v)->x; - gdouble dy = GTS_POINT(p)->y - GTS_POINT(v)->y; - gdouble theta = atan(fabs(dy / dx)); - - g_assert(finite(theta)); - - if (dx >= 0.) { - - if (dy >= 0.) { - GTS_POINT(v)->x += d * cos(theta); - GTS_POINT(v)->y += d * sin(theta); - } - else { - GTS_POINT(v)->x += d * cos(theta); - GTS_POINT(v)->y -= d * sin(theta); - } - - } - else { - - if (dy >= 0.) { - GTS_POINT(v)->x -= d * cos(theta); - GTS_POINT(v)->y += d * sin(theta); - } - else { - GTS_POINT(v)->x -= d * cos(theta); - GTS_POINT(v)->y -= d * sin(theta); - } - - } - -} - - -gdouble pathvertex_arcing_through_constraint(toporouter_vertex_t * pathv, toporouter_vertex_t * arcv) -{ - toporouter_vertex_t *v = pathv->child; - - if (!v || !v->routingedge) - return 0.; - - while (v->flags & VERTEX_FLAG_ROUTE && (tedge_v1(v->routingedge) == arcv || tedge_v2(v->routingedge) == arcv)) { - if (TOPOROUTER_IS_CONSTRAINT(v->routingedge)) - return gts_point_distance(GTS_POINT(tedge_v1(v->routingedge)), GTS_POINT(tedge_v2(v->routingedge))); - v = v->child; - } - - v = pathv->parent; - while (v->flags & VERTEX_FLAG_ROUTE && (tedge_v1(v->routingedge) == arcv || tedge_v2(v->routingedge) == arcv)) { - if (TOPOROUTER_IS_CONSTRAINT(v->routingedge)) - return gts_point_distance(GTS_POINT(tedge_v1(v->routingedge)), GTS_POINT(tedge_v2(v->routingedge))); - v = v->parent; - } - - return 0.; -} - -gint vertices_connected(toporouter_vertex_t * a, toporouter_vertex_t * b) -{ - return ((a->route->netlist == b->route->netlist && a->route->src->c == b->route->src->c) ? 1 : 0); -} - -gdouble edge_min_spacing(GList * list, toporouter_edge_t * e, toporouter_vertex_t * v, guint debug) -{ - toporouter_vertex_t *origin; - GList *i = list; - gdouble space = 0.; - toporouter_vertex_t *nextv, *prevv; - /*toporouter_vertex_t *edgev; - gdouble constraint_spacing; */ - - if (!list) - return INFINITY; - -/* printf("\t CMS %f,%f - %f,%f\n", vx(tedge_v1(e)), vy(tedge_v1(e)), vx(tedge_v2(e)), vy(tedge_v2(e))); */ - - prevv = origin = TOPOROUTER_VERTEX(list->data); - -/* print_edge(e); */ - - i = list; - if (gts_point_distance2(GTS_POINT(origin), GTS_POINT(edge_v1(e))) < gts_point_distance2(GTS_POINT(v), GTS_POINT(edge_v1(e)))) { - - /* towards v2 */ - while (i) { - nextv = edge_routing_next(e, i); - if (nextv->route && vertices_connected(nextv, prevv)) { - i = i->next; - continue; - } - if (!(nextv->flags & VERTEX_FLAG_TEMP)) { - gdouble ms = min_spacing(prevv, nextv); - if (nextv == tedge_v2(e)) { - gdouble cms = pathvertex_arcing_through_constraint(TOPOROUTER_VERTEX(i->data), tedge_v2(e)); -/* printf("\t CMS to %f,%f = %f \t ms = %f\n", vx(tedge_v2(e)), vy(tedge_v2(e)), cms, ms); - if(vx(tedge_v2(e)) > -EPSILON && vx(tedge_v2(e)) < EPSILON) { - printf("\t\tPROB: "); - print_vertex(tedge_v2(e)); - }*/ - if (cms > EPSILON) - space += MIN(ms, cms / 2.); - else - space += ms; - } - else - space += ms; - - prevv = nextv; - } -/* printf("%f ", space);*/ - i = i->next; - } - } - else { - - /* towards v1 */ - while (i) { - nextv = edge_routing_prev(e, i); - if (nextv->route && vertices_connected(nextv, prevv)) { - i = i->prev; - continue; - } - if (!(nextv->flags & VERTEX_FLAG_TEMP)) { - gdouble ms = min_spacing(prevv, nextv); - if (nextv == tedge_v1(e)) { - gdouble cms = pathvertex_arcing_through_constraint(TOPOROUTER_VERTEX(i->data), tedge_v1(e)); -/* printf("\t CMS to %f,%f = %f \t ms = %f\n", vx(tedge_v1(e)), vy(tedge_v1(e)), cms, ms); - if(vx(tedge_v1(e)) > -EPSILON && vx(tedge_v1(e)) < EPSILON) { - printf("\t\tPROB: "); - print_vertex(tedge_v1(e)); - }*/ - if (cms > EPSILON) - space += MIN(ms, cms / 2.); - else - space += ms; - } - else - space += ms; - - prevv = nextv; - } -/* printf("%f ", space);*/ - i = i->prev; - } - } - - if (TOPOROUTER_IS_CONSTRAINT(e) && space > gts_point_distance(GTS_POINT(edge_v1(e)), GTS_POINT(edge_v2(e))) / 2.) - space = gts_point_distance(GTS_POINT(edge_v1(e)), GTS_POINT(edge_v2(e))) / 2.; - -/* if(debug) printf("\tedge_min_spacing: %f\n", space);*/ - return space; -} - -/* line segment is 1 & 2, point is 3 - returns 0 if v3 is outside seg -*/ -guint -vertex_line_normal_intersection(gdouble x1, gdouble y1, gdouble x2, gdouble y2, gdouble x3, gdouble y3, gdouble * x, - gdouble * y) -{ - gdouble m1 = cartesian_gradient(x1, y1, x2, y2); - gdouble m2 = perpendicular_gradient(m1); - gdouble c2 = (isinf(m2)) ? x3 : y3 - (m2 * x3); - gdouble c1 = (isinf(m1)) ? x1 : y1 - (m1 * x1); - - if (isinf(m2)) - *x = x3; - else if (isinf(m1)) - *x = x1; - else - *x = (c2 - c1) / (m1 - m2); - - *y = (isinf(m2)) ? y1 : (m2 * (*x)) + c2; - - if (*x >= MIN(x1, x2) - EPSILON && *x <= MAX(x1, x2) + EPSILON && *y >= MIN(y1, y2) - EPSILON && *y <= MAX(y1, y2) + EPSILON) - return 1; - return 0; -} - -void print_toporouter_arc(toporouter_arc_t * arc) -{ -/* GList *i = arc->vs;*/ - - printf("ARC CENTRE: %f,%f ", vx(arc->centre), vy(arc->centre)); /* print_vertex(arc->centre); */ - printf("RADIUS: %f", arc->r); - - if (arc->dir > 0) - printf(" COUNTERCLOCKWISE "); - else if (arc->dir < 0) - printf(" CLOCKWISE "); - else - printf(" COLINEAR(ERROR) "); -/* - printf("\n\tVS: "); - - while(i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); - printf("%f,%f ", vx(v), vy(v)); - - i = i->next; - } -*/ -} - -void toporouter_arc_remove(toporouter_oproute_t * oproute, toporouter_arc_t * arc) -{ - oproute->arcs = g_list_remove(oproute->arcs, arc); - - if (arc->v) - arc->v->arc = NULL; -} - -toporouter_arc_t *toporouter_arc_new(toporouter_oproute_t * oproute, toporouter_vertex_t * v1, toporouter_vertex_t * v2, - toporouter_vertex_t * centre, gdouble r, gint dir) -{ - toporouter_arc_t *arc = TOPOROUTER_ARC(gts_object_new(GTS_OBJECT_CLASS(toporouter_arc_class()))); - arc->centre = centre; - arc->v = v1; - arc->v1 = v1; - arc->v2 = v2; - arc->r = r; - arc->dir = dir; - - if (v1) - v1->arc = arc; - arc->oproute = oproute; - - arc->clearance = NULL; - - return arc; -} - -void path_set_oproute(GList * path, toporouter_oproute_t * oproute) -{ - while (path) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(path->data); - - if (v->flags & VERTEX_FLAG_ROUTE) - v->oproute = oproute; - - path = path->next; - } -} - -void print_oproute(toporouter_oproute_t * oproute) -{ - GList *i = oproute->arcs; - - printf("Optimized Route:\n"); - printf("\tNetlist:\t\t%s\n\tStyle:\t\t%s\n", oproute->netlist, oproute->style); - /* printf("%s\n", oproute->netlist); */ -/* - i = oproute->term1->zlink; - while(i) { - toporouter_vertex_t *thisv = TOPOROUTER_VERTEX(i->data); - printf("\tNetlist:\t\t%s\n\tStyle:\t\t%s\n", vertex_bbox(thisv)->netlist, vertex_bbox(thisv)->style); - i = i->next; - } -*/ - printf("\t"); - print_vertex(oproute->term1); - printf("\n"); - i = oproute->arcs; - while (i) { - toporouter_arc_t *arc = (toporouter_arc_t *) i->data; - printf("\t"); - print_toporouter_arc(arc); - printf("\n"); - i = i->next; - } - printf("\t"); - print_vertex(oproute->term2); - printf("\n"); -} - -gdouble export_pcb_drawline(guint layer, guint x0, guint y0, guint x1, guint y1, guint thickness, guint clearance) -{ - gdouble d = 0.; - pcb_line_t *line; - line = pcb_line_new_merge(LAYER_PTR(layer), x0, y0, x1, y1, - thickness, clearance, pcb_flag_make(PCB_FLAG_AUTO | (PCB_FLAG_TEST(PCB_CLEARNEWFLAG, PCB) ? PCB_FLAG_CLEARLINE : 0))); - - if (line) { - pcb_undo_add_obj_to_create(PCB_TYPE_LINE, LAYER_PTR(layer), line, line); - d = coord_distance((double) x0, (double) y0, (double) x1, (double) y1) / 100.; - } - return d; -} - -gdouble arc_angle(toporouter_arc_t * arc) -{ - gdouble x0, x1, y0, y1; - - x0 = arc->x0 - vx(arc->centre); - x1 = arc->x1 - vx(arc->centre); - y0 = arc->y0 - vy(arc->centre); - y1 = arc->y1 - vy(arc->centre); - - return fabs(acos(((x0 * x1) + (y0 * y1)) / (sqrt(pow(x0, 2) + pow(y0, 2)) * sqrt(pow(x1, 2) + pow(y1, 2))))); -} - -gdouble export_pcb_drawarc(guint layer, toporouter_arc_t * a, guint thickness, guint clearance) -{ - gdouble sa, da, theta; - gdouble d = 0.; - pcb_arc_t *arc; - gint wind; - - wind = coord_wind(a->x0, a->y0, a->x1, a->y1, vx(a->centre), vy(a->centre)); - - sa = coord_xangle(a->x0, a->y0, vx(a->centre), vy(a->centre)) * 180. / M_PI; - - theta = arc_angle(a); - - if (!a->dir || !wind) - return 0.; - - if (a->dir != wind) - theta = 2. * M_PI - theta; - - da = -a->dir * theta * 180. / M_PI; - - if (da < 1. && da > -1.) - return 0.; - if (da > 359. || da < -359.) - return 0.; - - arc = pcb_arc_new(LAYER_PTR(layer), vx(a->centre), vy(a->centre), a->r, a->r, - sa, da, thickness, clearance, - pcb_flag_make(PCB_FLAG_AUTO | (PCB_FLAG_TEST(PCB_CLEARNEWFLAG, PCB) ? PCB_FLAG_CLEARLINE : 0))); - - if (arc) { - pcb_undo_add_obj_to_create(PCB_TYPE_ARC, LAYER_PTR(layer), arc, arc); - d = a->r * theta / 100.; - } - - return d; -} - -void calculate_term_to_arc(toporouter_vertex_t * v, toporouter_arc_t * arc, guint dir) -{ - gdouble theta, a, b, bx, by, a0x, a0y, a1x, a1y; - gint winddir; - - theta = acos(arc->r / gts_point_distance(GTS_POINT(v), GTS_POINT(arc->centre))); - a = arc->r * sin(theta); - b = arc->r * cos(theta); -#ifdef DEBUG_EXPORT - printf("drawing arc with r %f theta %f d %f centre = %f,%f\n", arc->r, theta, - gts_point_distance(GTS_POINT(v), GTS_POINT(arc->centre)), vx(arc->centre), vy(arc->centre)); -#endif - point_from_point_to_point(arc->centre, v, b, &bx, &by); - - coords_on_line(bx, by, perpendicular_gradient(point_gradient(GTS_POINT(v), GTS_POINT(arc->centre))), a, &a0x, &a0y, &a1x, - &a1y); - - winddir = coord_wind(vx(v), vy(v), a0x, a0y, vx(arc->centre), vy(arc->centre)); - - if (!winddir) { - printf("!winddir @ v %f,%f arc->centre %f,%f\n", vx(v), vy(v), vx(arc->centre), vy(arc->centre)); - /*TODO: fix hack: this shouldn't happen */ - arc->x0 = vx(v); - arc->y0 = vy(v); - arc->x1 = vx(v); - arc->y1 = vy(v); - return; - } - - g_assert(winddir); - - if (dir) - winddir = -winddir; - - if (winddir == arc->dir) { - if (!dir) { - arc->x0 = a0x; - arc->y0 = a0y; - } - else { - arc->x1 = a0x; - arc->y1 = a0y; - } - } - else { - if (!dir) { - arc->x0 = a1x; - arc->y0 = a1y; - } - else { - arc->x1 = a1x; - arc->y1 = a1y; - } - } - -} - - - -/* b1 is the projection in the direction of narc, while b2 is the perpendicular projection*/ -void arc_ortho_projections(toporouter_arc_t * arc, toporouter_arc_t * narc, gdouble * b1, gdouble * b2) -{ - gdouble nax, nay, ax, ay, alen2, c; - gdouble b1x, b1y, b2x, b2y; - -#ifdef DEBUG_EXPORT - printf("arc c = %f,%f narc c = %f,%f arc->0 = %f,%f\n", - vx(arc->centre), vy(arc->centre), vx(narc->centre), vy(narc->centre), arc->x0, arc->y0); -#endif - - nax = vx(narc->centre) - vx(arc->centre); - nay = vy(narc->centre) - vy(arc->centre); - alen2 = pow(nax, 2) + pow(nay, 2); - - - ax = arc->x0 - vx(arc->centre); - ay = arc->y0 - vy(arc->centre); - -#ifdef DEBUG_EXPORT - printf("norm narc = %f,%f - %f\tA=%f,%f\n", nax, nay, sqrt(alen2), ax, ay); -#endif - - c = ((ax * nax) + (ay * nay)) / alen2; - - b1x = c * nax; - b1y = c * nay; - b2x = ax - b1x; - b2y = ay - b1y; - -#ifdef DEBUG_EXPORT - printf("proj = %f,%f perp proj = %f,%f\n", b1x, b1y, b2x, b2y); -#endif - - *b1 = sqrt(pow(b1x, 2) + pow(b1y, 2)); - *b2 = sqrt(pow(b2x, 2) + pow(b2y, 2)); - -} - -guint calculate_arc_to_arc(toporouter_t * ar, toporouter_arc_t * parc, toporouter_arc_t * arc) -{ - gdouble theta, a, b, bx, by, a0x, a0y, a1x, a1y, m, preva, prevb; - gint winddir; - toporouter_arc_t *bigr, *smallr; - - if (parc->r > arc->r) { - bigr = parc; - smallr = arc; - } - else { - bigr = arc; - smallr = parc; - } -#ifdef DEBUG_EXPORT - printf("bigr centre = %f,%f smallr centre = %f,%f\n", vx(bigr->centre), vy(bigr->centre), - vx(smallr->centre), vy(smallr->centre)); -#endif - - m = perpendicular_gradient(point_gradient(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre))); - - if (bigr->centre == smallr->centre) { - - printf("bigr->centre == smallr->centre @ %f,%f\n", vx(smallr->centre), vy(smallr->centre)); - } - - g_assert(bigr->centre != smallr->centre); - - if (parc->dir == arc->dir) { -/*export_arc_straight:*/ - - theta = acos((bigr->r - smallr->r) / gts_point_distance(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre))); - a = bigr->r * sin(theta); - b = bigr->r * cos(theta); - - point_from_point_to_point(bigr->centre, smallr->centre, b, &bx, &by); - - coords_on_line(bx, by, m, a, &a0x, &a0y, &a1x, &a1y); - - winddir = coord_wind(vx(smallr->centre), vy(smallr->centre), a0x, a0y, vx(bigr->centre), vy(bigr->centre)); - - arc_ortho_projections(parc, arc, &prevb, &preva); -/*#ifdef DEBUG_EXPORT */ - if (!winddir) { - - printf("STRAIGHT:\n"); - printf("bigr centre = %f,%f smallr centre = %f,%f\n", vx(bigr->centre), vy(bigr->centre), - vx(smallr->centre), vy(smallr->centre)); - printf("theta = %f a = %f b = %f bigrr = %f d = %f po = %f\n", theta, a, b, bigr->r, - gts_point_distance(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre)), - bigr->r / gts_point_distance(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre))); - printf("bigr-r = %f smallr-r = %f ratio = %f\n", - bigr->r, smallr->r, (bigr->r - smallr->r) / gts_point_distance(GTS_POINT(bigr->centre), - GTS_POINT(smallr->centre))); - printf("preva = %f prevb = %f\n\n", preva, prevb); - - } -/*#endif*/ - g_assert(winddir); - - if (bigr == parc) - winddir = -winddir; - - if (winddir == bigr->dir) { - if (bigr == arc) { - bigr->x0 = a0x; - bigr->y0 = a0y; - } - else { - bigr->x1 = a0x; - bigr->y1 = a0y; - } - } - else { - if (bigr == arc) { - bigr->x0 = a1x; - bigr->y0 = a1y; - } - else { - bigr->x1 = a1x; - bigr->y1 = a1y; - } - } - - a = smallr->r * sin(theta); - b = smallr->r * cos(theta); - -#ifdef DEBUG_EXPORT - printf("a = %f b = %f\n", a, b); -#endif - point_from_point_to_point(smallr->centre, bigr->centre, -b, &bx, &by); - - coords_on_line(bx, by, m, a, &a0x, &a0y, &a1x, &a1y); - - if (winddir == bigr->dir) { - if (bigr == arc) { - smallr->x1 = a0x; - smallr->y1 = a0y; - } - else { - smallr->x0 = a0x; - smallr->y0 = a0y; - } - } - else { - if (bigr == arc) { - smallr->x1 = a1x; - smallr->y1 = a1y; - } - else { - smallr->x0 = a1x; - smallr->y0 = a1y; - } - } - - } - else { - -/*export_arc_twist: */ - - theta = acos((bigr->r + smallr->r) / gts_point_distance(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre))); - a = bigr->r * sin(theta); - b = bigr->r * cos(theta); - - point_from_point_to_point(bigr->centre, smallr->centre, b, &bx, &by); - - coords_on_line(bx, by, m, a, &a0x, &a0y, &a1x, &a1y); - - winddir = coord_wind(vx(smallr->centre), vy(smallr->centre), a0x, a0y, vx(bigr->centre), vy(bigr->centre)); -/*#ifdef DEBUG_EXPORT */ - if (!winddir) { - printf("TWIST:\n"); - printf("theta = %f a = %f b = %f r = %f d = %f po = %f\n", theta, a, b, bigr->r + smallr->r, - gts_point_distance(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre)), - (bigr->r + smallr->r) / gts_point_distance(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre))); - - printf("bigr centre = %f,%f smallr centre = %f,%f\n\n", vx(bigr->centre), vy(bigr->centre), - vx(smallr->centre), vy(smallr->centre)); - - printf("big wind = %d small wind = %d\n", bigr->dir, smallr->dir); - return 1; - } -/*#endif */ -/* if(!winddir) { - smallr->centre->flags |= VERTEX_FLAG_RED; - bigr->centre->flags |= VERTEX_FLAG_GREEN; - //bigr->centre->flags |= VERTEX_FLAG_RED; - { - int i; - for(i=0;ilayers[i].surface, buffer, 2096, 2096, 2, NULL, i, NULL); - } - } - return; - } -*/ - g_assert(winddir); - - if (bigr == parc) - winddir = -winddir; - - if (winddir == bigr->dir) { - if (bigr == arc) { - bigr->x0 = a0x; - bigr->y0 = a0y; - } - else { - bigr->x1 = a0x; - bigr->y1 = a0y; - } - } - else { - if (bigr == arc) { - bigr->x0 = a1x; - bigr->y0 = a1y; - } - else { - bigr->x1 = a1x; - bigr->y1 = a1y; - } - } - - a = smallr->r * sin(theta); - b = smallr->r * cos(theta); - - point_from_point_to_point(smallr->centre, bigr->centre, b, &bx, &by); - - coords_on_line(bx, by, m, a, &a0x, &a0y, &a1x, &a1y); - - winddir = coord_wind(vx(smallr->centre), vy(smallr->centre), a0x, a0y, vx(bigr->centre), vy(bigr->centre)); - - g_assert(winddir); - - if (bigr == parc) - winddir = -winddir; - - if (winddir == smallr->dir) { - if (bigr == arc) { - smallr->x1 = a0x; - smallr->y1 = a0y; - } - else { - smallr->x0 = a0x; - smallr->y0 = a0y; - } - } - else { - if (bigr == arc) { - smallr->x1 = a1x; - smallr->y1 = a1y; - } - else { - smallr->x0 = a1x; - smallr->y0 = a1y; - } - } - - } - - return 0; -} - -void export_oproutes(toporouter_t * ar, toporouter_oproute_t * oproute) -{ - guint layer = PCB->LayerGroups.Entries[oproute->layergroup][0]; - guint thickness = lookup_thickness(oproute->style); - guint clearance = lookup_clearance(oproute->style); - GList *arcs = oproute->arcs; - toporouter_arc_t *arc, *parc = NULL; - - if (!arcs) { - ar->wiring_score += - export_pcb_drawline(layer, vx(oproute->term1), vy(oproute->term1), vx(oproute->term2), vy(oproute->term2), thickness, - clearance); - return; - } - - -/* calculate_term_to_arc(oproute->term1, TOPOROUTER_ARC(arcs->data), 0, layer);*/ - - while (arcs) { - arc = TOPOROUTER_ARC(arcs->data); - - if (parc && arc) { - ar->wiring_score += export_pcb_drawarc(layer, parc, thickness, clearance); - ar->wiring_score += export_pcb_drawline(layer, parc->x1, parc->y1, arc->x0, arc->y0, thickness, clearance); - } - else if (!parc) { - ar->wiring_score += - export_pcb_drawline(layer, vx(oproute->term1), vy(oproute->term1), arc->x0, arc->y0, thickness, clearance); - } - - parc = arc; - arcs = arcs->next; - } - ar->wiring_score += export_pcb_drawarc(layer, arc, thickness, clearance); - ar->wiring_score += export_pcb_drawline(layer, arc->x1, arc->y1, vx(oproute->term2), vy(oproute->term2), thickness, clearance); - -} - - - -void oproute_free(toporouter_oproute_t * oproute) -{ - GList *i = oproute->arcs; - while (i) { - toporouter_arc_t *arc = (toporouter_arc_t *) i->data; - if (arc->centre->flags & VERTEX_FLAG_TEMP) - gts_object_destroy(GTS_OBJECT(arc->centre)); - - i = i->next; - } - - g_list_free(oproute->arcs); - free(oproute); -} - -void oproute_calculate_tof(toporouter_oproute_t * oproute) -{ - GList *arcs = oproute->arcs; - toporouter_arc_t *parc = NULL, *arc; - - oproute->tof = 0.; - - if (!arcs) { - oproute->tof = gts_point_distance(GTS_POINT(oproute->term1), GTS_POINT(oproute->term2)); - return; - } - - while (arcs) { - arc = TOPOROUTER_ARC(arcs->data); - - if (parc && arc) { - oproute->tof += arc_angle(parc) * parc->r; - oproute->tof += sqrt(pow(parc->x1 - arc->x0, 2) + pow(parc->y1 - arc->y0, 2)); - } - else if (!parc) { - oproute->tof += sqrt(pow(arc->x0 - vx(oproute->term1), 2) + pow(arc->y0 - vy(oproute->term1), 2)); - } - - parc = arc; - arcs = arcs->next; - } - - oproute->tof += arc_angle(parc) * parc->r; - oproute->tof += sqrt(pow(arc->x1 - vx(oproute->term2), 2) + pow(arc->y1 - vy(oproute->term2), 2)); - -} - -gdouble -line_line_distance_at_normal(gdouble line1_x1, gdouble line1_y1, - gdouble line1_x2, gdouble line1_y2, - gdouble line2_x1, gdouble line2_y1, gdouble line2_x2, gdouble line2_y2, gdouble x, gdouble y) -{ - gdouble m1 = perpendicular_gradient(cartesian_gradient(line1_x1, line1_y1, line1_x2, line1_y2)); - gdouble m2 = cartesian_gradient(line2_x1, line2_y1, line2_x2, line2_y2); - gdouble c1 = (isinf(m1)) ? x : y - (m1 * x); - gdouble c2 = (isinf(m2)) ? line2_x1 : line2_y1 - (m2 * line2_x1); - - gdouble intx, inty; - - if (isinf(m2)) - intx = line2_x1; - else if (isinf(m1)) - intx = x; - else - intx = (c2 - c1) / (m1 - m2); - - inty = (isinf(m2)) ? (m1 * intx) + c1 : (m2 * intx) + c2; - - return sqrt(pow(x - intx, 2) + pow(y - inty, 2)); -} - -void calculate_serpintine(gdouble delta, gdouble r, gdouble initiala, gdouble * a, guint * nhalfcycles) -{ - gdouble lhalfcycle = 2. * (initiala - r) + (M_PI * r); - guint n; - - printf("lhalfcycle = %f r = %f\n", lhalfcycle, r); - - n = (delta - M_PI * r) / (lhalfcycle - 2. * r) + 1; - *a = (delta + 4. * n * r - n * M_PI * r + 4. * r - M_PI * r) / (2. * n); - *nhalfcycles = n; -} - -gdouble oproute_min_spacing(toporouter_oproute_t * a, toporouter_oproute_t * b) -{ - return lookup_thickness(a->style) / 2. + lookup_thickness(b->style) / 2. + MAX(lookup_clearance(a->style), - lookup_clearance(b->style)); -} - -gdouble vector_angle(gdouble ox, gdouble oy, gdouble ax, gdouble ay, gdouble bx, gdouble by) -{ - gdouble alen = sqrt(pow(ax - ox, 2) + pow(ay - oy, 2)); - gdouble blen = sqrt(pow(bx - ox, 2) + pow(by - oy, 2)); - return acos(((ax - ox) * (bx - ox) + (ay - oy) * (by - oy)) / (alen * blen)); -} - -toporouter_serpintine_t *toporouter_serpintine_new(gdouble x, gdouble y, gdouble x0, gdouble y0, gdouble x1, gdouble y1, - gpointer start, gdouble halfa, gdouble radius, guint nhalfcycles) -{ - toporouter_serpintine_t *serp = (toporouter_serpintine_t *) malloc(sizeof(toporouter_serpintine_t)); - serp->x = x; - serp->y = y; - serp->x0 = x0; - serp->y0 = y0; - serp->x1 = x1; - serp->y1 = y1; - serp->start = start; - serp->halfa = halfa; - serp->radius = radius; - serp->nhalfcycles = nhalfcycles; - serp->arcs = NULL; - return serp; -} - -/*#define DEBUG_RUBBERBAND 1*/ - -gdouble -check_non_intersect_vertex(gdouble x0, gdouble y0, gdouble x1, gdouble y1, toporouter_vertex_t * pathv, - toporouter_vertex_t * arcv, toporouter_vertex_t * opv, gint wind, gint * arcwind, gdouble * arcr, - guint debug) -{ - gdouble ms, line_int_x, line_int_y, x, y, d = 0., m; - gdouble tx0, ty0, tx1, ty1; - gint wind1, wind2; - - g_assert(pathv->routingedge); - - if (TOPOROUTER_IS_CONSTRAINT(pathv->routingedge)) { - gdouble d = tvdistance(tedge_v1(pathv->routingedge), tedge_v2(pathv->routingedge)) / 2.; - ms = min_spacing(pathv, arcv); - if (ms > d) - ms = d; - } - else { - ms = edge_min_spacing(g_list_find(edge_routing(pathv->routingedge), pathv), pathv->routingedge, arcv, debug); - } - - - if (!vertex_line_normal_intersection(x0, y0, x1, y1, vx(arcv), vy(arcv), &line_int_x, &line_int_y)) { - - if (coord_distance2(x0, y0, line_int_x, line_int_y) < coord_distance2(x1, y1, line_int_x, line_int_y)) { - line_int_x = x0; - line_int_y = y0; - } - else { - line_int_x = x1; - line_int_y = y1; - } - - m = perpendicular_gradient(cartesian_gradient(vx(arcv), vy(arcv), line_int_x, line_int_y)); - } - else { - m = cartesian_gradient(x0, y0, x1, y1); - } - - coords_on_line(vx(arcv), vy(arcv), m, 100., &tx0, &ty0, &tx1, &ty1); - - wind1 = coord_wind(tx0, ty0, tx1, ty1, line_int_x, line_int_y); - wind2 = coord_wind(tx0, ty0, tx1, ty1, vx(opv), vy(opv)); - - if (!wind2 || wind1 == wind2) - return -1.; - - if (!wind) { - coords_on_line(line_int_x, line_int_y, perpendicular_gradient(m), ms, &tx0, &ty0, &tx1, &ty1); - if (coord_distance2(tx0, ty0, vx(opv), vy(opv)) < coord_distance2(tx1, ty1, vx(opv), vy(opv))) { - x = tx0; - y = ty0; - } - else { - x = tx1; - y = ty1; - } - } - else { - toporouter_vertex_t *parent = pathv->parent, *child = pathv->child; - guint windtests = 0; - - d = coord_distance(vx(arcv), vy(arcv), line_int_x, line_int_y); - coord_move_towards_coord_values(line_int_x, line_int_y, vx(arcv), vy(arcv), ms + d, &x, &y); - rewind_test: - wind1 = coord_wind(line_int_x, line_int_y, x, y, vx(parent), vy(parent)); - wind2 = coord_wind(line_int_x, line_int_y, x, y, vx(child), vy(child)); - if (wind1 && wind2 && wind1 == wind2) { -/* return -1.;*/ - if (windtests++ == 2) - return -1.; - - if (parent->flags & VERTEX_FLAG_ROUTE) - parent = parent->parent; - if (child->flags & VERTEX_FLAG_ROUTE) - child = child->child; - goto rewind_test; - } - } - - - *arcr = ms; - *arcwind = tvertex_wind(pathv->parent, pathv, arcv); - -#ifdef DEBUG_RUBBERBAND -/*if(debug) - printf("non-int check %f,%f ms %f d %f arcv %f,%f opv %f,%f\n", vx(arcv), vy(arcv), ms, d + ms, - vx(arcv), vy(arcv), vx(opv), vy(opv));*/ -#endif - - return d + ms; -} - -gdouble -check_intersect_vertex(gdouble x0, gdouble y0, gdouble x1, gdouble y1, toporouter_vertex_t * pathv, toporouter_vertex_t * arcv, - toporouter_vertex_t * opv, gint wind, gint * arcwind, gdouble * arcr, guint debug) -{ - gdouble ms, line_int_x, line_int_y, x, y, d = 0.; - - if (TOPOROUTER_IS_CONSTRAINT(pathv->routingedge)) { - gdouble d = tvdistance(tedge_v1(pathv->routingedge), tedge_v2(pathv->routingedge)) / 2.; - ms = min_spacing(pathv, arcv); - if (ms > d) - ms = d; - } - else { - ms = edge_min_spacing(g_list_find(edge_routing(pathv->routingedge), pathv), pathv->routingedge, arcv, debug); - } - - if (!vertex_line_normal_intersection(x0, y0, x1, y1, vx(arcv), vy(arcv), &line_int_x, &line_int_y)) - return -1.; - - d = coord_distance(line_int_x, line_int_y, vx(arcv), vy(arcv)); - - - if (d > ms - EPSILON) - return -1.; - - coord_move_towards_coord_values(vx(arcv), vy(arcv), line_int_x, line_int_y, ms, &x, &y); - - *arcr = ms; - *arcwind = tvertex_wind(pathv->parent, pathv, arcv); -/* *arcwind = coord_wind(x0, y0, x, y, x1, y1);*/ -#ifdef DEBUG_RUBBERBAND -/*if(debug) - printf("int check %f,%f ms %f d %f arcv %f,%f opv %f,%f\n", vx(arcv), vy(arcv), ms, ms - d, - vx(arcv), vy(arcv), vx(opv), vy(opv));*/ -#endif - - return ms - d; -} - -/* returns non-zero if arc has loops */ -guint check_arc_for_loops(gpointer t1, toporouter_arc_t * arc, gpointer t2) -{ - gdouble x0, y0, x1, y1; - - if (TOPOROUTER_IS_VERTEX(t1)) { - x0 = vx(TOPOROUTER_VERTEX(t1)); - y0 = vy(TOPOROUTER_VERTEX(t1)); - } - else { - x0 = TOPOROUTER_ARC(t1)->x1; - y0 = TOPOROUTER_ARC(t1)->y1; - } - - if (TOPOROUTER_IS_VERTEX(t2)) { - x1 = vx(TOPOROUTER_VERTEX(t2)); - y1 = vy(TOPOROUTER_VERTEX(t2)); - } - else { - x1 = TOPOROUTER_ARC(t2)->x0; - y1 = TOPOROUTER_ARC(t2)->y0; - } - - if (coord_intersect_prop(x0, y0, arc->x0, arc->y0, arc->x1, arc->y1, x1, y1)) { -/* || - (arc->x0 > arc->x1 - EPSILON && arc->x0 < arc->x1 + EPSILON && - arc->y0 > arc->y1 - EPSILON && arc->y0 < arc->y1 + EPSILON) - ) {*/ -#ifdef DEBUG_RUBBERBAND - printf("LOOPS %f %f -> %f %f & %f %f -> %f %f\n", x0, y0, arc->x0, arc->y0, arc->x1, arc->y1, x1, y1); -#endif - return 1; - } - return 0; -} - -toporouter_rubberband_arc_t *new_rubberband_arc(toporouter_vertex_t * pathv, toporouter_vertex_t * arcv, gdouble r, gdouble d, - gint wind, GList * list) -{ - toporouter_rubberband_arc_t *rba = (toporouter_rubberband_arc_t *) malloc(sizeof(toporouter_rubberband_arc_t)); - rba->pathv = pathv; - rba->arcv = arcv; - rba->r = r; - rba->d = d; - rba->wind = wind; - rba->list = list; - return rba; -} - -gint compare_rubberband_arcs(toporouter_rubberband_arc_t * a, toporouter_rubberband_arc_t * b) -{ - return b->d - a->d; -} - -void free_list_elements(gpointer data, gpointer user_data) -{ - free(data); -} - - -/* returns the edge opposite v from the triangle facing (x,y), or NULL if v is colinear with an edge between v and a neighbor */ -/* -GtsEdge * -vertex_edge_facing_vertex(GtsVertex *v, gdouble x, gdouble y) -{ - GSList *ts = gts_vertex_triangles(GTS_VERTEX(n), NULL); - GSList *i = ts; - - while(i) { - GtsTriangle *t = GTS_TRIANGLE(i->data); - GtsEdge *e = gts_triangle_edge_opposite(t, v); - - if(coord_wind(vx(edge_v1(e)), vy(edge_v1(e)), vx(v), vy(v), x, y) == vertex_wind(edge_v1(e), v, edge_v2(e)) && - coord_wind(vx(edge_v2(e)), vy(edge_v2(e)), vx(v), vy(v), x, y) == vertex_wind(edge_v2(e), v, edge_v1(e)) - ) { - g_slist_free(ts); - return e; - } - - i = i->next; - } - - g_slist_free(ts); - return NULL; -} -*/ - -gdouble -check_adj_pushing_vertex(toporouter_oproute_t * oproute, gdouble x0, gdouble y0, gdouble x1, gdouble y1, - toporouter_vertex_t * v, gdouble * arcr, gint * arcwind, toporouter_vertex_t ** arc) -{ - GSList *ns = gts_vertex_neighbors(GTS_VERTEX(v), NULL, NULL); - GSList *i = ns; - gdouble maxd = 0.; - - while (i) { - toporouter_vertex_t *n = TOPOROUTER_VERTEX(i->data); - gdouble segintx, seginty; - if (vertex_line_normal_intersection(x0, y0, x1, y1, vx(n), vy(n), &segintx, &seginty)) { - toporouter_edge_t *e = tedge(n, v); - gdouble ms = 0., d = coord_distance(segintx, seginty, vx(n), vy(n)); - /*toporouter_vertex_t *a; */ - toporouter_vertex_t *b; - GList *closestnet = NULL; - - g_assert(e); - - if (v == tedge_v1(e)) { - /*a = tedge_v1(e); */ - b = tedge_v2(e); - closestnet = edge_routing(e); - } - else { - /*a = tedge_v2(e); */ - b = tedge_v1(e); - closestnet = g_list_last(edge_routing(e)); - } - - if (closestnet) { - ms = edge_min_spacing(closestnet, e, b, 0); - ms += min_oproute_net_spacing(oproute, TOPOROUTER_VERTEX(closestnet->data)); - } - else { - ms = min_oproute_vertex_spacing(oproute, b); - } - - if (ms - d > maxd) { - *arcr = ms; - *arc = n; - maxd = ms - d; - if (vx(v) == x0 && vy(v) == y0) { - *arcwind = coord_wind(x0, y0, vx(n), vy(n), x1, y1); - } - else if (vx(v) == x1 && vy(v) == y1) { - *arcwind = coord_wind(x1, y1, vx(n), vy(n), x0, y0); - } - else { - fprintf(stderr, "ERROR: check_adj_pushing_vertex encountered bad vertex v (coordinates don't match)\n"); - } - } - } - - i = i->next; - } - - g_slist_free(ns); - return maxd; -} - - -/* path is t1 path*/ -GList *oproute_rubberband_segment(toporouter_t * r, toporouter_oproute_t * oproute, GList * path, gpointer t1, gpointer t2, - guint debug) -{ - gdouble x0, y0, x1, y1; - toporouter_vertex_t *v1, *v2, *av1, *av2; /* v{1,2} are the vertex terminals of the segment, or arc terminal centres */ - toporouter_arc_t *arc1 = NULL, *arc2 = NULL, *newarc = NULL; /* arc{1,2} are the arc terminals of the segment, if they exist */ - GList *i = path; - GList *list1, *list2; - - GList *arcs = NULL; - toporouter_rubberband_arc_t *max = NULL; - - gdouble d, arcr; - gint v1wind, v2wind, arcwind; - - if (TOPOROUTER_IS_VERTEX(t1)) { - v1 = TOPOROUTER_VERTEX(t1); - x0 = vx(v1); - y0 = vy(v1); - } - else { - g_assert(TOPOROUTER_IS_ARC(t1)); - arc1 = TOPOROUTER_ARC(t1); - v1 = TOPOROUTER_VERTEX(arc1->v1); - x0 = arc1->x1; - y0 = arc1->y1; - } - - if (TOPOROUTER_IS_VERTEX(t2)) { - v2 = TOPOROUTER_VERTEX(t2); - x1 = vx(v2); - y1 = vy(v2); - } - else { - g_assert(TOPOROUTER_IS_ARC(t2)); - arc2 = TOPOROUTER_ARC(t2); - v2 = TOPOROUTER_VERTEX(arc2->v2); - x1 = arc2->x0; - y1 = arc2->y0; - } - -#define TEST_AND_INSERT(z) if(d > EPSILON) arcs = g_list_prepend(arcs, new_rubberband_arc(v, z, arcr, d, arcwind, i)); -#define ARC_CHECKS(z) (!(arc1 && arc1->centre == z) && !(arc2 && arc2->centre == z) && \ - !(TOPOROUTER_IS_VERTEX(t1) && z == v1) && !(TOPOROUTER_IS_VERTEX(t2) && z == v2)) - - if (v1 == v2 || !i->next || TOPOROUTER_VERTEX(i->data) == v2) - return NULL; - -/*#ifdef DEBUG_RUBBERBAND*/ - if (debug) { - printf("\nRB: line %f,%f %f,%f v1 = %f,%f v2 = %f,%f \n ", x0, y0, x1, y1, vx(v1), vy(v1), vx(v2), vy(v2)); -/* if(v1->routingedge) print_edge(v1->routingedge); - if(v2->routingedge) print_edge(v2->routingedge);*/ - - } -/*#endif*/ - - /* check the vectices adjacent to the terminal vectices for push against the segment */ -/*if(TOPOROUTER_IS_VERTEX(t1)) { - toporouter_vertex_t *arcc = NULL; - d = check_adj_pushing_vertex(oproute, x0, y0, x1, y1, v1, &arcr, &arcwind, &arcc); - g_assert(arcc != v1); - if(ARC_CHECKS(arcc) && d > EPSILON) arcs = g_list_prepend(arcs, new_rubberband_arc(v1, arcc, arcr, d, arcwind, path->next)); - } - - if(TOPOROUTER_IS_VERTEX(t2)) { - toporouter_vertex_t *arcc = NULL; - d = check_adj_pushing_vertex(oproute, x0, y0, x1, y1, v2, &arcr, &arcwind, &arcc); - g_assert(arcc != v2); - if(ARC_CHECKS(arcc) && d > EPSILON) arcs = g_list_prepend(arcs, new_rubberband_arc(v2, arcc, arcr, d, arcwind, g_list_last(path)->prev)); - }*/ - - i = i->next; - while (i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); - - if (v == v2 || v == v1 || !v->routingedge) - break; - -#ifdef DEBUG_RUBBERBAND -/* if(debug) - printf("current v %f,%f - edge %f,%f %f,%f\n", vx(v), vy(v), - vx(tedge_v1(v->routingedge)), vy(tedge_v1(v->routingedge)), - vx(tedge_v2(v->routingedge)), vy(tedge_v2(v->routingedge)) - );*/ -#endif - g_assert(v->routingedge); - - v1wind = coord_wind(x0, y0, x1, y1, vx(tedge_v1(v->routingedge)), vy(tedge_v1(v->routingedge))); - v2wind = coord_wind(x0, y0, x1, y1, vx(tedge_v2(v->routingedge)), vy(tedge_v2(v->routingedge))); -/* if(debug) printf("\twinds: %d %d\n", v1wind, v2wind);*/ - if (!v1wind && !v2wind) { - i = i->next; - continue; - } - - - if (v1wind && v2wind && v1wind != v2wind) { /* edge is cutting through the current segment */ - - if (ARC_CHECKS(tedge_v1(v->routingedge))) { /* edge v1 is not the centre of an arc terminal */ - d = - check_intersect_vertex(x0, y0, x1, y1, v, tedge_v1(v->routingedge), tedge_v2(v->routingedge), v1wind, &arcwind, &arcr, - debug); - TEST_AND_INSERT(tedge_v1(v->routingedge)); - } - - if (ARC_CHECKS(tedge_v2(v->routingedge))) { /* edge v2 is not the centre of an arc terminal */ - d = - check_intersect_vertex(x0, y0, x1, y1, v, tedge_v2(v->routingedge), tedge_v1(v->routingedge), v2wind, &arcwind, &arcr, - debug); - TEST_AND_INSERT(tedge_v2(v->routingedge)); - } - } - else { /* edge is on one side of the segment */ - - if (ARC_CHECKS(tedge_v1(v->routingedge))) { /* edge v1 is not the centre of an arc terminal */ - d = - check_non_intersect_vertex(x0, y0, x1, y1, v, tedge_v1(v->routingedge), tedge_v2(v->routingedge), v1wind, &arcwind, - &arcr, debug); - TEST_AND_INSERT(tedge_v1(v->routingedge)); - } - - if (ARC_CHECKS(tedge_v2(v->routingedge))) { /* edge v2 is not the centre of an arc terminal */ - d = - check_non_intersect_vertex(x0, y0, x1, y1, v, tedge_v2(v->routingedge), tedge_v1(v->routingedge), v2wind, &arcwind, - &arcr, debug); - TEST_AND_INSERT(tedge_v2(v->routingedge)); - } - } - - i = i->next; - } - - arcs = g_list_sort(arcs, (GCompareFunc) compare_rubberband_arcs); -/*rubberband_insert_maxarc:*/ - if (!arcs) - return NULL; - max = TOPOROUTER_RUBBERBAND_ARC(arcs->data); - - av2 = max->pathv; - i = max->list->next; - while (i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); - if (v->routingedge && (tedge_v1(v->routingedge) == max->arcv || tedge_v2(v->routingedge) == max->arcv)) { - av2 = v; - i = i->next; - continue; - } - break; - } - - av1 = max->pathv; - i = max->list->prev; - while (i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); - if (v->routingedge && (tedge_v1(v->routingedge) == max->arcv || tedge_v2(v->routingedge) == max->arcv)) { - av1 = v; - i = i->prev; - continue; - } - break; - } -/*#ifdef DEBUG_RUBBERBAND*/ - if (debug) - printf("newarc @ %f,%f \t v1 = %f,%f v2 = %f,%f r = %f\n", vx(max->arcv), vy(max->arcv), vx(av1), vy(av1), vx(av2), vy(av2), - max->r); -/*#endif*/ - newarc = toporouter_arc_new(oproute, av1, av2, max->arcv, max->r, max->wind); - - if (TOPOROUTER_IS_VERTEX(t1)) - calculate_term_to_arc(TOPOROUTER_VERTEX(t1), newarc, 0); - else if (calculate_arc_to_arc(r, TOPOROUTER_ARC(t1), newarc)) { - printf("\tERROR: best: r = %f d = %f\n", max->r, max->d); - printf("\tOPROUTE: %s\n", oproute->netlist); - print_vertex(oproute->term1); - print_vertex(oproute->term2); - return NULL; - } - - if (TOPOROUTER_IS_VERTEX(t2)) - calculate_term_to_arc(TOPOROUTER_VERTEX(t2), newarc, 1); - else if (calculate_arc_to_arc(r, newarc, TOPOROUTER_ARC(t2))) { - printf("\tERROR: best: r = %f d = %f\n", max->r, max->d); - printf("\tOPROUTE: %s\n", oproute->netlist); - print_vertex(oproute->term1); - print_vertex(oproute->term2); - return NULL; - } - -/*if(check_arc_for_loops(t1, newarc, t2)) { - if(arc1 && arc2) calculate_arc_to_arc(r, arc1, arc2); - else if(arc1) calculate_term_to_arc(TOPOROUTER_VERTEX(t2), arc1, 1); - else if(arc2) calculate_term_to_arc(TOPOROUTER_VERTEX(t1), arc2, 0);*/ - -/*#ifdef DEBUG_RUBBERBAND - printf("REMOVING NEW ARC @ %f,%f\n", vx(newarc->centre), vy(newarc->centre)); - TODO: properly remove newarc - #endif*/ - -/* arcs = g_list_remove(arcs, max); - free(max); - goto rubberband_insert_maxarc; - }*/ - - - list1 = oproute_rubberband_segment(r, oproute, path, t1, newarc, debug); - list2 = oproute_rubberband_segment(r, oproute, i->next, newarc, t2, debug); - - if (list1) { - GList *list = g_list_last(list1); - toporouter_arc_t *testarc = TOPOROUTER_ARC(list->data); - toporouter_arc_t *parc = list->prev ? TOPOROUTER_ARC(list->prev->data) : arc1; - gdouble px = parc ? parc->x1 : vx(TOPOROUTER_VERTEX(t1)), py = parc ? parc->y1 : vy(TOPOROUTER_VERTEX(t1)); - - if (coord_intersect_prop(px, py, testarc->x0, testarc->y0, testarc->x1, testarc->y1, newarc->x0, newarc->y0)) { - list1 = g_list_remove(list1, testarc); - if (parc) - calculate_arc_to_arc(r, parc, newarc); - else - calculate_term_to_arc(TOPOROUTER_VERTEX(t1), newarc, 0); -/*#ifdef DEBUG_RUBBERBAND*/ - if (debug) - printf("REMOVING ARC @ %f,%f\n", vx(testarc->centre), vy(testarc->centre)); -/*#endif*/ - } - } - if (list2) { - toporouter_arc_t *testarc = TOPOROUTER_ARC(list2->data); - toporouter_arc_t *narc = list2->next ? TOPOROUTER_ARC(list2->next->data) : arc2; - gdouble nx = narc ? narc->x0 : vx(TOPOROUTER_VERTEX(t2)), ny = narc ? narc->y0 : vy(TOPOROUTER_VERTEX(t2)); - - if (coord_intersect_prop(newarc->x1, newarc->y1, testarc->x0, testarc->y0, testarc->x1, testarc->y1, nx, ny)) { - list2 = g_list_remove(list2, testarc); - if (narc) - calculate_arc_to_arc(r, newarc, narc); - else - calculate_term_to_arc(TOPOROUTER_VERTEX(t2), newarc, 1); - -/*#ifdef DEBUG_RUBBERBAND*/ - if (debug) - printf("REMOVING ARC @ %f,%f\n", vx(testarc->centre), vy(testarc->centre)); -/*#endif*/ - } - } - - g_list_foreach(arcs, free_list_elements, NULL); - g_list_free(arcs); - - return g_list_concat(list1, g_list_prepend(list2, newarc)); -} - -void oproute_check_all_loops(toporouter_t * r, toporouter_oproute_t * oproute) -{ - GList *i; - gpointer t1; - -loopcheck_restart: - t1 = oproute->term1; - i = oproute->arcs; - while (i) { - toporouter_arc_t *arc = TOPOROUTER_ARC(i->data); - gpointer t2 = i->next ? i->next->data : oproute->term2; - - if (check_arc_for_loops(t1, arc, t2)) { - - if (TOPOROUTER_IS_ARC(t1) && TOPOROUTER_IS_ARC(t2)) - calculate_arc_to_arc(r, TOPOROUTER_ARC(t1), TOPOROUTER_ARC(t2)); - else if (TOPOROUTER_IS_ARC(t1)) - calculate_term_to_arc(TOPOROUTER_VERTEX(t2), TOPOROUTER_ARC(t1), 1); - else if (TOPOROUTER_IS_ARC(t2)) - calculate_term_to_arc(TOPOROUTER_VERTEX(t1), TOPOROUTER_ARC(t2), 0); - - oproute->arcs = g_list_remove(oproute->arcs, arc); - goto loopcheck_restart; - } - - t1 = arc; - - i = i->next; - } - -} - -GtsTriangle *opposite_triangle(GtsTriangle * t, toporouter_edge_t * e) -{ - GSList *i = GTS_EDGE(e)->triangles; - - g_assert(e && t); - - while (i) { - if (GTS_TRIANGLE(i->data) != t) - return GTS_TRIANGLE(i->data); - i = i->next; - } - - return NULL; -} - - -void speccut_edge_routing_from_edge(GList * i, toporouter_edge_t * e) -{ - g_assert(TOPOROUTER_IS_EDGE(e)); - while (i) { - toporouter_vertex_t *curv = TOPOROUTER_VERTEX(i->data); - - if (!(curv->flags & VERTEX_FLAG_TEMP)) { - toporouter_vertex_t *newv = tvertex_intersect(curv, curv->parent, tedge_v1(e), tedge_v2(e)); - -/* printf("\nCURV:\n"); - print_vertex(curv); - - printf("CURV child:\n"); - if(curv->child) - print_vertex(curv->child); - else - printf("NULL\n"); - - printf("CURV parent:\n"); - if(curv->parent) - print_vertex(curv->parent); - else - printf("NULL\n");*/ - - if (newv) { - gint index; - newv->flags |= VERTEX_FLAG_ROUTE; - newv->flags |= VERTEX_FLAG_SPECCUT; - e->routing = g_list_insert_sorted_with_data(e->routing, newv, routing_edge_insert, e); - newv->route = curv->route; - newv->oproute = curv->oproute; - newv->routingedge = e; - GTS_POINT(newv)->z = vz(curv); - - newv->parent = curv->parent; - newv->child = curv; - -/* curv->parent = newv;*/ - - index = g_list_index(newv->route->path, curv); - - newv->route->path = g_list_insert(newv->route->path, newv, index); - - - if (newv->oproute) - newv->oproute->path = newv->route->path; - } - - if (!(curv->child->routingedge)) { - newv = tvertex_intersect(curv, curv->child, tedge_v1(e), tedge_v2(e)); - - if (newv) { - gint index; - newv->flags |= VERTEX_FLAG_ROUTE; - newv->flags |= VERTEX_FLAG_SPECCUT; - e->routing = g_list_insert_sorted_with_data(e->routing, newv, routing_edge_insert, e); - newv->route = curv->route; - newv->oproute = curv->oproute; - newv->routingedge = e; - GTS_POINT(newv)->z = vz(curv); - - newv->parent = curv; - newv->child = curv->child; - -/* curv->child = newv;*/ - - index = g_list_index(newv->route->path, curv); - - newv->route->path = g_list_insert(newv->route->path, newv, index + 1); - - - if (newv->oproute) - newv->oproute->path = newv->route->path; - } - - } - - } - i = i->next; - } - -} - -void speccut_edge_patch_links(toporouter_edge_t * e) -{ - GList *i = e->routing; - g_assert(TOPOROUTER_IS_EDGE(e)); - while (i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); - v->parent->child = v; - v->child->parent = v; - i = i->next; - } -} - -gint -check_speccut(toporouter_oproute_t * oproute, toporouter_vertex_t * v1, toporouter_vertex_t * v2, toporouter_edge_t * e, - toporouter_edge_t * e1, toporouter_edge_t * e2) -{ - GtsTriangle *t, *opt; - toporouter_vertex_t *opv, *opv2; - toporouter_edge_t *ope1, *ope2; - gdouble cap, flow, line_int_x, line_int_y; - - if (TOPOROUTER_IS_CONSTRAINT(e)) - return 0; - - if (!(t = gts_triangle_use_edges(GTS_EDGE(e), GTS_EDGE(e1), GTS_EDGE(e2)))) { - printf("check_speccut: NULL t\n"); - return 0; - } - - if (!(opt = opposite_triangle(t, e))) { -/* printf("check_speccut: NULL opt\n");*/ - return 0; - } - - if (!(opv = segment_common_vertex(GTS_SEGMENT(e1), GTS_SEGMENT(e2)))) { - printf("check_speccut: NULL opv\n"); - return 0; - } - - if (!(opv2 = TOPOROUTER_VERTEX(gts_triangle_vertex_opposite(opt, GTS_EDGE(e))))) { - printf("check_speccut: NULL opv2\n"); - return 0; - } - - /*TODO: shifting it out of the way would be better */ - if (e->routing) { - GList *i = e->routing; - while (i) { - toporouter_vertex_t *ev = TOPOROUTER_VERTEX(i->data); - if (!tvertex_wind(opv, ev, opv2)) - return 0; - i = i->next; - } - - } - - ope1 = tedge(opv2, tedge_v1(e)); - ope2 = tedge(opv2, tedge_v2(e)); - - /*this fixes the weird pad exits in r8c board - if(TOPOROUTER_IS_CONSTRAINT(ope1)) return 0; */ - if (TOPOROUTER_IS_CONSTRAINT(ope2)) - return 0; - - if (!tvertex_wind(opv2, tedge_v1(e), opv)) - return 0; - if (!tvertex_wind(opv2, tedge_v2(e), opv)) - return 0; - - if (!vertex_line_normal_intersection(vx(tedge_v1(e)), vy(tedge_v1(e)), - vx(tedge_v2(e)), vy(tedge_v2(e)), vx(opv2), vy(opv2), &line_int_x, &line_int_y)) - return 0; - - -/* return 0; - if(vertex_line_normal_intersection(tev1x(e), tev1y(e), tev2x(e), tev2y(e), vx(opv), vy(opv), &line_int_x, &line_int_y)) - return 0;*/ - - g_assert(opt && opv2); - - /* this is just temp, for the purposes of determining flow */ - if (tedge_v1(ope1) == opv2) { - if (TOPOROUTER_IS_CONSTRAINT(ope1)) - TOPOROUTER_CONSTRAINT(ope1)->routing = g_list_append(TOPOROUTER_CONSTRAINT(ope1)->routing, v1); - else - ope1->routing = g_list_append(ope1->routing, v1); - } - else { - if (TOPOROUTER_IS_CONSTRAINT(ope1)) - TOPOROUTER_CONSTRAINT(ope1)->routing = g_list_prepend(TOPOROUTER_CONSTRAINT(ope1)->routing, v1); - else - ope1->routing = g_list_prepend(ope1->routing, v1); - } - - cap = triangle_interior_capacity(opt, opv2); - flow = flow_from_edge_to_edge(opt, tedge(opv2, tedge_v1(e)), tedge(opv2, tedge_v2(e)), opv2, v1); - - /* temp v1 removed */ - if (TOPOROUTER_IS_CONSTRAINT(ope1)) - TOPOROUTER_CONSTRAINT(ope1)->routing = g_list_remove(TOPOROUTER_CONSTRAINT(ope1)->routing, v1); - else - ope1->routing = g_list_remove(ope1->routing, v1); - - if (flow >= cap) { - toporouter_edge_t *newe = - TOPOROUTER_EDGE(gts_edge_new(GTS_EDGE_CLASS(toporouter_edge_class()), GTS_VERTEX(opv), GTS_VERTEX(opv2))); - - speccut_edge_routing_from_edge(edge_routing(e1), newe); - speccut_edge_routing_from_edge(edge_routing(e2), newe); - speccut_edge_routing_from_edge(edge_routing(ope1), newe); - speccut_edge_routing_from_edge(edge_routing(ope2), newe); - - speccut_edge_patch_links(newe); -/* - printf("SPECCUT WITH v %f,%f for seg %f,%f %f,%f detected\n", vx(opv2), vy(opv2), - vx(v1), vy(v1), - vx(v2), vy(v2)); - printf("\tflow %f cap %f\n", flow, cap); - print_edge(newe); - */ - if (newe->routing) - return 1; - } - - - return 0; -} - - -gint oproute_path_speccut(toporouter_oproute_t * oproute) -{ - GList *i; - toporouter_vertex_t *pv; -path_speccut_restart: - i = oproute->path; - pv = NULL; - while (i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); - - - if (pv && (v->routingedge || pv->routingedge) && !(pv->flags & VERTEX_FLAG_SPECCUT) && !(v->flags & VERTEX_FLAG_SPECCUT)) { - - if (!v->routingedge) { - if (check_speccut - (oproute, pv, v, tedge(tedge_v1(pv->routingedge), v), pv->routingedge, tedge(tedge_v2(pv->routingedge), v))) - goto path_speccut_restart; - if (check_speccut - (oproute, pv, v, tedge(tedge_v2(pv->routingedge), v), pv->routingedge, tedge(tedge_v1(pv->routingedge), v))) - goto path_speccut_restart; - } - else if (!pv->routingedge) { - if (check_speccut - (oproute, v, pv, tedge(tedge_v1(v->routingedge), pv), v->routingedge, tedge(tedge_v2(v->routingedge), pv))) - goto path_speccut_restart; - if (check_speccut - (oproute, v, pv, tedge(tedge_v2(v->routingedge), pv), v->routingedge, tedge(tedge_v1(v->routingedge), pv))) - goto path_speccut_restart; - } - else { - toporouter_vertex_t *v1 = NULL, *v2 = NULL; - edges_third_edge(GTS_SEGMENT(v->routingedge), GTS_SEGMENT(pv->routingedge), &v1, &v2); - if (check_speccut(oproute, v, pv, tedge(v1, v2), v->routingedge, pv->routingedge)) - goto path_speccut_restart; - } - } - - - pv = v; - i = i->next; - } - - return 0; -} - -toporouter_oproute_t *oproute_rubberband(toporouter_t * r, GList * path) -{ - toporouter_oproute_t *oproute = (toporouter_oproute_t *) malloc(sizeof(toporouter_oproute_t)); - - g_assert(path); - - oproute->term1 = TOPOROUTER_VERTEX(path->data); - oproute->term2 = TOPOROUTER_VERTEX(g_list_last(path)->data); - oproute->arcs = NULL; - oproute->style = vertex_bbox(oproute->term1)->cluster->netlist->style; - oproute->netlist = vertex_bbox(oproute->term1)->cluster->netlist->netlist; - oproute->layergroup = vz(oproute->term1); - oproute->path = path; - oproute->serp = NULL; - - oproute->term1->parent = NULL; - oproute->term2->child = NULL; - - path_set_oproute(path, oproute); - -/* if(!strcmp(oproute->netlist, " unnamed_net1")) */ - oproute_path_speccut(oproute); - -#ifdef DEBUG_RUBBERBAND - if (!strcmp(oproute->netlist, " VCC3V3") && vx(oproute->term1) == 95700. && vy(oproute->term1) == 70800. && - vx(oproute->term2) == 196700. && vy(oproute->term2) == 67300.) { -/* printf("OPROUTE %s - %f,%f %f,%f\n", oproute->netlist, vx(oproute->term1), vy(oproute->term1), vx(oproute->term2), vy(oproute->term2)); - print_path(path);*/ - oproute->arcs = oproute_rubberband_segment(r, oproute, path, oproute->term1, oproute->term2, 1); - } - else -#endif - oproute->arcs = oproute_rubberband_segment(r, oproute, path, oproute->term1, oproute->term2, 0); - - oproute_check_all_loops(r, oproute); - return oproute; - -} - -void toporouter_export(toporouter_t * r) -{ - GList *i = r->routednets; - GList *oproutes = NULL; - - while (i) { - toporouter_route_t *routedata = TOPOROUTER_ROUTE(i->data); - toporouter_oproute_t *oproute = oproute_rubberband(r, routedata->path); - oproutes = g_list_prepend(oproutes, oproute); - i = i->next; - } - - i = oproutes; - while (i) { - toporouter_oproute_t *oproute = (toporouter_oproute_t *) i->data; - export_oproutes(r, oproute); - oproute_free(oproute); - i = i->next; - } - - pcb_message(PCB_MSG_INFO, _("Reticulating splines... successful\n\n")); - pcb_message(PCB_MSG_INFO, _("Wiring cost: %f inches\n"), r->wiring_score / 1000.); - printf("Wiring cost: %f inches\n", r->wiring_score / 1000.); - - g_list_free(oproutes); - -} - -toporouter_route_t *routedata_create(void) -{ - toporouter_route_t *routedata = (toporouter_route_t *) malloc(sizeof(toporouter_route_t)); - routedata->netlist = NULL; - routedata->alltemppoints = NULL; - routedata->path = NULL; - routedata->curpoint = NULL; - routedata->pscore = routedata->score = 0.; - routedata->flags = 0; - routedata->src = routedata->dest = NULL; - routedata->psrc = routedata->pdest = NULL; - routedata->ppath = routedata->topopath = NULL; - - routedata->ppathindices = NULL; - - routedata->destvertices = routedata->srcvertices = NULL; - return routedata; -} - -/* -void -print_routedata(toporouter_route_t *routedata) -{ - GList *srcvertices = cluster_vertices(routedata->src); - GList *destvertices = cluster_vertices(routedata->dest); - - printf("ROUTEDATA:\n"); - printf("SRCVERTICES:\n"); - print_vertices(srcvertices); - printf("DESTVERTICES:\n"); - print_vertices(destvertices); - - g_list_free(srcvertices); - g_list_free(destvertices); -}*/ - -toporouter_route_t *import_route(toporouter_t * r, pcb_rat_t * line) -{ - toporouter_route_t *routedata = routedata_create(); - - routedata->src = cluster_find(r, line->Point1.X, line->Point1.Y, line->group1); - routedata->dest = cluster_find(r, line->Point2.X, line->Point2.Y, line->group2); - - if (!routedata->src) - printf("couldn't locate src\n"); - if (!routedata->dest) - printf("couldn't locate dest\n"); - - if (!routedata->src || !routedata->dest) { - pcb_printf("PROBLEM: couldn't locate rat src or dest for rat %#mD, %d -> %#mD, %d\n", - line->Point1.X, line->Point1.Y, line->group1, line->Point2.X, line->Point2.Y, line->group2); - free(routedata); - return NULL; - } - - routedata->netlist = routedata->src->netlist; - - g_assert(routedata->src->netlist == routedata->dest->netlist); - - g_ptr_array_add(r->routes, routedata); - g_ptr_array_add(routedata->netlist->routes, routedata); - - r->failednets = g_list_prepend(r->failednets, routedata); - - return routedata; -} - -void delete_route(toporouter_route_t * routedata, guint destroy) -{ - GList *i = routedata->path; - toporouter_vertex_t *pv = NULL; - - while (i) { - toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data); - - g_assert(tv); - - if (tv && pv && !(tv->flags & VERTEX_FLAG_ROUTE) && !(pv->flags & VERTEX_FLAG_ROUTE)) { - toporouter_edge_t *e = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(tv), GTS_VERTEX(pv))); - - if (e && (e->flags & EDGE_FLAG_DIRECTCONNECTION)) { - e->flags ^= EDGE_FLAG_DIRECTCONNECTION; - } - } - pv = tv; - i = i->next; - } - - i = routedata->path; - while (i) { - toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data); - - tv->parent = NULL; - tv->child = NULL; - - if (tv->routingedge) { - if (TOPOROUTER_IS_CONSTRAINT(tv->routingedge)) - TOPOROUTER_CONSTRAINT(tv->routingedge)->routing = g_list_remove(TOPOROUTER_CONSTRAINT(tv->routingedge)->routing, tv); - else - tv->routingedge->routing = g_list_remove(tv->routingedge->routing, tv); - if (destroy) - gts_object_destroy(GTS_OBJECT(tv)); - } - - i = i->next; - } - - if (routedata->path) - g_list_free(routedata->path); - routedata->path = NULL; - routedata->curpoint = NULL; - routedata->score = INFINITY; - routedata->alltemppoints = NULL; -} - -/* remove route can be later reapplied */ -void remove_route(GList * path) -{ - GList *i = path; - - while (i) { - toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data); - - tv->parent = NULL; - tv->child = NULL; - -/* if(tv->flags & VERTEX_FLAG_ROUTE) g_assert(tv->route == routedata);*/ - - if (tv->routingedge) { - - if (TOPOROUTER_IS_CONSTRAINT(tv->routingedge)) - TOPOROUTER_CONSTRAINT(tv->routingedge)->routing = g_list_remove(TOPOROUTER_CONSTRAINT(tv->routingedge)->routing, tv); - else - tv->routingedge->routing = g_list_remove(tv->routingedge->routing, tv); - } - i = i->next; - } - -} - -gint apply_route(GList * path, toporouter_route_t * routedata) -{ - GList *i = path; - toporouter_vertex_t *pv = NULL; - gint count = 0; - - if (!path) - return 0; -/* g_assert(path);*/ - - while (i) { - toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data); - - if (tv->routingedge) { - if (TOPOROUTER_IS_CONSTRAINT(tv->routingedge)) - TOPOROUTER_CONSTRAINT(tv->routingedge)->routing = - g_list_insert_sorted_with_data(TOPOROUTER_CONSTRAINT(tv->routingedge)->routing, tv, routing_edge_insert, - tv->routingedge); - else - tv->routingedge->routing = g_list_insert_sorted_with_data(tv->routingedge->routing, - tv, routing_edge_insert, tv->routingedge); - - count++; - } - - if (pv) { - pv->child = tv; - tv->parent = pv; - } - - if (tv->flags & VERTEX_FLAG_ROUTE) - g_assert(tv->route == routedata); - - pv = tv; - i = i->next; - } - - TOPOROUTER_VERTEX(path->data)->parent = NULL; - pv->child = NULL; - - return count; -} - - -gint compare_routedata_ascending(gconstpointer a, gconstpointer b) -{ - toporouter_route_t *ra = (toporouter_route_t *) a; - toporouter_route_t *rb = (toporouter_route_t *) b; - return ra->score - rb->score; -} - -void print_costmatrix(gdouble * m, guint n) -{ - guint i; - printf("COST MATRIX:\n"); - for (i = 0; i < n; i++) { - guint j; - for (j = 0; j < n; j++) { - printf("%f ", m[(i * n) + j]); - } - printf("\n"); - } -} - - -static inline void init_cost_matrix(gdouble * m, guint n) -{ - guint i; - for (i = 0; i < n; i++) { - guint j; - for (j = 0; j < n; j++) { - m[(i * n) + j] = INFINITY; - } - } -} - - -toporouter_netscore_t *netscore_create(toporouter_t * r, toporouter_route_t * routedata, guint n, guint id) -{ - toporouter_netscore_t *netscore = (toporouter_netscore_t *) malloc(sizeof(toporouter_netscore_t)); - GList *path = route(r, routedata, 0); - guint i; - - netscore->id = id; - - netscore->routedata = routedata; - routedata->detourscore = netscore->score = routedata->score; - - if (!finite(routedata->detourscore)) { - printf("WARNING: !finite(detourscore)\n"); - print_cluster(routedata->src); - print_cluster(routedata->dest); - return NULL; - } - - netscore->pairwise_nodetour = (guint *) malloc(n * sizeof(guint)); - - for (i = 0; i < n; i++) { - netscore->pairwise_nodetour[i] = 0; - } - - netscore->pairwise_detour_sum = 0.; - netscore->pairwise_fails = 0; - - netscore->r = r; - - if (path) { - routedata->topopath = g_list_copy(routedata->path); - delete_route(routedata, 0); - } - - return netscore; -} - -static inline void netscore_destroy(toporouter_netscore_t * netscore) -{ - free(netscore->pairwise_nodetour); - free(netscore); -} - -void print_netscores(GPtrArray * netscores) -{ - toporouter_netscore_t **i; - printf("NETSCORES: \n\n"); - printf(" %15s %15s %15s\n----------------------------------------------------\n", "Score", "Detour Sum", - "Pairwise Fails"); - - for (i = (toporouter_netscore_t **) netscores->pdata; i < (toporouter_netscore_t **) netscores->pdata + netscores->len; i++) { -#ifdef DEBUG_NETSCORES - printf("%4d %15f %15f %15d %15x\n", (*i)->id, (*i)->score, (*i)->pairwise_detour_sum, (*i)->pairwise_fails, (guint) * i); -#endif - } - - printf("\n"); -} - -void netscore_pairwise_calculation(toporouter_netscore_t * netscore, GPtrArray * netscores) -{ - toporouter_netscore_t **i; - toporouter_netscore_t **netscores_base = (toporouter_netscore_t **) (netscores->pdata); - toporouter_route_t *temproutedata = routedata_create(); - - /*route(netscore->r, netscore->routedata, 0); */ - apply_route(netscore->routedata->topopath, netscore->routedata); - - for (i = netscores_base; i < netscores_base + netscores->len; i++) { - - if (!netscore->pairwise_nodetour[i - netscores_base] && *i != netscore - && (*i)->routedata->netlist != netscore->routedata->netlist) { - - temproutedata->src = (*i)->routedata->src; - temproutedata->dest = (*i)->routedata->dest; - - route(netscore->r, temproutedata, 0); - - if (temproutedata->score == (*i)->score) { - netscore->pairwise_nodetour[i - netscores_base] = 1; - (*i)->pairwise_nodetour[netscore->id] = 1; - } - else if (!finite(temproutedata->score)) { - netscore->pairwise_fails += 1; - } - else { - netscore->pairwise_detour_sum += temproutedata->score - (*i)->score; - } - - delete_route(temproutedata, 1); - } - - } - -/* delete_route(netscore->routedata, 1);*/ - remove_route(netscore->routedata->topopath); - - free(temproutedata); -} - -gint netscore_pairwise_size_compare(toporouter_netscore_t ** a, toporouter_netscore_t ** b) -{ - /* infinite scores are last */ - if (!finite((*a)->score) && !finite((*b)->score)) - return 0; - if (finite((*a)->score) && !finite((*b)->score)) - return -1; - if (finite((*b)->score) && !finite((*a)->score)) - return 1; - - /* order by pairwise fails */ - if ((*a)->pairwise_fails < (*b)->pairwise_fails) - return -1; - if ((*b)->pairwise_fails < (*a)->pairwise_fails) - return 1; - - /* order by pairwise detour */ - if ((*a)->pairwise_detour_sum < (*b)->pairwise_detour_sum) - return -1; - if ((*b)->pairwise_detour_sum < (*a)->pairwise_detour_sum) - return 1; - - /* order by score */ - if ((*a)->score < (*b)->score) - return -1; - if ((*b)->score < (*a)->score) - return 1; - - return 0; -} - -gint netscore_pairwise_compare(toporouter_netscore_t ** a, toporouter_netscore_t ** b) -{ - /* infinite scores are last */ - if (!finite((*a)->score) && !finite((*b)->score)) - return 0; - if (finite((*a)->score) && !finite((*b)->score)) - return -1; - if (finite((*b)->score) && !finite((*a)->score)) - return 1; - - /* order by pairwise fails */ - if ((*a)->pairwise_fails < (*b)->pairwise_fails) - return -1; - if ((*b)->pairwise_fails < (*a)->pairwise_fails) - return 1; - - /* order by pairwise detour */ - if ((*a)->pairwise_detour_sum < (*b)->pairwise_detour_sum) - return -1; - if ((*b)->pairwise_detour_sum < (*a)->pairwise_detour_sum) - return 1; - - return 0; -} - -guint order_nets_preroute_greedy(toporouter_t * r, GList * nets, GList ** rnets) -{ - gint len = g_list_length(nets); - GPtrArray *netscores = g_ptr_array_sized_new(len); - guint failcount = 0; - - while (nets) { - toporouter_netscore_t *ns = netscore_create(r, TOPOROUTER_ROUTE(nets->data), len, failcount++); - if (ns) - g_ptr_array_add(netscores, ns); - nets = nets->next; - } - - failcount = 0; - - g_ptr_array_foreach(netscores, (GFunc) netscore_pairwise_calculation, netscores); - - g_ptr_array_sort(netscores, (GCompareFunc) r->netsort); - -#ifdef DEBUG_ORDERING - print_netscores(netscores); -#endif - - *rnets = NULL; - FOREACH_NETSCORE(netscores) { - *rnets = g_list_prepend(*rnets, netscore->routedata); - if (!finite(netscore->score)) - failcount++; - netscore_destroy(netscore); - } - FOREACH_END; - - g_ptr_array_free(netscores, TRUE); - - return failcount; -} - -toporouter_vertex_t *edge_closest_vertex(toporouter_edge_t * e, toporouter_vertex_t * v) -{ - GList *i = v->routingedge ? edge_routing(v->routingedge) : NULL; - gdouble closestd = 0.; - toporouter_vertex_t *closestv = NULL; - - while (i) { - toporouter_vertex_t *ev = TOPOROUTER_VERTEX(i->data); - gdouble tempd = gts_point_distance2(GTS_POINT(ev), GTS_POINT(v)); - - if (!closestv || (tempd < closestd)) { - closestd = tempd; - closestv = ev; - } - - i = i->next; - } - - return closestv; -} - -void snapshot(toporouter_t * r, char *name, GList * datas) -{ - { - int i; - for (i = 0; i < groupcount(); i++) { - char buffer[256]; - sprintf(buffer, "route-%s-%d.png", name, i); - toporouter_draw_surface(r, r->layers[i].surface, buffer, 2048, 2048, 2, datas, i, NULL); - } - } -} - -/* -gdouble -route_conflict(toporouter_t *r, toporouter_route_t *route, guint *n) -{ - GList *i = route->path; - toporouter_vertex_t *pv = NULL; - gdouble cost = 0.; - - while(i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); - if(pv && vz(v) == vz(pv)) - cost += vertices_routing_conflict_cost(r, v, pv, n); - pv = v; - i = i->next; - } - - return cost; -} -*/ -GList *route_conflicts(toporouter_route_t * route) -{ - GList *conflicts = NULL, *i = route->path; - toporouter_vertex_t *pv = NULL; - - while (i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); - - if (pv && vz(pv) == vz(v)) { - GList *temp = vertices_routing_conflicts(pv, v), *j; - - j = temp; - while (j) { - toporouter_route_t *conroute = TOPOROUTER_ROUTE(j->data); - if (!g_list_find(conflicts, conroute)) - conflicts = g_list_prepend(conflicts, conroute); - j = j->next; - } - - if (temp) - g_list_free(temp); - } - - pv = v; - i = i->next; - } - return conflicts; -} - -gint spread_edge(gpointer item, gpointer data) -{ - toporouter_edge_t *e = TOPOROUTER_EDGE(item); - toporouter_vertex_t *v; - gdouble spacing, s; - GList *i; - - if (TOPOROUTER_IS_CONSTRAINT(e)) - return 0; - - i = edge_routing(e); - - if (!g_list_length(i)) - return 0; - - if (g_list_length(i) == 1) { - v = TOPOROUTER_VERTEX(i->data); - GTS_POINT(v)->x = (vx(edge_v1(e)) + vx(edge_v2(e))) / 2.; - GTS_POINT(v)->y = (vy(edge_v1(e)) + vy(edge_v2(e))) / 2.; - return 0; - } - - s = spacing = (gts_point_distance(GTS_POINT(edge_v1(e)), GTS_POINT(edge_v2(e)))) / (g_list_length(i) + 1); - - while (i) { - v = TOPOROUTER_VERTEX(i->data); - vertex_move_towards_vertex_values(edge_v1(e), edge_v2(e), s, &(GTS_POINT(v)->x), &(GTS_POINT(v)->y)); - - s += spacing; - i = i->next; - } - - return 0; -} - -void route_checkpoint(toporouter_route_t * route, toporouter_route_t * temproute) -{ - GList *i = g_list_last(route->path); - gint n = g_list_length(route->path); - - if (route->ppathindices) - free(route->ppathindices); - route->ppathindices = (gint *) malloc(sizeof(gint) * n); - -/* n = 0;*/ - while (i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); - n--; - - if (v->routingedge) { - GList *j = g_list_find(edge_routing(v->routingedge), v)->prev; - gint tempindex = g_list_index(edge_routing(v->routingedge), v); - - while (j) { - if (TOPOROUTER_VERTEX(j->data)->route == temproute) - tempindex--; - j = j->prev; - } - - route->ppathindices[n] = tempindex; - - if (TOPOROUTER_IS_CONSTRAINT(v->routingedge)) - TOPOROUTER_CONSTRAINT(v->routingedge)->routing = g_list_remove(TOPOROUTER_CONSTRAINT(v->routingedge)->routing, v); - else - v->routingedge->routing = g_list_remove(v->routingedge->routing, v); - } - - i = i->prev; - } - - route->pscore = route->score; - route->ppath = route->path; - remove_route(route->path); - route->path = NULL; - route->psrc = route->src; - route->pdest = route->dest; -/*route->src->pc = route->src->c; - route->dest->pc = route->dest->c;*/ -} - -void route_restore(toporouter_route_t * route) -{ - GList *i; - toporouter_vertex_t *pv = NULL; - gint n = 0; - - g_assert(route->ppath); - g_assert(route->ppathindices); - - route->path = route->ppath; - i = route->ppath; - while (i) { - toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); - - if (v->routingedge) { - if (TOPOROUTER_IS_CONSTRAINT(v->routingedge)) - TOPOROUTER_CONSTRAINT(v->routingedge)->routing = - g_list_insert(TOPOROUTER_CONSTRAINT(v->routingedge)->routing, v, route->ppathindices[n]); - else - v->routingedge->routing = g_list_insert(v->routingedge->routing, v, route->ppathindices[n]); - - /* space_edge(v->routingedge, NULL); */ - } - - if (pv) { - pv->child = v; - v->parent = pv; - } - - n++; - pv = v; - i = i->next; - } - - route->score = route->pscore; - route->src = route->psrc; - route->dest = route->pdest; -/*route->src->c = route->src->pc; - route->dest->c = route->dest->pc;*/ - -} - -void cluster_merge(toporouter_route_t * routedata) -{ - gint oldc = routedata->dest->c, newc = routedata->src->c; - - FOREACH_CLUSTER(routedata->netlist->clusters) { - if (cluster->c == oldc) - cluster->c = newc; - } - FOREACH_END; - -} - -void netlist_recalculate(toporouter_netlist_t * netlist, GList * ignore) -{ - GList *i = g_list_last(netlist->routed); - gint n = netlist->clusters->len - 1; - - FOREACH_CLUSTER(netlist->clusters) { - cluster->c = n--; - } FOREACH_END; - - while (i) { - if (!ignore || !g_list_find(ignore, i->data)) - cluster_merge(TOPOROUTER_ROUTE(i->data)); - i = i->prev; - } - -} - -void netlists_recalculate(GList * netlists, GList * ignore) -{ - GList *i = netlists; - while (i) { - netlist_recalculate(TOPOROUTER_NETLIST(i->data), ignore); - i = i->next; - } -} - -void netlists_rollback(GList * netlists) -{ -/* netlists_recalculate(netlists, NULL);*/ - while (netlists) { - toporouter_netlist_t *netlist = TOPOROUTER_NETLIST(netlists->data); - - FOREACH_CLUSTER(netlist->clusters) { - cluster->c = cluster->pc; - } - FOREACH_END; - - netlists = netlists->next; - } -} - -void print_netlist(toporouter_netlist_t * netlist) -{ - - printf("NETLIST %s: ", netlist->netlist); - - FOREACH_CLUSTER(netlist->clusters) { - printf("%d ", cluster->c); - - } FOREACH_END; - printf("\n"); -} - -#define REMOVE_ROUTING(x) x->netlist->routed = g_list_remove(x->netlist->routed, x); \ - r->routednets = g_list_remove(r->routednets, x); \ - r->failednets = g_list_prepend(r->failednets, x) - -#define INSERT_ROUTING(x) x->netlist->routed = g_list_prepend(x->netlist->routed, x); \ - r->routednets = g_list_prepend(r->routednets, x); \ - r->failednets = g_list_remove(r->failednets, x) - -gint roar_route(toporouter_t * r, toporouter_route_t * routedata, gint threshold) -{ - gint intfails = 0; - GList *netlists = NULL, *routed = NULL; - - g_assert(!routedata->path); - - if (routedata->src->c == routedata->dest->c) { - printf("ERROR: attempt to route already complete route\n"); - g_assert(routedata->src->c != routedata->dest->c); - } - - routedata->src->pc = routedata->src->c; - routedata->dest->pc = routedata->dest->c; - routedata->psrc = routedata->src; - routedata->pdest = routedata->dest; - - r->flags |= TOPOROUTER_FLAG_LEASTINVALID; - if (route(r, routedata, 0)) { - GList *conflicts, *j; - - INSERT_ROUTING(routedata); - - conflicts = route_conflicts(routedata); - cluster_merge(routedata); - - r->flags &= ~TOPOROUTER_FLAG_LEASTINVALID; - - j = conflicts; - while (j) { - toporouter_route_t *conflict = TOPOROUTER_ROUTE(j->data); - if (!g_list_find(netlists, conflict->netlist)) - netlists = g_list_prepend(netlists, conflict->netlist); - - route_checkpoint(conflict, routedata); - - REMOVE_ROUTING(conflict); - j = j->next; - } - - netlists = g_list_prepend(netlists, routedata->netlist); - netlists_recalculate(netlists, NULL); - - j = conflicts; - while (j) { - toporouter_route_t *conflict = TOPOROUTER_ROUTE(j->data); - g_assert(conflict->src->c != conflict->dest->c); - if (route(r, conflict, 0)) { - cluster_merge(conflict); - - routed = g_list_prepend(routed, conflict); - - INSERT_ROUTING(conflict); - - netlist_recalculate(conflict->netlist, NULL); - - } - else { - if (++intfails >= threshold) { - GList *i = routed; - while (i) { - toporouter_route_t *intconflict = TOPOROUTER_ROUTE(i->data); - REMOVE_ROUTING(intconflict); - delete_route(intconflict, 1); - i = i->next; - } - delete_route(routedata, 1); - i = g_list_last(conflicts); - while (i) { - toporouter_route_t *intconflict = TOPOROUTER_ROUTE(i->data); - - route_restore(intconflict); - INSERT_ROUTING(intconflict); - - i = i->prev; - } - REMOVE_ROUTING(routedata); - intfails = 0; - netlists_recalculate(netlists, NULL); - goto roar_route_end; - } - - } - j = j->next; - } - - - netlists_recalculate(netlists, NULL); - - intfails--; - roar_route_end: - g_list_free(conflicts); - g_list_free(netlists); - - } - else { - r->flags &= ~TOPOROUTER_FLAG_LEASTINVALID; - } - - g_list_free(routed); - return intfails; -} - -gint roar_router(toporouter_t * r, gint failcount, gint threshold) -{ - guint j; - gint pfailcount = failcount + 1; - - pcb_message(PCB_MSG_INFO, _("ROAR router: ")); - for (j = 0; j < 6; j++) { - GList *failed = g_list_copy(r->failednets), *k = failed; - - k = failed; - while (k) { - failcount += roar_route(r, TOPOROUTER_ROUTE(k->data), threshold); - k = k->next; - } - g_list_free(failed); - - printf("\tROAR pass %d - %d routed - %d failed\n", j, g_list_length(r->routednets), g_list_length(r->failednets)); - - if (!failcount || failcount >= pfailcount) { - pcb_message(PCB_MSG_INFO, _("%d nets remaining\n"), failcount); - break; - } - pcb_message(PCB_MSG_INFO, _("%d -> "), failcount); - pfailcount = failcount; - } - - return failcount; -} - -gint route_detour_compare(toporouter_route_t ** a, toporouter_route_t ** b) -{ - return ((*b)->score - (*b)->detourscore) - ((*a)->score - (*a)->detourscore); -} - - - -void roar_detour_route(toporouter_t * r, toporouter_route_t * data) -{ - gdouble pscore = data->score, nscore = 0.; - GList *netlists = NULL; - - route_checkpoint(data, NULL); - - REMOVE_ROUTING(data); - - netlists = g_list_prepend(NULL, data->netlist); - netlists_recalculate(netlists, NULL); - - r->flags |= TOPOROUTER_FLAG_LEASTINVALID; - if (route(r, data, 0)) { - GList *conflicts, *j; - - nscore = data->score; - conflicts = route_conflicts(data); - - INSERT_ROUTING(data); - - r->flags &= ~TOPOROUTER_FLAG_LEASTINVALID; - - j = conflicts; - while (j) { - toporouter_route_t *conflict = TOPOROUTER_ROUTE(j->data); - - if (!g_list_find(netlists, conflict->netlist)) - netlists = g_list_prepend(netlists, conflict->netlist); - pscore += conflict->score; - - route_checkpoint(conflict, NULL); - REMOVE_ROUTING(conflict); - - j = j->next; - } - netlists_recalculate(netlists, NULL); - - j = conflicts; - while (j) { - toporouter_route_t *conflict = TOPOROUTER_ROUTE(j->data); - - if (route(r, conflict, 0)) { - cluster_merge(conflict); - INSERT_ROUTING(conflict); - nscore += conflict->score; - } - else { - j = j->prev; - goto roar_detour_route_rollback_int; - } - j = j->next; - } - - if (nscore > pscore) { - j = g_list_last(conflicts); - roar_detour_route_rollback_int: - REMOVE_ROUTING(data); - - while (j) { - toporouter_route_t *conflict = TOPOROUTER_ROUTE(j->data); - REMOVE_ROUTING(conflict); - delete_route(conflict, 1); - j = j->prev; - } - - j = g_list_last(conflicts); - while (j) { - toporouter_route_t *conflict = TOPOROUTER_ROUTE(j->data); - route_restore(conflict); - INSERT_ROUTING(conflict); - j = j->prev; - } - delete_route(data, 1); - - goto roar_detour_route_rollback_exit; - - } - - g_list_free(conflicts); - } - else { - r->flags &= ~TOPOROUTER_FLAG_LEASTINVALID; - roar_detour_route_rollback_exit: - route_restore(data); - INSERT_ROUTING(data); - } - netlists_recalculate(netlists, NULL); - - g_list_free(netlists); -} - -void detour_router(toporouter_t * r) -{ - GList *i = r->routednets; - guint n = g_list_length(r->routednets); - GPtrArray *scores = g_ptr_array_sized_new(n); - - while (i) { - toporouter_route_t *curroute = TOPOROUTER_ROUTE(i->data); - curroute->score = path_score(r, curroute->path); - g_ptr_array_add(scores, i->data); - i = i->next; - } - - g_ptr_array_sort(scores, (GCompareFunc) route_detour_compare); - - r->flags |= TOPOROUTER_FLAG_DETOUR; - - { - toporouter_route_t **i; - for (i = (toporouter_route_t **) scores->pdata; i < (toporouter_route_t **) scores->pdata + scores->len; i++) { - toporouter_route_t *curroute = (*i); - - if (finite(curroute->score) && finite(curroute->detourscore)) { -/* printf("%15s %15f \t %8f,%8f - %8f,%8f\n", (*i)->src->netlist + 2, (*i)->score - (*i)->detourscore, - vx(curroute->mergebox1->point), vy(curroute->mergebox1->point), - vx(curroute->mergebox2->point), vy(curroute->mergebox2->point));*/ - - if (curroute->score - curroute->detourscore > 1000.) { - roar_detour_route(r, curroute); - } - else - break; - - } - } - } - printf("\n"); - - r->flags ^= TOPOROUTER_FLAG_DETOUR; - - g_ptr_array_free(scores, TRUE); - -} - -gint rubix_router(toporouter_t * r, gint failcount) -{ - GList *i, *ordering; - order_nets_preroute_greedy(r, r->failednets, &ordering); - - i = ordering; - while (i) { - toporouter_route_t *data = TOPOROUTER_ROUTE(i->data); - - if (route(r, data, 0)) { - INSERT_ROUTING(data); - cluster_merge(data); - failcount--; - } - - i = i->next; - } - - g_list_free(ordering); - - return failcount; -} - -guint hybrid_router(toporouter_t * r) -{ - guint i; - gint failcount = g_list_length(r->failednets); - r->flags |= TOPOROUTER_FLAG_AFTERORDER; - r->flags |= TOPOROUTER_FLAG_AFTERRUBIX; - failcount = rubix_router(r, failcount); - - pcb_message(PCB_MSG_INFO, _("RUBIX router: %d nets remaining\n"), failcount); - printf("RUBIX router: %d nets remaining\n", failcount); - - r->flags |= TOPOROUTER_FLAG_GOFAR; - - for (i = 0; i < 6 && failcount; i++) { - if (i % 2 == 1) { - failcount = roar_router(r, failcount, 5); - /* printf("THRESH 5\n"); */ - } - else { - failcount = roar_router(r, failcount, 2); - /* printf("THRESH 2\n"); */ - } - - detour_router(r); - } - - failcount = roar_router(r, failcount, 2); - detour_router(r); - - return failcount; -} - -void parse_arguments(toporouter_t * r, int argc, char **argv) -{ - int i, tempint; - guint group; - - for (i = 0; i < argc; i++) { - if (sscanf(argv[i], "viacost=%d", &tempint)) { - r->viacost = (double) tempint; - } - else if (sscanf(argv[i], "l%d", &tempint)) { - gdouble *layer = (gdouble *) malloc(sizeof(gdouble)); - *layer = (double) tempint; - r->keepoutlayers = g_list_prepend(r->keepoutlayers, layer); - } - } - - for (group = 0; group < pcb_max_group; group++) - for (i = 0; i < PCB->LayerGroups.Number[group]; i++) - pcb_layer_id_t lid = PCB->LayerGroups.Entries[group][i]; - flg = pcb_layer_flag(lid); - if ((lid & PCB_LYT_COPPER) && !(PCB->Data->Layer[lid].On)) { - gdouble *layer = (gdouble *) malloc(sizeof(gdouble)); - *layer = (double) group; - r->keepoutlayers = g_list_prepend(r->keepoutlayers, layer); - } - -} - -toporouter_t *toporouter_new(void) -{ - toporouter_t *r = (toporouter_t *) calloc(1, sizeof(toporouter_t)); - time_t ltime; - - gettimeofday(&r->starttime, NULL); - - r->netsort = netscore_pairwise_compare; - - r->destboxes = NULL; - r->consumeddestboxes = NULL; - - r->paths = NULL; - - r->layers = NULL; - r->flags = 0; - r->viamax = 3; - r->viacost = 10000.; - r->stublength = 300.; - r->serpintine_half_amplitude = 1500.; - - r->wiring_score = 0.; - - r->bboxes = NULL; - r->bboxtree = NULL; - - r->netlists = g_ptr_array_new(); - r->routes = g_ptr_array_new(); - - r->keepoutlayers = NULL; - - r->routednets = NULL; - r->failednets = NULL; - - ltime = time(NULL); - - gts_predicates_init(); - - pcb_message(PCB_MSG_INFO, _("Topological Autorouter\n")); - pcb_message(PCB_MSG_INFO, _("Started %s"), asctime(localtime(<ime))); - pcb_message(PCB_MSG_INFO, _("-------------------------------------\n")); - pcb_message(PCB_MSG_INFO, _("Copyright 2009 Anthony Blake (tonyb33@gmail.com)\n\n")); - return r; -} - -void acquire_twonets(toporouter_t * r) -{ - PCB_RAT_LOOP(PCB->Data); - if (PCB_FLAG_TEST(PCB_FLAG_SELECTED, line)) - import_route(r, line); - PCB_END_LOOP; - - if (!r->routes->len) { - PCB_RAT_LOOP(PCB->Data); - import_route(r, line); - PCB_END_LOOP; - } -} - -toporouter_netlist_t *find_netlist_by_name(toporouter_t * r, char *name) -{ - FOREACH_NETLIST(r->netlists) { - if (!strcmp(netlist->netlist, name)) - return netlist; - } - FOREACH_END; - return NULL; -} - -gint toporouter_set_pair(toporouter_t * r, toporouter_netlist_t * n1, toporouter_netlist_t * n2) -{ - if (!n1 || !n2) - return 0; - n1->pair = n2; - n2->pair = n1; - return 1; -} - -static int toporouter(int argc, char **argv, pcb_coord_t x, pcb_coord_t y) -{ - toporouter_t *r = toporouter_new(); - parse_arguments(r, argc, argv); - import_geometry(r); - acquire_twonets(r); - -/*if(!toporouter_set_pair(r, find_netlist_by_name(r, " DRAM_DQS_N"), find_netlist_by_name(r, " DRAM_DQS"))) { - printf("Couldn't associate pair\n"); - }*/ - - hybrid_router(r); -/* - for(gint i=0;ilayers[i].surface, space_edge, NULL); - } - { - int i; - for(i=0;ilayers[i].surface, buffer, 1024, 1024, 2, NULL, i, NULL); - } - } -*/ - toporouter_export(r); - toporouter_free(r); - - pcb_undo_save_serial(); - pcb_rats_destroy(pcb_false); - pcb_undo_restore_serial(); - pcb_rat_add_all(pcb_false, NULL); - pcb_undo_restore_serial(); - pcb_undo_inc_serial(); - pcb_redraw(); - - return 0; -} - -static int escape(int argc, char **argv, pcb_coord_t x, pcb_coord_t y) -{ - guint dir, viax, viay; - gdouble pitch, length, dx, dy; - - if (argc != 1) - return 0; - - dir = atoi(argv[0]); - - - PCB_PAD_ALL_LOOP(PCB->Data); - { - if (PCB_FLAG_TEST(PCB_FLAG_SELECTED, pad)) { - pcb_pin_t *via; - pcb_line_t *line; - - pcb_pad_t *pad0 = element->Pad->data; - pcb_pad_t *pad1 = g_list_next(element->Pad)->data; - - pitch = sqrt(pow(abs(pad0->Point1.X - pad1->Point1.X), 2) + pow(abs(pad0->Point1.Y - pad1->Point1.Y), 2)); - length = sqrt(pow(pitch, 2) + pow(pitch, 2)) / 2.; - - dx = length * sin(M_PI / 4.); - dy = length * cos(M_PI / 4.); - - switch (dir) { - case 1: - viax = pad->Point1.X - dx; - viay = pad->Point1.Y + dy; - break; - case 3: - viax = pad->Point1.X + dx; - viay = pad->Point1.Y + dy; - break; - case 9: - viax = pad->Point1.X + dx; - viay = pad->Point1.Y - dy; - break; - case 7: - viax = pad->Point1.X - dx; - viay = pad->Point1.Y - dy; - break; - case 2: - viax = pad->Point1.X; - viay = pad->Point1.Y + (pitch / 2); - break; - case 8: - viax = pad->Point1.X; - viay = pad->Point1.Y - (pitch / 2); - break; - case 4: - viax = pad->Point1.X - (pitch / 2); - viay = pad->Point1.Y; - break; - case 6: - viax = pad->Point1.X + (pitch / 2); - viay = pad->Point1.Y; - break; - default: - printf("ERROR: escape() with bad direction (%d)\n", dir); - return 1; - } - - if ((via = pcb_via_new(PCB->Data, viax, viay, - Settings.ViaThickness, 2 * Settings.Clearance, - 0, Settings.ViaDrillingHole, NULL, pcb_no_flags())) != NULL) { - pcb_undo_add_obj_to_create(PCB_TYPE_VIA, via, via, via); -/* if (gui->shift_is_pressed ()) - pcb_chg_obj_thermal(PCB_TYPE_VIA, via, via, via, PCB->ThermStyle);*/ - DrawVia(via); - if ((line = pcb_line_new_merge(CURRENT, pad->Point1.X + 1., pad->Point1.Y + 1., viax + 1., viay + 1., - Settings.LineThickness, 2 * Settings.Clearance, pcb_no_flags()))) { - - pcb_undo_add_obj_to_create(PCB_TYPE_LINE, CURRENT, line, line); - DrawLine(CURRENT, line); - - } - - } - - } - } - PCB_END_LOOP; - PCB_END_LOOP; - - pcb_undo_inc_serial(); - pcb_draw(); - return 0; -} - -static pcb_hid_action_t toporouter_action_list[] = { - {"Escape", "Select a set of pads", escape, "Pad escape", "Escape()"}, - {"Toporouter", "Select net(s)", toporouter, "Topological autorouter", "Toporouter()"} -}; - -PCB_REGISTER_ACTIONS(toporouter_action_list, toporouter_cookie) - -static void hid_toporouter_uninit(void) -{ - pcb_hid_remove_actions_by_cookie(toporouter_cookie); -} - -pcb_uninit_t hid_toporouter_init() -{ - register_toporouter_action_list(); - return hid_toporouter_uninit; -} Index: trunk/src_plugins/toporouter/Plug.tmpasm =================================================================== --- trunk/src_plugins/toporouter/Plug.tmpasm (revision 6802) +++ trunk/src_plugins/toporouter/Plug.tmpasm (nonexistent) @@ -1,28 +0,0 @@ -put /local/pcb/mod {toporouter} -put /local/pcb/mod/OBJS [@ $(PLUGDIR)/toporouter/toporouter.o @] - - -put /local/pcb/toporouter_rules [@ -../src_3rd/gts/libgts.a: - cd ../src_3rd/gts && make -@] - -switch /local/pcb/toporouter/controls - case {buildin} - append /local/pcb/CFLAGS {-I../src_3rd/gts} - append /local/pcb/RULES /local/pcb/toporouter_rules - append /local/pcb/LIBS { ../src_3rd/gts/libgts.a } - append /local/pcb/EXEDEPS { ../src_3rd/gts/libgts.a } - include /local/pcb/tmpasm/buildin - end; - case {plugin} - append /local/mod/CFLAGS {-I../src_3rd/gts} - append /local/pcb/RULES /local/pcb/toporouter_rules - append /local/pcb/toporouter/OBJS { ../src_3rd/gts/libgts.a } - include /local/pcb/tmpasm/plugin - end - case {disable} - put /local/pcb/mod/OBJS {} - include /local/pcb/tmpasm/disable - end -end Index: trunk/src_plugins/toporouter/toporouter.h =================================================================== --- trunk/src_plugins/toporouter/toporouter.h (revision 6802) +++ trunk/src_plugins/toporouter/toporouter.h (nonexistent) @@ -1,489 +0,0 @@ -/* - * COPYRIGHT - * - * Topological Autorouter for - * PCB, interactive printed circuit board design - * Copyright (C) 2009 Anthony Blake - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Contact addresses for email: - * Anthony Blake, tonyb33@gmail.com - * - */ - -#ifndef PCB_TOPOROUTER_H -#define PCB_TOPOROUTER_H - -#include -#include -#include "data.h" -#include "macro.h" -#include "../autoroute/autoroute.h" -#include "box.h" -#include "draw.h" -#include "error.h" -#include "find.h" -#include "heap.h" -#include "rtree.h" -#include "polygon.h" -#include "rats.h" -#include "remove.h" -#include "obj_pinvia_therm.h" -#include "undo.h" -#include "config.h" - -#include "gts.h" - -#include -#include - -#include - -#define TOPOROUTER_FLAG_VERBOSE (1<<0) -#define TOPOROUTER_FLAG_HARDDEST (1<<1) -#define TOPOROUTER_FLAG_HARDSRC (1<<2) -#define TOPOROUTER_FLAG_MATCH (1<<3) -#define TOPOROUTER_FLAG_LAYERHINT (1<<4) -#define TOPOROUTER_FLAG_LEASTINVALID (1<<5) -#define TOPOROUTER_FLAG_AFTERORDER (1<<6) -#define TOPOROUTER_FLAG_AFTERRUBIX (1<<7) -#define TOPOROUTER_FLAG_GOFAR (1<<8) -#define TOPOROUTER_FLAG_DETOUR (1<<9) - -/* Define to 1 to enable toporouter graphical output - wait, we don't link cairo?! */ -#define TOPO_OUTPUT_ENABLED 0 - - -#if TOPO_OUTPUT_ENABLED -#include -#endif - -#define EPSILON 0.0001f - -/*#define DEBUG_ROAR 1*/ - -#define coord_distance(a,b,c,d) sqrt(pow(a-c,2)+pow(b-d,2)) -#define coord_distance2(a,b,c,d) (pow(a-c,2)+pow(b-d,2)) - -#define tvdistance(a,b) sqrt(pow(vx(a)-vx(b),2)+pow(vy(a)-vy(b),2)) -#define tvdistance2(a,b) (pow(vx(a)-vx(b),2)+pow(vy(a)-vy(b),2)) - -#define edge_v1(e) (GTS_SEGMENT(e)->v1) -#define edge_v2(e) (GTS_SEGMENT(e)->v2) -#define tedge_v1(e) (TOPOROUTER_VERTEX(GTS_SEGMENT(e)->v1)) -#define tedge_v2(e) (TOPOROUTER_VERTEX(GTS_SEGMENT(e)->v2)) - -#define tedge(v1,v2) TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(v1), GTS_VERTEX(v2))) - -#define edge_routing(e) (TOPOROUTER_IS_CONSTRAINT(e) ? TOPOROUTER_CONSTRAINT(e)->routing : e->routing) -#define vrouting(v) (edge_routing(v->routingedge)) - -#define edge_routing_next(e,list) ((list->next) ? TOPOROUTER_VERTEX(list->next->data) : TOPOROUTER_VERTEX(edge_v2(e))) -#define edge_routing_prev(e,list) ((list->prev) ? TOPOROUTER_VERTEX(list->prev->data) : TOPOROUTER_VERTEX(edge_v1(e))) - -#define vx(v) (GTS_POINT(v)->x) -#define vy(v) (GTS_POINT(v)->y) -#define vz(v) (GTS_POINT(v)->z) - -#define close_enough_xy(a,b) (vx(a) > vx(b) - EPSILON && vx(a) < vx(b) + EPSILON && vy(a) > vy(b) - EPSILON && vy(a) < vy(b) + EPSILON) - -#define tev1x(e) (vx(tedge_v1(e)) -#define tev1y(e) (vy(tedge_v1(e)) -#define tev1z(e) (vz(tedge_v1(e)) -#define tev2x(e) (vx(tedge_v2(e)) -#define tev2y(e) (vy(tedge_v2(e)) -#define tev2z(e) (vz(tedge_v2(e)) - -#define tvertex_intersect(a,b,c,d) (TOPOROUTER_VERTEX(vertex_intersect(GTS_VERTEX(a),GTS_VERTEX(b),GTS_VERTEX(c),GTS_VERTEX(d)))) - -#define TOPOROUTER_IS_BBOX(obj) (gts_object_is_from_class (obj, toporouter_bbox_class ())) -#define TOPOROUTER_BBOX(obj) GTS_OBJECT_CAST (obj, toporouter_bbox_t, toporouter_bbox_class ()) -#define TOPOROUTER_BBOX_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass, toporouter_bbox_class_t, toporouter_bbox_class ()) - -typedef enum { - PAD, - PIN, - VIA, - ARC, - VIA_SHADOW, - LINE, - OTHER, - BOARD, - EXPANSION_AREA, - POLYGON, - TEMP -} toporouter_term_t; - -struct _toporouter_bbox_t { - GtsBBox b; - - toporouter_term_t type; - void *data; - int layer; - - GtsSurface *surface; - GtsTriangle *enclosing; - - GList *constraints; - GtsPoint *point, *realpoint; - -/* char *netlist, *style;*/ - - struct _toporouter_cluster_t *cluster; - -}; - -struct _toporouter_bbox_class_t { - GtsBBoxClass parent_class; -}; - -typedef struct _toporouter_bbox_t toporouter_bbox_t; -typedef struct _toporouter_bbox_class_t toporouter_bbox_class_t; - -#define TOPOROUTER_IS_EDGE(obj) (gts_object_is_from_class (obj, toporouter_edge_class ())) -#define TOPOROUTER_EDGE(obj) GTS_OBJECT_CAST (obj, toporouter_edge_t, toporouter_edge_class ()) -#define TOPOROUTER_EDGE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass, toporouter_edge_class_t, toporouter_edge_class ()) - -#define EDGE_FLAG_DIRECTCONNECTION (1<<0) - -struct _toporouter_edge_t { - GtsEdge e; - /*pcb_netlist_t *netlist; */ - - guint flags; - - GList *routing; -}; - -struct _toporouter_edge_class_t { - GtsEdgeClass parent_class; -}; - -typedef struct _toporouter_edge_t toporouter_edge_t; -typedef struct _toporouter_edge_class_t toporouter_edge_class_t; - -#define TOPOROUTER_IS_VERTEX(obj) (gts_object_is_from_class (obj, toporouter_vertex_class ())) -#define TOPOROUTER_VERTEX(obj) GTS_OBJECT_CAST (obj, toporouter_vertex_t, toporouter_vertex_class ()) -#define TOPOROUTER_VERTEX_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass, toporouter_vertex_class_t, toporouter_vertex_class ()) - -#define VERTEX_FLAG_VIZ (1<<1) -#define VERTEX_FLAG_CCW (1<<2) -#define VERTEX_FLAG_CW (1<<3) -#define VERTEX_FLAG_RED (1<<4) -#define VERTEX_FLAG_GREEN (1<<5) -#define VERTEX_FLAG_BLUE (1<<6) -#define VERTEX_FLAG_TEMP (1<<7) -#define VERTEX_FLAG_ROUTE (1<<8) -#define VERTEX_FLAG_FAKE (1<<10) -#define VERTEX_FLAG_SPECCUT (1<<11) - -struct _toporouter_vertex_t { - GtsVertex v; - /*GList *boxes; */ - struct _toporouter_bbox_t *bbox; - - struct _toporouter_vertex_t *parent; - struct _toporouter_vertex_t *child; - - toporouter_edge_t *routingedge; - - guint flags; - - gdouble gcost, hcost; - guint gn; - - struct _toporouter_arc_t *arc; - - struct _toporouter_oproute_t *oproute; - struct _toporouter_route_t *route; - - gdouble thickness; - -}; - -struct _toporouter_vertex_class_t { - GtsVertexClass parent_class; -}; - -typedef struct _toporouter_vertex_t toporouter_vertex_t; -typedef struct _toporouter_vertex_class_t toporouter_vertex_class_t; - -#define TOPOROUTER_IS_CONSTRAINT(obj) (gts_object_is_from_class (obj, toporouter_constraint_class ())) -#define TOPOROUTER_CONSTRAINT(obj) GTS_OBJECT_CAST (obj, toporouter_constraint_t, toporouter_constraint_class ()) -#define TOPOROUTER_CONSTRAINT_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass, toporouter_constraint_class_t, toporouter_constraint_class ()) - -struct _toporouter_constraint_t { - GtsConstraint c; - toporouter_bbox_t *box; - GList *routing; -}; - -struct _toporouter_constraint_class_t { - GtsConstraintClass parent_class; -}; - -typedef struct { - gdouble x, y; -} toporouter_spoint_t; - -typedef struct _toporouter_constraint_t toporouter_constraint_t; -typedef struct _toporouter_constraint_class_t toporouter_constraint_class_t; - -typedef struct { - GtsSurface *surface; -/* GtsTriangle *t;*/ -/* GtsVertex *v1, *v2, *v3;*/ - - GList *vertices; - GList *constraints; - GList *edges; - -} toporouter_layer_t; - -#define TOPOROUTER_VERTEX_REGION(x) ((toporouter_vertex_region_t *)x) -typedef struct { - - GList *points; - toporouter_vertex_t *v1, *v2; - toporouter_vertex_t *origin; - -} toporouter_vertex_region_t; - -struct _toporouter_rubberband_arc_t { - toporouter_vertex_t *pathv, *arcv; - gdouble r, d; - gint wind; - GList *list; -}; - -typedef struct _toporouter_rubberband_arc_t toporouter_rubberband_arc_t; -#define TOPOROUTER_RUBBERBAND_ARC(x) ((toporouter_rubberband_arc_t *)x) - -struct _toporouter_route_t { - - struct _toporouter_netlist_t *netlist; - - struct _toporouter_cluster_t *src, *dest; - struct _toporouter_cluster_t *psrc, *pdest; - - gdouble score, detourscore; - - toporouter_vertex_t *curpoint; - GHashTable *alltemppoints; - - GList *path; - - guint flags; - - GList *destvertices, *srcvertices; - - GList *topopath; - - gdouble pscore; - GList *ppath; - - gint *ppathindices; -}; - -typedef struct _toporouter_route_t toporouter_route_t; - -#define TOPOROUTER_ROUTE(x) ((toporouter_route_t *)x) - -struct _toporouter_netlist_t { - GPtrArray *clusters, *routes; - char *netlist, *style; - GList *routed; - - struct _toporouter_netlist_t *pair; -}; - -typedef struct _toporouter_netlist_t toporouter_netlist_t; - -#define TOPOROUTER_NETLIST(x) ((toporouter_netlist_t *)x) - -struct _toporouter_cluster_t { - gint c, pc; - GPtrArray *boxes; - toporouter_netlist_t *netlist; -}; - -typedef struct _toporouter_cluster_t toporouter_cluster_t; - -#define TOPOROUTER_CLUSTER(x) ((toporouter_cluster_t *)x) - -#define TOPOROUTER_OPROUTE(x) ((toporouter_oproute_t *)x) - -#define oproute_next(a,b) (b->next ? TOPOROUTER_ARC(b->next->data) : a->term2) -#define oproute_prev(a,b) (b->prev ? TOPOROUTER_ARC(b->prev->data) : a->term1) - -#define TOPOROUTER_SERPINTINE(x) ((toporouter_serpintine_t *)x) - -struct _toporouter_serpintine_t { - GList *arcs; - gdouble x, y; - gdouble x0, y0, x1, y1; - - gpointer start; - gdouble halfa, radius; - guint nhalfcycles; - -}; -typedef struct _toporouter_serpintine_t toporouter_serpintine_t; - -struct _toporouter_oproute_t { - GList *arcs; - toporouter_vertex_t *term1, *term2; - char *style; - char *netlist; - guint layergroup; - gdouble tof; - GList *path; - - toporouter_serpintine_t *serp; -}; - -typedef struct _toporouter_oproute_t toporouter_oproute_t; - - -#define TOPOROUTER_IS_ARC(obj) (gts_object_is_from_class (obj, toporouter_arc_class())) -#define TOPOROUTER_ARC(obj) GTS_OBJECT_CAST (obj, toporouter_arc_t, toporouter_arc_class()) -#define TOPOROUTER_ARC_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass, toporouter_arc_class_t, toporouter_arc_class()) - -struct _toporouter_arc_t { - GtsObject object; - - gdouble x0, y0, x1, y1; - toporouter_vertex_t *centre, *v; - gdouble r; - gint dir; - - GList *clearance; - - toporouter_oproute_t *oproute; - - toporouter_vertex_t *v1, *v2; -}; - -struct _toporouter_arc_class_t { - GtsObjectClass parent_class; - gboolean binary; -}; - -typedef struct _toporouter_arc_t toporouter_arc_t; -typedef struct _toporouter_arc_class_t toporouter_arc_class_t; - -typedef struct _toporouter_t toporouter_t; - - - -typedef struct { - guint id; - - guint *pairwise_nodetour; - gdouble pairwise_detour_sum; - gdouble score; - guint pairwise_fails; - - toporouter_route_t *routedata; - - toporouter_t *r; - -} toporouter_netscore_t; - -#define TOPOROUTER_NETSCORE(x) ((toporouter_netscore_t *)x) - -struct _toporouter_t { - GSList *bboxes; - GNode *bboxtree; - - toporouter_layer_t *layers; - - GList *paths; - - GList *keepoutlayers; - - guint flags; - - GList *destboxes, *consumeddestboxes; - - /* settings: */ - guint viamax; - gdouble viacost; - gdouble stublength; - gdouble serpintine_half_amplitude; - - gdouble wiring_score; - - GPtrArray *routes; - GPtrArray *netlists; - - GList *routednets, *failednets; - - gint(*netsort) (toporouter_netscore_t **, toporouter_netscore_t **); - - struct timeval starttime; - - FILE *debug; -}; - -typedef gint(*oproute_adjseg_func) - - (toporouter_t *, - GList **, GList **, guint *, gdouble, gdouble, gdouble, gdouble, toporouter_oproute_t *, toporouter_oproute_t *); - -typedef struct { -#ifdef CAIRO_H - cairo_t *cr; - cairo_surface_t *surface; -#endif - - double s; /* scale factor */ - - int mode; - void *data; - - char *filename; - double iw, ih; /* image dimensions */ -} drawing_context_t; - -#define FOREACH_CLUSTER(clusters) do { \ - toporouter_cluster_t **i; \ - for(i = ((toporouter_cluster_t **)clusters->pdata) + clusters->len - 1; i >= (toporouter_cluster_t **)clusters->pdata && clusters->len > 0; --i) { \ - toporouter_cluster_t *cluster = *i; - -#define FOREACH_BBOX(boxes) do { \ - toporouter_bbox_t **i; \ - for(i = ((toporouter_bbox_t **)boxes->pdata) + boxes->len - 1; i >= (toporouter_bbox_t **)boxes->pdata && boxes->len > 0; --i) { \ - toporouter_bbox_t *box = *i; - -#define FOREACH_ROUTE(routes) do { \ - toporouter_route_t **i; \ - for(i = ((toporouter_route_t **)routes->pdata) + routes->len - 1; i >= (toporouter_route_t **)routes->pdata && routes->len > 0; --i) { \ - toporouter_route_t *routedata = *i; - -#define FOREACH_NETSCORE(netscores) do { \ - toporouter_netscore_t **i; \ - for(i = ((toporouter_netscore_t **)netscores->pdata) + netscores->len - 1; i >= (toporouter_netscore_t **)netscores->pdata && netscores->len > 0; --i) { \ - toporouter_netscore_t *netscore = *i; - -#define FOREACH_NETLIST(netlists) do { \ - toporouter_netlist_t **i; \ - for(i = ((toporouter_netlist_t **)netlists->pdata) + netlists->len - 1; i >= (toporouter_netlist_t **)netlists->pdata && netlists->len > 0; --i) { \ - toporouter_netlist_t *netlist = *i; - -#define FOREACH_END }} while(0) - -#endif /* PCB_TOPOROUTER_H */ Index: trunk/src_plugins/toporouter/README =================================================================== --- trunk/src_plugins/toporouter/README (revision 6802) +++ trunk/src_plugins/toporouter/README (nonexistent) @@ -1,7 +0,0 @@ -Automatically route selected or all rats using a topological algorithm. This -is the new autorouter from 2009. - -#state: fails -#lstate: infinite loop in gts -#default: disabled -#implements: (feature) Index: trunk/src_plugins/toporouter/Makefile =================================================================== --- trunk/src_plugins/toporouter/Makefile (revision 6802) +++ trunk/src_plugins/toporouter/Makefile (nonexistent) @@ -1,6 +0,0 @@ -all: - cd ../../src && $(MAKE) mod_toporouter - -clean: - rm *.o *.so 2>/dev/null ; true - Index: work/obsolete/toporouter/src_3rd/gts/Makefile.dep =================================================================== --- work/obsolete/toporouter/src_3rd/gts/Makefile.dep (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/Makefile.dep (revision 6803) @@ -0,0 +1,36 @@ +### Generated file, do not edit, run make dep ### + +bbtree.o: bbtree.c gts.h +boolean.o: boolean.c gts.h +cdt.o: cdt.c ../../config.h gts.h +container.o: container.c gts.h +curvature.o: curvature.c gts.h +edge.o: edge.c gts.h +eheap.o: eheap.c gts.h +face.o: face.c gts.h +fifo.o: fifo.c gts.h +graph.o: graph.c gts.h +heap.o: heap.c gts.h +hsurface.o: hsurface.c gts.h +iso.o: iso.c gts.h +isotetra.o: isotetra.c gts.h +kdtree.o: kdtree.c gts.h +matrix.o: matrix.c gts.h +misc.o: misc.c gts.h gts-private.h ../../config.h +named.o: named.c gts.h +object.o: object.c gts.h gts-private.h +oocs.o: oocs.c gts.h +partition.o: partition.c gts.h +pgraph.o: pgraph.c gts.h +point.o: point.c gts.h gts-private.h predicates.h +predicates.o: predicates.c predicates.h rounding.h ../../config.h +psurface.o: psurface.c gts.h +refine.o: refine.c gts.h +segment.o: segment.c gts.h +split.o: split.c gts.h +stripe.o: stripe.c gts.h +surface.o: surface.c gts.h gts-private.h +triangle.o: triangle.c gts.h +tribox3.o: tribox3.c +vertex.o: vertex.c gts.h +vopt.o: vopt.c gts.h Index: work/obsolete/toporouter/src_3rd/gts/Makefile.in =================================================================== --- work/obsolete/toporouter/src_3rd/gts/Makefile.in (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/Makefile.in (revision 6803) @@ -0,0 +1,74 @@ +if /local/gts/enable +then +put /local/gts/CFLAGS [@-I. -I.. -I../.. -DG_LOG_DOMAIN=\"Gts\" @libs/sul/glib/cflags@@] +put /local/gts/OBJS [@ + object.o + point.o + vertex.o + segment.o + edge.o + triangle.o + face.o + kdtree.o + bbtree.o + misc.o + predicates.o + heap.o + eheap.o + fifo.o + matrix.o + surface.o + stripe.o + vopt.o + refine.o + iso.o + isotetra.o + split.o + psurface.o + hsurface.o + cdt.o + boolean.o + named.o + oocs.o + container.o + graph.o + pgraph.o + partition.o + curvature.o + tribox3.o +@] + +put /tmpasm/OFS { } +uniq /local/gts/OBJS +put /local/gts/SRCS /local/gts/OBJS +gsub /local/gts/SRCS {.o } {.c } + +print [@ +CFLAGS = @/local/gts/CFLAGS@ +OBJS = @/local/gts/OBJS@ +CC=@cc/cc@ + +libgts.a: $(OBJS) + @/host/fstools/ar@ rvu libgts.a $(OBJS) + +clean: + -@/host/fstools/rm@ $(OBJS) libgts.a +@] + +# generate explicit rules for .c -> .o +put /local/comp/OBJS /local/gts/OBJS +include {../../scconfig/Makefile.comp.inc} + +# generate deps +put /local/dep/CFLAGS /local/gts/CFLAGS +put /local/dep/SRCS /local/gts/SRCS +include {../../scconfig/Makefile.dep.inc} +else +print [@ +all: + +libgts.a: + +clean: +@] +end Index: work/obsolete/toporouter/src_3rd/gts/bbtree.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/bbtree.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/bbtree.c (revision 6803) @@ -0,0 +1,1289 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "gts.h" + +static void bbox_init (GtsBBox * bbox) +{ + bbox->bounded = NULL; +} + +/** + * gts_bbox_class: + * + * Returns: the #GtsBBoxClass. + */ +GtsBBoxClass * gts_bbox_class (void) +{ + static GtsBBoxClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo bbox_info = { + "GtsBBox", + sizeof (GtsBBox), + sizeof (GtsBBoxClass), + (GtsObjectClassInitFunc) NULL, + (GtsObjectInitFunc) bbox_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (gts_object_class (), &bbox_info); + } + + return klass; +} + +/** + * gts_bbox_set: + * @bbox: a #GtsBBox. + * @bounded: the object to be bounded. + * @x1: x-coordinate of the lower left corner. + * @y1: y-coordinate of the lower left corner. + * @z1: z-coordinate of the lower left corner. + * @x2: x-coordinate of the upper right corner. + * @y2: y-coordinate of the upper right corner. + * @z2: z-coordinate of the upper right corner. + * + * Sets fields of @bbox. + */ +void gts_bbox_set (GtsBBox * bbox, + gpointer bounded, + gdouble x1, gdouble y1, gdouble z1, + gdouble x2, gdouble y2, gdouble z2) +{ + g_return_if_fail (bbox != NULL); + g_return_if_fail (x2 >= x1 && y2 >= y1 && z2 >= z1); + + bbox->x1 = x1; bbox->y1 = y1; bbox->z1 = z1; + bbox->x2 = x2; bbox->y2 = y2; bbox->z2 = z2; + bbox->bounded = bounded; +} + +/** + * gts_bbox_new: + * @klass: a #GtsBBoxClass. + * @bounded: the object to be bounded. + * @x1: x-coordinate of the lower left corner. + * @y1: y-coordinate of the lower left corner. + * @z1: z-coordinate of the lower left corner. + * @x2: x-coordinate of the upper right corner. + * @y2: y-coordinate of the upper right corner. + * @z2: z-coordinate of the upper right corner. + * + * Returns: a new #GtsBBox. + */ +GtsBBox * gts_bbox_new (GtsBBoxClass * klass, + gpointer bounded, + gdouble x1, gdouble y1, gdouble z1, + gdouble x2, gdouble y2, gdouble z2) +{ + GtsBBox * bbox; + + g_return_val_if_fail (klass != NULL, NULL); + + bbox = GTS_BBOX (gts_object_new (GTS_OBJECT_CLASS (klass))); + gts_bbox_set (bbox, bounded, x1, y1, z1, x2, y2, z2); + return bbox; +} + +/** + * gts_bbox_triangle: + * @klass: a #GtsBBoxClass. + * @t: a #GtsTriangle. + * + * Returns: a new #GtsBBox bounding box of @t. + */ +GtsBBox * gts_bbox_triangle (GtsBBoxClass * klass, + GtsTriangle * t) +{ + GtsBBox * bbox; + GtsPoint * p; + + g_return_val_if_fail (t != NULL, NULL); + g_return_val_if_fail (klass != NULL, NULL); + + p = GTS_POINT (GTS_SEGMENT (t->e1)->v1); + bbox = gts_bbox_new (klass, t, p->x, p->y, p->z, p->x, p->y, p->z); + + p = GTS_POINT (GTS_SEGMENT (t->e1)->v2); + if (p->x > bbox->x2) bbox->x2 = p->x; + if (p->x < bbox->x1) bbox->x1 = p->x; + if (p->y > bbox->y2) bbox->y2 = p->y; + if (p->y < bbox->y1) bbox->y1 = p->y; + if (p->z > bbox->z2) bbox->z2 = p->z; + if (p->z < bbox->z1) bbox->z1 = p->z; + p = GTS_POINT (gts_triangle_vertex (t)); + if (p->x > bbox->x2) bbox->x2 = p->x; + if (p->x < bbox->x1) bbox->x1 = p->x; + if (p->y > bbox->y2) bbox->y2 = p->y; + if (p->y < bbox->y1) bbox->y1 = p->y; + if (p->z > bbox->z2) bbox->z2 = p->z; + if (p->z < bbox->z1) bbox->z1 = p->z; + + return bbox; +} + +/** + * gts_bbox_segment: + * @klass: a #GtsBBoxClass. + * @s: a #GtsSegment. + * + * Returns: a new #GtsBBox bounding box of @s. + */ +GtsBBox * gts_bbox_segment (GtsBBoxClass * klass, GtsSegment * s) +{ + GtsBBox * bbox; + GtsPoint * p1, * p2; + + g_return_val_if_fail (s != NULL, NULL); + g_return_val_if_fail (klass != NULL, NULL); + + bbox = gts_bbox_new (klass, s, 0., 0., 0., 0., 0., 0.); + + p1 = GTS_POINT (s->v1); + p2 = GTS_POINT (s->v2); + if (p1->x > p2->x) { + bbox->x2 = p1->x; bbox->x1 = p2->x; + } + else { + bbox->x1 = p1->x; bbox->x2 = p2->x; + } + if (p1->y > p2->y) { + bbox->y2 = p1->y; bbox->y1 = p2->y; + } + else { + bbox->y1 = p1->y; bbox->y2 = p2->y; + } + if (p1->z > p2->z) { + bbox->z2 = p1->z; bbox->z1 = p2->z; + } + else { + bbox->z1 = p1->z; bbox->z2 = p2->z; + } + + return bbox; +} + +static void bbox_foreach_vertex (GtsPoint * p, GtsBBox * bb) +{ + if (p->x < bb->x1) bb->x1 = p->x; + if (p->y < bb->y1) bb->y1 = p->y; + if (p->z < bb->z1) bb->z1 = p->z; + if (p->x > bb->x2) bb->x2 = p->x; + if (p->y > bb->y2) bb->y2 = p->y; + if (p->z > bb->z2) bb->z2 = p->z; +} + +/** + * gts_bbox_surface: + * @klass: a #GtsBBoxClass. + * @surface: a #GtsSurface. + * + * Returns: a new #GtsBBox bounding box of @surface. + */ +GtsBBox * gts_bbox_surface (GtsBBoxClass * klass, GtsSurface * surface) +{ + GtsBBox * bbox; + + g_return_val_if_fail (klass != NULL, NULL); + g_return_val_if_fail (surface != NULL, NULL); + + bbox = gts_bbox_new (klass, surface, 0., 0., 0., 0., 0., 0.); + bbox->x1 = bbox->y1 = bbox->z1 = G_MAXDOUBLE; + bbox->x2 = bbox->y2 = bbox->z2 = -G_MAXDOUBLE; + + gts_surface_foreach_vertex (surface, (GtsFunc) bbox_foreach_vertex, bbox); + + return bbox; +} + +/** + * gts_bbox_bboxes: + * @klass: a #GtsBBoxClass. + * @bboxes: a list of #GtsBBox. + * + * Returns: a new #GtsBBox bounding box of all the bounding boxes in + * @bboxes. + */ +GtsBBox * gts_bbox_bboxes (GtsBBoxClass * klass, GSList * bboxes) +{ + GtsBBox * bbox; + GtsBBox * bb; + + g_return_val_if_fail (bboxes != NULL, NULL); + g_return_val_if_fail (klass != NULL, NULL); + + bb = bboxes->data; + bbox = gts_bbox_new (klass, bboxes, + bb->x1, bb->y1, bb->z1, bb->x2, bb->y2, bb->z2); + bboxes = bboxes->next; + while (bboxes) { + bb = bboxes->data; + if (bb->x1 < bbox->x1) bbox->x1 = bb->x1; + if (bb->y1 < bbox->y1) bbox->y1 = bb->y1; + if (bb->z1 < bbox->z1) bbox->z1 = bb->z1; + if (bb->x2 > bbox->x2) bbox->x2 = bb->x2; + if (bb->y2 > bbox->y2) bbox->y2 = bb->y2; + if (bb->z2 > bbox->z2) bbox->z2 = bb->z2; + bboxes = bboxes->next; + } + + return bbox; +} + +/** + * gts_bbox_points: + * @klass: a #GtsBBoxClass. + * @points: a list of #GtsPoint. + * + * Returns: a new #GtsBBox bounding box of @points. + */ +GtsBBox * gts_bbox_points (GtsBBoxClass * klass, GSList * points) +{ + GtsPoint * p; + GtsBBox * bbox; + GSList * i; + + if (points == NULL) + return NULL; + + p = points->data; + bbox = gts_bbox_new (klass, points, p->x, p->y, p->z, p->x, p->y, p->z); + + i = points->next; + while (i) { + p = i->data; + if (p->x > bbox->x2) + bbox->x2 = p->x; + else if (p->x < bbox->x1) + bbox->x1 = p->x; + if (p->y > bbox->y2) + bbox->y2 = p->y; + else if (p->y < bbox->y1) + bbox->y1 = p->y; + if (p->z > bbox->z2) + bbox->z2 = p->z; + else if (p->z < bbox->z1) + bbox->z1 = p->z; + i = i->next; + } + + return bbox; +} + +/** + * gts_bboxes_are_overlapping: + * @bb1: a #GtsBBox. + * @bb2: a #GtsBBox. + * + * Returns: %TRUE if the bounding boxes @bb1 and @bb2 are overlapping + * (including just touching), %FALSE otherwise. + */ +gboolean gts_bboxes_are_overlapping (GtsBBox * bb1, GtsBBox * bb2) +{ + if (bb1 == bb2) + return TRUE; + if (bb1->x1 > bb2->x2) + return FALSE; + if (bb2->x1 > bb1->x2) + return FALSE; + if (bb1->y1 > bb2->y2) + return FALSE; + if (bb2->y1 > bb1->y2) + return FALSE; + if (bb1->z1 > bb2->z2) + return FALSE; + if (bb2->z1 > bb1->z2) + return FALSE; + return TRUE; +} + +#define bbox_volume(bb) (((bb)->x2 -\ + (bb)->x1)*\ + ((bb)->y2 -\ + (bb)->y1)*\ + ((bb)->z2 -\ + (bb)->z1)) + +/** + * gts_bbox_diagonal2: + * @bb: a #GtsBBox. + * + * Returns: the squared length of the diagonal of @bb. + */ +gdouble gts_bbox_diagonal2 (GtsBBox * bb) +{ + gdouble x, y, z; + + g_return_val_if_fail (bb != NULL, 0.); + + x = bb->x2 - bb->x1; + y = bb->y2 - bb->y1; + z = bb->z2 - bb->z1; + + return x*x + y*y + z*z; +} + +/** + * gts_bbox_draw: + * @bb: a #GtsBBox. + * @fptr: a file pointer. + * + * Writes in file @fptr an OOGL (Geomview) description of @bb. + */ +void gts_bbox_draw (GtsBBox * bb, FILE * fptr) +{ + g_return_if_fail (bb != NULL); + + fprintf (fptr, "OFF 8 6 12\n"); + fprintf (fptr, "%g %g %g\n", + bb->x1, bb->y1, bb->z1); + fprintf (fptr, "%g %g %g\n", + bb->x2, bb->y1, bb->z1); + fprintf (fptr, "%g %g %g\n", + bb->x2, bb->y2, bb->z1); + fprintf (fptr, "%g %g %g\n", + bb->x1, bb->y2, bb->z1); + fprintf (fptr, "%g %g %g\n", + bb->x1, bb->y1, bb->z2); + fprintf (fptr, "%g %g %g\n", + bb->x2, bb->y1, bb->z2); + fprintf (fptr, "%g %g %g\n", + bb->x2, bb->y2, bb->z2); + fprintf (fptr, "%g %g %g\n", + bb->x1, bb->y2, bb->z2); + fputs ("4 3 2 1 0\n" + "4 4 5 6 7\n" + "4 2 3 7 6\n" + "4 0 1 5 4\n" + "4 0 4 7 3\n" + "4 1 2 6 5\n", + fptr); +} + +#define MINMAX(x1, x2, xmin, xmax) { if (x1 < x2) { xmin = x1; xmax = x2; }\ + else { xmin = x2; xmax = x1; } } + +/** + * gts_bbox_point_distance2: + * @bb: a #GtsBBox. + * @p: a #GtsPoint. + * @min: a pointer on a gdouble. + * @max: a pointer on a gdouble. + * + * Sets @min and @max to lower and upper bounds for the square of the + * Euclidean distance between the object contained in @bb and @p. For these + * bounds to make any sense the bounding box must be "tight" i.e. each of the + * 6 faces of the box must at least be touched by one point of the bounded + * object. + */ +void gts_bbox_point_distance2 (GtsBBox * bb, GtsPoint * p, + gdouble * min, gdouble * max) +{ + gdouble x1, y1, z1, x2, y2, z2, x, y, z; + gdouble dmin, dmax, xd1, xd2, yd1, yd2, zd1, zd2; + gdouble mx, Mx, my, My, mz, Mz; + + g_return_if_fail (bb != NULL); + g_return_if_fail (p != NULL); + g_return_if_fail (min != NULL); + g_return_if_fail (max != NULL); + + x1 = bb->x1; y1 = bb->y1; z1 = bb->z1; + x2 = bb->x2; y2 = bb->y2; z2 = bb->z2; + x = p->x; y = p->y; z = p->z; + + xd1 = (x1 - x)*(x1 - x); + xd2 = (x - x2)*(x - x2); + yd1 = (y1 - y)*(y1 - y); + yd2 = (y - y2)*(y - y2); + zd1 = (z1 - z)*(z1 - z); + zd2 = (z - z2)*(z - z2); + + dmin = x < x1 ? xd1 : x > x2 ? xd2 : 0.0; + dmin += y < y1 ? yd1 : y > y2 ? yd2 : 0.0; + dmin += z < z1 ? zd1 : z > z2 ? zd2 : 0.0; + + MINMAX (xd1, xd2, mx, Mx); + MINMAX (yd1, yd2, my, My); + MINMAX (zd1, zd2, mz, Mz); + + dmax = mx + My + Mz; + dmax = MIN (dmax, Mx + my + Mz); + dmax = MIN (dmax, Mx + My + mz); + + *min = dmin; + *max = dmax; +} + +/** + * gts_bbox_is_stabbed: + * @bb: a #GtsBBox. + * @p: a #GtsPoint. + * + * Returns: %TRUE if the ray starting at @p and ending at (+infty, + * @p->y, @p->z) intersects with @bb, %FALSE otherwise. + */ +gboolean gts_bbox_is_stabbed (GtsBBox * bb, GtsPoint * p) +{ + g_return_val_if_fail (bb != NULL, FALSE); + g_return_val_if_fail (p != NULL, FALSE); + + if (p->x > bb->x2 || + p->y < bb->y1 || p->y > bb->y2 || + p->z < bb->z1 || p->z > bb->z2) + return FALSE; + return TRUE; +} + +extern int triBoxOverlap (double boxcenter[3], + double boxhalfsize[3], + double triverts[3][3]); + +/** + * gts_bbox_overlaps_triangle: + * @bb: a #GtsBBox. + * @t: a #GtsTriangle. + * + * This is a wrapper around the fast overlap test of Tomas + * Akenine-Moller (http://www.cs.lth.se/home/Tomas_Akenine_Moller/). + * + * Returns: %TRUE if @bb overlaps with @t, %FALSE otherwise. + */ +gboolean gts_bbox_overlaps_triangle (GtsBBox * bb, GtsTriangle * t) +{ + double bc[3], bh[3], tv[3][3]; + GtsPoint * p1, * p2, * p3; + + g_return_val_if_fail (bb != NULL, FALSE); + g_return_val_if_fail (t != NULL, FALSE); + + bc[0] = (bb->x2 + bb->x1)/2.; + bh[0] = (bb->x2 - bb->x1)/2.; + bc[1] = (bb->y2 + bb->y1)/2.; + bh[1] = (bb->y2 - bb->y1)/2.; + bc[2] = (bb->z2 + bb->z1)/2.; + bh[2] = (bb->z2 - bb->z1)/2.; + p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1); + p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); + p3 = GTS_POINT (gts_triangle_vertex (t)); + tv[0][0] = p1->x; tv[0][1] = p1->y; tv[0][2] = p1->z; + tv[1][0] = p2->x; tv[1][1] = p2->y; tv[1][2] = p2->z; + tv[2][0] = p3->x; tv[2][1] = p3->y; tv[2][2] = p3->z; + + return triBoxOverlap (bc, bh, tv); +} + +/** + * gts_bbox_overlaps_segment: + * @bb: a #GtsBBox. + * @s: a #GtsSegment. + * + * This functions uses gts_bbox_overlaps_triangle() with a degenerate + * triangle. + * + * Returns: %TRUE if @bb overlaps with @s, %FALSE otherwise. + */ +gboolean gts_bbox_overlaps_segment (GtsBBox * bb, GtsSegment * s) +{ + double bc[3], bh[3], tv[3][3]; + GtsPoint * p1, * p2, * p3; + + g_return_val_if_fail (bb != NULL, FALSE); + g_return_val_if_fail (s != NULL, FALSE); + + bc[0] = (bb->x2 + bb->x1)/2.; + bh[0] = (bb->x2 - bb->x1)/2.; + bc[1] = (bb->y2 + bb->y1)/2.; + bh[1] = (bb->y2 - bb->y1)/2.; + bc[2] = (bb->z2 + bb->z1)/2.; + bh[2] = (bb->z2 - bb->z1)/2.; + p1 = GTS_POINT (s->v1); + p2 = GTS_POINT (s->v2); + p3 = p1; + tv[0][0] = p1->x; tv[0][1] = p1->y; tv[0][2] = p1->z; + tv[1][0] = p2->x; tv[1][1] = p2->y; tv[1][2] = p2->z; + tv[2][0] = p3->x; tv[2][1] = p3->y; tv[2][2] = p3->z; + + return triBoxOverlap (bc, bh, tv); +} + +/** + * gts_bb_tree_new: + * @bboxes: a list of #GtsBBox. + * + * Builds a new hierarchy of bounding boxes for @bboxes. At each + * level, the GNode->data field contains a #GtsBBox bounding box of + * all the children. The tree is binary and is built by repeatedly + * cutting in two approximately equal halves the bounding boxes at + * each level until a leaf node (i.e. a bounding box given in @bboxes) + * is reached. In order to minimize the depth of the tree, the cutting + * direction is always chosen as perpendicular to the longest + * dimension of the bounding box. + * + * Returns: a new hierarchy of bounding boxes. + */ +GNode * gts_bb_tree_new (GSList * bboxes) +{ + GSList * i, * positive = NULL, * negative = NULL; + GNode * node; + GtsBBox * bbox; + guint dir, np = 0, nn = 0; + gdouble * p1, * p2; + gdouble cut; + + g_return_val_if_fail (bboxes != NULL, NULL); + + if (bboxes->next == NULL) /* leaf node */ + return g_node_new (bboxes->data); + + bbox = gts_bbox_bboxes (gts_bbox_class (), bboxes); + node = g_node_new (bbox); + + if (bbox->x2 - bbox->x1 > bbox->y2 - bbox->y1) { + if (bbox->z2 - bbox->z1 > bbox->x2 - bbox->x1) + dir = 2; + else + dir = 0; + } + else if (bbox->z2 - bbox->z1 > bbox->y2 - bbox->y1) + dir = 2; + else + dir = 1; + + p1 = (gdouble *) &bbox->x1; + p2 = (gdouble *) &bbox->x2; + cut = (p1[dir] + p2[dir])/2.; + i = bboxes; + while (i) { + bbox = i->data; + p1 = (gdouble *) &bbox->x1; + p2 = (gdouble *) &bbox->x2; + if ((p1[dir] + p2[dir])/2. > cut) { + positive = g_slist_prepend (positive, bbox); + np++; + } + else { + negative = g_slist_prepend (negative, bbox); + nn++; + } + i = i->next; + } + if (!positive) { + GSList * last = g_slist_nth (negative, (nn - 1)/2); + positive = last->next; + last->next = NULL; + } + else if (!negative) { + GSList * last = g_slist_nth (positive, (np - 1)/2); + negative = last->next; + last->next = NULL; + } + g_node_prepend (node, gts_bb_tree_new (positive)); + g_slist_free (positive); + g_node_prepend (node, gts_bb_tree_new (negative)); + g_slist_free (negative); + + return node; +} + +static void prepend_triangle_bbox (GtsTriangle * t, GSList ** bboxes) +{ + *bboxes = g_slist_prepend (*bboxes, + gts_bbox_triangle (gts_bbox_class (), t)); +} + +/** + * gts_bb_tree_surface: + * @s: a #GtsSurface. + * + * Returns: a new hierarchy of bounding boxes bounding the faces of @s. + */ +GNode * gts_bb_tree_surface (GtsSurface * s) +{ + GSList * bboxes = NULL; + GNode * tree; + + g_return_val_if_fail (s != NULL, NULL); + + gts_surface_foreach_face (s, (GtsFunc) prepend_triangle_bbox, &bboxes); + tree = gts_bb_tree_new (bboxes); + g_slist_free (bboxes); + + return tree; +} + +/** + * gts_bb_tree_stabbed: + * @tree: a bounding box tree. + * @p: a #GtsPoint. + * + * Returns: a list of bounding boxes, leaves of @tree which are + * stabbed by the ray defined by @p (see gts_bbox_is_stabbed()). + */ +GSList * gts_bb_tree_stabbed (GNode * tree, GtsPoint * p) +{ + GSList * list = NULL; + GtsBBox * bb; + GNode * i; + + g_return_val_if_fail (tree != NULL, NULL); + g_return_val_if_fail (p != NULL, NULL); + + bb = tree->data; + if (!gts_bbox_is_stabbed (bb, p)) + return NULL; + if (tree->children == NULL) /* leaf node */ + return g_slist_prepend (NULL, bb); + i = tree->children; + while (i) { + list = g_slist_concat (list, gts_bb_tree_stabbed (i, p)); + i = i->next; + } + return list; +} + +/** + * gts_bb_tree_overlap: + * @tree: a bounding box tree. + * @bbox: a #GtsBBox. + * + * Returns: a list of bounding boxes, leaves of @tree which overlap @bbox. + */ +GSList * gts_bb_tree_overlap (GNode * tree, GtsBBox * bbox) +{ + GSList * list = NULL; + GtsBBox * bb; + GNode * i; + + g_return_val_if_fail (tree != NULL, NULL); + g_return_val_if_fail (bbox != NULL, NULL); + + bb = tree->data; + if (!gts_bboxes_are_overlapping (bbox, bb)) + return NULL; + if (tree->children == NULL) /* leaf node */ + return g_slist_prepend (NULL, bb); + i = tree->children; + while (i) { + list = g_slist_concat (list, gts_bb_tree_overlap (i, bbox)); + i = i->next; + } + return list; +} + +/** + * gts_bb_tree_is_overlapping: + * @tree: a bounding box tree. + * @bbox: a #GtsBBox. + * + * Returns: %TRUE if any leaf of @tree overlaps @bbox, %FALSE otherwise. + */ +gboolean gts_bb_tree_is_overlapping (GNode * tree, GtsBBox * bbox) +{ + GtsBBox * bb; + GNode * i; + + g_return_val_if_fail (tree != NULL, FALSE); + g_return_val_if_fail (bbox != NULL, FALSE); + + bb = tree->data; + if (!gts_bboxes_are_overlapping (bbox, bb)) + return FALSE; + if (tree->children == NULL) /* leaf node */ + return TRUE; + i = tree->children; + while (i) { + if (gts_bb_tree_is_overlapping (i, bbox)) + return TRUE; + i = i->next; + } + return FALSE; +} + +/** + * gts_bb_tree_traverse_overlapping: + * @tree1: a bounding box tree. + * @tree2: a bounding box tree. + * @func: a #GtsBBTreeTraverseFunc. + * @data: user data to be passed to @func. + * + * Calls @func for each overlapping pair of leaves of @tree1 and @tree2. + */ +void gts_bb_tree_traverse_overlapping (GNode * tree1, GNode * tree2, + GtsBBTreeTraverseFunc func, + gpointer data) +{ + GtsBBox * bb1, * bb2; + + g_return_if_fail (tree1 != NULL && tree2 != NULL); + + bb1 = tree1->data; bb2 = tree2->data; + if (!gts_bboxes_are_overlapping (bb1, bb2)) + return; + + if (tree1->children == NULL && tree2->children == NULL) + (*func) (tree1->data, tree2->data, data); + else if (tree2->children == NULL || + (tree1->children != NULL && + bbox_volume (bb1) > bbox_volume (bb2))) { + GNode * i = tree1->children; + while (i) { + gts_bb_tree_traverse_overlapping (i, tree2, func, data); + i = i->next; + } + } + else { + GNode * i = tree2->children; + while (i) { + gts_bb_tree_traverse_overlapping (tree1, i, func, data); + i = i->next; + } + } +} + +/** + * gts_bb_tree_draw: + * @tree: a bounding box tree. + * @depth: a specified depth. + * @fptr: a file pointer. + * + * Write in @fptr an OOGL (Geomview) description of @tree for the + * depth specified by @depth. + */ +void gts_bb_tree_draw (GNode * tree, guint depth, FILE * fptr) +{ + guint d; + + g_return_if_fail (tree != NULL); + g_return_if_fail (fptr != NULL); + + d = g_node_depth (tree); + + if (d == 1) + fprintf (fptr, "{ LIST"); + + if (d == depth) + gts_bbox_draw (tree->data, fptr); + else if (d < depth) { + GNode * i = tree->children; + while (i) { + gts_bb_tree_draw (i, depth, fptr); + i = i->next; + } + } + + if (d == 1) + fprintf (fptr, "}\n"); +} + +static void bb_tree_free (GNode * tree, gboolean free_leaves) +{ + GNode * i; + + g_return_if_fail (tree != NULL); + + if (!free_leaves && tree->children == NULL) /* leaf node */ + return; + + gts_object_destroy (tree->data); + + i = tree->children; + while (i) { + bb_tree_free (i, free_leaves); + i = i->next; + } +} + +/** + * gts_bb_tree_destroy: + * @tree: a bounding box tree. + * @free_leaves: if %TRUE the bounding boxes given by the user are freed. + * + * Destroys all the bounding boxes created by @tree and destroys the + * tree itself. If @free_leaves is set to %TRUE, destroys boxes given + * by the user when creating the tree (i.e. leaves of the tree). + */ +void gts_bb_tree_destroy (GNode * tree, gboolean free_leaves) +{ + g_return_if_fail (tree != NULL); + + bb_tree_free (tree, free_leaves); + g_node_destroy (tree); +} + +static gdouble bb_tree_min_max (GNode * tree, + GtsPoint * p, + gdouble min_max, + GSList ** list) +{ + GNode * tree1, * tree2; + gdouble min1, max1, min2, max2; + + if (tree->children == NULL) { + *list = g_slist_prepend (*list, tree->data); + return min_max; + } + tree1 = tree->children; + gts_bbox_point_distance2 (tree1->data, p, &min1, &max1); + if (max1 < min_max) + min_max = max1; + + tree2 = tree1->next; + gts_bbox_point_distance2 (tree2->data, p, &min2, &max2); + if (max2 < min_max) + min_max = max2; + + if (min1 < min2) { + if (min1 <= min_max) { + min_max = bb_tree_min_max (tree1, p, min_max, list); + if (min2 <= min_max) + min_max = bb_tree_min_max (tree2, p, min_max, list); + } + } + else { + if (min2 <= min_max) { + min_max = bb_tree_min_max (tree2, p, min_max, list); + if (min1 <= min_max) + min_max = bb_tree_min_max (tree1, p, min_max, list); + } + } + + return min_max; +} + +/** + * gts_bb_tree_point_closest_bboxes: + * @tree: a bounding box tree. + * @p: a #GtsPoint. + * + * Returns: a list of #GtsBBox. One of the bounding boxes is assured to contain + * the object of @tree closest to @p. + */ +GSList * gts_bb_tree_point_closest_bboxes (GNode * tree, + GtsPoint * p) +{ + gdouble min, min_max; + GSList * list = NULL, * i, * prev = NULL; + + g_return_val_if_fail (tree != NULL, NULL); + g_return_val_if_fail (p != NULL, NULL); + + gts_bbox_point_distance2 (tree->data, p, &min, &min_max); + min_max = bb_tree_min_max (tree, p, min_max, &list); + + i = list; + while (i) { + GSList * next = i->next; + gdouble min, max; + + gts_bbox_point_distance2 (i->data, p, &min, &max); + + if (min > min_max) { + if (prev == NULL) + list = next; + else + prev->next = next; + g_slist_free_1 (i); + } + else + prev = i; + i = next; + } + + return list; +} + +/** + * gts_bb_tree_point_distance: + * @tree: a bounding box tree. + * @p: a #GtsPoint. + * @distance: a #GtsBBoxDistFunc. + * @bbox: if not %NULL is set to the bounding box containing the closest + * object. + * + * Returns: the distance as evaluated by @distance between @p and the closest + * object in @tree. + */ +gdouble gts_bb_tree_point_distance (GNode * tree, + GtsPoint * p, + GtsBBoxDistFunc distance, + GtsBBox ** bbox) +{ + GSList * list, * i; + gdouble dmin = G_MAXDOUBLE; + + g_return_val_if_fail (tree != NULL, dmin); + g_return_val_if_fail (p != NULL, dmin); + g_return_val_if_fail (distance != NULL, dmin); + + i = list = gts_bb_tree_point_closest_bboxes (tree, p); + while (i) { + gdouble d = (*distance) (p, GTS_BBOX (i->data)->bounded); + + if (fabs (d) < fabs (dmin)) { + dmin = d; + if (bbox) + *bbox = i->data; + } + i = i->next; + } + g_slist_free (list); + + return dmin; +} + +/** + * gts_bb_tree_point_closest: + * @tree: a bounding box tree. + * @p: a #GtsPoint. + * @closest: a #GtsBBoxClosestFunc. + * @distance: if not %NULL is set to the distance between @p and the + * new #GtsPoint. + * + * Returns: a new #GtsPoint, closest point to @p and belonging to an object of + * @tree. + */ +GtsPoint * gts_bb_tree_point_closest (GNode * tree, + GtsPoint * p, + GtsBBoxClosestFunc closest, + gdouble * distance) +{ + GSList * list, * i; + gdouble dmin = G_MAXDOUBLE; + GtsPoint * np = NULL; + + g_return_val_if_fail (tree != NULL, NULL); + g_return_val_if_fail (p != NULL, NULL); + g_return_val_if_fail (closest != NULL, NULL); + + i = list = gts_bb_tree_point_closest_bboxes (tree, p); + while (i) { + GtsPoint * tp = (*closest) (p, GTS_BBOX (i->data)->bounded); + gdouble d = gts_point_distance2 (tp, p); + + if (d < dmin) { + if (np) + gts_object_destroy (GTS_OBJECT (np)); + np = tp; + dmin = d; + } + else + gts_object_destroy (GTS_OBJECT (tp)); + i = i->next; + } + g_slist_free (list); + + if (distance) + *distance = dmin; + + return np; +} + +/** + * gts_bb_tree_triangle_distance: + * @tree: a bounding box tree. + * @t: a #GtsTriangle. + * @distance: a #GtsBBoxDistFunc. + * @delta: spatial scale of the sampling to be used. + * @range: a #GtsRange to be filled with the results. + * + * Given a triangle @t, points are sampled regularly on its surface + * using @delta as increment. The distance from each of these points + * to the closest object of @tree is computed using @distance and the + * gts_bb_tree_point_distance() function. The fields of @range are + * filled with the number of points sampled, the minimum, average and + * maximum value and the standard deviation. + */ +void gts_bb_tree_triangle_distance (GNode * tree, + GtsTriangle * t, + GtsBBoxDistFunc distance, + gdouble delta, + GtsRange * range) +{ + GtsPoint * p1, * p2, * p3, * p; + GtsVector p1p2, p1p3; + gdouble l1, t1, dt1; + guint i, n1; + + g_return_if_fail (tree != NULL); + g_return_if_fail (t != NULL); + g_return_if_fail (distance != NULL); + g_return_if_fail (delta > 0.); + g_return_if_fail (range != NULL); + + gts_triangle_vertices (t, + (GtsVertex **) &p1, + (GtsVertex **) &p2, + (GtsVertex **) &p3); + + gts_vector_init (p1p2, p1, p2); + gts_vector_init (p1p3, p1, p3); + gts_range_init (range); + p = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class ()))); + + l1 = sqrt (gts_vector_scalar (p1p2, p1p2)); + n1 = l1/delta + 1; + dt1 = 1.0/(gdouble) n1; + t1 = 0.0; + for (i = 0; i <= n1; i++, t1 += dt1) { + gdouble t2 = 1. - t1; + gdouble x = t2*p1p3[0]; + gdouble y = t2*p1p3[1]; + gdouble z = t2*p1p3[2]; + gdouble l2 = sqrt (x*x + y*y + z*z); + guint j, n2 = (guint) (l2/delta + 1); + gdouble dt2 = t2/(gdouble) n2; + + x = t2*p1->x + t1*p2->x; + y = t2*p1->y + t1*p2->y; + z = t2*p1->z + t1*p2->z; + + t2 = 0.0; + for (j = 0; j <= n2; j++, t2 += dt2) { + p->x = x + t2*p1p3[0]; + p->y = y + t2*p1p3[1]; + p->z = z + t2*p1p3[2]; + + gts_range_add_value (range, + gts_bb_tree_point_distance (tree, p, distance, NULL)); + } + } + + gts_object_destroy (GTS_OBJECT (p)); + gts_range_update (range); +} + +/** + * gts_bb_tree_segment_distance: + * @tree: a bounding box tree. + * @s: a #GtsSegment. + * @distance: a #GtsBBoxDistFunc. + * @delta: spatial scale of the sampling to be used. + * @range: a #GtsRange to be filled with the results. + * + * Given a segment @s, points are sampled regularly on its length + * using @delta as increment. The distance from each of these points + * to the closest object of @tree is computed using @distance and the + * gts_bb_tree_point_distance() function. The fields of @range are + * filled with the number of points sampled, the minimum, average and + * maximum value and the standard deviation. + */ +void gts_bb_tree_segment_distance (GNode * tree, + GtsSegment * s, + gdouble (*distance) (GtsPoint *, + gpointer), + gdouble delta, + GtsRange * range) +{ + GtsPoint * p1, * p2, * p; + GtsVector p1p2; + gdouble l, t, dt; + guint i, n; + + g_return_if_fail (tree != NULL); + g_return_if_fail (s != NULL); + g_return_if_fail (distance != NULL); + g_return_if_fail (delta > 0.); + g_return_if_fail (range != NULL); + + p1 = GTS_POINT (s->v1); + p2 = GTS_POINT (s->v2); + + gts_vector_init (p1p2, p1, p2); + gts_range_init (range); + p = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class()))); + + l = sqrt (gts_vector_scalar (p1p2, p1p2)); + n = (guint) (l/delta + 1); + dt = 1.0/(gdouble) n; + t = 0.0; + for (i = 0; i <= n; i++, t += dt) { + p->x = p1->x + t*p1p2[0]; + p->y = p1->y + t*p1p2[1]; + p->z = p1->z + t*p1p2[2]; + + gts_range_add_value (range, + gts_bb_tree_point_distance (tree, p, distance, NULL)); + } + + gts_object_destroy (GTS_OBJECT (p)); + gts_range_update (range); +} + +static void surface_distance_foreach_triangle (GtsTriangle * t, + gpointer * data) +{ + gdouble * delta = data[1]; + GtsRange * range = data[2]; + gdouble * total_area = data[3], area; + GtsRange range_triangle; + + gts_bb_tree_triangle_distance (data[0], t, data[4], *delta, &range_triangle); + + if (range_triangle.min < range->min) + range->min = range_triangle.min; + if (range_triangle.max > range->max) + range->max = range_triangle.max; + range->n += range_triangle.n; + + area = gts_triangle_area (t); + *total_area += area; + range->sum += area*range_triangle.mean; + range->sum2 += area*range_triangle.mean*range_triangle.mean; +} + +/** + * gts_bb_tree_surface_distance: + * @tree: a bounding box tree. + * @s: a #GtsSurface. + * @distance: a #GtsBBoxDistFunc. + * @delta: a sampling increment defined as the percentage of the diagonal + * of the root bounding box of @tree. + * @range: a #GtsRange to be filled with the results. + * + * Calls gts_bb_tree_triangle_distance() for each face of @s. The + * fields of @range are filled with the minimum, maximum and average + * distance. The average distance is defined as the sum of the average + * distances for each triangle weighthed by their area and divided by + * the total area of the surface. The standard deviation is defined + * accordingly. The @n field of @range is filled with the number of + * sampled points used. + */ +void gts_bb_tree_surface_distance (GNode * tree, + GtsSurface * s, + GtsBBoxDistFunc distance, + gdouble delta, + GtsRange * range) +{ + gpointer data[5]; + gdouble total_area = 0.; + + g_return_if_fail (tree != NULL); + g_return_if_fail (s != NULL); + g_return_if_fail (delta > 0. && delta < 1.); + g_return_if_fail (range != NULL); + + gts_range_init (range); + delta *= sqrt (gts_bbox_diagonal2 (tree->data)); + data[0] = tree; + data[1] = δ + data[2] = range; + data[3] = &total_area; + data[4] = distance; + + gts_surface_foreach_face (s, + (GtsFunc) surface_distance_foreach_triangle, + data); + + if (total_area > 0.) { + if (range->sum2 - range->sum*range->sum/total_area >= 0.) + range->stddev = sqrt ((range->sum2 - range->sum*range->sum/total_area) + /total_area); + else + range->stddev = 0.; + range->mean = range->sum/total_area; + } + else + range->min = range->max = range->mean = range->stddev = 0.; +} + +static void surface_distance_foreach_boundary (GtsEdge * e, + gpointer * data) +{ + gdouble * delta = data[1]; + GtsRange * range = data[2]; + gdouble * total_length = data[3], length; + GtsRange range_edge; + + if (gts_edge_is_boundary (e, NULL)) { + GtsSegment * s = GTS_SEGMENT (e); + + gts_bb_tree_segment_distance (data[0], s, data[4], *delta, &range_edge); + + if (range_edge.min < range->min) + range->min = range_edge.min; + if (range_edge.max > range->max) + range->max = range_edge.max; + range->n += range_edge.n; + + length = gts_point_distance (GTS_POINT (s->v1), GTS_POINT (s->v2)); + *total_length += length; + range->sum += length*range_edge.mean; + range->sum2 += length*range_edge.mean*range_edge.mean; + } +} + +/** + * gts_bb_tree_surface_boundary_distance: + * @tree: a bounding box tree. + * @s: a #GtsSurface. + * @distance: a #GtsBBoxDistFunc. + * @delta: a sampling increment defined as the percentage of the diagonal + * of the root bounding box of @tree. + * @range: a #GtsRange to be filled with the results. + * + * Calls gts_bb_tree_segment_distance() for each edge boundary of @s. + * The fields of @range are filled with the minimum, maximum and + * average distance. The average distance is defined as the sum of the + * average distances for each boundary edge weighthed by their length + * and divided by the total length of the boundaries. The standard + * deviation is defined accordingly. The @n field of @range is filled + * with the number of sampled points used. + */ +void gts_bb_tree_surface_boundary_distance (GNode * tree, + GtsSurface * s, + gdouble (*distance) (GtsPoint *, + gpointer), + gdouble delta, + GtsRange * range) +{ + gpointer data[5]; + gdouble total_length = 0.; + + g_return_if_fail (tree != NULL); + g_return_if_fail (s != NULL); + g_return_if_fail (delta > 0. && delta < 1.); + g_return_if_fail (range != NULL); + + gts_range_init (range); + delta *= sqrt (gts_bbox_diagonal2 (tree->data)); + data[0] = tree; + data[1] = δ + data[2] = range; + data[3] = &total_length; + data[4] = distance; + + gts_surface_foreach_edge (s, + (GtsFunc) surface_distance_foreach_boundary, + data); + + if (total_length > 0.) { + if (range->sum2 - range->sum*range->sum/total_length >= 0.) + range->stddev = sqrt ((range->sum2 - + range->sum*range->sum/total_length) + /total_length); + else + range->stddev = 0.; + range->mean = range->sum/total_length; + } + else + range->min = range->max = range->mean = range->stddev = 0.; +} Index: work/obsolete/toporouter/src_3rd/gts/boolean.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/boolean.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/boolean.c (revision 6803) @@ -0,0 +1,2048 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999--2002 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "gts.h" + +/*#define DEBUG*/ +/*#define DEBUG_BOOLEAN*/ +/*#define CHECK_ORIENTED*/ + +#ifdef DEBUG +# include "gts-private.h" +#endif /* DEBUG */ + +static void surface_inter_destroy (GtsObject * object) +{ + GtsSurfaceInter * si = GTS_SURFACE_INTER (object); + + gts_object_destroy (GTS_OBJECT (si->s1)); + gts_object_destroy (GTS_OBJECT (si->s2)); + g_slist_free (si->edges); + + (* GTS_OBJECT_CLASS (gts_surface_inter_class ())->parent_class->destroy) + (object); +} + +static void surface_inter_class_init (GtsObjectClass * klass) +{ + klass->destroy = surface_inter_destroy; +} + +static void surface_inter_init (GtsSurfaceInter * si) +{ + si->s1 = si->s2 = NULL; + si->edges = NULL; +} + +/** + * gts_surface_inter_class: + * + * Returns: the #GtsSurfaceInterClass. + */ +GtsSurfaceInterClass * gts_surface_inter_class (void) +{ + static GtsSurfaceInterClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo surface_inter_info = { + "GtsSurfaceInter", + sizeof (GtsSurfaceInter), + sizeof (GtsSurfaceInterClass), + (GtsObjectClassInitFunc) surface_inter_class_init, + (GtsObjectInitFunc) surface_inter_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (gts_object_class (), &surface_inter_info); + } + + return klass; +} + +/* EdgeInter: Header */ + +typedef struct _EdgeInter EdgeInter; + +struct _EdgeInter { + GtsEdge parent; + + GtsTriangle * t1, * t2; +}; + +#define EDGE_INTER(obj) GTS_OBJECT_CAST (obj,\ + EdgeInter,\ + edge_inter_class ()) +#define IS_EDGE_INTER(obj) (gts_object_is_from_class (obj,\ + edge_inter_class ())) + +static GtsEdgeClass * edge_inter_class (void); +static EdgeInter * edge_inter_new (GtsVertex * v1, GtsVertex * v2, + GtsTriangle * t1, GtsTriangle * t2); + +/* EdgeInter: Object */ + +static GtsEdgeClass * edge_inter_class (void) +{ + static GtsEdgeClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo edge_inter_info = { + "EdgeInter", + sizeof (EdgeInter), + sizeof (GtsEdgeClass), + (GtsObjectClassInitFunc) NULL, + (GtsObjectInitFunc) NULL, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_constraint_class ()), + &edge_inter_info); + } + + return klass; +} + +static EdgeInter * edge_inter_new (GtsVertex * v1, GtsVertex * v2, + GtsTriangle * t1, GtsTriangle * t2) +{ + EdgeInter * object; + + object = EDGE_INTER (gts_edge_new (GTS_EDGE_CLASS (edge_inter_class ()), + v1, v2)); + object->t1 = t1; + object->t2 = t2; + + return object; +} + +#ifdef DEBUG +static void write_surface_graph (GtsSurface * s, FILE * fp) +{ + GSList * l = NULL; + GtsGraph * g; + static void add_to_list (gpointer data, GSList ** l) { + *l = g_slist_prepend (*l, data); + } + + gts_surface_foreach_vertex (s, (GtsFunc) gts_object_reset_reserved, NULL); + gts_surface_foreach_edge (s, (GtsFunc) gts_object_reset_reserved, NULL); + gts_surface_foreach_edge (s, (GtsFunc) add_to_list, &l); + g = gts_segments_graph_new (gts_graph_class (), l); + gts_graph_write_dot (g, fp); + gts_object_destroy (GTS_OBJECT (g)); + g_slist_free (l); +} +#endif /* DEBUG */ + +static GtsPoint * segment_triangle_intersection (GtsSegment * s, + GtsTriangle * t, + GtsPointClass * klass) +{ + GtsPoint * A, * B, * C, * D, * E; + gint ABCE, ABCD, ADCE, ABDE, BCDE; + GtsEdge * AB, * BC, * CA; + gdouble a, b, c; + + g_return_val_if_fail (s != NULL, NULL); + g_return_val_if_fail (t != NULL, NULL); + g_return_val_if_fail (klass != NULL, NULL); + + gts_triangle_vertices_edges (t, NULL, + (GtsVertex **) &A, + (GtsVertex **) &B, + (GtsVertex **) &C, + &AB, &BC, &CA); + D = GTS_POINT (s->v1); + E = GTS_POINT (s->v2); + + ABCE = gts_point_orientation_3d_sos (A, B, C, E); + ABCD = gts_point_orientation_3d_sos (A, B, C, D); + if (ABCE < 0 || ABCD > 0) { + GtsPoint * tmpp; + gint tmp; + + tmpp = E; E = D; D = tmpp; + tmp = ABCE; ABCE = ABCD; ABCD = tmp; + } + if (ABCE < 0 || ABCD > 0) + return NULL; + ADCE = gts_point_orientation_3d_sos (A, D, C, E); + if (ADCE < 0) + return NULL; + ABDE = gts_point_orientation_3d_sos (A, B, D, E); + if (ABDE < 0) + return NULL; + BCDE = gts_point_orientation_3d_sos (B, C, D, E); + if (BCDE < 0) + return NULL; + a = gts_point_orientation_3d (A, B, C, E); + b = gts_point_orientation_3d (A, B, C, D); + if (a != b) { + c = a/(a - b); + return gts_point_new (klass, + E->x + c*(D->x - E->x), + E->y + c*(D->y - E->y), + E->z + c*(D->z - E->z)); + } + /* D and E are contained within ABC */ +#ifdef DEBUG + fprintf (stderr, + "segment: %p:%s triangle: %p:%s intersection\n" + "D and E contained in ABC\n", + s, GTS_NEDGE (s)->name, t, GTS_NFACE (t)->name); +#endif /* DEBUG */ + g_assert (a == 0.); + return gts_point_new (klass, + (E->x + D->x)/2., + (E->y + D->y)/2., + (E->z + D->z)/2.); +} + +static gint triangle_triangle_orientation (GtsPoint * p1, + GtsPoint * p2, GtsPoint * p3, + GtsPoint * p4, GtsPoint * p5, + GtsPoint * p6) +{ + gint o4 = 0, o5 = 0, o6 = 0; + + if (p4 != p1 && p4 != p2 && p4 != p3) + o4 = gts_point_orientation_3d_sos (p1, p2, p3, p4); + if (p5 != p1 && p5 != p2 && p5 != p3) + o5 = gts_point_orientation_3d_sos (p1, p2, p3, p5); + if (o4*o5 < 0) + return 0; + if (p6 != p1 && p6 != p2 && p6 != p3) + o6 = gts_point_orientation_3d_sos (p1, p2, p3, p6); + if (o4*o6 < 0 || o5*o6 < 0) + return 0; + if (o4) return o4; + if (o5) return o5; + g_assert (o6); + return o6; +} + +static gint triangle_point_orientation (GtsTriangle * t1, + GtsTriangle * t2, + gint o1, + GtsPoint * p) +{ + GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (t1->e1)->v1); + GtsPoint * p2 = GTS_POINT (GTS_SEGMENT (t1->e1)->v2); + GtsPoint * p3 = GTS_POINT (gts_triangle_vertex (t1)); + GtsPoint * p4 = GTS_POINT (GTS_SEGMENT (t2->e1)->v1); + GtsPoint * p5 = GTS_POINT (GTS_SEGMENT (t2->e1)->v2); + GtsPoint * p6 = GTS_POINT (gts_triangle_vertex (t2)); + gint o = triangle_triangle_orientation (p1, p2, p3, p4, p5, p6); + + if (o != 0) + return o; + o = triangle_triangle_orientation (p4, p5, p6, p1, p2, p3); + if (o != 0) { + gint o2 = gts_point_orientation_3d_sos (p4, p5, p6, p); + + return - o*o1*o2; + } + return 0; +} + +static void add_edge_inter (GtsEdge * e, + GtsTriangle * t, + GtsVertex * v) +{ + GtsVertex * ev1 = GTS_SEGMENT (e)->v1, * ev2 = GTS_SEGMENT (e)->v2; + GList * i = GTS_OBJECT (e)->reserved; + + GTS_OBJECT (v)->reserved = t; + if (i == NULL) { + GTS_OBJECT (e)->reserved = g_list_prepend (NULL, v); +#ifdef DEBUG + fprintf (stderr, "add_edge_inter: inserting %p (%p,%p)\n", v, e, t); +#endif /* DEBUG */ + } + else { + GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1); + GtsPoint * p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); + GtsPoint * p3 = GTS_POINT (gts_triangle_vertex (t)); + gint o1, oref = gts_point_orientation_3d_sos (p1, p2, p3, GTS_POINT (ev1)); + + o1 = oref; + while (i) { + gint o2 = triangle_point_orientation (t, GTS_OBJECT (i->data)->reserved, + oref, GTS_POINT (ev1)); + + if (o2 == 0) { +#ifdef DEBUG + g_warning ("add_edge_inter: safe sign evaluation failed\n"); +#endif /* DEBUG */ + o2 = gts_point_orientation_3d_sos (p1, p2, p3, i->data); + } + + if (o1*o2 < 0) + break; + ev1 = i->data; + o1 = o2; + i = i->next; + } + if (i != NULL) { + GList * n = g_list_prepend (NULL, v); + + ev2 = i->data; + n->next = i; + n->prev = i->prev; + i->prev = n; + if (n->prev == NULL) + GTS_OBJECT (e)->reserved = n; + else + n->prev->next = n; + } + else { + g_assert (o1*gts_point_orientation_3d_sos (p1, p2, p3, GTS_POINT (ev2)) + < 0); + GTS_OBJECT (e)->reserved = g_list_append (GTS_OBJECT (e)->reserved, v); + } +#ifdef DEBUG + fprintf (stderr, + "add_edge_inter: inserting %p (%p,%p) between %p and %p\n", + v, e, t, ev1, ev2); + i = GTS_OBJECT (e)->reserved; + while (i) { + fprintf (stderr, " %p", i->data); + i = i->next; + } + fprintf (stderr, "\n"); +#endif /* DEBUG */ + } +} + +static GtsVertex * intersects (GtsEdge * e, + GtsTriangle * t, + GtsSurface * s) +{ + GList * i = GTS_OBJECT (e)->reserved; + GtsVertex * v; + + while (i) { + if (GTS_OBJECT (i->data)->reserved == t) + return i->data; + i = i->next; + } + + v = GTS_VERTEX (segment_triangle_intersection (GTS_SEGMENT (e), t, + GTS_POINT_CLASS (s->vertex_class))); + if (v != NULL) { +#ifdef DEBUG + if (GTS_IS_NVERTEX (v) && GTS_IS_NEDGE (e) && GTS_IS_NFACE (t) && + GTS_NVERTEX (v)->name[0] == '\0') + g_snprintf (GTS_NVERTEX (v)->name, GTS_NAME_LENGTH, "%s|%s", + GTS_NEDGE (e)->name, GTS_NFACE (t)->name); +#endif /* DEBUG */ + if (s->vertex_class->intersection_attributes) + (*s->vertex_class->intersection_attributes) + (v, GTS_OBJECT (e), GTS_OBJECT (t)); + add_edge_inter (e, t, v); + } + return v; +} + +/* see figure misc/orientation.fig */ +static gint intersection_orientation (GtsTriangle * t1, + GtsEdge * e, + GtsTriangle * t2) +{ + GtsVertex * v1, * v2, * v3; + GtsEdge * e2, * e3; + GtsVertex * v4, * v5, * v6; + + gts_triangle_vertices_edges (t1, e, &v1, &v2, &v3, &e, &e2, &e3); + gts_triangle_vertices (t2, &v4, &v5, &v6); + + return gts_point_orientation_3d_sos (GTS_POINT (v4), + GTS_POINT (v5), + GTS_POINT (v6), + GTS_POINT (v2)); +} + +#define UPDATE_ORIENTATION if (o > 0) { vi2 = v; /* e2 = e; */ } else { vi2 = vi1;\ + /* e2 = e1; */\ + vi1 = v;\ + /* e1 = e; */ } + +static void intersect_edges (GtsBBox * bb1, GtsBBox * bb2, + GtsSurfaceInter * si) +{ + GtsSurface * s1 = GTS_OBJECT (si->s1)->reserved; + GtsTriangle * t1 = GTS_TRIANGLE (bb1->bounded); + GtsTriangle * t2 = GTS_TRIANGLE (bb2->bounded); + GtsVertex * v, * vi1 = NULL, * vi2 = NULL; + //GtsEdge * e1 = NULL, * e2 = NULL, * e; + + vi1 = intersects (t2->e1, t1, s1); + //e1 = t2->e1; + v = intersects (t2->e2, t1, s1); + //e = t2->e2; + if (!vi1) { + vi1 = v; + //e1 = e; + } + else if (v) { + gint o = intersection_orientation (t2, t2->e2, t1); + UPDATE_ORIENTATION; + } + if (!vi2) { + v = intersects (t2->e3, t1, s1); + //e = t2->e3; + if (!vi1) { + vi1 = v; + //e1 = e; + } + else if (v) { + gint o = intersection_orientation (t2, t2->e3, t1); + UPDATE_ORIENTATION; + } + } + if (!vi2) { + v = intersects (t1->e1, t2, s1); + //e = t1->e1; + if (!vi1) { + vi1 = v; + //e1 = e; + } + else if (v) { + gint o = - intersection_orientation (t1, t1->e1, t2); + UPDATE_ORIENTATION; + } + } + if (!vi2) { + v = intersects (t1->e2, t2, s1); + //e = t1->e2; + if (!vi1) { + vi1 = v; + //e1 = e; + } + else if (v) { + gint o = - intersection_orientation (t1, t1->e2, t2); + UPDATE_ORIENTATION; + } + } + if (!vi2) { + v = intersects (t1->e3, t2, s1); + //e = t1->e3; + if (!vi1) { + vi1 = v; + //e1 = e; + } + else if (v) { + gint o = - intersection_orientation (t1, t1->e3, t2); + UPDATE_ORIENTATION; + } + } + + g_assert ((!vi1 && !vi2) || (vi1 && vi2)); + if (vi1) { + GtsEdge * e = GTS_EDGE (edge_inter_new (vi1, vi2, t1, t2)); + +#ifdef DEBUG + fprintf (stderr, "creating constraint %p: %p->%p: %p/%p\n", + e, vi1, vi2, t1, t2); +#endif /* DEBUG */ + gts_surface_add_face (si->s1, GTS_FACE (t1)); + gts_surface_add_face (si->s2, GTS_FACE (t2)); + si->edges = g_slist_prepend (si->edges, e); + GTS_OBJECT (t1)->reserved = g_slist_prepend (GTS_OBJECT (t1)->reserved, e); + GTS_OBJECT (t2)->reserved = g_slist_prepend (GTS_OBJECT (t2)->reserved, e); + } +} + +static GtsSurfaceInter * surface_inter_new (GtsSurfaceInterClass * klass, + GtsSurface * s1, + GtsSurface * s2, + GNode * faces_tree1, + GNode * faces_tree2) +{ + GtsSurfaceInter * si; + + si = GTS_SURFACE_INTER (gts_object_new (GTS_OBJECT_CLASS (klass))); + si->s1 = gts_surface_new (gts_surface_class (), + s1->face_class, + s1->edge_class, + s1->vertex_class); + GTS_OBJECT (si->s1)->reserved = s1; + si->s2 = gts_surface_new (gts_surface_class (), + s2->face_class, + s2->edge_class, + s2->vertex_class); + GTS_OBJECT (si->s2)->reserved = s2; + gts_bb_tree_traverse_overlapping (faces_tree1, faces_tree2, + (GtsBBTreeTraverseFunc) intersect_edges, + si); + + return si; +} + +static void free_slist (GtsObject * o) +{ + g_slist_free (o->reserved); + o->reserved = NULL; +} + +static void free_glist (GtsObject * o) +{ + g_list_foreach (o->reserved, (GFunc) gts_object_reset_reserved, NULL); + g_list_free (o->reserved); + o->reserved = NULL; +} + +/** + * gts_surface_intersection: + * @s1: a #GtsSurface. + * @s2: a #GtsSurface. + * @faces_tree1: a bounding box tree (see gts_bb_tree_new()) for + * the faces of @s1. + * @faces_tree2: a bounding box tree for the faces of @s2. + * + * Returns: a list of #GtsEdge defining the curve intersection of the + * two surfaces. + */ +GSList * gts_surface_intersection (GtsSurface * s1, + GtsSurface * s2, + GNode * faces_tree1, + GNode * faces_tree2) +{ + GtsSurfaceInter * si; + GSList * inter; + + g_return_val_if_fail (s1 != NULL, NULL); + g_return_val_if_fail (s2 != NULL, NULL); + g_return_val_if_fail (faces_tree1 != NULL, NULL); + g_return_val_if_fail (faces_tree2 != NULL, NULL); + + si = surface_inter_new (gts_surface_inter_class (), + s1, s2, faces_tree1, faces_tree2); + + gts_surface_foreach_face (si->s1, (GtsFunc) free_slist, NULL); + gts_surface_foreach_face (si->s2, (GtsFunc) free_slist, NULL); + gts_surface_foreach_edge (si->s1, (GtsFunc) free_glist, NULL); + gts_surface_foreach_edge (si->s2, (GtsFunc) free_glist, NULL); + inter = si->edges; + si->edges = NULL; + gts_object_destroy (GTS_OBJECT (si)); + + return inter; +} + +typedef enum { + INTERIOR = 1 << (GTS_USER_FLAG), + RELEVANT = 1 << (GTS_USER_FLAG + 1) +} CurveFlag; + +#define IS_SET(s, f) ((GTS_OBJECT_FLAGS (s) & (f)) != 0) +#define SET(s, f) (GTS_OBJECT_FLAGS (s) |= (f)) +#define UNSET(s, f) (GTS_OBJECT_FLAGS (s) &= ~(f)) +#define NEXT(s) (GTS_OBJECT (s)->reserved) + +#ifdef DEBUG +static void print_segment (GtsSegment * s) +{ + fprintf (stderr, "%p: %s->%s ", s, + GTS_NVERTEX (s->v1)->name, + GTS_NVERTEX (s->v2)->name); + if (NEXT (s)) { + GtsSegment * next = NEXT (s); + + fprintf (stderr, "next %p: %s->%s\n", next, + GTS_NVERTEX (next->v1)->name, + GTS_NVERTEX (next->v2)->name); + } + else + fprintf (stderr, "next NULL\n"); +} + +static void write_nodes (GSList * i, GHashTable * hash, guint * nn, + FILE * fp) +{ + while (i) { + GtsSegment * s = i->data; + + if (!g_hash_table_lookup (hash, s->v1)) { + fprintf (fp, " %u [ label = \"%p\" ];\n", *nn, s->v1); + g_hash_table_insert (hash, s->v1, GUINT_TO_POINTER ((*nn)++)); + } + if (!g_hash_table_lookup (hash, s->v2)) { + fprintf (fp, " %u [ label = \"%p\" ];\n", *nn, s->v2); + g_hash_table_insert (hash, s->v2, GUINT_TO_POINTER ((*nn)++)); + } + i = i->next; + } +} + +static void write_edges (GSList * i, GHashTable * hash, + GtsSurface * surface, + FILE * fp) +{ + while (i) { + GtsSegment * s = i->data; + + fprintf (fp, " %u -> %u [ label = \"%p:%d\" ];\n", + GPOINTER_TO_UINT (g_hash_table_lookup (hash, s->v1)), + GPOINTER_TO_UINT (g_hash_table_lookup (hash, s->v2)), + s, + gts_edge_face_number (GTS_EDGE (s), surface)); + i = i->next; + } +} + +static void write_graph (GSList * boundary, GSList * interior, + GtsSurface * surface, + FILE * fp) +{ + GHashTable * hash = g_hash_table_new (NULL, NULL); + guint nn = 1; + + fprintf (fp, "digraph oriented_curve {\n"); + write_nodes (boundary, hash, &nn, fp); + write_nodes (interior, hash, &nn, fp); + write_edges (boundary, hash, surface, fp); + fprintf (fp, " edge [ color = red ];\n"); + write_edges (interior, hash, surface, fp); + fprintf (fp, "}\n"); + g_hash_table_destroy (hash); +} + +static void write_graph1 (GtsSegment * start, GSList * i, + GtsSurface * surface, + FILE * fp) +{ + GSList * boundary = NULL, * interior = NULL; + GtsSegment * s = start; + + do { + boundary = g_slist_prepend (boundary, s); + s = NEXT (s); + } while (s != start); + while (i) { + if (IS_SET (i->data, INTERIOR)) + interior = g_slist_prepend (interior, i->data); + i = i->next; + } + write_graph (boundary, interior, surface, fp); + g_slist_free (boundary); + g_slist_free (interior); +} + +static void print_loop (GtsSegment * start, FILE * fp) +{ + GtsSegment * s = start; + + do { + fprintf (fp, " %p: %p:%s -> %p:%s\n", + s, + s->v1, GTS_NVERTEX (s->v1)->name, + s->v2, GTS_NVERTEX (s->v2)->name); + s = NEXT (s); + } while (s != start && s != NULL); +} + +static void draw_vector (GtsPoint * p1, GtsPoint * p2, FILE * fp) +{ + gdouble x = p2->x - p1->x; + gdouble y = p2->y - p1->y; + gdouble z = p2->z - p1->z; + + fprintf (fp, "VECT 1 3 0 3 0 %g %g %g %g %g %g %g %g %g\n", + p1->x + x - (x - y/2.)/5., + p1->y + y - (x/2. + y)/5., + p1->z + z - (x/2. + z)/5., + p1->x + x, + p1->y + y, + p1->z + z, + p1->x + x - (x + y/2.)/5., + p1->y + y + (x/2. - y)/5., + p1->z + z + (x/2. - z)/5.); + fprintf (fp, "VECT 1 2 0 2 0 %g %g %g %g %g %g\n", + p1->x, p1->y, p1->z, + p1->x + x, + p1->y + y, + p1->z + z); +} + +static void draw_vector1 (GtsPoint * p1, GtsPoint * p2, GtsPoint * o, + FILE * fp) +{ + gdouble x1 = o->x + 0.9*(p1->x - o->x); + gdouble y1 = o->y + 0.9*(p1->y - o->y); + gdouble z1 = o->z + 0.9*(p1->z - o->z); + gdouble x2 = o->x + 0.9*(p2->x - o->x); + gdouble y2 = o->y + 0.9*(p2->y - o->y); + gdouble z2 = o->z + 0.9*(p2->z - o->z); + gdouble x = x2 - x1; + gdouble y = y2 - y1; + gdouble z = z2 - z1; + + fprintf (fp, "VECT 1 3 0 3 0 %g %g %g %g %g %g %g %g %g\n", + x1 + x - (x - y/2.)/5., + y1 + y - (x/2. + y)/5., + z1 + z - (x/2. + z)/5., + x1 + x, + y1 + y, + z1 + z, + x1 + x - (x + y/2.)/5., + y1 + y + (x/2. - y)/5., + z1 + z + (x/2. - z)/5.); + fprintf (fp, "VECT 1 2 0 2 0 %g %g %g %g %g %g\n", + x1, y1, z1, + x1 + x, + y1 + y, + z1 + z); +} + +static void write_segments (GSList * boundary, GSList * interior, + FILE * fp) +{ + GSList * i = boundary; + + fprintf (fp, "LIST {\n"); + while (i) { + GSList * inext = i->next; + GtsSegment * s = i->data; + GtsSegment * next = inext ? inext->data : boundary->data; + GtsVertex * v1, * v2; + + if (s->v1 != next->v1 && s->v1 != next->v2) { + v1 = s->v1; + v2 = s->v2; + } + else { + v1 = s->v2; + v2 = s->v1; + } + draw_vector (GTS_POINT (v1), GTS_POINT (v2), fp); + i = inext; + } + i = interior; + while (i) { + GtsSegment * s = i->data; + + draw_vector (GTS_POINT (s->v1), GTS_POINT (s->v2), fp); + i = i->next; + } + fprintf (fp, "}\n"); +} + +static void write_loops (GSList * i, FILE * fp) +{ + guint nl = 0; + + while (i) { + GtsSegment * start = i->data, * s; + GtsPoint os; + guint n = 0; + + fprintf (fp, "(geometry \"loop%d\" = LIST {\n", nl++); + + os.x = os.y = os.z = 0.; + s = start; + do { + GtsSegment * next = NEXT (s); + GtsPoint * p; + + if (s->v1 != next->v1 && s->v1 != next->v2) + p = GTS_POINT (s->v1); + else + p = GTS_POINT (s->v2); + os.x += p->x; os.y += p->y; os.z += p->z; n++; + s = next; + } while (s != start); + os.x /= n; os.y /= n; os.z /= n; + + s = start; + do { + GtsSegment * next = NEXT (s); + + if (s->v1 != next->v1 && s->v1 != next->v2) + draw_vector1 (GTS_POINT (s->v1), GTS_POINT (s->v2), &os, fp); + else + draw_vector1 (GTS_POINT (s->v2), GTS_POINT (s->v1), &os, fp); + s = next; + } while (s != start); + + fprintf (fp, "})\n"); + + i = i->next; + } +} + +#define NAME(v) (GTS_IS_NVERTEX (v) ? GTS_NVERTEX (v)->name : "") +#endif /* DEBUG */ + +static GtsSegment * prev_flag (GtsSegment * s, CurveFlag flag) +{ + GSList * i = s->v1->segments; + + while (i) { + if (i->data != s && IS_SET (i->data, flag)) + return i->data; + i = i->next; + } + return NULL; +} + +static GtsSegment * next_flag (GtsSegment * s, CurveFlag flag) +{ + GSList * i = s->v2->segments; + + while (i) { + if (i->data != s && IS_SET (i->data, flag)) + return i->data; + i = i->next; + } + return NULL; +} + +static GtsSegment * next_interior (GtsVertex * v) +{ + GSList * i = v->segments; + + while (i) { + GtsSegment * s = i->data; + + if (s->v1 == v && IS_SET (s, INTERIOR)) + return s; + i = i->next; + } + return NULL; +} + +static GtsSegment * prev_interior (GtsVertex * v) +{ + GSList * i = v->segments; + + while (i) { + GtsSegment * s = i->data; + + if (s->v2 == v && IS_SET (s, INTERIOR)) + return s; + i = i->next; + } + return NULL; +} + +static GtsSegment * reverse (GtsSegment * start, + gboolean interior, + gboolean * isloop) +{ + GtsSegment * s = start, * prev = NULL, * rprev = NULL; + GtsSegment * rstart = NULL, * rstart1 = NULL; + + do { + GtsSegment * rs; + + g_assert (IS_EDGE_INTER (s)); + rs = GTS_SEGMENT (edge_inter_new (s->v2, s->v1, + EDGE_INTER (s)->t1, EDGE_INTER (s)->t2)); + + if (rstart == NULL) + rstart = rs; + else if (rstart1 == NULL) + rstart1 = rs; + if (interior) + SET (rs, INTERIOR); + NEXT (rs) = rprev; + rprev = rs; + prev = s; + s = NEXT (s); + } while (s != NULL && s != start); + if (s == start) { + NEXT (rstart) = rprev; + *isloop = TRUE; + } + else { + NEXT (rstart) = start; + NEXT (prev) = rprev; + *isloop = FALSE; + } + return rstart1; +} + +static GSList * interior_loops (GSList * interior) +{ + GSList * i = interior; + GSList * loops = NULL; + + i = interior; + while (i) { + GtsSegment * s = i->data; + + if (IS_SET (s, RELEVANT)) { + GtsSegment * start = s, * end; + + do { + GtsSegment * next = next_flag (s, INTERIOR); + + UNSET (s, RELEVANT); + end = s; + s = NEXT (s) = next; + } while (s != NULL && s != start); + + if (s == start) + loops = g_slist_prepend (loops, start); + else { + GtsSegment * next, * prev; + gboolean isloop; + + s = prev_flag (start, INTERIOR); + while (s) { + UNSET (s, RELEVANT); + NEXT (s) = start; + start = s; + s = prev_flag (s, INTERIOR); + } + next = next_flag (end, RELEVANT); + prev = prev_flag (start, RELEVANT); + if (prev != NULL) + SET (start->v1, INTERIOR); + if (next != NULL) + SET (end->v2, INTERIOR); + if (next == NULL && prev == NULL) + loops = g_slist_prepend (loops, start); + else + reverse (start, TRUE, &isloop); + } + } + i = i->next; + } + return loops; +} + +#define ORIENTATION(p1,p2,p3,o) (gts_point_orientation_3d (p1, p2, o, p3)) +#define ORIENTATION_SOS(p1,p2,p3,o) (gts_point_orientation_3d_sos (p1, p2, o, p3)) + +#define ORIENTED_VERTICES(s,next,w1,w2) {\ + if ((s)->v1 == (next)->v1 || (s)->v1 == (next)->v2) {\ + w1 = (s)->v2;\ + w2 = (s)->v1;\ + }\ + else {\ + w1 = (s)->v1;\ + w2 = (s)->v2;\ + }\ +} + +#if 0 +static GtsSegment * segment_intersects (GtsPoint * p1, GtsPoint * p2, + GSList * i, + GtsPoint * o) +{ + while (i) { + GtsSegment * s = i->data; + GtsPoint * p3 = GTS_POINT (s->v1); + GtsPoint * p4 = GTS_POINT (s->v2); + + if (p3 != p1 && p3 != p2 && p4 != p1 && p4 != p2) { + gdouble o1 = ORIENTATION (p3, p4, p1, o); + gdouble o2 = ORIENTATION (p3, p4, p2, o); + + if ((o1 < 0. && o2 > 0.) || (o1 > 0. && o2 < 0.)) { + o1 = ORIENTATION (p1, p2, p3, o); + o2 = ORIENTATION (p1, p2, p4, o); + + if ((o1 <= 0. && o2 >= 0.) || (o1 >= 0. && o2 <= 0.)) + return s; + } + } + i = i->next; + } + return NULL; +} +#else +static GtsSegment * segment_intersects (GtsPoint * p1, GtsPoint * p2, + GSList * i, + GtsPoint * o) +{ + while (i) { + GtsSegment * s = i->data; + GtsPoint * p3 = GTS_POINT (s->v1); + GtsPoint * p4 = GTS_POINT (s->v2); + + if (p3 != p1 && p3 != p2 && p4 != p1 && p4 != p2) { + gint o1 = ORIENTATION_SOS (p3, p4, p1, o); + gint o2 = ORIENTATION_SOS (p3, p4, p2, o); + + if (o1*o2 < 0) { + o1 = ORIENTATION_SOS (p1, p2, p3, o); + o2 = ORIENTATION_SOS (p1, p2, p4, o); + + if (o1*o2 < 0) + return s; + } + } + i = i->next; + } + return NULL; +} +#endif + +static gboolean is_inside_wedge (GtsSegment * s1, GtsSegment * s2, + GtsPoint * p, GtsPoint * o) +{ + GtsVertex * v1, * v2, * v3; + + ORIENTED_VERTICES (s1, s2, v1, v2); + v3 = s2->v1 != v2 ? s2->v1 : s2->v2; + + if (ORIENTATION (GTS_POINT (v1), GTS_POINT (v2), + GTS_POINT (v3), o) >= 0.) { + if (ORIENTATION (GTS_POINT (v1), GTS_POINT (v2), p, o) <= 0. || + ORIENTATION (GTS_POINT (v2), GTS_POINT (v3), p, o) <= 0.) + return FALSE; + } + else if (ORIENTATION (GTS_POINT (v1), GTS_POINT (v2), p, o) <= 0. && + ORIENTATION (GTS_POINT (v2), GTS_POINT (v3), p, o) <= 0.) + return FALSE; + return TRUE; +} + +static GtsSegment * connection (GtsPoint * p, + GSList * interior, + GSList * bloops, + GtsPoint * o) +{ + while (bloops) { + GtsSegment * start = bloops->data, * s = start; + + do { + GtsSegment * next = NEXT (s); + GtsVertex * v2 = s->v1 == next->v1 || s->v1 == next->v2 ? s->v1 : s->v2; + + if (is_inside_wedge (s, next, p, o) && + !segment_intersects (p, GTS_POINT (v2), interior, o)) + return s; + s = next; + } while (s != start); + bloops = bloops->next; + } + return NULL; +} + +static gdouble loop_orientation (GtsSegment * start, + GtsPoint * p, GtsPoint * o) +{ + GtsSegment * s = start; + gdouble or = 0.; + + do { + GtsSegment * next = NEXT (s); + GtsVertex * v1, * v2; + + ORIENTED_VERTICES (s, next, v1, v2); + or += ORIENTATION (p, GTS_POINT (v1), GTS_POINT (v2), o); + s = next; + } while (s != start); + +#ifdef DEBUG + fprintf (stderr, "loop orientation: %g\n", or); +#endif /* DEBUG */ + + return or; +} + +static void connect_interior_loop (GtsSegment * start, + GSList ** interior, + GSList ** bloops, + GtsSurface * surface, + GtsPoint * o) +{ + GtsSegment * s = start, * c = NULL, * next, * s1, * rs1, * rs; + GtsVertex * v, * cv; + gboolean isloop; + + do { + if (!(c = connection (GTS_POINT (s->v2), *interior, *bloops, o))) + s = NEXT (s); + } while (s != start && !c); + g_assert (c); + next = NEXT (c); + v = c->v1 == next->v1 || c->v1 == next->v2 ? c->v1 : c->v2; + cv = s->v2; +#ifdef DEBUG + fprintf (stderr, "connecting %p:%s with %p:%s\n", + cv, NAME (cv), v, NAME (v)); + fprintf (stderr, " c: %p: %p:%s %p:%s\n", c, + c->v1, NAME (c->v1), + c->v2, NAME (c->v2)); + fprintf (stderr, " next: %p: %p:%s %p:%s\n", next, + next->v1, NAME (next->v1), + next->v2, NAME (next->v2)); +#endif /* DEBUG */ + rs = reverse (s, FALSE, &isloop); + if (isloop) { + if (loop_orientation (rs, GTS_POINT (v), o) < 0.) { + GtsSegment * tmp = s; + s = rs; + rs = tmp; + } + *bloops = g_slist_prepend (*bloops, rs); + } + s1 = GTS_SEGMENT (gts_edge_new (surface->edge_class, v, cv)); + rs1 = GTS_SEGMENT (gts_edge_new (surface->edge_class, cv, v)); + NEXT (c) = s1; + NEXT (rs1) = next; + *interior = g_slist_prepend (*interior, s1); + NEXT (s1) = NEXT (s); + NEXT (s) = rs1; +} + +static GSList * boundary_loops (GSList * boundary) +{ + GSList * i = boundary; + GtsSegment * start = i->data; + GSList * loops = NULL; + + while (i) { + GtsSegment * s = i->data; + GSList * inext = i->next; + GtsSegment * next = inext ? inext->data : start; + GtsVertex * v = s->v1 == next->v1 || s->v1 == next->v2 ? s->v1 : s->v2; + + if (IS_SET (v, INTERIOR)) { + GtsSegment * intprev = prev_interior (v); + + NEXT (intprev) = next; + NEXT (s) = next_interior (v); + UNSET (v, INTERIOR); + } + else + NEXT (s) = next; + i = inext; + } + + i = boundary; + while (i) { + start = i->data; + + if (IS_SET (start, RELEVANT)) { + GtsSegment * s = start; + + do { + UNSET (s, RELEVANT); + UNSET (s, INTERIOR); + s = NEXT (s); + } while (s != start); + loops = g_slist_prepend (loops, start); + } + i = i->next; + } + + return loops; +} + +typedef struct _Ear Ear; + +struct _Ear { + GtsVertex * v1, * v2, * v3; + GtsSegment * s1, * s2, * s3; +}; + +static gboolean point_in_wedge (GtsPoint * p1, GtsPoint * p2, GtsPoint * p3, + GtsPoint * p, gboolean closed, GtsPoint * o) +{ + gdouble o1; + + if (p == p2 || p == p3) + return FALSE; + o1 = ORIENTATION (p1, p2, p, o); + if ((closed && o1 < 0.) || (!closed && o1 <= 0.)) return FALSE; + o1 = ORIENTATION (p3, p1, p, o); + if ((closed && o1 < 0.) || (!closed && o1 <= 0.)) return FALSE; + return TRUE; +} + +#if 0 +static gboolean segment_intersects1 (GtsPoint * p1, GtsPoint * p2, + GtsPoint * p3, GtsPoint * p4, + gboolean closed, GtsPoint * o) +{ + gdouble o1 = ORIENTATION (p3, p4, p1, o); + gdouble o2 = ORIENTATION (p3, p4, p2, o); + gdouble o3, o4; + + if ((closed && ((o1 > 0. && o2 > 0.) || (o1 < 0. && o2 < 0.))) || + (!closed && ((o1 >= 0. && o2 >= 0.) || (o1 <= 0. && o2 <= 0.)))) + return FALSE; + o3 = ORIENTATION (p1, p2, p3, o); + o4 = ORIENTATION (p1, p2, p4, o); + if ((o3 > 0. && o4 > 0.) || (o3 < 0. && o4 < 0.)) + return FALSE; + if (closed) return TRUE; + if ((o3 == 0. && o4 > 0.) || (o4 == 0. && o3 > 0.)) + return TRUE; + return FALSE; +} +#else +static gboolean segment_intersects1 (GtsPoint * p1, GtsPoint * p2, + GtsPoint * p3, GtsPoint * p4, + gboolean closed, GtsPoint * o) +{ + gint o1, o2; + + o1 = ORIENTATION_SOS (p3, p4, p1, o); + o2 = ORIENTATION_SOS (p3, p4, p2, o); + if (o1*o2 > 0) + return FALSE; + o1 = ORIENTATION_SOS (p1, p2, p3, o); + o2 = ORIENTATION_SOS (p1, p2, p4, o); + if (o1*o2 > 0) + return FALSE; + return TRUE; +} +#endif + +static GtsSegment * triangle_intersects_segments (GtsPoint * p1, + GtsPoint * p2, + GtsPoint * p3, + gboolean closed, + GtsSegment * start, + GtsPoint * o) +{ + GtsSegment * s = start; + + do { + GtsPoint * p4 = GTS_POINT (s->v1); + GtsPoint * p5 = GTS_POINT (s->v2); + + if (p4 == p1) { + if (point_in_wedge (p1, p2, p3, p5, closed, o)) + return s; + } + else if (p4 == p2) { + if (point_in_wedge (p2, p3, p1, p5, closed, o)) + return s; + } + else if (p4 == p3) { + if (point_in_wedge (p3, p1, p2, p5, closed, o)) + return s; + } + else if (p5 == p1) { + if (point_in_wedge (p1, p2, p3, p4, closed, o)) + return s; + } + else if (p5 == p2) { + if (point_in_wedge (p2, p3, p1, p4, closed, o)) + return s; + } + else if (p5 == p3) { + if (point_in_wedge (p3, p1, p2, p4, closed, o)) + return s; + } + else if (segment_intersects1 (p1, p2, p4, p5, closed, o) || + segment_intersects1 (p2, p3, p4, p5, closed, o) || + segment_intersects1 (p3, p1, p4, p5, closed, o)) + return s; + s = NEXT (s); + } while (s != start); + return NULL; +} + +static gboolean new_ear (GtsSegment * s, + Ear * e, + GtsSegment * start, + guint sloppy, + GtsPoint * o) +{ + gdouble or; + + e->s1 = s; + e->s2 = NEXT (s); + + g_return_val_if_fail (e->s2, FALSE); + g_return_val_if_fail (e->s2 != e->s1, FALSE); + + ORIENTED_VERTICES (e->s1, e->s2, e->v1, e->v2); + e->v3 = e->s2->v1 != e->v2 ? e->s2->v1 : e->s2->v2; + if (e->v3 == e->v1) + return FALSE; + e->s3 = NEXT (e->s2); + if (gts_segment_connect (e->s3, e->v1, e->v3)) { + if (NEXT (e->s3) != e->s1) + return FALSE; + } + else if (gts_vertices_are_connected (e->v1, e->v3)) + return FALSE; + else + e->s3 = NULL; + or = ORIENTATION (GTS_POINT (e->v1), GTS_POINT (e->v2), GTS_POINT (e->v3),o); + switch (sloppy) { + case 0: + if (or <= 0. || + triangle_intersects_segments (GTS_POINT (e->v1), GTS_POINT (e->v2), + GTS_POINT (e->v3), TRUE, start, o)) + return FALSE; + break; + case 1: + if (or < 0. || + (or > 0. && + triangle_intersects_segments (GTS_POINT (e->v1), GTS_POINT (e->v2), + GTS_POINT (e->v3), FALSE, start, o))) + return FALSE; + break; + case 2: + if ((or > 0. && + triangle_intersects_segments (GTS_POINT (e->v1), GTS_POINT (e->v2), + GTS_POINT (e->v3), FALSE, start, o)) || + (or < 0. && + triangle_intersects_segments (GTS_POINT (e->v2), GTS_POINT (e->v1), + GTS_POINT (e->v3), FALSE, start, o))) + return FALSE; + break; + case 3: + if (or < 0.) + return FALSE; + break; + } +#ifdef DEBUG + if (or <= 0.) + fprintf (stderr, "or: %g\n", or); +#endif /* DEBUG */ + g_assert (or > -1e-6); + return TRUE; +} + +static void triangulate_loop (GtsSegment * start, + GtsSurface * surface, + GtsPoint * o) +{ + GtsSegment * prev = start, * s; + guint sloppy = 0; +#ifdef DEBUG + guint nt = 0; +#endif /* DEBUG */ + + s = NEXT (start); + while (NEXT (s) != s) { + GtsSegment * next = NEXT (s); + Ear e; + +#ifdef DEBUG + fprintf (stderr, "prev: %p s: %p next: %p\n", prev, s, next); +#endif /* DEBUG */ + + if (!new_ear (s, &e, start, sloppy, o)) { + if (s == start) { + sloppy++; +#ifdef DEBUG + fprintf (stderr, "sloppy: %u\n", sloppy); +#endif /* DEBUG */ + } + prev = s; + s = next; + } + else { + GtsFace * f; + + if (!GTS_IS_EDGE (e.s3)) + e.s3 = GTS_SEGMENT (gts_edge_new (surface->edge_class, e.v1, e.v3)); + f = gts_face_new (surface->face_class, + GTS_EDGE (e.s1), GTS_EDGE (e.s2), GTS_EDGE (e.s3)); + gts_surface_add_face (surface, f); + UNSET (e.s1, RELEVANT); + UNSET (e.s1, INTERIOR); + UNSET (e.s2, RELEVANT); + UNSET (e.s2, INTERIOR); + NEXT (prev) = e.s3; + NEXT (e.s3) = NEXT (e.s2); + NEXT (e.s1) = NEXT (e.s2) = NULL; + start = prev; + s = NEXT (prev); + sloppy = 0; +#ifdef DEBUG + { + gchar name[80]; + FILE * fp; + + fprintf (stderr, " t.%u: (%p:%s,%p:%s,%p:%s)\n", + nt, + e.v1, NAME (e.v1), + e.v2, NAME (e.v2), + e.v3, NAME (e.v3)); + sprintf (name, "/tmp/t.%u", nt++); + fp = fopen (name, "wt"); + // gts_surface_write (surface, fp); + gts_write_triangle (GTS_TRIANGLE (f), NULL, fp); + // write_graph1 (start, interior, surface, fp); + fclose (fp); + print_loop (start, stderr); + } +#endif /* DEBUG */ + } + } + UNSET (s, RELEVANT); + UNSET (s, INTERIOR); + NEXT (s) = NULL; +} + +#ifdef CHECK_ORIENTED +static void check_object (GtsObject * o) +{ + g_assert (o->reserved == NULL); + g_assert (o->flags == 0); +} + +static void check_boundary (GtsEdge * e, GtsSurface * s) +{ + check_object (GTS_OBJECT (e)); + check_object (GTS_OBJECT (GTS_SEGMENT (e)->v1)); + check_object (GTS_OBJECT (GTS_SEGMENT (e)->v2)); + g_assert (gts_edge_face_number (e, s) == 1); +} + +static void check_interior (GtsEdge * e, GtsSurface * s) +{ + guint n; + check_object (GTS_OBJECT (e)); + check_object (GTS_OBJECT (GTS_SEGMENT (e)->v1)); + check_object (GTS_OBJECT (GTS_SEGMENT (e)->v2)); + + n = gts_edge_face_number (e, s); +#ifdef DEBUG + if (n != 2) + gts_surface_print_stats (s, stderr); +#endif /* DEBUG */ + g_assert (n == 2); +} + +static void check_boundary_interior_triangulation (GSList * boundary, + GSList * interior, + GtsSurface * surface) +{ + g_slist_foreach (boundary, (GFunc) check_boundary, surface); + g_slist_foreach (interior, (GFunc) check_interior, surface); +} +#endif /*ifdef CHECK_ORIENTED */ + +static void merge_duplicate (GtsEdge * e) +{ + GtsEdge * dup = gts_edge_is_duplicate (e); + + g_assert (dup); + gts_edge_replace (dup, e); + gts_object_destroy (GTS_OBJECT (dup)); +} + +static void triangulate_boundary_interior (GSList * boundary, + GSList * interior, + GtsSurface * s, + GtsPoint * o) +{ + GSList * iloops, * bloops, * i; + + i = boundary; + while (i) { + SET (i->data, RELEVANT); + i = i->next; + } + i = interior; + while (i) { + SET (i->data, RELEVANT); + SET (i->data, INTERIOR); + i = i->next; + } + + iloops = interior_loops (interior); + bloops = boundary_loops (boundary); + + i = iloops; + while (i) { +#ifdef DEBUG + fprintf (stderr, "--- interior loop ---\n"); + print_loop (i->data, stderr); +#endif /* DEBUG */ + connect_interior_loop (i->data, &interior, &bloops, s, o); + i = i->next; + } + +#ifdef DEBUG + { + FILE * fp = fopen ("/tmp/bloops", "w"); + write_loops (bloops, fp); + fclose (fp); + } +#endif /* DEBUG */ + + i = bloops; + while (i) { +#ifdef DEBUG + fprintf (stderr, "--- boundary loop ---\n"); + print_loop (i->data, stderr); +#endif /* DEBUG */ + triangulate_loop (i->data, s, o); + i = i->next; + } + + g_slist_foreach (interior, (GFunc) merge_duplicate, NULL); + g_slist_free (iloops); + g_slist_free (bloops); + +#ifdef CHECK_ORIENTED + check_boundary_interior_triangulation (boundary, interior, s); +#endif /* CHECK_ORIENTED */ +} + +static void create_edges (GtsSegment * s, GtsSurface * surface) +{ + if (GTS_OBJECT (s)->reserved) { + GList * i = GTS_OBJECT (s)->reserved; + GtsVertex * v1 = i->data; + + GTS_OBJECT (s)->reserved = g_list_prepend (i, + gts_edge_new (surface->edge_class, s->v1, v1)); + while (i) { + GList * next = i->next; + GtsVertex * v2 = next ? next->data : s->v2; + + GTS_OBJECT (i->data)->reserved = NULL; + i->data = gts_edge_new (surface->edge_class, v1, v2); + v1 = v2; + i = next; + } + } +} + +static void add_boundary (GtsSegment * s, GtsSegment * next, + GSList ** boundary) +{ + if (GTS_OBJECT (s)->reserved == NULL) + *boundary = g_slist_prepend (*boundary, s); + else { + if (s->v2 == next->v2 || s->v2 == next->v1) { + GList * i = g_list_last (GTS_OBJECT (s)->reserved); + + while (i) { + *boundary = g_slist_prepend (*boundary, i->data); + i = i->prev; + } + } + else { + GList * i = GTS_OBJECT (s)->reserved; + + while (i) { + *boundary = g_slist_prepend (*boundary, i->data); + i = i->next; + } + } + } +} + +static void triangulate_face (GtsTriangle * t, GtsSurface * surface) +{ + GSList * interior = GTS_OBJECT (t)->reserved; + GSList * boundary = NULL; + GtsSurface * s = gts_surface_new (gts_surface_class (), + surface->face_class, + surface->edge_class, + surface->vertex_class); + gdouble x, y, z; + GtsPoint * p = GTS_POINT (GTS_SEGMENT (t->e1)->v1); + GtsPoint * o; + + GTS_OBJECT (t)->reserved = NULL; + gts_triangle_normal (t, &x, &y, &z); + g_assert (x != 0. || y != 0. || z != 0.); + o = gts_point_new (gts_point_class (), p->x + x, p->y + y, p->z + z); + add_boundary (GTS_SEGMENT (t->e3), GTS_SEGMENT (t->e1), &boundary); + add_boundary (GTS_SEGMENT (t->e2), GTS_SEGMENT (t->e3), &boundary); + add_boundary (GTS_SEGMENT (t->e1), GTS_SEGMENT (t->e2), &boundary); +#ifdef DEBUG + { + static guint nt = 0; + char name[80]; + FILE * fp; + + fprintf (stderr, "%u: triangulating %p\n", nt, t); +if (nt == 28) + fprintf (stderr, "tintin!!!!\n"); + sprintf (name, "/tmp/oc.%u", nt++); + fp = fopen (name, "wt"); + // write_graph (boundary, interior, s, fp); + write_segments (boundary, interior, fp); + fclose (fp); + } +#endif /* DEBUG */ + triangulate_boundary_interior (boundary, interior, s, o); + g_slist_free (interior); + g_slist_free (boundary); + if (GTS_OBJECT (t)->klass->attributes) + gts_surface_foreach_face (s, (GtsFunc) gts_object_attributes, t); + gts_surface_merge (surface, s); + gts_object_destroy (GTS_OBJECT (s)); + gts_object_destroy (GTS_OBJECT (o)); +} + +static void free_edge_list (GtsObject * o) +{ + g_list_free (o->reserved); + o->reserved = NULL; +} + +/** + * gts_surface_inter_new: + * @klass: a #GtsSurfaceInterClass. + * @s1: a #GtsSurface. + * @s2: a #GtsSurface. + * @faces_tree1: a bounding box tree (see gts_bb_tree_new()) for + * the faces of @s1. + * @faces_tree2: a bounding box tree for the faces of @s2. + * @is_open1: whether @s1 is an "open" surface. + * @is_open2: whether @s2 is an "open" surface. + * + * When triangulating the cut faces, the new faces inherit the + * attributes of these original faces through their attributes() + * method. + * + * Returns: a new #GtsSurfaceInter describing the intersection of @s1 + * and @s2. + */ +GtsSurfaceInter * gts_surface_inter_new (GtsSurfaceInterClass * klass, + GtsSurface * s1, + GtsSurface * s2, + GNode * faces_tree1, + GNode * faces_tree2, + gboolean is_open1, + gboolean is_open2) +{ + GtsSurfaceInter * si; + GtsSurface * s; + + g_return_val_if_fail (klass != NULL, NULL); + g_return_val_if_fail (s1 != NULL, NULL); + g_return_val_if_fail (s2 != NULL, NULL); + g_return_val_if_fail (faces_tree1 != NULL, NULL); + g_return_val_if_fail (faces_tree2 != NULL, NULL); + + si = surface_inter_new (klass, s1, s2, faces_tree1, faces_tree2); + + gts_surface_foreach_edge (si->s1, (GtsFunc) create_edges, si->s1); + gts_surface_foreach_edge (si->s2, (GtsFunc) create_edges, si->s2); + +#ifdef DEBUG + fprintf (stderr, "====== triangulating s1 ======\n"); +#endif /* DEBUG */ + s = gts_surface_new (gts_surface_class (), + s1->face_class, + s1->edge_class, + s1->vertex_class); + gts_surface_foreach_face (si->s1, (GtsFunc) triangulate_face, s); + gts_surface_foreach_edge (si->s1, (GtsFunc) free_edge_list, NULL); + gts_object_destroy (GTS_OBJECT (si->s1)); + si->s1 = s; + GTS_OBJECT (si->s1)->reserved = s1; + +#ifdef DEBUG + fprintf (stderr, "====== triangulating s2 ======\n"); +#endif /* DEBUG */ + s = gts_surface_new (gts_surface_class (), + s2->face_class, + s2->edge_class, + s2->vertex_class); + gts_surface_foreach_face (si->s2, (GtsFunc) triangulate_face, s); + gts_surface_foreach_edge (si->s2, (GtsFunc) free_edge_list, NULL); + gts_object_destroy (GTS_OBJECT (si->s2)); + si->s2 = s; + GTS_OBJECT (si->s2)->reserved = s2; + + return si; +} + +static void check_surface_edge (GtsEdge * e, gpointer * data) +{ + gboolean * ok = data[0]; + GtsSurface * s = data[1]; + GtsSurface * bs = GTS_OBJECT (s)->reserved; + guint nf = gts_edge_face_number (e, s); + + if (nf < 1 || nf > 2) { + *ok = FALSE; + g_return_if_fail (nf >= 1 && nf <= 2); + } + if (nf == 1 && gts_edge_face_number (e, bs) == 0) { + *ok = FALSE; + g_return_if_fail (gts_edge_face_number (e, bs) > 0); + } +} + +static void mark_edge (GtsObject * o, gpointer data) +{ + o->reserved = data; +} + +static gint triangle_orientation (GtsTriangle * t, GtsEdge * e) +{ + GtsSegment * s = GTS_SEGMENT (t->e1 == e ? t->e2 + : + t->e2 == e ? t->e3 + : + t->e1); + GtsVertex * v2 = GTS_SEGMENT (e)->v2; + + if (s->v1 == v2 || s->v2 == v2) + return 1; + return -1; +} + +static gboolean check_orientation (GtsEdge * e, GtsSurface * s) +{ + GtsTriangle * t1 = NULL, * t2 = NULL; + GSList * i = e->triangles; + gint o1 = 0, o2 = 0; + + while (i) { + if (GTS_IS_FACE (i->data) && + gts_face_has_parent_surface (i->data, s)) { + if (t1 == NULL) { + t1 = i->data; + o1 = triangle_orientation (t1, e); + } + else if (t2 == NULL) { + t2 = i->data; + o2 = triangle_orientation (t2, e); + g_return_val_if_fail (o1*o2 < 0, FALSE); + } + else + g_assert_not_reached (); + } + i = i->next; + } + g_return_val_if_fail (t1 && t2, FALSE); + return TRUE; +} + +static void check_edge (GtsSegment * s, gpointer * data) +{ + gboolean * ok = data[0]; + GtsSurfaceInter * si = data[1]; + gboolean * closed = data[2]; + GSList * j; + guint nn = 0; + + j = s->v1->segments; + while (j && *ok) { + GtsSegment * s1 = j->data; + + if (s1 != s && GTS_OBJECT (s1)->reserved == si) { + if (s1->v2 != s->v1) + *ok = FALSE; + nn++; + } + j = j->next; + } + j = s->v2->segments; + while (j && *ok) { + GtsSegment * s1 = j->data; + + if (s1 != s && GTS_OBJECT (s1)->reserved == si) { + if (s1->v1 != s->v2) + *ok = FALSE; + nn++; + } + j = j->next; + } + if (nn != 2) + *closed = FALSE; + + if (!check_orientation (GTS_EDGE (s), si->s1)) + *ok = FALSE; + if (!check_orientation (GTS_EDGE (s), si->s2)) + *ok = FALSE; +} + +/** + * gts_surface_inter_check: + * @si: a #GtsSurfaceInter. + * @closed: is set to %TRUE if @si->edges is a closed curve, %FALSE + * otherwise. + * + * Returns: %TRUE if the curve described by @si is an orientable + * manifold, %FALSE otherwise. + */ +gboolean gts_surface_inter_check (GtsSurfaceInter * si, + gboolean * closed) +{ + gboolean ok = TRUE; + gpointer data[3]; + + g_return_val_if_fail (si != NULL, FALSE); + g_return_val_if_fail (closed != NULL, FALSE); + + *closed = si->edges ? TRUE : FALSE; + + /* mark edges as used by si */ + g_slist_foreach (si->edges, (GFunc) mark_edge, si); + + data[0] = &ok; + data[1] = si; + data[2] = closed; + g_slist_foreach (si->edges, (GFunc) check_edge, data); + g_slist_foreach (si->edges, (GFunc) gts_object_reset_reserved, NULL); + + /* check connectivity of the faces of @si */ + if (*closed) { + gpointer data[2]; + + data[0] = &ok; + data[1] = si->s1; + gts_surface_foreach_edge (si->s1, (GtsFunc) check_surface_edge, data); + data[1] = si->s2; + gts_surface_foreach_edge (si->s2, (GtsFunc) check_surface_edge, data); + } + + return ok; +} + +/* Given @e and @f returns a #GtsFace compatible with @f and belonging to + @s1 or @s2 */ +static GtsFace * next_compatible_face (GtsEdge * e, + GtsFace * f, + GtsSurface * s1, + GtsSurface * s2) +{ + GSList * i = e->triangles; + GtsFace * f2 = NULL, * f3 = NULL; + + while (i) { + GtsFace * f1 = i->data; + + if (f1 != f && GTS_IS_FACE (f1)) { + if (gts_face_has_parent_surface (f1, s1)) + return f1; + if (gts_face_has_parent_surface (f1, s2)) { + if (f2 == NULL) f2 = f1; + else if (f3 == NULL) f3 = f1; + else g_assert_not_reached (); /* s2 is a non-manifold surface */ + } + } + i = i->next; + } + if (f3 == NULL) { + if (gts_edge_is_boundary (e, s2)) + return NULL; + return f2; + } + g_assert (gts_face_has_parent_surface (f, s1)); + if (gts_triangles_are_compatible (GTS_TRIANGLE (f), GTS_TRIANGLE (f2), e)) + return f2; + return f3; +} + +static void walk_faces (GtsEdge * e, GtsFace * f, + GtsSurface * s1, + GtsSurface * s2, + GtsSurface * s) +{ + GtsFifo * faces = gts_fifo_new (); + GtsFifo * edges = gts_fifo_new (); + + gts_fifo_push (faces, f); + gts_fifo_push (edges, e); + while ((f = gts_fifo_pop (faces)) && (e = gts_fifo_pop (edges))) { + if (!GTS_OBJECT (f)->reserved) { + GtsTriangle * t = GTS_TRIANGLE (f); + GtsFace * f1; + + gts_surface_add_face (s, f); + GTS_OBJECT (f)->reserved = s; + if (t->e1 != e && !GTS_OBJECT (t->e1)->reserved && + (f1 = next_compatible_face (t->e1, f, s1, s2))) { + gts_fifo_push (faces, f1); + gts_fifo_push (edges, t->e1); + } + if (t->e2 != e && !GTS_OBJECT (t->e2)->reserved && + (f1 = next_compatible_face (t->e2, f, s1, s2))) { + gts_fifo_push (faces, f1); + gts_fifo_push (edges, t->e2); + } + if (t->e3 != e && !GTS_OBJECT (t->e3)->reserved && + (f1 = next_compatible_face (t->e3, f, s1, s2))) { + gts_fifo_push (faces, f1); + gts_fifo_push (edges, t->e3); + } + } + } + gts_fifo_destroy (faces); + gts_fifo_destroy (edges); +} + +/** + * gts_surface_inter_boolean: + * @si: a #GtsSurfaceInter. + * @surface: a #GtsSurface. + * @op: a #GtsBooleanOperation. + * + * Adds to @surface the part of the surface described by @si and @op. + */ +void gts_surface_inter_boolean (GtsSurfaceInter * si, + GtsSurface * surface, + GtsBooleanOperation op) +{ + GtsSurface * s = NULL; + gint orient = 1; + GSList * i; + + g_return_if_fail (si != NULL); + g_return_if_fail (surface != NULL); + + switch (op) { + case GTS_1_OUT_2: s = si->s1; orient = 1; break; + case GTS_1_IN_2: s = si->s1; orient = -1; break; + case GTS_2_OUT_1: s = si->s2; orient = -1; break; + case GTS_2_IN_1: s = si->s2; orient = 1; break; + default: g_assert_not_reached (); + } + + /* mark edges as belonging to intersection */ + g_slist_foreach (si->edges, (GFunc) mark_edge, si); + + i = si->edges; + while (i) { + GtsEdge * e = i->data; + GSList * j = e->triangles; + + while (j) { + if (gts_face_has_parent_surface (j->data, s) && + orient*triangle_orientation (j->data, e) > 0) { +#ifdef DEBUG_BOOLEAN + GtsFace * boundary = gts_edge_is_boundary (e, surface); + + g_assert (!boundary || boundary == j->data); +#endif /* DEBUG_BOOLEAN */ + walk_faces (e, j->data, s, GTS_OBJECT (s)->reserved, surface); + break; + } + j = j->next; + } + i = i->next; + } + g_slist_foreach (si->edges, (GFunc) gts_object_reset_reserved, NULL); + gts_surface_foreach_face (surface, + (GtsFunc) gts_object_reset_reserved, NULL); +} + +static void self_intersecting (GtsBBox * bb1, GtsBBox * bb2, + gpointer * d) +{ + GtsTriangle * t1 = bb1->bounded; + GtsTriangle * t2 = bb2->bounded; + + if (t1 != t2) { + GtsSegment * s1 = GTS_SEGMENT (t1->e1); + GtsSegment * s2 = GTS_SEGMENT (t1->e2); + GtsSegment * s3 = GTS_SEGMENT (t1->e3); + GtsSegment * s4 = GTS_SEGMENT (t2->e1); + GtsSegment * s5 = GTS_SEGMENT (t2->e2); + GtsSegment * s6 = GTS_SEGMENT (t2->e3); + GtsPoint * pi; + + if ((!gts_segments_touch (s4, s1) && + !gts_segments_touch (s4, s2) && + !gts_segments_touch (s4, s3) && + (pi = segment_triangle_intersection (s4, t1, gts_point_class ())) + != NULL) || + (!gts_segments_touch (s5, s1) && + !gts_segments_touch (s5, s2) && + !gts_segments_touch (s5, s3) && + (pi = segment_triangle_intersection (s5, t1, gts_point_class ())) + != NULL) || + (!gts_segments_touch (s6, s1) && + !gts_segments_touch (s6, s2) && + !gts_segments_touch (s6, s3) && + (pi = segment_triangle_intersection (s6, t1, gts_point_class ())) + != NULL)) { + GtsBBTreeTraverseFunc func = d[0]; + gpointer data = d[1]; + gboolean * self_inter = d[2]; + + gts_object_destroy (GTS_OBJECT (pi)); + *self_inter = TRUE; + (* func) (bb1, bb2, data); + } + } +} + +/** + * gts_surface_foreach_intersecting_face: + * @s: a #GtsSurface. + * @func: a #GtsBBTreeTraverseFunc. + * @data: user data to pass to @func. + * + * Calls @func for each intersecting pair of faces of @s. + * + * Returns: %TRUE if @func was called at least once, %FALSE otherwise. + */ +gboolean gts_surface_foreach_intersecting_face (GtsSurface * s, + GtsBBTreeTraverseFunc func, + gpointer data) +{ + GNode * tree; + gpointer d[3]; + gboolean self_inter = FALSE; + + g_return_val_if_fail (s != NULL, FALSE); + g_return_val_if_fail (func != NULL, FALSE); + + tree = gts_bb_tree_surface (s); + d[0] = func; + d[1] = data; + d[2] = &self_inter; + gts_bb_tree_traverse_overlapping (tree, tree, + (GtsBBTreeTraverseFunc) self_intersecting, + d); + gts_bb_tree_destroy (tree, TRUE); + + return self_inter; +} + +static void add_intersecting (GtsBBox * bb1, GtsBBox * bb2, + GtsSurface * intersected) +{ + gts_surface_add_face (intersected, bb1->bounded); + gts_surface_add_face (intersected, bb2->bounded); +} + +/** + * gts_surface_is_self_intersecting: + * @s: a #GtsSurface. + * + * Returns: a new #GtsSurface containing the faces of @s which are + * self-intersecting or %NULL if no faces of @s are self-intersecting. + */ +GtsSurface * gts_surface_is_self_intersecting (GtsSurface * s) +{ + GtsSurface * intersected; + + g_return_val_if_fail (s != NULL, NULL); + + intersected = gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass), + s->face_class, + s->edge_class, + s->vertex_class); + if (!gts_surface_foreach_intersecting_face (s, + (GtsBBTreeTraverseFunc) add_intersecting, intersected)) { + gts_object_destroy (GTS_OBJECT (intersected)); + intersected = NULL; + } + return intersected; +} Index: work/obsolete/toporouter/src_3rd/gts/cdt.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/cdt.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/cdt.c (revision 6803) @@ -0,0 +1,1173 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + + +#include +#include "gts.h" + +#ifdef USE_SURFACE_BTREE + +static gint find_closest (GtsTriangle * t, gpointer value, gpointer * data) +{ + guint * ns = data[2]; + guint * n = data[3]; + + if (*n >= *ns) + return TRUE; + else { + gdouble * dmin = data[0]; + gpointer * closest = data[1]; + GtsPoint * p = data[4]; + + if (gts_triangle_orientation (t) > 0.) { + GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1); + gdouble d = (p->x - p1->x)*(p->x - p1->x) + (p->y - p1->y)*(p->y - p1->y); + + if (d < *dmin) { + *dmin = d; + *closest = t; + } + (*n)++; + } + } + return FALSE; +} + +/* select the face closest to @p among n^1/3 randomly picked faces + * of @surface */ +static GtsFace * closest_face (GtsSurface * s, GtsPoint * p) +{ + guint n = 0, nt, ns; + gdouble dmin = G_MAXDOUBLE; + GtsFace * closest = NULL; + gpointer data[5]; + + nt = gts_surface_face_number (s); + if (!nt) + return NULL; + ns = exp (log ((gdouble) nt)/3.); + + data[0] = &dmin; + data[1] = &closest; + data[2] = &ns; + data[3] = &n; + data[4] = p; + g_tree_traverse (s->faces, (GTraverseFunc) find_closest, G_IN_ORDER, data); + + return closest; +} + +#else /* not USE_SURFACE_BTREE */ + +typedef struct _SFindClosest SFindClosest; + +struct _SFindClosest { + gdouble dmin; + GtsFace *closest; + GtsPoint * p; + gint stop; +}; + +# if GLIB_CHECK_VERSION(2,4,0) +/* finally, with g_hash_table_find we are able to stop iteration over the hash + table in the middle */ + +static gboolean find_closest (gpointer key, gpointer value, gpointer user_data) +{ + SFindClosest * data = (SFindClosest *) user_data; + GtsFace * f = GTS_FACE (value); + + if (gts_triangle_orientation (GTS_TRIANGLE (f)) > 0.) { + GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (GTS_TRIANGLE (f)->e1)->v1); + gdouble d = ((data->p->x - p1->x)*(data->p->x - p1->x) + + (data->p->y - p1->y)*(data->p->y - p1->y)); + + if (d < data->dmin) { + data->dmin = d; + data->closest = f; + } + } + data->stop--; + return !(data->stop > 0); +} + +static GtsFace * closest_face (GtsSurface * s, GtsPoint * p) +{ + SFindClosest fc; + + fc.dmin = G_MAXDOUBLE; + fc.closest = NULL; + fc.p = p; + fc.stop = (gint) exp (log ((gdouble) g_hash_table_size (s->faces))/3.); + g_hash_table_find (s->faces, find_closest, &fc); + + return fc.closest; +} + +# else /* VERSION < 2.4.0 */ + +static void +find_closest (gpointer key, gpointer value, gpointer user_data) +{ + SFindClosest * data = (SFindClosest *) user_data; + GtsFace * f = GTS_FACE (value); + + if (gts_triangle_orientation (GTS_TRIANGLE (f)) > 0.) { + GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (GTS_TRIANGLE (f)->e1)->v1); + gdouble d = ((data->p->x - p1->x)*(data->p->x - p1->x) + + (data->p->y - p1->y)*(data->p->y - p1->y)); + + if (d < data->dmin) { + data->dmin = d; + data->closest = f; + } + } + data->stop--; +} + +/* select the face closest to @p among n^1/3 randomly picked faces + * of @surface */ +static GtsFace * closest_face (GtsSurface * s, GtsPoint * p) +{ + SFindClosest fc; + + if (!g_hash_table_size (s->faces)) + return NULL; + + fc.dmin = G_MAXDOUBLE; + fc.closest = NULL; + fc.p = p; + fc.stop = (gint) exp (log ((gdouble) g_hash_table_size (s->faces))/3.); + g_hash_table_foreach (s->faces, find_closest, &fc); + return fc.closest; +} +# endif /* VERSION < 2.4.0 */ +#endif /* not USE_SURFACE_BTREE */ + +/* returns the face belonging to @surface and neighbor of @f via @e */ +static GtsFace * neighbor (GtsFace * f, + GtsEdge * e, + GtsSurface * surface) +{ + GSList * i = e->triangles; + GtsTriangle * t = GTS_TRIANGLE (f); + + while (i) { + GtsTriangle * t1 = i->data; + if (t1 != t && + GTS_IS_FACE (t1) && + gts_face_has_parent_surface (GTS_FACE (t1), surface)) + return GTS_FACE (t1); + i = i->next; + } + return NULL; +} + +/* given a triangle @t and a segment s (@o -> @p). + @o must be in @t. Returns the + edge of @t which is intersected by s or %NULL if @p is also + contained in @t (on_summit is set to %FALSE) or if s intersects @t + exactly on one of its summit (on_summit is set to %TRUE). */ +static GtsEdge * triangle_next_edge (GtsTriangle * t, + GtsPoint * o, GtsPoint * p, + gboolean * on_summit) +{ + GtsVertex * v1, * v2, * v3; + GtsEdge * e1, * e2, * e3; + gdouble orient = 0.0; + + gts_triangle_vertices_edges (t, NULL, + &v1, &v2, &v3, + &e1, &e2, &e3); + + *on_summit = FALSE; + orient = gts_point_orientation (o, GTS_POINT (v1), p); + if (orient > 0.0) { + orient = gts_point_orientation (o, GTS_POINT (v2), p); + if (orient > 0.0) { + if (gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p) >= 0.0) + return NULL; + return e2; + } + if (orient < 0.0) { + if (gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), p) >= 0.0) + return NULL; + return e1; + } + if (gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), p) < 0.0) + *on_summit = TRUE; + return NULL; + } + + if (orient < 0.0) { + orient = gts_point_orientation (o, GTS_POINT (v3), p); + if (orient > 0.0) { + if (gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), p) >= 0.0) + return NULL; + return e3; + } + if (orient < 0.0) { + if (gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p) >= 0.0) + return NULL; + return e2; + } + if (gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), p) < 0.0) + *on_summit = TRUE; + return NULL; + } + + if (gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p) < 0.0) + return e2; + if (gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), p) < 0.0) + *on_summit = TRUE; + return NULL; +} + +static void triangle_barycenter (GtsTriangle * t, GtsPoint * b) +{ + GtsPoint * p = GTS_POINT (gts_triangle_vertex (t)); + b->x = (p->x + + GTS_POINT (GTS_SEGMENT(t->e1)->v1)->x + + GTS_POINT (GTS_SEGMENT(t->e1)->v2)->x)/3.; + b->y = (p->y + + GTS_POINT (GTS_SEGMENT(t->e1)->v1)->y + + GTS_POINT (GTS_SEGMENT(t->e1)->v2)->y)/3.; +} + +static GtsFace * point_locate (GtsPoint * o, + GtsPoint * p, + GtsFace * f, + GtsSurface * surface) +{ + GtsEdge * prev; + gboolean on_summit; + GtsVertex * v1, * v2, * v3; + GtsEdge * e2, * e3; + + prev = triangle_next_edge (GTS_TRIANGLE (f), o, p, &on_summit); + + if (!prev) { + GtsFace * f1; + + if (!on_summit) + return f; /* p is inside f */ + + /* s intersects f exactly on a summit: restarts from a neighbor of f */ + if ((f1 = neighbor (f, GTS_TRIANGLE (f)->e1, surface)) || + (f1 = neighbor (f, GTS_TRIANGLE (f)->e2, surface)) || + (f1 = neighbor (f, GTS_TRIANGLE (f)->e3, surface))) { + triangle_barycenter (GTS_TRIANGLE (f1), o); + return point_locate (o, p, f1, surface); + } + return NULL; + } + + f = neighbor (f, prev, surface); + if (f) + gts_triangle_vertices_edges (GTS_TRIANGLE (f), prev, + &v1, &v2, &v3, &prev, &e2, &e3); + while (f) { + gdouble orient = gts_point_orientation (o, GTS_POINT (v3), p); + + if (orient < 0.0) { + if (gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p) >= 0.0) + return f; /* p is inside f */ + f = neighbor (f, e2, surface); + prev = e2; + v1 = v3; + } + else if (orient > 0.0) { + if (gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), p) >= 0.0) + return f; /* p is inside f */ + f = neighbor (f, e3, surface); + prev = e3; + v2 = v3; + } + else { + GtsFace * f1; + + if (gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p) >= 0.0) + return f; /* p is inside f */ + + /* s intersects f exactly on v3: restarts from a neighbor of f */ + if ((f1 = neighbor (f, e2, surface)) || + (f1 = neighbor (f, e3, surface))) { + triangle_barycenter (GTS_TRIANGLE (f1), o); + return point_locate (o, p, f1, surface); + } + return NULL; + } + /* update e2, e3, v3 for the new triangle */ + if (f) { + if (prev == GTS_TRIANGLE (f)->e1) { + e2 = GTS_TRIANGLE (f)->e2; e3 = GTS_TRIANGLE (f)->e3; + } + else if (prev == GTS_TRIANGLE (f)->e2) { + e2 = GTS_TRIANGLE (f)->e3; e3 = GTS_TRIANGLE (f)->e1; + } + else { + e2 = GTS_TRIANGLE (f)->e1; e3 = GTS_TRIANGLE (f)->e2; + } + if (GTS_SEGMENT (e2)->v1 == v1 || GTS_SEGMENT (e2)->v1 == v2) + v3 = GTS_SEGMENT (e2)->v2; + else + v3 = GTS_SEGMENT (e2)->v1; + } + } + return NULL; +} + +/** + * gts_point_locate: + * @p: a #GtsPoint. + * @surface: a #GtsSurface. + * @guess: %NULL or a face of @surface close to @p. + * + * Locates the face of the planar projection of @surface containing + * @p. The planar projection of @surface must define a connected set + * of triangles without holes and bounded by a convex boundary. The + * algorithm is randomized and performs in O(n^1/3) expected time + * where n is the number of triangles of @surface. + * + * If a good @guess is given the point location can be significantly faster. + * + * Returns: a #GtsFace of @surface containing @p or %NULL if @p is not + * contained within the boundary of @surface. + */ +GtsFace * gts_point_locate (GtsPoint * p, + GtsSurface * surface, + GtsFace * guess) +{ + GtsFace * fr; + GtsPoint * o; + + g_return_val_if_fail (p != NULL, NULL); + g_return_val_if_fail (surface != NULL, NULL); + g_return_val_if_fail (guess == NULL || + gts_face_has_parent_surface (guess, surface), NULL); + + if (guess == NULL) + guess = closest_face (surface, p); + else + g_return_val_if_fail (gts_triangle_orientation (GTS_TRIANGLE (guess)) > 0., NULL); + + if (guess == NULL) + return NULL; + + o = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class ()))); + triangle_barycenter (GTS_TRIANGLE (guess), o); + fr = point_locate (o, p, guess, surface); + gts_object_destroy (GTS_OBJECT (o)); + + return fr; +} + + +/** + * gts_constraint_class: + * + * Returns: the #GtsConstraintClass. + */ +GtsConstraintClass * gts_constraint_class (void) +{ + static GtsConstraintClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo constraint_info = { + "GtsConstraint", + sizeof (GtsConstraint), + sizeof (GtsConstraintClass), + (GtsObjectClassInitFunc) NULL, + (GtsObjectInitFunc) NULL, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_edge_class ()), + &constraint_info); + } + + return klass; +} + +static void split_list (GtsListFace * f, GtsListFace * f1, GtsListFace * f2, + GtsPoint * p1, GtsPoint * p2, + GSList ** last1, GSList ** last2) +{ + GSList * i = f->points, * l1 = *last1, * l2 = *last2; + + while (i) { + GtsPoint * p = i->data; + + if (gts_point_orientation (p1, p2, p) >= 0.) { + if (l1) l1->next = i; else f1->points = i; + l1 = i; + } + else { + if (l2) l2->next = i; else f2->points = i; + l2 = i; + } + i = i->next; + } + f->points = NULL; + *last1 = l1; + *last2 = l2; +} + +/* cf. figure misc/swap.fig */ +static void swap_if_in_circle (GtsFace * f1, + GtsVertex * v1, + GtsVertex * v2, + GtsVertex * v3, + GtsEdge * e1, + GtsEdge * e2, + GtsEdge * e3, + GtsSurface * surface) +{ + GtsFace * f2; + GtsEdge * e4, *e5; + GtsVertex * v4; + + if (GTS_IS_CONSTRAINT (e1)) /* @e1 is a constraint can not swap */ + return; + + f2 = neighbor (f1, e1, surface); + if (f2 == NULL) /* @e1 is a boundary of @surface */ + return; + + if (GTS_TRIANGLE (f2)->e1 == e1) { + e4 = GTS_TRIANGLE (f2)->e2; e5 = GTS_TRIANGLE (f2)->e3; + } + else if (GTS_TRIANGLE (f2)->e2 == e1) { + e4 = GTS_TRIANGLE (f2)->e3; e5 = GTS_TRIANGLE (f2)->e1; + } + else { + e4 = GTS_TRIANGLE (f2)->e1; e5 = GTS_TRIANGLE (f2)->e2; + } + if (GTS_SEGMENT (e4)->v1 == GTS_SEGMENT (e1)->v1 || + GTS_SEGMENT (e4)->v1 == GTS_SEGMENT (e1)->v2) + v4 = GTS_SEGMENT (e4)->v2; + else + v4 = GTS_SEGMENT (e4)->v1; + + if (gts_point_in_circle (GTS_POINT (v4), GTS_POINT (v1), + GTS_POINT (v2), GTS_POINT (v3)) > 0.0) { + GtsEdge * en; + GtsSegment * sn = gts_vertices_are_connected (v3, v4); + GtsFace * f3, * f4; + + if (!GTS_IS_EDGE (sn)) + en = gts_edge_new (surface->edge_class, v3, v4); + else + en = GTS_EDGE (sn); + + f3 = gts_face_new (surface->face_class, en, e5, e2); + gts_object_attributes (GTS_OBJECT (f3), GTS_OBJECT (f1)); + f4 = gts_face_new (surface->face_class, en, e3, e4); + gts_object_attributes (GTS_OBJECT (f4), GTS_OBJECT (f2)); + + if (GTS_IS_LIST_FACE (f3)) { + GSList * last3 = NULL, * last4 = NULL; + + if (GTS_IS_LIST_FACE (f1)) + split_list (GTS_LIST_FACE (f1), GTS_LIST_FACE (f3), GTS_LIST_FACE (f4), + GTS_POINT (v3), GTS_POINT (v4), &last3, &last4); + if (GTS_IS_LIST_FACE (f2)) + split_list (GTS_LIST_FACE (f2), GTS_LIST_FACE (f3), GTS_LIST_FACE (f4), + GTS_POINT (v3), GTS_POINT (v4), &last3, &last4); + if (last3) last3->next = NULL; + if (last4) last4->next = NULL; + } + + gts_surface_remove_face (surface, f1); + gts_surface_remove_face (surface, f2); + gts_surface_add_face (surface, f3); + gts_surface_add_face (surface, f4); + + swap_if_in_circle (f3, v4, v2, v3, e5, e2, en, surface); + swap_if_in_circle (f4, v1, v4, v3, e4, en, e3, surface); + } +} + +/** + * gts_delaunay_add_vertex_to_face: + * @surface: a #GtsSurface. + * @v: a #GtsVertex. + * @f: a #GtsFace belonging to @surface. + * + * Adds vertex @v to the face @f of the Delaunay triangulation defined + * by @surface. + * + * Returns: %NULL is @v has been successfully added to @surface or was + * already contained in @surface or a #GtsVertex having the same x and + * y coordinates as @v. + */ +GtsVertex * gts_delaunay_add_vertex_to_face (GtsSurface * surface, + GtsVertex * v, + GtsFace * f) +{ + GtsEdge * e1, * e2, * e3; + GtsSegment * s4, * s5, * s6; + GtsEdge * e4, * e5, * e6; + GtsVertex * v1, * v2, * v3; + GtsFace * nf[3]; + + g_return_val_if_fail (surface != NULL, v); + g_return_val_if_fail (v != NULL, v); + g_return_val_if_fail (f != NULL, v); + + gts_triangle_vertices_edges (GTS_TRIANGLE (f), NULL, + &v1, &v2, &v3, &e1, &e2, &e3); + if (v == v1 || v == v2 || v == v3) /* v already in @surface */ + return NULL; + if (GTS_POINT (v)->x == GTS_POINT (v1)->x && + GTS_POINT (v)->y == GTS_POINT (v1)->y) + return v1; + if (GTS_POINT (v)->x == GTS_POINT (v2)->x && + GTS_POINT (v)->y == GTS_POINT (v2)->y) + return v2; + if (GTS_POINT (v)->x == GTS_POINT (v3)->x && + GTS_POINT (v)->y == GTS_POINT (v3)->y) + return v3; + + s4 = gts_vertices_are_connected (v, v1); + if (!GTS_IS_EDGE (s4)) + e4 = gts_edge_new (surface->edge_class, v, v1); + else + e4 = GTS_EDGE (s4); + s5 = gts_vertices_are_connected (v, v2); + if (!GTS_IS_EDGE (s5)) + e5 = gts_edge_new (surface->edge_class, v, v2); + else + e5 = GTS_EDGE (s5); + s6 = gts_vertices_are_connected (v, v3); + if (!GTS_IS_EDGE (s6)) + e6 = gts_edge_new (surface->edge_class, v, v3); + else + e6 = GTS_EDGE (s6); + + /* cf. figure misc/swap.fig */ + nf[0] = gts_face_new (surface->face_class, e4, e1, e5); + gts_object_attributes (GTS_OBJECT (nf[0]), GTS_OBJECT (f)); + nf[1] = gts_face_new (surface->face_class, e5, e2, e6); + gts_object_attributes (GTS_OBJECT (nf[1]), GTS_OBJECT (f)); + nf[2] = gts_face_new (surface->face_class, e6, e3, e4); + gts_object_attributes (GTS_OBJECT (nf[2]), GTS_OBJECT (f)); + + if (GTS_IS_LIST_FACE (f) && GTS_IS_LIST_FACE (nf[0])) { + GSList * i = GTS_LIST_FACE (f)->points, * last[3] = { NULL, NULL, NULL }; + + while (i) { + GtsPoint * p = i->data; + GSList * next = i->next; + guint j; + + if (p != GTS_POINT (v)) { + if (gts_point_orientation (GTS_POINT (v), GTS_POINT (v1), p) >= 0.) { + gdouble o = gts_point_orientation (GTS_POINT (v), GTS_POINT (v2), p); + + if (o != 0.) + j = o > 0. ? 1 : 0; + else + j = gts_point_orientation (GTS_POINT (v), GTS_POINT (v3), p) + > 0. ? 0 : 1; + } + else if (gts_point_orientation (GTS_POINT (v), GTS_POINT (v3), p) > 0.) + j = 2; + else + j = 1; + if (last[j]) + last[j]->next = i; + else + GTS_LIST_FACE (nf[j])->points = i; + last[j] = i; + } + else + g_slist_free_1 (i); + i = next; + } + GTS_LIST_FACE (f)->points = NULL; + if (last[0]) last[0]->next = NULL; + if (last[1]) last[1]->next = NULL; + if (last[2]) last[2]->next = NULL; + } + + gts_surface_remove_face (surface, f); + gts_surface_add_face (surface, nf[0]); + gts_surface_add_face (surface, nf[1]); + gts_surface_add_face (surface, nf[2]); + + swap_if_in_circle (nf[0], v1, v2, v, e1, e5, e4, surface); + swap_if_in_circle (nf[1], v2, v3, v, e2, e6, e5, surface); + swap_if_in_circle (nf[2], v3, v1, v, e3, e4, e6, surface); + + return NULL; +} + +/** + * gts_delaunay_add_vertex: + * @surface: a #GtsSurface. + * @v: a #GtsVertex. + * @guess: %NULL or a #GtsFace belonging to @surface to be used as an initial + * guess for point location. + * + * Adds vertex @v to the Delaunay triangulation defined by + * @surface. If @v is not contained in the convex hull bounding + * @surface, @v is not added to the triangulation. + * + * Returns: %NULL is @v has been successfully added to @surface or was + * already contained in @surface, @v if @v is not contained in the + * convex hull bounding surface or a #GtsVertex having the same x and + * y coordinates as @v. + */ +GtsVertex * gts_delaunay_add_vertex (GtsSurface * surface, + GtsVertex * v, + GtsFace * guess) +{ + GtsFace * f; + + g_return_val_if_fail (surface != NULL, v); + g_return_val_if_fail (v != NULL, v); + + if (!(f = gts_point_locate (GTS_POINT (v), surface, guess))) + return v; + return gts_delaunay_add_vertex_to_face (surface, v, f); +} + +static gboolean polygon_in_circle (GSList * poly, + GtsPoint * p1, + GtsPoint * p2, + GtsPoint * p3) +{ + GtsVertex * v1 = NULL, * v2 = NULL; + + while (poly) { + GtsSegment * s = poly->data; + GtsVertex * v; + v = s->v1; + if (v != v1 && v != v2 && + v != GTS_VERTEX (p1) && + v != GTS_VERTEX (p2) && + v != GTS_VERTEX (p3) && + gts_point_in_circle (GTS_POINT (v), p1, p2, p3) > 0.) + return TRUE; + v = s->v2; + if (v != v1 && v != v2 && + v != GTS_VERTEX (p1) && + v != GTS_VERTEX (p2) && + v != GTS_VERTEX (p3) && + gts_point_in_circle (GTS_POINT (v), p1, p2, p3) > 0.) + return TRUE; + v1 = s->v1; + v2 = s->v2; + poly = poly->next; + } + return FALSE; +} + +static void triangulate_polygon (GSList * poly, + GtsSurface * surface, + GtsFace * ref) +{ + GSList * i, * poly1, * poly2; + GtsVertex * v1, * v2, * v3 = NULL; + gboolean found = FALSE; + GtsSegment * s, * s1, * s2; + GtsEdge * e1, * e2; + GtsFace * f; + + if (poly == NULL || poly->next == NULL) { + g_slist_free (poly); + return; + } + + s = poly->data; + s1 = poly->next->data; + if (s->v1 == s1->v1 || s->v1 == s1->v2) { + v1 = s->v2; + v2 = s->v1; + } + else { + g_assert (s->v2 == s1->v1 || s->v2 == s1->v2); + v1 = s->v1; + v2 = s->v2; + } + + i = poly->next; + v3 = v2; + while (i && !found) { + s1 = i->data; + if (s1->v1 == v3) + v3 = s1->v2; + else { + g_assert (s1->v2 == v3); + v3 = s1->v1; + } + if (v3 != v1 && + gts_point_orientation (GTS_POINT (v1), + GTS_POINT (v2), + GTS_POINT (v3)) >= 0. && + !polygon_in_circle (poly, + GTS_POINT (v1), + GTS_POINT (v2), + GTS_POINT (v3))) + found = TRUE; + else + i = i->next; + } + + if (!found) { + g_slist_free (poly); + return; + } + + s1 = gts_vertices_are_connected (v2, v3); + if (!GTS_IS_EDGE (s1)) + e1 = gts_edge_new (surface->edge_class, v2, v3); + else + e1 = GTS_EDGE (s1); + s2 = gts_vertices_are_connected (v3, v1); + if (!GTS_IS_EDGE (s2)) + e2 = gts_edge_new (surface->edge_class, v3, v1); + else + e2 = GTS_EDGE (s2); + f = gts_face_new (surface->face_class, GTS_EDGE (s), e1, e2); + gts_object_attributes (GTS_OBJECT (f), GTS_OBJECT (ref)); + gts_surface_add_face (surface, f); + + poly1 = poly->next; + g_slist_free_1 (poly); + if (i->next && e2 != i->next->data) + poly2 = g_slist_prepend (i->next, e2); + else + poly2 = i->next; + if (e1 != i->data) + i->next = g_slist_prepend (NULL, e1); + else + i->next = NULL; + + triangulate_polygon (poly1, surface, ref); + triangulate_polygon (poly2, surface, ref); +} + +/** + * gts_delaunay_remove_vertex: + * @surface: a #GtsSurface. + * @v: a #GtsVertex. + * + * Removes @v from the Delaunay triangulation defined by @surface and + * restores the Delaunay property. Vertex @v must not be used by any + * constrained edge otherwise the triangulation is not guaranteed to + * be Delaunay. + */ +void gts_delaunay_remove_vertex (GtsSurface * surface, GtsVertex * v) +{ + GSList * triangles, * i; + GtsFace * ref = NULL; + + g_return_if_fail (surface != NULL); + g_return_if_fail (v != NULL); + + i = triangles = gts_vertex_triangles (v, NULL); + while (i && !ref) { + if (GTS_IS_FACE (i->data) && + gts_face_has_parent_surface (i->data, surface)) + ref = i->data; + i = i->next; + } + if (!ref) { + g_slist_free (triangles); + g_return_if_fail (ref); + } + triangulate_polygon (gts_vertex_fan_oriented (v, surface), surface, ref); + i = triangles; + while (i) { + if (GTS_IS_FACE (i->data) && + gts_face_has_parent_surface (i->data, surface)) + gts_surface_remove_face (surface, i->data); + i = i->next; + } + g_slist_free (triangles); +} + +#define NEXT_CUT(edge, edge1, list) { next = neighbor (f, edge, surface);\ + remove_triangles (e, surface);\ + if (!constraint && !e->triangles)\ + gts_object_destroy (GTS_OBJECT (e));\ + g_assert (next);\ + *list = g_slist_prepend (*list, edge1);\ + return g_slist_concat (constraint,\ + remove_intersected_edge (s, edge,\ + next, surface, left, right));\ + } + +static void remove_triangles (GtsEdge * e, GtsSurface * s) +{ + GSList * i = e->triangles; + + while (i) { + GSList * next = i->next; + + if (GTS_IS_FACE (i->data) && gts_face_has_parent_surface (i->data, s)) + gts_surface_remove_face (s, i->data); + i = next; + } +} + +static GSList * +remove_intersected_edge (GtsSegment * s, + GtsEdge * e, + GtsFace * f, + GtsSurface * surface, + GSList ** left, GSList ** right) +{ + GtsVertex * v1, * v2, * v3; + GtsEdge * e1, * e2; + gdouble o1, o2; + GtsFace * next; + GSList * constraint = NULL; + + if (GTS_IS_CONSTRAINT (e)) + constraint = g_slist_prepend (NULL, e); + + gts_triangle_vertices_edges (GTS_TRIANGLE (f), e, + &v1, &v2, &v3, &e, &e1, &e2); + + o1 = gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), + GTS_POINT (s->v2)); + o2 = gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), + GTS_POINT (s->v2)); + + if (o1 == 0. && o2 == 0.) { +/* if(o2 != 0.) { + fprintf(stderr, "o1 = %f o2 = %f\n", o1, o2); + fprintf(stderr, "v1 = %f, %f\n", GTS_POINT(v1)->x, GTS_POINT(v1)->y); + fprintf(stderr, "v2 = %f, %f\n", GTS_POINT(v2)->x, GTS_POINT(v2)->y); + fprintf(stderr, "v3 = %f, %f\n", GTS_POINT(v3)->x, GTS_POINT(v3)->y); + fprintf(stderr, "s->v2 = %f, %f\n", GTS_POINT(s->v2)->x, GTS_POINT(s->v2)->y); + + g_assert (o2 == 0.); + }*/ + // if(o2 == 0.) { + remove_triangles (e, surface); + if (!constraint && !e->triangles) + gts_object_destroy (GTS_OBJECT (e)); + *left = g_slist_prepend (*left, e2); + *right = g_slist_prepend (*right, e1); +// } + } + else if (o1 > 0.) { + g_assert (o2 <= 0.); + NEXT_CUT (e2, e1, right) + } + else if (o2 >= 0.) + NEXT_CUT (e1, e2, left) + else { + gdouble o3 = gts_point_orientation (GTS_POINT (s->v1), GTS_POINT (s->v2), + GTS_POINT (v3)); + if (o3 > 0.) + NEXT_CUT (e1, e2, left) + else + NEXT_CUT (e2, e1, right) + } + return constraint; +} + +static GSList * +remove_intersected_vertex (GtsSegment * s, + GtsVertex * v, + GtsSurface * surface, + GSList ** left, + GSList ** right, + GtsFace ** ref) +{ + GSList * triangles = gts_vertex_triangles (v, NULL); + GSList * i; + + i = triangles; + while (i) { + GtsTriangle * t = i->data; + if (GTS_IS_FACE (t) && + gts_face_has_parent_surface (GTS_FACE (t), surface)) { + GtsVertex * v1, * v2, * v3; + gdouble o1, o2; + + gts_triangle_vertices (t, &v1, &v2, &v3); + if (v == v2) { + v2 = v3; + v3 = v1; + } + else if (v == v3) { + v3 = v2; + v2 = v1; + } + else + g_assert (v == v1); + + if ((o1 = gts_point_orientation (GTS_POINT (v), GTS_POINT (v2), + GTS_POINT (s->v2))) >= 0. && + (o2 = gts_point_orientation (GTS_POINT (v3), GTS_POINT (v), + GTS_POINT (s->v2))) >= 0.) { + gdouble o3 = gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), + GTS_POINT (s->v2)); + GtsEdge * e = gts_triangle_edge_opposite (t, v); + GtsEdge * e1, * e2; + GtsFace * next = neighbor (GTS_FACE (t), e, surface); + + *ref = GTS_FACE (t); + gts_triangle_vertices_edges (t, e, &v2, &v3, &v, &e, &e2, &e1); + + g_slist_free (triangles); + + if (o3 >= 0.) /* @s->v2 is inside (or on the edge) of t */ + return NULL; + + gts_allow_floating_faces = TRUE; + gts_surface_remove_face (surface, GTS_FACE (t)); + gts_allow_floating_faces = FALSE; + + *left = g_slist_prepend (*left, e2); + *right = g_slist_prepend (*right, e1); + + g_assert (next); + return remove_intersected_edge (s, e, next, surface, left, right); + } + } + i = i->next; + } + + g_assert_not_reached (); + return NULL; +} + +/** + * gts_delaunay_add_constraint: + * @surface: a #GtsSurface. + * @c: a #GtsConstraint. + * + * Add constraint @c to the constrained Delaunay triangulation defined by + * @surface. + * + * Returns: a list of #GtsConstraint conflicting (i.e. intersecting) with @c + * which were removed from @surface (%NULL if there was none). + */ +GSList * gts_delaunay_add_constraint (GtsSurface * surface, + GtsConstraint * c) +{ + GSList * constraints; + GtsVertex * v1; //, * v2; + GSList * left = NULL, * right = NULL; + GtsFace * ref = NULL; + + g_return_val_if_fail (surface != NULL, NULL); + g_return_val_if_fail (c != NULL, NULL); + g_return_val_if_fail (GTS_IS_CONSTRAINT (c), NULL); + + v1 = GTS_SEGMENT (c)->v1; + //v2 = GTS_SEGMENT (c)->v2; + + gts_allow_floating_edges = TRUE; + constraints = remove_intersected_vertex (GTS_SEGMENT (c), v1, surface, + &left, &right, &ref); + gts_allow_floating_edges = FALSE; +#if 1 + triangulate_polygon (g_slist_prepend (g_slist_reverse (right), c), + surface, ref); + triangulate_polygon (g_slist_prepend (left, c), + surface, ref); +#else + right = g_slist_prepend (g_slist_reverse (right), c); + left = g_slist_prepend (left, c); + { + FILE * fp0 = fopen ("hole", "wt"); + FILE * fp1 = fopen ("right", "wt"); + FILE * fp2 = fopen ("left", "wt"); + GSList * i = left; + + gts_surface_write (surface, fp0); + fclose (fp0); + + fprintf (fp2, "LIST {\n"); + while (i) { + GtsSegment * s = i->data; + fprintf (fp2, + "# %p: %p->%p\n" + "VECT 1 2 0 2 0 %g %g 0 %g %g 0\n", + s, s->v1, s->v2, + GTS_POINT (s->v1)->x, GTS_POINT (s->v1)->y, + GTS_POINT (s->v2)->x, GTS_POINT (s->v2)->y); + i = i->next; + } + fprintf (fp2, "}\n"); + fprintf (fp1, "LIST {\n"); + i = right; + while (i) { + GtsSegment * s = i->data; + fprintf (fp1, + "# %p: %p->%p\n" + "VECT 1 2 0 2 0 %g %g 0 %g %g 0\n", + s, s->v1, s->v2, + GTS_POINT (s->v1)->x, GTS_POINT (s->v1)->y, + GTS_POINT (s->v2)->x, GTS_POINT (s->v2)->y); + i = i->next; + } + fprintf (fp1, "}\n"); + fclose (fp1); + fclose (fp2); + } + triangulate_polygon (right, surface); + triangulate_polygon (left, surface); +#endif + if (ref && !ref->surfaces) { + gts_allow_floating_edges = TRUE; + gts_object_destroy (GTS_OBJECT (ref)); + gts_allow_floating_edges = FALSE; + } + return constraints; +} + +static void delaunay_check (GtsTriangle * t, gpointer * data) +{ + GtsSurface * surface = data[0]; + GtsFace ** face = data[1]; + + if (*face == NULL) { + GSList * i, * list; + GtsVertex * v1, * v2, * v3; + + gts_triangle_vertices (t, &v1, &v2, &v3); + list = gts_vertex_neighbors (v1, NULL, surface); + list = gts_vertex_neighbors (v2, list, surface); + list = gts_vertex_neighbors (v3, list, surface); + i = list; + while (i && *face == NULL) { + GtsVertex * v = i->data; + if (v != v1 && v != v2 && v != v3 && + gts_point_in_circle (GTS_POINT (v), + GTS_POINT (v1), + GTS_POINT (v2), + GTS_POINT (v3)) > 0.) + *face = GTS_FACE (t); + i = i->next; + } + g_slist_free (list); + } +} + +/** + * gts_delaunay_check: + * @surface: a #GtsSurface. + * + * Returns: %NULL if the planar projection of @surface is a Delaunay + * triangulation (unconstrained), a #GtsFace violating the Delaunay + * property otherwise. + */ +GtsFace * gts_delaunay_check (GtsSurface * surface) +{ + GtsFace * face = NULL; + gpointer data[2]; + + g_return_val_if_fail (surface != NULL, FALSE); + + data[0] = surface; + data[1] = &face; + gts_surface_foreach_face (surface, (GtsFunc) delaunay_check, data); + + return face; +} + +/** + * gts_delaunay_remove_hull: + * @surface: a #GtsSurface. + * + * Removes all the edges of the boundary of @surface which are not + * constraints. + */ +void gts_delaunay_remove_hull (GtsSurface * surface) +{ + GSList * boundary; + + g_return_if_fail (surface != NULL); + + boundary = gts_surface_boundary (surface); + gts_allow_floating_edges = TRUE; + while (boundary) { + GSList * i = boundary; + GtsEdge * e = i->data; + + boundary = i->next; + g_slist_free_1 (i); + if (!GTS_IS_CONSTRAINT (e)) { + GtsTriangle * t = GTS_TRIANGLE (gts_edge_is_boundary (e, surface)); + + if (t != NULL) { + if (t->e1 != e && !GTS_IS_CONSTRAINT (t->e1) && + !gts_edge_is_boundary (t->e1, surface)) + boundary = g_slist_prepend (boundary, t->e1); + if (t->e2 != e && !GTS_IS_CONSTRAINT (t->e2) && + !gts_edge_is_boundary (t->e2, surface)) + boundary = g_slist_prepend (boundary, t->e2); + if (t->e3 != e && !GTS_IS_CONSTRAINT (t->e3) && + !gts_edge_is_boundary (t->e3, surface)) + boundary = g_slist_prepend (boundary, t->e3); + gts_surface_remove_face (surface, GTS_FACE (t)); + } + if (!e->triangles) + gts_object_destroy (GTS_OBJECT (e)); + } + } + gts_allow_floating_edges = FALSE; +} + +/* GtsListFace: Object */ + +static void gts_list_face_destroy (GtsObject * object) +{ + g_slist_free (GTS_LIST_FACE (object)->points); + + (* GTS_OBJECT_CLASS (gts_list_face_class ())->parent_class->destroy) + (object); +} + +static void gts_list_face_class_init (GtsFaceClass * klass) +{ + GTS_OBJECT_CLASS (klass)->destroy = gts_list_face_destroy; +} + +GtsFaceClass * gts_list_face_class (void) +{ + static GtsFaceClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo gts_list_face_info = { + "GtsListFace", + sizeof (GtsListFace), + sizeof (GtsFaceClass), + (GtsObjectClassInitFunc) gts_list_face_class_init, + (GtsObjectInitFunc) NULL, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_face_class ()), + >s_list_face_info); + } + + return klass; +} Index: work/obsolete/toporouter/src_3rd/gts/container.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/container.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/container.c (revision 6803) @@ -0,0 +1,493 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gts.h" + +/* GtsContainee */ + +static void containee_class_init (GtsContaineeClass * klass) +{ + klass->remove_container = NULL; + klass->add_container = NULL; + klass->foreach = NULL; + klass->is_contained = NULL; + klass->replace = NULL; +} + +GtsContaineeClass * gts_containee_class (void) +{ + static GtsContaineeClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo containee_info = { + "GtsContainee", + sizeof (GtsContainee), + sizeof (GtsContaineeClass), + (GtsObjectClassInitFunc) containee_class_init, + (GtsObjectInitFunc) NULL, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (gts_object_class (), + &containee_info); + } + + return klass; +} + +GtsContainee * gts_containee_new (GtsContaineeClass * klass) +{ + GtsContainee * object; + + object = GTS_CONTAINEE (gts_object_new (GTS_OBJECT_CLASS (klass))); + + return object; +} + +gboolean gts_containee_is_contained (GtsContainee * item, + GtsContainer * c) +{ + g_return_val_if_fail (item != NULL, FALSE); + g_return_val_if_fail (c != NULL, FALSE); + + if (GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->is_contained) + return + (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->is_contained) + (item, c); + return FALSE; +} + +void gts_containee_replace (GtsContainee * item, + GtsContainee * with) +{ + if (GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->replace) + (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->replace) (item, with); + if (GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->foreach) { + (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->foreach) + (item, (GtsFunc) gts_container_add, with); + (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->foreach) + (item, (GtsFunc) gts_container_remove, item); + } +} + +/* GtsSListContainee */ + +static void slist_containee_destroy (GtsObject * object) +{ + GtsSListContainee * item = GTS_SLIST_CONTAINEE (object); + GSList * i; + + i = item->containers; + while (i) { + GSList * next = i->next; + + gts_container_remove (i->data, GTS_CONTAINEE (item)); + i = next; + } + g_assert (item->containers == NULL); + + (* GTS_OBJECT_CLASS (gts_slist_containee_class ())->parent_class->destroy) + (object); +} + +static void slist_containee_remove_container (GtsContainee * i, + GtsContainer * c) +{ + GtsSListContainee * item = GTS_SLIST_CONTAINEE (i); + item->containers = g_slist_remove (item->containers, c); +} + +static void slist_containee_add_container (GtsContainee * i, + GtsContainer * c) +{ + GtsSListContainee * item = GTS_SLIST_CONTAINEE (i); + if (!g_slist_find (item->containers, c)) + item->containers = g_slist_prepend (item->containers, c); +} + +static void slist_containee_foreach (GtsContainee * c, + GtsFunc func, + gpointer data) +{ + GSList * i = GTS_SLIST_CONTAINEE (c)->containers; + + while (i) { + GSList * next = i->next; + + (* func) (i->data, data); + i = next; + } +} + +static gboolean slist_containee_is_contained (GtsContainee * i, + GtsContainer * c) +{ + return g_slist_find (GTS_SLIST_CONTAINEE (i)->containers, c) ? TRUE : FALSE; +} + +static void slist_containee_class_init (GtsSListContaineeClass * klass) +{ + GTS_CONTAINEE_CLASS (klass)->remove_container = + slist_containee_remove_container; + GTS_CONTAINEE_CLASS (klass)->add_container = + slist_containee_add_container; + GTS_CONTAINEE_CLASS (klass)->foreach = + slist_containee_foreach; + GTS_CONTAINEE_CLASS (klass)->is_contained = + slist_containee_is_contained; + + GTS_OBJECT_CLASS (klass)->destroy = slist_containee_destroy; +} + +static void slist_containee_init (GtsSListContainee * object) +{ + object->containers = NULL; +} + +GtsSListContaineeClass * gts_slist_containee_class (void) +{ + static GtsSListContaineeClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo slist_containee_info = { + "GtsSListContainee", + sizeof (GtsSListContainee), + sizeof (GtsSListContaineeClass), + (GtsObjectClassInitFunc) slist_containee_class_init, + (GtsObjectInitFunc) slist_containee_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_containee_class ()), + &slist_containee_info); + } + + return klass; +} + +/* GtsContainer */ + +static void remove_container (GtsContainee * item, GtsContainer * c) +{ + if (GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->remove_container) + (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->remove_container) + (item, c); +} + +static void container_destroy (GtsObject * object) +{ + GtsContainer * c = GTS_CONTAINER (object); + + gts_container_foreach (c, (GtsFunc) remove_container, c); + + (* GTS_OBJECT_CLASS (gts_container_class ())->parent_class->destroy) + (object); +} + +static void container_add (GtsContainer * c, GtsContainee * item) +{ + if (GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->add_container) + (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->add_container) + (item, c); +} + +static void container_remove (GtsContainer * c, GtsContainee * item) +{ + if (GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->remove_container) + (* GTS_CONTAINEE_CLASS (GTS_OBJECT (item)->klass)->remove_container) + (item, c); +} + +static void container_clone_add (GtsContainee * item, GtsContainer * clone) +{ + gts_container_add (clone, item); +} + +static void container_clone (GtsObject * clone, GtsObject * object) +{ + gts_object_init (clone, object->klass); + gts_container_foreach (GTS_CONTAINER (object), + (GtsFunc) container_clone_add, clone); +} + +static void container_class_init (GtsContainerClass * klass) +{ + klass->add = container_add; + klass->remove = container_remove; + klass->foreach = NULL; + klass->size = NULL; + + GTS_OBJECT_CLASS (klass)->destroy = container_destroy; + GTS_OBJECT_CLASS (klass)->clone = container_clone; +} + +GtsContainerClass * gts_container_class (void) +{ + static GtsContainerClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo container_info = { + "GtsContainer", + sizeof (GtsContainer), + sizeof (GtsContainerClass), + (GtsObjectClassInitFunc) container_class_init, + (GtsObjectInitFunc) NULL, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = + gts_object_class_new (GTS_OBJECT_CLASS (gts_slist_containee_class ()), + &container_info); + } + + return klass; +} + +GtsContainer * gts_container_new (GtsContainerClass * klass) +{ + GtsContainer * object; + + object = GTS_CONTAINER (gts_object_new (GTS_OBJECT_CLASS (klass))); + + return object; +} + +void gts_container_add (GtsContainer * c, + GtsContainee * item) +{ + g_return_if_fail (c != NULL); + g_return_if_fail (item != NULL); + + g_assert (GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->add); + (* GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->add) (c, item); +} + +void gts_container_remove (GtsContainer * c, + GtsContainee * item) +{ + g_return_if_fail (c != NULL); + g_return_if_fail (item != NULL); + + g_assert (GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->remove); + (* GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->remove) (c, item); +} + +void gts_container_foreach (GtsContainer * c, + GtsFunc func, + gpointer data) +{ + g_return_if_fail (c != NULL); + g_return_if_fail (func != NULL); + + if (GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->foreach) + (* GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->foreach) (c, func, data); +} + +guint gts_container_size (GtsContainer * c) +{ + g_return_val_if_fail (c != NULL, 0); + + if (GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->size) + return (* GTS_CONTAINER_CLASS (GTS_OBJECT (c)->klass)->size) (c); + return 0; +} + +/* GtsHashContainer */ + +static void hash_container_destroy (GtsObject * object) +{ + GHashTable * items = GTS_HASH_CONTAINER (object)->items; + + (* GTS_OBJECT_CLASS (gts_hash_container_class ())->parent_class->destroy) + (object); + + g_hash_table_destroy (items); +} + +static void hash_container_add (GtsContainer * c, GtsContainee * item) +{ + g_return_if_fail (GTS_HASH_CONTAINER (c)->frozen == FALSE); + + g_hash_table_insert (GTS_HASH_CONTAINER (c)->items, item, NULL); + + (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_hash_container_class ())->parent_class)->add) (c, item); +} + +static void hash_container_remove (GtsContainer * c, GtsContainee * item) +{ + g_return_if_fail (GTS_HASH_CONTAINER (c)->frozen == FALSE); + + g_hash_table_remove (GTS_HASH_CONTAINER (c)->items, item); + + (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_hash_container_class ())->parent_class)->remove) (c, item); +} + +static void hash_foreach (GtsContainee * item, + gpointer item_data, + gpointer * info) +{ + (* ((GtsFunc) info[0])) (item, info[1]); +} + +static void hash_container_foreach (GtsContainer * c, + GtsFunc func, + gpointer data) +{ + gpointer info[2]; + + info[0] = func; + info[1] = data; + /* prevent removing or adding items */ + GTS_HASH_CONTAINER (c)->frozen = TRUE; + g_hash_table_foreach (GTS_HASH_CONTAINER (c)->items, + (GHFunc) hash_foreach, info); + GTS_HASH_CONTAINER (c)->frozen = FALSE; +} + +static guint hash_container_size (GtsContainer * c) +{ + return g_hash_table_size (GTS_HASH_CONTAINER (c)->items); +} + +static void hash_container_class_init (GtsHashContainerClass * klass) +{ + GTS_CONTAINER_CLASS (klass)->add = hash_container_add; + GTS_CONTAINER_CLASS (klass)->remove = hash_container_remove; + GTS_CONTAINER_CLASS (klass)->foreach = hash_container_foreach; + GTS_CONTAINER_CLASS (klass)->size = hash_container_size; + + GTS_OBJECT_CLASS (klass)->destroy = hash_container_destroy; +} + +static void hash_container_init (GtsHashContainer * object) +{ + object->items = g_hash_table_new (NULL, NULL); + object->frozen = FALSE; +} + +GtsHashContainerClass * gts_hash_container_class (void) +{ + static GtsHashContainerClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo hash_container_info = { + "GtsHashContainer", + sizeof (GtsHashContainer), + sizeof (GtsHashContainerClass), + (GtsObjectClassInitFunc) hash_container_class_init, + (GtsObjectInitFunc) hash_container_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_container_class ()), + &hash_container_info); + } + + return klass; +} + +/* GtsSListContainer */ + +static void slist_container_destroy (GtsObject * object) +{ + GSList * items = GTS_SLIST_CONTAINER (object)->items; + + (* GTS_OBJECT_CLASS (gts_slist_container_class ())->parent_class->destroy) + (object); + + g_slist_free (items); +} + +static void slist_container_add (GtsContainer * c, GtsContainee * item) +{ + g_return_if_fail (GTS_SLIST_CONTAINER (c)->frozen == FALSE); + + if (!g_slist_find (GTS_SLIST_CONTAINER (c)->items, item)) + GTS_SLIST_CONTAINER (c)->items = + g_slist_prepend (GTS_SLIST_CONTAINER (c)->items, item); + + (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_slist_container_class ())->parent_class)->add) (c, item); +} + +static void slist_container_remove (GtsContainer * c, GtsContainee * item) +{ + g_return_if_fail (GTS_SLIST_CONTAINER (c)->frozen == FALSE); + + GTS_SLIST_CONTAINER (c)->items = + g_slist_remove (GTS_SLIST_CONTAINER (c)->items, item); + + (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_slist_container_class ())->parent_class)->remove) (c, item); +} + +static void slist_container_foreach (GtsContainer * c, + GtsFunc func, + gpointer data) +{ + GSList * i; + + i = GTS_SLIST_CONTAINER (c)->items; + while (i) { + GSList * next = i->next; + + (* func) (i->data, data); + i = next; + } +} + +static guint slist_container_size (GtsContainer * c) +{ + return g_slist_length (GTS_SLIST_CONTAINER (c)->items); +} + +static void slist_container_class_init (GtsSListContainerClass * klass) +{ + GTS_CONTAINER_CLASS (klass)->add = slist_container_add; + GTS_CONTAINER_CLASS (klass)->remove = slist_container_remove; + GTS_CONTAINER_CLASS (klass)->foreach = slist_container_foreach; + GTS_CONTAINER_CLASS (klass)->size = slist_container_size; + + GTS_OBJECT_CLASS (klass)->destroy = slist_container_destroy; +} + +static void slist_container_init (GtsSListContainer * object) +{ + object->items = NULL; + object->frozen = FALSE; +} + +GtsSListContainerClass * gts_slist_container_class (void) +{ + static GtsSListContainerClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo slist_container_info = { + "GtsSListContainer", + sizeof (GtsSListContainer), + sizeof (GtsSListContainerClass), + (GtsObjectClassInitFunc) slist_container_class_init, + (GtsObjectInitFunc) slist_container_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_container_class ()), + &slist_container_info); + } + + return klass; +} Index: work/obsolete/toporouter/src_3rd/gts/curvature.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/curvature.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/curvature.c (revision 6803) @@ -0,0 +1,621 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999-2002 Ray Jones, Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "gts.h" + +static gboolean angle_obtuse (GtsVertex * v, GtsFace * f) +{ + GtsEdge * e = gts_triangle_edge_opposite (GTS_TRIANGLE (f), v); + GtsVector vec1, vec2; + + gts_vector_init (vec1, GTS_POINT (v), GTS_POINT (GTS_SEGMENT (e)->v1)); + gts_vector_init (vec2, GTS_POINT (v), GTS_POINT (GTS_SEGMENT (e)->v2)); + + return (gts_vector_scalar (vec1, vec2) < 0.0); +} + +static gboolean triangle_obtuse (GtsVertex * v, GtsFace * f) +{ + GtsEdge * e = gts_triangle_edge_opposite (GTS_TRIANGLE (f), v); + + return (angle_obtuse (v, f) || + angle_obtuse (GTS_SEGMENT (e)->v1, f) || + angle_obtuse (GTS_SEGMENT (e)->v2, f)); +} + +static gdouble cotan (GtsVertex * vo, GtsVertex * v1, GtsVertex * v2) +{ + /* cf. Appendix B of [Meyer et al 2002] */ + GtsVector u, v; + gdouble udotv, denom; + + gts_vector_init (u, GTS_POINT (vo), GTS_POINT (v1)); + gts_vector_init (v, GTS_POINT (vo), GTS_POINT (v2)); + + udotv = gts_vector_scalar (u, v); + denom = sqrt (gts_vector_scalar (u,u)*gts_vector_scalar (v,v) - + udotv*udotv); + + + /* denom can be zero if u==v. Returning 0 is acceptable, based on + * the callers of this function below. */ + if (denom == 0.0) return (0.0); + + return (udotv/denom); +} + +static gdouble angle_from_cotan (GtsVertex * vo, + GtsVertex * v1, GtsVertex * v2) +{ + /* cf. Appendix B and the caption of Table 1 from [Meyer et al 2002] */ + GtsVector u, v; + gdouble udotv, denom; + + gts_vector_init (u, GTS_POINT (vo), GTS_POINT (v1)); + gts_vector_init (v, GTS_POINT (vo), GTS_POINT (v2)); + + udotv = gts_vector_scalar (u, v); + denom = sqrt (gts_vector_scalar (u,u)*gts_vector_scalar (v,v) + - udotv*udotv); + + /* Note: I assume this is what they mean by using atan2 (). -Ray Jones */ + + /* tan = denom/udotv = y/x (see man page for atan2) */ + return (fabs (atan2 (denom, udotv))); +} + +static gdouble region_area (GtsVertex * v, GtsFace * f) +{ + /* cf. Section 3.3 of [Meyer et al 2002] */ + + if (gts_triangle_area (GTS_TRIANGLE (f)) == 0.0) return (0.0); + + if (triangle_obtuse (v, f)) { + if (angle_obtuse (v, f)) + return (gts_triangle_area (GTS_TRIANGLE (f))/2.0); + else + return (gts_triangle_area (GTS_TRIANGLE (f))/4.0); + } else { + GtsEdge * e = gts_triangle_edge_opposite (GTS_TRIANGLE (f), v); + + return ((cotan (GTS_SEGMENT (e)->v1, v, GTS_SEGMENT (e)->v2)* + gts_point_distance2 (GTS_POINT (v), + GTS_POINT (GTS_SEGMENT (e)->v2)) + + cotan (GTS_SEGMENT (e)->v2, v, GTS_SEGMENT (e)->v1)* + gts_point_distance2 (GTS_POINT (v), + GTS_POINT (GTS_SEGMENT (e)->v1))) + /8.0); + } +} + +/** + * gts_vertex_mean_curvature_normal: + * @v: a #GtsVertex. + * @s: a #GtsSurface. + * @Kh: the Mean Curvature Normal at @v. + * + * Computes the Discrete Mean Curvature Normal approximation at @v. + * The mean curvature at @v is half the magnitude of the vector @Kh. + * + * Note: the normal computed is not unit length, and may point either + * into or out of the surface, depending on the curvature at @v. It + * is the responsibility of the caller of the function to use the mean + * curvature normal appropriately. + * + * This approximation is from the paper: + * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds + * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr + * VisMath '02, Berlin (Germany) + * http://www-grail.usc.edu/pubs.html + * + * Returns: %TRUE if the operator could be evaluated, %FALSE if the + * evaluation failed for some reason (@v is boundary or is the + * endpoint of a non-manifold edge.) + */ +gboolean gts_vertex_mean_curvature_normal (GtsVertex * v, GtsSurface * s, + GtsVector Kh) +{ + GSList * faces, * edges, * i; + gdouble area = 0.0; + + g_return_val_if_fail (v != NULL, FALSE); + g_return_val_if_fail (s != NULL, FALSE); + + /* this operator is not defined for boundary edges */ + if (gts_vertex_is_boundary (v, s)) return (FALSE); + + faces = gts_vertex_faces (v, s, NULL); + g_return_val_if_fail (faces != NULL, FALSE); + + edges = gts_vertex_fan_oriented (v, s); + if (edges == NULL) { + g_slist_free (faces); + return (FALSE); + } + + i = faces; + while (i) { + GtsFace * f = i->data; + + area += region_area (v, f); + i = i->next; + } + g_slist_free (faces); + + Kh[0] = Kh[1] = Kh[2] = 0.0; + + i = edges; + while (i) { + GtsEdge * e = i->data; + GtsVertex * v1 = GTS_SEGMENT (e)->v1; + GtsVertex * v2 = GTS_SEGMENT (e)->v2; + gdouble temp; + + temp = cotan (v1, v, v2); + Kh[0] += temp*(GTS_POINT (v2)->x - GTS_POINT (v)->x); + Kh[1] += temp*(GTS_POINT (v2)->y - GTS_POINT (v)->y); + Kh[2] += temp*(GTS_POINT (v2)->z - GTS_POINT (v)->z); + + temp = cotan (v2, v, v1); + Kh[0] += temp*(GTS_POINT (v1)->x - GTS_POINT (v)->x); + Kh[1] += temp*(GTS_POINT (v1)->y - GTS_POINT (v)->y); + Kh[2] += temp*(GTS_POINT (v1)->z - GTS_POINT (v)->z); + + i = i->next; + } + g_slist_free (edges); + + if (area > 0.0) { + Kh[0] /= 2*area; + Kh[1] /= 2*area; + Kh[2] /= 2*area; + } else { + return (FALSE); + } + + return TRUE; +} + +/** + * gts_vertex_gaussian_curvature: + * @v: a #GtsVertex. + * @s: a #GtsSurface. + * @Kg: the Discrete Gaussian Curvature approximation at @v. + * + * Computes the Discrete Gaussian Curvature approximation at @v. + * + * This approximation is from the paper: + * Discrete Differential-Geometry Operators for Triangulated 2-Manifolds + * Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr + * VisMath '02, Berlin (Germany) + * http://www-grail.usc.edu/pubs.html + * + * Returns: %TRUE if the operator could be evaluated, %FALSE if the + * evaluation failed for some reason (@v is boundary or is the + * endpoint of a non-manifold edge.) + */ +gboolean gts_vertex_gaussian_curvature (GtsVertex * v, GtsSurface * s, + gdouble * Kg) +{ + GSList * faces, * edges, * i; + gdouble area = 0.0; + gdouble angle_sum = 0.0; + + g_return_val_if_fail (v != NULL, FALSE); + g_return_val_if_fail (s != NULL, FALSE); + g_return_val_if_fail (Kg != NULL, FALSE); + + /* this operator is not defined for boundary edges */ + if (gts_vertex_is_boundary (v, s)) return (FALSE); + + faces = gts_vertex_faces (v, s, NULL); + g_return_val_if_fail (faces != NULL, FALSE); + + edges = gts_vertex_fan_oriented (v, s); + if (edges == NULL) { + g_slist_free (faces); + return (FALSE); + } + + i = faces; + while (i) { + GtsFace * f = i->data; + + area += region_area (v, f); + i = i->next; + } + g_slist_free (faces); + + i = edges; + while (i) { + GtsEdge * e = i->data; + GtsVertex * v1 = GTS_SEGMENT (e)->v1; + GtsVertex * v2 = GTS_SEGMENT (e)->v2; + + angle_sum += angle_from_cotan (v, v1, v2); + i = i->next; + } + g_slist_free (edges); + + *Kg = (2.0*M_PI - angle_sum)/area; + + return TRUE; +} + +/** + * gts_vertex_principal_curvatures: + * @Kh: mean curvature. + * @Kg: Gaussian curvature. + * @K1: first principal curvature. + * @K2: second principal curvature. + * + * Computes the principal curvatures at a point given the mean and + * Gaussian curvatures at that point. + * + * The mean curvature can be computed as one-half the magnitude of the + * vector computed by gts_vertex_mean_curvature_normal(). + * + * The Gaussian curvature can be computed with + * gts_vertex_gaussian_curvature(). + */ +void gts_vertex_principal_curvatures (gdouble Kh, gdouble Kg, + gdouble * K1, gdouble * K2) +{ + gdouble temp = Kh*Kh - Kg; + + g_return_if_fail (K1 != NULL); + g_return_if_fail (K2 != NULL); + + if (temp < 0.0) temp = 0.0; + temp = sqrt (temp); + *K1 = Kh + temp; + *K2 = Kh - temp; +} + +/* from Maple */ +static void linsolve (gdouble m11, gdouble m12, gdouble b1, + gdouble m21, gdouble m22, gdouble b2, + gdouble * x1, gdouble * x2) +{ + gdouble temp; + + temp = 1.0 / (m21*m12 - m11*m22); + *x1 = (m12*b2 - m22*b1)*temp; + *x2 = (m11*b2 - m21*b1)*temp; +} + +/* from Maple - largest eigenvector of [a b; b c] */ +static void eigenvector (gdouble a, gdouble b, gdouble c, + GtsVector e) +{ + if (b == 0.0) { + e[0] = 0.0; + } else { + e[0] = -(c - a - sqrt (c*c - 2*a*c + a*a + 4*b*b))/(2*b); + } + e[1] = 1.0; + e[2] = 0.0; +} + +/** + * gts_vertex_principal_directions: + * @v: a #GtsVertex. + * @s: a #GtsSurface. + * @Kh: mean curvature normal (a #GtsVector). + * @Kg: Gaussian curvature (a gdouble). + * @e1: first principal curvature direction (direction of largest curvature). + * @e2: second principal curvature direction. + * + * Computes the principal curvature directions at a point given @Kh + * and @Kg, the mean curvature normal and Gaussian curvatures at that + * point, computed with gts_vertex_mean_curvature_normal() and + * gts_vertex_gaussian_curvature(), respectively. + * + * Note that this computation is very approximate and tends to be + * unstable. Smoothing of the surface or the principal directions may + * be necessary to achieve reasonable results. + */ +void gts_vertex_principal_directions (GtsVertex * v, GtsSurface * s, + GtsVector Kh, gdouble Kg, + GtsVector e1, GtsVector e2) +{ + GtsVector N; + gdouble normKh; + GSList * i, * j; + GtsVector basis1, basis2, d, eig; + gdouble ve2, vdotN; + gdouble aterm_da, bterm_da, cterm_da, const_da; + gdouble aterm_db, bterm_db, cterm_db, const_db; + gdouble a, b, c; + gdouble K1, K2; + gdouble *weights, *kappas, *d1s, *d2s; + gint edge_count; + gdouble err_e1, err_e2; + int e; + + /* compute unit normal */ + normKh = sqrt (gts_vector_scalar (Kh, Kh)); + + if (normKh > 0.0) { + N[0] = Kh[0] / normKh; + N[1] = Kh[1] / normKh; + N[2] = Kh[2] / normKh; + } else { + /* This vertex is a point of zero mean curvature (flat or saddle + * point). Compute a normal by averaging the adjacent triangles + */ + N[0] = N[1] = N[2] = 0.0; + i = gts_vertex_faces (v, s, NULL); + while (i) { + gdouble x, y, z; + gts_triangle_normal (GTS_TRIANGLE ((GtsFace *) i->data), + &x, &y, &z); + N[0] += x; + N[1] += y; + N[2] += z; + + i = i->next; + } + g_return_if_fail (gts_vector_norm (N) > 0.0); + gts_vector_normalize (N); + } + + + /* construct a basis from N: */ + /* set basis1 to any component not the largest of N */ + basis1[0] = basis1[1] = basis1[2] = 0.0; + if (fabs (N[0]) > fabs (N[1])) + basis1[1] = 1.0; + else + basis1[0] = 1.0; + + /* make basis2 orthogonal to N */ + gts_vector_cross (basis2, N, basis1); + gts_vector_normalize (basis2); + + /* make basis1 orthogonal to N and basis2 */ + gts_vector_cross (basis1, N, basis2); + gts_vector_normalize (basis1); + + aterm_da = bterm_da = cterm_da = const_da = 0.0; + aterm_db = bterm_db = cterm_db = const_db = 0.0; + + weights = g_malloc (sizeof (gdouble)*g_slist_length (v->segments)); + kappas = g_malloc (sizeof (gdouble)*g_slist_length (v->segments)); + d1s = g_malloc (sizeof (gdouble)*g_slist_length (v->segments)); + d2s = g_malloc (sizeof (gdouble)*g_slist_length (v->segments)); + edge_count = 0; + + i = v->segments; + while (i) { + GtsEdge * e; + GtsFace * f1, * f2; + gdouble weight, kappa, d1, d2; + GtsVector vec_edge; + + if (! GTS_IS_EDGE (i->data)) { + i = i->next; + continue; + } + + e = i->data; + + /* since this vertex passed the tests in + * gts_vertex_mean_curvature_normal(), this should be true. */ + g_assert (gts_edge_face_number (e, s) == 2); + + /* identify the two triangles bordering e in s */ + f1 = f2 = NULL; + j = e->triangles; + while (j) { + if ((! GTS_IS_FACE (j->data)) || + (! gts_face_has_parent_surface (GTS_FACE (j->data), s))) { + j = j->next; + continue; + } + if (f1 == NULL) + f1 = GTS_FACE (j->data); + else { + f2 = GTS_FACE (j->data); + break; + } + j = j->next; + } + g_assert (f2 != NULL); + + /* We are solving for the values of the curvature tensor + * B = [ a b ; b c ]. + * The computations here are from section 5 of [Meyer et al 2002]. + * + * The first step is to calculate the linear equations governing + * the values of (a,b,c). These can be computed by setting the + * derivatives of the error E to zero (section 5.3). + * + * Since a + c = norm(Kh), we only compute the linear equations + * for dE/da and dE/db. (NB: [Meyer et al 2002] has the + * equation a + b = norm(Kh), but I'm almost positive this is + * incorrect.) + * + * Note that the w_ij (defined in section 5.2) are all scaled by + * (1/8*A_mixed). We drop this uniform scale factor because the + * solution of the linear equations doesn't rely on it. + * + * The terms of the linear equations are xterm_dy with x in + * {a,b,c} and y in {a,b}. There are also const_dy terms that are + * the constant factors in the equations. + */ + + /* find the vector from v along edge e */ + gts_vector_init (vec_edge, GTS_POINT (v), + GTS_POINT ((GTS_SEGMENT (e)->v1 == v) ? + GTS_SEGMENT (e)->v2 : GTS_SEGMENT (e)->v1)); + ve2 = gts_vector_scalar (vec_edge, vec_edge); + vdotN = gts_vector_scalar (vec_edge, N); + + /* section 5.2 - There is a typo in the computation of kappa. The + * edges should be x_j-x_i. + */ + kappa = 2.0 * vdotN / ve2; + + /* section 5.2 */ + + /* I don't like performing a minimization where some of the + * weights can be negative (as can be the case if f1 or f2 are + * obtuse). To ensure all-positive weights, we check for + * obtuseness and use values similar to those in region_area(). */ + weight = 0.0; + if (! triangle_obtuse(v, f1)) { + weight += ve2 * + cotan (gts_triangle_vertex_opposite (GTS_TRIANGLE (f1), e), + GTS_SEGMENT (e)->v1, GTS_SEGMENT (e)->v2) / 8.0; + } else { + if (angle_obtuse (v, f1)) { + weight += ve2 * gts_triangle_area (GTS_TRIANGLE (f1)) / 4.0; + } else { + weight += ve2 * gts_triangle_area (GTS_TRIANGLE (f1)) / 8.0; + } + } + + if (! triangle_obtuse(v, f2)) { + weight += ve2 * + cotan (gts_triangle_vertex_opposite (GTS_TRIANGLE (f2), e), + GTS_SEGMENT (e)->v1, GTS_SEGMENT (e)->v2) / 8.0; + } else { + if (angle_obtuse (v, f2)) { + weight += ve2 * gts_triangle_area (GTS_TRIANGLE (f2)) / 4.0; + } else { + weight += ve2 * gts_triangle_area (GTS_TRIANGLE (f2)) / 8.0; + } + } + + /* projection of edge perpendicular to N (section 5.3) */ + d[0] = vec_edge[0] - vdotN * N[0]; + d[1] = vec_edge[1] - vdotN * N[1]; + d[2] = vec_edge[2] - vdotN * N[2]; + gts_vector_normalize (d); + + /* not explicit in the paper, but necessary. Move d to 2D basis. */ + d1 = gts_vector_scalar (d, basis1); + d2 = gts_vector_scalar (d, basis2); + + /* store off the curvature, direction of edge, and weights for later use */ + weights[edge_count] = weight; + kappas[edge_count] = kappa; + d1s[edge_count] = d1; + d2s[edge_count] = d2; + edge_count++; + + /* Finally, update the linear equations */ + aterm_da += weight * d1 * d1 * d1 * d1; + bterm_da += weight * d1 * d1 * 2 * d1 * d2; + cterm_da += weight * d1 * d1 * d2 * d2; + const_da += weight * d1 * d1 * (- kappa); + + aterm_db += weight * d1 * d2 * d1 * d1; + bterm_db += weight * d1 * d2 * 2 * d1 * d2; + cterm_db += weight * d1 * d2 * d2 * d2; + const_db += weight * d1 * d2 * (- kappa); + + i = i->next; + } + + /* now use the identity (Section 5.3) a + c = |Kh| = 2 * kappa_h */ + aterm_da -= cterm_da; + const_da += cterm_da * normKh; + + aterm_db -= cterm_db; + const_db += cterm_db * normKh; + + /* check for solvability of the linear system */ + if (((aterm_da * bterm_db - aterm_db * bterm_da) != 0.0) && + ((const_da != 0.0) || (const_db != 0.0))) { + linsolve (aterm_da, bterm_da, -const_da, + aterm_db, bterm_db, -const_db, + &a, &b); + + c = normKh - a; + + eigenvector (a, b, c, eig); + } else { + /* region of v is planar */ + eig[0] = 1.0; + eig[1] = 0.0; + } + + /* Although the eigenvectors of B are good estimates of the + * principal directions, it seems that which one is attached to + * which curvature direction is a bit arbitrary. This may be a bug + * in my implementation, or just a side-effect of the inaccuracy of + * B due to the discrete nature of the sampling. + * + * To overcome this behavior, we'll evaluate which assignment best + * matches the given eigenvectors by comparing the curvature + * estimates computed above and the curvatures calculated from the + * discrete differential operators. */ + + gts_vertex_principal_curvatures (0.5 * normKh, Kg, &K1, &K2); + + err_e1 = err_e2 = 0.0; + /* loop through the values previously saved */ + for (e = 0; e < edge_count; e++) { + gdouble weight, kappa, d1, d2; + gdouble temp1, temp2; + gdouble delta; + + weight = weights[e]; + kappa = kappas[e]; + d1 = d1s[e]; + d2 = d2s[e]; + + temp1 = fabs (eig[0] * d1 + eig[1] * d2); + temp1 = temp1 * temp1; + temp2 = fabs (eig[1] * d1 - eig[0] * d2); + temp2 = temp2 * temp2; + + /* err_e1 is for K1 associated with e1 */ + delta = K1 * temp1 + K2 * temp2 - kappa; + err_e1 += weight * delta * delta; + + /* err_e2 is for K1 associated with e2 */ + delta = K2 * temp1 + K1 * temp2 - kappa; + err_e2 += weight * delta * delta; + } + g_free (weights); + g_free (kappas); + g_free (d1s); + g_free (d2s); + + /* rotate eig by a right angle if that would decrease the error */ + if (err_e2 < err_e1) { + gdouble temp = eig[0]; + + eig[0] = eig[1]; + eig[1] = -temp; + } + + e1[0] = eig[0] * basis1[0] + eig[1] * basis2[0]; + e1[1] = eig[0] * basis1[1] + eig[1] * basis2[1]; + e1[2] = eig[0] * basis1[2] + eig[1] * basis2[2]; + gts_vector_normalize (e1); + + /* make N,e1,e2 a right handed coordinate sytem */ + gts_vector_cross (e2, N, e1); + gts_vector_normalize (e2); +} Index: work/obsolete/toporouter/src_3rd/gts/edge.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/edge.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/edge.c (revision 6803) @@ -0,0 +1,582 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gts.h" + +gboolean gts_allow_floating_edges = FALSE; + +static void edge_destroy (GtsObject * object) +{ + GtsEdge * edge = GTS_EDGE (object); + GSList * i; + + i = edge->triangles; + while (i) { + GSList * next = i->next; + gts_object_destroy (i->data); + i = next; + } + g_assert (edge->triangles == NULL); + + (* GTS_OBJECT_CLASS (gts_edge_class ())->parent_class->destroy) (object); +} + +static void edge_clone (GtsObject * clone, GtsObject * object) +{ + (* GTS_OBJECT_CLASS (gts_edge_class ())->parent_class->clone) (clone, + object); + GTS_SEGMENT (clone)->v1 = GTS_SEGMENT (clone)->v2 = NULL; + GTS_EDGE (clone)->triangles = NULL; +} + +static void edge_class_init (GtsObjectClass * klass) +{ + klass->clone = edge_clone; + klass->destroy = edge_destroy; +} + +static void edge_init (GtsEdge * edge) +{ + edge->triangles = NULL; +} + +/** + * gts_edge_class: + * + * Returns: the #GtsEdgeClass. + */ +GtsEdgeClass * gts_edge_class (void) +{ + static GtsEdgeClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo edge_info = { + "GtsEdge", + sizeof (GtsEdge), + sizeof (GtsEdgeClass), + (GtsObjectClassInitFunc) edge_class_init, + (GtsObjectInitFunc) edge_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_segment_class ()), + &edge_info); + } + + return klass; +} + +/** + * gts_edge_new: + * @klass: a #GtsEdgeClass. + * @v1: a #GtsVertex. + * @v2: a #GtsVertex. + * + * Returns: a new #GtsEdge linking @v1 and @v2. + */ +GtsEdge * gts_edge_new (GtsEdgeClass * klass, + GtsVertex * v1, GtsVertex * v2) +{ + return GTS_EDGE (gts_segment_new (GTS_SEGMENT_CLASS (klass), v1, v2)); +} + +void gts_edge_remove(GtsEdge *edge) +{ + edge->segment.v1->segments = g_slist_remove(edge->segment.v1->segments, &edge->segment); + edge->segment.v2->segments = g_slist_remove(edge->segment.v2->segments, &edge->segment); + edge_destroy(GTS_OBJECT (edge)); +} + +/** + * gts_edge_replace: + * @e: a #GtsEdge. + * @with: a #GtsEdge. + * + * Replaces @e with @with. For each triangle which uses @e as an + * edge, @e is replaced with @with. The @with->triangles list is + * updated appropriately and the @e->triangles list is freed and set + * to %NULL. + */ +void gts_edge_replace (GtsEdge * e, GtsEdge * with) +{ + GSList * i; + + g_return_if_fail (e != NULL && with != NULL && e != with); + + i = e->triangles; + while (i) { + GtsTriangle * t = i->data; + if (t->e1 == e) t->e1 = with; + if (t->e2 == e) t->e2 = with; + if (t->e3 == e) t->e3 = with; + if (!g_slist_find (with->triangles, t)) + with->triangles = g_slist_prepend (with->triangles, t); + i = i->next; + } + g_slist_free (e->triangles); + e->triangles = NULL; +} + +/** + * gts_edge_has_parent_surface: + * @e: a #GtsEdge. + * @surface: a #GtsSurface. + * + * Returns: a #GtsFace of @surface having @e as an edge, %NULL otherwise. + */ +GtsFace * gts_edge_has_parent_surface (GtsEdge * e, GtsSurface * surface) +{ + GSList * i; + + g_return_val_if_fail (e != NULL, NULL); + + i = e->triangles; + while (i) { + if (GTS_IS_FACE (i->data) && + gts_face_has_parent_surface (i->data, surface)) + return i->data; + i = i->next; + } + return NULL; +} + +/** + * gts_edge_has_any_parent_surface: + * @e: a #GtsEdge. + * + * Returns: %NULL if @e is not an edge of any triangle or if all the + * faces having @e has an edge do not belong to any surface, + * a #GtsFace belonging to a surface and having @e as an edge. + */ +GtsFace * gts_edge_has_any_parent_surface (GtsEdge * e) +{ + GSList * i; + + g_return_val_if_fail (e != NULL, NULL); + + i = e->triangles; + while (i) { + GtsTriangle * t = i->data; + if (GTS_IS_FACE (t) && GTS_FACE (t)->surfaces != NULL) + return GTS_FACE (t); + i = i->next; + } + return NULL; +} + +/** + * gts_edge_is_boundary: + * @e: a #GtsEdge. + * @surface: a #GtsSurface or %NULL. + * + * Returns: the unique #GtsFace (which belongs to @surface) and which + * has @e as an edge (i.e. @e is a boundary edge (of @surface)) or %NULL + * if there is more than one or no faces (belonging to @surface) and + * with @e as an edge. + */ +GtsFace * gts_edge_is_boundary (GtsEdge * e, GtsSurface * surface) +{ + GSList * i; + GtsFace * f = NULL; + + g_return_val_if_fail (e != NULL, NULL); + + i = e->triangles; + while (i) { + if (GTS_IS_FACE (i->data)) { + if (!surface || gts_face_has_parent_surface (i->data, surface)) { + if (f != NULL) + return NULL; + f = i->data; + } + } + i = i->next; + } + return f; +} + +/** + * gts_edges_from_vertices: + * @vertices: a list of #GtsVertex. + * @parent: a #GtsSurface. + * + * Returns: a list of unique #GtsEdge which have one of their vertices in + * @vertices and are used by a face of @parent. + */ +GSList * gts_edges_from_vertices (GSList * vertices, GtsSurface * parent) +{ + GHashTable * hash; + GSList * edges = NULL, * i; + + g_return_val_if_fail (parent != NULL, NULL); + + hash = g_hash_table_new (NULL, NULL); + i = vertices; + while (i) { + GSList * j = GTS_VERTEX (i->data)->segments; + while (j) { + GtsSegment * s = j->data; + if (GTS_IS_EDGE (s) && + gts_edge_has_parent_surface (GTS_EDGE (s), parent) && + g_hash_table_lookup (hash, s) == NULL) { + edges = g_slist_prepend (edges, s); + g_hash_table_insert (hash, s, i); + } + j = j->next; + } + i = i->next; + } + g_hash_table_destroy (hash); + return edges; +} + +/** + * gts_edge_face_number: + * @e: a #GtsEdge. + * @s: a #GtsSurface. + * + * Returns: the number of faces using @e and belonging to @s. + */ +guint gts_edge_face_number (GtsEdge * e, GtsSurface * s) +{ + GSList * i; + guint nt = 0; + + g_return_val_if_fail (e != NULL, 0); + g_return_val_if_fail (s != NULL, 0); + + i = e->triangles; + while (i) { + if (GTS_IS_FACE (i->data) && + gts_face_has_parent_surface (GTS_FACE (i->data), s)) + nt++; + i = i->next; + } + return nt; +} + +/** + * gts_edge_is_duplicate: + * @e: a #GtsEdge. + * + * Returns: the first #GtsEdge different from @e which shares the + * same endpoints or %NULL if there is none. + */ +GtsEdge * gts_edge_is_duplicate (GtsEdge * e) +{ + GSList * i; + GtsVertex * v2; + + g_return_val_if_fail (e != NULL, NULL); + + v2 = GTS_SEGMENT (e)->v2; + i = GTS_SEGMENT (e)->v1->segments; + if (GTS_SEGMENT (e)->v1 == v2) /* e is degenerate: special treatment */ + while (i) { + GtsSegment * s = i->data; + if (s != GTS_SEGMENT (e) && + GTS_IS_EDGE (s) && + s->v1 == v2 && s->v2 == v2) + return GTS_EDGE (s); + i = i->next; + } + else /* e is not degenerate */ + while (i) { + GtsSegment * s = i->data; + if (s != GTS_SEGMENT (e) && + GTS_IS_EDGE (s) && + (s->v1 == v2 || s->v2 == v2)) + return GTS_EDGE (s); + i = i->next; + } + return NULL; +} + +/** + * gts_edges_merge: + * @edges: a list of #GtsEdge. + * + * For each edge in @edges check if it is duplicated (as + * returned by gts_edge_is_duplicate()). If it is replace it by its + * duplicate, destroy it and remove it from the list. + * + * Returns: the updated @edges list. + */ +GList * gts_edges_merge (GList * edges) +{ + GList * i = edges; + + /* we want to control edge destruction */ + gts_allow_floating_edges = TRUE; + while (i) { + GtsEdge * e = i->data; + GtsEdge * de = gts_edge_is_duplicate (e); + if (de) { + GList * next = i->next; + edges = g_list_remove_link (edges, i); + g_list_free_1 (i); + i = next; + gts_edge_replace (e, de); + gts_object_destroy (GTS_OBJECT (e)); + } + else + i = i->next; + } + gts_allow_floating_edges = FALSE;; + + return edges; +} + +static void triangle_vertices_edges (GtsTriangle * t, + GtsEdge * e, + GtsVertex ** v, + GtsEdge ** ee1, + GtsEdge ** ee2) +{ + GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3; + GtsVertex * v1 = GTS_SEGMENT (e)->v1; + + if (e1 == e) e1 = e3; + else if (e2 == e) e2 = e3; + else g_assert (e3 == e); + + if (GTS_SEGMENT (e2)->v1 == v1 || GTS_SEGMENT (e2)->v2 == v1) { + e3 = e1; e1 = e2; e2 = e3; + } + if (GTS_SEGMENT (e1)->v1 == v1) + *v = GTS_SEGMENT (e1)->v2; + else + *v = GTS_SEGMENT (e1)->v1; + *ee1 = e1; + *ee2 = e2; +} + +/** + * gts_edge_belongs_to_tetrahedron: + * @e: a #GtsEdge. + * + * Returns: %TRUE if @e is used by faces forming a tetrahedron, %FALSE + * otherwise. + */ +gboolean gts_edge_belongs_to_tetrahedron (GtsEdge * e) +{ + GSList * i; + + g_return_val_if_fail (e != NULL, FALSE); + + i = e->triangles; + while (i) { + GtsEdge * e1, * e2; + GtsVertex * vt1; + GSList * j = i->next; + triangle_vertices_edges (i->data, e, &vt1, &e1, &e2); + while (j) { + GtsSegment * s5; + GtsEdge * e3, * e4; + GtsVertex * vt2; + + triangle_vertices_edges (j->data, e, &vt2, &e3, &e4); + s5 = gts_vertices_are_connected (vt1, vt2); + if (GTS_IS_EDGE (s5) && + gts_triangle_use_edges (e1, e3, GTS_EDGE (s5)) && + gts_triangle_use_edges (e2, e4, GTS_EDGE (s5))) + return TRUE; + j = j->next; + } + i = i->next; + } + + return FALSE; +} + +#define edge_use_vertex(e, v) (GTS_SEGMENT(e)->v1 == v ||\ + GTS_SEGMENT(e)->v2 == v) + +static GtsEdge * next_edge (GtsTriangle * t, + GtsEdge * e1, + GtsEdge * e) +{ + GtsVertex * v1 = GTS_SEGMENT (e)->v1; + GtsVertex * v2 = GTS_SEGMENT (e)->v2; + + if (t->e1 != e1 && t->e1 != e && + (edge_use_vertex (t->e1, v1) || edge_use_vertex (t->e1, v2))) + return t->e1; + else if (t->e2 != e1 && t->e2 != e && + (edge_use_vertex (t->e2, v1) || edge_use_vertex (t->e2, v2))) + return t->e2; + else if (t->e3 != e1 && t->e3 != e && + (edge_use_vertex (t->e3, v1) || edge_use_vertex (t->e3, v2))) + return t->e3; + g_assert_not_reached (); + return NULL; +} + +static void triangle_next (GtsEdge * e1, GtsEdge * e) +{ + GSList * i; + + i = e1->triangles; + while (i) { + GtsTriangle * t = i->data; + if (GTS_OBJECT (t)->reserved) { + GTS_OBJECT (t)->reserved = NULL; + triangle_next (next_edge (t, e1, e), e); + } + i = i->next; + } +} + +/** + * gts_edge_is_contact: + * @e: a #GtsEdge. + * + * Returns: the number of sets of connected triangles sharing @e as a + * contact edge. + */ +guint gts_edge_is_contact (GtsEdge * e) +{ + GSList * i, * triangles; + guint ncomponent = 0; + + g_return_val_if_fail (e != NULL, 0); + + triangles = gts_vertex_triangles (GTS_SEGMENT (e)->v1, NULL); + i = triangles = gts_vertex_triangles (GTS_SEGMENT (e)->v2, triangles); + while (i) { + GTS_OBJECT (i->data)->reserved = i; + i = i->next; + } + + i = e->triangles; + while (i) { + GtsTriangle * t = i->data; + if (GTS_OBJECT (t)->reserved) { + GtsEdge * e1; + GTS_OBJECT (t)->reserved = NULL; + e1 = next_edge (t, NULL, e); + triangle_next (e1, e); + triangle_next (next_edge (t, e1, e), e); + ncomponent++; + } + i = i->next; + } + + g_slist_foreach (triangles, (GFunc) gts_object_reset_reserved, NULL); + g_slist_free (triangles); + + return ncomponent; +} + +/** + * 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_edge_manifold_faces: + * @e: a #GtsEdge. + * @s: a #GtsSurface. + * @f1: pointer for first face. + * @f2: pointer for second face. + * + * If @e is a manifold edge of surface @s, fills @f1 and @f2 with the + * faces belonging to @s and sharing @e. + * + * Returns: %TRUE if @e is a manifold edge, %FALSE otherwise. + */ +gboolean gts_edge_manifold_faces (GtsEdge * e, GtsSurface * s, + GtsFace ** f1, GtsFace ** f2) +{ + GSList * i; + + g_return_val_if_fail (e != NULL, FALSE); + g_return_val_if_fail (s != NULL, FALSE); + g_return_val_if_fail (f1 != NULL, FALSE); + g_return_val_if_fail (f2 != NULL, FALSE); + + *f1 = *f2 = NULL; + i = e->triangles; + while (i) { + if (GTS_IS_FACE (i->data) && gts_face_has_parent_surface (i->data, s)) { + if (!(*f1)) *f1 = i->data; + else if (!(*f2)) *f2 = i->data; + else return FALSE; + } + i = i->next; + } + + return (*f1 && *f2); +} Index: work/obsolete/toporouter/src_3rd/gts/eheap.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/eheap.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/eheap.c (revision 6803) @@ -0,0 +1,461 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "gts.h" + +#define PARENT(i) ((i) >= 2 ? (i)/2 : 0) +#define LEFT_CHILD(i) (2*(i)) +#define RIGHT_CHILD(i) (2*(i) + 1) + + +/** + * gts_eheap_new: + * @key_func: a #GtsKeyFunc or %NULL. + * @data: user data to be passed to @key_func. + * + * Returns: a new #GtsEHeap using @key_func as key. + */ +GtsEHeap * gts_eheap_new (GtsKeyFunc key_func, + gpointer data) +{ + GtsEHeap * heap; + + heap = g_malloc (sizeof(GtsEHeap)); + heap->elts = g_ptr_array_new (); + heap->func = key_func; + heap->data = data; + heap->frozen = FALSE; + heap->randomized = FALSE; + return heap; +} + +static void sift_up (GtsEHeap * heap, guint i) +{ + GtsEHeapPair * parent, * child; + guint p; + gpointer * pdata = heap->elts->pdata; + gdouble key; + + child = pdata[i - 1]; + key = child->key; + while ((p = PARENT (i))) { + parent = pdata[p - 1]; + if (parent->key > key || + (heap->randomized && parent->key == key && rand () < RAND_MAX/2)) { + pdata[p - 1] = child; + pdata[i - 1] = parent; + child->pos = p; + parent->pos = i; + i = p; + } + else + i = 0; + } +} + +/** + * gts_eheap_insert: + * @heap: a #GtsEHeap. + * @p: a pointer to add to the heap. + * + * Inserts a new element @p in the heap. + * + * Returns: a #GtsEHeapPair describing the position of the element in the heap. + * This pointer is necessary for gts_eheap_remove() and + * gts_eheap_decrease_key(). + */ +GtsEHeapPair * gts_eheap_insert (GtsEHeap * heap, gpointer p) +{ + GtsEHeapPair * pair; + GPtrArray * elts; + + g_return_val_if_fail (heap != NULL, NULL); + g_return_val_if_fail (heap->func != NULL, NULL); + + elts = heap->elts; + pair = g_malloc (sizeof (GtsEHeapPair)); + g_ptr_array_add (elts, pair); + pair->data = p; + pair->pos = elts->len; + pair->key = (*heap->func) (p, heap->data); + if (!heap->frozen) + sift_up (heap, elts->len); + return pair; +} + +/** + * gts_eheap_insert_with_key: + * @heap: a #GtsEHeap. + * @p: a pointer to add to the heap. + * @key: the value of the key associated to @p. + * + * Inserts a new element @p in the heap. + * + * Returns: a #GtsEHeapPair describing the position of the element in the heap. + * This pointer is necessary for gts_eheap_remove() and + * gts_eheap_decrease_key(). + */ +GtsEHeapPair * gts_eheap_insert_with_key (GtsEHeap * heap, + gpointer p, + gdouble key) +{ + GtsEHeapPair * pair; + GPtrArray * elts; + + g_return_val_if_fail (heap != NULL, NULL); + + elts = heap->elts; + pair = g_malloc (sizeof (GtsEHeapPair)); + g_ptr_array_add (elts, pair); + pair->data = p; + pair->pos = elts->len; + pair->key = key; + if (!heap->frozen) + sift_up (heap, elts->len); + return pair; +} + +static void sift_down (GtsEHeap * heap, guint i) +{ + GtsEHeapPair * left_child, * right_child, * child, * parent; + guint lc, rc, c; + gpointer * pdata = heap->elts->pdata; + guint len = heap->elts->len; + gdouble key; + + lc = LEFT_CHILD (i); + rc = RIGHT_CHILD (i); + left_child = lc <= len ? pdata[lc - 1] : NULL; + right_child = rc <= len ? pdata[rc - 1] : NULL; + + parent = pdata[i - 1]; + key = parent->key; + while (left_child != NULL) { + if (right_child == NULL || left_child->key < right_child->key) { + child = left_child; + c = lc; + } + else { + child = right_child; + c = rc; + } + if (key > child->key) { + pdata[i - 1] = child; + child->pos = i; + pdata[c - 1] = parent; + parent->pos = c; + i = c; + lc = LEFT_CHILD (i); + rc = RIGHT_CHILD (i); + left_child = lc <= len ? pdata[lc - 1] : NULL; + right_child = rc <= len ? pdata[rc - 1] : NULL; + } + else + left_child = NULL; + } +} + +/** + * gts_eheap_remove_top: + * @heap: a #GtsEHeap. + * @key: a pointer on a gdouble or %NULL. + * + * Removes the element at the top of the heap and optionally (if @key is not + * %NULL) returns the value of its key. + * + * Returns: the element at the top of the heap. + */ +gpointer gts_eheap_remove_top (GtsEHeap * heap, gdouble * key) +{ + gpointer root; + GPtrArray * elts; + guint len; + GtsEHeapPair * pair; + + g_return_val_if_fail (heap != NULL, NULL); + + elts = heap->elts; + len = elts->len; + + if (len == 0) + return NULL; + if (len == 1) { + pair = g_ptr_array_remove_index (elts, 0); + root = pair->data; + if (key) + *key = pair->key; + g_free (pair); + return root; + } + + pair = elts->pdata[0]; + root = pair->data; + if (key) + *key = pair->key; + g_free (pair); + pair = g_ptr_array_remove_index (elts, len - 1); + elts->pdata[0] = pair; + pair->pos = 1; + sift_down (heap, 1); + return root; +} + +/** + * gts_eheap_top: + * @heap: a #GtsEHeap. + * @key: a pointer on a gdouble or %NULL. + * + * Returns: the element at the top of the heap and optionally (if @key is not + * %NULL) its key. + */ +gpointer gts_eheap_top (GtsEHeap * heap, gdouble * key) +{ + GtsEHeapPair * pair; + GPtrArray * elts; + + g_return_val_if_fail (heap != NULL, NULL); + + elts = heap->elts; + + if (elts->len == 0) + return NULL; + + pair = elts->pdata[0]; + if (key) + *key = pair->key; + return pair->data; +} + +/** + * gts_eheap_destroy: + * @heap: a #GtsEHeap. + * + * Free all the memory allocated for @heap. + */ +void gts_eheap_destroy (GtsEHeap * heap) +{ + guint i; + + g_return_if_fail (heap != NULL); + + for (i = 0; i < heap->elts->len; i++) + g_free (heap->elts->pdata[i]); + g_ptr_array_free (heap->elts, TRUE); + g_free (heap); +} + +/** + * gts_eheap_thaw: + * @heap: a #GtsEHeap. + * + * If @heap has been frozen previously using gts_eheap_freeze(), reorder it + * in O(n) time and unfreeze it. + */ +void gts_eheap_thaw (GtsEHeap * heap) +{ + guint i; + + g_return_if_fail (heap != NULL); + + if (!heap->frozen) + return; + + for (i = heap->elts->len/2; i > 0; i--) + sift_down (heap, i); + + heap->frozen = FALSE; +} + +/** + * gts_eheap_foreach: + * @heap: a #GtsEHeap. + * @func: the function to call for each element in the heap. + * @data: to pass to @func. + */ +void gts_eheap_foreach (GtsEHeap * heap, + GFunc func, + gpointer data) +{ + guint i; + GPtrArray * elts; + + g_return_if_fail (heap != NULL); + g_return_if_fail (func != NULL); + + elts = heap->elts; + for (i = 0; i < elts->len; i++) + (*func) (((GtsEHeapPair *) elts->pdata[i])->data, data); +} + +/** + * gts_eheap_remove: + * @heap: a #GtsEHeap. + * @p: a #GtsEHeapPair. + * + * Removes element corresponding to @p from @heap in O(log n). + * + * Returns: the element just removed from @heap. + */ +gpointer gts_eheap_remove (GtsEHeap * heap, GtsEHeapPair * p) +{ + GtsEHeapPair ** pdata; + GtsEHeapPair * parent; + guint i, par; + gpointer data; + + g_return_val_if_fail (heap != NULL, NULL); + g_return_val_if_fail (p != NULL, NULL); + + pdata = (GtsEHeapPair **)heap->elts->pdata; + i = p->pos; + data = p->data; + + g_return_val_if_fail (i > 0 && i <= heap->elts->len, NULL); + g_return_val_if_fail (p == pdata[i - 1], NULL); + + /* move element to the top */ + while ((par = PARENT (i))) { + parent = pdata[par - 1]; + pdata[par - 1] = p; + pdata[i - 1] = parent; + p->pos = par; + parent->pos = i; + i = par; + } + + gts_eheap_remove_top (heap, NULL); + + return data; +} + +/** + * gts_eheap_decrease_key: + * @heap: a #GtsEHeap. + * @p: a #GtsEHeapPair. + * @new_key: the new value of the key for this element. Must be smaller than + * the current key. + * + * Decreases the value of the key of the element at position @p. + */ +void gts_eheap_decrease_key (GtsEHeap * heap, + GtsEHeapPair * p, + gdouble new_key) +{ + guint i; + + g_return_if_fail (heap != NULL); + g_return_if_fail (p != NULL); + + i = p->pos; + g_return_if_fail (i > 0 && i <= heap->elts->len); + g_return_if_fail (p == heap->elts->pdata[i - 1]); + + g_return_if_fail (new_key <= p->key); + + p->key = new_key; + if (!heap->frozen) + sift_up (heap, i); +} + +/** + * gts_eheap_freeze: + * @heap: a #GtsEHeap. + * + * Freezes the heap. Any subsequent operation will not preserve the heap + * property. Used in conjunction with gts_eheap_insert() and gts_eheap_thaw() + * to create a heap in O(n) time. + */ +void gts_eheap_freeze (GtsEHeap * heap) +{ + g_return_if_fail (heap != NULL); + + heap->frozen = TRUE; +} + +/** + * gts_eheap_size: + * @heap: a #GtsEHeap. + * + * Returns: the number of items in @heap. + */ +guint gts_eheap_size (GtsEHeap * heap) +{ + g_return_val_if_fail (heap != NULL, 0); + + return heap->elts->len; +} + +/** + * gts_eheap_update: + * @heap: a #GtsEHeap. + * + * Updates the key of each element of @heap and reorders it. + */ +void gts_eheap_update (GtsEHeap * heap) +{ + guint i, len; + GtsEHeapPair ** pairs; + gpointer data; + GtsKeyFunc func; + + g_return_if_fail (heap != NULL); + g_return_if_fail (heap->func != NULL); + + heap->frozen = TRUE; + + len = heap->elts->len; + pairs = (GtsEHeapPair **) heap->elts->pdata; + data = heap->data; + func = heap->func; + + for (i = 0; i < len; i++) { + GtsEHeapPair * pair = pairs[i]; + pair->key = (*func) (pair->data, data); + } + + gts_eheap_thaw (heap); +} + +/** + * gts_eheap_key: + * @heap: a #GtsEHeap. + * @p: a pointer to be tested; + * + * Returns: the value of the key for pointer @p. + */ +gdouble gts_eheap_key (GtsEHeap * heap, gpointer p) +{ + g_return_val_if_fail (heap != NULL, 0.); + g_return_val_if_fail (heap->func != NULL, 0.); + + return (* heap->func) (p, heap->data); +} + +/** + * gts_eheap_randomized: + * @heap: a #GtsEHeap. + * @randomized: whether @heap should be randomized. + */ +void gts_eheap_randomized (GtsEHeap * heap, gboolean randomized) +{ + g_return_if_fail (heap != NULL); + + heap->randomized = randomized; +} Index: work/obsolete/toporouter/src_3rd/gts/face.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/face.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/face.c (revision 6803) @@ -0,0 +1,297 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gts.h" + +gboolean gts_allow_floating_faces = FALSE; + +static void face_destroy (GtsObject * object) +{ + GtsFace * face = GTS_FACE (object); + GSList * i; + + i = face->surfaces; + while (i) { + GSList * next = i->next; + gts_surface_remove_face (i->data, face); + i = next; + } + g_assert (face->surfaces == NULL); + + (* GTS_OBJECT_CLASS (gts_face_class ())->parent_class->destroy) (object); +} + +static void face_clone (GtsObject * clone, GtsObject * object) +{ + (* GTS_OBJECT_CLASS (gts_face_class ())->parent_class->clone) (clone, + object); + GTS_FACE (clone)->surfaces = NULL; +} + +static void face_class_init (GtsFaceClass * klass) +{ + GTS_OBJECT_CLASS (klass)->clone = face_clone; + GTS_OBJECT_CLASS (klass)->destroy = face_destroy; +} + +static void face_init (GtsFace * face) +{ + face->surfaces = NULL; +} + +/** + * gts_face_class: + * + * Returns: the #GtsFaceClass. + */ +GtsFaceClass * gts_face_class (void) +{ + static GtsFaceClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo face_info = { + "GtsFace", + sizeof (GtsFace), + sizeof (GtsFaceClass), + (GtsObjectClassInitFunc) face_class_init, + (GtsObjectInitFunc) face_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_triangle_class ()), + &face_info); + } + + return klass; +} + +/** + * gts_face_new: + * @klass: a #GtsFaceClass. + * @e1: a #GtsEdge. + * @e2: a #GtsEdge. + * @e3: a #GtsEdge. + * + * Returns: a new #GtsFace using @e1, @e2 and @e3 as edges. + */ +GtsFace * gts_face_new (GtsFaceClass * klass, + GtsEdge * e1, GtsEdge * e2, GtsEdge * e3) +{ + GtsFace * f; + + f = GTS_FACE (gts_object_new (GTS_OBJECT_CLASS (klass))); + gts_triangle_set (GTS_TRIANGLE (f), e1, e2, e3); + + return f; +} + +/** + * gts_face_has_parent_surface: + * @f: a #GtsFace. + * @s: a #GtsSurface. + * + * Returns: %TRUE if @f belongs to @s, %FALSE otherwise. + */ +gboolean gts_face_has_parent_surface (GtsFace * f, GtsSurface * s) +{ + GSList * i; + + g_return_val_if_fail (f != NULL, FALSE); + + i = f->surfaces; + while (i) { + if (i->data == s) + return TRUE; + i = i->next; + } + return FALSE; +} + +/** + * gts_faces_from_edges: + * @edges: a list of #GtsEdge. + * @s: a #GtsSurface or %NULL. + * + * Builds a list of unique faces which belong to @s and have + * one of their edges in @edges. + * + * Returns: the list of faces. + */ +GSList * gts_faces_from_edges (GSList * edges, GtsSurface * s) +{ + GHashTable * hash; + GSList * faces = NULL, * i; + + hash = g_hash_table_new (NULL, NULL); + i = edges; + while (i) { + GSList * j = GTS_EDGE (i->data)->triangles; + while (j) { + GtsTriangle * t = j->data; + if (GTS_IS_FACE (t) && + (!s || gts_face_has_parent_surface (GTS_FACE (t), s)) && + g_hash_table_lookup (hash, t) == NULL) { + faces = g_slist_prepend (faces, t); + g_hash_table_insert (hash, t, i); + } + j = j->next; + } + i = i->next; + } + g_hash_table_destroy (hash); + + return faces; +} + +/** + * gts_face_neighbor_number: + * @f: a #GtsFace. + * @s: a #GtsSurface or %NULL. + * + * Returns: the number of faces neighbors of @f and belonging to @s. + */ +guint gts_face_neighbor_number (GtsFace * f, GtsSurface * s) +{ + GSList * i; + guint nn = 0; + GtsEdge * e[4], ** e1 = e; + + g_return_val_if_fail (f != NULL, 0); + + e[0] = GTS_TRIANGLE (f)->e1; + e[1] = GTS_TRIANGLE (f)->e2; + e[2] = GTS_TRIANGLE (f)->e3; + e[3] = NULL; + while (*e1) { + i = (*e1++)->triangles; + while (i) { + GtsTriangle * t = i->data; + if (GTS_FACE (t) != f && + GTS_IS_FACE (t) && + (!s || gts_face_has_parent_surface (GTS_FACE (t), s))) + nn++; + i = i->next; + } + } + + return nn; +} + +/** + * gts_face_neighbors: + * @f: a #GtsFace. + * @s: a #GtsSurface or %NULL. + * + * Returns: a list of unique #GtsFace neighbors of @f and belonging to @s. + */ +GSList * gts_face_neighbors (GtsFace * f, GtsSurface * s) +{ + GSList * i, * list = NULL; + GtsEdge * e[4], ** e1 = e; + + g_return_val_if_fail (f != NULL, NULL); + + e[0] = GTS_TRIANGLE (f)->e1; + e[1] = GTS_TRIANGLE (f)->e2; + e[2] = GTS_TRIANGLE (f)->e3; + e[3] = NULL; + while (*e1) { + i = (*e1++)->triangles; + while (i) { + GtsTriangle * t = i->data; + if (GTS_FACE (t) != f && + GTS_IS_FACE (t) && + (!s || gts_face_has_parent_surface (GTS_FACE (t), s))) + list = g_slist_prepend (list, t); + i = i->next; + } + } + + return list; +} + +/** + * gts_face_foreach_neighbor: + * @f: a #GtsFace. + * @s: a #GtsSurface or %NULL. + * @func: a #GtsFunc. + * @data: user data to pass to @func. + * + * Calls @func for each neighbor of @f belonging to @s (if not %NULL). + */ +void gts_face_foreach_neighbor (GtsFace * f, + GtsSurface * s, + GtsFunc func, + gpointer data) +{ + GSList * i; + GtsEdge * e[4], ** e1 = e; + + g_return_if_fail (f != NULL); + g_return_if_fail (func != NULL); + + e[0] = GTS_TRIANGLE (f)->e1; + e[1] = GTS_TRIANGLE (f)->e2; + e[2] = GTS_TRIANGLE (f)->e3; + e[3] = NULL; + while (*e1) { + i = (*e1++)->triangles; + while (i) { + GtsTriangle * t = i->data; + if (GTS_FACE (t) != f && + GTS_IS_FACE (t) && + (!s || gts_face_has_parent_surface (GTS_FACE (t), s))) + (* func) (t, data); + i = i->next; + } + } +} + +static gboolean triangle_is_incompatible (GtsTriangle * t, GtsEdge * e, GtsSurface * s) +{ + GSList * i = e->triangles; + + while (i) { + if (i->data != t && + GTS_IS_FACE (i->data) && + gts_face_has_parent_surface (i->data, s) && + !gts_triangles_are_compatible (t, i->data, e)) + return TRUE; + i = i->next; + } + return FALSE; +} + +/** + * gts_face_is_compatible: + * @f: a #GtsFace. + * @s: a #GtsSurface. + * + * Returns: %TRUE if @f is compatible with all its neighbors belonging + * to @s, %FALSE otherwise. + */ +gboolean gts_face_is_compatible (GtsFace * f, GtsSurface * s) +{ + g_return_val_if_fail (f != NULL, FALSE); + g_return_val_if_fail (s != NULL, FALSE); + + return !(triangle_is_incompatible (GTS_TRIANGLE (f), GTS_TRIANGLE (f)->e1, s) || + triangle_is_incompatible (GTS_TRIANGLE (f), GTS_TRIANGLE (f)->e2, s) || + triangle_is_incompatible (GTS_TRIANGLE (f), GTS_TRIANGLE (f)->e3, s)); +} Index: work/obsolete/toporouter/src_3rd/gts/fifo.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/fifo.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/fifo.c (revision 6803) @@ -0,0 +1,192 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gts.h" + +struct _GtsFifo { + GList * head; + GList * tail; +}; + +/** + * gts_fifo_new: + * + * Returns: a new #GtsFifo. + */ +GtsFifo * gts_fifo_new () +{ + GtsFifo * fifo = g_malloc (sizeof (GtsFifo)); + + fifo->head = fifo->tail = NULL; + return fifo; +} + +/** + * gts_fifo_write: + * @fifo: a #GtsFifo. + * @fp: a file pointer. + * + * Writes the content of @fifo in @fp. + */ +void gts_fifo_write (GtsFifo * fifo, FILE * fp) +{ + GList * i; + + g_return_if_fail (fifo != NULL); + g_return_if_fail (fp != NULL); + + fprintf (fp, "["); + i = fifo->head; + while (i) { + fprintf (fp, "%p ", i->data); + i = i->next; + } + fprintf (fp, "]"); +} + +/** + * gts_fifo_push: + * @fifo: a #GtsFifo. + * @data: data to add to @fifo. + * + * Push @data into @fifo. + */ +void gts_fifo_push (GtsFifo * fifo, gpointer data) +{ + g_return_if_fail (fifo != NULL); + + fifo->head = g_list_prepend (fifo->head, data); + if (fifo->tail == NULL) + fifo->tail = fifo->head; +} + +/** + * gts_fifo_pop: + * @fifo: a #GtsFifo. + * + * Removes the first element from @fifo. + * + * Returns: the first element in @fifo or %NULL if @fifo is empty. + */ +gpointer gts_fifo_pop (GtsFifo * fifo) +{ + gpointer data; + GList * tail; + + g_return_val_if_fail (fifo != NULL, NULL); + + if (fifo->tail == NULL) + return NULL; + tail = fifo->tail->prev; + data = fifo->tail->data; + fifo->head = g_list_remove_link (fifo->head, fifo->tail); + g_list_free_1 (fifo->tail); + fifo->tail = tail; + return data; +} + +/** + * gts_fifo_top: + * @fifo: a #GtsFifo. + * + * Returns: the first element in @fifo or %NULL if @fifo is empty. + */ +gpointer gts_fifo_top (GtsFifo * fifo) +{ + g_return_val_if_fail (fifo != NULL, NULL); + + if (fifo->tail == NULL) + return NULL; + return fifo->tail->data; +} + +/** + * gts_fifo_size: + * @fifo: a #GtsFifo. + * + * Returns: the number of elements in @fifo. + */ +guint gts_fifo_size (GtsFifo * fifo) +{ + g_return_val_if_fail (fifo != NULL, 0); + + return g_list_length (fifo->head); +} + +/** + * gts_fifo_destroy: + * @fifo: a #GtsFifo. + * + * Frees all the memory allocated for @fifo. + */ +void gts_fifo_destroy (GtsFifo * fifo) +{ + g_return_if_fail (fifo != NULL); + g_list_free (fifo->head); + g_free (fifo); +} + +/** + * gts_fifo_is_empty: + * @fifo: a #GtsFifo. + * + * Returns: %TRUE if @fifo is empty, %FALSE otherwise. + */ +gboolean gts_fifo_is_empty (GtsFifo * fifo) +{ + g_return_val_if_fail (fifo != NULL, TRUE); + + return (fifo->head == NULL); +} + +/** + * gts_fifo_foreach: + * @fifo: a #GtsFifo. + * @func: a #GtsFunc. + * @data: user data to be passed to @func. + * + * Calls @func in order for each item in @fifo, passing @data. + */ +void gts_fifo_foreach (GtsFifo * fifo, GtsFunc func, gpointer data) +{ + GList * i; + + g_return_if_fail (fifo != NULL); + g_return_if_fail (func != NULL); + + i = fifo->tail; + while (i) { + (* func) (i->data, data); + i = i->prev; + } +} + +/** + * gts_fifo_reverse: + * @fifo: a #GtsFifo. + * + * Reverses the order of elements in @fifo. + */ +void gts_fifo_reverse (GtsFifo * fifo) +{ + g_return_if_fail (fifo != NULL); + + fifo->tail = fifo->head; + fifo->head = g_list_reverse (fifo->head); +} Index: work/obsolete/toporouter/src_3rd/gts/graph.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/graph.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/graph.c (revision 6803) @@ -0,0 +1,1776 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include "gts.h" + +/* GtsGNode */ + +gboolean gts_allow_floating_gnodes = FALSE; + +static void gnode_remove_container (GtsContainee * i, GtsContainer * c) +{ + (* GTS_CONTAINEE_CLASS (GTS_OBJECT_CLASS (gts_gnode_class ())->parent_class)->remove_container) (i, c); + if (GTS_SLIST_CONTAINEE (i)->containers == NULL && + !gts_allow_floating_gnodes && + !GTS_OBJECT_DESTROYED(GTS_OBJECT (i))) + gts_object_destroy (GTS_OBJECT (i)); +} + +static void gnode_class_init (GtsGNodeClass * klass) +{ + klass->weight = NULL; + + GTS_CONTAINEE_CLASS (klass)->remove_container = gnode_remove_container; +} + +static void gnode_init (GtsGNode * n) +{ + n->level = 0; +} + +/** + * gts_gnode_class: + * + * Returns: the #GtsGNodeClass. + */ +GtsGNodeClass * gts_gnode_class (void) +{ + static GtsGNodeClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo gnode_info = { + "GtsGNode", + sizeof (GtsGNode), + sizeof (GtsGNodeClass), + (GtsObjectClassInitFunc) gnode_class_init, + (GtsObjectInitFunc) gnode_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = + gts_object_class_new (GTS_OBJECT_CLASS (gts_slist_container_class ()), + &gnode_info); + } + + return klass; +} + +/** + * gts_gnode_new: + * @klass: a #GtsGNodeClass. + * + * Returns: a new #GtsGNode. + */ +GtsGNode * gts_gnode_new (GtsGNodeClass * klass) +{ + GtsGNode * object; + + object = GTS_GNODE (gts_object_new (GTS_OBJECT_CLASS (klass))); + + return object; +} + +/** + * gts_gnode_foreach_neighbor: + * @n: a #GtsGNode. + * @g: a #GtsGraph or %NULL. + * @func: a #GtsFunc. + * @data: user data to be passed to @func. + * + * Calls @func for each neighbor #GtsGNode of @n (belonging to @g if + * @g is not %NULL. + */ +void gts_gnode_foreach_neighbor (GtsGNode * n, + GtsGraph * g, + GtsFunc func, + gpointer data) +{ + GSList * i; + + g_return_if_fail (n != NULL); + g_return_if_fail (func != NULL); + + i = GTS_SLIST_CONTAINER (n)->items; + while (i) { + GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); + if (g == NULL || gts_containee_is_contained (GTS_CONTAINEE (n1), + GTS_CONTAINER (g))) + (* func) (n1, data); + i = i->next; + } +} + +/** + * gts_gnode_foreach_edge: + * @n: a #GtsGNode. + * @g: a #GtsGraph or %NULL. + * @func: a #GtsFunc. + * @data: user data to be passed to @func. + * + * Calls @func for each #GtsGEdge connecting @n to another #GtsGNode + * (belonging to @g if @g is not %NULL. + */ +void gts_gnode_foreach_edge (GtsGNode * n, + GtsGraph * g, + GtsFunc func, + gpointer data) +{ + GSList * i; + + g_return_if_fail (n != NULL); + g_return_if_fail (func != NULL); + + i = GTS_SLIST_CONTAINER (n)->items; + while (i) { + GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); + if (g == NULL || gts_containee_is_contained (GTS_CONTAINEE (n1), + GTS_CONTAINER (g))) + (* func) (i->data, data); + i = i->next; + } +} + +/** + * gts_gnode_degree: + * @n: a #GtsGNode. + * @g: a #GtsGraph or %NULL. + * + * Returns: the number of neighbors of @n (belonging to @g if @g is not %NULL). + */ +guint gts_gnode_degree (GtsGNode * n, + GtsGraph * g) +{ + GSList * i; + guint nn = 0; + + g_return_val_if_fail (n != NULL, 0); + + i = GTS_SLIST_CONTAINER (n)->items; + while (i) { + GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); + if (g == NULL || gts_containee_is_contained (GTS_CONTAINEE (n1), + GTS_CONTAINER (g))) + nn++; + i = i->next; + } + + return nn; +} + +/** + * gts_gnode_move_cost: + * @n: a #GtsGNode. + * @src: a #GtsGraph containing @n. + * @dst: another #GtsGraph. + * + * Returns: the cost (increase in the sum of the weights of the edges cut) of + * moving @n from @src to @dst. + */ +gfloat gts_gnode_move_cost (GtsGNode * n, + GtsGraph * src, + GtsGraph * dst) +{ + GSList * i; + gfloat cost = 0.; + + g_return_val_if_fail (n != NULL, G_MAXFLOAT); + g_return_val_if_fail (src != NULL, G_MAXFLOAT); + g_return_val_if_fail (dst != NULL, G_MAXFLOAT); + g_return_val_if_fail (gts_containee_is_contained (GTS_CONTAINEE (n), + GTS_CONTAINER (src)), + G_MAXFLOAT); + + i = GTS_SLIST_CONTAINER (n)->items; + while (i) { + GtsGEdge * ge = i->data; + GtsGNode * neighbor = GTS_GNODE_NEIGHBOR (n, ge); + + if (gts_containee_is_contained (GTS_CONTAINEE (neighbor), + GTS_CONTAINER (src))) + cost += gts_gedge_weight (ge); + else if (gts_containee_is_contained (GTS_CONTAINEE (neighbor), + GTS_CONTAINER (dst))) + cost -= gts_gedge_weight (ge); + i = i->next; + } + + return cost; +} + +/** + * gts_gnode_weight: + * @n: a #GtsGNode. + * + * Returns: the weight of @n as defined by the weight() method of the + * #GtsGNodeClass. + */ +gfloat gts_gnode_weight (GtsGNode * n) +{ + g_return_val_if_fail (n != NULL, 0.); + + if (GTS_GNODE_CLASS (GTS_OBJECT (n)->klass)->weight) + return (* GTS_GNODE_CLASS (GTS_OBJECT (n)->klass)->weight) (n); + return 1.; +} + +/* GtsNGNode */ + +static void ngnode_init (GtsNGNode * n) +{ + n->id = 0; +} + +/** + * gts_ngnode_class: + * + * Returns: the #GtsNGNodeClass. + */ +GtsNGNodeClass * gts_ngnode_class (void) +{ + static GtsNGNodeClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo ngnode_info = { + "GtsNGNode", + sizeof (GtsNGNode), + sizeof (GtsNGNodeClass), + (GtsObjectClassInitFunc) NULL, + (GtsObjectInitFunc) ngnode_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()), + &ngnode_info); + } + + return klass; +} + +/** + * gts_ngnode_new: + * @klass: a #GtsNGNodeClass. + * + * Returns: a new #GtsNGNode with identity @id. + */ +GtsNGNode * gts_ngnode_new (GtsNGNodeClass * klass, + guint id) +{ + GtsNGNode * n; + + n = GTS_NGNODE (gts_gnode_new (GTS_GNODE_CLASS (klass))); + n->id = id; + + return n; +} + +/* GtsWGNode */ + +static gfloat wgnode_weight (GtsGNode * n) +{ + return GTS_WGNODE (n)->weight; +} + +static void wgnode_class_init (GtsWGNodeClass * klass) +{ + GTS_GNODE_CLASS (klass)->weight = wgnode_weight; +} + +static void wgnode_init (GtsWGNode * n) +{ + n->weight = 1.; +} + +/** + * gts_wgnode_class: + * + * Returns: the #GtsWGNodeClass. + */ +GtsWGNodeClass * gts_wgnode_class (void) +{ + static GtsWGNodeClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo wgnode_info = { + "GtsWGNode", + sizeof (GtsWGNode), + sizeof (GtsWGNodeClass), + (GtsObjectClassInitFunc) wgnode_class_init, + (GtsObjectInitFunc) wgnode_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()), + &wgnode_info); + } + + return klass; +} + +/** + * gts_wgnode_new: + * @klass: a #GtsWGNodeClass. + * @weight: the weight of the #GtsWGNode to create. + * + * Returns: a new #GtsWGNode of weight @weight. + */ +GtsWGNode * gts_wgnode_new (GtsWGNodeClass * klass, + gfloat weight) +{ + GtsWGNode * n; + + n = GTS_WGNODE (gts_gnode_new (GTS_GNODE_CLASS (klass))); + n->weight = weight; + + return n; +} + +/* GtsPNode */ + +static void pnode_write (GtsGNode * n, FILE * fp) +{ + if (GTS_IS_NVERTEX (GTS_PNODE (n)->data)) + fprintf (fp, "label=\"%p:%s\",", + GTS_PNODE (n)->data, + GTS_NVERTEX (GTS_PNODE (n)->data)->name); + else + fprintf (fp, "label=\"%p\",", GTS_PNODE (n)->data); +} + +static void pnode_class_init (GtsPNodeClass * klass) +{ + GTS_GNODE_CLASS (klass)->write = pnode_write; +} + +static void pnode_init (GtsPNode * pn) +{ + pn->data = NULL; +} + +/** + * gts_pnode_class: + * + * Returns: the #GtsPNodeClass. + */ +GtsPNodeClass * gts_pnode_class (void) +{ + static GtsPNodeClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo pnode_info = { + "GtsPNode", + sizeof (GtsPNode), + sizeof (GtsPNodeClass), + (GtsObjectClassInitFunc) pnode_class_init, + (GtsObjectInitFunc) pnode_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()), + &pnode_info); + } + + return klass; +} + +/** + * gts_pnode_new: + * @klass: a #GtsPNodeClass. + * @data: user data. + * + * Returns: a new #GtsPNode associated with @data. + */ +GtsPNode * gts_pnode_new (GtsPNodeClass * klass, gpointer data) +{ + GtsPNode * pn; + + pn = GTS_PNODE (gts_object_new (GTS_OBJECT_CLASS (klass))); + pn->data = data; + + return pn; +} + +/* GtsFNode */ + +static void fnode_write (GtsGNode * n, FILE * fp) +{ + fprintf (fp, "label=\"%p\",", GTS_FNODE (n)->f); +} + +static void fnode_class_init (GtsGNodeClass * klass) +{ + klass->write = fnode_write; +} + +static void fnode_init (GtsFNode * fn) +{ + fn->f = NULL; +} + +/** + * gts_fnode_class: + * + * Returns: the #GtsFNodeClass. + */ +GtsFNodeClass * gts_fnode_class (void) +{ + static GtsFNodeClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo fnode_info = { + "GtsFNode", + sizeof (GtsFNode), + sizeof (GtsFNodeClass), + (GtsObjectClassInitFunc) fnode_class_init, + (GtsObjectInitFunc) fnode_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()), + &fnode_info); + } + + return klass; +} + +/** + * gts_fnode_new: + * @klass: a #GtsFNodeClass. + * @f: a #GtsFace. + * + * Returns: a new #GtsFNode associated with face @f. + */ +GtsFNode * gts_fnode_new (GtsFNodeClass * klass, GtsFace * f) +{ + GtsFNode * fn; + + g_return_val_if_fail (f != NULL, NULL); + + fn = GTS_FNODE (gts_object_new (GTS_OBJECT_CLASS (klass))); + fn->f = f; + + return fn; +} + +/* GtsGEdge */ + +static void gedge_destroy (GtsObject * object) +{ + GtsGEdge * ge = GTS_GEDGE (object); + + if (ge->n1) + gts_container_remove (GTS_CONTAINER (ge->n1), GTS_CONTAINEE (ge)); + if (ge->n2) + gts_container_remove (GTS_CONTAINER (ge->n2), GTS_CONTAINEE (ge)); + + (* GTS_OBJECT_CLASS (gts_gedge_class ())->parent_class->destroy) (object); +} + +static void gedge_remove_container (GtsContainee * i, GtsContainer * c) +{ + GtsGEdge * ge = GTS_GEDGE (i); + GtsGNode * n1 = ge->n1; + GtsGNode * n2 = ge->n2; + + ge->n1 = ge->n2 = NULL; + if (n1 != NULL && n2 != NULL) { + if (GTS_CONTAINER (n1) == c) { + if (n2 && n2 != n1) gts_container_remove (GTS_CONTAINER (n2), i); + } + else if (GTS_CONTAINER (n2) == c) { + if (n1 && n1 != n2) gts_container_remove (GTS_CONTAINER (n1), i); + } + else + g_assert_not_reached (); + (* GTS_OBJECT_CLASS (gts_gedge_class ())->parent_class->destroy) + (GTS_OBJECT (i)); + } +} + +static gboolean gedge_is_contained (GtsContainee * i, GtsContainer * c) +{ + GtsGEdge * ge = GTS_GEDGE (i); + + if (GTS_CONTAINER (ge->n1) == c || GTS_CONTAINER (ge->n2) == c) + return TRUE; + return FALSE; +} + +static void gedge_class_init (GtsGEdgeClass * klass) +{ + klass->link = NULL; + klass->weight = NULL; + + GTS_CONTAINEE_CLASS (klass)->remove_container = gedge_remove_container; + GTS_CONTAINEE_CLASS (klass)->is_contained = gedge_is_contained; + + GTS_OBJECT_CLASS (klass)->destroy = gedge_destroy; +} + +static void gedge_init (GtsGEdge * object) +{ + object->n1 = object->n2 = NULL; +} + +/** + * gts_gedge_class: + * + * Returns: the #GtsGEdgeClass. + */ +GtsGEdgeClass * gts_gedge_class (void) +{ + static GtsGEdgeClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo gedge_info = { + "GtsGEdge", + sizeof (GtsGEdge), + sizeof (GtsGEdgeClass), + (GtsObjectClassInitFunc) gedge_class_init, + (GtsObjectInitFunc) gedge_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_containee_class ()), + &gedge_info); + } + + return klass; +} + +/** + * gts_gedge_new: + * @klass: a #GtsGEdgeClass. + * @n1: a #GtsGNode. + * @n2: another #GtsGNode. + * + * Returns: a new #GtsGEdge linking @n1 and @n2. + */ +GtsGEdge * gts_gedge_new (GtsGEdgeClass * klass, GtsGNode * n1, GtsGNode * n2) +{ + GtsGEdge * object; + + g_return_val_if_fail (n1 != NULL, NULL); + g_return_val_if_fail (n2 != NULL, NULL); + + object = GTS_GEDGE (gts_object_new (GTS_OBJECT_CLASS (klass))); + object->n1 = n1; + gts_container_add (GTS_CONTAINER (n1), GTS_CONTAINEE (object)); + object->n2 = n2; + if (n1 != n2) + gts_container_add (GTS_CONTAINER (n2), GTS_CONTAINEE (object)); + + if (klass->link) + object = (* klass->link) (object, n1, n2); + + return object; +} + +/** + * gts_gedge_weight: + * @e: a #GtsGEdge. + * + * Returns: the weight of edge @e as defined by the weight() method of + * #GtsGEdgeClass. + */ +gfloat gts_gedge_weight (GtsGEdge * e) +{ + g_return_val_if_fail (e != NULL, 0.); + + if (GTS_GEDGE_CLASS (GTS_OBJECT (e)->klass)->weight) + return (* GTS_GEDGE_CLASS (GTS_OBJECT (e)->klass)->weight) (e); + return 1.; +} + +/* GtsPGEdge */ + +static void pgedge_write (GtsGEdge * ge, FILE * fp) +{ + if (GTS_IS_EDGE (GTS_PGEDGE (ge)->data)) { + GtsEdge * e = GTS_PGEDGE (ge)->data; + guint n = g_slist_length (e->triangles); + + fprintf (fp, "label=\"%p:%s:%d\",color=%s", e, + GTS_IS_NEDGE (e) ? GTS_NEDGE (e)->name : "", + n, + n == 0 ? "black" : + n == 1 ? "blue" : + n == 2 ? "green" : + n == 3 ? "violet" : + n == 4 ? "red" : + "pink"); + } + else + fprintf (fp, "label=\"%p\",", GTS_PGEDGE (ge)->data); +} + +static void pgedge_class_init (GtsPGEdgeClass * klass) +{ + GTS_GEDGE_CLASS (klass)->write = pgedge_write; +} + +static void pgedge_init (GtsPGEdge * e) +{ + e->data = NULL; +} + +/** + * gts_pgedge_class: + * + * Returns: the #GtsPGEdgeClass. + */ +GtsPGEdgeClass * gts_pgedge_class (void) +{ + static GtsPGEdgeClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo pgedge_info = { + "GtsPGEdge", + sizeof (GtsPGEdge), + sizeof (GtsPGEdgeClass), + (GtsObjectClassInitFunc) pgedge_class_init, + (GtsObjectInitFunc) pgedge_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gedge_class ()), + &pgedge_info); + } + + return klass; +} + +/** + * gts_pgedge_new: + * @klass: a #GtsPGEdgeClass. + * @n1: a #GtsGNode. + * @n2: another #GtsGNode. + * @data: user data. + * + * Returns: a new #GtsPGEdge associated with @data linking @n1 and @n2. + */ +GtsPGEdge * gts_pgedge_new (GtsPGEdgeClass * klass, + GtsGNode * g1, + GtsGNode * g2, + gpointer data) +{ + GtsPGEdge * we; + + we = GTS_PGEDGE (gts_gedge_new (GTS_GEDGE_CLASS (klass), g1, g2)); + we->data = data; + + return we; +} + +/* GtsWGEdge */ + +static gfloat wgedge_weight (GtsGEdge * e) +{ + return GTS_WGEDGE (e)->weight; +} + +static void wgedge_class_init (GtsWGEdgeClass * klass) +{ + GTS_GEDGE_CLASS (klass)->weight = wgedge_weight; +} + +static void wgedge_init (GtsWGEdge * e) +{ + e->weight = 1.; +} + +/** + * gts_wgedge_class: + * + * Returns: the #GtsWGEdgeClass. + */ +GtsWGEdgeClass * gts_wgedge_class (void) +{ + static GtsWGEdgeClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo wgedge_info = { + "GtsWGEdge", + sizeof (GtsWGEdge), + sizeof (GtsWGEdgeClass), + (GtsObjectClassInitFunc) wgedge_class_init, + (GtsObjectInitFunc) wgedge_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_gedge_class ()), + &wgedge_info); + } + + return klass; +} + +/** + * gts_wgedge_new: + * @klass: a #GtsWGEdgeClass. + * @n1: a #GtsGNode. + * @n2: another #GtsGNode. + * @weight: the weight of the new edge. + * + * Returns: a new #GtsWGEdge of weight @weight linking @n1 and @n2. + */ +GtsWGEdge * gts_wgedge_new (GtsWGEdgeClass * klass, + GtsGNode * g1, + GtsGNode * g2, + gfloat weight) +{ + GtsWGEdge * we; + + we = GTS_WGEDGE (gts_gedge_new (GTS_GEDGE_CLASS (klass), g1, g2)); + we->weight = weight; + + return we; +} + +/* GtsGraph */ + +static void graph_init (GtsGraph * g) +{ + g->graph_class = gts_graph_class (); + g->node_class = gts_gnode_class (); + g->edge_class = gts_gedge_class (); +} + +static void graph_write (GtsObject * object, FILE * fp) +{ + GtsGraph * graph = GTS_GRAPH (object); + + fprintf (fp, " %s %s %s", + object->klass->info.name, + GTS_OBJECT_CLASS (graph->node_class)->info.name, + GTS_OBJECT_CLASS (graph->edge_class)->info.name); +} + +static void graph_read (GtsObject ** object, GtsFile * f) +{ + GtsObjectClass * klass; + + if (f->type != GTS_STRING) { + gts_file_error (f, "expecting a string (GtsGNodeClass)"); + return; + } + klass = gts_object_class_from_name (f->token->str); + if (klass == NULL) { + gts_file_error (f, "unknown class `%s'", f->token->str); + return; + } + if (!gts_object_class_is_from_class (klass, gts_gnode_class ())) { + gts_file_error (f, "class `%s' is not a GtsGNodeClass", f->token->str); + return; + } + GTS_GRAPH (*object)->node_class = GTS_GNODE_CLASS (klass); + gts_file_next_token (f); + + if (f->type != GTS_STRING) { + gts_file_error (f, "expecting a string (GtsGEdgeClass)"); + return; + } + klass = gts_object_class_from_name (f->token->str); + if (klass == NULL) { + gts_file_error (f, "unknown class `%s'", f->token->str); + return; + } + if (!gts_object_class_is_from_class (klass, gts_gedge_class ())) { + gts_file_error (f, "class `%s' is not a GtsGEdgeClass", f->token->str); + return; + } + GTS_GRAPH (*object)->edge_class = GTS_GEDGE_CLASS (klass); + gts_file_next_token (f); +} + +static void graph_class_init (GtsGraphClass * klass) +{ + klass->weight = NULL; + + GTS_OBJECT_CLASS (klass)->write = graph_write; + GTS_OBJECT_CLASS (klass)->read = graph_read; +} + +/** + * gts_graph_class: + * + * Returns: the #GtsGraphClass. + */ +GtsGraphClass * gts_graph_class (void) +{ + static GtsGraphClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo graph_info = { + "GtsGraph", + sizeof (GtsGraph), + sizeof (GtsGraphClass), + (GtsObjectClassInitFunc) graph_class_init, + (GtsObjectInitFunc) graph_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_hash_container_class ()), + &graph_info); + } + + return klass; +} + +/** + * gts_graph_new: + * @klass: a #GtsGraphClass. + * @node_class: a #GtsGNodeClass. + * @edge_class: a #GtsGEdgeClass. + * + * Returns: a new #GtsGraph using @node_class and @edge_class as node types. + */ +GtsGraph * gts_graph_new (GtsGraphClass * klass, + GtsGNodeClass * node_class, + GtsGEdgeClass * edge_class) +{ + GtsGraph * g; + + g_return_val_if_fail (klass != NULL, NULL); + g_return_val_if_fail (node_class != NULL, NULL); + g_return_val_if_fail (edge_class != NULL, NULL); + + g = GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (klass))); + g->node_class = node_class; + g->edge_class = edge_class; + + return g; +} + +static void compute_degree (GtsGNode * n, gpointer * data) +{ + GtsGraph * g = data[0]; + GtsRange * degree = data[1]; + + gts_range_add_value (degree, gts_gnode_degree (n, g)); +} + +/** + * gts_graph_print_stats: + * @g: a #GtsGraph. + * @fp: a file pointer. + * + * Writes to @fp a summary of the properties of @g. + */ +void gts_graph_print_stats (GtsGraph * g, FILE * fp) +{ + GtsRange degree; + gpointer data[2]; + + g_return_if_fail (g != NULL); + g_return_if_fail (fp != NULL); + + fprintf (fp, "# nodes: %d weight: %g\n", + gts_container_size (GTS_CONTAINER (g)), + gts_graph_weight (g)); + fprintf (fp, "# degree: "); + gts_range_init (°ree); + data[0] = g; + data[1] = °ree; + gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) compute_degree, data); + gts_range_update (°ree); + gts_range_print (°ree, fp); + fprintf (fp, "\n"); + fprintf (fp, "# edges cut: %d edges cut weight: %g\n", + gts_graph_edges_cut (g), + gts_graph_edges_cut_weight (g)); +} + +struct _GtsGraphTraverse { + GtsFifo * q; + GtsGraph * g; +}; + +static void reset_level (GtsGNode * n) +{ + n->level = 0; +} + +/** + * gts_graph_traverse_new: + * @g: a #GtsGraph. + * @n: a #GtsGNode belonging to @g. + * @type: the type of traversal. + * @reinit: if %TRUE, the traversal is reinitialized. + * + * Returns: a new #GtsGraphTraverse initialized for the traversal of + * @g of type @type, starting from @n. + */ +GtsGraphTraverse * gts_graph_traverse_new (GtsGraph * g, + GtsGNode * n, + GtsTraverseType type, + gboolean reinit) +{ + GtsGraphTraverse * t; + + g_return_val_if_fail (g != NULL, NULL); + g_return_val_if_fail (n != NULL, NULL); + g_return_val_if_fail (gts_containee_is_contained (GTS_CONTAINEE (n), + GTS_CONTAINER (g)), + NULL); + + if (reinit) + gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) reset_level, NULL); + + t = g_malloc (sizeof (GtsGraphTraverse)); + t->q = gts_fifo_new (); + t->g = g; + n->level = 1; + gts_fifo_push (t->q, n); + + return t; +} + +static void push_neighbor (GtsGNode * n, gpointer * data) +{ + GtsFifo * q = data[0]; + GtsGNode * u = data[1]; + + if (n->level == 0) { + n->level = u->level + 1; + gts_fifo_push (q, n); + } +} + +/** + * gts_graph_traverse_next: + * @t: a #GtsGraphTraverse. + * + * Returns: the next #GtsGNode of the traversal defined by @t or %NULL + * if the traversal is complete. + */ +GtsGNode * gts_graph_traverse_next (GtsGraphTraverse * t) +{ + GtsGNode * u; + + g_return_val_if_fail (t != NULL, NULL); + + u = gts_fifo_pop (t->q); + if (u) { + gpointer data[2]; + + data[0] = t->q; + data[1] = u; + gts_gnode_foreach_neighbor (u, t->g, (GtsFunc) push_neighbor, data); + } + + return u; +} + +/** + * gts_graph_traverse_what_next: + * @t: a #GtsGraphTraverse. + * + * Returns: the next #GtsGNode of the traversal defined by @t or %NULL + * if the traversal is complete but without advancing the traversal. + */ +GtsGNode * gts_graph_traverse_what_next (GtsGraphTraverse * t) +{ + g_return_val_if_fail (t != NULL, NULL); + + return gts_fifo_top (t->q); +} + +/** + * gts_graph_traverse_destroy: + * @t: a #GtsGraphTraverse. + * + * Frees all the memory allocated for @t. + */ +void gts_graph_traverse_destroy (GtsGraphTraverse * t) +{ + g_return_if_fail (t != NULL); + + gts_fifo_destroy (t->q); + g_free (t); +} + +static void edge_foreach_node (GtsGNode * n, gpointer * info) +{ + GtsFunc func = (GtsFunc) info[0]; + gpointer data = info[1]; + GHashTable * hash = info[2]; + GSList * i = GTS_SLIST_CONTAINER (n)->items; + + while (i) { + GtsGEdge * e = i->data; + if (!g_hash_table_lookup (hash, e)) { + (* func) (e, data); + g_hash_table_insert (hash, e, e); + } + i = i->next; + } +} + +/** + * gts_graph_foreach_edge: + * @g: a #GtsGraph. + * @func: a #GtsFunc. + * @data: user data to be passed to @func. + * + * Calls @func for each #GtsEdge of @g. + */ +void gts_graph_foreach_edge (GtsGraph * g, GtsFunc func, gpointer data) +{ + gpointer info[3]; + GHashTable * hash; + + g_return_if_fail (g != NULL); + g_return_if_fail (func != NULL); + + info[0] = func; + info[1] = data; + info[2] = hash = g_hash_table_new (NULL, NULL); + gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) edge_foreach_node, info); + g_hash_table_destroy (hash); +} + +/** + * gts_graph_weight: + * @g: a #GtsGraph. + * + * Returns: the weight of graph @g as defined by the weight() method + * of #GtsGraphClass. + */ +gfloat gts_graph_weight (GtsGraph * g) +{ + g_return_val_if_fail (g != NULL, 0.); + + if (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass)->weight) + return (* GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass)->weight) (g); + return (gfloat) gts_container_size (GTS_CONTAINER (g)); +} + +/** + * gts_graph_distance_sum: + * @g: a #GtsGraph. + * @center: a #GtsGNode of @g. + * + * Returns: the sum of the distances between all the other #GtsGNode + * of @g and @center. + */ +guint gts_graph_distance_sum (GtsGraph * g, GtsGNode * center) +{ + GtsGraphTraverse * t; + GtsGNode * n; + guint sum = 0; + + g_return_val_if_fail (g != NULL, 0); + g_return_val_if_fail (center != NULL, 0); + + t = gts_graph_traverse_new (g, center, GTS_BREADTH_FIRST, TRUE); + while ((n = gts_graph_traverse_next (t))) + sum += n->level - 1; + gts_graph_traverse_destroy (t); + + return sum; +} + +/** + * gts_graph_farthest: + * @g: a #GtsGraph. + * @gnodes: a list of #GtsGNode belonging to @g. + * + * Returns: the #GtsGNode belonging to @g and farthest from all the nodes in + * @gnodes (hmmm, definition of "farthest"?). + */ +GtsGNode * gts_graph_farthest (GtsGraph * g, GSList * gnodes) +{ + GtsGNode * farthest = NULL; + GSList * i; + gboolean reinit = TRUE, changed = TRUE; + guint level = 1; + + g_return_val_if_fail (g != NULL, NULL); + + /* initialize traversals */ + i = gnodes; + while (i) { + GTS_OBJECT (i->data)->reserved = + gts_graph_traverse_new (g, i->data, GTS_BREADTH_FIRST, reinit); + reinit = FALSE; + i = i->next; + } + + while (changed) { + changed = FALSE; + i = gnodes; + while (i) { + GtsGraphTraverse * t = GTS_OBJECT (i->data)->reserved; + GtsGNode * n; + while ((n = gts_graph_traverse_what_next (t)) && n->level == level) { + changed = TRUE; + farthest = n; + gts_graph_traverse_next (t); + } + i = i->next; + } + level++; + } + + /* destroy traversals */ + i = gnodes; + while (i) { + gts_graph_traverse_destroy (GTS_OBJECT (i->data)->reserved); + GTS_OBJECT (i->data)->reserved = NULL; + i = i->next; + } + return farthest; +} + +static void neighbor_count (GtsGNode * n, gpointer * data) +{ + guint * cuts = data[0]; + GtsGraph * g = data[1]; + + if (!gts_containee_is_contained (GTS_CONTAINEE (n), GTS_CONTAINER (g))) + (*cuts)++; +} + +static void count_edge_cuts (GtsGNode * n, gpointer * data) +{ + gts_gnode_foreach_neighbor (n, NULL, (GtsFunc) neighbor_count, data); +} + +/** + * gts_graph_edges_cut: + * @g: a #GtsGraph. + * + * Returns: the number of edges of @g connecting nodes belonging to @g + * to nodes not belonging to @g. + */ +guint gts_graph_edges_cut (GtsGraph * g) +{ + guint cuts = 0; + gpointer data[2]; + + g_return_val_if_fail (g != NULL, 0); + + data[0] = &cuts; + data[1] = g; + gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) count_edge_cuts, data); + + return cuts; +} + +static void sum_edge_cuts_weight (GtsGNode * n, gpointer * data) +{ + gfloat * weight = data[0]; + GtsGraph * g = data[1]; + GSList * i = GTS_SLIST_CONTAINER (n)->items; + + while (i) { + GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); + if (!gts_containee_is_contained (GTS_CONTAINEE (n1), GTS_CONTAINER (g))) + *weight += gts_gedge_weight (i->data); + i = i->next; + } +} + +/** + * gts_graph_edges_cut_weight: + * @g: a #GtsGraph. + * + * Returns: the sum of the weights of the edges of @g connecting nodes + * belonging to @g to nodes not belonging to @g. + */ +gfloat gts_graph_edges_cut_weight (GtsGraph * g) +{ + gfloat weight = 0.; + gpointer data[2]; + + g_return_val_if_fail (g != NULL, 0); + + data[0] = &weight; + data[1] = g; + gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) sum_edge_cuts_weight, + data); + + return weight; +} + +/** + * gts_graph_read_jostle: + * @g: a #GtsGraph. + * @fp: a #GtsFile. + * + * Adds to @g the nodes and edges defined in the file pointed to by + * @fp. This file must use the Jostle "graph" ASCII format. + * The nodes created are of type #GtsNGNode and their identities are the + * line number at which they appear in @fp. + * + * Returns: 0 if the lecture was successful, the line number at which + * an error occured otherwise (in which case the @error field of @fp + * is set). + */ +guint gts_graph_read_jostle (GtsGraph * g, GtsFile * fp) +{ + guint nn, ne, n; + GtsGNode ** nodes; + + g_return_val_if_fail (g != NULL, 1); + g_return_val_if_fail (fp != NULL, 1); + + if (fp->type != GTS_INT) { + gts_file_error (fp, "expecting an integer (number of nodes)"); + return fp->line; + } + nn = atoi (fp->token->str); + gts_file_next_token (fp); + + if (fp->type != GTS_INT) { + gts_file_error (fp, "expecting an integer (number of edges)"); + return fp->line; + } + ne = atoi (fp->token->str); + + gts_file_first_token_after (fp, '\n'); + nodes = g_malloc (sizeof (GtsGNode *)*(nn + 1)); + + n = 0; + while (n < nn && fp->type != GTS_ERROR) { + GtsNGNode * node = gts_ngnode_new (gts_ngnode_class (), fp->line); + + nodes[n++] = GTS_GNODE (node); + gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (node)); + do { + if (fp->type != GTS_INT) + gts_file_error (fp, "expecting an integer (node index)"); + else { + guint in = atoi (fp->token->str); + + if (in == 0 || in > nn) + gts_file_error (fp, "node index `%d' is out of range `[1,%d]'", + in, nn); + else if (in == n) + gts_file_error (fp, "node index `%d' references itself", in); + else if (in < n) { + gts_gedge_new (g->edge_class, GTS_GNODE (node), nodes[in - 1]); + ne--; + gts_file_next_token (fp); + } + } + } while (fp->type != GTS_ERROR && fp->type != '\n'); + } + g_free (nodes); + + if (fp->type != GTS_ERROR) { + if (n != nn) + gts_file_error (fp, "only `%d' nodes read out of `%d'", + n, nn); + else if (ne > 0) + gts_file_error (fp, "`%d' unallocated edges remaining", + ne); + } + + if (fp->type == GTS_ERROR) + return fp->line; + return 0; +} + +static void count_edges (GtsGEdge * e, guint * nedge) +{ + (*nedge)++; +} + +static void write_node (GtsObject * node, gpointer * data) +{ + FILE * fp = data[0]; + guint * nnode = data[1]; + + node->reserved = GUINT_TO_POINTER ((*nnode)++); + if (node->klass->write) + (* node->klass->write) (node, fp); + fputc ('\n', fp); +} + +static void write_edge (GtsGEdge * edge, FILE * fp) +{ + fprintf (fp, "%u %u", + GPOINTER_TO_UINT (GTS_OBJECT (edge->n1)->reserved), + GPOINTER_TO_UINT (GTS_OBJECT (edge->n2)->reserved)); + if (GTS_OBJECT (edge)->klass->write) + (* GTS_OBJECT (edge)->klass->write) (GTS_OBJECT (edge), fp); + fputc ('\n', fp); +} + +/** + * gts_graph_write: + * @g: a #GtsGraph. + * @fp: a file pointer. + * + * Writes in the file @fp an ASCII representation of @g. The file + * format is as follows. + * + * All the lines beginning with #GTS_COMMENTS are ignored. The first line + * contains two unsigned integers separated by spaces. The first + * integer is the number of nodes, nn, the second is the number of + * edges, ne. + * + * Follows nn lines containing node description. + * Follows ne lines containing the two indices (starting + * from one) of the nodes of each edge. + * + * The format described above is the least common denominator to all + * GTS files. Consistent with an object-oriented approach, the GTS + * file format is extensible. Each of the lines of the file can be + * extended with user-specific attributes accessible through the + * read() and write() virtual methods of each of the objects written + * (graph, nodes or edges). When read with different object classes, + * these extra attributes are just ignored. + */ +void gts_graph_write (GtsGraph * g, FILE * fp) +{ + guint nnode = 1, nedge = 0; + gpointer data[2]; + + g_return_if_fail (g != NULL); + g_return_if_fail (fp != NULL); + + gts_graph_foreach_edge (g, (GtsFunc) count_edges, &nedge); + fprintf (fp, "%u %u", gts_container_size (GTS_CONTAINER (g)), nedge); + if (GTS_OBJECT (g)->klass->write) + (* GTS_OBJECT (g)->klass->write) (GTS_OBJECT (g), fp); + fputc ('\n', fp); + data[0] = fp; + data[1] = &nnode; + gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) write_node, data); + gts_graph_foreach_edge (g, (GtsFunc) write_edge, fp); + gts_container_foreach (GTS_CONTAINER (g), + (GtsFunc) gts_object_reset_reserved, NULL); +} + +/** + * gts_graph_read: + * @fp: a #GtsFile. + * + * Reads a graph from a file. + * + * Returns: the new #GtsGraph or %NULL if an error occured (in which + * case the @error field of @fp is set). + */ +GtsGraph * gts_graph_read (GtsFile * fp) +{ + GtsGraph * g; + GtsGNode ** nodes; + guint nn, ne, n; + + g_return_val_if_fail (fp != NULL, NULL); + + if (fp->type != GTS_INT) { + gts_file_error (fp, "expecting an integer (number of nodes)"); + return NULL; + } + nn = atoi (fp->token->str); + gts_file_next_token (fp); + + if (fp->type != GTS_INT) { + gts_file_error (fp, "expecting an integer (number of edges)"); + return NULL; + } + ne = atoi (fp->token->str); + + gts_file_next_token (fp); + if (fp->type != '\n') { + GtsObjectClass * klass; + + gts_graph_class (); + gts_gnode_class (); + gts_gedge_class (); + + if (fp->type != GTS_STRING) { + gts_file_error (fp, "expecting a string (GtsGraphClass)"); + return NULL; + } + klass = gts_object_class_from_name (fp->token->str); + if (klass == NULL) { + gts_file_error (fp, "unknown class `%s'", fp->token->str); + return NULL; + } + if (!gts_object_class_is_from_class (klass, gts_graph_class ())) { + gts_file_error (fp, "class `%s' is not a GtsGraphClass", fp->token->str); + return NULL; + } + g = GTS_GRAPH (gts_object_new (klass)); + g->graph_class = GTS_GRAPH_CLASS (klass); + gts_file_next_token (fp); + (* klass->read) ((GtsObject **) &g, fp); + if (fp->type == GTS_ERROR) { + gts_object_destroy (GTS_OBJECT (g)); + return NULL; + } + } + else + g = GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (gts_graph_class ()))); + gts_file_first_token_after (fp, '\n'); + if (nn <= 0) + return g; + + nodes = g_malloc ((nn + 1)*sizeof (GtsGNode *)); + + n = 0; + while (n < nn && fp->type != GTS_ERROR) { + GtsObject * new_node = + gts_object_new (GTS_OBJECT_CLASS (g->node_class)); + + gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (new_node)); + if (GTS_OBJECT_CLASS (g->node_class)->read) + (*GTS_OBJECT_CLASS (g->node_class)->read) (&new_node, fp); + gts_file_first_token_after (fp, '\n'); + nodes[n++] = GTS_GNODE (new_node); + } + if (fp->type == GTS_ERROR) + nn = n; + + n = 0; + while (n < ne && fp->type != GTS_ERROR) { + guint n1, n2; + + if (fp->type != GTS_INT) + gts_file_error (fp, "expecting an integer (first node index)"); + else { + n1 = atoi (fp->token->str); + if (n1 == 0 || n1 > nn) + gts_file_error (fp, "node index `%d' is out of range `[1,%d]'", + n1, nn); + else { + gts_file_next_token (fp); + if (fp->type != GTS_INT) + gts_file_error (fp, "expecting an integer (second node index)"); + else { + n2 = atoi (fp->token->str); + if (n2 == 0 || n2 > nn) + gts_file_error (fp, "node index `%d' is out of range `[1,%d]'", + n2, nn); + else { + GtsGEdge * new_edge = + gts_gedge_new (g->edge_class, nodes[n1 - 1], nodes [n2 - 1]); + + gts_file_next_token (fp); + if (fp->type != '\n') + if (GTS_OBJECT_CLASS (g->edge_class)->read) + (*GTS_OBJECT_CLASS (g->edge_class)->read) + ((GtsObject **) &new_edge, fp); + gts_file_first_token_after (fp, '\n'); + n++; + } + } + } + } + } + + if (fp->type == GTS_ERROR) { + gts_allow_floating_gnodes = TRUE; + while (nn) + gts_object_destroy (GTS_OBJECT (nodes[nn-- - 1])); + gts_allow_floating_gnodes = FALSE; + } + g_free (nodes); + + if (fp->type == GTS_ERROR) { + gts_object_destroy (GTS_OBJECT (g)); + return NULL; + } + return g; +} + +static void write_dot_node (GtsGNode * node, gpointer * data) +{ + FILE * fp = data[0]; + guint * nnode = data[1]; + + fprintf (fp, " n%u", *nnode); + if (GTS_GNODE_CLASS (GTS_OBJECT (node)->klass)->write) { + fputs (" [", fp); + (* GTS_GNODE_CLASS (GTS_OBJECT (node)->klass)->write) (node, fp); + fputc (']', fp); + } + fputs (";\n", fp); + GTS_OBJECT (node)->reserved = GUINT_TO_POINTER ((*nnode)++); +} + +static void write_dot_edge (GtsGEdge * edge, FILE * fp) +{ + fprintf (fp, " n%u -> n%u", + GPOINTER_TO_UINT (GTS_OBJECT (edge->n1)->reserved), + GPOINTER_TO_UINT (GTS_OBJECT (edge->n2)->reserved)); + if (GTS_GEDGE_CLASS (GTS_OBJECT (edge)->klass)->write) { + fputs (" [", fp); + (* GTS_GEDGE_CLASS (GTS_OBJECT (edge)->klass)->write) (edge, fp); + fputc (']', fp); + } + fputs (";\n", fp); +} + +/** + * gts_graph_write_dot: + * @g: a #GtsGraph. + * @fp: a file pointer. + * + * Writes in the file @fp an ASCII representation of @g in the dot format of + * AT&T Bell Labs. + */ +void gts_graph_write_dot (GtsGraph * g, FILE * fp) +{ + guint nnode = 1; + gpointer data[2]; + + g_return_if_fail (g != NULL); + g_return_if_fail (fp != NULL); + + fprintf (fp, "digraph \"%p\" {\n", g); + data[0] = fp; + data[1] = &nnode; + gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) write_dot_node, data); + gts_graph_foreach_edge (g, (GtsFunc) write_dot_edge, fp); + fputs ("}\n", fp); + + gts_container_foreach (GTS_CONTAINER (g), + (GtsFunc) gts_object_reset_reserved, NULL); +} + +/* GtsWGraph */ + +static gfloat wgraph_weight (GtsGraph * g) +{ + return GTS_WGRAPH (g)->weight; +} + +static void wgraph_add (GtsContainer * g, GtsContainee * n) +{ + GtsWGraph * wg = GTS_WGRAPH (g); + gfloat w = gts_gnode_weight (GTS_GNODE (n)); + + wg->weight += w; + + (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_wgraph_class ())->parent_class)->add) (g, n); +} + +static void wgraph_remove (GtsContainer * g, GtsContainee * n) +{ + GTS_WGRAPH (g)->weight -= gts_gnode_weight (GTS_GNODE (n)); + + (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_wgraph_class ())->parent_class)->remove) (g, n); +} + +static void wgraph_class_init (GtsWGraphClass * klass) +{ + GTS_GRAPH_CLASS (klass)->weight = wgraph_weight; + + GTS_CONTAINER_CLASS (klass)->add = wgraph_add; + GTS_CONTAINER_CLASS (klass)->remove = wgraph_remove; +} + +static void wgraph_init (GtsWGraph * g) +{ + g->weight = 0.; +} + +/** + * gts_wgraph_class: + * + * Returns: the #GtsWGraphClass. + */ +GtsWGraphClass * gts_wgraph_class (void) +{ + static GtsWGraphClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo wgraph_info = { + "GtsWGraph", + sizeof (GtsWGraph), + sizeof (GtsWGraphClass), + (GtsObjectClassInitFunc) wgraph_class_init, + (GtsObjectInitFunc) wgraph_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_graph_class ()), + &wgraph_info); + } + + return klass; +} + +static void weight_max (GtsGNode * n, gfloat * wmax) +{ + gfloat w = gts_gnode_weight (n); + + if (w > *wmax) + *wmax = w; +} + +/** + * gts_wgraph_weight_max: + * @wg: a #GtsWGraph. + * + * Returns: the maximum weight of any vertices belonging to @g. + */ +gfloat gts_wgraph_weight_max (GtsWGraph * wg) +{ + gfloat wmax = - G_MAXFLOAT; + + g_return_val_if_fail (wg != NULL, 0.); + + gts_container_foreach (GTS_CONTAINER (wg), (GtsFunc) weight_max, &wmax); + + return wmax; +} + +/* Surface graph */ + +static void create_node (GtsFace * f, GtsGraph * graph) +{ + GtsFNode * fn = gts_fnode_new (gts_fnode_class (), f); + + gts_container_add (GTS_CONTAINER (graph), GTS_CONTAINEE (fn)); + GTS_OBJECT (f)->reserved = fn; +} + +static void create_edge (GtsEdge * e, GtsSurface * s) +{ + GSList * i = e->triangles; + + while (i) { + GtsFace * f = i->data; + if (GTS_IS_FACE (f) && gts_face_has_parent_surface (f, s)) { + GSList * j = i->next; + while (j) { + GtsFace * f1 = j->data; + if (GTS_IS_FACE (f1) && gts_face_has_parent_surface (f1, s)) + gts_pgedge_new (gts_pgedge_class (), + GTS_OBJECT (f)->reserved, + GTS_OBJECT (f1)->reserved, + e); + j = j->next; + } + } + i = i->next; + } +} + +/** + * gts_surface_graph_new: + * @klass: a #GtsGraphClass. + * @s: a #GtsSurface. + * + * Returns: a new #GtsGraph representing the connectivity of the faces + * of @s. This graph uses #GtsFGNode as nodes which allows to store + * the dependencies between nodes and faces of @s. + */ +GtsGraph * gts_surface_graph_new (GtsGraphClass * klass, + GtsSurface * s) +{ + GtsGraph * graph; + + g_return_val_if_fail (klass != NULL, NULL); + g_return_val_if_fail (s != NULL, NULL); + + graph = GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (klass))); + gts_surface_foreach_face (s, (GtsFunc) create_node, graph); + gts_surface_foreach_edge (s, (GtsFunc) create_edge, s); + gts_surface_foreach_face (s, (GtsFunc) gts_object_reset_reserved, NULL); + + return graph; +} + +static void create_segment_edge (GtsSegment * s, GtsGraph * graph) +{ + GtsGNode * n1 = GTS_OBJECT (s->v1)->reserved, * n2; + + if (n1 == NULL) { + n1 = GTS_GNODE (gts_pnode_new (gts_pnode_class (), s->v1)); + gts_container_add (GTS_CONTAINER (graph), GTS_CONTAINEE (n1)); + GTS_OBJECT (s->v1)->reserved = n1; + } + + n2 = GTS_OBJECT (s->v2)->reserved; + if (n2 == NULL) { + n2 = GTS_GNODE (gts_pnode_new (gts_pnode_class (), s->v2)); + gts_container_add (GTS_CONTAINER (graph), GTS_CONTAINEE (n2)); + GTS_OBJECT (s->v2)->reserved = n2; + } + + gts_pgedge_new (gts_pgedge_class (), n1, n2, s); +} + +static void reset_reserved (GtsSegment * s) +{ + GTS_OBJECT (s->v1)->reserved = GTS_OBJECT (s->v2)->reserved = NULL; +} + +/** + * gts_segments_graph_new: + * @klass: a #GtsGraphClass. + * @segments: a list of #GtsSegment. + * + * Returns: a new #GtsGraph representing the connectivity of the segments + * in @segments. + */ +GtsGraph * gts_segments_graph_new (GtsGraphClass * klass, + GSList * segments) +{ + GtsGraph * graph; + + g_return_val_if_fail (klass != NULL, NULL); + + graph = GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (klass))); + g_slist_foreach (segments, (GFunc) create_segment_edge, graph); + g_slist_foreach (segments, (GFunc) reset_reserved, NULL); + + return graph; +} + +static void add_to_surface (GtsGNode * n, GtsSurface * s) +{ + if (GTS_IS_FNODE (n)) + gts_surface_add_face (s, GTS_FNODE (n)->f); +} + +/** + * gts_surface_graph_surface: + * @surface_graph: a #GtsGraph using #GtsFGNode as nodes. + * @s: a #GtsSurface. + * + * Returns: a new #GtsSurface using the same classes as @s and + * composed of the faces defined by @surface_graph. + */ +GtsSurface * gts_surface_graph_surface (GtsGraph * surface_graph, + GtsSurface * s) +{ + GtsSurface * s1; + + g_return_val_if_fail (surface_graph != NULL, NULL); + g_return_val_if_fail (s != NULL, NULL); + + s1 = gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass), + s->face_class, + s->edge_class, + s->vertex_class); + gts_container_foreach (GTS_CONTAINER (surface_graph), + (GtsFunc) add_to_surface, s1); + return s1; +} + Index: work/obsolete/toporouter/src_3rd/gts/gts-private.h =================================================================== --- work/obsolete/toporouter/src_3rd/gts/gts-private.h (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/gts-private.h (revision 6803) @@ -0,0 +1,37 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GTS_PRIVATE_H__ +#define __GTS_PRIVATE_H__ + +/* Debugging flags */ + +/* #define DEBUG_FUNCTIONS */ + +#ifdef DEBUG_FUNCTIONS +/* #define DEBUG_LEAKS */ +#define DEBUG_IDENTITY +guint id (gpointer p); +void id_insert (gpointer p); +void id_remove (gpointer p); +void gts_write_triangle (GtsTriangle * t, GtsPoint * o, FILE * fptr); +void gts_write_segment (GtsSegment * s, GtsPoint * o, FILE * fptr); +#endif /* DEBUG_FUNCTIONS */ + +#endif /* __GTS_PRIVATE_H__ */ Index: work/obsolete/toporouter/src_3rd/gts/gts.h =================================================================== --- work/obsolete/toporouter/src_3rd/gts/gts.h (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/gts.h (revision 6803) @@ -0,0 +1,2577 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GTS_H__ +#define __GTS_H__ + +#include +#include + +#define GTS_MAJOR_VERSION 0 +#define GTS_MINOR_VERSION 7 +#define GTS_MICRO_VERSION 6 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Added based on glib.h by M J Loehr 01/01/01 */ +/* GTS version. + * we prefix variable declarations so they can + * properly get exported in windows dlls. + */ +#ifdef NATIVE_WIN32 +# ifdef GTS_COMPILATION +# define GTS_C_VAR __declspec(dllexport) +# else /* not GTS_COMPILATION */ +# define GTS_C_VAR extern __declspec(dllimport) +# endif /* not GTS_COMPILATION */ +#else /* not NATIVE_WIN32 */ +# define GTS_C_VAR extern +#endif /* not NATIVE_WIN32 */ + +GTS_C_VAR const guint gts_major_version; +GTS_C_VAR const guint gts_minor_version; +GTS_C_VAR const guint gts_micro_version; +GTS_C_VAR const guint gts_interface_age; +GTS_C_VAR const guint gts_binary_age; + +#define GTS_CHECK_VERSION(major,minor,micro) \ + (gts_major_version > (major) || \ + (gts_major_version == (major) && gts_minor_version > (minor)) || \ + (gts_major_version == (major) && gts_minor_version == (minor) && \ + gts_micro_version >= (micro))) + +#define GTS_COMMENTS "#!" +#define GTS_MAINTAINER "popinet@users.sourceforge.net" + + + + +void gts_predicates_init(); + + +/* Class declarations for base types */ + +typedef struct _GtsObjectClassInfo GtsObjectClassInfo; +typedef struct _GtsObject GtsObject; +typedef struct _GtsObjectClass GtsObjectClass; +typedef struct _GtsPoint GtsPoint; +typedef struct _GtsPointClass GtsPointClass; +typedef struct _GtsVertex GtsVertex; +typedef struct _GtsVertexClass GtsVertexClass; +typedef struct _GtsSegment GtsSegment; +typedef struct _GtsSegmentClass GtsSegmentClass; +typedef struct _GtsEdge GtsEdge; +typedef struct _GtsEdgeClass GtsEdgeClass; +typedef struct _GtsTriangle GtsTriangle; +typedef struct _GtsTriangleClass GtsTriangleClass; +typedef struct _GtsFace GtsFace; +typedef struct _GtsFaceClass GtsFaceClass; +typedef struct _GtsBBox GtsBBox; +typedef struct _GtsBBoxClass GtsBBoxClass; +typedef struct _GtsSurface GtsSurface; +typedef struct _GtsSurfaceClass GtsSurfaceClass; + +typedef void (*GtsObjectClassInitFunc) (GtsObjectClass * objclass); +typedef void (*GtsObjectInitFunc) (GtsObject * obj); +typedef void (*GtsArgSetFunc) (GtsObject * obj); +typedef void (*GtsArgGetFunc) (GtsObject * obj); + +typedef gdouble GtsVector[3]; +typedef gdouble GtsVector4[4]; +typedef GtsVector4 GtsMatrix; +/** + * GtsKeyFunc: + * @item: A pointer to an item to be stored in the heap. + * @data: User data passed to gts_eheap_new(). + * + * Returns: the value of the key for the given item. + */ +typedef gdouble (*GtsKeyFunc) (gpointer item, + gpointer data); +typedef enum +{ + GTS_OUT = -1, + GTS_ON = 0, + GTS_IN = 1 +} GtsIntersect; + +typedef struct _GtsColor GtsColor; + +struct _GtsColor { + gfloat r, g, b; +}; + +typedef gint (*GtsFunc) (gpointer item, + gpointer data); + +/* misc.c */ + +typedef struct _GtsFile GtsFile; + +typedef enum { + GTS_NONE = 1 << 8, + GTS_INT = 1 << 9, + GTS_UINT = 1 << 10, + GTS_FLOAT = 1 << 11, + GTS_DOUBLE = 1 << 12, + GTS_STRING = 1 << 13, + GTS_FILE = 1 << 14, + GTS_ERROR = 1 << 15 +} GtsTokenType; + +struct _GtsFile { + FILE * fp; + gchar * s, * s1; + guint line, pos; + GString * token; + GtsTokenType type; + gchar * error; + + guint curline, curpos; + guint scope, scope_max; + gint next_token; + gchar * delimiters; + gchar * comments; + gchar * tokens; +}; + +typedef struct _GtsFileVariable GtsFileVariable; + +struct _GtsFileVariable { + GtsTokenType type; + gchar name[30]; + gboolean unique; + gpointer data; + gboolean set; + guint line, pos; +}; + + +GtsFile * gts_file_new (FILE * fp); +GtsFile * gts_file_new_from_string (const gchar * s); +void gts_file_verror (GtsFile * f, + const gchar * format, + va_list args); +void gts_file_error (GtsFile * f, + const gchar * format, + ...); +gint gts_file_getc (GtsFile * f); +guint gts_file_read (GtsFile * f, + gpointer ptr, + guint size, + guint nmemb); +gint gts_file_getc_scope (GtsFile * f); +void gts_file_next_token (GtsFile * f); +void gts_file_first_token_after (GtsFile * f, + GtsTokenType type); +void gts_file_assign_start (GtsFile * f, + GtsFileVariable * vars); +GtsFileVariable * gts_file_assign_next (GtsFile * f, + GtsFileVariable * vars); +void gts_file_assign_variables (GtsFile * f, + GtsFileVariable * vars); +void gts_file_variable_error (GtsFile * f, + GtsFileVariable * vars, + const gchar * name, + const gchar * format, + ...); +void gts_file_destroy (GtsFile * f); + +/* Objects: object.c */ + +#ifdef GTS_CHECK_CASTS +# define GTS_OBJECT_CAST(obj, type, klass) ((type *) gts_object_check_cast (obj, klass)) +# define GTS_OBJECT_CLASS_CAST(objklass, type, klass) ((type *) gts_object_class_check_cast (objklass, klass)) +#else /* not GTS_CHECK_CASTS */ +# define GTS_OBJECT_CAST(obj, type, klass) ((type *) (obj)) +# define GTS_OBJECT_CLASS_CAST(objklass, type, klass) ((type *) (objklass)) +#endif /* not GTS_CHECK_CASTS */ + +#define GTS_CLASS_NAME_LENGTH 40 +#define GTS_OBJECT(obj) GTS_OBJECT_CAST (obj,\ + GtsObject,\ + gts_object_class ()) +#define GTS_OBJECT_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsObjectClass,\ + gts_object_class()) +#define GTS_IS_OBJECT(obj) (gts_object_is_from_class (obj,\ + gts_object_class ())) + +typedef enum +{ + GTS_DESTROYED = 1 << 0, + GTS_USER_FLAG = 1 /* user flags start from here */ +} GtsObjectFlags; + +#define GTS_OBJECT_FLAGS(obj) (GTS_OBJECT (obj)->flags) +#define GTS_OBJECT_DESTROYED(obj) ((GTS_OBJECT_FLAGS (obj) & GTS_DESTROYED) != 0) +#define GTS_OBJECT_SET_FLAGS(obj,flag) G_STMT_START{ (GTS_OBJECT_FLAGS (obj) |= (flag)); }G_STMT_END +#define GTS_OBJECT_UNSET_FLAGS(obj,flag) G_STMT_START{ (GTS_OBJECT_FLAGS (obj) &= ~(flag)); }G_STMT_END + +struct _GtsObjectClassInfo { + gchar name[GTS_CLASS_NAME_LENGTH]; + guint object_size; + guint class_size; + GtsObjectClassInitFunc class_init_func; + GtsObjectInitFunc object_init_func; + GtsArgSetFunc arg_set_func; + GtsArgGetFunc arg_get_func; +}; + +struct _GtsObject { + GtsObjectClass * klass; + + gpointer reserved; + guint32 flags; +}; + +struct _GtsObjectClass { + GtsObjectClassInfo info; + GtsObjectClass * parent_class; + + void (* clone) (GtsObject *, GtsObject *); + void (* destroy) (GtsObject *); + void (* read) (GtsObject **, GtsFile *); + void (* write) (GtsObject *, FILE *); + GtsColor (* color) (GtsObject *); + void (* attributes) (GtsObject *, GtsObject *); +}; + +gpointer gts_object_class_new (GtsObjectClass * parent_class, + GtsObjectClassInfo * info); +GtsObjectClass * gts_object_class (void); +gpointer gts_object_check_cast (gpointer object, + gpointer klass); +gpointer gts_object_class_check_cast (gpointer klass, + gpointer from); + +static inline +gpointer gts_object_is_from_class (gpointer object, + gpointer klass) +{ + GtsObjectClass * c; + + g_return_val_if_fail (klass != NULL, NULL); + + if (object == NULL) + return NULL; + + c = ((GtsObject *) object)->klass; + + g_return_val_if_fail (c != NULL, NULL); + + while (c) { + if (c == klass) + return object; + c = c->parent_class; + } + + return NULL; +} + +static inline +gpointer gts_object_class_is_from_class (gpointer klass, + gpointer from) +{ + GtsObjectClass * c; + + g_return_val_if_fail (klass != NULL, NULL); + g_return_val_if_fail (from != NULL, NULL); + + c = (GtsObjectClass *) klass; + while (c) { + if (c == from) + return klass; + c = c->parent_class; + } + + return NULL; +} + +GtsObjectClass * gts_object_class_from_name (const gchar * name); + +GtsObject * gts_object_new (GtsObjectClass * klass); +GtsObject * gts_object_clone (GtsObject * object); +void gts_object_attributes (GtsObject * object, + GtsObject * from); +void gts_object_init (GtsObject * object, + GtsObjectClass * klass); +void gts_object_reset_reserved (GtsObject * object); +void gts_object_destroy (GtsObject * object); +void gts_finalize (void); + +/* Ranges: surface.c */ +typedef struct _GtsRange GtsRange; + +struct _GtsRange { + gdouble min, max, sum, sum2, mean, stddev; + guint n; +}; + +void gts_range_init (GtsRange * r); +void gts_range_reset (GtsRange * r); +void gts_range_add_value (GtsRange * r, + gdouble val); +void gts_range_update (GtsRange * r); +void gts_range_print (GtsRange * r, + FILE * fptr); + +/* Points: point.c */ + +#define GTS_IS_POINT(obj) (gts_object_is_from_class (obj,\ + gts_point_class ())) +#define GTS_POINT(obj) GTS_OBJECT_CAST (obj,\ + GtsPoint,\ + gts_point_class ()) +#define GTS_POINT_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsPointClass,\ + gts_point_class ()) + +struct _GtsPoint { + GtsObject object; + + gdouble x, y, z; /* must be contiguous (cast to robust functions) */ +}; + +struct _GtsPointClass { + GtsObjectClass parent_class; + gboolean binary; +}; + +GtsPointClass * gts_point_class (void); +GtsPoint * gts_point_new (GtsPointClass * klass, + gdouble x, + gdouble y, + gdouble z); +void gts_point_set (GtsPoint * p, + gdouble x, + gdouble y, + gdouble z); +#define gts_point_is_in_rectangle(p, p1, p2) ((p)->x >= (p1)->x &&\ + (p)->x <= (p2)->x &&\ + (p)->y >= (p1)->y &&\ + (p)->y <= (p2)->y &&\ + (p)->z >= (p1)->z &&\ + (p)->z <= (p2)->z) +GtsPoint * gts_segment_triangle_intersection (GtsSegment * s, + GtsTriangle * t, + gboolean boundary, + GtsPointClass * klass); +void gts_point_transform (GtsPoint * p, + GtsMatrix * m); +gdouble gts_point_distance (GtsPoint * p1, + GtsPoint * p2); +gdouble gts_point_distance2 (GtsPoint * p1, + GtsPoint * p2); +gdouble gts_point_orientation_3d (GtsPoint * p1, + GtsPoint * p2, + GtsPoint * p3, + GtsPoint * p4); +gint gts_point_orientation_3d_sos (GtsPoint * p1, + GtsPoint * p2, + GtsPoint * p3, + GtsPoint * p4); +GtsIntersect gts_point_is_in_triangle (GtsPoint * p, + GtsTriangle * t); +gdouble gts_point_in_circle (GtsPoint * p, + GtsPoint * p1, + GtsPoint * p2, + GtsPoint * p3); +gdouble gts_point_in_sphere (GtsPoint * p, + GtsPoint * p1, + GtsPoint * p2, + GtsPoint * p3, + GtsPoint * p4); +gdouble gts_point_in_triangle_circle (GtsPoint * p, + GtsTriangle * t); +gdouble gts_point_orientation (GtsPoint * p1, + GtsPoint * p2, + GtsPoint * p3); +gint gts_point_orientation_sos (GtsPoint * p1, + GtsPoint * p2, + GtsPoint * p3); +gdouble gts_point_segment_distance2 (GtsPoint * p, + GtsSegment * s); +gdouble gts_point_segment_distance (GtsPoint * p, + GtsSegment * s); +void gts_point_segment_closest (GtsPoint * p, + GtsSegment * s, + GtsPoint * closest); +gdouble gts_point_triangle_distance2 (GtsPoint * p, + GtsTriangle * t); +gdouble gts_point_triangle_distance (GtsPoint * p, + GtsTriangle * t); +void gts_point_triangle_closest (GtsPoint * p, + GtsTriangle * t, + GtsPoint * closest); +gboolean gts_point_is_inside_surface (GtsPoint * p, + GNode * tree, + gboolean is_open); + +/* Vertices: vertex.c */ + +#define GTS_IS_VERTEX(obj) (gts_object_is_from_class (obj,\ + gts_vertex_class ())) +#define GTS_VERTEX(obj) GTS_OBJECT_CAST (obj,\ + GtsVertex,\ + gts_vertex_class ()) +#define GTS_VERTEX_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsVertexClass,\ + gts_vertex_class ()) +struct _GtsVertex { + GtsPoint p; + + GSList * segments; +}; + +struct _GtsVertexClass { + GtsPointClass parent_class; + + void (* intersection_attributes) (GtsVertex *, + GtsObject *, + GtsObject *); +}; + +GTS_C_VAR +gboolean gts_allow_floating_vertices; + +GtsVertexClass * gts_vertex_class (void); +GtsVertex * gts_vertex_new (GtsVertexClass * klass, + gdouble x, + gdouble y, + gdouble z); +void gts_vertex_replace (GtsVertex * v, + GtsVertex * with); +gboolean gts_vertex_is_unattached (GtsVertex * v); +GtsSegment * gts_vertices_are_connected (GtsVertex * v1, + GtsVertex * v2); +GSList * gts_vertex_triangles (GtsVertex * v, + GSList * list); +GSList * gts_vertex_faces (GtsVertex * v, + GtsSurface * surface, + GSList * list); +GSList * gts_vertex_neighbors (GtsVertex * v, + GSList * list, + GtsSurface * surface); +GSList * gts_vertices_from_segments (GSList * segments); +gboolean gts_vertex_is_boundary (GtsVertex * v, + GtsSurface * surface); +GList * gts_vertices_merge (GList * vertices, + gdouble epsilon, + gboolean (* check) (GtsVertex *, GtsVertex *)); +GSList * gts_vertex_fan_oriented (GtsVertex * v, + GtsSurface * surface); +guint gts_vertex_is_contact (GtsVertex * v, gboolean sever); + +/* GtsVertexNormal: Header */ + +typedef struct _GtsVertexNormal GtsVertexNormal; + +struct _GtsVertexNormal { + /*< private >*/ + GtsVertex parent; + + /*< public >*/ + GtsVector n; +}; + +#define GTS_VERTEX_NORMAL(obj) GTS_OBJECT_CAST (obj,\ + GtsVertexNormal,\ + gts_vertex_normal_class ()) +#define GTS_IS_VERTEX_NORMAL(obj) (gts_object_is_from_class (obj,\ + gts_vertex_normal_class ())) + +GtsVertexClass * gts_vertex_normal_class (void); + +/* GtsColorVertex: Header */ + +typedef struct _GtsColorVertex GtsColorVertex; + +struct _GtsColorVertex { + /*< private >*/ + GtsVertex parent; + + /*< public >*/ + GtsColor c; +}; + +#define GTS_COLOR_VERTEX(obj) GTS_OBJECT_CAST (obj,\ + GtsColorVertex,\ + gts_color_vertex_class ()) +#define GTS_IS_COLOR_VERTEX(obj) (gts_object_is_from_class (obj,\ + gts_color_vertex_class ())) + +GtsVertexClass * gts_color_vertex_class (void); + +/* Segments: segment.c */ + +#define GTS_IS_SEGMENT(obj) (gts_object_is_from_class (obj,\ + gts_segment_class ())) +#define GTS_SEGMENT(obj) GTS_OBJECT_CAST (obj,\ + GtsSegment,\ + gts_segment_class ()) +#define GTS_SEGMENT_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsSegmentClass,\ + gts_segment_class ()) + +struct _GtsSegment { + GtsObject object; + + GtsVertex * v1; + GtsVertex * v2; +}; + +struct _GtsSegmentClass { + GtsObjectClass parent_class; +}; + +GtsSegmentClass * gts_segment_class (void); +GtsSegment * gts_segment_new (GtsSegmentClass * klass, + GtsVertex * v1, + GtsVertex * v2); +#define gts_segment_connect(s, e1, e2) (((s)->v1 == e1 &&\ + (s)->v2 == e2) || \ + ((s)->v1 == e2 &&\ + (s)->v2 == e1)) +#define gts_segments_are_identical(s1, s2) (((s1)->v1 == (s2)->v1 &&\ + (s1)->v2 == (s2)->v2)\ + ||\ + ((s1)->v1 == (s2)->v2 &&\ + (s1)->v2 == (s2)->v1)) +#define gts_segments_touch(s1, s2) ((s1)->v1 == (s2)->v1 ||\ + (s1)->v1 == (s2)->v2 ||\ + (s1)->v2 == (s2)->v1 ||\ + (s1)->v2 == (s2)->v2) +GtsIntersect gts_segments_are_intersecting (GtsSegment * s1, + GtsSegment * s2); +GtsSegment * gts_segment_is_duplicate (GtsSegment * s); +GtsVertex * gts_segment_midvertex (GtsSegment * s, + GtsVertexClass * klass); +GSList * gts_segments_from_vertices (GSList * vertices); +gboolean gts_segment_is_ok (GtsSegment * s); + +/* Edges: edge.c */ + +#define GTS_IS_EDGE(obj) (gts_object_is_from_class (obj,\ + gts_edge_class ())) +#define GTS_EDGE(obj) GTS_OBJECT_CAST (obj,\ + GtsEdge,\ + gts_edge_class ()) +#define GTS_EDGE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsEdgeClass,\ + gts_edge_class ()) + +struct _GtsEdge { + GtsSegment segment; + + GSList * triangles; +}; + +struct _GtsEdgeClass { + GtsSegmentClass parent_class; +}; + +GTS_C_VAR +gboolean gts_allow_floating_edges; + +GtsEdgeClass * gts_edge_class (void); +GtsEdge * gts_edge_new (GtsEdgeClass * klass, + GtsVertex * v1, + GtsVertex * v2); +/** + * gts_edge_is_unattached: + * @s: a #GtsEdge. + * + * Evaluates to %TRUE if no triangles uses @s as an edge, %FALSE otherwise. + */ +#define gts_edge_is_unattached(s) ((s)->triangles == NULL ? TRUE : FALSE) +GtsFace * gts_edge_has_parent_surface (GtsEdge * e, + GtsSurface * surface); +GtsFace * gts_edge_has_any_parent_surface (GtsEdge * e); +GtsFace * gts_edge_is_boundary (GtsEdge * e, + GtsSurface * surface); +void gts_edge_replace (GtsEdge * e, + GtsEdge * with); +GSList * gts_edges_from_vertices (GSList * vertices, + GtsSurface * parent); +guint gts_edge_face_number (GtsEdge * e, + GtsSurface * s); +gboolean gts_edge_collapse_is_valid (GtsEdge * e); +gboolean gts_edge_collapse_creates_fold (GtsEdge * e, + GtsVertex * v, + gdouble max); +GtsEdge * gts_edge_is_duplicate (GtsEdge * e); +GList * gts_edges_merge (GList * edges); +gboolean gts_edge_belongs_to_tetrahedron (GtsEdge * e); +guint gts_edge_is_contact (GtsEdge * e); +void gts_edge_swap (GtsEdge * e, + GtsSurface * s); +gboolean gts_edge_manifold_faces (GtsEdge * e, + GtsSurface * s, + GtsFace ** f1, + GtsFace ** f2); + +/* Triangles: triangle.c */ + +#define GTS_IS_TRIANGLE(obj) (gts_object_is_from_class (obj,\ + gts_triangle_class ())) +#define GTS_TRIANGLE(obj) GTS_OBJECT_CAST (obj,\ + GtsTriangle,\ + gts_triangle_class ()) +#define GTS_TRIANGLE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsTriangleClass,\ + gts_triangle_class ()) + +struct _GtsTriangle { + GtsObject object; + + GtsEdge * e1; + GtsEdge * e2; + GtsEdge * e3; +}; + +struct _GtsTriangleClass { + GtsObjectClass parent_class; +}; + +GtsTriangleClass * gts_triangle_class (void); +void gts_triangle_set (GtsTriangle * triangle, + GtsEdge * e1, + GtsEdge * e2, + GtsEdge * e3); +GtsTriangle * gts_triangle_new (GtsTriangleClass * klass, + GtsEdge * e1, + GtsEdge * e2, + GtsEdge * e3); +#define gts_triangle_vertex(t) (GTS_SEGMENT (GTS_TRIANGLE (t)->e1)->v1 ==\ + GTS_SEGMENT (GTS_TRIANGLE (t)->e2)->v1 || \ + GTS_SEGMENT (GTS_TRIANGLE (t)->e1)->v2 ==\ + GTS_SEGMENT (GTS_TRIANGLE (t)->e2)->v1 ? \ + GTS_SEGMENT (GTS_TRIANGLE (t)->e2)->v2 :\ + GTS_SEGMENT (GTS_TRIANGLE (t)->e2)->v1) +GtsVertex * gts_triangle_vertex_opposite (GtsTriangle * t, + GtsEdge * e); +GtsEdge * gts_triangle_edge_opposite (GtsTriangle * t, + GtsVertex * v); +gdouble gts_triangles_angle (GtsTriangle * t1, + GtsTriangle * t2); +gboolean gts_triangles_are_compatible (GtsTriangle * t1, + GtsTriangle * t2, + GtsEdge * e); +gdouble gts_triangle_area (GtsTriangle * t); +gdouble gts_triangle_perimeter (GtsTriangle * t); +gdouble gts_triangle_quality (GtsTriangle * t); +void gts_triangle_normal (GtsTriangle * t, + gdouble * x, + gdouble * y, + gdouble * z); +gdouble gts_triangle_orientation (GtsTriangle * t); +void gts_triangle_revert (GtsTriangle * t); +GSList * gts_triangles_from_edges (GSList * edges); +void gts_triangle_vertices_edges (GtsTriangle * t, + GtsEdge * e, + GtsVertex ** v1, + GtsVertex ** v2, + GtsVertex ** v3, + GtsEdge ** e1, + GtsEdge ** e2, + GtsEdge ** e3); +GtsTriangle * gts_triangle_enclosing (GtsTriangleClass * klass, + GSList * points, + gdouble scale); +guint gts_triangle_neighbor_number (GtsTriangle * t); +GSList * gts_triangle_neighbors (GtsTriangle * t); +GtsEdge * gts_triangles_common_edge (GtsTriangle * t1, + GtsTriangle * t2); +GtsTriangle * gts_triangle_is_duplicate (GtsTriangle * t); +GtsTriangle * gts_triangle_use_edges (GtsEdge * e1, + GtsEdge * e2, + GtsEdge * e3); +gboolean gts_triangle_is_ok (GtsTriangle * t); +void gts_triangle_vertices (GtsTriangle * t, + GtsVertex ** v1, + GtsVertex ** v2, + GtsVertex ** v3); +GtsPoint * gts_triangle_circumcircle_center (GtsTriangle * t, + GtsPointClass * point_class); +gboolean gts_triangles_are_folded (GSList * triangles, + GtsVertex * A, GtsVertex * B, + gdouble max); +GtsObject * gts_triangle_is_stabbed (GtsTriangle * t, + GtsPoint * p, + gdouble * orientation); +void gts_triangle_interpolate_height (GtsTriangle * t, + GtsPoint * p); + +/* Faces: face.c */ + +#define GTS_IS_FACE(obj) (gts_object_is_from_class (obj,\ + gts_face_class ())) +#define GTS_FACE(obj) GTS_OBJECT_CAST (obj,\ + GtsFace,\ + gts_face_class ()) +#define GTS_FACE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsFaceClass,\ + gts_face_class ()) + +struct _GtsFace { + GtsTriangle triangle; + + GSList * surfaces; +}; + +struct _GtsFaceClass { + GtsTriangleClass parent_class; +}; + +GTS_C_VAR +gboolean gts_allow_floating_faces; + +GtsFaceClass * gts_face_class (void); +GtsFace * gts_face_new (GtsFaceClass * klass, + GtsEdge * e1, + GtsEdge * e2, + GtsEdge * e3); +gboolean gts_face_has_parent_surface (GtsFace * f, + GtsSurface * s); +GSList * gts_faces_from_edges (GSList * edges, + GtsSurface * s); +guint gts_face_neighbor_number (GtsFace * f, + GtsSurface * s); +GSList * gts_face_neighbors (GtsFace * f, + GtsSurface * s); +void gts_face_foreach_neighbor (GtsFace * f, + GtsSurface * s, + GtsFunc func, + gpointer data); +gboolean gts_face_is_compatible (GtsFace * f, + GtsSurface * s); + +/* Matrices: matrix.c */ + +#define gts_vector_cross(C,A,B) ((C)[0] = (A)[1]*(B)[2] - (A)[2]*(B)[1],\ + (C)[1] = (A)[2]*(B)[0] - (A)[0]*(B)[2],\ + (C)[2] = (A)[0]*(B)[1] - (A)[1]*(B)[0]) + +#define gts_vector_init(v, p1, p2) ((v)[0] = (p2)->x - (p1)->x,\ + (v)[1] = (p2)->y - (p1)->y,\ + (v)[2] = (p2)->z - (p1)->z) +#define gts_vector_scalar(v1, v2) ((v1)[0]*(v2)[0] +\ + (v1)[1]*(v2)[1] +\ + (v1)[2]*(v2)[2]) +#define gts_vector_norm(v) (sqrt ((v)[0]*(v)[0] +\ + (v)[1]*(v)[1] +\ + (v)[2]*(v)[2])) +#define gts_vector_normalize(v) {\ + gdouble __gts_n = gts_vector_norm (v);\ + if (__gts_n > 0.) {\ + (v)[0] /= __gts_n;\ + (v)[1] /= __gts_n;\ + (v)[2] /= __gts_n;\ + }\ +} +GtsMatrix * gts_matrix_new (gdouble a00, gdouble a01, gdouble a02, gdouble a03, + gdouble a10, gdouble a11, gdouble a12, gdouble a13, + gdouble a20, gdouble a21, gdouble a22, gdouble a23, + gdouble a30, gdouble a31, gdouble a32, gdouble a33); +void gts_matrix_assign (GtsMatrix * m, + gdouble a00, gdouble a01, gdouble a02, gdouble a03, + gdouble a10, gdouble a11, gdouble a12, gdouble a13, + gdouble a20, gdouble a21, gdouble a22, gdouble a23, + gdouble a30, gdouble a31, gdouble a32, gdouble a33); +GtsMatrix * gts_matrix_projection (GtsTriangle * t); +GtsMatrix * gts_matrix_transpose (GtsMatrix * m); +gdouble gts_matrix_determinant (GtsMatrix * m); +GtsMatrix * gts_matrix_inverse (GtsMatrix * m); +GtsMatrix * gts_matrix3_inverse (GtsMatrix * m); +void gts_matrix_print (GtsMatrix * m, + FILE * fptr); +guint gts_matrix_compatible_row (GtsMatrix * A, + GtsVector b, + guint n, + GtsVector A1, + gdouble b1); +guint gts_matrix_quadratic_optimization (GtsMatrix * A, + GtsVector b, + guint n, + GtsMatrix * H, + GtsVector c); +GtsMatrix * gts_matrix_product (GtsMatrix * m1, + GtsMatrix * m2); +GtsMatrix * gts_matrix_zero (GtsMatrix * m); +GtsMatrix * gts_matrix_identity (GtsMatrix * m); +GtsMatrix * gts_matrix_scale (GtsMatrix * m, + GtsVector s); +GtsMatrix * gts_matrix_translate (GtsMatrix * m, + GtsVector t); +GtsMatrix * gts_matrix_rotate (GtsMatrix * m, + GtsVector r, + gdouble angle); +void gts_matrix_destroy (GtsMatrix * m); +void gts_vector_print (GtsVector v, + FILE * fptr); +void gts_vector4_print (GtsVector4 v, + FILE * fptr); + +/* Kdtrees: kdtree.c */ + +#define gts_kdtree_destroy(tree) g_node_destroy(tree) + +GNode * gts_kdtree_new (GPtrArray * points, + int (*compare) + (const void *, + const void *)); +GSList * gts_kdtree_range (GNode * tree, + GtsBBox * bbox, + int (*compare) + (const void *, + const void *)); + +/* Bboxtrees: bbtree.c */ + +/** + * GtsBBTreeTraverseFunc: + * @bb1: a #GtsBBox. + * @bb2: another #GtsBBox. + * @data: user data passed to the function. + * + * User function called for each pair of overlapping bounding + * boxes. See gts_bb_tree_traverse_overlapping(). + */ +typedef void (*GtsBBTreeTraverseFunc) (GtsBBox * bb1, + GtsBBox * bb2, + gpointer data); +/** + * GtsBBoxDistFunc: + * @p: a #GtsPoint. + * @bounded: an object bounded by a #GtsBBox. + * + * User function returning the (minimum) distance between the object + * defined by @bounded and point @p. + * + * Returns: the distance between @p and @bounded. + */ +typedef gdouble (*GtsBBoxDistFunc) (GtsPoint * p, + gpointer bounded); +/** + * GtsBBoxClosestFunc: + * @p: a #GtsPoint. + * @bounded: an object bounded by a #GtsBBox. + * + * User function returning a #GtsPoint belonging to the object defined + * by @bounded and closest to @p. + * + * Returns: a #GtsPoint. + */ +typedef GtsPoint * (*GtsBBoxClosestFunc) (GtsPoint * p, + gpointer bounded); + +/** + * GTS_IS_BBOX: + * @obj: a #GtsObject. + * + * Evaluates to %TRUE if @obj is a #GtsBBox, %FALSE otherwise. + */ +#define GTS_IS_BBOX(obj) (gts_object_is_from_class (obj,\ + gts_bbox_class ())) +/** + * GTS_BBOX: + * @obj: a #GtsObject. + * + * Casts @obj to #GtsBBox. + */ +#define GTS_BBOX(obj) GTS_OBJECT_CAST (obj,\ + GtsBBox,\ + gts_bbox_class ()) +/** + * GTS_BBOX_CLASS: + * @klass: a descendant of #GtsBBoxClass. + * + * Casts @klass to #GtsBBoxClass. + */ +#define GTS_BBOX_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsBBoxClass,\ + gts_bbox_class ()) + +struct _GtsBBox { + GtsObject object; + gpointer bounded; + gdouble x1, y1, z1; + gdouble x2, y2, z2; +}; + +struct _GtsBBoxClass { + GtsObjectClass parent_class; +}; + +GtsBBoxClass * gts_bbox_class (void); +GtsBBox * gts_bbox_new (GtsBBoxClass * klass, + gpointer bounded, + gdouble x1, + gdouble y1, + gdouble z1, + gdouble x2, + gdouble y2, + gdouble z2); +void gts_bbox_set (GtsBBox * bbox, + gpointer bounded, + gdouble x1, + gdouble y1, + gdouble z1, + gdouble x2, + gdouble y2, + gdouble z2); +GtsBBox * gts_bbox_segment (GtsBBoxClass * klass, + GtsSegment * s); +GtsBBox * gts_bbox_triangle (GtsBBoxClass * klass, + GtsTriangle * t); +GtsBBox * gts_bbox_surface (GtsBBoxClass * klass, + GtsSurface * surface); +GtsBBox * gts_bbox_bboxes (GtsBBoxClass * klass, + GSList * bboxes); +GtsBBox * gts_bbox_points (GtsBBoxClass * klass, + GSList * points); +/** + * gts_bbox_point_is_inside: + * @bbox: a #GtsBBox. + * @p: a #GtsPoint. + * + * Evaluates to %TRUE if @p is inside (or on the boundary) of @bbox, %FALSE otherwise. + */ +#define gts_bbox_point_is_inside(bbox, p) ((p)->x >= (bbox)->x1 &&\ + (p)->y >= (bbox)->y1 &&\ + (p)->z >= (bbox)->z1 &&\ + (p)->x <= (bbox)->x2 &&\ + (p)->y <= (bbox)->y2 &&\ + (p)->z <= (bbox)->z2) +gboolean gts_bboxes_are_overlapping (GtsBBox * bb1, + GtsBBox * bb2); +void gts_bbox_draw (GtsBBox * bb, + FILE * fptr); +gdouble gts_bbox_diagonal2 (GtsBBox * bb); +void gts_bbox_point_distance2 (GtsBBox * bb, + GtsPoint * p, + gdouble * min, + gdouble * max); +gboolean gts_bbox_is_stabbed (GtsBBox * bb, + GtsPoint * p); +gboolean gts_bbox_overlaps_triangle (GtsBBox * bb, + GtsTriangle * t); +gboolean gts_bbox_overlaps_segment (GtsBBox * bb, + GtsSegment * s); + +GNode * gts_bb_tree_new (GSList * bboxes); +GNode * gts_bb_tree_surface (GtsSurface * s); +GSList * gts_bb_tree_stabbed (GNode * tree, + GtsPoint * p); +GSList * gts_bb_tree_overlap (GNode * tree, + GtsBBox * bbox); +gboolean gts_bb_tree_is_overlapping (GNode * tree, + GtsBBox * bbox); +void gts_bb_tree_traverse_overlapping (GNode * tree1, + GNode * tree2, + GtsBBTreeTraverseFunc func, + gpointer data); +void gts_bb_tree_draw (GNode * tree, + guint depth, + FILE * fptr); +GSList * gts_bb_tree_point_closest_bboxes (GNode * tree, + GtsPoint * p); +gdouble gts_bb_tree_point_distance (GNode * tree, + GtsPoint * p, + GtsBBoxDistFunc distance, + GtsBBox ** bbox); +GtsPoint * gts_bb_tree_point_closest (GNode * tree, + GtsPoint * p, + GtsBBoxClosestFunc closest, + gdouble * distance); +void gts_bb_tree_segment_distance (GNode * tree, + GtsSegment * s, + GtsBBoxDistFunc distance, + gdouble delta, + GtsRange * range); +void gts_bb_tree_triangle_distance (GNode * tree, + GtsTriangle * t, + GtsBBoxDistFunc distance, + gdouble delta, + GtsRange * range); +void gts_bb_tree_surface_distance (GNode * tree, + GtsSurface * s, + GtsBBoxDistFunc distance, + gdouble delta, + GtsRange * range); +void gts_bb_tree_surface_boundary_distance + (GNode * tree, + GtsSurface * s, + GtsBBoxDistFunc distance, + gdouble delta, + GtsRange * range); +void gts_bb_tree_destroy (GNode * tree, + gboolean free_leaves); + +/* Surfaces: surface.c */ + +typedef struct _GtsSurfaceStats GtsSurfaceStats; +typedef struct _GtsSurfaceQualityStats GtsSurfaceQualityStats; +typedef GtsVertex * (*GtsRefineFunc) (GtsEdge * e, + GtsVertexClass * klass, + gpointer data); +typedef GtsVertex * (*GtsCoarsenFunc) (GtsEdge * e, + GtsVertexClass * klass, + gpointer data); +typedef gboolean (*GtsStopFunc) (gdouble cost, + guint nedge, + gpointer data); + +struct _GtsSurfaceStats { + guint n_faces; + guint n_incompatible_faces; + guint n_duplicate_faces; + guint n_duplicate_edges; + guint n_boundary_edges; + guint n_non_manifold_edges; + GtsRange edges_per_vertex, faces_per_edge; + GtsSurface * parent; +}; + +struct _GtsSurfaceQualityStats { + GtsRange face_quality; + GtsRange face_area; + GtsRange edge_length; + GtsRange edge_angle; + GtsSurface * parent; +}; + +struct _GtsSurface { + GtsObject object; + +#ifdef USE_SURFACE_BTREE + GTree * faces; +#else /* not USE_SURFACE_BTREE */ + GHashTable * faces; +#endif /* not USE_SURFACE_BTREE */ + GtsFaceClass * face_class; + GtsEdgeClass * edge_class; + GtsVertexClass * vertex_class; + gboolean keep_faces; +}; + +struct _GtsSurfaceClass { + GtsObjectClass parent_class; + + void (* add_face) (GtsSurface *, GtsFace *); + void (* remove_face) (GtsSurface *, GtsFace *); +}; + +#define GTS_IS_SURFACE(obj) (gts_object_is_from_class (obj,\ + gts_surface_class ())) +#define GTS_SURFACE(obj) GTS_OBJECT_CAST (obj,\ + GtsSurface,\ + gts_surface_class ()) +#define GTS_SURFACE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsSurfaceClass,\ + gts_surface_class ()) + +GtsSurfaceClass * gts_surface_class (void); +GtsSurface * gts_surface_new (GtsSurfaceClass * klass, + GtsFaceClass * face_class, + GtsEdgeClass * edge_class, + GtsVertexClass * vertex_class); +void gts_surface_add_face (GtsSurface * s, + GtsFace * f); +void gts_surface_remove_face (GtsSurface * s, + GtsFace * f); +guint gts_surface_read (GtsSurface * surface, + GtsFile * f); +gdouble gts_surface_area (GtsSurface * s); +void gts_surface_stats (GtsSurface * s, + GtsSurfaceStats * stats); +void gts_surface_quality_stats (GtsSurface * s, + GtsSurfaceQualityStats * stats); +void gts_surface_print_stats (GtsSurface * s, + FILE * fptr); +void gts_surface_write (GtsSurface * s, + FILE * fptr); +void gts_surface_write_oogl (GtsSurface * s, + FILE * fptr); +void gts_surface_write_vtk (GtsSurface * s, + FILE * fptr); +void gts_surface_write_oogl_boundary (GtsSurface * s, + FILE * fptr); +void gts_surface_foreach_vertex (GtsSurface * s, + GtsFunc func, + gpointer data); +void gts_surface_foreach_edge (GtsSurface * s, + GtsFunc func, + gpointer data); +void gts_surface_foreach_face (GtsSurface * s, + GtsFunc func, + gpointer data); +guint gts_surface_foreach_face_remove (GtsSurface * s, + GtsFunc func, + gpointer data); +typedef struct _GtsSurfaceTraverse GtsSurfaceTraverse; +GtsSurfaceTraverse * gts_surface_traverse_new (GtsSurface * s, + GtsFace * f); +GtsFace * gts_surface_traverse_next (GtsSurfaceTraverse * t, + guint * level); +void gts_surface_traverse_destroy (GtsSurfaceTraverse * t); +void gts_surface_refine (GtsSurface * surface, + GtsKeyFunc cost_func, + gpointer cost_data, + GtsRefineFunc refine_func, + gpointer refine_data, + GtsStopFunc stop_func, + gpointer stop_data); +gboolean gts_edge_collapse_is_valid (GtsEdge * e); +void gts_surface_coarsen (GtsSurface * surface, + GtsKeyFunc cost_func, + gpointer cost_data, + GtsCoarsenFunc coarsen_func, + gpointer coarsen_data, + GtsStopFunc stop_func, + gpointer stop_data, + gdouble minangle); +gboolean gts_coarsen_stop_number (gdouble cost, + guint nedge, + guint * min_number); +gboolean gts_coarsen_stop_cost (gdouble cost, + guint nedge, + gdouble * max_cost); +void gts_surface_tessellate (GtsSurface * s, + GtsRefineFunc refine_func, + gpointer refine_data); +GtsSurface * gts_surface_generate_sphere (GtsSurface * s, + guint geodesation_order); +GtsSurface * gts_surface_copy (GtsSurface * s1, + GtsSurface * s2); +void gts_surface_merge (GtsSurface * s, + GtsSurface * with); +gboolean gts_surface_is_manifold (GtsSurface * s); +gboolean gts_surface_is_closed (GtsSurface * s); +gboolean gts_surface_is_orientable (GtsSurface * s); +gdouble gts_surface_volume (GtsSurface * s); +gdouble gts_surface_center_of_mass (GtsSurface * s, + GtsVector cm); +gdouble gts_surface_center_of_area (GtsSurface * s, + GtsVector cm); +guint gts_surface_vertex_number (GtsSurface * s); +guint gts_surface_edge_number (GtsSurface * s); +guint gts_surface_face_number (GtsSurface * s); +void gts_surface_distance (GtsSurface * s1, + GtsSurface * s2, + gdouble delta, + GtsRange * face_range, + GtsRange * boundary_range); +GSList * gts_surface_boundary (GtsSurface * surface); +GSList * gts_surface_split (GtsSurface * s); + +/* Discrete differential operators: curvature.c */ + +gboolean gts_vertex_mean_curvature_normal (GtsVertex * v, + GtsSurface * s, + GtsVector Kh); +gboolean gts_vertex_gaussian_curvature (GtsVertex * v, + GtsSurface * s, + gdouble * Kg); +void gts_vertex_principal_curvatures (gdouble Kh, + gdouble Kg, + gdouble * K1, + gdouble * K2); +void gts_vertex_principal_directions (GtsVertex * v, + GtsSurface * s, + GtsVector Kh, + gdouble Kg, + GtsVector e1, + GtsVector e2); + +/* Volume optimization: vopt.c */ +typedef struct _GtsVolumeOptimizedParams GtsVolumeOptimizedParams; + +struct _GtsVolumeOptimizedParams { + gdouble volume_weight; + gdouble boundary_weight; + gdouble shape_weight; +}; + +GtsVertex * gts_volume_optimized_vertex (GtsEdge * edge, + GtsVertexClass * klass, + GtsVolumeOptimizedParams * params); +gdouble gts_volume_optimized_cost (GtsEdge * e, + GtsVolumeOptimizedParams * params); + +/* bool operations: boolean.c */ + +GSList * gts_surface_intersection (GtsSurface * s1, + GtsSurface * s2, + GNode * faces_tree1, + GNode * faces_tree2); + +typedef struct _GtsSurfaceInter GtsSurfaceInter; +typedef struct _GtsSurfaceInterClass GtsSurfaceInterClass; +/** + * GtsBooleanOperation: + * @GTS_1_OUT_2: identifies the part of the first surface which lies + * outside the second surface. + * @GTS_1_IN_2: identifies the part of the first surface which lies + * inside the second surface. + * @GTS_2_OUT_1: identifies the part of the second surface which lies + * outside the first surface. + * @GTS_2_IN_1: identifies the part of the second surface which lies + * inside the first surface. + */ +typedef enum { GTS_1_OUT_2, + GTS_1_IN_2, + GTS_2_OUT_1, + GTS_2_IN_1 } GtsBooleanOperation; + +/** + * GTS_IS_SURFACE_INTER: + * @obj: a #GtsObject. + * + * Evaluates to %TRUE if @obj is a #GtsSurfaceInter, %FALSE otherwise. + */ +#define GTS_IS_SURFACE_INTER(obj) (gts_object_is_from_class (obj,\ + gts_surface_inter_class ())) +/** + * GTS_SURFACE_INTER: + * @obj: a descendant of #GtsSurfaceInter. + * + * Casts @obj to #GtsSurfaceInter. + */ +#define GTS_SURFACE_INTER(obj) GTS_OBJECT_CAST (obj,\ + GtsSurfaceInter,\ + gts_surface_inter_class ()) +/** + * GTS_SURFACE_INTER_CLASS: + * @klass: a descendant of #GtsSurfaceInterClass. + * + * Casts @klass to #GtsSurfaceInterClass. + */ +#define GTS_SURFACE_INTER_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsSurfaceInterClass,\ + gts_surface_inter_class ()) + +struct _GtsSurfaceInter { + GtsObject object; + + GtsSurface * s1; + GtsSurface * s2; + GSList * edges; +}; + +struct _GtsSurfaceInterClass { + GtsObjectClass parent_class; +}; + +GtsSurfaceInterClass * +gts_surface_inter_class (void); +GtsSurfaceInter * +gts_surface_inter_new (GtsSurfaceInterClass * klass, + GtsSurface * s1, + GtsSurface * s2, + GNode * faces_tree1, + GNode * faces_tree2, + gboolean is_open1, + gboolean is_open2); +gboolean +gts_surface_inter_check (GtsSurfaceInter * si, + gboolean * closed); +void +gts_surface_inter_boolean (GtsSurfaceInter * si, + GtsSurface * surface, + GtsBooleanOperation op); +gboolean gts_surface_foreach_intersecting_face (GtsSurface * s, + GtsBBTreeTraverseFunc func, + gpointer data); +GtsSurface * +gts_surface_is_self_intersecting (GtsSurface * s); + +/* Binary Heap: heap.c */ + +typedef struct _GtsHeap GtsHeap; + +GtsHeap * gts_heap_new (GCompareFunc compare_func); +void gts_heap_insert (GtsHeap * heap, gpointer p); +gpointer gts_heap_remove_top (GtsHeap * heap); +gpointer gts_heap_top (GtsHeap * heap); +void gts_heap_thaw (GtsHeap * heap); +void gts_heap_foreach (GtsHeap * heap, + GFunc func, + gpointer user_data); +void gts_heap_freeze (GtsHeap * heap); +guint gts_heap_size (GtsHeap * heap); +void gts_heap_destroy (GtsHeap * heap); + +/* Extended Binary Heap: eheap.c */ + +typedef struct _GtsEHeap GtsEHeap; +typedef struct _GtsEHeapPair GtsEHeapPair; + +struct _GtsEHeap { + GPtrArray * elts; + GtsKeyFunc func; + gpointer data; + gboolean frozen, randomized; +}; + +/** + * _GtsEHeapPair: + * @data: Points to the item stored in the heap. + * @key: Value of the key for this item. + * @pos: Private field. + */ +struct _GtsEHeapPair { + gpointer data; + gdouble key; + guint pos; +}; + +GtsEHeap * gts_eheap_new (GtsKeyFunc key_func, + gpointer data); +GtsEHeapPair * gts_eheap_insert (GtsEHeap * heap, + gpointer p); +GtsEHeapPair * gts_eheap_insert_with_key (GtsEHeap * heap, + gpointer p, + gdouble key); +gpointer gts_eheap_remove_top (GtsEHeap * heap, + gdouble * key); +gpointer gts_eheap_top (GtsEHeap * heap, + gdouble * key); +void gts_eheap_thaw (GtsEHeap * heap); +void gts_eheap_foreach (GtsEHeap * heap, + GFunc func, + gpointer data); +gpointer gts_eheap_remove (GtsEHeap * heap, + GtsEHeapPair * p); +void gts_eheap_decrease_key (GtsEHeap * heap, + GtsEHeapPair * p, + gdouble new_key); +void gts_eheap_freeze (GtsEHeap * heap); +guint gts_eheap_size (GtsEHeap * heap); +void gts_eheap_update (GtsEHeap * heap); +gdouble gts_eheap_key (GtsEHeap * heap, + gpointer p); +void gts_eheap_randomized (GtsEHeap * heap, + gboolean randomized); +void gts_eheap_destroy (GtsEHeap * heap); + +/* FIFO queues: fifo.c */ + +typedef struct _GtsFifo GtsFifo; + +GtsFifo * gts_fifo_new (void); +void gts_fifo_write (GtsFifo * fifo, + FILE * fp); +void gts_fifo_push (GtsFifo * fifo, + gpointer data); +gpointer gts_fifo_pop (GtsFifo * fifo); +gpointer gts_fifo_top (GtsFifo * fifo); +guint gts_fifo_size (GtsFifo * fifo); +gboolean gts_fifo_is_empty (GtsFifo * fifo); +void gts_fifo_foreach (GtsFifo * fifo, + GtsFunc func, + gpointer data); +void gts_fifo_reverse (GtsFifo * fifo); +void gts_fifo_destroy (GtsFifo * fifo); + +/* Progressive surfaces */ + +/* split.c */ + +typedef struct _GtsSplit GtsSplit; +typedef struct _GtsSplitClass GtsSplitClass; +typedef struct _GtsSplitCFace GtsSplitCFace; + +struct _GtsSplit { + GtsObject object; + + GtsVertex * v; + GtsObject * v1; + GtsObject * v2; + GtsSplitCFace * cfaces; + guint ncf; +}; + +struct _GtsSplitClass { + GtsObjectClass parent_class; +}; + +#define GTS_IS_SPLIT(obj) (gts_object_is_from_class (obj,\ + gts_split_class ())) +#define GTS_SPLIT(obj) GTS_OBJECT_CAST (obj,\ + GtsSplit,\ + gts_split_class ()) +#define GTS_SPLIT_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsSplitClass,\ + gts_split_class ()) +#define GTS_SPLIT_V1(vs) (GTS_IS_SPLIT ((vs)->v1) ?\ + GTS_SPLIT ((vs)->v1)->v :\ + GTS_VERTEX ((vs)->v1)) +#define GTS_SPLIT_V2(vs) (GTS_IS_SPLIT ((vs)->v2) ?\ + GTS_SPLIT ((vs)->v2)->v :\ + GTS_VERTEX ((vs)->v2)) + +GtsSplitClass * gts_split_class (void); +GtsSplit * gts_split_new (GtsSplitClass * klass, + GtsVertex * v, + GtsObject * o1, + GtsObject * o2); +void gts_split_collapse (GtsSplit * vs, + GtsEdgeClass * klass, + GtsEHeap * heap); +void gts_split_expand (GtsSplit * vs, + GtsSurface * s, + GtsEdgeClass * klass); +typedef gboolean (*GtsSplitTraverseFunc) (GtsSplit * vs, + gpointer data); +void gts_split_traverse (GtsSplit * root, + GTraverseType order, + gint depth, + GtsSplitTraverseFunc func, + gpointer data); +guint gts_split_height (GtsSplit * root); + +/* psurface.c */ + +typedef struct _GtsPSurface GtsPSurface; +typedef struct _GtsPSurfaceClass GtsPSurfaceClass; + +struct _GtsPSurface { + GtsObject object; + + GtsSurface * s; + GPtrArray * split; + GtsSplitClass * split_class; + guint pos, min; + + GPtrArray * vertices; + GPtrArray * faces; +}; + +struct _GtsPSurfaceClass { + GtsObjectClass parent_class; +}; + +#define GTS_IS_PSURFACE(obj) (gts_object_is_from_class (obj,\ + gts_psurface_class ())) +#define GTS_PSURFACE(obj) GTS_OBJECT_CAST (obj,\ + GtsPSurface,\ + gts_psurface_class ()) +#define GTS_PSURFACE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsPSurfaceClass,\ + gts_psurface_class ()) +#define GTS_PSURFACE_IS_CLOSED(ps) (!(ps)->vertices) + +GtsPSurfaceClass * gts_psurface_class (void); +GtsPSurface * gts_psurface_new (GtsPSurfaceClass * klass, + GtsSurface * surface, + GtsSplitClass * split_class, + GtsKeyFunc cost_func, + gpointer cost_data, + GtsCoarsenFunc coarsen_func, + gpointer coarsen_data, + GtsStopFunc stop_func, + gpointer stop_data, + gdouble minangle); +GtsSplit * gts_psurface_add_vertex (GtsPSurface * ps); +GtsSplit * gts_psurface_remove_vertex (GtsPSurface * ps); +guint gts_psurface_max_vertex_number (GtsPSurface * ps); +guint gts_psurface_min_vertex_number (GtsPSurface * ps); +void gts_psurface_set_vertex_number (GtsPSurface * ps, + guint n); +guint gts_psurface_get_vertex_number (GtsPSurface * ps); +void gts_psurface_write (GtsPSurface * ps, + FILE * fptr); +GtsPSurface * gts_psurface_open (GtsPSurfaceClass * klass, + GtsSurface * s, + GtsSplitClass * split_class, + GtsFile * f); +GtsSplit * gts_psurface_read_vertex (GtsPSurface * ps, + GtsFile * fp); +void gts_psurface_close (GtsPSurface * ps); +void gts_psurface_foreach_vertex (GtsPSurface * ps, + GtsFunc func, + gpointer data); + +/* hsurface.c */ + +typedef struct _GtsHSplit GtsHSplit; +typedef struct _GtsHSplitClass GtsHSplitClass; +typedef struct _GtsHSurface GtsHSurface; +typedef struct _GtsHSurfaceClass GtsHSurfaceClass; + +struct _GtsHSplit { + GtsSplit split; + + GtsEHeapPair * index; + GtsHSplit * parent; + guint nchild; +}; + +struct _GtsHSplitClass { + GtsSplitClass parent_class; +}; + +#define GTS_IS_HSPLIT(obj) (gts_object_is_from_class (obj,\ + gts_hsplit_class ())) +#define GTS_HSPLIT(obj) GTS_OBJECT_CAST (obj,\ + GtsHSplit,\ + gts_hsplit_class ()) +#define GTS_HSPLIT_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsHSplitClass,\ + gts_hsplit_class ()) + +GtsHSplitClass * gts_hsplit_class (void); +GtsHSplit * gts_hsplit_new (GtsHSplitClass * klass, + GtsSplit * vs); +void gts_hsplit_collapse (GtsHSplit * hs, + GtsHSurface * hsurface); +void gts_hsplit_expand (GtsHSplit * hs, + GtsHSurface * hsurface); +void gts_hsplit_force_expand (GtsHSplit * hs, + GtsHSurface * hsurface); + +struct _GtsHSurface { + GtsObject object; + + GtsSurface * s; + GSList * roots; + GtsEHeap * expandable; + GtsEHeap * collapsable; + GPtrArray * split; + guint nvertex; +}; + +struct _GtsHSurfaceClass { + GtsObjectClass parent_class; +}; + +#define GTS_IS_HSURFACE(obj) (gts_object_is_from_class (obj,\ + gts_hsurface_class ())) +#define GTS_HSURFACE(obj) GTS_OBJECT_CAST (obj,\ + GtsHSurface,\ + gts_hsurface_class ()) +#define GTS_HSURFACE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsHSurfaceClass,\ + gts_hsurface_class ()) + +GtsHSurfaceClass * gts_hsurface_class (void); +GtsHSurface * gts_hsurface_new (GtsHSurfaceClass * klass, + GtsHSplitClass * hsplit_class, + GtsPSurface * psurface, + GtsKeyFunc expand_key, + gpointer expand_data, + GtsKeyFunc collapse_key, + gpointer collapse_data); +void gts_hsurface_traverse (GtsHSurface * hsurface, + GTraverseType order, + gint depth, + GtsSplitTraverseFunc func, + gpointer data); +void gts_hsurface_foreach (GtsHSurface * hsurface, + GTraverseType order, + GtsFunc func, + gpointer data); +guint gts_hsurface_height (GtsHSurface * hsurface); + +/* Constrained Delaunay triangulation: cdt.c */ + +/** + * GTS_IS_CONSTRAINT: + * @obj: a #GtsObject. + * + * Evaluates to %TRUE if @obj is a #GtsConstraint, %FALSE otherwise. + */ +#define GTS_IS_CONSTRAINT(obj) (gts_object_is_from_class (obj,\ + gts_constraint_class ())) +/** + * GTS_CONSTRAINT: + * @obj: a descendant of #GtsConstraint. + * + * Casts @obj to #GtsConstraint. + */ +#define GTS_CONSTRAINT(obj) GTS_OBJECT_CAST (obj,\ + GtsConstraint,\ + gts_constraint_class ()) +/** + * GTS_CONSTRAINT_CLASS: + * @klass: a desscendant of #GtsConstraintClass. + * + * Casts @klass to #GtsConstraintClass. + */ +#define GTS_CONSTRAINT_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsConstraintClass,\ + gts_constraint_class ()) + +struct _GtsConstraint { + GtsEdge edge; +}; + +struct _GtsConstraintClass { + GtsEdgeClass parent_class; +}; + +typedef struct _GtsConstraint GtsConstraint; +typedef struct _GtsConstraintClass GtsConstraintClass; + +GtsConstraintClass * gts_constraint_class (void); + +GtsFace * gts_point_locate (GtsPoint * p, + GtsSurface * surface, + GtsFace * guess); +GtsVertex * gts_delaunay_add_vertex_to_face (GtsSurface * surface, + GtsVertex * v, + GtsFace * f); +GtsVertex * gts_delaunay_add_vertex (GtsSurface * surface, + GtsVertex * v, + GtsFace * guess); +void gts_delaunay_remove_vertex (GtsSurface * surface, + GtsVertex * v); +GtsFace * gts_delaunay_check (GtsSurface * surface); +GSList * gts_delaunay_add_constraint (GtsSurface * surface, + GtsConstraint * c); +void gts_delaunay_remove_hull (GtsSurface * surface); + +/* GtsListFace: Header */ + +typedef struct _GtsListFace GtsListFace; + +struct _GtsListFace { + /*< private >*/ + GtsFace parent; + + /*< public >*/ + GSList * points; +}; + +#define GTS_LIST_FACE(obj) GTS_OBJECT_CAST (obj,\ + GtsListFace,\ + gts_list_face_class ()) +#define GTS_IS_LIST_FACE(obj) (gts_object_is_from_class (obj,\ + gts_list_face_class ())) + +GtsFaceClass * gts_list_face_class (void); + +/* Constrained Delaunay refinement: refine.c */ + +typedef gboolean (* GtsEncroachFunc) (GtsVertex * v, + GtsEdge * e, + GtsSurface * s, + gpointer data); + +gboolean gts_vertex_encroaches_edge (GtsVertex * v, + GtsEdge * e); +GtsVertex * gts_edge_is_encroached (GtsEdge * e, + GtsSurface * s, + GtsEncroachFunc encroaches, + gpointer data); +guint gts_delaunay_conform (GtsSurface * surface, + gint steiner_max, + GtsEncroachFunc encroaches, + gpointer data); +guint gts_delaunay_refine (GtsSurface * surface, + gint steiner_max, + GtsEncroachFunc encroaches, + gpointer encroach_data, + GtsKeyFunc cost, + gpointer cost_data); + +/* Isosurfaces (marching cubes): iso.c */ + +typedef struct _GtsGridPlane GtsGridPlane; +typedef struct _GtsIsoSlice GtsIsoSlice; +typedef struct _GtsCartesianGrid GtsCartesianGrid; + +struct _GtsGridPlane { + GtsPoint ** p; + guint nx, ny; +}; + +struct _GtsCartesianGrid { + guint nx, ny, nz; + gdouble x, dx, y, dy, z, dz; +}; + +typedef void (*GtsIsoCartesianFunc) (gdouble ** a, + GtsCartesianGrid g, + guint i, + gpointer data); + +GtsGridPlane * gts_grid_plane_new (guint nx, + guint ny); +void gts_grid_plane_destroy (GtsGridPlane * g); +GtsIsoSlice * gts_iso_slice_new (guint nx, guint ny); +void gts_iso_slice_fill (GtsIsoSlice * slice, + GtsGridPlane * plane1, + GtsGridPlane * plane2, + gdouble ** f1, + gdouble ** f2, + gdouble iso, + GtsVertexClass * klass); +void gts_iso_slice_fill_cartesian (GtsIsoSlice * slice, + GtsCartesianGrid g, + gdouble ** f1, + gdouble ** f2, + gdouble iso, + GtsVertexClass * klass); +void gts_iso_slice_destroy (GtsIsoSlice * slice); +void gts_isosurface_slice (GtsIsoSlice * slice1, + GtsIsoSlice * slice2, + GtsSurface * surface); +void gts_isosurface_cartesian (GtsSurface * surface, + GtsCartesianGrid g, + GtsIsoCartesianFunc f, + gpointer data, + gdouble iso); + +/* Isosurfaces (marching tetrahedra): isotetra.c */ + +void gts_isosurface_tetra (GtsSurface * surface, + GtsCartesianGrid g, + GtsIsoCartesianFunc f, + gpointer data, + gdouble iso); +void gts_isosurface_tetra_bcl (GtsSurface * surface, + GtsCartesianGrid g, + GtsIsoCartesianFunc f, + gpointer data, + gdouble iso); +void gts_isosurface_tetra_bounded (GtsSurface * surface, + GtsCartesianGrid g, + GtsIsoCartesianFunc f, + gpointer data, + gdouble iso); + +/* Named vertices, edges and triangles: named.c */ + +#define GTS_NAME_LENGTH 40 + +#define GTS_NVERTEX(obj) GTS_OBJECT_CAST (obj,\ + GtsNVertex,\ + gts_nvertex_class ()) +#define GTS_NVERTEX_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsNVertexClass,\ + gts_nvertex_class()) +#define GTS_IS_NVERTEX(obj) (gts_object_is_from_class (obj,\ + gts_nvertex_class ())) + +typedef struct _GtsNVertex GtsNVertex; +typedef struct _GtsNVertexClass GtsNVertexClass; + +struct _GtsNVertex { + GtsVertex parent; + char name[GTS_NAME_LENGTH]; +}; + +struct _GtsNVertexClass { + GtsVertexClass parent_class; +}; + +GtsNVertexClass * gts_nvertex_class (void); + +#define GTS_NEDGE(obj) GTS_OBJECT_CAST (obj,\ + GtsNEdge,\ + gts_nedge_class ()) +#define GTS_NEDGE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsNEdgeClass,\ + gts_nedge_class()) +#define GTS_IS_NEDGE(obj) (gts_object_is_from_class (obj,\ + gts_nedge_class ())) + +typedef struct _GtsNEdge GtsNEdge; +typedef struct _GtsNEdgeClass GtsNEdgeClass; + +struct _GtsNEdge { + GtsEdge parent; + char name[GTS_NAME_LENGTH]; +}; + +struct _GtsNEdgeClass { + GtsEdgeClass parent_class; +}; + +GtsNEdgeClass * gts_nedge_class (void); + +#define GTS_NFACE(obj) GTS_OBJECT_CAST (obj,\ + GtsNFace,\ + gts_nface_class ()) +#define GTS_NFACE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsNFaceClass,\ + gts_nface_class()) +#define GTS_IS_NFACE(obj) (gts_object_is_from_class (obj,\ + gts_nface_class ())) + +typedef struct _GtsNFace GtsNFace; +typedef struct _GtsNFaceClass GtsNFaceClass; + +struct _GtsNFace { + GtsFace parent; + char name[GTS_NAME_LENGTH]; +}; + +struct _GtsNFaceClass { + GtsFaceClass parent_class; +}; + +GtsNFaceClass * gts_nface_class (void); + +/* Cluster object for out-of-core simplification: oocs.c */ + +#define GTS_CLUSTER(obj) GTS_OBJECT_CAST (obj,\ + GtsCluster,\ + gts_cluster_class ()) +#define GTS_CLUSTER_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsClusterClass,\ + gts_cluster_class()) +#define GTS_IS_CLUSTER(obj) (gts_object_is_from_class (obj,\ + gts_cluster_class ())) + +typedef struct _GtsCluster GtsCluster; +typedef struct _GtsClusterClass GtsClusterClass; +typedef struct _GtsClusterId GtsClusterId; + +struct _GtsClusterId { + guint x, y, z; +}; + +struct _GtsCluster { + GtsObject parent; + + GtsClusterId id; + GtsVertex * v; + guint n; +}; + +struct _GtsClusterClass { + GtsObjectClass parent_class; + + void (* add) (GtsCluster * c, GtsPoint * p, gpointer data); + void (* update) (GtsCluster * c); +}; + +GtsClusterClass * gts_cluster_class (void); +GtsCluster * gts_cluster_new (GtsClusterClass * klass, + GtsClusterId id, + GtsVertexClass * vklass); +void gts_cluster_add (GtsCluster * c, + GtsPoint * p, + gpointer data); +void gts_cluster_update (GtsCluster * c); + +/* Cluster group object for out-of-core simplification: oocs.c */ + +#define GTS_CLUSTER_GRID(obj) GTS_OBJECT_CAST (obj,\ + GtsClusterGrid,\ + gts_cluster_grid_class ()) +#define GTS_CLUSTER_GRID_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsClusterGridClass,\ + gts_cluster_grid_class()) +#define GTS_IS_CLUSTER_GRID(obj) (gts_object_is_from_class (obj,\ + gts_cluster_grid_class ())) + +typedef struct _GtsClusterGrid GtsClusterGrid; +typedef struct _GtsClusterGridClass GtsClusterGridClass; + +struct _GtsClusterGrid { + GtsObject parent; + + GtsSurface * surface; + GtsBBox * bbox; + GtsVector size; + + GtsClusterClass * cluster_class; + GHashTable * clusters; +}; + +struct _GtsClusterGridClass { + GtsObjectClass parent_class; +}; + +GtsClusterGridClass * gts_cluster_grid_class (void); +GtsClusterGrid * gts_cluster_grid_new (GtsClusterGridClass * klass, + GtsClusterClass * cluster_class, + GtsSurface * s, + GtsBBox * bbox, + gdouble delta); +void gts_cluster_grid_add_triangle (GtsClusterGrid * cluster_grid, + GtsPoint * p1, + GtsPoint * p2, + GtsPoint * p3, + gpointer data); +GtsRange gts_cluster_grid_update (GtsClusterGrid * cluster_grid); + +/* Triangle strip generation: stripe.c */ +GSList * gts_surface_strip (GtsSurface * s); + +/* GtsContainee: container.c */ + +typedef struct _GtsContainee GtsContainee; +typedef struct _GtsContaineeClass GtsContaineeClass; +typedef struct _GtsContainer GtsContainer; +typedef struct _GtsContainerClass GtsContainerClass; + +struct _GtsContainee { + GtsObject object; +}; + +struct _GtsContaineeClass { + GtsObjectClass parent_class; + + void (* add_container) (GtsContainee *, GtsContainer *); + void (* remove_container) (GtsContainee *, GtsContainer *); + void (* foreach) (GtsContainee *, GtsFunc, gpointer); + gboolean (* is_contained) (GtsContainee *, GtsContainer *); + void (* replace) (GtsContainee *, GtsContainee *); +}; + +#define GTS_CONTAINEE(obj) GTS_OBJECT_CAST (obj,\ + GtsContainee,\ + gts_containee_class ()) +#define GTS_CONTAINEE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsContaineeClass,\ + gts_containee_class()) +#define GTS_IS_CONTAINEE(obj) (gts_object_is_from_class (obj,\ + gts_containee_class ())) + +GtsContaineeClass * gts_containee_class (void); +GtsContainee * gts_containee_new (GtsContaineeClass * klass); +gboolean gts_containee_is_contained (GtsContainee * item, + GtsContainer * c); +void gts_containee_replace (GtsContainee * item, + GtsContainee * with); + +/* GtsSListContainee: container.c */ + +typedef struct _GtsSListContainee GtsSListContainee; +typedef struct _GtsSListContaineeClass GtsSListContaineeClass; + +struct _GtsSListContainee { + GtsContainee containee; + + GSList * containers; +}; + +struct _GtsSListContaineeClass { + GtsContaineeClass parent_class; +}; + +#define GTS_SLIST_CONTAINEE(obj) GTS_OBJECT_CAST (obj,\ + GtsSListContainee,\ + gts_slist_containee_class ()) +#define GTS_SLIST_CONTAINEE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsSListContaineeClass,\ + gts_slist_containee_class()) +#define GTS_IS_SLIST_CONTAINEE(obj) (gts_object_is_from_class (obj,\ + gts_slist_containee_class ())) + +GtsSListContaineeClass * gts_slist_containee_class (void); + +/* GtsContainer: container.c */ + +struct _GtsContainer { + GtsSListContainee object; +}; + +struct _GtsContainerClass { + GtsSListContaineeClass parent_class; + + void (* add) (GtsContainer *, GtsContainee *); + void (* remove) (GtsContainer *, GtsContainee *); + void (* foreach) (GtsContainer *, GtsFunc, gpointer); + guint (* size) (GtsContainer *); +}; + +#define GTS_CONTAINER(obj) GTS_OBJECT_CAST (obj,\ + GtsContainer,\ + gts_container_class ()) +#define GTS_CONTAINER_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsContainerClass,\ + gts_container_class()) +#define GTS_IS_CONTAINER(obj) (gts_object_is_from_class (obj,\ + gts_container_class ())) + +GtsContainerClass * gts_container_class (void); +GtsContainer * gts_container_new (GtsContainerClass * klass); +void gts_container_add (GtsContainer * c, + GtsContainee * item); +void gts_container_remove (GtsContainer * c, + GtsContainee * item); +void gts_container_foreach (GtsContainer * c, + GtsFunc func, + gpointer data); +guint gts_container_size (GtsContainer * c); + +/* GtsHashContainer: container.c */ + +typedef struct _GtsHashContainer GtsHashContainer; +typedef struct _GtsHashContainerClass GtsHashContainerClass; + +struct _GtsHashContainer { + GtsContainer c; + + GHashTable * items; + gboolean frozen; +}; + +struct _GtsHashContainerClass { + GtsContainerClass parent_class; +}; + +#define GTS_HASH_CONTAINER(obj) GTS_OBJECT_CAST (obj,\ + GtsHashContainer,\ + gts_hash_container_class ()) +#define GTS_HASH_CONTAINER_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsHashContainerClass,\ + gts_hash_container_class()) +#define GTS_IS_HASH_CONTAINER(obj) (gts_object_is_from_class (obj,\ + gts_hash_container_class ())) + +GtsHashContainerClass * gts_hash_container_class (void); + +/* GtsSListContainer: container.c */ + +typedef struct _GtsSListContainer GtsSListContainer; +typedef struct _GtsSListContainerClass GtsSListContainerClass; + +struct _GtsSListContainer { + GtsContainer c; + + GSList * items; + gboolean frozen; +}; + +struct _GtsSListContainerClass { + GtsContainerClass parent_class; +}; + +#define GTS_SLIST_CONTAINER(obj) GTS_OBJECT_CAST (obj,\ + GtsSListContainer,\ + gts_slist_container_class ()) +#define GTS_SLIST_CONTAINER_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsSListContainerClass,\ + gts_slist_container_class()) +#define GTS_IS_SLIST_CONTAINER(obj) (gts_object_is_from_class (obj,\ + gts_slist_container_class ())) + +GtsSListContainerClass * gts_slist_container_class (void); + +/* GtsGNode: graph.c */ + +typedef struct _GtsGNode GtsGNode; +typedef struct _GtsGNodeClass GtsGNodeClass; +typedef struct _GtsGraph GtsGraph; +typedef struct _GtsGraphClass GtsGraphClass; + +struct _GtsGNode { + GtsSListContainer container; + + guint level; +}; + +struct _GtsGNodeClass { + GtsSListContainerClass parent_class; + + gfloat (* weight) (GtsGNode *); + void (* write) (GtsGNode *, FILE *); +}; + +#define GTS_GNODE(obj) GTS_OBJECT_CAST (obj,\ + GtsGNode,\ + gts_gnode_class ()) +#define GTS_GNODE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsGNodeClass,\ + gts_gnode_class()) +#define GTS_IS_GNODE(obj) (gts_object_is_from_class (obj,\ + gts_gnode_class ())) +#define GTS_GNODE_NEIGHBOR(n,e) (GTS_GEDGE (e)->n1 == n ? GTS_GEDGE (e)->n2 : GTS_GEDGE (e)->n2 == n ? GTS_GEDGE (e)->n1 : NULL) + +GtsGNodeClass * gts_gnode_class (void); +GtsGNode * gts_gnode_new (GtsGNodeClass * klass); +void gts_gnode_foreach_neighbor (GtsGNode * n, + GtsGraph * g, + GtsFunc func, + gpointer data); +void gts_gnode_foreach_edge (GtsGNode * n, + GtsGraph * g, + GtsFunc func, + gpointer data); +guint gts_gnode_degree (GtsGNode * n, + GtsGraph * g); +gfloat gts_gnode_move_cost (GtsGNode * n, + GtsGraph * src, + GtsGraph * dst); +gfloat gts_gnode_weight (GtsGNode * n); + +GTS_C_VAR +gboolean gts_allow_floating_gnodes; + +/* GtsNGNode: graph.c */ + +typedef struct _GtsNGNode GtsNGNode; +typedef struct _GtsNGNodeClass GtsNGNodeClass; + +struct _GtsNGNode { + GtsGNode node; + + guint id; +}; + +struct _GtsNGNodeClass { + GtsGNodeClass parent_class; +}; + +#define GTS_NGNODE(obj) GTS_OBJECT_CAST (obj,\ + GtsNGNode,\ + gts_ngnode_class ()) +#define GTS_NGNODE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsNGNodeClass,\ + gts_ngnode_class()) +#define GTS_IS_NGNODE(obj) (gts_object_is_from_class (obj,\ + gts_ngnode_class ())) + +GtsNGNodeClass * gts_ngnode_class (void); +GtsNGNode * gts_ngnode_new (GtsNGNodeClass * klass, + guint id); + +/* GtsWGNode: graph.c */ + +typedef struct _GtsWGNode GtsWGNode; +typedef struct _GtsWGNodeClass GtsWGNodeClass; + +struct _GtsWGNode { + GtsGNode node; + + gfloat weight; +}; + +struct _GtsWGNodeClass { + GtsGNodeClass parent_class; +}; + +#define GTS_WGNODE(obj) GTS_OBJECT_CAST (obj,\ + GtsWGNode,\ + gts_wgnode_class ()) +#define GTS_WGNODE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsWGNodeClass,\ + gts_wgnode_class()) +#define GTS_IS_WGNODE(obj) (gts_object_is_from_class (obj,\ + gts_wgnode_class ())) + +GtsWGNodeClass * gts_wgnode_class (void); +GtsWGNode * gts_wgnode_new (GtsWGNodeClass * klass, + gfloat weight); + +/* GtsPNode */ + +typedef struct _GtsPNode GtsPNode; +typedef struct _GtsPNodeClass GtsPNodeClass; + +struct _GtsPNode { + GtsGNode node; + + gpointer data; +}; + +struct _GtsPNodeClass { + GtsGNodeClass parent_class; +}; + +#define GTS_PNODE(obj) GTS_OBJECT_CAST (obj,\ + GtsPNode,\ + gts_pnode_class ()) +#define GTS_PNODE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsPNodeClass,\ + gts_pnode_class()) +#define GTS_IS_PNODE(obj) (gts_object_is_from_class (obj,\ + gts_pnode_class ())) + +GtsPNodeClass * gts_pnode_class (void); +GtsPNode * gts_pnode_new (GtsPNodeClass * klass, + gpointer data); + +/* GtsFNode */ + +typedef struct _GtsFNode GtsFNode; +typedef struct _GtsFNodeClass GtsFNodeClass; + +struct _GtsFNode { + GtsGNode node; + + GtsFace * f; +}; + +struct _GtsFNodeClass { + GtsGNodeClass parent_class; +}; + +#define GTS_FNODE(obj) GTS_OBJECT_CAST (obj,\ + GtsFNode,\ + gts_fnode_class ()) +#define GTS_FNODE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsFNodeClass,\ + gts_fnode_class()) +#define GTS_IS_FNODE(obj) (gts_object_is_from_class (obj,\ + gts_fnode_class ())) + +GtsFNodeClass * gts_fnode_class (void); +GtsFNode * gts_fnode_new (GtsFNodeClass * klass, + GtsFace * f); + +/* GtsGEdge: graph.c */ + +typedef struct _GtsGEdge GtsGEdge; +typedef struct _GtsGEdgeClass GtsGEdgeClass; + +struct _GtsGEdge { + GtsContainee containee; + + GtsGNode * n1; + GtsGNode * n2; +}; + +struct _GtsGEdgeClass { + GtsContaineeClass parent_class; + + GtsGEdge * (* link) (GtsGEdge * e, GtsGNode * n1, GtsGNode * n2); + gfloat (* weight) (GtsGEdge * e); + void (* write) (GtsGEdge * e, FILE * fp); +}; + +#define GTS_GEDGE(obj) GTS_OBJECT_CAST (obj,\ + GtsGEdge,\ + gts_gedge_class ()) +#define GTS_GEDGE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsGEdgeClass,\ + gts_gedge_class()) +#define GTS_IS_GEDGE(obj) (gts_object_is_from_class (obj,\ + gts_gedge_class ())) + +GtsGEdgeClass * gts_gedge_class (void); +GtsGEdge * gts_gedge_new (GtsGEdgeClass * klass, + GtsGNode * n1, + GtsGNode * n2); +gfloat gts_gedge_weight (GtsGEdge * e); +#define gts_gedge_connects(e, a1, a2)\ + (((e)->n1 == a1 && (e)->n2 == a2) || ((e)->n1 == a2 && (e)->n2 == a1)) + +/* GtsPGEdge: graph.c */ + +typedef struct _GtsPGEdge GtsPGEdge; +typedef struct _GtsPGEdgeClass GtsPGEdgeClass; + +struct _GtsPGEdge { + GtsGEdge gedge; + + gpointer data; +}; + +struct _GtsPGEdgeClass { + GtsGEdgeClass parent_class; +}; + +#define GTS_PGEDGE(obj) GTS_OBJECT_CAST (obj,\ + GtsPGEdge,\ + gts_pgedge_class ()) +#define GTS_PGEDGE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsPGEdgeClass,\ + gts_pgedge_class()) +#define GTS_IS_PGEDGE(obj) (gts_object_is_from_class (obj,\ + gts_pgedge_class ())) + +GtsPGEdgeClass * gts_pgedge_class (void); +GtsPGEdge * gts_pgedge_new (GtsPGEdgeClass * klass, + GtsGNode * n1, + GtsGNode * n2, + gpointer data); + +/* GtsWGEdge: graph.c */ + +typedef struct _GtsWGEdge GtsWGEdge; +typedef struct _GtsWGEdgeClass GtsWGEdgeClass; + +struct _GtsWGEdge { + GtsGEdge gedge; + + gfloat weight; +}; + +struct _GtsWGEdgeClass { + GtsGEdgeClass parent_class; +}; + +#define GTS_WGEDGE(obj) GTS_OBJECT_CAST (obj,\ + GtsWGEdge,\ + gts_wgedge_class ()) +#define GTS_WGEDGE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsWGEdgeClass,\ + gts_wgedge_class()) +#define GTS_IS_WGEDGE(obj) (gts_object_is_from_class (obj,\ + gts_wgedge_class ())) + +GtsWGEdgeClass * gts_wgedge_class (void); +GtsWGEdge * gts_wgedge_new (GtsWGEdgeClass * klass, + GtsGNode * n1, + GtsGNode * n2, + gfloat weight); + +/* GtsGraph: graph.c */ + +struct _GtsGraph { + GtsHashContainer object; + + GtsGraphClass * graph_class; + GtsGNodeClass * node_class; + GtsGEdgeClass * edge_class; +}; + +struct _GtsGraphClass { + GtsHashContainerClass parent_class; + + gfloat (* weight) (GtsGraph *); +}; + +#define GTS_GRAPH(obj) GTS_OBJECT_CAST (obj,\ + GtsGraph,\ + gts_graph_class ()) +#define GTS_GRAPH_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsGraphClass,\ + gts_graph_class()) +#define GTS_IS_GRAPH(obj) (gts_object_is_from_class (obj,\ + gts_graph_class ())) + +GtsGraphClass * gts_graph_class (void); +GtsGraph * gts_graph_new (GtsGraphClass * klass, + GtsGNodeClass * node_class, + GtsGEdgeClass * edge_class); +void gts_graph_print_stats (GtsGraph * g, + FILE * fp); +typedef struct _GtsGraphTraverse GtsGraphTraverse; +typedef enum { GTS_BREADTH_FIRST + } GtsTraverseType; +GtsGraphTraverse * gts_graph_traverse_new (GtsGraph * g, + GtsGNode * n, + GtsTraverseType type, + gboolean reinit); +GtsGNode * gts_graph_traverse_next (GtsGraphTraverse * t); +GtsGNode * gts_graph_traverse_what_next (GtsGraphTraverse * t); +void gts_graph_traverse_destroy (GtsGraphTraverse * t); +void gts_graph_foreach_edge (GtsGraph * g, + GtsFunc func, + gpointer data); +gfloat gts_graph_weight (GtsGraph * g); +guint gts_graph_distance_sum (GtsGraph * g, + GtsGNode * center); +GtsGNode * gts_graph_farthest (GtsGraph * g, + GSList * gnodes); +guint gts_graph_edges_cut (GtsGraph * g); +gfloat gts_graph_edges_cut_weight (GtsGraph * g); +void gts_graph_write (GtsGraph * g, + FILE * fp); +void gts_graph_write_dot (GtsGraph * g, + FILE * fp); +GtsGraph * gts_graph_read (GtsFile * fp); +guint gts_graph_read_jostle (GtsGraph * g, + GtsFile * fp); + +/* GtsWGraph: graph.c */ + +typedef struct _GtsWGraph GtsWGraph; +typedef struct _GtsWGraphClass GtsWGraphClass; + +struct _GtsWGraph { + GtsGraph graph; + + gfloat weight; +}; + +struct _GtsWGraphClass { + GtsGraphClass parent_class; +}; + +#define GTS_WGRAPH(obj) GTS_OBJECT_CAST (obj,\ + GtsWGraph,\ + gts_wgraph_class ()) +#define GTS_WGRAPH_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsWGraphClass,\ + gts_wgraph_class()) +#define GTS_IS_WGRAPH(obj) (gts_object_is_from_class (obj,\ + gts_wgraph_class ())) + +GtsWGraphClass * gts_wgraph_class (void); +gfloat gts_wgraph_weight_max (GtsWGraph * wg); + +/* Surface graph: graph.c */ + +GtsGraph * gts_surface_graph_new (GtsGraphClass * klass, + GtsSurface * s); +GtsSurface * gts_surface_graph_surface (GtsGraph * surface_graph, + GtsSurface * s); + +/* Segments graph: graph.c */ + +GtsGraph * gts_segments_graph_new (GtsGraphClass * klass, + GSList * segments); + +/* GtsGNodeSplit: pgraph.c */ + +typedef struct _GtsGNodeSplit GtsGNodeSplit; +typedef struct _GtsGNodeSplitClass GtsGNodeSplitClass; + +struct _GtsGNodeSplit { + GtsObject object; + + GtsGNode * n; + GtsObject * n1; + GtsObject * n2; +}; + +struct _GtsGNodeSplitClass { + GtsObjectClass parent_class; +}; + +#define GTS_GNODE_SPLIT(obj) GTS_OBJECT_CAST (obj,\ + GtsGNodeSplit,\ + gts_gnode_split_class ()) +#define GTS_GNODE_SPLIT_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsGNodeSplitClass,\ + gts_gnode_split_class()) +#define GTS_IS_GNODE_SPLIT(obj) (gts_object_is_from_class (obj,\ + gts_gnode_split_class ())) +#define GTS_GNODE_SPLIT_N1(ns) (GTS_IS_GNODE_SPLIT ((ns)->n1) ? GTS_GNODE_SPLIT ((ns)->n1)->n : GTS_GNODE ((ns)->n1)) +#define GTS_GNODE_SPLIT_N2(ns) (GTS_IS_GNODE_SPLIT ((ns)->n2) ? GTS_GNODE_SPLIT ((ns)->n2)->n : GTS_GNODE ((ns)->n2)) + +GtsGNodeSplitClass * gts_gnode_split_class (void); +GtsGNodeSplit * gts_gnode_split_new (GtsGNodeSplitClass * klass, + GtsGNode * n, + GtsObject * n1, + GtsObject * n2); +void gts_gnode_split_collapse (GtsGNodeSplit * ns, + GtsGraph * g, + GtsWGEdgeClass * klass); +void gts_gnode_split_expand (GtsGNodeSplit * ns, + GtsGraph * g); + +/* GtsPGraph: pgraph.c */ + +typedef struct _GtsPGraph GtsPGraph; +typedef struct _GtsPGraphClass GtsPGraphClass; + +struct _GtsPGraph { + GtsObject object; + + GtsGraph * g; + GPtrArray * split; + GArray * levels; + GtsGNodeSplitClass * split_class; + GtsWGEdgeClass * edge_class; + guint pos, min, level; +}; + +struct _GtsPGraphClass { + GtsObjectClass parent_class; +}; + +#define GTS_PGRAPH(obj) GTS_OBJECT_CAST (obj,\ + GtsPGraph,\ + gts_pgraph_class ()) +#define GTS_PGRAPH_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass,\ + GtsPGraphClass,\ + gts_pgraph_class()) +#define GTS_IS_PGRAPH(obj) (gts_object_is_from_class (obj,\ + gts_pgraph_class ())) + +GtsPGraphClass * gts_pgraph_class (void); +GtsPGraph * gts_pgraph_new (GtsPGraphClass * klass, + GtsGraph * g, + GtsGNodeSplitClass * split_class, + GtsWGNodeClass * node_class, + GtsWGEdgeClass * edge_class, + guint min); +GtsGNodeSplit * gts_pgraph_add_node (GtsPGraph * pg); +GtsGNodeSplit * gts_pgraph_remove_node (GtsPGraph * pg); +void gts_pgraph_set_node_number (GtsPGraph *pg, + guint n); +guint gts_pgraph_get_node_number (GtsPGraph *pg); +guint gts_pgraph_min_node_number (GtsPGraph *pg); +guint gts_pgraph_max_node_number (GtsPGraph *pg); +void gts_pgraph_foreach_node (GtsPGraph *pg, + GtsFunc func, + gpointer data); +gboolean gts_pgraph_down (GtsPGraph * pg, + GtsFunc func, + gpointer data); +/* Graph partition: partition.c */ + +GSList * gts_graph_bubble_partition (GtsGraph * g, + guint np, + guint niter, + GtsFunc step_info, + gpointer data); +guint gts_graph_partition_edges_cut (GSList * partition); +gfloat gts_graph_partition_edges_cut_weight (GSList * partition); +void gts_graph_partition_print_stats (GSList * partition, + FILE * fp); +gfloat gts_graph_partition_balance (GSList * partition); +GSList * gts_graph_partition_clone (GSList * partition); +GSList * gts_graph_recursive_bisection (GtsWGraph * wg, + guint n, + guint ntry, + guint mmax, + guint nmin, + gfloat imbalance); +void gts_graph_partition_destroy (GSList * partition); + +/* Graph bisection: partition.c */ + +typedef struct _GtsGraphBisection GtsGraphBisection; + +struct _GtsGraphBisection { + GtsGraph * g; + GtsGraph * g1; + GtsGraph * g2; + GHashTable * bg1; + GHashTable * bg2; +}; + +gboolean gts_graph_bisection_check (GtsGraphBisection * bg); +GtsGraphBisection * gts_graph_ggg_bisection (GtsGraph * g, + guint ntry); +GtsGraphBisection * gts_graph_bfgg_bisection (GtsGraph * g, + guint ntry); +gdouble gts_graph_bisection_kl_refine (GtsGraphBisection * bg, + guint mmax); +gdouble gts_graph_bisection_bkl_refine (GtsGraphBisection * bg, + guint mmax, + gfloat imbalance); +GtsGraphBisection * gts_graph_bisection_new (GtsWGraph * wg, + guint ntry, + guint mmax, + guint nmin, + gfloat imbalance); +void gts_graph_bisection_destroy (GtsGraphBisection * bg, + gboolean destroy_graphs); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __GTS_H__ */ Index: work/obsolete/toporouter/src_3rd/gts/heap.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/heap.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/heap.c (revision 6803) @@ -0,0 +1,258 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "gts.h" + +#define PARENT(i) ((i) >= 2 ? (i)/2 : 0) +#define LEFT_CHILD(i) (2*(i)) +#define RIGHT_CHILD(i) (2*(i) + 1) + +struct _GtsHeap { + GPtrArray * elts; + GCompareFunc func; + gboolean frozen; +}; + +/** + * gts_heap_new: + * @compare_func: a GCompareFunc. + * + * Returns: a new #GtsHeap using @compare_func as a sorting function. + */ +GtsHeap * gts_heap_new (GCompareFunc compare_func) +{ + GtsHeap * heap; + + g_return_val_if_fail (compare_func != NULL, NULL); + + heap = g_malloc (sizeof(GtsHeap)); + heap->elts = g_ptr_array_new (); + heap->func = compare_func; + heap->frozen = FALSE; + return heap; +} + +static void sift_up (GtsHeap * heap, guint i) +{ + gpointer parent, child; + guint p; + gpointer * pdata = heap->elts->pdata; + GCompareFunc func = heap->func; + + child = pdata[i - 1]; + while ((p = PARENT (i))) { + parent = pdata[p - 1]; + if ((*func) (parent, child) > 0) { + pdata[p - 1] = child; + pdata[i - 1] = parent; + i = p; + } + else + i = 0; + } +} + +/** + * gts_heap_insert: + * @heap: a #GtsHeap. + * @p: a pointer to add to the heap. + * + * Inserts a new element @p in the heap. + */ +void gts_heap_insert (GtsHeap * heap, gpointer p) +{ + g_return_if_fail (heap != NULL); + + g_ptr_array_add (heap->elts, p); + if (!heap->frozen) + sift_up (heap, heap->elts->len); +} + +static void sift_down (GtsHeap * heap, guint i) +{ + gpointer left_child, right_child, child, parent; + guint lc, rc, c; + gpointer * pdata = heap->elts->pdata; + guint len = heap->elts->len; + GCompareFunc func = heap->func; + + lc = LEFT_CHILD (i); + rc = RIGHT_CHILD (i); + left_child = lc <= len ? pdata[lc - 1] : NULL; + right_child = rc <= len ? pdata[rc - 1] : NULL; + + parent = pdata[i - 1]; + while (left_child != NULL) { + if (right_child == NULL || + (*func) (left_child, right_child) < 0) { + child = left_child; + c = lc; + } + else { + child = right_child; + c = rc; + } + if ((*func) (parent, child) > 0) { + pdata[i - 1] = child; + pdata[c - 1] = parent; + i = c; + lc = LEFT_CHILD (i); + rc = RIGHT_CHILD (i); + left_child = lc <= len ? pdata[lc - 1] : NULL; + right_child = rc <= len ? pdata[rc - 1] : NULL; + } + else + left_child = NULL; + } +} + +/** + * gts_heap_remove_top: + * @heap: a #GtsHeap. + * + * Removes the element at the top of the heap. + * + * Returns: the element at the top of the heap. + */ +gpointer gts_heap_remove_top (GtsHeap * heap) +{ + gpointer root; + GPtrArray * elts; + guint len; + + g_return_val_if_fail (heap != NULL, NULL); + + elts = heap->elts; len = elts->len; + + if (len == 0) + return NULL; + if (len == 1) + return g_ptr_array_remove_index (elts, 0); + + root = elts->pdata[0]; + elts->pdata[0] = g_ptr_array_remove_index (elts, len - 1); + sift_down (heap, 1); + return root; +} + +/** + * gts_heap_top: + * @heap: a #GtsHeap. + * + * Returns: the element at the top of the heap. + */ +gpointer gts_heap_top (GtsHeap * heap) +{ + GPtrArray * elts; + guint len; + + g_return_val_if_fail (heap != NULL, NULL); + + elts = heap->elts; + len = elts->len; + if (len == 0) + return NULL; + return elts->pdata[0]; +} + +/** + * gts_heap_destroy: + * @heap: a #GtsHeap. + * + * Free all the memory allocated for @heap. + */ +void gts_heap_destroy (GtsHeap * heap) +{ + g_return_if_fail (heap != NULL); + + g_ptr_array_free (heap->elts, TRUE); + g_free (heap); +} + +/** + * gts_heap_thaw: + * @heap: a #GtsHeap. + * + * If @heap has been frozen previously using gts_heap_freeze(), reorder it + * in O(n) time and unfreeze it. + */ +void gts_heap_thaw (GtsHeap * heap) +{ + guint i; + + g_return_if_fail (heap != NULL); + + if (!heap->frozen) + return; + + for (i = heap->elts->len/2; i > 0; i--) + sift_down (heap, i); + + heap->frozen = FALSE; +} + +/** + * gts_heap_foreach: + * @heap: a #GtsHeap. + * @func: the function to call for each element in the heap. + * @user_data: to pass to @func. + */ +void gts_heap_foreach (GtsHeap * heap, + GFunc func, + gpointer user_data) +{ + guint i; + GPtrArray * elts; + + g_return_if_fail (heap != NULL); + g_return_if_fail (func != NULL); + + elts = heap->elts; + for (i = 0; i < elts->len; i++) + (*func) (elts->pdata[i], user_data); +} + +/** + * gts_heap_freeze: + * @heap: a #GtsHeap. + * + * Freezes the heap. Any subsequent operation will not preserve the heap + * property. Used in conjunction with gts_heap_insert() and gts_heap_thaw() + * to create a heap in O(n) time. + */ +void gts_heap_freeze (GtsHeap * heap) +{ + g_return_if_fail (heap != NULL); + + heap->frozen = TRUE; +} + +/** + * gts_heap_size: + * @heap: a #GtsHeap. + * + * Returns: the number of items in @heap. + */ +guint gts_heap_size (GtsHeap * heap) +{ + g_return_val_if_fail (heap != NULL, 0); + + return heap->elts->len; +} Index: work/obsolete/toporouter/src_3rd/gts/hsurface.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/hsurface.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/hsurface.c (revision 6803) @@ -0,0 +1,405 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include "gts.h" + +#define HEAP_INSERT_HSPLIT(h, e) ((e)->index = gts_eheap_insert (h, e)) +#define HEAP_REMOVE_HSPLIT(h, e) (gts_eheap_remove (h, (e)->index),\ + (e)->index = NULL) + +static void hsplit_init (GtsHSplit * hsplit) +{ + hsplit->index = NULL; + hsplit->parent = NULL; + hsplit->nchild = 0; +} + +/** + * gts_hsplit_class: + * + * Returns: the #GtsHSplitClass. + */ +GtsHSplitClass * gts_hsplit_class (void) +{ + static GtsHSplitClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo hsplit_info = { + "GtsHSplit", + sizeof (GtsHSplit), + sizeof (GtsHSplitClass), + (GtsObjectClassInitFunc) NULL, + (GtsObjectInitFunc) hsplit_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_split_class ()), + &hsplit_info); + } + + return klass; +} + +/** + * gts_hsplit_new: + * @klass: a #GtsHSplitClass. + * @vs: a #GtsSplit. + * + * Returns: a new #GtsHSplit, hierarchical extension of @vs. + */ +GtsHSplit * gts_hsplit_new (GtsHSplitClass * klass, GtsSplit * vs) +{ + GtsHSplit * hs; + + g_return_val_if_fail (vs != NULL, NULL); + + hs = GTS_HSPLIT (gts_object_new (GTS_OBJECT_CLASS (klass))); + memcpy (hs, vs, sizeof (GtsSplit)); + GTS_OBJECT (hs)->reserved = NULL; + + return hs; +} + +/** + * gts_hsplit_collapse: + * @hs: a #GtsHSplit. + * @hsurface: a #GtsHSurface. + * + * Collapses the #GtsSplit defined by @hs, updates the expandable and + * collapsable priority heaps of @hsurface. + */ +void gts_hsplit_collapse (GtsHSplit * hs, + GtsHSurface * hsurface) +{ + GtsHSplit * parent; + GtsSplit * vs; + + g_return_if_fail (hs != NULL); + g_return_if_fail (hs->nchild == 2); + g_return_if_fail (hsurface != NULL); + + gts_split_collapse (GTS_SPLIT (hs), hsurface->s->edge_class, NULL); + + hsurface->nvertex--; + hs->nchild = 0; + HEAP_REMOVE_HSPLIT (hsurface->collapsable, hs); + HEAP_INSERT_HSPLIT (hsurface->expandable, hs); + + vs = GTS_SPLIT (hs); + if (GTS_IS_HSPLIT (vs->v1)) + HEAP_REMOVE_HSPLIT (hsurface->expandable, GTS_HSPLIT (vs->v1)); + if (GTS_IS_HSPLIT (vs->v2)) + HEAP_REMOVE_HSPLIT (hsurface->expandable, GTS_HSPLIT (vs->v2)); + + parent = hs->parent; + if (parent && ++parent->nchild == 2) + HEAP_INSERT_HSPLIT (hsurface->collapsable, parent); +} + +/** + * gts_hsplit_expand: + * @hs: a #GtsHSplit. + * @hsurface: a #GtsHSurface. + * + * Expands the #GtsSplit defined by @hs (which must be expandable) + * and updates the priority heaps of @hsurface. + */ +void gts_hsplit_expand (GtsHSplit * hs, + GtsHSurface * hsurface) +{ + GtsHSplit * parent; + GtsSplit * vs; + + g_return_if_fail (hs != NULL); + g_return_if_fail (hsurface != NULL); + g_return_if_fail (hs->nchild == 0); + + gts_split_expand (GTS_SPLIT (hs), hsurface->s, hsurface->s->edge_class); + hsurface->nvertex++; + hs->nchild = 2; + HEAP_REMOVE_HSPLIT (hsurface->expandable, hs); + HEAP_INSERT_HSPLIT (hsurface->collapsable, hs); + + vs = GTS_SPLIT (hs); + if (GTS_IS_HSPLIT (vs->v1)) + HEAP_INSERT_HSPLIT (hsurface->expandable, GTS_HSPLIT (vs->v1)); + if (GTS_IS_HSPLIT (vs->v2)) + HEAP_INSERT_HSPLIT (hsurface->expandable, GTS_HSPLIT (vs->v2)); + + parent = hs->parent; + if (parent && parent->nchild-- == 2) + HEAP_REMOVE_HSPLIT (hsurface->collapsable, parent); +} + +static void hsurface_destroy (GtsObject * object) +{ + GtsHSurface * hs = GTS_HSURFACE (object); + + gts_hsurface_traverse (hs, G_POST_ORDER, -1, + (GtsSplitTraverseFunc) gts_object_destroy, + NULL); + g_slist_free (hs->roots); + if (hs->expandable) + gts_eheap_destroy (hs->expandable); + if (hs->collapsable) + gts_eheap_destroy (hs->collapsable); + g_ptr_array_free (hs->split, TRUE); + + (* GTS_OBJECT_CLASS (gts_hsurface_class ())->parent_class->destroy) (object); +} + +static void hsurface_class_init (GtsObjectClass * klass) +{ + klass->destroy = hsurface_destroy; +} + +static void hsurface_init (GtsHSurface * hsurface) +{ + hsurface->s = NULL; + hsurface->roots = NULL; + hsurface->expandable = hsurface->collapsable = NULL; + hsurface->split = g_ptr_array_new (); + hsurface->nvertex = 0; +} + +/** + * gts_hsurface_class: + * + * Returns: the #GtsHSurfaceClass. + */ +GtsHSurfaceClass * gts_hsurface_class (void) +{ + static GtsHSurfaceClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo hsurface_info = { + "GtsHSurface", + sizeof (GtsHSurface), + sizeof (GtsHSurfaceClass), + (GtsObjectClassInitFunc) hsurface_class_init, + (GtsObjectInitFunc) hsurface_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (gts_object_class (), + &hsurface_info); + } + + return klass; +} + +/** + * gts_hsurface_new: + * @klass: a #GtsHSurfaceClass. + * @hsplit_class: a #GtsHSplitClass. + * @psurface: a #GtsPSurface. + * @expand_key: a #GtsKeyFunc used to order the priority heap of expandable + * #GtsHSplit. + * @expand_data: data to be passed to @expand_key. + * @collapse_key: a #GtsKeyFunc used to order the priority heap of collapsable + * #GtsHSplit. + * @collapse_data: data to be passed to @collapsed_key. + * + * Returns: a new #GtsHSurface, hierarchical extension of @psurface + * and using #GtsHSplit of class @hsplit_class. Note that @psurface is + * destroyed in the process. + */ +GtsHSurface * gts_hsurface_new (GtsHSurfaceClass * klass, + GtsHSplitClass * hsplit_class, + GtsPSurface * psurface, + GtsKeyFunc expand_key, + gpointer expand_data, + GtsKeyFunc collapse_key, + gpointer collapse_data) +{ + GtsHSurface * hsurface; + + g_return_val_if_fail (klass != NULL, NULL); + g_return_val_if_fail (hsplit_class != NULL, NULL); + g_return_val_if_fail (psurface != NULL, NULL); + g_return_val_if_fail (expand_key != NULL, NULL); + g_return_val_if_fail (collapse_key != NULL, NULL); + + hsurface = GTS_HSURFACE (gts_object_new (GTS_OBJECT_CLASS (klass))); + hsurface->s = psurface->s; + hsurface->expandable = gts_eheap_new (expand_key, expand_data); + hsurface->collapsable = gts_eheap_new (collapse_key, collapse_data); + g_ptr_array_set_size (hsurface->split, psurface->split->len); + + while (gts_psurface_remove_vertex (psurface)) + ; + while (psurface->pos) { + GtsSplit * vs = g_ptr_array_index (psurface->split, psurface->pos - 1); + GtsHSplit * hs = gts_hsplit_new (hsplit_class, vs); + + g_ptr_array_index (hsurface->split, psurface->pos - 1) = hs; + psurface->pos--; + + hs->parent = GTS_OBJECT (vs)->reserved; + if (hs->parent) { + GtsSplit * vsp = GTS_SPLIT (hs->parent); + + if (vsp->v1 == GTS_OBJECT (vs)) { + g_assert (vsp->v2 != GTS_OBJECT (vs)); + vsp->v1 = GTS_OBJECT (hs); + } + else { + g_assert (vsp->v2 == GTS_OBJECT (vs)); + vsp->v2 = GTS_OBJECT (hs); + } + } + else + hsurface->roots = g_slist_prepend (hsurface->roots, hs); + + hs->nchild = 0; + if (GTS_IS_SPLIT (vs->v1)) + GTS_OBJECT (vs->v1)->reserved = hs; + else + hs->nchild++; + if (GTS_IS_SPLIT (vs->v2)) + GTS_OBJECT (vs->v2)->reserved = hs; + else + hs->nchild++; + + gts_split_expand (vs, psurface->s, psurface->s->edge_class); + + if (hs->nchild == 2) + HEAP_INSERT_HSPLIT (hsurface->collapsable, hs); + } + + hsurface->nvertex = gts_surface_vertex_number (hsurface->s); + gts_object_destroy (GTS_OBJECT (psurface)); + + return hsurface; +} + +/** + * gts_hsurface_traverse: + * @hsurface: a #GtsHSurface. + * @order: the order in which nodes are visited - G_PRE_ORDER or G_POST_ORDER. + * @depth: the maximum depth of the traversal. Nodes below this depth + * will not be visited. If max_depth is -1 all nodes in the tree are + * visited. If depth is 1, only the root is visited. If depth is 2, + * the root and its children are visited. And so on. + * @func: the function to call for each visited #GtsHSplit. + * @data: user data to pass to the function. + * + * Traverses a hierarchical surface starting from its roots. It calls + * the given function for each #GtsHSplit visited. + * See also gts_split_traverse(). + */ +void gts_hsurface_traverse (GtsHSurface * hsurface, + GTraverseType order, + gint depth, + GtsSplitTraverseFunc func, + gpointer data) +{ + GSList * i; + + g_return_if_fail (hsurface != NULL); + g_return_if_fail (func != NULL); + g_return_if_fail (order < G_LEVEL_ORDER); + g_return_if_fail (depth == -1 || depth > 0); + + i = hsurface->roots; + while (i) { + gts_split_traverse (i->data, order, depth, func, data); + i = i->next; + } +} + +/** + * gts_hsurface_foreach: + * @hsurface: a #GtsHSurface. + * @order: the order in which #GtsHSplit are visited - G_PRE_ORDER or + * G_POST_ORDER. + * @func: the function to call for each visited #GtsHSplit. + * @data: user data to pass to the function. + * + * Starts by expanding all the #GtsHSplit of @hsurface. If @order is + * G_PRE_ORDER, calls @func for each #GtsHSplit and collapses it. If + * order is G_POST_ORDER, collapses each #GtsHSplit first and then + * calls @func. The traversal can be halted at any point by returning + * TRUE from func. + */ +void gts_hsurface_foreach (GtsHSurface * hsurface, + GTraverseType order, + GtsFunc func, + gpointer data) +{ + GtsHSplit * hs; + guint i = 0, len; + gboolean stop = FALSE; + + g_return_if_fail (hsurface != NULL); + g_return_if_fail (func != NULL); + g_return_if_fail (order == G_PRE_ORDER || order == G_POST_ORDER); + + while ((hs = gts_eheap_top (hsurface->expandable, NULL))) + gts_hsplit_expand (hs, hsurface); + + len = hsurface->split->len; + switch (order) { + case G_PRE_ORDER: + while (i < len && !stop) { + GtsHSplit * hs = g_ptr_array_index (hsurface->split, i); + stop = (*func) (hs, data); + if (!stop) + gts_hsplit_collapse (hs, hsurface); + i++; + } + break; + case G_POST_ORDER: + while (i < len && !stop) { + GtsHSplit * hs = g_ptr_array_index (hsurface->split, i); + gts_hsplit_collapse (hs, hsurface); + stop = (*func) (hs, data); + i++; + } + break; + default: + g_assert_not_reached (); + } +} + +/** + * gts_hsurface_height: + * @hsurface: a #GtsHSurface. + * + * Returns: the maximum height of the tree described by @hsurface. + */ +guint gts_hsurface_height (GtsHSurface * hsurface) +{ + GSList * i; + guint height = 0; + + g_return_val_if_fail (hsurface != NULL, 0); + + i = hsurface->roots; + while (i) { + guint tmp_height = gts_split_height (i->data); + if (tmp_height > height) + height = tmp_height; + i = i->next; + } + + return height; +} Index: work/obsolete/toporouter/src_3rd/gts/iso.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/iso.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/iso.c (revision 6803) @@ -0,0 +1,455 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gts.h" + +typedef enum { LEFT = 0, RIGHT = 1 } Orientation; + +typedef struct { + GtsVertex * v; + Orientation orientation; +} OrientedVertex; + +struct _GtsIsoSlice { + OrientedVertex *** vertices; + guint nx, ny; +}; + +/* coordinates of the edges of the cube (see doc/isocube.fig) */ +static guint c[12][4] = { + {0, 0, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 1}, {0, 0, 1, 0}, + {1, 0, 0, 0}, {1, 0, 0, 1}, {1, 1, 0, 1}, {1, 1, 0, 0}, + {2, 0, 0, 0}, {2, 1, 0, 0}, {2, 1, 1, 0}, {2, 0, 1, 0}}; + +/* first index is the edge number, second index is the edge orientation + (RIGHT or LEFT), third index are the edges which this edge may connect to + in order */ +static guint edge[12][2][3] = { + {{9, 1, 8}, {4, 3, 7}}, /* 0 */ + {{6, 2, 5}, {8, 0, 9}}, /* 1 */ + {{10, 3, 11}, {5, 1, 6}}, /* 2 */ + {{7, 0, 4}, {11, 2, 10}}, /* 3 */ + {{3, 7, 0}, {8, 5, 11}}, /* 4 */ + {{11, 4, 8}, {1, 6, 2}}, /* 5 */ + {{2, 5, 1}, {9, 7, 10}}, /* 6 */ + {{10, 6, 9}, {0, 4, 3}}, /* 7 */ + {{5, 11, 4}, {0, 9, 1}}, /* 8 */ + {{1, 8, 0}, {7, 10, 6}}, /* 9 */ + {{6, 9, 7}, {3, 11, 2}}, /* 10 */ + {{2, 10, 3}, {4, 8, 5}} /* 11 */ +}; + +static void ** malloc2D (guint nx, guint ny, gulong size) +{ + void ** m = g_malloc (nx*sizeof (void *)); + guint i; + + for (i = 0; i < nx; i++) + m[i] = g_malloc0 (ny*size); + + return m; +} + +static void free2D (void ** m, guint nx) +{ + guint i; + + g_return_if_fail (m != NULL); + + for (i = 0; i < nx; i++) + g_free (m[i]); + g_free (m); +} + +/** + * gts_grid_plane_new: + * @nx: + * @ny: + * + * Returns: + */ +GtsGridPlane * gts_grid_plane_new (guint nx, guint ny) +{ + GtsGridPlane * g = g_malloc (sizeof (GtsGridPlane)); + + g->p = (GtsPoint **) malloc2D (nx, ny, sizeof (GtsPoint)); + g->nx = nx; + g->ny = ny; + + return g; +} + +/** + * gts_grid_plane_destroy: + * @g: + * + */ +void gts_grid_plane_destroy (GtsGridPlane * g) +{ + g_return_if_fail (g != NULL); + + free2D ((void **) g->p, g->nx); + g_free (g); +} + +/** + * gts_iso_slice_new: + * @nx: number of vertices in the x direction. + * @ny: number of vertices in the y direction. + * + * Returns: a new #GtsIsoSlice. + */ +GtsIsoSlice * gts_iso_slice_new (guint nx, guint ny) +{ + GtsIsoSlice * slice; + + g_return_val_if_fail (nx > 1, NULL); + g_return_val_if_fail (ny > 1, NULL); + + slice = g_malloc (sizeof (GtsIsoSlice)); + + slice->vertices = g_malloc (3*sizeof (OrientedVertex **)); + slice->vertices[0] = + (OrientedVertex **) malloc2D (nx, ny, sizeof (OrientedVertex)); + slice->vertices[1] = + (OrientedVertex **) malloc2D (nx - 1, ny, sizeof (OrientedVertex)); + slice->vertices[2] = + (OrientedVertex **) malloc2D (nx, ny - 1, sizeof (OrientedVertex)); + slice->nx = nx; + slice->ny = ny; + + return slice; +} + +/** + * gts_iso_slice_fill: + * @slice: a #GtsIsoSlice. + * @plane1: a #GtsGridPlane. + * @plane2: another #GtsGridPlane. + * @f1: values of the function corresponding to @plane1. + * @f2: values of the function corresponding to @plane2. + * @iso: isosurface value. + * @klass: a #GtsVertexClass or one of its descendant to be used for the + * new vertices. + * + * Fill @slice with the coordinates of the vertices defined by + * f1 (x,y,z) = @iso and f2 (x, y, z) = @iso. + */ +void gts_iso_slice_fill (GtsIsoSlice * slice, + GtsGridPlane * plane1, + GtsGridPlane * plane2, + gdouble ** f1, + gdouble ** f2, + gdouble iso, + GtsVertexClass * klass) +{ + OrientedVertex *** vertices; + GtsPoint ** p1, ** p2 = NULL; + guint i, j, nx, ny; + + g_return_if_fail (slice != NULL); + g_return_if_fail (plane1 != NULL); + g_return_if_fail (f1 != NULL); + g_return_if_fail (f2 == NULL || plane2 != NULL); + + p1 = plane1->p; + if (plane2) + p2 = plane2->p; + vertices = slice->vertices; + nx = slice->nx; + ny = slice->ny; + + if (f2) + for (i = 0; i < nx; i++) + for (j = 0; j < ny; j++) { + gdouble v1 = f1[i][j] - iso; + gdouble v2 = f2[i][j] - iso; + if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) { + gdouble c2 = v1/(v1 - v2), c1 = 1. - c2; + vertices[0][i][j].v = + gts_vertex_new (klass, + c1*p1[i][j].x + c2*p2[i][j].x, + c1*p1[i][j].y + c2*p2[i][j].y, + c1*p1[i][j].z + c2*p2[i][j].z); + vertices[0][i][j].orientation = v2 >= 0. ? RIGHT : LEFT; + } + else + vertices[0][i][j].v = NULL; + } + for (i = 0; i < nx - 1; i++) + for (j = 0; j < ny; j++) { + gdouble v1 = f1[i][j] - iso; + gdouble v2 = f1[i+1][j] - iso; + if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) { + gdouble c2 = v1/(v1 - v2), c1 = 1. - c2; + vertices[1][i][j].v = + gts_vertex_new (klass, + c1*p1[i][j].x + c2*p1[i+1][j].x, + c1*p1[i][j].y + c2*p1[i+1][j].y, + c1*p1[i][j].z + c2*p1[i+1][j].z); + vertices[1][i][j].orientation = v2 >= 0. ? RIGHT : LEFT; + } + else + vertices[1][i][j].v = NULL; + } + for (i = 0; i < nx; i++) + for (j = 0; j < ny - 1; j++) { + gdouble v1 = f1[i][j] - iso; + gdouble v2 = f1[i][j+1] - iso; + if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) { + gdouble c2 = v1/(v1 - v2), c1 = 1. - c2; + vertices[2][i][j].v = + gts_vertex_new (klass, + c1*p1[i][j].x + c2*p1[i][j+1].x, + c1*p1[i][j].y + c2*p1[i][j+1].y, + c1*p1[i][j].z + c2*p1[i][j+1].z); + vertices[2][i][j].orientation = v2 >= 0. ? RIGHT : LEFT; + } + else + vertices[2][i][j].v = NULL; + } +} + +/** + * gts_iso_slice_fill_cartesian: + * @slice: a #GtsIsoSlice. + * @g: a #GtsCartesianGrid. + * @f1: values of the function for plane z = @g.z. + * @f2: values of the function for plane z = @g.z + @g.dz. + * @iso: isosurface value. + * @klass: a #GtsVertexClass. + * + * Fill @slice with the coordinates of the vertices defined by + * f1 (x,y,z) = @iso and f2 (x, y, z) = @iso. + */ +void gts_iso_slice_fill_cartesian (GtsIsoSlice * slice, + GtsCartesianGrid g, + gdouble ** f1, + gdouble ** f2, + gdouble iso, + GtsVertexClass * klass) +{ + OrientedVertex *** vertices; + guint i, j; + gdouble x, y; + + g_return_if_fail (slice != NULL); + g_return_if_fail (f1 != NULL); + + vertices = slice->vertices; + + if (f2) + for (i = 0, x = g.x; i < g.nx; i++, x += g.dx) + for (j = 0, y = g.y; j < g.ny; j++, y += g.dy) { + gdouble v1 = f1[i][j] - iso; + gdouble v2 = f2[i][j] - iso; + if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) { + vertices[0][i][j].v = + gts_vertex_new (klass, + x, y, g.z + g.dz*v1/(v1 - v2)); + vertices[0][i][j].orientation = v2 >= 0. ? RIGHT : LEFT; + } + else + vertices[0][i][j].v = NULL; + } + for (i = 0, x = g.x; i < g.nx - 1; i++, x += g.dx) + for (j = 0, y = g.y; j < g.ny; j++, y += g.dy) { + gdouble v1 = f1[i][j] - iso; + gdouble v2 = f1[i+1][j] - iso; + if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) { + vertices[1][i][j].v = + gts_vertex_new (klass, x + g.dx*v1/(v1 - v2), y, g.z); + vertices[1][i][j].orientation = v2 >= 0. ? RIGHT : LEFT; + } + else + vertices[1][i][j].v = NULL; + } + for (i = 0, x = g.x; i < g.nx; i++, x += g.dx) + for (j = 0, y = g.y; j < g.ny - 1; j++, y += g.dy) { + gdouble v1 = f1[i][j] - iso; + gdouble v2 = f1[i][j+1] - iso; + if ((v1 >= 0. && v2 < 0.) || (v1 < 0. && v2 >= 0.)) { + vertices[2][i][j].v = + gts_vertex_new (klass, x, y + g.dy*v1/(v1 - v2), g.z); + vertices[2][i][j].orientation = v2 >= 0. ? RIGHT : LEFT; + } + else + vertices[2][i][j].v = NULL; + } +} + +/** + * gts_iso_slice_destroy: + * @slice: a #GtsIsoSlice. + * + * Free all memory allocated for @slice. + */ +void gts_iso_slice_destroy (GtsIsoSlice * slice) +{ + g_return_if_fail (slice != NULL); + + free2D ((void **) slice->vertices[0], slice->nx); + free2D ((void **) slice->vertices[1], slice->nx - 1); + free2D ((void **) slice->vertices[2], slice->nx); + g_free (slice->vertices); + g_free (slice); +} + +/** + * gts_isosurface_slice: + * @slice1: a #GtsIsoSlice. + * @slice2: another #GtsIsoSlice. + * @surface: a #GtsSurface. + * + * Given two successive slices @slice1 and @slice2 link their vertices with + * segments and triangles which are added to @surface. + */ +void gts_isosurface_slice (GtsIsoSlice * slice1, + GtsIsoSlice * slice2, + GtsSurface * surface) +{ + guint j, k, l, nx, ny; + OrientedVertex *** vertices[2]; + GtsVertex * va[12]; + + g_return_if_fail (slice1 != NULL); + g_return_if_fail (slice2 != NULL); + g_return_if_fail (surface != NULL); + g_return_if_fail (slice1->nx == slice2->nx && slice1->ny == slice2->ny); + + vertices[0] = slice1->vertices; + vertices[1] = slice2->vertices; + nx = slice1->nx; + ny = slice1->ny; + + /* link vertices with segments and triangles */ + for (j = 0; j < nx - 1; j++) + for (k = 0; k < ny - 1; k++) { + gboolean cube_is_cut = FALSE; + for (l = 0; l < 12; l++) { + guint nv = 0, e = l; + OrientedVertex ov = + vertices[c[e][1]][c[e][0]][j + c[e][2]][k + c[e][3]]; + while (ov.v && !GTS_OBJECT (ov.v)->reserved) { + guint m = 0, * ne = edge[e][ov.orientation]; + va[nv++] = ov.v; + GTS_OBJECT (ov.v)->reserved = surface; + ov.v = NULL; + while (m < 3 && !ov.v) { + e = ne[m++]; + ov = vertices[c[e][1]][c[e][0]][j + c[e][2]][k + c[e][3]]; + } + } + /* create edges and faces */ + if (nv > 2) { + GtsEdge * e1, * e2, * e3; + guint m; + if (!(e1 = GTS_EDGE (gts_vertices_are_connected (va[0], va[1])))) + e1 = gts_edge_new (surface->edge_class, va[0], va[1]); + for (m = 1; m < nv - 1; m++) { + if (!(e2 = GTS_EDGE (gts_vertices_are_connected (va[m], va[m+1])))) + e2 = gts_edge_new (surface->edge_class, va[m], va[m+1]); + if (!(e3 = GTS_EDGE (gts_vertices_are_connected (va[m+1], va[0])))) + e3 = gts_edge_new (surface->edge_class, va[m+1], va[0]); + gts_surface_add_face (surface, + gts_face_new (surface->face_class, + e1, e2, e3)); + e1 = e3; + } + } + if (nv > 0) + cube_is_cut = TRUE; + } + if (cube_is_cut) + for (l = 0; l < 12; l++) { + GtsVertex * v = + vertices[c[l][1]][c[l][0]][j + c[l][2]][k + c[l][3]].v; + if (v) + GTS_OBJECT (v)->reserved = NULL; + } + } +} + +#define SWAP(s1, s2, tmp) (tmp = s1, s1 = s2, s2 = tmp) + +/** + * gts_isosurface_cartesian: + * @surface: a #GtsSurface. + * @g: a #GtsCartesianGrid. + * @f: a #GtsIsoCartesianFunc. + * @data: user data to be passed to @f. + * @iso: isosurface value. + * + * Adds to @surface new faces defining the isosurface f(x,y,z) = @iso. By + * convention, the normals to the surface are pointing toward the positive + * values of f(x,y,z) - @iso. + * + * The user function @f is called successively for each value of the z + * coordinate defined by @g. It must fill the corresponding (x,y) plane with + * the values of the function for which the isosurface is to be computed. + */ +void gts_isosurface_cartesian (GtsSurface * surface, + GtsCartesianGrid g, + GtsIsoCartesianFunc f, + gpointer data, + gdouble iso) +{ + void * tmp; + gdouble ** f1, ** f2; + GtsIsoSlice * slice1, * slice2; + guint i; + + g_return_if_fail (surface != NULL); + g_return_if_fail (f != NULL); + g_return_if_fail (g.nx > 1); + g_return_if_fail (g.ny > 1); + g_return_if_fail (g.nz > 1); + + slice1 = gts_iso_slice_new (g.nx, g.ny); + slice2 = gts_iso_slice_new (g.nx, g.ny); + f1 = (gdouble **) malloc2D (g.nx, g.ny, sizeof (gdouble)); + f2 = (gdouble **) malloc2D (g.nx, g.ny, sizeof (gdouble)); + + (*f) (f1, g, 0, data); + g.z += g.dz; + (*f) (f2, g, 1, data); + g.z -= g.dz; + gts_iso_slice_fill_cartesian (slice1, g, f1, f2, iso, + surface->vertex_class); + g.z += g.dz; + for (i = 2; i < g.nz; i++) { + g.z += g.dz; + (*f) (f1, g, i, data); + SWAP (f1, f2, tmp); + g.z -= g.dz; + gts_iso_slice_fill_cartesian (slice2, g, f1, f2, iso, + surface->vertex_class); + g.z += g.dz; + gts_isosurface_slice (slice1, slice2, surface); + SWAP (slice1, slice2, tmp); + } + gts_iso_slice_fill_cartesian (slice2, g, f2, NULL, iso, + surface->vertex_class); + gts_isosurface_slice (slice1, slice2, surface); + + gts_iso_slice_destroy (slice1); + gts_iso_slice_destroy (slice2); + free2D ((void **) f1, g.nx); + free2D ((void **) f2, g.nx); +} Index: work/obsolete/toporouter/src_3rd/gts/isotetra.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/isotetra.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/isotetra.c (revision 6803) @@ -0,0 +1,840 @@ +/* GTS-Library conform marching tetrahedra algorithm + * Copyright (C) 2002 Gert Wollny + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#ifdef NATIVE_WIN32 +# include +# define M_SQRT2 1.41421356237309504880 +#endif /* NATIVE_WIN32 */ + +typedef struct { + gint nx, ny; + gdouble ** data; +} slice_t; + +typedef struct { + gint x, y, z; + gboolean mid; + gdouble d; +} tetra_vertex_t; + +/* this helper is a lookup table for vertices */ +typedef struct { + gint nx, ny; + GtsVertex ** vtop, ** vmid, **vbot; +} helper_t ; + +typedef struct { + GHashTable * vbot, * vtop; +} helper_bcl ; + + +static helper_t * init_helper (int nx, int ny) +{ + gint nxy = 4*nx*ny; + helper_t *retval = g_malloc0 (sizeof (helper_t)); + + retval->nx = nx; + retval->ny = ny; + retval->vtop = g_malloc0 (sizeof (GtsVertex *)*nxy); + retval->vmid = g_malloc0 (sizeof (GtsVertex *)*nxy); + retval->vbot = g_malloc0 (sizeof (GtsVertex *)*nxy); + return retval; +} + +static helper_bcl * init_helper_bcl (void) +{ + helper_bcl *retval = g_malloc0 (sizeof (helper_bcl)); + + retval->vtop = g_hash_table_new (g_str_hash, g_str_equal); + retval->vbot = g_hash_table_new (g_str_hash, g_str_equal); + return retval; +} + +static void free_helper (helper_t * h) +{ + g_free (h->vtop); + g_free (h->vmid); + g_free (h->vbot); + g_free (h); +} + +static void free_helper_bcl (helper_bcl * h) +{ + g_hash_table_destroy (h->vtop); + g_hash_table_destroy (h->vbot); + g_free (h); +} + +/* move the vertices in the bottom slice to the top, and clear the + other slices in the lookup tables */ +static void helper_advance (helper_t * h) +{ + GtsVertex ** help = h->vbot; + h->vbot = h->vtop; + h->vtop = help; + + memset (h->vmid, 0, 4*sizeof(GtsVertex *) * h->nx * h->ny); + memset (h->vbot, 0, 4*sizeof(GtsVertex *) * h->nx * h->ny); +} + +static void helper_advance_bcl (helper_bcl * h) +{ + GHashTable * help = g_hash_table_new (g_str_hash, g_str_equal); + + g_hash_table_destroy (h->vbot); + h->vbot = h->vtop; + h->vtop = help; +} + +/* find the zero-crossing of line through v1 and v2 and return the + corresponding GtsVertex */ +static GtsVertex * get_vertex (gint mz, + const tetra_vertex_t * v1, + const tetra_vertex_t * v2, + helper_t * help, + GtsCartesianGrid * g, + GtsVertexClass * klass) +{ + GtsVertex ** vertex; + gint x, y, index, idx2, z; + gdouble dx, dy, dz, d; + + g_assert (v1->d - v2->d != 0.); + + dx = dy = dz = 0.0; + d = v1->d/(v1->d - v2->d); + + index = 0; + + if (v1->x != v2->x) { + index |= 1; + dx = d; + } + + if (v1->y != v2->y) { + index |= 2; + dy = d; + } + + if (v1->z != v2->z) { + dz = d; + } + + x = v1->x; + if (v1->x > v2->x) { x = v2->x; dx = 1.0 - dx; } + + y = v1->y; + if (v1->y > v2->y) { y = v2->y; dy = 1.0 - dy;} + + z = v1->z; + if (v1->z > v2->z) { z = v2->z; dz = 1.0 - dz;} + + idx2 = 4 * ( x + y * help->nx ) + index; + + if (v1->z == v2->z) + vertex = (mz == z) ? &help->vtop[idx2] : &help->vbot[idx2]; + else + vertex = &help->vmid[idx2]; + + if (mz != z && dz != 0.0) { + fprintf(stderr, "%f \n", dz); + } + + /* if vertex is not yet created, do it now */ + if (!*vertex) + *vertex = gts_vertex_new (klass, + g->dx * ( x + dx) + g->x, + g->dy * ( y + dy) + g->y, + g->dz * ( z + dz) + g->z); + + return *vertex; +} + +static GtsVertex * get_vertex_bcl (gint mz, + const tetra_vertex_t * v1, + const tetra_vertex_t * v2, + helper_bcl * help, + GtsCartesianGrid * g, + GtsVertexClass * klass) +{ + GtsVertex * v; + GHashTable * table; + gchar * s1, * s2, * hash; + gdouble x1, x2, y1, y2, z1, z2, d; + + g_assert (v1->d - v2->d != 0.); + + /* first find correct hash table */ + if ((v1->z > mz) && (v2->z > mz)) + table = help->vtop; + else + table = help->vbot; + + d = v1->d / (v1->d - v2->d); + + /* sort vertices */ + s1 = g_strdup_printf ("%d %d %d %d", v1->x, v1->y, v1->z, v1->mid); + s2 = g_strdup_printf ("%d %d %d %d", v2->x, v2->y, v2->z, v2->mid); + + hash = (d == 0.0) ? g_strdup (s1) : + (d == 1.0) ? g_strdup (s2) : + (strcmp (s1, s2) < 0) ? g_strjoin (" ", s1, s2, NULL) : + g_strjoin (" ", s2, s1, NULL); + + /* return existing vertex or make a new one */ + v = g_hash_table_lookup (table, hash); + if (!v){ + + x1 = g->dx * (v1->x + (v1->mid / 2.0)) + g->x; + x2 = g->dx * (v2->x + (v2->mid / 2.0)) + g->x; + y1 = g->dy * (v1->y + (v1->mid / 2.0)) + g->y; + y2 = g->dy * (v2->y + (v2->mid / 2.0)) + g->y; + z1 = g->dz * (v1->z + (v1->mid / 2.0)) + g->z; + z2 = g->dz * (v2->z + (v2->mid / 2.0)) + g->z; + + v = gts_vertex_new (klass, x1 * (1.0 - d) + d * x2, + y1 * (1.0 - d) + d * y2, + z1 * (1.0 - d) + d * z2); + + g_hash_table_insert (table, g_strdup(hash), v); + } + g_free (s1); + g_free (s2); + g_free (hash); + + return v; +} + +/* create an edge connecting the zero crossings of lines through a + pair of vertices, or return an existing one */ +static GtsEdge * get_edge (GtsVertex * v1, GtsVertex * v2, + GtsEdgeClass * klass) +{ + GtsSegment *s; + GtsEdge *edge; + + g_assert (v1); + g_assert (v2); + + s = gts_vertices_are_connected (v1, v2); + + if (GTS_IS_EDGE (s)) + edge = GTS_EDGE(s); + else + edge = gts_edge_new (klass, v1, v2); + return edge; +} + +static void add_face (GtsSurface * surface, + const tetra_vertex_t * a1, const tetra_vertex_t * a2, + const tetra_vertex_t * b1, const tetra_vertex_t * b2, + const tetra_vertex_t * c1, const tetra_vertex_t * c2, + gint rev, helper_t * help, + gint z, GtsCartesianGrid * g) +{ + GtsFace * t; + GtsEdge * e1, * e2, * e3; + GtsVertex * v1 = get_vertex (z, a1, a2, help, g, surface->vertex_class); + GtsVertex * v2 = get_vertex (z, b1, b2, help, g, surface->vertex_class); + GtsVertex * v3 = get_vertex (z, c1, c2, help, g, surface->vertex_class); + + g_assert (v1 != v2); + g_assert (v2 != v3); + g_assert (v1 != v3); + + if (!rev) { + e1 = get_edge (v1, v2, surface->edge_class); + e2 = get_edge (v2, v3, surface->edge_class); + e3 = get_edge (v1, v3, surface->edge_class); + } else { + e1 = get_edge (v1, v3, surface->edge_class); + e2 = get_edge (v2, v3, surface->edge_class); + e3 = get_edge (v1, v2, surface->edge_class); + } + + t = gts_face_new (surface->face_class, e1, e2, e3); + gts_surface_add_face (surface, t); +} + +static void add_face_bcl (GtsSurface * surface, + const tetra_vertex_t * a1, + const tetra_vertex_t * a2, + const tetra_vertex_t * b1, + const tetra_vertex_t * b2, + const tetra_vertex_t * c1, + const tetra_vertex_t * c2, + gint rev, helper_bcl * help, + gint z, GtsCartesianGrid * g) +{ + GtsFace * t; + GtsEdge * e1, * e2, * e3; + GtsVertex * v1 = get_vertex_bcl (z, a1, a2, help, g, surface->vertex_class); + GtsVertex * v2 = get_vertex_bcl (z, b1, b2, help, g, surface->vertex_class); + GtsVertex * v3 = get_vertex_bcl (z, c1, c2, help, g, surface->vertex_class); + + if (v1 == v2 || v2 == v3 || v1 == v3) + return; + + if (!rev) { + e1 = get_edge (v1, v2, surface->edge_class); + e2 = get_edge (v2, v3, surface->edge_class); + e3 = get_edge (v1, v3, surface->edge_class); + } else { + e1 = get_edge (v1, v3, surface->edge_class); + e2 = get_edge (v2, v3, surface->edge_class); + e3 = get_edge (v1, v2, surface->edge_class); + } + + t = gts_face_new (surface->face_class, e1, e2, e3); + gts_surface_add_face (surface, t); +} + +/* create a new slice of site nx \times ny */ +static slice_t * new_slice (gint nx, gint ny) +{ + gint x; + slice_t * retval = g_malloc (sizeof (slice_t)); + + retval->data = g_malloc (nx*sizeof(gdouble *)); + retval->nx = nx; + retval->ny = ny; + for (x = 0; x < nx; x++) + retval->data[x] = g_malloc (ny*sizeof (gdouble)); + return retval; +} + +/* initialize a slice with inival */ +static void slice_init (slice_t * slice, gdouble inival) +{ + gint x, y; + + g_assert (slice); + + for (x = 0; x < slice->nx; x++) + for (y = 0; y < slice->ny; y++) + slice->data[x][y] = inival; +} + +/* free the memory of a slice */ +static void free_slice (slice_t * slice) +{ + gint x; + + g_return_if_fail (slice != NULL); + + for (x = 0; x < slice->nx; x++) + g_free (slice->data[x]); + g_free (slice->data); + g_free (slice); +} + +static void analyze_tetrahedra (const tetra_vertex_t * a, + const tetra_vertex_t * b, + const tetra_vertex_t * c, + const tetra_vertex_t * d, + gint parity, GtsSurface * surface, + helper_t * help, + gint z, GtsCartesianGrid * g) +{ + gint rev = parity; + gint code = 0; + + if (a->d >= 0.) code |= 1; + if (b->d >= 0.) code |= 2; + if (c->d >= 0.) code |= 4; + if (d->d >= 0.) code |= 8; + + switch (code) { + case 15: + case 0: return; /* all inside or outside */ + + case 14:rev = !parity; + case 1:add_face (surface, a, b, a, d, a, c, rev, help, z, g); + break; + case 13:rev = ! parity; + case 2:add_face (surface, a, b, b, c, b, d, rev, help, z, g); + break; + case 12:rev = !parity; + case 3:add_face (surface, a, d, a, c, b, c, rev, help, z, g); + add_face (surface, a, d, b, c, b, d, rev, help, z, g); + break; + case 11:rev = !parity; + case 4:add_face (surface, a, c, c, d, b, c, rev, help, z, g); + break; + case 10:rev = !parity; + case 5: add_face (surface, a, b, a, d, c, d, rev, help, z, g); + add_face (surface, a, b, c, d, b, c, rev, help, z, g); + break; + case 9:rev = !parity; + case 6:add_face (surface, a, b, a, c, c, d, rev, help, z, g); + add_face (surface, a, b, c, d, b, d, rev, help, z, g); + break; + case 7:rev = !parity; + case 8:add_face (surface, a, d, b, d, c, d, rev, help, z, g); + break; + } +} + +static void analyze_tetrahedra_bcl (const tetra_vertex_t * a, + const tetra_vertex_t * b, + const tetra_vertex_t * c, + const tetra_vertex_t * d, + GtsSurface * surface, + helper_bcl * help, + gint z, GtsCartesianGrid * g) +{ + gint rev = 0; + gint code = 0; + + if (a->d >= 0.) code |= 1; + if (b->d >= 0.) code |= 2; + if (c->d >= 0.) code |= 4; + if (d->d >= 0.) code |= 8; + + switch (code) { + case 15: + case 0: return; /* all inside or outside */ + + case 14:rev = !rev; + case 1:add_face_bcl (surface, a, b, a, d, a, c, rev, help, z, g); + break; + case 13:rev = !rev; + case 2:add_face_bcl (surface, a, b, b, c, b, d, rev, help, z, g); + break; + case 12:rev = !rev; + case 3:add_face_bcl (surface, a, d, a, c, b, c, rev, help, z, g); + add_face_bcl (surface, a, d, b, c, b, d, rev, help, z, g); + break; + case 11:rev = !rev; + case 4:add_face_bcl (surface, a, c, c, d, b, c, rev, help, z, g); + break; + case 10:rev = !rev; + case 5: add_face_bcl (surface, a, b, a, d, c, d, rev, help, z, g); + add_face_bcl (surface, a, b, c, d, b, c, rev, help, z, g); + break; + case 9:rev = !rev; + case 6:add_face_bcl (surface, a, b, a, c, c, d, rev, help, z, g); + add_face_bcl (surface, a, b, c, d, b, d, rev, help, z, g); + break; + case 7:rev = !rev; + case 8:add_face_bcl (surface, a, d, b, d, c, d, rev, help, z, g); + break; + } +} + +static void iso_slice_evaluate (slice_t * s1, slice_t * s2, + GtsCartesianGrid g, + gint z, GtsSurface * surface, helper_t * help) +{ + gint x,y; + tetra_vertex_t v0, v1, v2, v3, v4, v5, v6, v7; + gdouble ** s1p = s1->data; + gdouble ** s2p = s2->data; + + for (y = 0; y < g.ny-1; y++) + for (x = 0; x < g.nx-1; x++) { + gint parity = (((x ^ y) ^ z) & 1); + + v0.x = x ; v0.y = y ; v0.z = z ; v0.mid = FALSE; v0.d = s1p[x ][y ]; + v1.x = x ; v1.y = y+1; v1.z = z ; v1.mid = FALSE; v1.d = s1p[x ][y+1]; + v2.x = x+1; v2.y = y ; v2.z = z ; v2.mid = FALSE; v2.d = s1p[x+1][y ]; + v3.x = x+1; v3.y = y+1; v3.z = z ; v3.mid = FALSE; v3.d = s1p[x+1][y+1]; + v4.x = x ; v4.y = y ; v4.z = z+1; v4.mid = FALSE; v4.d = s2p[x ][y ]; + v5.x = x ; v5.y = y+1; v5.z = z+1; v5.mid = FALSE; v5.d = s2p[x ][y+1]; + v6.x = x+1; v6.y = y ; v6.z = z+1; v6.mid = FALSE; v6.d = s2p[x+1][y ]; + v7.x = x+1; v7.y = y+1; v7.z = z+1; v7.mid = FALSE; v7.d = s2p[x+1][y+1]; + + if (parity == 0) { + analyze_tetrahedra (&v0, &v1, &v2, &v4, parity, surface, help, z, &g); + analyze_tetrahedra (&v7, &v1, &v4, &v2, parity, surface, help, z, &g); + analyze_tetrahedra (&v1, &v7, &v3, &v2, parity, surface, help, z, &g); + analyze_tetrahedra (&v1, &v7, &v4, &v5, parity, surface, help, z, &g); + analyze_tetrahedra (&v2, &v6, &v4, &v7, parity, surface, help, z, &g); + }else{ + analyze_tetrahedra (&v4, &v5, &v6, &v0, parity, surface, help, z, &g); + analyze_tetrahedra (&v3, &v5, &v0, &v6, parity, surface, help, z, &g); + analyze_tetrahedra (&v5, &v3, &v7, &v6, parity, surface, help, z, &g); + analyze_tetrahedra (&v5, &v3, &v0, &v1, parity, surface, help, z, &g); + analyze_tetrahedra (&v6, &v2, &v0, &v3, parity, surface, help, z, &g); + } + } +} + +static void iso_slice_evaluate_bcl (slice_t * s1, slice_t * s2, slice_t * s3, + GtsCartesianGrid g, + gint z, GtsSurface * surface, + helper_bcl * help) +{ + gint x,y; + tetra_vertex_t v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, w0; + gdouble ** s1p = s1->data; + gdouble ** s2p = s2->data; + gdouble ** s3p = s3->data; + + for (y = 0; y < g.ny-2; y++) + for (x = 0; x < g.nx-2; x++) { + v0.x = x ; v0.y = y ; v0.z = z ; v0.mid = TRUE; + v0.d = (s1p[x ][y ] + s2p[x ][y ] + + s1p[x ][y+1] + s2p[x ][y+1] + + s1p[x+1][y ] + s2p[x+1][y ] + + s1p[x+1][y+1] + s2p[x+1][y+1])/8.0; + + v1.x = x+1; v1.y = y ; v1.z = z ; v1.mid = TRUE; + v1.d = (s1p[x+1][y ] + s2p[x+1][y ] + + s1p[x+1][y+1] + s2p[x+1][y+1] + + s1p[x+2][y ] + s2p[x+2][y ] + + s1p[x+2][y+1] + s2p[x+2][y+1])/8.0; + + v2.x = x ; v2.y = y+1; v2.z = z ; v2.mid = TRUE; + v2.d = (s1p[x ][y+1] + s2p[x ][y+1] + + s1p[x ][y+2] + s2p[x ][y+2] + + s1p[x+1][y+1] + s2p[x+1][y+1] + + s1p[x+1][y+2] + s2p[x+1][y+2])/8.0; + + v3.x = x ; v3.y = y ; v3.z = z+1; v3.mid = TRUE; + v3.d = (s2p[x ][y ] + s3p[x ][y ] + + s2p[x ][y+1] + s3p[x ][y+1] + + s2p[x+1][y ] + s3p[x+1][y ] + + s2p[x+1][y+1] + s3p[x+1][y+1])/8.0; + + v4.x = x+1; v4.y = y ; v4.z = z ; v4.mid = FALSE; v4.d = s1p[x+1][y ]; + v5.x = x ; v5.y = y+1; v5.z = z ; v5.mid = FALSE; v5.d = s1p[x ][y+1]; + v6.x = x+1; v6.y = y+1; v6.z = z ; v6.mid = FALSE; v6.d = s1p[x+1][y+1]; + v7.x = x+1; v7.y = y ; v7.z = z+1; v7.mid = FALSE; v7.d = s2p[x+1][y ]; + v8.x = x ; v8.y = y+1; v8.z = z+1; v8.mid = FALSE; v8.d = s2p[x ][y+1]; + v9.x = x+1; v9.y = y+1; v9.z = z+1; v9.mid = FALSE; v9.d = s2p[x+1][y+1]; + w0.x = x ; w0.y = y ; w0.z = z+1; w0.mid = FALSE; w0.d = s2p[x ][y ]; + + analyze_tetrahedra_bcl (&v0, &v9, &v6, &v1, surface, help, z, &g); + analyze_tetrahedra_bcl (&v0, &v6, &v4, &v1, surface, help, z, &g); + analyze_tetrahedra_bcl (&v0, &v4, &v7, &v1, surface, help, z, &g); + analyze_tetrahedra_bcl (&v0, &v7, &v9, &v1, surface, help, z, &g); + analyze_tetrahedra_bcl (&v0, &v5, &v6, &v2, surface, help, z, &g); + analyze_tetrahedra_bcl (&v0, &v6, &v9, &v2, surface, help, z, &g); + analyze_tetrahedra_bcl (&v0, &v9, &v8, &v2, surface, help, z, &g); + analyze_tetrahedra_bcl (&v0, &v8, &v5, &v2, surface, help, z, &g); + analyze_tetrahedra_bcl (&v0, &v8, &v9, &v3, surface, help, z, &g); + analyze_tetrahedra_bcl (&v0, &v9, &v7, &v3, surface, help, z, &g); + analyze_tetrahedra_bcl (&v0, &v7, &w0, &v3, surface, help, z, &g); + analyze_tetrahedra_bcl (&v0, &w0, &v8, &v3, surface, help, z, &g); + } +} + +/* copy src into dest by stripping off the iso value and leave out + the boundary (which should be G_MINDOUBLE) */ +static void copy_to_bounded (slice_t * dest, slice_t * src, + gdouble iso, gdouble fill) +{ + gint x,y; + gdouble * src_ptr; + gdouble * dest_ptr = dest->data[0]; + + g_assert(dest->ny == src->ny + 2); + g_assert(dest->nx == src->nx + 2); + + for (y = 0; y < dest->ny; ++y, ++dest_ptr) + *dest_ptr = fill; + + for (x = 1; x < src->nx - 1; ++x) { + dest_ptr = dest->data[x]; + src_ptr = src->data[x-1]; + *dest_ptr++ = fill; + for (y = 0; y < src->ny; ++y, ++dest_ptr, ++src_ptr) + *dest_ptr = *src_ptr - iso; + *dest_ptr++ = fill; + } + + dest_ptr = dest->data[y]; + + for (y = 0; y < dest->ny; ++y, ++dest_ptr) + *dest_ptr = fill; +} + +static void iso_sub (slice_t * s, gdouble iso) +{ + gint x,y; + + for (x = 0; x < s->nx; ++x) { + gdouble *ptr = s->data[x]; + + for (y = 0; y < s->ny; ++y, ++ptr) + *ptr -= iso; + } +} + + +/** + * gts_isosurface_tetra_bounded: + * @surface: a #GtsSurface. + * @g: a #GtsCartesianGrid. + * @f: a #GtsIsoCartesianFunc. + * @data: user data to be passed to @f. + * @iso: isosurface value. + * + * Adds to @surface new faces defining the isosurface f(x,y,z) = + * @iso. By convention, the normals to the surface are pointing toward + * the positive values of f(x,y,z) - @iso. To ensure a closed object, + * a boundary of G_MINDOUBLE is added around the domain + * + * The user function @f is called successively for each value of the z + * coordinate defined by @g. It must fill the corresponding (x,y) + * plane with the values of the function for which the isosurface is + * to be computed. + */ +void gts_isosurface_tetra_bounded (GtsSurface * surface, + GtsCartesianGrid g, + GtsIsoCartesianFunc f, + gpointer data, + gdouble iso) +{ + slice_t *slice1, *slice2, *transfer_slice; + GtsCartesianGrid g_intern = g; + helper_t *helper; + gint z; + + g_return_if_fail (surface != NULL); + g_return_if_fail (f != NULL); + g_return_if_fail (g.nx > 1); + g_return_if_fail (g.ny > 1); + g_return_if_fail (g.nz > 1); + + /* create the helper slices */ + slice1 = new_slice (g.nx + 2, g.ny + 2); + slice2 = new_slice (g.nx + 2, g.ny + 2); + + /* initialize the first slice as OUTSIDE */ + slice_init (slice1, -1.0); + + /* create a slice of the original image size */ + transfer_slice = new_slice (g.nx, g.ny); + + /* adapt the parameters to our enlarged image */ + g_intern.x -= g.dx; + g_intern.y -= g.dy; + g_intern.z -= g.dz; + g_intern.nx = g.nx + 2; + g_intern.ny = g.ny + 2; + g_intern.nz = g.nz; + + /* create the helper for vertex-lookup */ + helper = init_helper (g_intern.nx, g_intern.ny); + + /* go slicewise through the data */ + z = 0; + while (z < g.nz) { + slice_t * hs; + + /* request slice */ + f (transfer_slice->data, g, z, data); + g.z += g.dz; + + /* copy slice in enlarged image and mark the border as OUTSIDE */ + copy_to_bounded (slice2, transfer_slice, iso, -1.); + + /* triangulate */ + iso_slice_evaluate (slice1, slice2, g_intern, z, surface, helper); + + /* switch the input slices */ + hs = slice1; slice1 = slice2; slice2 = hs; + + /* switch the vertex lookup tables */ + helper_advance(helper); + ++z; + } + + /* initialize the last slice as OUTSIDE */ + slice_init (slice2, - 1.0); + + /* close the object */ + iso_slice_evaluate(slice1, slice2, g_intern, z, surface, helper); + + free_helper (helper); + free_slice (slice1); + free_slice (slice2); + free_slice (transfer_slice); +} + +/** + * gts_isosurface_tetra: + * @surface: a #GtsSurface. + * @g: a #GtsCartesianGrid. + * @f: a #GtsIsoCartesianFunc. + * @data: user data to be passed to @f. + * @iso: isosurface value. + * + * Adds to @surface new faces defining the isosurface f(x,y,z) = + * @iso. By convention, the normals to the surface are pointing toward + * the positive values of f(x,y,z) - @iso. + * + * The user function @f is called successively for each value of the z + * coordinate defined by @g. It must fill the corresponding (x,y) + * plane with the values of the function for which the isosurface is + * to be computed. + */ +void gts_isosurface_tetra (GtsSurface * surface, + GtsCartesianGrid g, + GtsIsoCartesianFunc f, + gpointer data, + gdouble iso) +{ + slice_t *slice1, *slice2; + helper_t *helper; + gint z; + GtsCartesianGrid g_internal; + + g_return_if_fail (surface != NULL); + g_return_if_fail (f != NULL); + g_return_if_fail (g.nx > 1); + g_return_if_fail (g.ny > 1); + g_return_if_fail (g.nz > 1); + + memcpy (&g_internal, &g, sizeof (GtsCartesianGrid)); + + /* create the helper slices */ + slice1 = new_slice (g.nx, g.ny); + slice2 = new_slice (g.nx, g.ny); + + /* create the helper for vertex-lookup */ + helper = init_helper (g.nx, g.ny); + + z = 0; + f (slice1->data, g, z, data); + iso_sub (slice1, iso); + + z++; + g.z += g.dz; + + /* go slicewise through the data */ + while (z < g.nz) { + slice_t * hs; + + /* request slice */ + f (slice2->data, g, z, data); + iso_sub (slice2, iso); + + g.z += g.dz; + + /* triangulate */ + iso_slice_evaluate (slice1, slice2, g_internal, z-1, surface, helper); + + /* switch the input slices */ + hs = slice1; slice1 = slice2; slice2 = hs; + + /* switch the vertex lookup tables */ + helper_advance (helper); + + ++z; + } + + free_helper(helper); + free_slice(slice1); + free_slice(slice2); +} + +/** + * gts_isosurface_tetra_bcl: + * @surface: a #GtsSurface. + * @g: a #GtsCartesianGrid. + * @f: a #GtsIsoCartesianFunc. + * @data: user data to be passed to @f. + * @iso: isosurface value. + * + * Adds to @surface new faces defining the isosurface f(x,y,z) = + * @iso. By convention, the normals to the surface are pointing toward + * the positive values of f(x,y,z) - @iso. + * + * The user function @f is called successively for each value of the z + * coordinate defined by @g. It must fill the corresponding (x,y) + * plane with the values of the function for which the isosurface is + * to be computed. + * + * This version produces the dual "body-centered" faces relative to + * the faces produced by gts_isosurface_tetra(). + */ +void gts_isosurface_tetra_bcl (GtsSurface * surface, + GtsCartesianGrid g, + GtsIsoCartesianFunc f, + gpointer data, + gdouble iso) +{ + slice_t *slice1, *slice2, *slice3; + helper_bcl *helper; + gint z; + GtsCartesianGrid g_internal; + + g_return_if_fail (surface != NULL); + g_return_if_fail (f != NULL); + g_return_if_fail (g.nx > 1); + g_return_if_fail (g.ny > 1); + g_return_if_fail (g.nz > 1); + + memcpy (&g_internal, &g, sizeof (GtsCartesianGrid)); + + /* create the helper slices */ + slice1 = new_slice (g.nx, g.ny); + slice2 = new_slice (g.nx, g.ny); + slice3 = new_slice (g.nx, g.ny); + + /* create the helper for vertex-lookup */ + helper = init_helper_bcl (); + + z = 0; + f (slice1->data, g, z, data); + iso_sub (slice1, iso); + + z++; + g.z += g.dz; + + f (slice2->data, g, z, data); + iso_sub (slice1, iso); + + z++; + g.z += g.dz; + + /* go slicewise through the data */ + while (z < g.nz) { + slice_t * hs; + + /* request slice */ + f (slice3->data, g, z, data); + iso_sub (slice3, iso); + + g.z += g.dz; + + /* triangulate */ + iso_slice_evaluate_bcl (slice1, slice2, slice3, g_internal, z-2, + surface, helper); + + /* switch the input slices */ + hs = slice1; slice1 = slice2; slice2 = slice3; slice3 = hs; + + /* switch the vertex lookup tables */ + helper_advance_bcl (helper); + + ++z; + } + + free_helper_bcl(helper); + free_slice(slice1); + free_slice(slice2); + free_slice(slice3); +} Index: work/obsolete/toporouter/src_3rd/gts/kdtree.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/kdtree.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/kdtree.c (revision 6803) @@ -0,0 +1,152 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "gts.h" + + +static int compare_x (const void * p1, const void * p2) { + GtsPoint + * pp1 = *((gpointer *) p1), + * pp2 = *((gpointer *) p2); + if (pp1->x > pp2->x) + return 1; + return -1; +} + +static int compare_y (const void * p1, const void * p2) { + GtsPoint + * pp1 = *((gpointer *) p1), + * pp2 = *((gpointer *) p2); + if (pp1->y > pp2->y) + return 1; + return -1; +} + +static int compare_z (const void * p1, const void * p2) { + GtsPoint + * pp1 = *((gpointer *) p1), + * pp2 = *((gpointer *) p2); + if (pp1->z > pp2->z) + return 1; + return -1; +} + +/** + * gts_kdtree_new: + * @points: an array of #GtsPoint. + * @compare: always %NULL. + * + * Note that the order of the points in array @points is modified by this + * function. + * + * Returns: a new 3D tree for @points. + */ +GNode * gts_kdtree_new (GPtrArray * points, + int (*compare) (const void *, const void *)) +{ + guint middle; + GPtrArray array; + GNode * node; + GtsPoint * point; + + g_return_val_if_fail (points != NULL, NULL); + g_return_val_if_fail (points->len > 0, NULL); + + /* sort the points */ + if (compare == compare_x) compare = compare_y; + else if (compare == compare_y) compare = compare_z; + else compare = compare_x; + qsort (points->pdata, points->len, sizeof (gpointer), compare); + + middle = (points->len - 1)/2; + point = points->pdata[middle]; + node = g_node_new (point); + + if (points->len > 1) { + array.len = middle; + if (array.len > 0) { + array.pdata = points->pdata; + g_node_prepend (node, gts_kdtree_new (&array, compare)); + } + else + g_node_prepend (node, g_node_new (NULL)); + + array.len = points->len - middle - 1; + if (array.len > 0) { + array.pdata = &(points->pdata[middle + 1]); + g_node_prepend (node, gts_kdtree_new (&array, compare)); + } + else + g_node_prepend (node, g_node_new (NULL)); + } + + return node; +} + +/** + * gts_kdtree_range: + * @tree: a 3D tree. + * @bbox: a #GtsBBox. + * @compare: always %NULL. + * + * Returns: a list of #GtsPoint belonging to @tree which are inside @bbox. + */ +GSList * gts_kdtree_range (GNode * tree_3d, + GtsBBox * bbox, + int (*compare) (const void *, const void *)) +{ + GSList * list = NULL; + GtsPoint * p; + gdouble left, right, v; + GNode * node; + + g_return_val_if_fail (tree_3d != NULL, NULL); + g_return_val_if_fail (bbox != NULL, NULL); + + p = tree_3d->data; + if (p == NULL) + return NULL; + + if (gts_bbox_point_is_inside (bbox, p)) + list = g_slist_prepend (list, p); + + if (compare == compare_x) { + left = bbox->y1; right = bbox->y2; v = p->y; + compare = compare_y; + } + else if (compare == compare_y) { + left = bbox->z1; right = bbox->z2; v = p->z; + compare = compare_z; + } + else { + left = bbox->x1; right = bbox->x2; v = p->x; + compare = compare_x; + } + + if ((node = tree_3d->children)) { + if (right >= v) + list = g_slist_concat (list, gts_kdtree_range (node, bbox, compare)); + node = node->next; + if (left <= v) + list = g_slist_concat (list, gts_kdtree_range (node, bbox, compare)); + } + return list; +} + Index: work/obsolete/toporouter/src_3rd/gts/matrix.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/matrix.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/matrix.c (revision 6803) @@ -0,0 +1,725 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "gts.h" + +/** + * gts_matrix_new: + * @a00: element [0][0]. + * @a01: element [0][1]. + * @a02: element [0][2]. + * @a03: element [0][3]. + * @a10: element [1][0]. + * @a11: element [1][1]. + * @a12: element [1][2]. + * @a13: element [1][3]. + * @a20: element [2][0]. + * @a21: element [2][1]. + * @a22: element [2][2]. + * @a23: element [2][3]. + * @a30: element [3][0]. + * @a31: element [3][1]. + * @a32: element [3][2]. + * @a33: element [3][3]. + * + * Allocates memory and initializes a new #GtsMatrix. + * + * Returns: a pointer to the newly created #GtsMatrix. + */ +GtsMatrix * gts_matrix_new (gdouble a00, gdouble a01, gdouble a02, gdouble a03, + gdouble a10, gdouble a11, gdouble a12, gdouble a13, + gdouble a20, gdouble a21, gdouble a22, gdouble a23, + gdouble a30, gdouble a31, gdouble a32, gdouble a33) +{ + GtsMatrix * m; + + m = g_malloc (4*sizeof (GtsVector4)); + + m[0][0] = a00; m[1][0] = a10; m[2][0] = a20; m[3][0] = a30; + m[0][1] = a01; m[1][1] = a11; m[2][1] = a21; m[3][1] = a31; + m[0][2] = a02; m[1][2] = a12; m[2][2] = a22; m[3][2] = a32; + m[0][3] = a03; m[1][3] = a13; m[2][3] = a23; m[3][3] = a33; + + return m; +} + +/** + * gts_matrix_assign: + * @m: a #GtsMatrix. + * @a00: element [0][0]. + * @a01: element [0][1]. + * @a02: element [0][2]. + * @a03: element [0][3]. + * @a10: element [1][0]. + * @a11: element [1][1]. + * @a12: element [1][2]. + * @a13: element [1][3]. + * @a20: element [2][0]. + * @a21: element [2][1]. + * @a22: element [2][2]. + * @a23: element [2][3]. + * @a30: element [3][0]. + * @a31: element [3][1]. + * @a32: element [3][2]. + * @a33: element [3][3]. + * + * Set values of matrix elements. + */ +void gts_matrix_assign (GtsMatrix * m, + gdouble a00, gdouble a01, gdouble a02, gdouble a03, + gdouble a10, gdouble a11, gdouble a12, gdouble a13, + gdouble a20, gdouble a21, gdouble a22, gdouble a23, + gdouble a30, gdouble a31, gdouble a32, gdouble a33) +{ + g_return_if_fail (m != NULL); + + m[0][0] = a00; m[1][0] = a10; m[2][0] = a20; m[3][0] = a30; + m[0][1] = a01; m[1][1] = a11; m[2][1] = a21; m[3][1] = a31; + m[0][2] = a02; m[1][2] = a12; m[2][2] = a22; m[3][2] = a32; + m[0][3] = a03; m[1][3] = a13; m[2][3] = a23; m[3][3] = a33; +} + +/** + * gts_matrix_projection: + * @t: a #GtsTriangle. + * + * Creates a new #GtsMatrix representing the projection onto a plane of normal + * given by @t. + * + * Returns: a pointer to the newly created #GtsMatrix. + */ +GtsMatrix * gts_matrix_projection (GtsTriangle * t) +{ + GtsVertex * v1, * v2, * v3; + GtsEdge * e1, * e2, * e3; + GtsMatrix * m; + gdouble x1, y1, z1, x2, y2, z2, x3, y3, z3, l; + + g_return_val_if_fail (t != NULL, NULL); + + m = g_malloc (4*sizeof (GtsVector4)); + gts_triangle_vertices_edges (t, NULL, &v1, &v2, &v3, &e1, &e2, &e3); + + x1 = GTS_POINT (v2)->x - GTS_POINT (v1)->x; + y1 = GTS_POINT (v2)->y - GTS_POINT (v1)->y; + z1 = GTS_POINT (v2)->z - GTS_POINT (v1)->z; + x2 = GTS_POINT (v3)->x - GTS_POINT (v1)->x; + y2 = GTS_POINT (v3)->y - GTS_POINT (v1)->y; + z2 = GTS_POINT (v3)->z - GTS_POINT (v1)->z; + x3 = y1*z2 - z1*y2; y3 = z1*x2 - x1*z2; z3 = x1*y2 - y1*x2; + x2 = y3*z1 - z3*y1; y2 = z3*x1 - x3*z1; z2 = x3*y1 - y3*x1; + + g_assert ((l = sqrt (x1*x1 + y1*y1 + z1*z1)) > 0.0); + m[0][0] = x1/l; m[1][0] = y1/l; m[2][0] = z1/l; m[3][0] = 0.; + g_assert ((l = sqrt (x2*x2 + y2*y2 + z2*z2)) > 0.0); + m[0][1] = x2/l; m[1][1] = y2/l; m[2][1] = z2/l; m[3][1] = 0.; + g_assert ((l = sqrt (x3*x3 + y3*y3 + z3*z3)) > 0.0); + m[0][2] = x3/l; m[1][2] = y3/l; m[2][2] = z3/l; m[3][2] = 0.; + m[0][3] = 0; m[1][3] = 0.; m[2][3] = 0.; m[3][3] = 1.; + + return m; +} + +/** + * gts_matrix_transpose: + * @m: a #GtsMatrix. + * + * Returns: a pointer to a newly created #GtsMatrix transposed of @m. + */ +GtsMatrix * gts_matrix_transpose (GtsMatrix * m) +{ + GtsMatrix * mi; + + g_return_val_if_fail (m != NULL, NULL); + + mi = g_malloc (4*sizeof (GtsVector4)); + + mi[0][0] = m[0][0]; mi[1][0] = m[0][1]; + mi[2][0] = m[0][2]; mi[3][0] = m[0][3]; + mi[0][1] = m[1][0]; mi[1][1] = m[1][1]; + mi[2][1] = m[1][2]; mi[3][1] = m[1][3]; + mi[0][2] = m[2][0]; mi[1][2] = m[2][1]; + mi[2][2] = m[2][2]; mi[3][2] = m[2][3]; + mi[0][3] = m[3][0]; mi[1][3] = m[3][1]; + mi[2][3] = m[3][2]; mi[3][3] = m[3][3]; + + return mi; +} + +/* + * calculate the determinant of a 2x2 matrix. + * + * Adapted from: + * Matrix Inversion + * by Richard Carling + * from "Graphics Gems", Academic Press, 1990 + */ +static gdouble det2x2 (gdouble a, gdouble b, gdouble c, gdouble d) +{ + gdouble ans2; + + ans2 = a*d - b*c; + return ans2; +} + +/* + * calculate the determinant of a 3x3 matrix + * in the form + * + * | a1, b1, c1 | + * | a2, b2, c2 | + * | a3, b3, c3 | + * + * Adapted from: + * Matrix Inversion + * by Richard Carling + * from "Graphics Gems", Academic Press, 1990 + */ +static gdouble det3x3 (gdouble a1, gdouble a2, gdouble a3, + gdouble b1, gdouble b2, gdouble b3, + gdouble c1, gdouble c2, gdouble c3) +{ + gdouble ans3; + + ans3 = a1 * det2x2( b2, b3, c2, c3 ) + - b1 * det2x2( a2, a3, c2, c3 ) + + c1 * det2x2( a2, a3, b2, b3 ); + return ans3; +} + +/** + * gts_matrix_determinant: + * @m: a #GtsMatrix. + * + * Returns: the value of det(@m). + */ +gdouble gts_matrix_determinant (GtsMatrix * m) +{ + gdouble ans4; + gdouble a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4; + + g_return_val_if_fail (m != NULL, 0.0); + + a1 = m[0][0]; b1 = m[0][1]; + c1 = m[0][2]; d1 = m[0][3]; + + a2 = m[1][0]; b2 = m[1][1]; + c2 = m[1][2]; d2 = m[1][3]; + + a3 = m[2][0]; b3 = m[2][1]; + c3 = m[2][2]; d3 = m[2][3]; + + a4 = m[3][0]; b4 = m[3][1]; + c4 = m[3][2]; d4 = m[3][3]; + + ans4 = a1 * det3x3 (b2, b3, b4, c2, c3, c4, d2, d3, d4) + - b1 * det3x3 (a2, a3, a4, c2, c3, c4, d2, d3, d4) + + c1 * det3x3 (a2, a3, a4, b2, b3, b4, d2, d3, d4) + - d1 * det3x3 (a2, a3, a4, b2, b3, b4, c2, c3, c4); + + return ans4; +} + +/* + * adjoint( original_matrix, inverse_matrix ) + * + * calculate the adjoint of a 4x4 matrix + * + * Let a denote the minor determinant of matrix A obtained by + * ij + * + * deleting the ith row and jth column from A. + * + * i+j + * Let b = (-1) a + * ij ji + * + * The matrix B = (b ) is the adjoint of A + * ij + */ +static GtsMatrix * adjoint (GtsMatrix * m) +{ + gdouble a1, a2, a3, a4, b1, b2, b3, b4; + gdouble c1, c2, c3, c4, d1, d2, d3, d4; + GtsMatrix * ma; + + a1 = m[0][0]; b1 = m[0][1]; + c1 = m[0][2]; d1 = m[0][3]; + + a2 = m[1][0]; b2 = m[1][1]; + c2 = m[1][2]; d2 = m[1][3]; + + a3 = m[2][0]; b3 = m[2][1]; + c3 = m[2][2]; d3 = m[2][3]; + + a4 = m[3][0]; b4 = m[3][1]; + c4 = m[3][2]; d4 = m[3][3]; + + ma = g_malloc (4*sizeof (GtsVector4)); + + /* row column labeling reversed since we transpose rows & columns */ + + ma[0][0] = det3x3 (b2, b3, b4, c2, c3, c4, d2, d3, d4); + ma[1][0] = - det3x3 (a2, a3, a4, c2, c3, c4, d2, d3, d4); + ma[2][0] = det3x3 (a2, a3, a4, b2, b3, b4, d2, d3, d4); + ma[3][0] = - det3x3 (a2, a3, a4, b2, b3, b4, c2, c3, c4); + + ma[0][1] = - det3x3 (b1, b3, b4, c1, c3, c4, d1, d3, d4); + ma[1][1] = det3x3 (a1, a3, a4, c1, c3, c4, d1, d3, d4); + ma[2][1] = - det3x3 (a1, a3, a4, b1, b3, b4, d1, d3, d4); + ma[3][1] = det3x3 (a1, a3, a4, b1, b3, b4, c1, c3, c4); + + ma[0][2] = det3x3 (b1, b2, b4, c1, c2, c4, d1, d2, d4); + ma[1][2] = - det3x3 (a1, a2, a4, c1, c2, c4, d1, d2, d4); + ma[2][2] = det3x3 (a1, a2, a4, b1, b2, b4, d1, d2, d4); + ma[3][2] = - det3x3 (a1, a2, a4, b1, b2, b4, c1, c2, c4); + + ma[0][3] = - det3x3 (b1, b2, b3, c1, c2, c3, d1, d2, d3); + ma[1][3] = det3x3 (a1, a2, a3, c1, c2, c3, d1, d2, d3); + ma[2][3] = - det3x3 (a1, a2, a3, b1, b2, b3, d1, d2, d3); + ma[3][3] = det3x3 (a1, a2, a3, b1, b2, b3, c1, c2, c3); + + return ma; +} + + +/** + * gts_matrix_inverse: + * @m: a #GtsMatrix. + * + * Returns: a pointer to a newly created #GtsMatrix inverse of @m or %NULL + * if @m is not invertible. + */ +GtsMatrix * gts_matrix_inverse (GtsMatrix * m) +{ + GtsMatrix * madj; + gdouble det; + gint i, j; + + g_return_val_if_fail (m != NULL, NULL); + + det = gts_matrix_determinant (m); + if (det == 0.) + return NULL; + + madj = adjoint (m); + for (i = 0; i < 4; i++) + for(j = 0; j < 4; j++) + madj[i][j] /= det; + + return madj; +} + +/** + * gts_matrix3_inverse: + * @m: a 3x3 #GtsMatrix. + * + * Returns: a pointer to a newly created 3x3 #GtsMatrix inverse of @m or %NULL + * if @m is not invertible. + */ +GtsMatrix * gts_matrix3_inverse (GtsMatrix * m) +{ + GtsMatrix * mi; + gdouble det; + + g_return_val_if_fail (m != NULL, NULL); + + det = (m[0][0]*(m[1][1]*m[2][2] - m[2][1]*m[1][2]) - + m[0][1]*(m[1][0]*m[2][2] - m[2][0]*m[1][2]) + + m[0][2]*(m[1][0]*m[2][1] - m[2][0]*m[1][1])); + if (det == 0.0) + return NULL; + + mi = g_malloc0 (4*sizeof (GtsVector)); + + mi[0][0] = (m[1][1]*m[2][2] - m[1][2]*m[2][1])/det; + mi[0][1] = (m[2][1]*m[0][2] - m[0][1]*m[2][2])/det; + mi[0][2] = (m[0][1]*m[1][2] - m[1][1]*m[0][2])/det; + mi[1][0] = (m[1][2]*m[2][0] - m[1][0]*m[2][2])/det; + mi[1][1] = (m[0][0]*m[2][2] - m[2][0]*m[0][2])/det; + mi[1][2] = (m[1][0]*m[0][2] - m[0][0]*m[1][2])/det; + mi[2][0] = (m[1][0]*m[2][1] - m[2][0]*m[1][1])/det; + mi[2][1] = (m[2][0]*m[0][1] - m[0][0]*m[2][1])/det; + mi[2][2] = (m[0][0]*m[1][1] - m[0][1]*m[1][0])/det; + + return mi; +} + +/** + * gts_matrix_print: + * @m: a #GtsMatrix. + * @fptr: a file descriptor. + * + * Print @m to file @fptr. + */ +void gts_matrix_print (GtsMatrix * m, FILE * fptr) +{ + g_return_if_fail (m != NULL); + g_return_if_fail (fptr != NULL); + + fprintf (fptr, + "[[%15.7g %15.7g %15.7g %15.7g]\n" + " [%15.7g %15.7g %15.7g %15.7g]\n" + " [%15.7g %15.7g %15.7g %15.7g]\n" + " [%15.7g %15.7g %15.7g %15.7g]]\n", + m[0][0], m[0][1], m[0][2], m[0][3], + m[1][0], m[1][1], m[1][2], m[1][3], + m[2][0], m[2][1], m[2][2], m[2][3], + m[3][0], m[3][1], m[3][2], m[3][3]); +} + +/** + * gts_vector_print: + * @v: a #GtsVector. + * @fptr: a file descriptor. + * + * Print @s to file @fptr. + */ +void gts_vector_print (GtsVector v, FILE * fptr) +{ + g_return_if_fail (fptr != NULL); + + fprintf (fptr, + "[%15.7g %15.7g %15.7g ]\n", + v[0], v[1], v[2]); +} + +/** + * gts_vector4_print: + * @v: a #GtsVector4. + * @fptr: a file descriptor. + * + * Print @v to file @fptr. + */ +void gts_vector4_print (GtsVector4 v, FILE * fptr) +{ + g_return_if_fail (fptr != NULL); + + fprintf (fptr, + "[%15.7g %15.7g %15.7g %15.7g]\n", + v[0], v[1], v[2], v[3]); +} + +/* [cos(alpha)]^2 */ +#define COSALPHA2 0.999695413509 /* alpha = 1 degree */ +/* [sin(alpha)]^2 */ +#define SINALPHA2 3.04586490453e-4 /* alpha = 1 degree */ + +/** + * gts_matrix_compatible_row: + * @A: a #GtsMatrix. + * @b: a #GtsVector. + * @n: the number of previous constraints of @A.x=@b. + * @A1: a #GtsMatrix. + * @b1: a #GtsVector. + * + * Given a system of @n constraints @A.x=@b adds to it the compatible + * constraints defined by @A1.x=@b1. The compatibility is determined + * by insuring that the resulting system is well-conditioned (see + * Lindstrom and Turk (1998, 1999)). + * + * Returns: the number of constraints of the resulting system. + */ +guint gts_matrix_compatible_row (GtsMatrix * A, + GtsVector b, + guint n, + GtsVector A1, + gdouble b1) +{ + gdouble na1; + + g_return_val_if_fail (A != NULL, 0); + + na1 = gts_vector_scalar (A1, A1); + if (na1 == 0.0) + return n; + + /* normalize row */ + na1 = sqrt (na1); + A1[0] /= na1; A1[1] /= na1; A1[2] /= na1; b1 /= na1; + + if (n == 1) { + gdouble a0a1 = gts_vector_scalar (A[0], A1); + if (a0a1*a0a1 >= COSALPHA2) + return 1; + } + else if (n == 2) { + GtsVector V; + gdouble s; + + gts_vector_cross (V, A[0], A[1]); + s = gts_vector_scalar (V, A1); + if (s*s <= gts_vector_scalar (V, V)*SINALPHA2) + return 2; + } + + A[n][0] = A1[0]; A[n][1] = A1[1]; A[n][2] = A1[2]; b[n] = b1; + return n + 1; +} + +/** + * gts_matrix_quadratic_optimization: + * @A: a #GtsMatrix. + * @b: a #GtsVector. + * @n: the number of constraints (must be smaller than 3). + * @H: a symmetric positive definite Hessian. + * @c: a #GtsVector. + * + * Solve a quadratic optimization problem: Given a quadratic objective function + * f which can be written as: f(x) = x^t.@H.x + @c^t.x + k, where @H is the + * symmetric positive definite Hessian of f and k is a constant, find the + * minimum of f subject to the set of @n prior linear constraints, defined by + * the first @n rows of @A and @b (@A.x = @b). The new constraints given by + * the minimization are added to @A and @b only if they are linearly + * independent as determined by gts_matrix_compatible_row(). + * + * Returns: the new number of constraints defined by @A and @b. + */ +guint gts_matrix_quadratic_optimization (GtsMatrix * A, + GtsVector b, + guint n, + GtsMatrix * H, + GtsVector c) +{ + g_return_val_if_fail (A != NULL, 0); + g_return_val_if_fail (b != NULL, 0); + g_return_val_if_fail (n < 3, 0); + g_return_val_if_fail (H != NULL, 0); + + switch (n) { + case 0: { + n = gts_matrix_compatible_row (A, b, n, H[0], - c[0]); + n = gts_matrix_compatible_row (A, b, n, H[1], - c[1]); + n = gts_matrix_compatible_row (A, b, n, H[2], - c[2]); + return n; + } + case 1: { + GtsVector Q0 = {0., 0., 0.}; + GtsVector Q1 = {0., 0., 0.}; + GtsVector A1; + gdouble max = A[0][0]*A[0][0]; + guint d = 0; + + /* build a vector orthogonal to the constraint */ + if (A[0][1]*A[0][1] > max) { max = A[0][1]*A[0][1]; d = 1; } + if (A[0][2]*A[0][2] > max) { max = A[0][2]*A[0][2]; d = 2; } + switch (d) { + case 0: Q0[0] = - A[0][2]/A[0][0]; Q0[2] = 1.0; break; + case 1: Q0[1] = - A[0][2]/A[0][1]; Q0[2] = 1.0; break; + case 2: Q0[2] = - A[0][0]/A[0][2]; Q0[0] = 1.0; break; + } + + /* build a second vector orthogonal to the first and to the constraint */ + gts_vector_cross (Q1, A[0], Q0); + + A1[0] = gts_vector_scalar (Q0, H[0]); + A1[1] = gts_vector_scalar (Q0, H[1]); + A1[2] = gts_vector_scalar (Q0, H[2]); + + n = gts_matrix_compatible_row (A, b, n, A1, - gts_vector_scalar (Q0, c)); + + A1[0] = gts_vector_scalar (Q1, H[0]); + A1[1] = gts_vector_scalar (Q1, H[1]); + A1[2] = gts_vector_scalar (Q1, H[2]); + + n = gts_matrix_compatible_row (A, b, n, A1, - gts_vector_scalar (Q1, c)); + + return n; + } + case 2: { + /* build a vector orthogonal to the two constraints */ + GtsVector A1, Q; + + gts_vector_cross (Q, A[0], A[1]); + A1[0] = gts_vector_scalar (Q, H[0]); + A1[1] = gts_vector_scalar (Q, H[1]); + A1[2] = gts_vector_scalar (Q, H[2]); + + n = gts_matrix_compatible_row (A, b, n, A1, - gts_vector_scalar (Q, c)); + + return n; + } + default: + g_assert_not_reached (); + } + return 0; +} + +/** + * gts_matrix_destroy: + * @m: a #GtsMatrix. + * + * Free all the memory allocated for @m. + */ +void gts_matrix_destroy (GtsMatrix * m) +{ + g_free (m); +} + +/** + * gts_matrix_product: + * @m1: a #GtsMatrix. + * @m2: another #GtsMatrix. + * + * Returns: a new #GtsMatrix, product of @m1 and @m2. + */ +GtsMatrix * gts_matrix_product (GtsMatrix * m1, GtsMatrix * m2) +{ + guint i, j; + GtsMatrix * m; + + g_return_val_if_fail (m1 != NULL, NULL); + g_return_val_if_fail (m2 != NULL, NULL); + g_return_val_if_fail (m1 != m2, NULL); + + m = g_malloc (4*sizeof (GtsVector4)); + + for (i = 0; i < 4; i++) + for (j = 0; j < 4; j++) + m[i][j] = m1[i][0]*m2[0][j] + m1[i][1]*m2[1][j] + + m1[i][2]*m2[2][j] + m1[i][3]*m2[3][j]; + return m; +} + +/** + * gts_matrix_zero: + * @m: a #GtsMatrix or $NULL. + * + * Initializes @m to zeros. Allocates a matrix if @m is %NULL. + * + * Returns: the zero'ed matrix. + */ +GtsMatrix * gts_matrix_zero (GtsMatrix * m) +{ + if (m == NULL) + m = g_malloc0 (4*sizeof (GtsVector4)); + else { + m[0][0] = m[1][0] = m[2][0] = m[3][0] = 0.; + m[0][1] = m[1][1] = m[2][1] = m[3][1] = 0.; + m[0][2] = m[1][2] = m[2][2] = m[3][2] = 0.; + m[0][3] = m[1][3] = m[2][3] = m[3][3] = 0.; + } + return m; +} + +/** + * gts_matrix_identity: + * @m: a #GtsMatrix or %NULL. + * + * Initializes @m to an identity matrix. Allocates a matrix if @m is %NULL. + * + * Returns: the identity matrix. + */ +GtsMatrix * gts_matrix_identity (GtsMatrix * m) +{ + m = gts_matrix_zero (m); + m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.; + return m; +} + +/** + * gts_matrix_scale: + * @m: a #GtsMatrix or %NULL. + * @s: the scaling vector. + * + * Initializes @m to a scaling matrix for @s. Allocates a matrix if @m + * is %NULL. + * + * Returns: the scaling matrix. + */ +GtsMatrix * gts_matrix_scale (GtsMatrix * m, GtsVector s) +{ + m = gts_matrix_zero (m); + m[0][0] = s[0]; + m[1][1] = s[1]; + m[2][2] = s[2]; + m[3][3] = 1.; + return m; +} + +/** + * gts_matrix_translate: + * @m: a #GtsMatrix or %NULL. + * @t: the translation vector. + * + * Initializes @m to a translation matrix for @t. Allocates a new + * matrix if @m is %NULL. + * + * Returns: the translation matix. + */ +GtsMatrix * gts_matrix_translate (GtsMatrix * m, GtsVector t) +{ + m = gts_matrix_zero (m); + m[0][3] = t[0]; + m[1][3] = t[1]; + m[2][3] = t[2]; + m[3][3] = 1.; + m[0][0] = m[1][1] = m[2][2] = 1.; + return m; +} + +/** + * gts_matrix_rotate: + * @m: a #GtsMatrix or %NULL. + * @r: the rotation axis. + * @angle: the angle (in radians) to rotate by. + * + * Initializes @m to a rotation matrix around @r by @angle. + * Allocates a new matrix if @m is %NULL. + * + * Returns: the rotation matrix. + */ +GtsMatrix * gts_matrix_rotate (GtsMatrix * m, + GtsVector r, + gdouble angle) +{ + gdouble c, c1, s; + + gts_vector_normalize (r); + + c = cos (angle); + c1 = 1. - c; + s = sin (angle); + + if (m == NULL) + m = g_malloc (4*sizeof (GtsVector4)); + + m[0][0] = r[0]*r[0]*c1 + c; + m[0][1] = r[0]*r[1]*c1 - r[2]*s; + m[0][2] = r[0]*r[2]*c1 + r[1]*s; + m[0][3] = 0.; + + m[1][0] = r[1]*r[0]*c1 + r[2]*s; + m[1][1] = r[1]*r[1]*c1 + c; + m[1][2] = r[1]*r[2]*c1 - r[0]*s; + m[1][3] = 0.; + + m[2][0] = r[2]*r[0]*c1 - r[1]*s; + m[2][1] = r[2]*r[1]*c1 + r[0]*s; + m[2][2] = r[2]*r[2]*c1 + c; + m[2][3] = 0.; + + m[3][0] = 0.; + m[3][1] = 0.; + m[3][2] = 0.; + m[3][3] = 1.; + + return m; +} Index: work/obsolete/toporouter/src_3rd/gts/misc.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/misc.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/misc.c (revision 6803) @@ -0,0 +1,692 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include + +#include "gts.h" +#include "gts-private.h" +#include "config.h" + +const guint gts_major_version = GTS_MAJOR_VERSION; +const guint gts_minor_version = GTS_MINOR_VERSION; +const guint gts_micro_version = GTS_MICRO_VERSION; +const guint gts_interface_age = 1; +const guint gts_binary_age = 1; + +static gboolean char_in_string (char c, const char * s) +{ + while (*s != '\0') + if (*(s++) == c) + return TRUE; + return FALSE; +} + +static GtsFile * file_new (void) +{ + GtsFile * f; + + f = g_malloc (sizeof (GtsFile)); + f->fp = NULL; + f->s = f->s1 = NULL; + f->curline = 1; + f->curpos = 1; + f->token = g_string_new (""); + f->type = '\0'; + f->error = NULL; + f->next_token = '\0'; + + f->scope = f->scope_max = 0; + f->delimiters = g_strdup (" \t"); + f->comments = g_strdup (GTS_COMMENTS); + f->tokens = g_strdup ("\n{}()="); + + return f; +} + +/** + * gts_file_new: + * @fp: a file pointer. + * + * Returns: a new #GtsFile. + */ +GtsFile * gts_file_new (FILE * fp) +{ + GtsFile * f; + + g_return_val_if_fail (fp != NULL, NULL); + + f = file_new (); + f->fp = fp; + gts_file_next_token (f); + + return f; +} + +/** + * gts_file_new_from_string: + * @s: a string. + * + * Returns: a new #GtsFile. + */ +GtsFile * gts_file_new_from_string (const gchar * s) +{ + GtsFile * f; + + g_return_val_if_fail (s != NULL, NULL); + + f = file_new (); + f->s1 = f->s = g_strdup (s); + gts_file_next_token (f); + + return f; +} + +/** + * gts_file_destroy: + * @f: a #GtsFile. + * + * Frees all the memory allocated for @f. + */ +void gts_file_destroy (GtsFile * f) +{ + g_return_if_fail (f != NULL); + + g_free (f->delimiters); + g_free (f->comments); + g_free (f->tokens); + if (f->error) + g_free (f->error); + if (f->s1) + g_free (f->s1); + g_string_free (f->token, TRUE); + g_free (f); +} + +/** + * gts_file_verror: + * @f: a @GtsFile. + * @format: the standard sprintf() format string. + * @args: the list of parameters to insert into the format string. + * + * Sets the @error field of @f using g_strdup_vprintf(). + * + * This function can be called only once and disables any other + * operation on @f (gts_file_close() excepted). + */ +void gts_file_verror (GtsFile * f, + const gchar * format, + va_list args) +{ + g_return_if_fail (f != NULL); + g_return_if_fail (format != NULL); + + g_assert (f->type != GTS_ERROR); + f->error = g_strdup_vprintf (format, args); + f->type = GTS_ERROR; +} + +/** + * gts_file_error: + * @f: a @GtsFile. + * @format: the standard sprintf() format string. + * @...: the parameters to insert into the format string. + * + * Sets the @error field of @f using gts_file_verror(). + * + * This function can be called only once and disables any other + * operation on @f (gts_file_close() excepted). + */ +void gts_file_error (GtsFile * f, + const gchar * format, + ...) +{ + va_list args; + + g_return_if_fail (f != NULL); + g_return_if_fail (format != NULL); + + va_start (args, format); + gts_file_verror (f, format, args); + va_end (args); +} + +static gint next_char (GtsFile * f) +{ + if (f->fp) + return fgetc (f->fp); + else if (*f->s == '\0') + return EOF; + return *(f->s++); +} + +/** + * gts_file_getc : + * @f: a #GtsFile. + * + * Returns: the next character in @f or EOF if the end of the file is + * reached or if an error occured. + */ +gint gts_file_getc (GtsFile * f) +{ + gint c; + + g_return_val_if_fail (f != NULL, EOF); + + if (f->type == GTS_ERROR) + return EOF; + + c = next_char (f); + f->curpos++; + while (char_in_string (c, f->comments)) { + while (c != EOF && c != '\n') + c = next_char (f); + if (c == '\n') { + f->curline++; + f->curpos = 1; + c = next_char (f); + } + } + switch (c) { + case '\n': + f->curline++; + f->curpos = 1; + break; + case '{': + f->scope++; + break; + case '}': + if (f->scope == 0) { + f->line = f->curline; + f->pos = f->curpos - 1; + gts_file_error (f, "no matching opening brace"); + c = EOF; + } + else + f->scope--; + } + return c; +} + +/** + * gts_file_read: + * @f: a #GtsFile. + * @ptr: a pointer. + * @size: size of an element. + * @nmemb: number of elements. + * + * Reads @nmemb elements of data, each @size bytes long, from @f, + * storing them at the location given by @ptr. + * + * Returns: the number of elements read. + */ +guint gts_file_read (GtsFile * f, gpointer ptr, guint size, guint nmemb) +{ + guint i, n; + gchar * p; + + g_return_val_if_fail (f != NULL, 0); + g_return_val_if_fail (ptr != NULL, 0); + g_return_val_if_fail (f->fp != NULL, 0); + + if (f->type == GTS_ERROR) + return 0; + + n = fread (ptr, size, nmemb, f->fp); + for (i = 0, p = ptr; i < n*size; i++, p++) { + f->curpos++; + if (*p == '\n') { + f->curline++; + f->curpos = 1; + } + } + return n; +} + +/** + * gts_file_getc_scope : + * @f: a #GtsFile. + * + * Returns: the next character in @f in the scope defined by + * @f->scope_max or EOF if the end of the file is reached or if an + * error occured. + */ +gint gts_file_getc_scope (GtsFile * f) +{ + gint c; + + g_return_val_if_fail (f != NULL, EOF); + + if (f->type == GTS_ERROR) + return EOF; + + if (f->scope <= f->scope_max) + c = gts_file_getc (f); + else { + c = gts_file_getc (f); + while (c != EOF && f->scope > f->scope_max) + c = gts_file_getc (f); + } + return c; +} + +/** + * gts_file_next_token: + * @f: a #GtsFile. + * + * Reads next token from @f and updates its @token and @delim fields. + */ +void gts_file_next_token (GtsFile * f) +{ + gint c; + gboolean in_string = FALSE; + + g_return_if_fail (f != NULL); + + if (f->type == GTS_ERROR) + return; + f->token->str[0] = '\0'; + f->token->len = 0; + if (f->next_token != '\0') { + if (char_in_string (f->next_token, f->tokens)) { + f->line = f->curline; + f->pos = f->curpos - 1; + g_string_append_c (f->token, f->next_token); + f->type = f->next_token; + f->next_token = '\0'; + return; + } + else { + c = f->next_token; + f->next_token = '\0'; + } + } + else + c = gts_file_getc_scope (f); + f->type = GTS_NONE; + while (c != EOF && (!in_string || !char_in_string (c, f->delimiters))) { + if (in_string) { + if (char_in_string (c, f->tokens)) { + f->next_token = c; + break; + } + g_string_append_c (f->token, c); + } + else if (!char_in_string (c, f->delimiters)) { + in_string = TRUE; + f->line = f->curline; + f->pos = f->curpos - 1; + g_string_append_c (f->token, c); + if (char_in_string (c, f->tokens)) { + f->type = c; + break; + } + } + c = gts_file_getc_scope (f); + } + if (f->type == GTS_NONE && f->token->len > 0) { + gchar * a; + + a = f->token->str; + while (*a != '\0' && char_in_string (*a, "+-")) a++; + if (*a == '\0') { + f->type = GTS_STRING; + return; + } + a = f->token->str; + while (*a != '\0' && char_in_string (*a, "+-0123456789")) a++; + if (*a == '\0') { + f->type = GTS_INT; + return; + } + a = f->token->str; + while (*a != '\0' && char_in_string (*a, "+-eE.")) a++; + if (*a == '\0') { + f->type = GTS_STRING; + return; + } + a = f->token->str; + while (*a != '\0' && char_in_string (*a, "+-0123456789eE.")) a++; + if (*a == '\0') { + f->type = GTS_FLOAT; + return; + } + a = f->token->str; + if (!strncmp (a, "0x", 2) || + !strncmp (a, "-0x", 3) || + !strncmp (a, "+0x", 3)) { + while (*a != '\0' && char_in_string (*a, "+-0123456789abcdefx")) a++; + if (*a == '\0') { + f->type = GTS_INT; + return; + } + a = f->token->str; + while (*a != '\0' && char_in_string (*a, "+-0123456789abcdefx.p")) a++; + if (*a == '\0') { + f->type = GTS_FLOAT; + return; + } + } + f->type = GTS_STRING; + } +} + +/** + * gts_file_first_token_after: + * @f: a #GtsFile. + * @type: a #GtsTokenType. + * + * Finds and sets the first token of a type different from @type + * occuring after a token of type @type. + */ +void gts_file_first_token_after (GtsFile * f, GtsTokenType type) +{ + g_return_if_fail (f != NULL); + + while (f->type != GTS_ERROR && + f->type != GTS_NONE && + f->type != type) + gts_file_next_token (f); + while (f->type == type) + gts_file_next_token (f); +} + +/** + * gts_file_assign_start: + * @f: a #GtsFile. + * @vars: a %GTS_NONE terminated array of #GtsFileVariable. + * + * Opens a block delimited by braces to read a list of optional + * arguments specified by @vars. + * + * If an error is encountered the @error field of @f is set. + */ +void gts_file_assign_start (GtsFile * f, GtsFileVariable * vars) +{ + GtsFileVariable * var; + + g_return_if_fail (f != NULL); + g_return_if_fail (vars != NULL); + + var = vars; + while (var->type != GTS_NONE) + (var++)->set = FALSE; + + if (f->type != '{') { + gts_file_error (f, "expecting an opening brace"); + return; + } + + f->scope_max++; + gts_file_next_token (f); +} + +/** + * gts_file_assign_next: + * @f: a #GtsFile. + * @vars: a %GTS_NONE terminated array of #GtsFileVariable. + * + * Assigns the next optional argument of @vars read from @f. + * + * Returns: the variable of @vars which has been assigned or %NULL if + * no variable has been assigned (if an error has been encountered the + * @error field of @f is set). + */ +GtsFileVariable * gts_file_assign_next (GtsFile * f, GtsFileVariable * vars) +{ + GtsFileVariable * var; + gboolean found = FALSE; + + g_return_val_if_fail (f != NULL, NULL); + g_return_val_if_fail (vars != NULL, NULL); + + while (f->type == '\n') + gts_file_next_token (f); + if (f->type == '}') { + f->scope_max--; + gts_file_next_token (f); + return NULL; + } + if (f->type == GTS_ERROR) + return NULL; + + var = vars; + while (f->type != GTS_ERROR && var->type != GTS_NONE && !found) { + if (!strcmp (var->name, f->token->str)) { + found = TRUE; + if (var->unique && var->set) + gts_file_error (f, "variable `%s' was already set at line %d:%d", + var->name, var->line, var->pos); + else { + var->line = f->line; + var->pos = f->pos; + gts_file_next_token (f); + if (f->type != '=') + gts_file_error (f, "expecting `='"); + else { + var->set = TRUE; + switch (var->type) { + case GTS_FILE: + break; + case GTS_INT: + gts_file_next_token (f); + if (f->type != GTS_INT) { + gts_file_error (f, "expecting an integer"); + var->set = FALSE; + } + else if (var->data) + *((gint *) var->data) = atoi (f->token->str); + break; + case GTS_UINT: + gts_file_next_token (f); + if (f->type != GTS_INT) { + gts_file_error (f, "expecting an integer"); + var->set = FALSE; + } + else if (var->data) + *((guint *) var->data) = atoi (f->token->str); + break; + case GTS_FLOAT: + gts_file_next_token (f); + if (f->type != GTS_INT && f->type != GTS_FLOAT) { + gts_file_error (f, "expecting a number"); + var->set = FALSE; + } + else if (var->data) + *((gfloat *) var->data) = atof (f->token->str); + break; + case GTS_DOUBLE: + gts_file_next_token (f); + if (f->type != GTS_INT && f->type != GTS_FLOAT) { + gts_file_error (f, "expecting a number"); + var->set = FALSE; + } + else if (var->data) + *((gdouble *) var->data) = atof (f->token->str); + break; + case GTS_STRING: + gts_file_next_token (f); + if (f->type != GTS_INT && + f->type != GTS_FLOAT && + f->type != GTS_STRING) { + gts_file_error (f, "expecting a string"); + var->set = FALSE; + } + else if (var->data) + *((gchar **) var->data) = g_strdup (f->token->str); + break; + default: + g_assert_not_reached (); + } + } + } + } + else + var++; + } + if (!found) + gts_file_error (f, "unknown identifier `%s'", f->token->str); + else if (f->type != GTS_ERROR) { + g_assert (var->set); + gts_file_next_token (f); + return var; + } + return NULL; +} + +/** + * gts_file_assign_variables: + * @f: a #GtsFile. + * @vars: an array of #GtsFileVariable. + * + * Assigns all the variables belonging to @vars found in @f. + * + * If an error is encountered the @error field of @f is set. + */ +void gts_file_assign_variables (GtsFile * f, GtsFileVariable * vars) +{ + g_return_if_fail (f != NULL); + g_return_if_fail (vars != NULL); + + gts_file_assign_start (f, vars); + while (gts_file_assign_next (f, vars)) + ; +} + +/** + * gts_file_variable_error: + * @f: a #GtsFile. + * @vars: an array of #GtsFileVariable. + * @name: the name of a variable in @vars. + * @format: the standard sprintf() format string. + * @...: the parameters to insert into the format string. + * + * Sets the @error field of @f using gts_file_verror(). + * + * String @name must match one of the variable names in @vars. + * + * If variable @name has been assigned (using gts_file_assign_variables()) + * sets the @line and @pos fields of @f to the line and position where + * it has been assigned. + */ +void gts_file_variable_error (GtsFile * f, + GtsFileVariable * vars, + const gchar * name, + const gchar * format, + ...) +{ + va_list args; + GtsFileVariable * var; + + g_return_if_fail (f != NULL); + g_return_if_fail (vars != NULL); + g_return_if_fail (name != NULL); + g_return_if_fail (format != NULL); + + var = vars; + while (var->type != GTS_NONE && strcmp (var->name, name)) + var++; + + g_return_if_fail (var->type != GTS_NONE); /* @name not found in @vars */ + + if (var->set) { + f->line = var->line; + f->pos = var->pos; + } + + va_start (args, format); + gts_file_verror (f, format, args); + va_end (args); +} + +#ifdef DEBUG_FUNCTIONS +static GHashTable * ids = NULL; +static guint next_id = 1; + +guint id (gpointer p) +{ + g_return_val_if_fail (p != NULL, 0); + g_return_val_if_fail (ids != NULL, 0); + g_assert (g_hash_table_lookup (ids, p)); + return GPOINTER_TO_UINT (g_hash_table_lookup (ids, p)); +} + +void id_insert (gpointer p) +{ + g_return_if_fail (p != NULL); + if (ids == NULL) ids = g_hash_table_new (NULL, NULL); + g_assert (g_hash_table_lookup (ids, p) == NULL); + g_hash_table_insert (ids, p, GUINT_TO_POINTER (next_id++)); +} + +void id_remove (gpointer p) +{ + g_assert (g_hash_table_lookup (ids, p)); + g_hash_table_remove (ids, p); +} + +void gts_write_triangle (GtsTriangle * t, + GtsPoint * o, + FILE * fptr) +{ + gdouble xo = o ? o->x : 0.0; + gdouble yo = o ? o->y : 0.0; + gdouble zo = o ? o->z : 0.0; + + g_return_if_fail (t != NULL && fptr != NULL); + + fprintf (fptr, "(hdefine geometry \"t%d\" { =\n", id (t)); + fprintf (fptr, "OFF 3 1 0\n" + "%g %g %g\n%g %g %g\n%g %g %g\n3 0 1 2\n})\n" + "(geometry \"t%d\" { : \"t%d\"})\n" + "(normalization \"t%d\" none)\n", + GTS_POINT (GTS_SEGMENT (t->e1)->v1)->x - xo, + GTS_POINT (GTS_SEGMENT (t->e1)->v1)->y - yo, + GTS_POINT (GTS_SEGMENT (t->e1)->v1)->z - zo, + GTS_POINT (GTS_SEGMENT (t->e1)->v2)->x - xo, + GTS_POINT (GTS_SEGMENT (t->e1)->v2)->y - yo, + GTS_POINT (GTS_SEGMENT (t->e1)->v2)->z - zo, + GTS_POINT (gts_triangle_vertex (t))->x - xo, + GTS_POINT (gts_triangle_vertex (t))->y - yo, + GTS_POINT (gts_triangle_vertex (t))->z - zo, + id (t), id (t), id (t)); +} + +void gts_write_segment (GtsSegment * s, + GtsPoint * o, + FILE * fptr) +{ + gdouble xo = o ? o->x : 0.0; + gdouble yo = o ? o->y : 0.0; + gdouble zo = o ? o->z : 0.0; + + g_return_if_fail (s != NULL && fptr != NULL); + + fprintf (fptr, "(geometry \"s%d\" { =\n", id (s)); + fprintf (fptr, "VECT 1 2 0 2 0 %g %g %g %g %g %g })\n" + "(normalization \"s%d\" none)\n", + GTS_POINT (s->v1)->x - xo, + GTS_POINT (s->v1)->y - yo, + GTS_POINT (s->v1)->z - zo, + GTS_POINT (s->v2)->x - xo, + GTS_POINT (s->v2)->y - yo, + GTS_POINT (s->v2)->z - zo, + id (s)); +} +#endif /* DEBUG_FUNCTIONS */ Index: work/obsolete/toporouter/src_3rd/gts/named.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/named.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/named.c (revision 6803) @@ -0,0 +1,188 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "gts.h" + +static void nvertex_read (GtsObject ** po, GtsFile * fp) +{ + if ((*po)->klass->parent_class->read) + (* (*po)->klass->parent_class->read) (po, fp); + + if (fp->type != '\n' && fp->type != GTS_ERROR) { + strncpy (GTS_NVERTEX (*po)->name, fp->token->str, GTS_NAME_LENGTH); + gts_file_next_token (fp); + } +} + +static void nvertex_write (GtsObject * o, FILE * fptr) +{ + GtsNVertex * nv = GTS_NVERTEX (o); + + (* o->klass->parent_class->write) (o, fptr); + if (nv->name[0] != '\0') + fprintf (fptr, " %s", nv->name); +} + +static void nvertex_class_init (GtsNVertexClass * klass) +{ + GTS_OBJECT_CLASS (klass)->read = nvertex_read; + GTS_OBJECT_CLASS (klass)->write = nvertex_write; +} + +static void nvertex_init (GtsNVertex * nvertex) +{ + nvertex->name[0] = '\0'; +} + +/** + * gts_nvertex_class: + * + * Returns: the #GtsNVertexClass. + */ +GtsNVertexClass * gts_nvertex_class (void) +{ + static GtsNVertexClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo nvertex_info = { + "GtsNVertex", + sizeof (GtsNVertex), + sizeof (GtsNVertexClass), + (GtsObjectClassInitFunc) nvertex_class_init, + (GtsObjectInitFunc) nvertex_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_vertex_class ()), + &nvertex_info); + } + + return klass; +} + +static void nedge_read (GtsObject ** po, GtsFile * fp) +{ + if (fp->type != GTS_STRING) { + gts_file_error (fp, "expecting a string (name)"); + return; + } + strncpy (GTS_NEDGE (*po)->name, fp->token->str, GTS_NAME_LENGTH); + gts_file_next_token (fp); +} + +static void nedge_write (GtsObject * o, FILE * fptr) +{ + GtsNEdge * ne = GTS_NEDGE (o); + + if (ne->name[0] != '\0') + fprintf (fptr, " %s", ne->name); +} + +static void nedge_class_init (GtsNEdgeClass * klass) +{ + GTS_OBJECT_CLASS (klass)->read = nedge_read; + GTS_OBJECT_CLASS (klass)->write = nedge_write; +} + +static void nedge_init (GtsNEdge * nedge) +{ + nedge->name[0] = '\0'; +} + +/** + * gts_nedge_class: + * + * Returns: the #GtsNEdgeClass. + */ +GtsNEdgeClass * gts_nedge_class (void) +{ + static GtsNEdgeClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo nedge_info = { + "GtsNEdge", + sizeof (GtsNEdge), + sizeof (GtsNEdgeClass), + (GtsObjectClassInitFunc) nedge_class_init, + (GtsObjectInitFunc) nedge_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_edge_class ()), + &nedge_info); + } + + return klass; +} + +static void nface_read (GtsObject ** po, GtsFile * fp) +{ + if (fp->type != GTS_STRING) { + gts_file_error (fp, "expecting a string (name)"); + return; + } + strncpy (GTS_NFACE (*po)->name, fp->token->str, GTS_NAME_LENGTH); + gts_file_next_token (fp); +} + +static void nface_write (GtsObject * o, FILE * fptr) +{ + GtsNFace * nf = GTS_NFACE (o); + + if (nf->name[0] != '\0') + fprintf (fptr, " %s", GTS_NFACE (o)->name); +} + +static void nface_class_init (GtsNFaceClass * klass) +{ + GTS_OBJECT_CLASS (klass)->read = nface_read; + GTS_OBJECT_CLASS (klass)->write = nface_write; +} + +static void nface_init (GtsNFace * nface) +{ + nface->name[0] = '\0'; +} + +/** + * gts_nface_class: + * + * Returns: the #GtsNFaceClass. + */ +GtsNFaceClass * gts_nface_class (void) +{ + static GtsNFaceClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo nface_info = { + "GtsNFace", + sizeof (GtsNFace), + sizeof (GtsNFaceClass), + (GtsObjectClassInitFunc) nface_class_init, + (GtsObjectInitFunc) nface_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_face_class ()), + &nface_info); + } + + return klass; +} Index: work/obsolete/toporouter/src_3rd/gts/object.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/object.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/object.c (revision 6803) @@ -0,0 +1,345 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "gts.h" +#include "gts-private.h" + +static GHashTable * class_table = NULL; + +static void gts_object_class_init (GtsObjectClass * klass, + GtsObjectClass * parent_class) +{ + if (parent_class) { + gts_object_class_init (klass, parent_class->parent_class); + if (parent_class->info.class_init_func) + (*parent_class->info.class_init_func) (klass); + } +} + +/** + * gts_object_class_new: + * @parent_class: a #GtsObjectClass. + * @info: a #GtsObjectClassInfo, description of the new class to create. + * + * Returns: a new #GtsObjectClass derived from @parent_class and described by + * @info. + */ +gpointer gts_object_class_new (GtsObjectClass * parent_class, + GtsObjectClassInfo * info) +{ + GtsObjectClass * klass; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (parent_class == NULL || + info->object_size >= parent_class->info.object_size, + NULL); + g_return_val_if_fail (parent_class == NULL || + info->class_size >= parent_class->info.class_size, + NULL); + + klass = g_malloc0 (info->class_size); + klass->info = *info; + klass->parent_class = parent_class; + gts_object_class_init (klass, klass); + + if (!class_table) + class_table = g_hash_table_new (g_str_hash, g_str_equal); + g_hash_table_insert (class_table, klass->info.name, klass); + + return klass; +} + +/** + * gts_object_class_from_name: + * @name: the name of a #GtsObjectClass. + * + * Returns: the #GtsObjectClass with name @name or %NULL if it hasn't been + * instantiated yet. + */ +GtsObjectClass * gts_object_class_from_name (const gchar * name) +{ + g_return_val_if_fail (name != NULL, NULL); + + if (!class_table) + return NULL; + return g_hash_table_lookup (class_table, name); +} + +static void object_destroy (GtsObject * object) +{ +#ifdef DEBUG_IDENTITY +#ifdef DEBUG_LEAKS + fprintf (stderr, "destroy %s %p->%d\n", + object->klass->info.name, + object, + id (object)); +#endif + id_remove (object); +#endif + object->klass = NULL; + g_free (object); +} + +static void object_clone (GtsObject * clone, GtsObject * object) +{ + memcpy (clone, object, object->klass->info.object_size); + clone->reserved = NULL; +} + +static void object_class_init (GtsObjectClass * klass) +{ + klass->clone = object_clone; + klass->destroy = object_destroy; + klass->read = NULL; + klass->write = NULL; + klass->color = NULL; + klass->attributes = NULL; +} + +static void object_init (GtsObject * object) +{ + object->reserved = NULL; + object->flags = 0; +} + +/** + * gts_object_class: + * + * Returns: the #GtsObjectClass. + */ +GtsObjectClass * gts_object_class (void) +{ + static GtsObjectClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo object_info = { + "GtsObject", + sizeof (GtsObject), + sizeof (GtsObjectClass), + (GtsObjectClassInitFunc) object_class_init, + (GtsObjectInitFunc) object_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (NULL, &object_info); + } + + return klass; +} + +/** + * gts_object_check_cast: + * @object: a #GtsObject. + * @klass: a #GtsObjectClass. + * + * Returns: @object while emitting warnings if @object is not of class @klass. + */ +gpointer gts_object_check_cast (gpointer object, + gpointer klass) +{ + if (!object) { + g_warning ("invalid cast from (NULL) pointer to `%s'", + GTS_OBJECT_CLASS (klass)->info.name); + return object; + } + if (!((GtsObject *) object)->klass) { + g_warning ("invalid unclassed pointer in cast to `%s'", + GTS_OBJECT_CLASS (klass)->info.name); + return object; + } + if (!gts_object_is_from_class (object, klass)) { + g_warning ("invalid cast from `%s' to `%s'", + ((GtsObject *) object)->klass->info.name, + GTS_OBJECT_CLASS (klass)->info.name); + return object; + } + return object; +} + +/** + * gts_object_class_check_cast: + * @klass: a #GtsObjectClass. + * @from: a #GtsObjectClass. + * + * Returns: @klass while emitting warnings if @klass is not derived from + * @from. + */ +gpointer gts_object_class_check_cast (gpointer klass, + gpointer from) +{ + if (!klass) { + g_warning ("invalid cast from (NULL) pointer to `%s'", + GTS_OBJECT_CLASS (from)->info.name); + return klass; + } + if (!gts_object_class_is_from_class (klass, from)) { + g_warning ("invalid cast from `%s' to `%s'", + GTS_OBJECT_CLASS (klass)->info.name, + GTS_OBJECT_CLASS (from)->info.name); + return klass; + } + return klass; +} + +/** + * gts_object_init: + * @object: a #GtsObject. + * @klass: a #GtsObjectClass. + * + * Calls the init method of @klass with @object as argument. This is done + * recursively in the correct order (from the base class to the top). You + * should rarely need this function as it is called automatically by the + * constructor for each class. + */ +void gts_object_init (GtsObject * object, GtsObjectClass * klass) +{ + GtsObjectClass * parent_class; + + g_return_if_fail (object != NULL); + g_return_if_fail (klass != NULL); + + parent_class = klass->parent_class; + if (parent_class) + gts_object_init (object, parent_class); + if (klass->info.object_init_func) + (*klass->info.object_init_func) (object); +} + +/** + * gts_object_new: + * @klass: a #GtsObjectClass. + * + * Returns: a new initialized object of class @klass. + */ +GtsObject * gts_object_new (GtsObjectClass * klass) +{ + GtsObject * object; + + g_return_val_if_fail (klass != NULL, NULL); + + object = g_malloc0 (klass->info.object_size); + object->klass = klass; + gts_object_init (object, klass); + +#ifdef DEBUG_IDENTITY + id_insert (object); +#ifdef DEBUG_LEAKS + fprintf (stderr, "new %s %p->%d\n", klass->info.name, + object, + id (object)); +#endif +#endif + + return object; +} + +/** + * gts_object_clone: + * @object: a #GtsObject. + * + * Calls the clone method of @object. The call to this function will fail + * if no clone method exists for the given object. + * + * Returns: a new object clone of @object. + */ +GtsObject * gts_object_clone (GtsObject * object) +{ + GtsObject * clone; + + g_return_val_if_fail (object != NULL, NULL); + g_return_val_if_fail (object->klass->clone, NULL); + + clone = g_malloc0 (object->klass->info.object_size); + clone->klass = object->klass; + object_init (clone); + (* object->klass->clone) (clone, object); + +#ifdef DEBUG_IDENTITY + id_insert (clone); +#ifdef DEBUG_LEAKS + fprintf (stderr, "clone %s %p->%d\n", clone->klass->info.name, + clone, + id (clone)); +#endif +#endif + + return clone; +} + +/** + * gts_object_destroy: + * @object: a #GtsObject. + * + * Calls the destroy method of @object, freeing all memory allocated for it. + */ +void gts_object_destroy (GtsObject * object) +{ + g_assert (object->klass->destroy); + GTS_OBJECT_SET_FLAGS (object, GTS_DESTROYED); + (* object->klass->destroy) (object); +} + +/** + * gts_object_reset_reserved: + * @object: a #GtsObject. + * + * Reset the reserved field of @object. + */ +void gts_object_reset_reserved (GtsObject * object) +{ + g_return_if_fail (object != NULL); + + object->reserved = NULL; +} + +/** + * gts_object_attributes: + * @object: a #GtsObject. + * @from: a #GtsObject. + * + * Calls the attributes() method of @object using @from as source. + */ +void gts_object_attributes (GtsObject * object, GtsObject * from) +{ + g_return_if_fail (object != NULL); + + if (object->klass->attributes) + (* object->klass->attributes) (object, from); +} + +static void free_class (gchar * name, GtsObjectClass * klass) +{ + g_free (klass); +} + +/** + * gts_finalize: + * + * Free all the memory allocated by the object system of GTS. No other + * GTS function can be called after this function has been called. + */ +void gts_finalize (void) +{ + if (class_table) { + g_hash_table_foreach (class_table, (GHFunc) free_class, NULL); + g_hash_table_destroy (class_table); + class_table = NULL; + } +} Index: work/obsolete/toporouter/src_3rd/gts/oocs.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/oocs.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/oocs.c (revision 6803) @@ -0,0 +1,387 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "gts.h" + +static void cluster_destroy (GtsObject * object) +{ + GtsCluster * c = GTS_CLUSTER (object); + + if (c->v && gts_vertex_is_unattached (c->v)) + gts_object_destroy (GTS_OBJECT (c->v)); + + /* do not forget to call destroy method of the parent */ + (* GTS_OBJECT_CLASS (gts_cluster_class ())->parent_class->destroy) (object); +} + +static void cluster_add (GtsCluster * c, GtsPoint * p, gpointer data) +{ + GtsPoint * cp; + + g_return_if_fail (c != NULL); + g_return_if_fail (c->v != NULL); + g_return_if_fail (p != NULL); + + cp = GTS_POINT (c->v); + + cp->x += p->x; + cp->y += p->y; + cp->z += p->z; + c->n++; +} + +static void cluster_update (GtsCluster * c) +{ + GtsPoint * p; + + g_return_if_fail (c != NULL); + g_return_if_fail (c->v != NULL); + + if (c->n > 1) { + p = GTS_POINT (c->v); + p->x /= c->n; + p->y /= c->n; + p->z /= c->n; + } +} + +static void cluster_class_init (GtsClusterClass * klass) +{ + klass->add = cluster_add; + klass->update = cluster_update; + + GTS_OBJECT_CLASS (klass)->destroy = cluster_destroy; +} + +static void cluster_init (GtsCluster * c) +{ + c->v = NULL; + c->n = 0; +} + +/** + * gts_cluster_class: + * + * Returns: the #GtsClusterClass. + */ +GtsClusterClass * gts_cluster_class (void) +{ + static GtsClusterClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo cluster_info = { + "GtsCluster", + sizeof (GtsCluster), + sizeof (GtsClusterClass), + (GtsObjectClassInitFunc) cluster_class_init, + (GtsObjectInitFunc) cluster_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (gts_object_class (), &cluster_info); + } + + return klass; +} + +/** + * gts_cluster_new: + * @klass: a #GtsClusterClass. + * @id: the id of the new cluster. + * @vklass: a #GtsVertexClass for the representative vertex of the cluster. + * + * Returns: a new #GtsCluster. + */ +GtsCluster * gts_cluster_new (GtsClusterClass * klass, + GtsClusterId id, + GtsVertexClass * vklass) +{ + GtsCluster * c; + + c = GTS_CLUSTER (gts_object_new (GTS_OBJECT_CLASS (klass))); + c->id = id; + c->v = gts_vertex_new (vklass, 0., 0., 0.); + + return c; +} + +/** + * gts_cluster_add: + * @c: a #GtsCluster. + * @p: a #GtsPoint. + * @data: data to pass to the add() virtual method of #GtsClusterClass. + * + * Adds point @p to cluster @c. + */ +void gts_cluster_add (GtsCluster * c, GtsPoint * p, gpointer data) +{ + g_return_if_fail (c != NULL); + g_return_if_fail (p != NULL); + + (* GTS_CLUSTER_CLASS (GTS_OBJECT (c)->klass)->add) (c, p, data); +} + +/** + * gts_cluster_update: + * @c: a #GtsCluster. + * + * Updates the position of the vertex representative of all the + * vertices added to @c. + */ +void gts_cluster_update (GtsCluster * c) +{ + g_return_if_fail (c != NULL); + + (* GTS_CLUSTER_CLASS (GTS_OBJECT (c)->klass)->update) (c); +} + +static void destroy_cluster (GtsClusterId * id, GtsObject * cluster) +{ + gts_object_destroy (cluster); +} + +static void cluster_grid_destroy (GtsObject * object) +{ + GtsClusterGrid * cluster_grid = GTS_CLUSTER_GRID (object); + + g_hash_table_foreach (cluster_grid->clusters, + (GHFunc) destroy_cluster, NULL); + g_hash_table_destroy (cluster_grid->clusters); + + (* GTS_OBJECT_CLASS (gts_cluster_grid_class ())->parent_class->destroy) + (object); +} + +static void cluster_grid_class_init (GtsClusterGridClass * klass) +{ + GTS_OBJECT_CLASS (klass)->destroy = cluster_grid_destroy; +} + +static gint cluster_id_equal (gconstpointer v1, + gconstpointer v2) +{ + const GtsClusterId * id1 = (const GtsClusterId *) v1; + const GtsClusterId * id2 = (const GtsClusterId *) v2; + return ((id1->x == id2->x) && (id1->y == id2->y) && (id1->z == id2->z)); +} + +static guint cluster_id_hash (gconstpointer key) +{ + const GtsClusterId * id = (const GtsClusterId *) key; + return id->x + id->y + id->z; +} + +static void cluster_grid_init (GtsClusterGrid * cluster_grid) +{ + cluster_grid->surface = NULL; + cluster_grid->bbox = NULL; + cluster_grid->cluster_class = gts_cluster_class (); + cluster_grid->clusters = g_hash_table_new (cluster_id_hash, + cluster_id_equal); +} + +/** + * gts_cluster_grid_class: + * + * Returns: the #GtsClusterGridClass. + */ +GtsClusterGridClass * gts_cluster_grid_class (void) +{ + static GtsClusterGridClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo cluster_grid_info = { + "GtsClusterGrid", + sizeof (GtsClusterGrid), + sizeof (GtsClusterGridClass), + (GtsObjectClassInitFunc) cluster_grid_class_init, + (GtsObjectInitFunc) cluster_grid_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (gts_object_class (), &cluster_grid_info); + } + + return klass; +} + +/** + * gts_cluster_grid_new: + * @klass: a #GtsClusterGridClass. + * @cluster_class: the klass to be used for the vertex clusters. + * @s: the simplified surface. + * @bbox: bounding box of the surface to be simplified. + * @delta: the size of one grid cell of the simplification grid. + * + * Returns: a new #GtsClusterGrid. + */ +GtsClusterGrid * gts_cluster_grid_new (GtsClusterGridClass * klass, + GtsClusterClass * cluster_class, + GtsSurface * s, + GtsBBox * bbox, + gdouble delta) +{ + GtsClusterGrid * cluster_grid; + GtsVector size; + + g_return_val_if_fail (klass != NULL, NULL); + g_return_val_if_fail (cluster_class != NULL, NULL); + g_return_val_if_fail (s != NULL, NULL); + g_return_val_if_fail (bbox != NULL, NULL); + g_return_val_if_fail (delta > 0., NULL); + + size[0] = ceil ((bbox->x2 - bbox->x1)/delta); + size[1] = ceil ((bbox->y2 - bbox->y1)/delta); + size[2] = ceil ((bbox->z2 - bbox->z1)/delta); + g_return_val_if_fail (size[0] <= 2.*G_MAXINT + 2. && + size[1] <= 2.*G_MAXINT + 2. && + size[2] <= 2.*G_MAXINT + 2., NULL); + cluster_grid = + GTS_CLUSTER_GRID (gts_object_new (GTS_OBJECT_CLASS (klass))); + cluster_grid->cluster_class = cluster_class; + cluster_grid->surface = s; + cluster_grid->bbox = bbox; + cluster_grid->size[0] = size[0]; + cluster_grid->size[1] = size[1]; + cluster_grid->size[2] = size[2]; + + return cluster_grid; +} + +static GtsClusterId cluster_index (GtsPoint * p, + GtsBBox * bb, + GtsVector n) +{ + GtsClusterId id = {0, 0, 0}; + + g_return_val_if_fail (p->x >= bb->x1 && p->x <= bb->x2, id); + g_return_val_if_fail (p->y >= bb->y1 && p->y <= bb->y2, id); + g_return_val_if_fail (p->z >= bb->z1 && p->z <= bb->z2, id); + + id.x = (guint) (p->x == bb->x2 ? n[0] - 1. : n[0]*(p->x - bb->x1)/(bb->x2 - bb->x1)); + id.y = (guint) (p->y == bb->y2 ? n[1] - 1. : n[1]*(p->y - bb->y1)/(bb->y2 - bb->y1)); + id.z = (guint) (p->z == bb->z2 ? n[2] - 1. : n[2]*(p->z - bb->z1)/(bb->z2 - bb->z1)); + + return id; +} + +static GtsCluster * cluster_grid_add_point (GtsClusterGrid * cluster_grid, + GtsPoint * p, + gpointer data) +{ + GtsClusterId id = cluster_index (p, + cluster_grid->bbox, + cluster_grid->size); + GtsCluster * c = g_hash_table_lookup (cluster_grid->clusters, &id); + + if (c == NULL) { + c = gts_cluster_new (cluster_grid->cluster_class, id, + cluster_grid->surface->vertex_class); + g_hash_table_insert (cluster_grid->clusters, &c->id, c); + } + + gts_cluster_add (c, p, data); + + return c; +} + +/** + * gts_cluster_grid_add_triangle: + * @cluster_grid: a #GtsClusterGrid. + * @p1: a #GtsPoint. + * @p2: a #GtsPoint. + * @p3: a #GtsPoint. + * @data: user data to pass to the cluster add() method. + * + * Adds the triangle defined by @p1, @p2 and @p3 to the respective clusters + * of @cluster_grid. + */ +void gts_cluster_grid_add_triangle (GtsClusterGrid * cluster_grid, + GtsPoint * p1, + GtsPoint * p2, + GtsPoint * p3, + gpointer data) +{ + GtsCluster * c1, * c2, * c3; + + g_return_if_fail (cluster_grid != NULL); + g_return_if_fail (p1 != NULL); + g_return_if_fail (p2 != NULL); + g_return_if_fail (p3 != NULL); + g_return_if_fail (cluster_grid->surface != NULL); + + c1 = cluster_grid_add_point (cluster_grid, p1, data); + c2 = cluster_grid_add_point (cluster_grid, p2, data); + c3 = cluster_grid_add_point (cluster_grid, p3, data); + + if (c1 != c2 && c2 != c3 && c3 != c1) { + GtsVertex * v1, * v2, * v3; + GtsEdge * e1, * e2, * e3; + gboolean new_edge = FALSE; + + v1 = c1->v; v2 = c2->v; v3 = c3->v; + + if ((e1 = GTS_EDGE (gts_vertices_are_connected (v1, v2))) == NULL) { + e1 = gts_edge_new (cluster_grid->surface->edge_class, v1, v2); + new_edge = TRUE; + } + if ((e2 = GTS_EDGE (gts_vertices_are_connected (v2, v3))) == NULL) { + e2 = gts_edge_new (cluster_grid->surface->edge_class, v2, v3); + new_edge = TRUE; + } + if ((e3 = GTS_EDGE (gts_vertices_are_connected (v3, v1))) == NULL) { + e3 = gts_edge_new (cluster_grid->surface->edge_class, v3, v1); + new_edge = TRUE; + } + if (new_edge || !gts_triangle_use_edges (e1, e2, e3)) + gts_surface_add_face (cluster_grid->surface, + gts_face_new (cluster_grid->surface->face_class, + e1, e2, e3)); + } +} + +static void update_cluster (gint * id, GtsCluster * cluster, GtsRange * stats) +{ + gts_cluster_update (cluster); + gts_range_add_value (stats, cluster->n); +} + +/** + * gts_cluster_grid_update: + * @cluster_grid: a #GtsClusterGrid. + * + * Updates the representative vertices of all the clusters of @cluster_grid. + * + * Returns: a #GtsRange describing the statistics for the number of vertices + * added to each cluster of @cluster_grid. + */ +GtsRange gts_cluster_grid_update (GtsClusterGrid * cluster_grid) +{ + GtsRange stats; + + gts_range_init (&stats); + g_return_val_if_fail (cluster_grid != NULL, stats); + + g_hash_table_foreach (cluster_grid->clusters, + (GHFunc) update_cluster, &stats); + gts_range_update (&stats); + + return stats; +} Index: work/obsolete/toporouter/src_3rd/gts/partition.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/partition.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/partition.c (revision 6803) @@ -0,0 +1,1219 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#include "gts.h" + +/* #define DEBUG */ + +/* Graph partition */ + +/** + * gts_graph_partition_edges_cut: + * @partition: a list of @GtsGraph representing a partition. + * + * Returns: the number of edges cut by the partition. + */ +guint gts_graph_partition_edges_cut (GSList * partition) +{ + guint cuts = 0; + + while (partition) { + cuts += gts_graph_edges_cut (partition->data); + partition = partition->next; + } + + return cuts/2; +} + +/** + * gts_graph_partition_edges_cut_weight: + * @partition: a list of @GtsGraph representing a partition. + * + * Returns: the total weight of the edges cut by the partition. + */ +gfloat gts_graph_partition_edges_cut_weight (GSList * partition) +{ + gfloat weight = 0.; + + while (partition) { + weight += gts_graph_edges_cut_weight (partition->data); + partition = partition->next; + } + + return weight/2.; +} + +/** + * gts_graph_partition_print_stats: + * @partition: a list of @GtsGraph representing a partition. + * @fp: a file pointer. + * + * Writes to @fp a summary of the properties of @partition. + */ +void gts_graph_partition_print_stats (GSList * partition, + FILE * fp) +{ + GtsRange weight; + GSList * i; + + g_return_if_fail (partition != NULL); + g_return_if_fail (fp != NULL); + + gts_range_init (&weight); + i = partition; + while (i) { + gts_range_add_value (&weight, gts_graph_weight (i->data)); + i = i->next; + } + gts_range_update (&weight); + + fprintf (fp, + "# parts: %d\n" + "# edge cuts: %5d edge cuts weight: %5g\n" + "# weight: ", + g_slist_length (partition), + gts_graph_partition_edges_cut (partition), + gts_graph_partition_edges_cut_weight (partition)); + gts_range_print (&weight, fp); + fputc ('\n', fp); +} + +/** + * gts_graph_partition_balance: + * @partition: a list of @GtsGraph representing a partition. + * + * Returns: the difference between the maximum and the minimum weight + * of the graphs in @partition. + */ +gfloat gts_graph_partition_balance (GSList * partition) +{ + gfloat wmin = G_MAXFLOAT; + gfloat wmax = - G_MAXFLOAT; + + g_return_val_if_fail (partition != NULL, 0.); + + while (partition) { + gfloat weight = gts_graph_weight (partition->data); + if (weight < wmin) + wmin = weight; + if (weight > wmax) + wmax = weight; + partition = partition->next; + } + return wmax - wmin; +} + +/** + * gts_graph_partition_clone: + * @partition: a list of @GtsGraph representing a partition. + * + * Returns: a new partition clone of @partition (i.e. a list of new + * graphs clones of the graphs in @partition). + */ +GSList * gts_graph_partition_clone (GSList * partition) +{ + GSList * cparts = NULL; + + while (partition) { + cparts = + g_slist_prepend (cparts, + gts_object_clone (GTS_OBJECT (partition->data))); + partition = partition->next; + } + return cparts; +} + +/** + * gts_graph_partition_destroy: + * @partition: a list of @GtsGraph representing a partition. + * + * Destroys all the graphs in @partition and frees @partition. + */ +void gts_graph_partition_destroy (GSList * partition) +{ + GSList * i = partition; + + while (i) { + gts_object_destroy (GTS_OBJECT (i->data)); + i = i->next; + } + g_slist_free (partition); +} + +static void find_smallest_degree (GtsGNode * n, gpointer * data) +{ + GtsGNode ** nmin = data[0]; + GtsGraph * g = data[1]; + guint * min = data[2]; + guint degree = gts_gnode_degree (n, g); + + if (degree < *min) { + *min = degree; + *nmin = n; + } +} + +static gint graph_comp_weight (GtsGraph * g1, GtsGraph * g2) +{ + if (gts_graph_weight (g1) > gts_graph_weight (g2)) + return 1; + return -1; +} + +static void partition_update (GSList * list, GtsGraph * g) +{ + GSList * i; + GtsGraph * g1; + GtsHeap * size_heap; + gboolean reinit = TRUE; + + /* initialize traversals */ + i = list; + while (i) { + GtsGNode * seed = GTS_OBJECT (i->data)->reserved; + GTS_OBJECT (seed)->reserved = + gts_graph_traverse_new (g, seed, GTS_BREADTH_FIRST, reinit); + reinit = FALSE; + i = i->next; + } + + size_heap = gts_heap_new ((GCompareFunc) graph_comp_weight); + i = list; + while (i) { + gts_heap_insert (size_heap, i->data); + i = i->next; + } + while ((g1 = gts_heap_remove_top (size_heap))) { + GtsGraphTraverse * t = GTS_OBJECT (GTS_OBJECT (g1)->reserved)->reserved; + GtsGNode * n = gts_graph_traverse_next (t); + if (n) { + gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); + gts_heap_insert (size_heap, g1); + } + } + gts_heap_destroy (size_heap); + + /* destroy traversals */ + i = list; + while (i) { + GtsGNode * seed = GTS_OBJECT (i->data)->reserved; + gts_graph_traverse_destroy (GTS_OBJECT (seed)->reserved); + GTS_OBJECT (seed)->reserved = NULL; + i = i->next; + } +} + +static void better_seed (GtsGNode * n, gpointer * data) +{ + guint * sum = data[0]; + GtsGNode ** seed = data[1]; + GtsGraph * g = data[2]; + guint sum1 = gts_graph_distance_sum (g, n); + + if (sum1 < *sum) { + *sum = sum1; + *seed = n; + } +} + +static GtsGNode * graph_new_seed (GtsGraph * g, GtsGNode * seed) +{ + guint sum = gts_graph_distance_sum (g, seed); + gpointer data[3]; + GtsGNode * new_seed = seed; + + data[0] = ∑ + data[1] = &new_seed; + data[2] = g; + gts_gnode_foreach_neighbor (seed, g, (GtsFunc) better_seed, data); + + return new_seed; +} + +/** + * gts_graph_bubble_partition: + * @g: a #GtsGraph. + * @np: number of partitions. + * @niter: the maximum number of iterations. + * @step_info: a #GtsFunc or %NULL. + * @data: user data to pass to @step_info. + * + * An implementation of the "bubble partitioning algorithm" of + * Diekmann, Preis, Schlimbach and Walshaw (2000). The maximum number + * of iteration on the positions of the graph growing seeds is + * controlled by @niter. + * + * If not %NULL @step_info is called after each iteration on the seeds + * positions passing the partition (a GSList) as argument. + * + * Returns: a list of @np new #GtsGraph representing the partition. + */ +GSList * gts_graph_bubble_partition (GtsGraph * g, + guint np, + guint niter, + GtsFunc step_info, + gpointer data) +{ + GSList * list = NULL, * seeds = NULL; + GtsGNode * seed = NULL; + guint min = G_MAXINT/2 - 1; + gpointer info[3]; + GtsGraph * g1; + gboolean changed = TRUE; + + g_return_val_if_fail (g != NULL, NULL); + g_return_val_if_fail (np > 0, NULL); + + info[0] = &seed; + info[1] = g; + info[2] = &min; + gts_container_foreach (GTS_CONTAINER (g), + (GtsFunc) find_smallest_degree, + info); + if (seed == NULL) + return NULL; + + g1 = GTS_GRAPH (gts_object_new (GTS_OBJECT (g)->klass)); + gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed)); + list = g_slist_prepend (list, g1); + GTS_OBJECT (g1)->reserved = seed; + seeds = g_slist_prepend (seeds, seed); + + while (--np && seed) + if ((seed = gts_graph_farthest (g, seeds))) { + g1 = GTS_GRAPH (gts_object_new (GTS_OBJECT (g)->klass)); + gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed)); + list = g_slist_prepend (list, g1); + GTS_OBJECT (g1)->reserved = seed; + seeds = g_slist_prepend (seeds, seed); + } + g_slist_free (seeds); + + partition_update (list, g); + + while (changed && niter--) { + GSList * i; + + changed = FALSE; + i = list; + while (i) { + GtsGraph * g1 = i->data; + GtsGNode * seed = GTS_OBJECT (g1)->reserved; + GtsGNode * new_seed = graph_new_seed (g1, seed); + if (new_seed != seed) { + changed = TRUE; + GTS_OBJECT (g1)->reserved = new_seed; + } + i = i->next; + } + + if (changed) { + i = list; + while (i) { + GtsGraph * g1 = i->data; + GtsGNode * seed = GTS_OBJECT (g1)->reserved; + + gts_object_destroy (GTS_OBJECT (g1)); + i->data = g1 = GTS_GRAPH (gts_object_new (GTS_OBJECT (g)->klass)); + gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed)); + GTS_OBJECT (g1)->reserved = seed; + i = i->next; + } + partition_update (list, g); + if (step_info) + (* step_info) (list, data); + } + } + g_slist_foreach (list, (GFunc) gts_object_reset_reserved, NULL); + return list; +} + +/* Graph bisection */ + +static gdouble node_cost (GtsGNode * n, gpointer * data) +{ + GtsGraph * g = data[0]; + GtsGraph * g1 = data[1]; + GSList * i = GTS_SLIST_CONTAINER (n)->items; + gdouble cost = 0.; + + while (i) { + GtsGEdge * e = i->data; + GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, e); + + if (gts_containee_is_contained (GTS_CONTAINEE (n1), GTS_CONTAINER (g))) { + if (gts_containee_is_contained (GTS_CONTAINEE (n1), GTS_CONTAINER (g1))) + cost -= gts_gedge_weight (e); + else + cost += gts_gedge_weight (e); + } + i = i->next; + } + + return cost; +} + +static void add_neighbor (GtsGNode * n, GtsEHeap * heap) +{ + if (GTS_OBJECT (n)->reserved == n) + return; + if (GTS_OBJECT (n)->reserved) + gts_eheap_remove (heap, GTS_OBJECT (n)->reserved); + GTS_OBJECT (n)->reserved = gts_eheap_insert (heap, n); +} + +static void add_unused (GtsGNode * n, GtsGraph * g2) +{ + if (GTS_OBJECT (n)->reserved) + GTS_OBJECT (n)->reserved = NULL; + else + gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n)); +} + +static gdouble degree_cost (GtsGNode * n, GtsGraph * g) +{ + return gts_gnode_degree (n, g); +} + +static void add_seed (GtsGNode * n, GtsEHeap * heap) +{ + gts_eheap_insert (heap, n); +} + +static void boundary_node1 (GtsGNode * n, GtsGraphBisection * bg) +{ + GSList * i = GTS_SLIST_CONTAINER (n)->items; + + while (i) { + GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); + if (gts_containee_is_contained (GTS_CONTAINEE (n1), + GTS_CONTAINER (bg->g2))) { + g_hash_table_insert (bg->bg1, n, n1); + return; + } + i = i->next; + } +} + +static void boundary_node2 (GtsGNode * n, GtsGraphBisection * bg) +{ + GSList * i = GTS_SLIST_CONTAINER (n)->items; + + while (i) { + GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); + if (gts_containee_is_contained (GTS_CONTAINEE (n1), + GTS_CONTAINER (bg->g1))) { + g_hash_table_insert (bg->bg2, n, n1); + return; + } + i = i->next; + } +} + +static void check_bg (GtsGNode * n, gpointer * data) +{ + GHashTable * bg = data[0]; + GtsGraph * g = data[1]; + gboolean * ok = data[2]; + guint * nb = data[3]; + guint nn = gts_gnode_degree (n, g); + + if (nn > 0) + (*nb)++; + if ((nn > 0 && !g_hash_table_lookup (bg, n)) || + (nn == 0 && g_hash_table_lookup (bg, n))) { + g_warning ("nn: %d lookup: %p\n", + nn, g_hash_table_lookup (bg, n)); + *ok = FALSE; + } +} + +/** + * gts_graph_bisection_check: + * @bg: a #GtsGraphBisection. + * + * Checks that the boundary of @bg is correctly defined (used for + * debugging purposes). + * + * Returns: %TRUE if @bg is ok, %FALSE otherwise. + */ +gboolean gts_graph_bisection_check (GtsGraphBisection * bg) +{ + gboolean ok = TRUE; + guint nb; + gpointer data[4]; + + g_return_val_if_fail (bg != NULL, FALSE); + + nb = 0; + data[0] = bg->bg1; + data[1] = bg->g2; + data[2] = &ok; + data[3] = &nb; + gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) check_bg, data); + g_return_val_if_fail (g_hash_table_size (bg->bg1) == nb, FALSE); + + nb = 0; + data[0] = bg->bg2; + data[1] = bg->g1; + gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) check_bg, data); + g_return_val_if_fail (g_hash_table_size (bg->bg2) == nb, FALSE); + + return ok; +} + +/** + * gts_graph_ggg_bisection: + * @g: a #GtsGraph. + * @ntry: the number of randomly selected initial seeds. + * + * An implementation of the "Greedy Graph Growing" algorithm of + * Karypis and Kumar (1997). + * + * @ntry randomly chosen seeds are used and the best partition is retained. + * + * Returns: a new #GtsGraphBisection of @g. + */ +GtsGraphBisection * gts_graph_ggg_bisection (GtsGraph * g, guint ntry) +{ + gfloat size, bestcost = G_MAXFLOAT, smin; + GtsGraph * bestg1 = NULL, * bestg2 = NULL; + gboolean balanced = FALSE; + GtsEHeap * degree_heap; + GtsGNode * seed; + GtsGraphBisection * bg; + + g_return_val_if_fail (g != NULL, NULL); + + bg = g_malloc (sizeof (GtsGraphBisection)); + bg->g = g; + + size = gts_graph_weight (g)/2.; + smin = 0.9*size; + + degree_heap = gts_eheap_new ((GtsKeyFunc) degree_cost, g); + gts_eheap_freeze (degree_heap); + gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_seed, degree_heap); + gts_eheap_thaw (degree_heap); + + while (ntry && ((seed = gts_eheap_remove_top (degree_heap, NULL)))) { + GtsGraph * g1, * g2; + GtsGNode * n; + gdouble cost; + gpointer data[2]; + GtsEHeap * heap; + + g1 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass), + g->node_class, g->edge_class); + g2 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass), + g->node_class, g->edge_class); + + data[0] = g; + data[1] = g1; + heap = gts_eheap_new ((GtsKeyFunc) node_cost, data); + + gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (seed)); + GTS_OBJECT (seed)->reserved = seed; + gts_gnode_foreach_neighbor (seed, g, (GtsFunc) add_neighbor, heap); + + while ((n = gts_eheap_remove_top (heap, &cost))) + if (gts_graph_weight (g1) + gts_gnode_weight (n) <= size) { + gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); + GTS_OBJECT (n)->reserved = n; + gts_gnode_foreach_neighbor (n, g, (GtsFunc) add_neighbor, heap); + } + else + GTS_OBJECT (n)->reserved = NULL; + gts_eheap_destroy (heap); + + gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_unused, g2); + + cost = gts_graph_edges_cut_weight (g1); + if (!bestg1 || + (!balanced && gts_graph_weight (g1) >= smin) || + (cost < bestcost && gts_graph_weight (g1) >= smin)) { + if (bestg1) + bestcost = cost; + if (bestg1) + gts_object_destroy (GTS_OBJECT (bestg1)); + if (bestg2) + gts_object_destroy (GTS_OBJECT (bestg2)); + bestg1 = g1; + bestg2 = g2; + if (gts_graph_weight (g1) >= smin) + balanced = TRUE; + } + else { + gts_object_destroy (GTS_OBJECT (g1)); + gts_object_destroy (GTS_OBJECT (g2)); + } + + ntry--; + } + gts_eheap_destroy (degree_heap); + +#ifdef DEBUG + fprintf (stderr, "bestcost: %5g g1: %5g|%5d g2: %5g|%5d\n", + bestcost, + gts_graph_weight (bestg1), + gts_container_size (GTS_CONTAINER (bestg1)), + gts_graph_weight (bestg2), + gts_container_size (GTS_CONTAINER (bestg2))); +#endif + + g_assert (bestg1 != NULL); + bg->g1 = bestg1; + g_assert (bestg2 != NULL); + bg->g2 = bestg2; + + /* boundary nodes */ + bg->bg1 = g_hash_table_new (NULL, NULL); + gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) boundary_node1, bg); + bg->bg2 = g_hash_table_new (NULL, NULL); + gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) boundary_node2, bg); + + return bg; +} + +/** + * gts_graph_bfgg_bisection: + * @g: a #GtsGraph. + * @ntry: the number of randomly selected initial seeds. + * + * An implementation of a "Breadth-First Graph Growing" algorithm. + * + * @ntry randomly chosen seeds are used and the best partition is retained. + * + * Returns: a new #GtsGraphBisection of @g. + */ +GtsGraphBisection * gts_graph_bfgg_bisection (GtsGraph * g, guint ntry) +{ + gfloat size, bestcost = G_MAXFLOAT, smin; + GtsGraph * bestg1 = NULL, * bestg2 = NULL; + GtsEHeap * degree_heap; + GtsGNode * seed; + GtsGraphBisection * bg; + + g_return_val_if_fail (g != NULL, NULL); + + bg = g_malloc (sizeof (GtsGraphBisection)); + bg->g = g; + + size = gts_graph_weight (g)/2.; + smin = 0.9*size; + + degree_heap = gts_eheap_new ((GtsKeyFunc) degree_cost, g); + gts_eheap_freeze (degree_heap); + gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_seed, degree_heap); + gts_eheap_thaw (degree_heap); + + while (ntry && ((seed = gts_eheap_remove_top (degree_heap, NULL)))) { + GtsGraph * g1, * g2; + GtsGNode * n; + gdouble cost; + GtsGraphTraverse * t = gts_graph_traverse_new (g, seed, + GTS_BREADTH_FIRST, TRUE); + + g1 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass), + g->node_class, g->edge_class); + g2 = gts_graph_new (GTS_GRAPH_CLASS (GTS_OBJECT (g)->klass), + g->node_class, g->edge_class); + + while ((n = gts_graph_traverse_next (t))) + if (gts_graph_weight (g1) + gts_gnode_weight (n) <= size) { + gts_container_add (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); + GTS_OBJECT (n)->reserved = n; + } + gts_graph_traverse_destroy (t); + + gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) add_unused, g2); + + cost = gts_graph_edges_cut_weight (g1); + if (!bestg1 || (cost < bestcost && gts_graph_weight (g1) >= smin)) { + if (bestg1) + bestcost = cost; + if (bestg1) + gts_object_destroy (GTS_OBJECT (bestg1)); + if (bestg2) + gts_object_destroy (GTS_OBJECT (bestg2)); + bestg1 = g1; + bestg2 = g2; + } + else { + gts_object_destroy (GTS_OBJECT (g1)); + gts_object_destroy (GTS_OBJECT (g2)); + } + + ntry--; + } + gts_eheap_destroy (degree_heap); + +#ifdef DEBUG + fprintf (stderr, "bestcost: %5g g1: %5g|%5d g2: %5g|%5d\n", + bestcost, + gts_graph_weight (bestg1), + gts_container_size (GTS_CONTAINER (bestg1)), + gts_graph_weight (bestg2), + gts_container_size (GTS_CONTAINER (bestg2))); +#endif + + bg->g1 = bestg1; + bg->g2 = bestg2; + + /* boundary nodes */ + bg->bg1 = g_hash_table_new (NULL, NULL); + gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) boundary_node1, bg); + bg->bg2 = g_hash_table_new (NULL, NULL); + gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) boundary_node2, bg); + + return bg; +} + +static gdouble node_move_cost1 (GtsGNode * n, GtsGraphBisection * bg) +{ + return gts_gnode_move_cost (n, bg->g1, bg->g2); +} + +static gdouble node_move_cost2 (GtsGNode * n, GtsGraphBisection * bg) +{ + return gts_gnode_move_cost (n, bg->g2, bg->g1); +} + +static void build_heap (GtsGNode * n, GtsEHeap * heap) +{ + GTS_OBJECT (n)->reserved = gts_eheap_insert (heap, n); +} + +/** + * gts_graph_bisection_kl_refine: + * @bg: a #GtsGraphBisection. + * @mmax: the maximum number of unsuccessful successive moves. + * + * An implementation of the simplified Kernighan-Lin algorithm for + * graph bisection refinement as described in Karypis and Kumar + * (1997). + * + * The algorithm stops if @mmax consecutive modes do not lead to a + * decrease in the number of edges cut. This last @mmax moves are + * undone. + * + * Returns: the decrease in the weight of the edges cut by the bisection. + */ +gdouble gts_graph_bisection_kl_refine (GtsGraphBisection * bg, + guint mmax) +{ + GtsEHeap * h1, * h2; + GtsGNode * n; + guint nm = 0, i; + GtsGNode ** moves; + gdouble bestcost = 0., totalcost = 0., best_balance; + + g_return_val_if_fail (bg != NULL, 0.); + g_return_val_if_fail (mmax > 0, 0.); + + h1 = gts_eheap_new ((GtsKeyFunc) node_move_cost1, bg); + gts_eheap_freeze (h1); + gts_container_foreach (GTS_CONTAINER (bg->g1), (GtsFunc) build_heap, h1); + gts_eheap_thaw (h1); + + h2 = gts_eheap_new ((GtsKeyFunc) node_move_cost2, bg); + gts_eheap_freeze (h2); + gts_container_foreach (GTS_CONTAINER (bg->g2), (GtsFunc) build_heap, h2); + gts_eheap_thaw (h2); + + moves = g_malloc (sizeof (GtsGNode *)*mmax); + best_balance = fabs (gts_graph_weight (bg->g1) - gts_graph_weight (bg->g2)); + + do { + GtsGraph * g1, * g2; + gdouble cost; + + if (gts_graph_weight (bg->g1) > gts_graph_weight (bg->g2)) { + n = gts_eheap_remove_top (h1, &cost); + g1 = bg->g1; + g2 = bg->g2; + } + else { + n = gts_eheap_remove_top (h2, &cost); + g1 = bg->g2; + g2 = bg->g1; + } + if (n) { + GSList * i; + + GTS_OBJECT (n)->reserved = NULL; + gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n)); + gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); + + totalcost += cost; + if (totalcost < bestcost) { + bestcost = totalcost; + nm = 0; + } + else if (totalcost == bestcost) { + gdouble balance = fabs (gts_graph_weight (g1) - gts_graph_weight (g2)); + + if (balance < best_balance) { + best_balance = balance; + nm = 0; + } + } + else + moves[nm++] = n; + + i = GTS_SLIST_CONTAINER (n)->items; + while (i) { + GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); + if (GTS_OBJECT (n1)->reserved && + gts_containee_is_contained (GTS_CONTAINEE (n1), + GTS_CONTAINER (bg->g))) { + GtsEHeap * h = + gts_containee_is_contained (GTS_CONTAINEE (n1), + GTS_CONTAINER (bg->g1)) ? h1 : h2; + gts_eheap_remove (h, GTS_OBJECT (n1)->reserved); + GTS_OBJECT (n1)->reserved = gts_eheap_insert (h, n1); + } + i = i->next; + } + } + } while (n && nm < mmax); + + gts_eheap_foreach (h1, (GFunc) gts_object_reset_reserved, NULL); + gts_eheap_foreach (h2, (GFunc) gts_object_reset_reserved, NULL); + gts_eheap_destroy (h1); + gts_eheap_destroy (h2); + + /* undo last nm moves */ + for (i = 0; i < nm; i++) { + GtsGNode * n = moves[i]; + GtsGraph * g1 = + gts_containee_is_contained (GTS_CONTAINEE (n), + GTS_CONTAINER (bg->g1)) ? bg->g1 : bg->g2; + GtsGraph * g2 = g1 == bg->g1 ? bg->g2 : bg->g1; + + gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n)); + gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); + } + g_free (moves); + + return bestcost; +} + +static void build_bheap (GtsGNode * n, GtsGNode * n1, GtsEHeap * heap) +{ + GTS_OBJECT (n)->reserved = gts_eheap_insert (heap, n); +} + +static void update_neighbors (GtsGNode * n, GtsGraphBisection * bg, + GtsEHeap * h1, GtsEHeap * h2) +{ + GSList * i; + + i = GTS_SLIST_CONTAINER (n)->items; + while (i) { + GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); + if (gts_containee_is_contained (GTS_CONTAINEE (n1), + GTS_CONTAINER (bg->g))) { + GtsEHeap * h; + GtsGraph /* * g1,*/ * g2; + GHashTable * bg1; + + if (gts_containee_is_contained (GTS_CONTAINEE (n1), + GTS_CONTAINER (bg->g1))) { + h = h1; + //g1 = bg->g1; + g2 = bg->g2; + bg1 = bg->bg1; + } + else { + h = h2; + //g1 = bg->g2; + g2 = bg->g1; + bg1 = bg->bg2; + } + g_hash_table_remove (bg1, n1); + if (h && GTS_OBJECT (n1)->reserved && GTS_OBJECT (n1)->reserved != n1) { + gts_eheap_remove (h, GTS_OBJECT (n1)->reserved); + GTS_OBJECT (n1)->reserved = NULL; + } + if (gts_gnode_degree (n1, g2)) { + g_hash_table_insert (bg1, n1, n1); + if (h && GTS_OBJECT (n1)->reserved != n1) + GTS_OBJECT (n1)->reserved = gts_eheap_insert (h, n1); + } + } + i = i->next; + } +} + +/** + * gts_graph_bisection_bkl_refine: + * @bg: a #GtsGraphBisection. + * @mmax: the maximum number of unsuccessful successive moves. + * @imbalance: the maximum relative imbalance allowed between the + * weights of both halves of the partition. + * + * An implementation of the simplified boundary Kernighan-Lin + * algorithm for graph bisection refinement as described in Karypis + * and Kumar (1997). + * + * The algorithm stops if @mmax consecutive modes do not lead to a + * decrease in the number of edges cut. This last @mmax moves are + * undone. + * + * Returns: the decrease in the weight of the edges cut by the bisection. + */ +gdouble gts_graph_bisection_bkl_refine (GtsGraphBisection * bg, + guint mmax, + gfloat imbalance) +{ + GtsEHeap * h1, * h2; + GtsGNode * n; + guint nm = 0, i; + GtsGNode ** moves; + gdouble bestcost = 0., totalcost = 0., best_balance; + gboolean balanced = FALSE; + + g_return_val_if_fail (bg != NULL, 0.); + g_return_val_if_fail (mmax > 0, 0.); + g_return_val_if_fail (imbalance >= 0. && imbalance <= 1., 0.); + + h1 = gts_eheap_new ((GtsKeyFunc) node_move_cost1, bg); + gts_eheap_freeze (h1); + g_hash_table_foreach (bg->bg1, (GHFunc) build_bheap, h1); + gts_eheap_thaw (h1); + + h2 = gts_eheap_new ((GtsKeyFunc) node_move_cost2, bg); + gts_eheap_freeze (h2); + g_hash_table_foreach (bg->bg2, (GHFunc) build_bheap, h2); + gts_eheap_thaw (h2); + + moves = g_malloc (sizeof (GtsGNode *)*mmax); + imbalance *= gts_graph_weight (bg->g); + best_balance = fabs (gts_graph_weight (bg->g1) - gts_graph_weight (bg->g2)); + if (best_balance <= imbalance) + balanced = TRUE; + + do { + GtsGraph * g1, * g2; + GHashTable * bg1, * bg2; + gdouble cost; + + if (gts_graph_weight (bg->g1) > gts_graph_weight (bg->g2)) { + n = gts_eheap_remove_top (h1, &cost); + g1 = bg->g1; + g2 = bg->g2; + bg1 = bg->bg1; + bg2 = bg->bg2; + } + else { + n = gts_eheap_remove_top (h2, &cost); + g1 = bg->g2; + g2 = bg->g1; + bg1 = bg->bg2; + bg2 = bg->bg1; + } + if (n) { + gdouble balance; + + GTS_OBJECT (n)->reserved = n; + gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n)); + gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); + g_hash_table_remove (bg1, n); + if (gts_gnode_degree (n, g1)) + g_hash_table_insert (bg2, n, n); + + update_neighbors (n, bg, h1, h2); + + totalcost += cost; + balance = fabs (gts_graph_weight (g1) - gts_graph_weight (g2)); + + if (!balanced && balance <= imbalance) { + bestcost = totalcost; + best_balance = balance; + balanced = TRUE; + nm = 0; + } + else if (totalcost < bestcost && + (balance < best_balance || balance <= imbalance)) { + bestcost = totalcost; + best_balance = balance; + nm = 0; + } + else if (totalcost == bestcost && balance < best_balance) { + best_balance = balance; + nm = 0; + } + else + moves[nm++] = n; + } + } while (n && nm < mmax); + + gts_container_foreach (GTS_CONTAINER (bg->g), + (GtsFunc) gts_object_reset_reserved, NULL); + gts_eheap_destroy (h1); + gts_eheap_destroy (h2); + + /* undo last nm moves */ + for (i = 0; i < nm; i++) { + GtsGNode * n = moves[i]; + GtsGraph * g1, * g2; + GHashTable * bg1, * bg2; + + if (gts_containee_is_contained (GTS_CONTAINEE (n), + GTS_CONTAINER (bg->g1))) { + g1 = bg->g1; + g2 = bg->g2; + bg1 = bg->bg1; + bg2 = bg->bg2; + } + else { + g1 = bg->g2; + g2 = bg->g1; + bg1 = bg->bg2; + bg2 = bg->bg1; + } + + gts_container_add (GTS_CONTAINER (g2), GTS_CONTAINEE (n)); + gts_container_remove (GTS_CONTAINER (g1), GTS_CONTAINEE (n)); + g_hash_table_remove (bg1, n); + if (gts_gnode_degree (n, g1)) + g_hash_table_insert (bg2, n, n); + + update_neighbors (n, bg, NULL, NULL); + } + g_free (moves); + + return bestcost; +} + +/* Multilevel partitioning */ + +static void bisection_children (GtsGNodeSplit * ns, GtsGraphBisection * bg) +{ + GtsGraph * g, * g1; + GHashTable * bbg; + GtsGNode * n1 = GTS_GNODE_SPLIT_N1 (ns); + GtsGNode * n2 = GTS_GNODE_SPLIT_N2 (ns); + + if (gts_containee_is_contained (GTS_CONTAINEE (ns->n), + GTS_CONTAINER (bg->g1))) { + g = bg->g1; + g1 = bg->g2; + bbg = bg->bg1; + } + else { + g = bg->g2; + g1 = bg->g1; + bbg = bg->bg2; + } + + gts_allow_floating_gnodes = TRUE; + gts_container_remove (GTS_CONTAINER (g), GTS_CONTAINEE (ns->n)); + gts_allow_floating_gnodes = FALSE; + gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (n1)); + gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (n2)); + + if (g_hash_table_lookup (bbg, ns->n)) { + g_hash_table_remove (bbg, ns->n); + if (gts_gnode_degree (n1, g1) > 0) + g_hash_table_insert (bbg, n1, n1); + if (gts_gnode_degree (n2, g1) > 0) + g_hash_table_insert (bbg, n2, n2); + } +} + +/** + * gts_graph_bisection_new: + * @wg: a #GtsWGraph. + * @ntry: the number of tries for the graph growing algorithm. + * @mmax: the number of unsucessful moves for the refinement algorithm. + * @nmin: the minimum number of nodes of the coarsest graph. + * @imbalance: the maximum relative imbalance allowed between the + * weights of both halves of the partition. + * + * An implementation of a multilevel bisection algorithm as presented + * in Karypis and Kumar (1997). A multilevel hierarchy of graphs is + * created using the #GtsPGraph object. The bisection of the coarsest + * graph is created using the gts_graph_ggg_bisection() function. The + * graph is then uncoarsened using gts_pgraph_down() and at each level + * the bisection is refined using gts_graph_bisection_bkl_refine(). + * + * Returns: a new #GtsGraphBisection of @wg. + */ +GtsGraphBisection * gts_graph_bisection_new (GtsWGraph * wg, + guint ntry, + guint mmax, + guint nmin, + gfloat imbalance) +{ + GtsGraph * g; + GtsPGraph * pg; + GtsGraphBisection * bg; + gdouble cost; + + g_return_val_if_fail (wg != NULL, NULL); + + g = GTS_GRAPH (wg); + pg = gts_pgraph_new (gts_pgraph_class (), g, + gts_gnode_split_class (), + gts_wgnode_class (), + gts_wgedge_class (), + nmin); + + bg = gts_graph_ggg_bisection (g, ntry); +#ifdef DEBUG + fprintf (stderr, "before size: %5d weight: %5g cuts: %5d cweight: %5g\n", + gts_container_size (GTS_CONTAINER (bg->g1)), + gts_graph_weight (bg->g1), + gts_graph_edges_cut (bg->g1), + gts_graph_edges_cut_weight (bg->g1)); + g_assert (gts_graph_bisection_check (bg)); +#endif + while ((cost = gts_graph_bisection_bkl_refine (bg, mmax, imbalance))) { +#ifdef DEBUG + fprintf (stderr, " cost: %g\n", cost); + g_assert (gts_graph_bisection_check (bg)); +#endif + } +#ifdef DEBUG + fprintf (stderr, "after size: %5d weight: %5g cuts: %5d cweight: %5g\n", + gts_container_size (GTS_CONTAINER (bg->g1)), + gts_graph_weight (bg->g1), + gts_graph_edges_cut (bg->g1), + gts_graph_edges_cut_weight (bg->g1)); +#endif + while (gts_pgraph_down (pg, (GtsFunc) bisection_children, bg)) { +#ifdef DEBUG + fprintf (stderr, "before size: %5d weight: %5g cuts: %5d cweight: %5g\n", + gts_container_size (GTS_CONTAINER (bg->g1)), + gts_graph_weight (bg->g1), + gts_graph_edges_cut (bg->g1), + gts_graph_edges_cut_weight (bg->g1)); +#endif + while ((cost = gts_graph_bisection_bkl_refine (bg, mmax, imbalance))) { +#ifdef DEBUG + fprintf (stderr, " cost: %g\n", cost); + g_assert (gts_graph_bisection_check (bg)); +#endif + } +#ifdef DEBUG + fprintf (stderr, "after size: %5d weight: %5g cuts: %5d cweight: %5g\n", + gts_container_size (GTS_CONTAINER (bg->g1)), + gts_graph_weight (bg->g1), + gts_graph_edges_cut (bg->g1), + gts_graph_edges_cut_weight (bg->g1)); +#endif + } + gts_object_destroy (GTS_OBJECT (pg)); + + return bg; +} + +/** + * gts_graph_bisection_destroy: + * @bg: a #GtsGraphBisection. + * @destroy_graphs: controls graph destruction. + * + * Frees all the memory allocated for @bg. If @destroy_graphs is %TRUE + * the graphs created by @bg are destroyed. + */ +void gts_graph_bisection_destroy (GtsGraphBisection * bg, + gboolean destroy_graphs) +{ + g_return_if_fail (bg != NULL); + + g_hash_table_destroy (bg->bg1); + g_hash_table_destroy (bg->bg2); + + if (destroy_graphs) { + gts_object_destroy (GTS_OBJECT (bg->g1)); + gts_object_destroy (GTS_OBJECT (bg->g2)); + } + + g_free (bg); +} + +static void recursive_bisection (GtsWGraph * wg, + guint np, + guint ntry, + guint mmax, + guint nmin, + gfloat imbalance, + GSList ** list) +{ + if (np == 0) + *list = g_slist_prepend (*list, wg); + else { + GtsGraphBisection * bg = + gts_graph_bisection_new (wg, ntry, mmax, nmin, imbalance); + GtsGraph * g1 = bg->g1; + GtsGraph * g2 = bg->g2; + + gts_object_destroy (GTS_OBJECT (wg)); + gts_graph_bisection_destroy (bg, FALSE); + recursive_bisection (GTS_WGRAPH (g1), np - 1, ntry, mmax, nmin, imbalance, + list); + recursive_bisection (GTS_WGRAPH (g2), np - 1, ntry, mmax, nmin, imbalance, + list); + } +} + +/** + * gts_graph_recursive_bisection: + * @wg: a #GtsWGraph. + * @n: the number of bisection levels. + * @ntry: the number of tries for the graph growing algorithm. + * @mmax: the number of unsucessful moves for the refinement algorithm. + * @nmin: the minimum number of nodes of the coarsest graph. + * @imbalance: the maximum relative imbalance allowed between the + * weights of both halves of the partition. + * + * Calls gts_graph_bisection_new() recursively in order to obtain a + * 2^@n partition of @wg. + * + * Returns: a list of 2^@n new #GtsGraph representing the partition. + */ +GSList * gts_graph_recursive_bisection (GtsWGraph * wg, + guint n, + guint ntry, + guint mmax, + guint nmin, + gfloat imbalance) +{ + GtsGraphBisection * bg; + GtsGraph * g1, * g2; + GSList * list = NULL; + + g_return_val_if_fail (wg != NULL, NULL); + g_return_val_if_fail (n > 0, NULL); + + bg = gts_graph_bisection_new (wg, ntry, mmax, nmin, imbalance); + g1 = bg->g1; + g2 = bg->g2; + gts_graph_bisection_destroy (bg, FALSE); + recursive_bisection (GTS_WGRAPH (g1), n - 1, ntry, mmax, nmin, imbalance, + &list); + recursive_bisection (GTS_WGRAPH (g2), n - 1, ntry, mmax, nmin, imbalance, + &list); + + return list; +} Index: work/obsolete/toporouter/src_3rd/gts/pgraph.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/pgraph.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/pgraph.c (revision 6803) @@ -0,0 +1,584 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gts.h" + +/* GtsGNodeSplit */ + +static void gnode_split_destroy (GtsObject * object) +{ + GtsGNodeSplit * ns = GTS_GNODE_SPLIT (object); + + if (gts_container_size (GTS_CONTAINER (ns->n)) == 0) { + g_assert (GTS_SLIST_CONTAINEE (ns->n)->containers == NULL); + gts_object_destroy (GTS_OBJECT (ns->n)); + } + else { + /* GtsGNode * n1 = GTS_GNODE_SPLIT_N1 (ns); */ + /* GtsGNode * n2 = GTS_GNODE_SPLIT_N2 (ns); */ + + g_warning ("Memory deallocation for GtsGNodeSplit not fully implemented yet: memory leak!"); + } + + (* GTS_OBJECT_CLASS (gts_gnode_split_class ())->parent_class->destroy) + (object); +} + +static void gnode_split_class_init (GtsGNodeSplitClass * klass) +{ + GTS_OBJECT_CLASS (klass)->destroy = gnode_split_destroy; +} + +static void gnode_split_init (GtsGNodeSplit * ns) +{ + ns->n = NULL; + ns->n1 = ns->n2 = NULL; +} + +/** + * gts_gnode_split_class: + * + * Returns: the #GtsGNodeSplitClass. + */ +GtsGNodeSplitClass * gts_gnode_split_class (void) +{ + static GtsGNodeSplitClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo gnode_split_info = { + "GtsGNodeSplit", + sizeof (GtsGNodeSplit), + sizeof (GtsGNodeSplitClass), + (GtsObjectClassInitFunc) gnode_split_class_init, + (GtsObjectInitFunc) gnode_split_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (gts_object_class (), &gnode_split_info); + } + + return klass; +} + +/** + * gts_gnode_split_new: + * @klass: a #GtsGNodeSplitClass. + * @n: a #GtsGNode. + * @n1: a #GtsGNodeSplit or #GtsGNode. + * @n2: a #GtsGNodeSplit or #GtsGNode. + * + * Creates a new #GtsGNodeSplit which would collapse @n1 and @n2 into + * @n. The collapse itself is not performed. + * + * Returns: the new #GtsGNodeSplit. + */ +GtsGNodeSplit * gts_gnode_split_new (GtsGNodeSplitClass * klass, + GtsGNode * n, + GtsObject * n1, + GtsObject * n2) +{ + GtsGNodeSplit * ns; + + g_return_val_if_fail (klass != NULL, NULL); + g_return_val_if_fail (n != NULL, NULL); + g_return_val_if_fail (GTS_IS_GNODE_SPLIT (n1) || GTS_IS_GNODE (n1), NULL); + g_return_val_if_fail (GTS_IS_GNODE_SPLIT (n2) || GTS_IS_GNODE (n2), NULL); + + ns = GTS_GNODE_SPLIT (gts_object_new (GTS_OBJECT_CLASS (klass))); + ns->n = n; + ns->n1 = n1; + ns->n2 = n2; + + return ns; +} + +static void connect_edge (GtsGEdge * e, gpointer * data) +{ + GtsGNode * n = data[0]; + GtsGNode * n1 = data[1]; + GtsGNode * n2 = data[2]; + + if (GTS_OBJECT (e)->reserved || /* edge is disconnected */ + gts_gedge_connects (e, n1, n2)) + return; + if (e->n1 == n1 || e->n1 == n2) + e->n1 = n; + else if (e->n2 == n1 || e->n2 == n2) + e->n2 = n; + else + g_assert_not_reached (); + gts_container_add (GTS_CONTAINER (n), GTS_CONTAINEE (e)); +} + +/** + * gts_gnode_split_collapse: + * @ns: a #GtsGNodeSplit. + * @g: a #GtsGraph. + * @klass: a #GtsWGEdgeClass. + * + * Collapses the node split @ns. Any new edge created during the + * process will be of class @klass. + */ +void gts_gnode_split_collapse (GtsGNodeSplit * ns, + GtsGraph * g, + GtsWGEdgeClass * klass) +{ + GtsGNode * n1, * n2; + GSList * i; + gpointer data[3]; + + g_return_if_fail (ns != NULL); + g_return_if_fail (g != NULL); + g_return_if_fail (gts_container_size (GTS_CONTAINER (ns->n)) == 0); + + n1 = GTS_GNODE_SPLIT_N1 (ns); + n2 = GTS_GNODE_SPLIT_N2 (ns); + + /* look for triangles */ + i = GTS_SLIST_CONTAINER (n1)->items; + while (i) { + GtsGEdge * e13 = i->data; + GtsGNode * n3 = GTS_GNODE_NEIGHBOR (n1, e13); + if (n3 != n2) { + GSList * j = GTS_SLIST_CONTAINER (n3)->items; + while (j) { + GtsGEdge * e32 = j->data; + GSList * next = j->next; + GtsGNode * n4 = GTS_GNODE_NEIGHBOR (n3, e32); + if (n4 == n2) { /* found triangle n1 (e13) n3 (e32) n2 */ + gts_wgedge_new (klass, ns->n, n3, + gts_gedge_weight (e13) + gts_gedge_weight (e32)); + GTS_OBJECT (e13)->reserved = n3; + GTS_OBJECT (e32)->reserved = n3; + GTS_SLIST_CONTAINER (n3)->items = + g_slist_remove (GTS_SLIST_CONTAINER (n3)->items, e32); + } + j = next; + } + if (GTS_OBJECT (e13)->reserved == n3) + GTS_SLIST_CONTAINER (n3)->items = + g_slist_remove (GTS_SLIST_CONTAINER (n3)->items, e13); + } + i = i->next; + } + + /* connect edges to new node */ + data[0] = ns->n; + data[1] = n1; + data[2] = n2; + gts_container_foreach (GTS_CONTAINER (n1), (GtsFunc) connect_edge, data); + gts_container_foreach (GTS_CONTAINER (n2), (GtsFunc) connect_edge, data); + + gts_allow_floating_gnodes = TRUE; + gts_container_remove (GTS_CONTAINER (g), GTS_CONTAINEE (n1)); + gts_container_remove (GTS_CONTAINER (g), GTS_CONTAINEE (n2)); + gts_allow_floating_gnodes = FALSE; + gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (ns->n)); +} + +static void restore_edge (GtsGEdge * e, gpointer * data) +{ + GtsGNode * n = data[0]; + GtsGNode * n1 = data[1]; + GtsGNode * n2 = data[2]; + GtsGNode * n3 = GTS_OBJECT (e)->reserved; + + if (n3) { /* e is a disconnected edge */ + GTS_OBJECT (e)->reserved = NULL; + gts_container_add (GTS_CONTAINER (n3), GTS_CONTAINEE (e)); + return; + } + + if (gts_gedge_connects (e, n1, n2)) + return; + + if (e->n1 == n) + e->n1 = n1; + else if (e->n2 == n) + e->n2 = n1; + else + g_assert_not_reached (); + GTS_SLIST_CONTAINER (n)->items = + g_slist_remove (GTS_SLIST_CONTAINER (n)->items, e); +} + +/** + * gts_gnode_split_expand: + * @ns: a #GtsGNodeSplit. + * @g: a #GtsGraph. + * + * Expands the node split ns adding the new nodes to @g. + */ +void gts_gnode_split_expand (GtsGNodeSplit * ns, + GtsGraph * g) +{ + GtsGNode * n1, * n2; + gpointer data[3]; + GSList * i; + + g_return_if_fail (ns != NULL); + g_return_if_fail (g != NULL); + g_return_if_fail (gts_containee_is_contained (GTS_CONTAINEE (ns->n), + GTS_CONTAINER (g))); + + n1 = GTS_GNODE_SPLIT_N1 (ns); + n2 = GTS_GNODE_SPLIT_N2 (ns); + + data[0] = ns->n; + data[1] = n1; + data[2] = n2; + gts_container_foreach (GTS_CONTAINER (n1), (GtsFunc) restore_edge, data); + data[1] = n2; + data[2] = n1; + gts_container_foreach (GTS_CONTAINER (n2), (GtsFunc) restore_edge, data); + + i = GTS_SLIST_CONTAINER (ns->n)->items; + while (i) { + GSList * next = i->next; + gts_container_remove (GTS_CONTAINER (ns->n), GTS_CONTAINEE (i->data)); + i = next; + } + g_assert (gts_container_size (GTS_CONTAINER (ns->n)) == 0); + + gts_allow_floating_gnodes = TRUE; + gts_container_remove (GTS_CONTAINER (g), GTS_CONTAINEE (ns->n)); + gts_allow_floating_gnodes = FALSE; + + gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (n1)); + gts_container_add (GTS_CONTAINER (g), GTS_CONTAINEE (n2)); +} + +/* GtsPGraph */ + +static void pgraph_destroy (GtsObject * object) +{ + GtsPGraph * pg = GTS_PGRAPH (object); + guint i; + + for (i = 0; i < pg->split->len; i++) + gts_object_destroy (GTS_OBJECT (g_ptr_array_index (pg->split, i))); + g_ptr_array_free (pg->split, TRUE); + g_array_free (pg->levels, TRUE); + + (* GTS_OBJECT_CLASS (gts_pgraph_class ())->parent_class->destroy) (object); +} + +static void pgraph_class_init (GtsPGraphClass * klass) +{ + GTS_OBJECT_CLASS (klass)->destroy = pgraph_destroy; +} + +static void pgraph_init (GtsPGraph * pg) +{ + pg->g = NULL; + pg->split = g_ptr_array_new (); + pg->levels = g_array_new (FALSE, FALSE, sizeof (guint)); + pg->level = 0; + pg->split_class = gts_gnode_split_class (); + pg->edge_class = gts_wgedge_class (); + pg->pos = pg->min = 0; +} + +/** + * gts_pgraph_class: + * + * Returns: the #GtsPGraphClass. + */ +GtsPGraphClass * gts_pgraph_class (void) +{ + static GtsPGraphClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo pgraph_info = { + "GtsPGraph", + sizeof (GtsPGraph), + sizeof (GtsPGraphClass), + (GtsObjectClassInitFunc) pgraph_class_init, + (GtsObjectInitFunc) pgraph_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (gts_object_class (), &pgraph_info); + } + + return klass; +} + +static void match_neighbor (GtsGNode * n, gpointer * data) +{ + if (!GTS_OBJECT (n)->reserved) { + GtsGraph * g = data[0]; + GSList ** list = data[1]; + GSList * i = GTS_SLIST_CONTAINER (n)->items; + gfloat wmax = - G_MAXFLOAT; + GtsGEdge * emax = NULL; + + while (i) { + GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, i->data); + if (!GTS_OBJECT (n1)->reserved && + gts_gedge_weight (i->data) > wmax && + gts_containee_is_contained (GTS_CONTAINEE (n1), GTS_CONTAINER (g))) { + emax = i->data; + wmax = gts_gedge_weight (emax); + } + i = i->next; + } + if (emax) { + GtsGNode * n1 = GTS_GNODE_NEIGHBOR (n, emax); + + GTS_OBJECT (n1)->reserved = n; + GTS_OBJECT (n)->reserved = n1; + *list = g_slist_prepend (*list, emax); + } + } +} + +static GSList * maximal_matching (GtsGraph * g) +{ + GSList * list = NULL; + gpointer data[2]; + + data[0] = g; + data[1] = &list; + gts_container_foreach (GTS_CONTAINER (g), (GtsFunc) match_neighbor, data); + gts_container_foreach (GTS_CONTAINER (g), + (GtsFunc) gts_object_reset_reserved, + NULL); + + return list; +} + +/** + * gts_pgraph_new: + * @klass: a #GtsPGraphClass. + * @g: a #GtsGraph. + * @split_class: a #GtsGNodeSplitClass. + * @node_class: a #GtsWGNodeClass. + * @edge_class: a #GtsWGEdgeClass. + * @min: the minimum number of nodes. + * + * Creates a new multilevel approximation of graph @g. At each level a + * maximal matching is created using the Heavy Edge Matching (HEM) + * technique of Karypis and Kumar (1997). The newly created nodes are + * of type @node_class and their weight is set to the sum of the + * weights of their children. The newly created edges are of type + * @edge_class and their weight is set to the sum of the weight of the + * collapsed edges. The last level is reached when the maximal + * matching obtained would lead to a graph with less than @min nodes. + * + * Returns: the new #GtsPGraph containing the multilevel + * representation of @g. + */ +GtsPGraph * gts_pgraph_new (GtsPGraphClass * klass, + GtsGraph * g, + GtsGNodeSplitClass * split_class, + GtsWGNodeClass * node_class, + GtsWGEdgeClass * edge_class, + guint min) +{ + GtsPGraph * pg; + GSList * matching; + + g_return_val_if_fail (klass != NULL, NULL); + g_return_val_if_fail (g != NULL, NULL); + g_return_val_if_fail (split_class != NULL, NULL); + g_return_val_if_fail (node_class != NULL, NULL); + g_return_val_if_fail (edge_class != NULL, NULL); + + pg = GTS_PGRAPH (gts_object_new (GTS_OBJECT_CLASS (klass))); + pg->g = g; + pg->split_class = split_class; + pg->edge_class = edge_class; + + while (gts_container_size (GTS_CONTAINER (g)) > min && + (matching = maximal_matching (g))) { + GSList * i = matching; + guint size = gts_container_size (GTS_CONTAINER (g)); + + g_array_append_val (pg->levels, size); + + while (i && gts_container_size (GTS_CONTAINER (g)) > min) { + GtsGEdge * e = i->data; + GtsGNode * n = GTS_GNODE (gts_wgnode_new (node_class, + gts_gnode_weight (e->n1) + + gts_gnode_weight (e->n2))); + GtsGNodeSplit * ns = gts_gnode_split_new (split_class, n, + GTS_OBJECT (e->n1), + GTS_OBJECT (e->n2)); + gts_gnode_split_collapse (ns, g, edge_class); + g_ptr_array_add (pg->split, ns); + i = i->next; + } + g_slist_free (matching); + } + + pg->pos = pg->split->len; + pg->min = gts_container_size (GTS_CONTAINER (g)); + pg->level = pg->levels->len; + + return pg; +} + +/** + * gts_pgraph_add_node: + * @pg: a #GtsPGraph. + * + * Adds one node to the multilevel graph @pg by expanding the next + * available #GtsGNodeSplit. + * + * Returns: the expanded #GtsGNodeSplit or #NULL if all the + * #GtsGNodeSplit have already been expanded. + */ +GtsGNodeSplit * gts_pgraph_add_node (GtsPGraph * pg) +{ + GtsGNodeSplit * ns; + + g_return_val_if_fail (pg != NULL, NULL); + + if (pg->pos == 0) + return NULL; + + ns = g_ptr_array_index (pg->split, --pg->pos); + gts_gnode_split_expand (ns, pg->g); + + return ns; +} + +/** + * gts_pgraph_remove_node: + * @pg: a #GtsPGraph. + * + * Removes one node from the multilevel graph @pg by collapsing the + * first available #GtsGNodeSplit. + * + * Returns: the collapsed #GtsGNodeSplit or %NULL if all the + * #GtsGNodeSplit have already been collapsed. + */ +GtsGNodeSplit * gts_pgraph_remove_node (GtsPGraph * pg) +{ + GtsGNodeSplit * ns; + + g_return_val_if_fail (pg != NULL, NULL); + + if (pg->pos == pg->split->len) + return NULL; + + ns = g_ptr_array_index (pg->split, pg->pos++); + gts_gnode_split_collapse (ns, pg->g, pg->edge_class); + + return ns; +} + +/** + * gts_pgraph_max_node_number: + * @pg: a #GtsPGraph. + * + * Returns: the maximum number of nodes of @pg i.e. the number of + * nodes if all the #GtsGNodeSplit were expanded. + */ +guint gts_pgraph_max_node_number (GtsPGraph * pg) +{ + g_return_val_if_fail (pg != NULL, 0); + + return pg->min + pg->split->len; +} + +/** + * gts_pgraph_min_node_number: + * @pg: a #GtsPGraph. + * + * Returns: the minimum number of nodes of @pg i.e. the number of + * nodes if all the #GtsGNodeSplit were collapsed. + */ +guint gts_pgraph_min_node_number (GtsPGraph * pg) +{ + g_return_val_if_fail (pg != NULL, 0); + + return pg->min; +} + +/** + * gts_pgraph_set_node_number: + * @pg: a #GtsPGraph. + * @n: a number of nodes. + * + * Performs the required number of collapses or expansions to set the + * number of nodes of @pg to @n. + */ +void gts_pgraph_set_node_number (GtsPGraph * pg, guint n) +{ + g_return_if_fail (pg != NULL); + + n = pg->min + pg->split->len - n; + while (pg->pos > n && gts_pgraph_add_node (pg)) + ; + while (pg->pos < n && gts_pgraph_remove_node (pg)) + ; +} + +/** + * gts_pgraph_get_node_number: + * @pg: a #GtsPGraph. + * + * Returns: the current number of nodes of @pg. + */ +guint gts_pgraph_get_node_number (GtsPGraph * pg) +{ + g_return_val_if_fail (pg != NULL, 0); + + return pg->min + pg->split->len - pg->pos; +} + +/** + * gts_pgraph_down: + * @pg: a #GtsPGraph. + * @func: a #GtsFunc or %NULL. + * @data: user data to pass to @func. + * + * Performs the required number of expansions to go from the current + * level to the level immediately below. + * + * If @func is not %NULL, it is called after each #GtsGNodeSplit has + * been expanded. + * + * Returns: %FALSE if it is not possible to go down one level, %TRUE + * otherwise. + */ +gboolean gts_pgraph_down (GtsPGraph * pg, + GtsFunc func, + gpointer data) +{ + guint size; + + g_return_val_if_fail (pg != NULL, FALSE); + + if (pg->level == 0) + return FALSE; + + size = g_array_index (pg->levels, guint, --(pg->level)); + while (gts_container_size (GTS_CONTAINER (pg->g)) < size) { + GtsGNodeSplit * ns = gts_pgraph_add_node (pg); + + g_assert (ns); + if (func) + (* func) (ns, data); + } + return TRUE; +} + Index: work/obsolete/toporouter/src_3rd/gts/point.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/point.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/point.c (revision 6803) @@ -0,0 +1,986 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include "gts.h" +#include "gts-private.h" +#include "predicates.h" + +static void point_read (GtsObject ** o, GtsFile * f) +{ + GtsPoint * p = GTS_POINT (*o); + + if (GTS_POINT_CLASS ((*o)->klass)->binary) { + if (gts_file_read (f, &(p->x), sizeof (gdouble), 1) != 1) { + gts_file_error (f, "expecting a binary number (x coordinate)"); + return; + } + if (gts_file_read (f, &(p->y), sizeof (gdouble), 1) != 1) { + gts_file_error (f, "expecting a binary number (y coordinate)"); + return; + } + if (gts_file_read (f, &(p->z), sizeof (gdouble), 1) != 1) { + gts_file_error (f, "expecting a binary number (z coordinate)"); + return; + } + } + else { + if (f->type != GTS_INT && f->type != GTS_FLOAT) { + gts_file_error (f, "expecting a number (x coordinate)"); + return; + } + p->x = atof (f->token->str); + + gts_file_next_token (f); + if (f->type != GTS_INT && f->type != GTS_FLOAT) { + gts_file_error (f, "expecting a number (y coordinate)"); + return; + } + p->y = atof (f->token->str); + + gts_file_next_token (f); + if (f->type != GTS_INT && f->type != GTS_FLOAT) { + gts_file_error (f, "expecting a number (z coordinate)"); + return; + } + p->z = atof (f->token->str); + + gts_file_next_token (f); + } +} + +static void point_write (GtsObject * o, FILE * fptr) +{ + GtsPoint * p = GTS_POINT (o); + + if (GTS_POINT_CLASS ((o)->klass)->binary) { + fwrite (&(p->x), sizeof (gdouble), 1, fptr); + fwrite (&(p->y), sizeof (gdouble), 1, fptr); + fwrite (&(p->z), sizeof (gdouble), 1, fptr); + } + else + fprintf (fptr, "%.10g %.10g %.10g", p->x, p->y, p->z); +} + +static void point_class_init (GtsObjectClass * klass) +{ + klass->read = point_read; + klass->write = point_write; +} + +/** + * gts_point_class: + * + * Returns: the #GtsPointClass. + */ +GtsPointClass * gts_point_class (void) +{ + static GtsPointClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo point_info = { + "GtsPoint", + sizeof (GtsPoint), + sizeof (GtsPointClass), + (GtsObjectClassInitFunc) point_class_init, + (GtsObjectInitFunc) NULL, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (gts_object_class (), + &point_info); + } + + return klass; +} + +/** + * gts_point_new: + * @klass: a #GtsPointClass. + * @x: the x-coordinate. + * @y: the y-coordinate. + * @z: the z-coordinate. + * + * Returns: a new #GtsPoint. + */ +GtsPoint * gts_point_new (GtsPointClass * klass, + gdouble x, gdouble y, gdouble z) +{ + GtsPoint * p; + + p = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (klass))); + p->x = x; + p->y = y; + p->z = z; + + return p; +} + +/** + * gts_point_set: + * @p: a #GtsPoint. + * @x: the x-coordinate. + * @y: the y-coordinate. + * @z: the z-coordinate. + * + * Sets the coordinates of @p. + */ +void gts_point_set (GtsPoint * p, gdouble x, gdouble y, gdouble z) +{ + g_return_if_fail (p != NULL); + + p->x = x; + p->y = y; + p->z = z; +} + +/** + * gts_point_distance: + * @p1: a #GtsPoint. + * @p2: another #GtsPoint. + * + * Returns: the Euclidean distance between @p1 and @p2. + */ +gdouble gts_point_distance (GtsPoint * p1, GtsPoint * p2) +{ + g_return_val_if_fail (p1 != NULL && p2 != NULL, 0.0); + + return sqrt ((p1->x - p2->x)*(p1->x - p2->x) + + (p1->y - p2->y)*(p1->y - p2->y) + + (p1->z - p2->z)*(p1->z - p2->z)); +} + +/** + * gts_point_distance2: + * @p1: a #GtsPoint. + * @p2: another #GtsPoint. + * + * Returns: the square of the Euclidean distance between @p1 and @p2. + */ +gdouble gts_point_distance2 (GtsPoint * p1, GtsPoint * p2) +{ + g_return_val_if_fail (p1 != NULL && p2 != NULL, 0.0); + + return + (p1->x - p2->x)*(p1->x - p2->x) + + (p1->y - p2->y)*(p1->y - p2->y) + + (p1->z - p2->z)*(p1->z - p2->z); +} + +/** + * gts_point_orientation_3d: + * @p1: a #GtsPoint. + * @p2: a #GtsPoint. + * @p3: a #GtsPoint. + * @p4: a #GtsPoint. + * + * Checks if @p4 lies above, below or on the plane passing through the + * points @p1, @p2 and @p3. Below is defined so that @p1, @p2 and @p3 + * appear in counterclockwise order when viewed from above the + * plane. The returned value is an approximation of six times the + * signed volume of the tetrahedron defined by the four points. This + * function uses adaptive floating point arithmetic and is + * consequently geometrically robust. + * + * Returns: a positive value if @p4 lies below, a negative value if + * @p4 lies above the plane, zero if the four points are coplanar. + */ +gdouble gts_point_orientation_3d (GtsPoint * p1, + GtsPoint * p2, + GtsPoint * p3, + GtsPoint * p4) +{ + g_return_val_if_fail (p1 != NULL && p2 != NULL && + p3 != NULL && p4 != NULL, 0.0); + return orient3d ((gdouble *) &p1->x, + (gdouble *) &p2->x, + (gdouble *) &p3->x, + (gdouble *) &p4->x); +} + +/** + * gts_point_is_in_triangle: + * @p: a #GtsPoint. + * @t: a #GtsTriangle. + * + * Tests if the planar projection (x, y) of @p is inside, outside or + * on the boundary of the planar projection of @t. This function is + * geometrically robust. + * + * Returns: %GTS_IN if @p is inside @t, %GTS_ON if @p is on the boundary of + * @t, %GTS_OUT otherwise. + */ +GtsIntersect gts_point_is_in_triangle (GtsPoint * p, GtsTriangle * t) +{ + GtsVertex * v1, * v2, * v3; + gdouble d1, d2, d3; + + g_return_val_if_fail (p != NULL && t != NULL, FALSE); + + gts_triangle_vertices (t, &v1, &v2, &v3); + + d1 = gts_point_orientation (GTS_POINT (v1), GTS_POINT (v2), p); + if (d1 < 0.0) + return GTS_OUT; + d2 = gts_point_orientation (GTS_POINT (v2), GTS_POINT (v3), p); + if (d2 < 0.0) + return GTS_OUT; + d3 = gts_point_orientation (GTS_POINT (v3), GTS_POINT (v1), p); + if (d3 < 0.0) + return GTS_OUT; + if (d1 == 0.0 || d2 == 0.0 || d3 == 0.0) + return GTS_ON; + return GTS_IN; +} + +/** + * gts_point_in_triangle_circle: + * @p: a #GtsPoint. + * @t: a #GtsTriangle. + * + * Tests if the planar projection (x, y) of @p is inside or outside + * the circumcircle of the planar projection of @t. This function is + * geometrically robust. + * + * Returns: a positive number if @p lies inside, + * a negative number if @p lies outside and zero if @p lies on + * the circumcircle of @t. + */ +gdouble gts_point_in_triangle_circle (GtsPoint * p, GtsTriangle * t) +{ + GtsPoint * p1, * p2, * p3; + + g_return_val_if_fail (p != NULL && t != NULL, 0.0); + + gts_triangle_vertices (t, + (GtsVertex **) &p1, + (GtsVertex **) &p2, + (GtsVertex **) &p3); + + return incircle ((gdouble *) &p1->x, + (gdouble *) &p2->x, + (gdouble *) &p3->x, + (gdouble *) &p->x); +} + +/** + * gts_point_in_circle: + * @p: a #GtsPoint. + * @p1: a #GtsPoint. + * @p2: a #GtsPoint. + * @p3: a #GtsPoint. + * + * Tests if the planar projection (x, y) of @p is inside or outside the + * circle defined by the planar projection of @p1, @p2 and @p3. + * + * Returns: a positive number if @p lies inside, + * a negative number if @p lies outside and zero if @p lies on + * the circle. + */ +gdouble gts_point_in_circle (GtsPoint * p, + GtsPoint * p1, GtsPoint * p2, GtsPoint * p3) +{ + g_return_val_if_fail (p != NULL && p1 != NULL && p2 != NULL && p3 != NULL, + 0.0); + + return incircle ((gdouble *) &p1->x, + (gdouble *) &p2->x, + (gdouble *) &p3->x, + (gdouble *) &p->x); +} + +/** + * gts_point_in_sphere: + * @p: a #GtsPoint. + * @p1: a #GtsPoint. + * @p2: a #GtsPoint. + * @p3: a #GtsPoint. + * @p4: a #GtsPoint. + * + * Tests if @p is inside or outside the sphere defined by @p1, @p2, + * @p3 and @p4. + * + * Returns: a positive number if @p lies inside, + * a negative number if @p lies outside and zero if @p lies on + * the sphere. + */ +gdouble gts_point_in_sphere (GtsPoint * p, + GtsPoint * p1, GtsPoint * p2, GtsPoint * p3, GtsPoint * p4) +{ + g_return_val_if_fail (p != NULL && p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL, + 0.0); + + return insphere ((gdouble *) &p1->x, + (gdouble *) &p2->x, + (gdouble *) &p3->x, + (gdouble *) &p4->x, + (gdouble *) &p->x); +} + +/** + * gts_point_segment_distance2: + * @p: a #GtsPoint. + * @s: a #GtsSegment. + * + * Returns: the square of the minimun Euclidean distance between @p and @s. + */ +gdouble gts_point_segment_distance2 (GtsPoint * p, GtsSegment * s) +{ + gdouble t, ns2, x, y, z; + GtsPoint * p1, * p2; + + g_return_val_if_fail (p != NULL, 0.0); + g_return_val_if_fail (s != NULL, 0.0); + + p1 = GTS_POINT (s->v1); + p2 = GTS_POINT (s->v2); + ns2 = gts_point_distance2 (p1, p2); + if (ns2 == 0.0) + return gts_point_distance2 (p, p1); + t = ((p2->x - p1->x)*(p->x - p1->x) + + (p2->y - p1->y)*(p->y - p1->y) + + (p2->z - p1->z)*(p->z - p1->z))/ns2; + if (t > 1.0) + return gts_point_distance2 (p, p2); + if (t < 0.0) + return gts_point_distance2 (p, p1); + x = (1. - t)*p1->x + t*p2->x - p->x; + y = (1. - t)*p1->y + t*p2->y - p->y; + z = (1. - t)*p1->z + t*p2->z - p->z; + return x*x + y*y + z*z; +} + +/** + * gts_point_segment_distance: + * @p: a #GtsPoint. + * @s: a #GtsSegment. + * + * Returns: the minimun Euclidean distance between @p and @s. + */ +gdouble gts_point_segment_distance (GtsPoint * p, GtsSegment * s) +{ + g_return_val_if_fail (p != NULL, 0.0); + g_return_val_if_fail (s != NULL, 0.0); + + return sqrt (gts_point_segment_distance2 (p, s)); +} + +/** + * gts_point_segment_closest: + * @p: a #GtsPoint. + * @s: a #GtsSegment. + * @closest: a #GtsPoint. + * + * Set the coordinates of @closest to the coordinates of the point belonging + * to @s closest to @p. + */ +void gts_point_segment_closest (GtsPoint * p, + GtsSegment * s, + GtsPoint * closest) +{ + gdouble t, ns2; + GtsPoint * p1, * p2; + + g_return_if_fail (p != NULL); + g_return_if_fail (s != NULL); + g_return_if_fail (closest != NULL); + + p1 = GTS_POINT (s->v1); + p2 = GTS_POINT (s->v2); + ns2 = gts_point_distance2 (p1, p2); + + if (ns2 == 0.0) { + gts_point_set (closest, p1->x, p1->y, p1->z); + return; + } + + t = ((p2->x - p1->x)*(p->x - p1->x) + + (p2->y - p1->y)*(p->y - p1->y) + + (p2->z - p1->z)*(p->z - p1->z))/ns2; + + if (t > 1.0) + gts_point_set (closest, p2->x, p2->y, p2->z); + else if (t < 0.0) + gts_point_set (closest, p1->x, p1->y, p1->z); + else + gts_point_set (closest, + (1. - t)*p1->x + t*p2->x, + (1. - t)*p1->y + t*p2->y, + (1. - t)*p1->z + t*p2->z); +} + +/** + * gts_point_triangle_distance2: + * @p: a #GtsPoint. + * @t: a #GtsTriangle. + * + * Returns: the square of the minimun Euclidean distance between @p and @t. + */ +gdouble gts_point_triangle_distance2 (GtsPoint * p, GtsTriangle * t) +{ + GtsPoint * p1, * p2, * p3; + GtsEdge * e1, * e2, * e3; + GtsVector p1p2, p1p3, pp1; + gdouble A, B, C, D, E, det; + gdouble t1, t2; + gdouble x, y, z; + + g_return_val_if_fail (p != NULL, 0.0); + g_return_val_if_fail (t != NULL, 0.0); + + gts_triangle_vertices_edges (t, NULL, + (GtsVertex **) &p1, + (GtsVertex **) &p2, + (GtsVertex **) &p3, + &e1, &e2, &e3); + + gts_vector_init (p1p2, p1, p2); + gts_vector_init (p1p3, p1, p3); + gts_vector_init (pp1, p, p1); + + B = gts_vector_scalar (p1p3, p1p2); + E = gts_vector_scalar (p1p2, p1p2); + C = gts_vector_scalar (p1p3, p1p3); + + det = B*B - E*C; + if (det == 0.) { /* p1p2 and p1p3 are colinear */ + gdouble d1 = gts_point_segment_distance2 (p, GTS_SEGMENT (e1)); + gdouble d2 = gts_point_segment_distance2 (p, GTS_SEGMENT (e3)); + if (d1 < d2) + return d1; + return d2; + } + + A = gts_vector_scalar (p1p3, pp1); + D = gts_vector_scalar (p1p2, pp1); + + t1 = (D*C - A*B)/det; + t2 = (A*E - D*B)/det; + + if (t1 < 0.) + return gts_point_segment_distance2 (p, GTS_SEGMENT (e3)); + if (t2 < 0.) + return gts_point_segment_distance2 (p, GTS_SEGMENT (e1)); + if (t1 + t2 > 1.) + return gts_point_segment_distance2 (p, GTS_SEGMENT (e2)); + + x = pp1[0] + t1*p1p2[0] + t2*p1p3[0]; + y = pp1[1] + t1*p1p2[1] + t2*p1p3[1]; + z = pp1[2] + t1*p1p2[2] + t2*p1p3[2]; + + return x*x + y*y + z*z; +} + +/** + * gts_point_triangle_distance: + * @p: a #GtsPoint. + * @t: a #GtsTriangle. + * + * Returns: the minimun Euclidean distance between @p and @t. + */ +gdouble gts_point_triangle_distance (GtsPoint * p, GtsTriangle * t) +{ + g_return_val_if_fail (p != NULL, 0.0); + g_return_val_if_fail (t != NULL, 0.0); + + return sqrt (gts_point_triangle_distance2 (p, t)); +} + +/** + * gts_point_triangle_closest: + * @p: a #GtsPoint. + * @t: a #GtsTriangle. + * @closest: a #GtsPoint. + * + * Set the coordinates of @closest to those of the point belonging to @t and + * closest to @p. + */ +void gts_point_triangle_closest (GtsPoint * p, + GtsTriangle * t, + GtsPoint * closest) +{ + GtsPoint * p1, * p2, * p3; + GtsEdge * e1, * e2, * e3; + GtsVector p1p2, p1p3, pp1; + gdouble A, B, C, D, E, det; + gdouble t1, t2; + + g_return_if_fail (p != NULL); + g_return_if_fail (t != NULL); + g_return_if_fail (closest != NULL); + + gts_triangle_vertices_edges (t, NULL, + (GtsVertex **) &p1, + (GtsVertex **) &p2, + (GtsVertex **) &p3, + &e1, &e2, &e3); + + gts_vector_init (p1p2, p1, p2); + gts_vector_init (p1p3, p1, p3); + gts_vector_init (pp1, p, p1); + + B = gts_vector_scalar (p1p3, p1p2); + E = gts_vector_scalar (p1p2, p1p2); + C = gts_vector_scalar (p1p3, p1p3); + + det = B*B - E*C; + if (det == 0.) { /* p1p2 and p1p3 are colinear */ + GtsPoint * cp = + GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class ()))); + gts_point_segment_closest (p, GTS_SEGMENT (e1), cp); + gts_point_segment_closest (p, GTS_SEGMENT (e3), closest); + + if (gts_point_distance2 (cp, p) < gts_point_distance2 (closest, p)) + gts_point_set (closest, cp->x, cp->y, cp->z); + gts_object_destroy (GTS_OBJECT (cp)); + return; + } + + A = gts_vector_scalar (p1p3, pp1); + D = gts_vector_scalar (p1p2, pp1); + + t1 = (D*C - A*B)/det; + t2 = (A*E - D*B)/det; + + if (t1 < 0.) + gts_point_segment_closest (p, GTS_SEGMENT (e3), closest); + else if (t2 < 0.) + gts_point_segment_closest (p, GTS_SEGMENT (e1), closest); + else if (t1 + t2 > 1.) + gts_point_segment_closest (p, GTS_SEGMENT (e2), closest); + else + gts_point_set (closest, + p1->x + t1*p1p2[0] + t2*p1p3[0], + p1->y + t1*p1p2[1] + t2*p1p3[1], + p1->z + t1*p1p2[2] + t2*p1p3[2]); +} + +/** + * gts_segment_triangle_intersection: + * @s: a #GtsSegment. + * @t: a #GtsTriangle. + * @boundary: if %TRUE, the boundary of @t is taken into account. + * @klass: a #GtsPointClass to be used for the new point. + * + * Checks if @s intersects @t. If this is the case, creates a new + * point pi intersection of @s with @t. + * + * This function is geometrically robust in the sense that it will not + * return a point if @s and @t do not intersect and will return a + * point if @s and @t do intersect. However, the point coordinates are + * subject to round-off errors. + * + * Note that this function will not return any point if @s is contained in + * the plane defined by @t. + * + * Returns: a summit of @t (if @boundary is set to %TRUE), one of the endpoints + * of @s or a new #GtsPoint, intersection of @s with @t or %NULL if @s + * and @t don't intersect. + */ +GtsPoint * gts_segment_triangle_intersection (GtsSegment * s, + GtsTriangle * t, + gboolean boundary, + GtsPointClass * klass) +{ + GtsPoint * A, * B, * C, * D, * E, * I; + gdouble ABCE, ABCD, ADCE, ABDE, BCDE; + gdouble c; + + g_return_val_if_fail (s != NULL, NULL); + g_return_val_if_fail (t != NULL, NULL); + g_return_val_if_fail (klass != NULL, NULL); + + A = GTS_POINT (GTS_SEGMENT (t->e1)->v1); + B = GTS_POINT (GTS_SEGMENT (t->e1)->v2); + C = GTS_POINT (gts_triangle_vertex (t)); + D = GTS_POINT (s->v1); + E = GTS_POINT (s->v2); + + ABCE = gts_point_orientation_3d (A, B, C, E); + ABCD = gts_point_orientation_3d (A, B, C, D); + if (ABCE < 0.0 || ABCD > 0.0) { + GtsPoint * tmpp; + gdouble tmp; + tmpp = E; E = D; D = tmpp; + tmp = ABCE; ABCE = ABCD; ABCD = tmp; + } + if (ABCE < 0.0 || ABCD > 0.0) + return NULL; + ADCE = gts_point_orientation_3d (A, D, C, E); + if ((boundary && ADCE < 0.) || (!boundary && ADCE <= 0.)) + return NULL; + ABDE = gts_point_orientation_3d (A, B, D, E); + if ((boundary && ABDE < 0.) || (!boundary && ABDE <= 0.)) + return NULL; + BCDE = gts_point_orientation_3d (B, C, D, E); + if ((boundary && BCDE < 0.) || (!boundary && BCDE <= 0.)) + return NULL; + if (ABCE == 0.0) { + if (ABCD == 0.0) + /* s is contained in the plane defined by t*/ + return NULL; + return E; + } + if (ABCD == 0.0) + return D; + if (boundary) { /* corners of @t */ + if (ABDE == 0.) { + if (ADCE == 0.) + return A; + if (BCDE == 0.) + return B; + } + else if (BCDE == 0. && ADCE == 0.) + return C; + } + c = ABCE/(ABCE - ABCD); + I = GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (klass))); + gts_point_set (I, + E->x + c*(D->x - E->x), + E->y + c*(D->y - E->y), + E->z + c*(D->z - E->z)); + return I; +} + +/** + * gts_point_transform: + * @p: a #GtsPoint. + * @m: the #GtsMatrix representing the transformation to + * apply to the coordinates of @p. + * + * Transform the coordinates of @p according to @m. (p[] becomes m[][].p[]). + */ +void gts_point_transform (GtsPoint * p, GtsMatrix * m) +{ + gdouble x, y, z; + g_return_if_fail (p != NULL && m != NULL); + x = m[0][0]*p->x + m[0][1]*p->y + m[0][2]*p->z + m[0][3]; + y = m[1][0]*p->x + m[1][1]*p->y + m[1][2]*p->z + m[1][3]; + z = m[2][0]*p->x + m[2][1]*p->y + m[2][2]*p->z + m[2][3]; + p->x = x; p->y = y; p->z = z; +} + +/** + * gts_point_orientation: + * @p1: a #GtsPoint. + * @p2: a #GtsPoint. + * @p3: a #GtsPoint. + * + * Checks for orientation of the projection of three points on the + * (x,y) plane. The result is also an approximation of twice the + * signed area of the triangle defined by the three points. This + * function uses adaptive floating point arithmetic and is + * consequently geometrically robust. + * + * Returns: a positive value if @p1, @p2 and @p3 appear in + * counterclockwise order, a negative value if they appear in + * clockwise order and zero if they are colinear. + */ +gdouble gts_point_orientation (GtsPoint * p1, GtsPoint * p2, GtsPoint * p3) +{ + g_return_val_if_fail (p1 != NULL && p2 != NULL && p3 != NULL, 0.0); + + return orient2d ((gdouble *) &p1->x, + (gdouble *) &p2->x, + (gdouble *) &p3->x); +} + +static gboolean ray_intersects_triangle (GtsPoint * D, GtsPoint * E, + GtsTriangle * t) +{ + GtsPoint * A, * B, * C; + gint ABCE, ABCD, ADCE, ABDE, BCDE; + + gts_triangle_vertices (t, (GtsVertex **) &A, + (GtsVertex **) &B, + (GtsVertex **) &C); + + ABCE = gts_point_orientation_3d_sos (A, B, C, E); + ABCD = gts_point_orientation_3d_sos (A, B, C, D); + if (ABCE < 0 || ABCD > 0) { + GtsPoint * tmpp; + gint tmp; + + tmpp = E; E = D; D = tmpp; + tmp = ABCE; ABCE = ABCD; ABCD = tmp; + } + if (ABCE < 0 || ABCD > 0) + return FALSE; + ADCE = gts_point_orientation_3d_sos (A, D, C, E); + if (ADCE < 0) + return FALSE; + ABDE = gts_point_orientation_3d_sos (A, B, D, E); + if (ABDE < 0) + return FALSE; + BCDE = gts_point_orientation_3d_sos (B, C, D, E); + if (BCDE < 0) + return FALSE; + return TRUE; +} + +/** + * gts_point_is_inside_surface: + * @p: a #GtsPoint. + * @tree: a bounding box tree of the faces of a closed, orientable + * surface (see gts_bb_tree_surface()). + * @is_open: %TRUE if the surface defined by @tree is "open" i.e. its volume + * is negative, %FALSE otherwise. + * + * Returns: %TRUE if @p is inside the surface defined by @tree, %FALSE + * otherwise. + */ +gboolean gts_point_is_inside_surface (GtsPoint * p, + GNode * tree, + gboolean is_open) +{ + GSList * list, * i; + guint nc = 0; + GtsPoint * p1; + GtsBBox * bb; + + g_return_val_if_fail (p != NULL, FALSE); + g_return_val_if_fail (tree != NULL, FALSE); + + bb = tree->data; + p1 = gts_point_new (gts_point_class (), bb->x2 + fabs (bb->x2)/10., p->y, p->z); + i = list = gts_bb_tree_stabbed (tree, p); + while (i) { + GtsTriangle * t = GTS_TRIANGLE (GTS_BBOX (i->data)->bounded); + + if (ray_intersects_triangle (p, p1, t)) + nc++; + i = i->next; + } + g_slist_free (list); + gts_object_destroy (GTS_OBJECT (p1)); + + return is_open ? (nc % 2 == 0) : (nc % 2 != 0); +} + +#define SIGN(x) ((x) > 0. ? 1 : -1) +#define ORIENT1D(a,b) ((a) > (b) ? 1 : (a) < (b) ? -1 : 0) + +static gint sortp (gpointer * p, guint n) +{ + gint sign = 1; + guint i, j; + + for (i = 0; i < n - 1; i++) + for (j = 0; j < n - 1 - i; j++) + if (GPOINTER_TO_UINT (p[j+1]) < GPOINTER_TO_UINT (p[j])) { + gpointer tmp = p[j]; + + p[j] = p[j+1]; + p[j+1] = tmp; + sign = - sign; + } + return sign; +} + +/** + * gts_point_orientation_3d_sos: + * @p1: a #GtsPoint. + * @p2: a #GtsPoint. + * @p3: a #GtsPoint. + * @p4: a #GtsPoint. + * + * Checks if @p4 lies above or below the plane passing through the + * points @p1, @p2 and @p3. Below is defined so that @p1, @p2 and @p3 + * appear in counterclockwise order when viewed from above the + * plane. This function uses adaptive floating point arithmetic and is + * consequently geometrically robust. + * + * Simulation of Simplicity (SoS) is used to break ties when the + * orientation is degenerate (i.e. @p4 lies on the plane defined by + * @p1, @p2 and @p3). + * + * Returns: +1 if @p4 lies below, -1 if @p4 lies above the plane. + */ +gint gts_point_orientation_3d_sos (GtsPoint * p1, + GtsPoint * p2, + GtsPoint * p3, + GtsPoint * p4) +{ + gdouble o; + + g_return_val_if_fail (p1 != NULL && p2 != NULL && + p3 != NULL && p4 != NULL, 0); + + o = orient3d ((gdouble *) &p1->x, + (gdouble *) &p2->x, + (gdouble *) &p3->x, + (gdouble *) &p4->x); + if (o != 0.) + return SIGN (o); + else { + GtsPoint * p[4]; + gdouble a[2], b[2], c[2]; + gint sign; + + p[0] = p1; p[1] = p2; p[2] = p3; p[3] = p4; + sign = sortp ((gpointer *) p, 4); + + /* epsilon^1/8 */ + a[0] = p[1]->x; a[1] = p[1]->y; + b[0] = p[2]->x; b[1] = p[2]->y; + c[0] = p[3]->x; c[1] = p[3]->y; + o = orient2d (a, b, c); + if (o != 0.) + return SIGN (o)*sign; + + /* epsilon^1/4 */ + a[0] = p[1]->x; a[1] = p[1]->z; + b[0] = p[2]->x; b[1] = p[2]->z; + c[0] = p[3]->x; c[1] = p[3]->z; + o = orient2d (a, b, c); + if (o != 0.) + return - SIGN (o)*sign; + + /* epsilon^1/2 */ + a[0] = p[1]->y; a[1] = p[1]->z; + b[0] = p[2]->y; b[1] = p[2]->z; + c[0] = p[3]->y; c[1] = p[3]->z; + o = orient2d (a, b, c); + if (o != 0.) + return SIGN (o)*sign; + + /* epsilon */ + a[0] = p[0]->x; a[1] = p[0]->y; + b[0] = p[2]->x; b[1] = p[2]->y; + c[0] = p[3]->x; c[1] = p[3]->y; + o = orient2d (a, b, c); + if (o != 0.) + return - SIGN (o)*sign; + + /* epsilon^5/4 */ + o = ORIENT1D (p[2]->x, p[3]->x); + if (o != 0.) + return SIGN (o)*sign; + + /* epsilon^3/2 */ + o = ORIENT1D (p[2]->y, p[3]->y); + if (o != 0.) + return - SIGN (o)*sign; + + /* epsilon^2 */ + a[0] = p[0]->x; a[1] = p[0]->z; + b[0] = p[2]->x; b[1] = p[2]->z; + c[0] = p[3]->x; c[1] = p[3]->z; + o = orient2d (a, b, c); + if (o != 0.) + return SIGN (o)*sign; + + /* epsilon^5/2 */ + o = ORIENT1D (p[2]->z, p[3]->z); + if (o != 0.) + return SIGN (o)*sign; + + /* epsilon^4 */ + a[0] = p[0]->y; a[1] = p[0]->z; + b[0] = p[2]->y; b[1] = p[2]->z; + c[0] = p[3]->y; c[1] = p[3]->z; + o = orient2d (a, b, c); + if (o != 0.) + return - SIGN (o)*sign; + + /* epsilon^8 */ + a[0] = p[0]->x; a[1] = p[0]->y; + b[0] = p[1]->x; b[1] = p[1]->y; + c[0] = p[3]->x; c[1] = p[3]->y; + o = orient2d (a, b, c); + if (o != 0.) + return SIGN (o)*sign; + + /* epsilon^33/4 */ + o = ORIENT1D (p[1]->x, p[3]->x); + if (o != 0.) + return - SIGN (o)*sign; + + /* epsilon^17/2 */ + o = ORIENT1D (p[1]->y, p[3]->y); + if (o != 0.) + return SIGN (o)*sign; + + /* epsilon^10 */ + o = ORIENT1D (p[0]->x, p[3]->x); + if (o != 0.) + return SIGN (o)*sign; + + /* epsilon^21/2 */ + return sign; + } +} + +/** + * gts_point_orientation_sos: + * @p1: a #GtsPoint. + * @p2: a #GtsPoint. + * @p3: a #GtsPoint. + * + * Checks for orientation of the projection of three points on the + * (x,y) plane. + * + * Simulation of Simplicity (SoS) is used to break ties when the + * orientation is degenerate (i.e. @p3 lies on the line defined by + * @p1 and @p2). + * + * Returns: a positive value if @p1, @p2 and @p3 appear in + * counterclockwise order or a negative value if they appear in + * clockwise order. + */ +gint gts_point_orientation_sos (GtsPoint * p1, + GtsPoint * p2, + GtsPoint * p3) +{ + gdouble o; + + g_return_val_if_fail (p1 != NULL && p2 != NULL && p3 != NULL, 0); + + o = orient2d ((gdouble *) &p1->x, + (gdouble *) &p2->x, + (gdouble *) &p3->x); + if (o != 0.) + return SIGN (o); + else { + GtsPoint * p[3]; + gint sign; + + p[0] = p1; p[1] = p2; p[2] = p3; + sign = sortp ((gpointer *) p, 3); + + /* epsilon^1/4 */ + o = ORIENT1D (p[1]->x, p[2]->x); + if (o != 0.) + return - SIGN (o)*sign; + + /* epsilon^1/2 */ + o = ORIENT1D (p[1]->y, p[2]->y); + if (o != 0.) + return SIGN (o)*sign; + + /* epsilon */ + o = ORIENT1D (p[0]->x, p[2]->x); + if (o != 0.) + return SIGN (o)*sign; + + /* epsilon^3/2 */ + return sign; + } +} Index: work/obsolete/toporouter/src_3rd/gts/predicates.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/predicates.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/predicates.c (revision 6803) @@ -0,0 +1,2742 @@ +/*****************************************************************************/ +/* */ +/* Routines for Arbitrary Precision Floating-point Arithmetic */ +/* and Fast Robust Geometric Predicates */ +/* (predicates.c) */ +/* */ +/* May 18, 1996 */ +/* */ +/* Placed in the public domain by */ +/* Jonathan Richard Shewchuk */ +/* School of Computer Science */ +/* Carnegie Mellon University */ +/* 5000 Forbes Avenue */ +/* Pittsburgh, Pennsylvania 15213-3891 */ +/* jrs@cs.cmu.edu */ +/* */ +/* This file contains C implementation of algorithms for exact addition */ +/* and multiplication of floating-point numbers, and predicates for */ +/* robustly performing the orientation and incircle tests used in */ +/* computational geometry. The algorithms and underlying theory are */ +/* described in Jonathan Richard Shewchuk. "Adaptive Precision Floating- */ +/* Point Arithmetic and Fast Robust Geometric Predicates." Technical */ +/* Report CMU-CS-96-140, School of Computer Science, Carnegie Mellon */ +/* University, Pittsburgh, Pennsylvania, May 1996. (Submitted to */ +/* Discrete & Computational Geometry.) */ +/* */ +/* This file, the paper listed above, and other information are available */ +/* from the Web page http://www.cs.cmu.edu/~quake/robust.html . */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* Using this code: */ +/* */ +/* First, read the short or long version of the paper (from the Web page */ +/* above). */ +/* */ +/* Be sure to call exactinit() once, before calling any of the arithmetic */ +/* functions or geometric predicates. Also be sure to turn on the */ +/* optimizer when compiling this file. */ +/* */ +/* */ +/* Several geometric predicates are defined. Their parameters are all */ +/* points. Each point is an array of two or three floating-point */ +/* numbers. The geometric predicates, described in the papers, are */ +/* */ +/* orient2d(pa, pb, pc) */ +/* orient2dfast(pa, pb, pc) */ +/* orient3d(pa, pb, pc, pd) */ +/* orient3dfast(pa, pb, pc, pd) */ +/* incircle(pa, pb, pc, pd) */ +/* incirclefast(pa, pb, pc, pd) */ +/* insphere(pa, pb, pc, pd, pe) */ +/* inspherefast(pa, pb, pc, pd, pe) */ +/* */ +/* Those with suffix "fast" are approximate, non-robust versions. Those */ +/* without the suffix are adaptive precision, robust versions. There */ +/* are also versions with the suffices "exact" and "slow", which are */ +/* non-adaptive, exact arithmetic versions, which I use only for timings */ +/* in my arithmetic papers. */ +/* */ +/* */ +/* An expansion is represented by an array of floating-point numbers, */ +/* sorted from smallest to largest magnitude (possibly with interspersed */ +/* zeros). The length of each expansion is stored as a separate integer, */ +/* and each arithmetic function returns an integer which is the length */ +/* of the expansion it created. */ +/* */ +/* Several arithmetic functions are defined. Their parameters are */ +/* */ +/* e, f Input expansions */ +/* elen, flen Lengths of input expansions (must be >= 1) */ +/* h Output expansion */ +/* b Input scalar */ +/* */ +/* The arithmetic functions are */ +/* */ +/* grow_expansion(elen, e, b, h) */ +/* grow_expansion_zeroelim(elen, e, b, h) */ +/* expansion_sum(elen, e, flen, f, h) */ +/* expansion_sum_zeroelim1(elen, e, flen, f, h) */ +/* expansion_sum_zeroelim2(elen, e, flen, f, h) */ +/* fast_expansion_sum(elen, e, flen, f, h) */ +/* fast_expansion_sum_zeroelim(elen, e, flen, f, h) */ +/* linear_expansion_sum(elen, e, flen, f, h) */ +/* linear_expansion_sum_zeroelim(elen, e, flen, f, h) */ +/* scale_expansion(elen, e, b, h) */ +/* scale_expansion_zeroelim(elen, e, b, h) */ +/* compress(elen, e, h) */ +/* */ +/* All of these are described in the long version of the paper; some are */ +/* described in the short version. All return an integer that is the */ +/* length of h. Those with suffix _zeroelim perform zero elimination, */ +/* and are recommended over their counterparts. The procedure */ +/* fast_expansion_sum_zeroelim() (or linear_expansion_sum_zeroelim() on */ +/* processors that do not use the round-to-even tiebreaking rule) is */ +/* recommended over expansion_sum_zeroelim(). Each procedure has a */ +/* little note next to it (in the code below) that tells you whether or */ +/* not the output expansion may be the same array as one of the input */ +/* expansions. */ +/* */ +/* */ +/* If you look around below, you'll also find macros for a bunch of */ +/* simple unrolled arithmetic operations, and procedures for printing */ +/* expansions (commented out because they don't work with all C */ +/* compilers) and for generating random floating-point numbers whose */ +/* significand bits are all random. Most of the macros have undocumented */ +/* requirements that certain of their parameters should not be the same */ +/* variable; for safety, better to make sure all the parameters are */ +/* distinct variables. Feel free to send email to jrs@cs.cmu.edu if you */ +/* have questions. */ +/* */ +/*****************************************************************************/ + +#include +#include +#include +#include "predicates.h" + +/* Use header file generated automatically by predicates_init. */ +//#define USE_PREDICATES_INIT + +#ifdef USE_PREDICATES_INIT +#include "predicates_init.h" +#endif /* USE_PREDICATES_INIT */ + +/* FPU control. We MUST have only double precision (not extended precision) */ +#include "rounding.h" + +/* On some machines, the exact arithmetic routines might be defeated by the */ +/* use of internal extended precision floating-point registers. Sometimes */ +/* this problem can be fixed by defining certain values to be volatile, */ +/* thus forcing them to be stored to memory and rounded off. This isn't */ +/* a great solution, though, as it slows the arithmetic down. */ +/* */ +/* To try this out, write "#define INEXACT volatile" below. Normally, */ +/* however, INEXACT should be defined to be nothing. ("#define INEXACT".) */ + +#define INEXACT /* Nothing */ +/* #define INEXACT volatile */ + +#define REAL double /* float or double */ +#define REALPRINT doubleprint +#define REALRAND doublerand +#define NARROWRAND narrowdoublerand +#define UNIFORMRAND uniformdoublerand + +/* Which of the following two methods of finding the absolute values is */ +/* fastest is compiler-dependent. A few compilers can inline and optimize */ +/* the fabs() call; but most will incur the overhead of a function call, */ +/* which is disastrously slow. A faster way on IEEE machines might be to */ +/* mask the appropriate bit, but that's difficult to do in C. */ + +#define Absolute(a) ((a) >= 0.0 ? (a) : -(a)) +/* #define Absolute(a) fabs(a) */ + +/* Many of the operations are broken up into two pieces, a main part that */ +/* performs an approximate operation, and a "tail" that computes the */ +/* roundoff error of that operation. */ +/* */ +/* The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(), */ +/* Split(), and Two_Product() are all implemented as described in the */ +/* reference. Each of these macros requires certain variables to be */ +/* defined in the calling routine. The variables `bvirt', `c', `abig', */ +/* `_i', `_j', `_k', `_l', `_m', and `_n' are declared `INEXACT' because */ +/* they store the result of an operation that may incur roundoff error. */ +/* The input parameter `x' (or the highest numbered `x_' parameter) must */ +/* also be declared `INEXACT'. */ + +#define Fast_Two_Sum_Tail(a, b, x, y) \ + bvirt = x - a; \ + y = b - bvirt + +#define Fast_Two_Sum(a, b, x, y) \ + x = (REAL) (a + b); \ + Fast_Two_Sum_Tail(a, b, x, y) + +#define Fast_Two_Diff_Tail(a, b, x, y) \ + bvirt = a - x; \ + y = bvirt - b + +#define Fast_Two_Diff(a, b, x, y) \ + x = (REAL) (a - b); \ + Fast_Two_Diff_Tail(a, b, x, y) + +#define Two_Sum_Tail(a, b, x, y) \ + bvirt = (REAL) (x - a); \ + avirt = x - bvirt; \ + bround = b - bvirt; \ + around = a - avirt; \ + y = around + bround + +#define Two_Sum(a, b, x, y) \ + x = (REAL) (a + b); \ + Two_Sum_Tail(a, b, x, y) + +#define Two_Diff_Tail(a, b, x, y) \ + bvirt = (REAL) (a - x); \ + avirt = x + bvirt; \ + bround = bvirt - b; \ + around = a - avirt; \ + y = around + bround + +#define Two_Diff(a, b, x, y) \ + x = (REAL) (a - b); \ + Two_Diff_Tail(a, b, x, y) + +#define Split(a, ahi, alo) \ + c = (REAL) (splitter * a); \ + abig = (REAL) (c - a); \ + ahi = c - abig; \ + alo = a - ahi + +#define Two_Product_Tail(a, b, x, y) \ + Split(a, ahi, alo); \ + Split(b, bhi, blo); \ + err1 = x - (ahi * bhi); \ + err2 = err1 - (alo * bhi); \ + err3 = err2 - (ahi * blo); \ + y = (alo * blo) - err3 + +#define Two_Product(a, b, x, y) \ + x = (REAL) (a * b); \ + Two_Product_Tail(a, b, x, y) + +/* Two_Product_Presplit() is Two_Product() where one of the inputs has */ +/* already been split. Avoids redundant splitting. */ + +#define Two_Product_Presplit(a, b, bhi, blo, x, y) \ + x = (REAL) (a * b); \ + Split(a, ahi, alo); \ + err1 = x - (ahi * bhi); \ + err2 = err1 - (alo * bhi); \ + err3 = err2 - (ahi * blo); \ + y = (alo * blo) - err3 + +/* Two_Product_2Presplit() is Two_Product() where both of the inputs have */ +/* already been split. Avoids redundant splitting. */ + +#define Two_Product_2Presplit(a, ahi, alo, b, bhi, blo, x, y) \ + x = (REAL) (a * b); \ + err1 = x - (ahi * bhi); \ + err2 = err1 - (alo * bhi); \ + err3 = err2 - (ahi * blo); \ + y = (alo * blo) - err3 + +/* Square() can be done more quickly than Two_Product(). */ + +#define Square_Tail(a, x, y) \ + Split(a, ahi, alo); \ + err1 = x - (ahi * ahi); \ + err3 = err1 - ((ahi + ahi) * alo); \ + y = (alo * alo) - err3 + +#define Square(a, x, y) \ + x = (REAL) (a * a); \ + Square_Tail(a, x, y) + +/* Macros for summing expansions of various fixed lengths. These are all */ +/* unrolled versions of Expansion_Sum(). */ + +#define Two_One_Sum(a1, a0, b, x2, x1, x0) \ + Two_Sum(a0, b , _i, x0); \ + Two_Sum(a1, _i, x2, x1) + +#define Two_One_Diff(a1, a0, b, x2, x1, x0) \ + Two_Diff(a0, b , _i, x0); \ + Two_Sum( a1, _i, x2, x1) + +#define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \ + Two_One_Sum(a1, a0, b0, _j, _0, x0); \ + Two_One_Sum(_j, _0, b1, x3, x2, x1) + +#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \ + Two_One_Diff(a1, a0, b0, _j, _0, x0); \ + Two_One_Diff(_j, _0, b1, x3, x2, x1) + +#define Four_One_Sum(a3, a2, a1, a0, b, x4, x3, x2, x1, x0) \ + Two_One_Sum(a1, a0, b , _j, x1, x0); \ + Two_One_Sum(a3, a2, _j, x4, x3, x2) + +#define Four_Two_Sum(a3, a2, a1, a0, b1, b0, x5, x4, x3, x2, x1, x0) \ + Four_One_Sum(a3, a2, a1, a0, b0, _k, _2, _1, _0, x0); \ + Four_One_Sum(_k, _2, _1, _0, b1, x5, x4, x3, x2, x1) + +#define Four_Four_Sum(a3, a2, a1, a0, b4, b3, b1, b0, x7, x6, x5, x4, x3, x2, \ + x1, x0) \ + Four_Two_Sum(a3, a2, a1, a0, b1, b0, _l, _2, _1, _0, x1, x0); \ + Four_Two_Sum(_l, _2, _1, _0, b4, b3, x7, x6, x5, x4, x3, x2) + +#define Eight_One_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b, x8, x7, x6, x5, x4, \ + x3, x2, x1, x0) \ + Four_One_Sum(a3, a2, a1, a0, b , _j, x3, x2, x1, x0); \ + Four_One_Sum(a7, a6, a5, a4, _j, x8, x7, x6, x5, x4) + +#define Eight_Two_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0, x9, x8, x7, \ + x6, x5, x4, x3, x2, x1, x0) \ + Eight_One_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b0, _k, _6, _5, _4, _3, _2, \ + _1, _0, x0); \ + Eight_One_Sum(_k, _6, _5, _4, _3, _2, _1, _0, b1, x9, x8, x7, x6, x5, x4, \ + x3, x2, x1) + +#define Eight_Four_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b4, b3, b1, b0, x11, \ + x10, x9, x8, x7, x6, x5, x4, x3, x2, x1, x0) \ + Eight_Two_Sum(a7, a6, a5, a4, a3, a2, a1, a0, b1, b0, _l, _6, _5, _4, _3, \ + _2, _1, _0, x1, x0); \ + Eight_Two_Sum(_l, _6, _5, _4, _3, _2, _1, _0, b4, b3, x11, x10, x9, x8, \ + x7, x6, x5, x4, x3, x2) + +/* Macros for multiplying expansions of various fixed lengths. */ + +#define Two_One_Product(a1, a0, b, x3, x2, x1, x0) \ + Split(b, bhi, blo); \ + Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \ + Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \ + Two_Sum(_i, _0, _k, x1); \ + Fast_Two_Sum(_j, _k, x3, x2) + +#define Four_One_Product(a3, a2, a1, a0, b, x7, x6, x5, x4, x3, x2, x1, x0) \ + Split(b, bhi, blo); \ + Two_Product_Presplit(a0, b, bhi, blo, _i, x0); \ + Two_Product_Presplit(a1, b, bhi, blo, _j, _0); \ + Two_Sum(_i, _0, _k, x1); \ + Fast_Two_Sum(_j, _k, _i, x2); \ + Two_Product_Presplit(a2, b, bhi, blo, _j, _0); \ + Two_Sum(_i, _0, _k, x3); \ + Fast_Two_Sum(_j, _k, _i, x4); \ + Two_Product_Presplit(a3, b, bhi, blo, _j, _0); \ + Two_Sum(_i, _0, _k, x5); \ + Fast_Two_Sum(_j, _k, x7, x6) + +#define Two_Two_Product(a1, a0, b1, b0, x7, x6, x5, x4, x3, x2, x1, x0) \ + Split(a0, a0hi, a0lo); \ + Split(b0, bhi, blo); \ + Two_Product_2Presplit(a0, a0hi, a0lo, b0, bhi, blo, _i, x0); \ + Split(a1, a1hi, a1lo); \ + Two_Product_2Presplit(a1, a1hi, a1lo, b0, bhi, blo, _j, _0); \ + Two_Sum(_i, _0, _k, _1); \ + Fast_Two_Sum(_j, _k, _l, _2); \ + Split(b1, bhi, blo); \ + Two_Product_2Presplit(a0, a0hi, a0lo, b1, bhi, blo, _i, _0); \ + Two_Sum(_1, _0, _k, x1); \ + Two_Sum(_2, _k, _j, _1); \ + Two_Sum(_l, _j, _m, _2); \ + Two_Product_2Presplit(a1, a1hi, a1lo, b1, bhi, blo, _j, _0); \ + Two_Sum(_i, _0, _n, _0); \ + Two_Sum(_1, _0, _i, x2); \ + Two_Sum(_2, _i, _k, _1); \ + Two_Sum(_m, _k, _l, _2); \ + Two_Sum(_j, _n, _k, _0); \ + Two_Sum(_1, _0, _j, x3); \ + Two_Sum(_2, _j, _i, _1); \ + Two_Sum(_l, _i, _m, _2); \ + Two_Sum(_1, _k, _i, x4); \ + Two_Sum(_2, _i, _k, x5); \ + Two_Sum(_m, _k, x7, x6) + +/* An expansion of length two can be squared more quickly than finding the */ +/* product of two different expansions of length two, and the result is */ +/* guaranteed to have no more than six (rather than eight) components. */ + +#define Two_Square(a1, a0, x5, x4, x3, x2, x1, x0) \ + Square(a0, _j, x0); \ + _0 = a0 + a0; \ + Two_Product(a1, _0, _k, _1); \ + Two_One_Sum(_k, _1, _j, _l, _2, x1); \ + Square(a1, _j, _1); \ + Two_Two_Sum(_j, _1, _l, _2, x5, x4, x3, x2) + +#ifndef USE_PREDICATES_INIT + +static REAL splitter; /* = 2^ceiling(p / 2) + 1. Used to split floats in half. */ +/* A set of coefficients used to calculate maximum roundoff errors. */ +static REAL resulterrbound; +static REAL ccwerrboundA, ccwerrboundB, ccwerrboundC; +static REAL o3derrboundA, o3derrboundB, o3derrboundC; +static REAL iccerrboundA, iccerrboundB, iccerrboundC; +static REAL isperrboundA, isperrboundB, isperrboundC; + +void +gts_predicates_init() +{ + double half = 0.5; + double check = 1.0, lastcheck; + int every_other = 1; + /* epsilon = 2^(-p). Used to estimate roundoff errors. */ + double epsilon = 1.0; + + FPU_ROUND_DOUBLE; + + splitter = 1.; + + /* Repeatedly divide `epsilon' by two until it is too small to add to */ + /* one without causing roundoff. (Also check if the sum is equal to */ + /* the previous sum, for machines that round up instead of using exact */ + /* rounding. Not that this library will work on such machines anyway). */ + do { + lastcheck = check; + epsilon *= half; + if (every_other) { + splitter *= 2.0; + } + every_other = !every_other; + check = 1.0 + epsilon; + } while ((check != 1.0) && (check != lastcheck)); + splitter += 1.0; + /* Error bounds for orientation and incircle tests. */ + resulterrbound = (3.0 + 8.0 * epsilon) * epsilon; + ccwerrboundA = (3.0 + 16.0 * epsilon) * epsilon; + ccwerrboundB = (2.0 + 12.0 * epsilon) * epsilon; + ccwerrboundC = (9.0 + 64.0 * epsilon) * epsilon * epsilon; + o3derrboundA = (7.0 + 56.0 * epsilon) * epsilon; + o3derrboundB = (3.0 + 28.0 * epsilon) * epsilon; + o3derrboundC = (26.0 + 288.0 * epsilon) * epsilon * epsilon; + iccerrboundA = (10.0 + 96.0 * epsilon) * epsilon; + iccerrboundB = (4.0 + 48.0 * epsilon) * epsilon; + iccerrboundC = (44.0 + 576.0 * epsilon) * epsilon * epsilon; + isperrboundA = (16.0 + 224.0 * epsilon) * epsilon; + isperrboundB = (5.0 + 72.0 * epsilon) * epsilon; + isperrboundC = (71.0 + 1408.0 * epsilon) * epsilon * epsilon; + + + FPU_RESTORE; +} + +#endif /* USE_PREDICATES_INIT */ + +/*****************************************************************************/ +/* */ +/* doubleprint() Print the bit representation of a double. */ +/* */ +/* Useful for debugging exact arithmetic routines. */ +/* */ +/*****************************************************************************/ + +/* +void doubleprint(number) +double number; +{ + unsigned long long no; + unsigned long long sign, expo; + int exponent; + int i, bottomi; + + no = *(unsigned long long *) &number; + sign = no & 0x8000000000000000ll; + expo = (no >> 52) & 0x7ffll; + exponent = (int) expo; + exponent = exponent - 1023; + if (sign) { + printf("-"); + } else { + printf(" "); + } + if (exponent == -1023) { + printf( + "0.0000000000000000000000000000000000000000000000000000_ ( )"); + } else { + printf("1."); + bottomi = -1; + for (i = 0; i < 52; i++) { + if (no & 0x0008000000000000ll) { + printf("1"); + bottomi = i; + } else { + printf("0"); + } + no <<= 1; + } + printf("_%d (%d)", exponent, exponent - 1 - bottomi); + } +} +*/ + +/*****************************************************************************/ +/* */ +/* floatprint() Print the bit representation of a float. */ +/* */ +/* Useful for debugging exact arithmetic routines. */ +/* */ +/*****************************************************************************/ + +/* +void floatprint(number) +float number; +{ + unsigned no; + unsigned sign, expo; + int exponent; + int i, bottomi; + + no = *(unsigned *) &number; + sign = no & 0x80000000; + expo = (no >> 23) & 0xff; + exponent = (int) expo; + exponent = exponent - 127; + if (sign) { + printf("-"); + } else { + printf(" "); + } + if (exponent == -127) { + printf("0.00000000000000000000000_ ( )"); + } else { + printf("1."); + bottomi = -1; + for (i = 0; i < 23; i++) { + if (no & 0x00400000) { + printf("1"); + bottomi = i; + } else { + printf("0"); + } + no <<= 1; + } + printf("_%3d (%3d)", exponent, exponent - 1 - bottomi); + } +} +*/ + +/*****************************************************************************/ +/* */ +/* expansion_print() Print the bit representation of an expansion. */ +/* */ +/* Useful for debugging exact arithmetic routines. */ +/* */ +/*****************************************************************************/ + +/* +void expansion_print(elen, e) +int elen; +REAL *e; +{ + int i; + + for (i = elen - 1; i >= 0; i--) { + REALPRINT(e[i]); + if (i > 0) { + printf(" +\n"); + } else { + printf("\n"); + } + } +} +*/ + +/*****************************************************************************/ +/* */ +/* doublerand() Generate a double with random 53-bit significand and a */ +/* random exponent in [0, 511]. */ +/* */ +/*****************************************************************************/ + +/* +static double doublerand() +{ + double result; + double expo; + long a, b, c; + long i; + + a = random(); + b = random(); + c = random(); + result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8); + for (i = 512, expo = 2; i <= 131072; i *= 2, expo = expo * expo) { + if (c & i) { + result *= expo; + } + } + return result; +} +*/ + +/*****************************************************************************/ +/* */ +/* narrowdoublerand() Generate a double with random 53-bit significand */ +/* and a random exponent in [0, 7]. */ +/* */ +/*****************************************************************************/ + +/* +static double narrowdoublerand() +{ + double result; + double expo; + long a, b, c; + long i; + + a = random(); + b = random(); + c = random(); + result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8); + for (i = 512, expo = 2; i <= 2048; i *= 2, expo = expo * expo) { + if (c & i) { + result *= expo; + } + } + return result; +} +*/ + +/*****************************************************************************/ +/* */ +/* uniformdoublerand() Generate a double with random 53-bit significand. */ +/* */ +/*****************************************************************************/ + +/* +static double uniformdoublerand() +{ + double result; + long a, b; + + a = random(); + b = random(); + result = (double) (a - 1073741824) * 8388608.0 + (double) (b >> 8); + return result; +} +*/ + +/*****************************************************************************/ +/* */ +/* floatrand() Generate a float with random 24-bit significand and a */ +/* random exponent in [0, 63]. */ +/* */ +/*****************************************************************************/ + +/* +static float floatrand() +{ + float result; + float expo; + long a, c; + long i; + + a = random(); + c = random(); + result = (float) ((a - 1073741824) >> 6); + for (i = 512, expo = 2; i <= 16384; i *= 2, expo = expo * expo) { + if (c & i) { + result *= expo; + } + } + return result; +} +*/ + +/*****************************************************************************/ +/* */ +/* narrowfloatrand() Generate a float with random 24-bit significand and */ +/* a random exponent in [0, 7]. */ +/* */ +/*****************************************************************************/ + +/* +static float narrowfloatrand() +{ + float result; + float expo; + long a, c; + long i; + + a = random(); + c = random(); + result = (float) ((a - 1073741824) >> 6); + for (i = 512, expo = 2; i <= 2048; i *= 2, expo = expo * expo) { + if (c & i) { + result *= expo; + } + } + return result; +} +*/ + +/*****************************************************************************/ +/* */ +/* uniformfloatrand() Generate a float with random 24-bit significand. */ +/* */ +/*****************************************************************************/ + +/* +static float uniformfloatrand() +{ + float result; + long a; + + a = random(); + result = (float) ((a - 1073741824) >> 6); + return result; +} +*/ + +/*****************************************************************************/ +/* */ +/* fast_expansion_sum_zeroelim() Sum two expansions, eliminating zero */ +/* components from the output expansion. */ +/* */ +/* Sets h = e + f. See the long version of my paper for details. */ +/* */ +/* If round-to-even is used (as with IEEE 754), maintains the strongly */ +/* nonoverlapping property. (That is, if e is strongly nonoverlapping, h */ +/* will be also.) Does NOT maintain the nonoverlapping or nonadjacent */ +/* properties. */ +/* */ +/*****************************************************************************/ + +static int fast_expansion_sum_zeroelim(int elen, REAL *e, + int flen, REAL *f, REAL *h) + /* h cannot be e or f. */ +{ + REAL Q; + INEXACT REAL Qnew; + INEXACT REAL hh; + INEXACT REAL bvirt; + REAL avirt, bround, around; + int eindex, findex, hindex; + REAL enow, fnow; + + enow = e[0]; + fnow = f[0]; + eindex = findex = 0; + if ((fnow > enow) == (fnow > -enow)) { + Q = enow; + enow = e[++eindex]; + } else { + Q = fnow; + fnow = f[++findex]; + } + hindex = 0; + if ((eindex < elen) && (findex < flen)) { + if ((fnow > enow) == (fnow > -enow)) { + Fast_Two_Sum(enow, Q, Qnew, hh); + enow = e[++eindex]; + } else { + Fast_Two_Sum(fnow, Q, Qnew, hh); + fnow = f[++findex]; + } + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + while ((eindex < elen) && (findex < flen)) { + if ((fnow > enow) == (fnow > -enow)) { + Two_Sum(Q, enow, Qnew, hh); + enow = e[++eindex]; + } else { + Two_Sum(Q, fnow, Qnew, hh); + fnow = f[++findex]; + } + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + } + while (eindex < elen) { + Two_Sum(Q, enow, Qnew, hh); + enow = e[++eindex]; + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + while (findex < flen) { + Two_Sum(Q, fnow, Qnew, hh); + fnow = f[++findex]; + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + if ((Q != 0.0) || (hindex == 0)) { + h[hindex++] = Q; + } + return hindex; +} + +/*****************************************************************************/ +/* */ +/* scale_expansion_zeroelim() Multiply an expansion by a scalar, */ +/* eliminating zero components from the */ +/* output expansion. */ +/* */ +/* Sets h = be. See either version of my paper for details. */ +/* */ +/* Maintains the nonoverlapping property. If round-to-even is used (as */ +/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ +/* properties as well. (That is, if e has one of these properties, so */ +/* will h.) */ +/* */ +/*****************************************************************************/ + +static int scale_expansion_zeroelim(int elen, REAL *e, REAL b, REAL *h) + /* e and h cannot be the same. */ +{ + INEXACT REAL Q, sum; + REAL hh; + INEXACT REAL product1; + REAL product0; + int eindex, hindex; + REAL enow; + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + + Split(b, bhi, blo); + Two_Product_Presplit(e[0], b, bhi, blo, Q, hh); + hindex = 0; + if (hh != 0) { + h[hindex++] = hh; + } + for (eindex = 1; eindex < elen; eindex++) { + enow = e[eindex]; + Two_Product_Presplit(enow, b, bhi, blo, product1, product0); + Two_Sum(Q, product0, sum, hh); + if (hh != 0) { + h[hindex++] = hh; + } + Fast_Two_Sum(product1, sum, Q, hh); + if (hh != 0) { + h[hindex++] = hh; + } + } + if ((Q != 0.0) || (hindex == 0)) { + h[hindex++] = Q; + } + return hindex; +} + +/*****************************************************************************/ +/* */ +/* estimate() Produce a one-word estimate of an expansion's value. */ +/* */ +/* See either version of my paper for details. */ +/* */ +/*****************************************************************************/ + +static REAL estimate(int elen, REAL *e) +{ + REAL Q; + int eindex; + + Q = e[0]; + for (eindex = 1; eindex < elen; eindex++) { + Q += e[eindex]; + } + return Q; +} + +/*****************************************************************************/ +/* */ +/* orient2dfast() Approximate 2D orientation test. Nonrobust. */ +/* orient2dexact() Exact 2D orientation test. Robust. */ +/* orient2dslow() Another exact 2D orientation test. Robust. */ +/* orient2d() Adaptive exact 2D orientation test. Robust. */ +/* */ +/* Return a positive value if the points pa, pb, and pc occur */ +/* in counterclockwise order; a negative value if they occur */ +/* in clockwise order; and zero if they are collinear. The */ +/* result is also a rough approximation of twice the signed */ +/* area of the triangle defined by the three points. */ +/* */ +/* Only the first and last routine should be used; the middle two are for */ +/* timings. */ +/* */ +/* The last three use exact arithmetic to ensure a correct answer. The */ +/* result returned is the determinant of a matrix. In orient2d() only, */ +/* this determinant is computed adaptively, in the sense that exact */ +/* arithmetic is used only to the degree it is needed to ensure that the */ +/* returned value has the correct sign. Hence, orient2d() is usually quite */ +/* fast, but will run more slowly when the input points are collinear or */ +/* nearly so. */ +/* */ +/*****************************************************************************/ + +static REAL orient2dadapt(REAL *pa, REAL *pb, REAL *pc, REAL detsum) +{ + INEXACT REAL acx, acy, bcx, bcy; + REAL acxtail, acytail, bcxtail, bcytail; + INEXACT REAL detleft, detright; + REAL detlefttail, detrighttail; + REAL det, errbound; + REAL B[4], C1[8], C2[12], D[16]; + INEXACT REAL B3; + int C1length, C2length, Dlength; + REAL u[4]; + INEXACT REAL u3; + INEXACT REAL s1, t1; + REAL s0, t0; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + acx = (REAL) (pa[0] - pc[0]); + bcx = (REAL) (pb[0] - pc[0]); + acy = (REAL) (pa[1] - pc[1]); + bcy = (REAL) (pb[1] - pc[1]); + + Two_Product(acx, bcy, detleft, detlefttail); + Two_Product(acy, bcx, detright, detrighttail); + + Two_Two_Diff(detleft, detlefttail, detright, detrighttail, + B3, B[2], B[1], B[0]); + B[3] = B3; + + det = estimate(4, B); + errbound = ccwerrboundB * detsum; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pc[0], acx, acxtail); + Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail); + Two_Diff_Tail(pa[1], pc[1], acy, acytail); + Two_Diff_Tail(pb[1], pc[1], bcy, bcytail); + + if ((acxtail == 0.0) && (acytail == 0.0) + && (bcxtail == 0.0) && (bcytail == 0.0)) { + return det; + } + + errbound = ccwerrboundC * detsum + resulterrbound * Absolute(det); + det += (acx * bcytail + bcy * acxtail) + - (acy * bcxtail + bcx * acytail); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Product(acxtail, bcy, s1, s0); + Two_Product(acytail, bcx, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1); + + Two_Product(acx, bcytail, s1, s0); + Two_Product(acy, bcxtail, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2); + + Two_Product(acxtail, bcytail, s1, s0); + Two_Product(acytail, bcxtail, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D); + + return(D[Dlength - 1]); +} + +REAL orient2d(pa, pb, pc) +REAL *pa; +REAL *pb; +REAL *pc; +{ + REAL detleft, detright, det; + REAL detsum, errbound; + REAL orient; + + FPU_ROUND_DOUBLE; + + detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]); + detright = (pa[1] - pc[1]) * (pb[0] - pc[0]); + det = detleft - detright; + + if (detleft > 0.0) { + if (detright <= 0.0) { + FPU_RESTORE; + return det; + } else { + detsum = detleft + detright; + } + } else if (detleft < 0.0) { + if (detright >= 0.0) { + FPU_RESTORE; + return det; + } else { + detsum = -detleft - detright; + } + } else { + FPU_RESTORE; + return det; + } + + errbound = ccwerrboundA * detsum; + if ((det >= errbound) || (-det >= errbound)) { + FPU_RESTORE; + return det; + } + + orient = orient2dadapt(pa, pb, pc, detsum); + FPU_RESTORE; + return orient; +} + +/*****************************************************************************/ +/* */ +/* orient3dfast() Approximate 3D orientation test. Nonrobust. */ +/* orient3dexact() Exact 3D orientation test. Robust. */ +/* orient3dslow() Another exact 3D orientation test. Robust. */ +/* orient3d() Adaptive exact 3D orientation test. Robust. */ +/* */ +/* Return a positive value if the point pd lies below the */ +/* plane passing through pa, pb, and pc; "below" is defined so */ +/* that pa, pb, and pc appear in counterclockwise order when */ +/* viewed from above the plane. Returns a negative value if */ +/* pd lies above the plane. Returns zero if the points are */ +/* coplanar. The result is also a rough approximation of six */ +/* times the signed volume of the tetrahedron defined by the */ +/* four points. */ +/* */ +/* Only the first and last routine should be used; the middle two are for */ +/* timings. */ +/* */ +/* The last three use exact arithmetic to ensure a correct answer. The */ +/* result returned is the determinant of a matrix. In orient3d() only, */ +/* this determinant is computed adaptively, in the sense that exact */ +/* arithmetic is used only to the degree it is needed to ensure that the */ +/* returned value has the correct sign. Hence, orient3d() is usually quite */ +/* fast, but will run more slowly when the input points are coplanar or */ +/* nearly so. */ +/* */ +/*****************************************************************************/ + +static REAL orient3dadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, + REAL permanent) +{ + INEXACT REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz; + REAL det, errbound; + + INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; + REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; + REAL bc[4], ca[4], ab[4]; + INEXACT REAL bc3, ca3, ab3; + REAL adet[8], bdet[8], cdet[8]; + int alen, blen, clen; + REAL abdet[16]; + int ablen; + REAL *finnow, *finother, *finswap; + REAL fin1[192], fin2[192]; + int finlength; + + REAL adxtail, bdxtail, cdxtail; + REAL adytail, bdytail, cdytail; + REAL adztail, bdztail, cdztail; + INEXACT REAL at_blarge, at_clarge; + INEXACT REAL bt_clarge, bt_alarge; + INEXACT REAL ct_alarge, ct_blarge; + REAL at_b[4], at_c[4], bt_c[4], bt_a[4], ct_a[4], ct_b[4]; + int at_blen, at_clen, bt_clen, bt_alen, ct_alen, ct_blen; + INEXACT REAL bdxt_cdy1, cdxt_bdy1, cdxt_ady1; + INEXACT REAL adxt_cdy1, adxt_bdy1, bdxt_ady1; + REAL bdxt_cdy0, cdxt_bdy0, cdxt_ady0; + REAL adxt_cdy0, adxt_bdy0, bdxt_ady0; + INEXACT REAL bdyt_cdx1, cdyt_bdx1, cdyt_adx1; + INEXACT REAL adyt_cdx1, adyt_bdx1, bdyt_adx1; + REAL bdyt_cdx0, cdyt_bdx0, cdyt_adx0; + REAL adyt_cdx0, adyt_bdx0, bdyt_adx0; + REAL bct[8], cat[8], abt[8]; + int bctlen, catlen, abtlen; + INEXACT REAL bdxt_cdyt1, cdxt_bdyt1, cdxt_adyt1; + INEXACT REAL adxt_cdyt1, adxt_bdyt1, bdxt_adyt1; + REAL bdxt_cdyt0, cdxt_bdyt0, cdxt_adyt0; + REAL adxt_cdyt0, adxt_bdyt0, bdxt_adyt0; + REAL u[4], v[12], w[16]; + INEXACT REAL u3; + int vlength, wlength; + REAL negate; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j, _k; + REAL _0; + + adx = (REAL) (pa[0] - pd[0]); + bdx = (REAL) (pb[0] - pd[0]); + cdx = (REAL) (pc[0] - pd[0]); + ady = (REAL) (pa[1] - pd[1]); + bdy = (REAL) (pb[1] - pd[1]); + cdy = (REAL) (pc[1] - pd[1]); + adz = (REAL) (pa[2] - pd[2]); + bdz = (REAL) (pb[2] - pd[2]); + cdz = (REAL) (pc[2] - pd[2]); + + Two_Product(bdx, cdy, bdxcdy1, bdxcdy0); + Two_Product(cdx, bdy, cdxbdy1, cdxbdy0); + Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]); + bc[3] = bc3; + alen = scale_expansion_zeroelim(4, bc, adz, adet); + + Two_Product(cdx, ady, cdxady1, cdxady0); + Two_Product(adx, cdy, adxcdy1, adxcdy0); + Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]); + ca[3] = ca3; + blen = scale_expansion_zeroelim(4, ca, bdz, bdet); + + Two_Product(adx, bdy, adxbdy1, adxbdy0); + Two_Product(bdx, ady, bdxady1, bdxady0); + Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]); + ab[3] = ab3; + clen = scale_expansion_zeroelim(4, ab, cdz, cdet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1); + + det = estimate(finlength, fin1); + errbound = o3derrboundB * permanent; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pd[0], adx, adxtail); + Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); + Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); + Two_Diff_Tail(pa[1], pd[1], ady, adytail); + Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); + Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); + Two_Diff_Tail(pa[2], pd[2], adz, adztail); + Two_Diff_Tail(pb[2], pd[2], bdz, bdztail); + Two_Diff_Tail(pc[2], pd[2], cdz, cdztail); + + if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) + && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0) + && (adztail == 0.0) && (bdztail == 0.0) && (cdztail == 0.0)) { + return det; + } + + errbound = o3derrboundC * permanent + resulterrbound * Absolute(det); + det += (adz * ((bdx * cdytail + cdy * bdxtail) + - (bdy * cdxtail + cdx * bdytail)) + + adztail * (bdx * cdy - bdy * cdx)) + + (bdz * ((cdx * adytail + ady * cdxtail) + - (cdy * adxtail + adx * cdytail)) + + bdztail * (cdx * ady - cdy * adx)) + + (cdz * ((adx * bdytail + bdy * adxtail) + - (ady * bdxtail + bdx * adytail)) + + cdztail * (adx * bdy - ady * bdx)); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + finnow = fin1; + finother = fin2; + + if (adxtail == 0.0) { + if (adytail == 0.0) { + at_b[0] = 0.0; + at_blen = 1; + at_c[0] = 0.0; + at_clen = 1; + } else { + negate = -adytail; + Two_Product(negate, bdx, at_blarge, at_b[0]); + at_b[1] = at_blarge; + at_blen = 2; + Two_Product(adytail, cdx, at_clarge, at_c[0]); + at_c[1] = at_clarge; + at_clen = 2; + } + } else { + if (adytail == 0.0) { + Two_Product(adxtail, bdy, at_blarge, at_b[0]); + at_b[1] = at_blarge; + at_blen = 2; + negate = -adxtail; + Two_Product(negate, cdy, at_clarge, at_c[0]); + at_c[1] = at_clarge; + at_clen = 2; + } else { + Two_Product(adxtail, bdy, adxt_bdy1, adxt_bdy0); + Two_Product(adytail, bdx, adyt_bdx1, adyt_bdx0); + Two_Two_Diff(adxt_bdy1, adxt_bdy0, adyt_bdx1, adyt_bdx0, + at_blarge, at_b[2], at_b[1], at_b[0]); + at_b[3] = at_blarge; + at_blen = 4; + Two_Product(adytail, cdx, adyt_cdx1, adyt_cdx0); + Two_Product(adxtail, cdy, adxt_cdy1, adxt_cdy0); + Two_Two_Diff(adyt_cdx1, adyt_cdx0, adxt_cdy1, adxt_cdy0, + at_clarge, at_c[2], at_c[1], at_c[0]); + at_c[3] = at_clarge; + at_clen = 4; + } + } + if (bdxtail == 0.0) { + if (bdytail == 0.0) { + bt_c[0] = 0.0; + bt_clen = 1; + bt_a[0] = 0.0; + bt_alen = 1; + } else { + negate = -bdytail; + Two_Product(negate, cdx, bt_clarge, bt_c[0]); + bt_c[1] = bt_clarge; + bt_clen = 2; + Two_Product(bdytail, adx, bt_alarge, bt_a[0]); + bt_a[1] = bt_alarge; + bt_alen = 2; + } + } else { + if (bdytail == 0.0) { + Two_Product(bdxtail, cdy, bt_clarge, bt_c[0]); + bt_c[1] = bt_clarge; + bt_clen = 2; + negate = -bdxtail; + Two_Product(negate, ady, bt_alarge, bt_a[0]); + bt_a[1] = bt_alarge; + bt_alen = 2; + } else { + Two_Product(bdxtail, cdy, bdxt_cdy1, bdxt_cdy0); + Two_Product(bdytail, cdx, bdyt_cdx1, bdyt_cdx0); + Two_Two_Diff(bdxt_cdy1, bdxt_cdy0, bdyt_cdx1, bdyt_cdx0, + bt_clarge, bt_c[2], bt_c[1], bt_c[0]); + bt_c[3] = bt_clarge; + bt_clen = 4; + Two_Product(bdytail, adx, bdyt_adx1, bdyt_adx0); + Two_Product(bdxtail, ady, bdxt_ady1, bdxt_ady0); + Two_Two_Diff(bdyt_adx1, bdyt_adx0, bdxt_ady1, bdxt_ady0, + bt_alarge, bt_a[2], bt_a[1], bt_a[0]); + bt_a[3] = bt_alarge; + bt_alen = 4; + } + } + if (cdxtail == 0.0) { + if (cdytail == 0.0) { + ct_a[0] = 0.0; + ct_alen = 1; + ct_b[0] = 0.0; + ct_blen = 1; + } else { + negate = -cdytail; + Two_Product(negate, adx, ct_alarge, ct_a[0]); + ct_a[1] = ct_alarge; + ct_alen = 2; + Two_Product(cdytail, bdx, ct_blarge, ct_b[0]); + ct_b[1] = ct_blarge; + ct_blen = 2; + } + } else { + if (cdytail == 0.0) { + Two_Product(cdxtail, ady, ct_alarge, ct_a[0]); + ct_a[1] = ct_alarge; + ct_alen = 2; + negate = -cdxtail; + Two_Product(negate, bdy, ct_blarge, ct_b[0]); + ct_b[1] = ct_blarge; + ct_blen = 2; + } else { + Two_Product(cdxtail, ady, cdxt_ady1, cdxt_ady0); + Two_Product(cdytail, adx, cdyt_adx1, cdyt_adx0); + Two_Two_Diff(cdxt_ady1, cdxt_ady0, cdyt_adx1, cdyt_adx0, + ct_alarge, ct_a[2], ct_a[1], ct_a[0]); + ct_a[3] = ct_alarge; + ct_alen = 4; + Two_Product(cdytail, bdx, cdyt_bdx1, cdyt_bdx0); + Two_Product(cdxtail, bdy, cdxt_bdy1, cdxt_bdy0); + Two_Two_Diff(cdyt_bdx1, cdyt_bdx0, cdxt_bdy1, cdxt_bdy0, + ct_blarge, ct_b[2], ct_b[1], ct_b[0]); + ct_b[3] = ct_blarge; + ct_blen = 4; + } + } + + bctlen = fast_expansion_sum_zeroelim(bt_clen, bt_c, ct_blen, ct_b, bct); + wlength = scale_expansion_zeroelim(bctlen, bct, adz, w); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, + finother); + finswap = finnow; finnow = finother; finother = finswap; + + catlen = fast_expansion_sum_zeroelim(ct_alen, ct_a, at_clen, at_c, cat); + wlength = scale_expansion_zeroelim(catlen, cat, bdz, w); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, + finother); + finswap = finnow; finnow = finother; finother = finswap; + + abtlen = fast_expansion_sum_zeroelim(at_blen, at_b, bt_alen, bt_a, abt); + wlength = scale_expansion_zeroelim(abtlen, abt, cdz, w); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, + finother); + finswap = finnow; finnow = finother; finother = finswap; + + if (adztail != 0.0) { + vlength = scale_expansion_zeroelim(4, bc, adztail, v); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdztail != 0.0) { + vlength = scale_expansion_zeroelim(4, ca, bdztail, v); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdztail != 0.0) { + vlength = scale_expansion_zeroelim(4, ab, cdztail, v); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, vlength, v, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + if (adxtail != 0.0) { + if (bdytail != 0.0) { + Two_Product(adxtail, bdytail, adxt_bdyt1, adxt_bdyt0); + Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdz, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + if (cdztail != 0.0) { + Two_One_Product(adxt_bdyt1, adxt_bdyt0, cdztail, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if (cdytail != 0.0) { + negate = -adxtail; + Two_Product(negate, cdytail, adxt_cdyt1, adxt_cdyt0); + Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdz, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + if (bdztail != 0.0) { + Two_One_Product(adxt_cdyt1, adxt_cdyt0, bdztail, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + } + if (bdxtail != 0.0) { + if (cdytail != 0.0) { + Two_Product(bdxtail, cdytail, bdxt_cdyt1, bdxt_cdyt0); + Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adz, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + if (adztail != 0.0) { + Two_One_Product(bdxt_cdyt1, bdxt_cdyt0, adztail, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if (adytail != 0.0) { + negate = -bdxtail; + Two_Product(negate, adytail, bdxt_adyt1, bdxt_adyt0); + Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdz, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + if (cdztail != 0.0) { + Two_One_Product(bdxt_adyt1, bdxt_adyt0, cdztail, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + } + if (cdxtail != 0.0) { + if (adytail != 0.0) { + Two_Product(cdxtail, adytail, cdxt_adyt1, cdxt_adyt0); + Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdz, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + if (bdztail != 0.0) { + Two_One_Product(cdxt_adyt1, cdxt_adyt0, bdztail, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if (bdytail != 0.0) { + negate = -cdxtail; + Two_Product(negate, bdytail, cdxt_bdyt1, cdxt_bdyt0); + Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adz, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + if (adztail != 0.0) { + Two_One_Product(cdxt_bdyt1, cdxt_bdyt0, adztail, u3, u[2], u[1], u[0]); + u[3] = u3; + finlength = fast_expansion_sum_zeroelim(finlength, finnow, 4, u, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + } + + if (adztail != 0.0) { + wlength = scale_expansion_zeroelim(bctlen, bct, adztail, w); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdztail != 0.0) { + wlength = scale_expansion_zeroelim(catlen, cat, bdztail, w); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdztail != 0.0) { + wlength = scale_expansion_zeroelim(abtlen, abt, cdztail, w); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, wlength, w, + finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + return finnow[finlength - 1]; +} + +REAL orient3d(pa, pb, pc, pd) +REAL *pa; +REAL *pb; +REAL *pc; +REAL *pd; +{ + REAL adx, bdx, cdx, ady, bdy, cdy, adz, bdz, cdz; + REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; + REAL det; + REAL permanent, errbound; + REAL orient; + + FPU_ROUND_DOUBLE; + + adx = pa[0] - pd[0]; + bdx = pb[0] - pd[0]; + cdx = pc[0] - pd[0]; + ady = pa[1] - pd[1]; + bdy = pb[1] - pd[1]; + cdy = pc[1] - pd[1]; + adz = pa[2] - pd[2]; + bdz = pb[2] - pd[2]; + cdz = pc[2] - pd[2]; + + bdxcdy = bdx * cdy; + cdxbdy = cdx * bdy; + + cdxady = cdx * ady; + adxcdy = adx * cdy; + + adxbdy = adx * bdy; + bdxady = bdx * ady; + + det = adz * (bdxcdy - cdxbdy) + + bdz * (cdxady - adxcdy) + + cdz * (adxbdy - bdxady); + + permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * Absolute(adz) + + (Absolute(cdxady) + Absolute(adxcdy)) * Absolute(bdz) + + (Absolute(adxbdy) + Absolute(bdxady)) * Absolute(cdz); + errbound = o3derrboundA * permanent; + if ((det > errbound) || (-det > errbound)) { + FPU_RESTORE; + return det; + } + + orient = orient3dadapt(pa, pb, pc, pd, permanent); + FPU_RESTORE; + return orient; +} + +/*****************************************************************************/ +/* */ +/* incirclefast() Approximate 2D incircle test. Nonrobust. */ +/* incircleexact() Exact 2D incircle test. Robust. */ +/* incircleslow() Another exact 2D incircle test. Robust. */ +/* incircle() Adaptive exact 2D incircle test. Robust. */ +/* */ +/* Return a positive value if the point pd lies inside the */ +/* circle passing through pa, pb, and pc; a negative value if */ +/* it lies outside; and zero if the four points are cocircular.*/ +/* The points pa, pb, and pc must be in counterclockwise */ +/* order, or the sign of the result will be reversed. */ +/* */ +/* Only the first and last routine should be used; the middle two are for */ +/* timings. */ +/* */ +/* The last three use exact arithmetic to ensure a correct answer. The */ +/* result returned is the determinant of a matrix. In incircle() only, */ +/* this determinant is computed adaptively, in the sense that exact */ +/* arithmetic is used only to the degree it is needed to ensure that the */ +/* returned value has the correct sign. Hence, incircle() is usually quite */ +/* fast, but will run more slowly when the input points are cocircular or */ +/* nearly so. */ +/* */ +/*****************************************************************************/ + +static REAL incircleadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, + REAL permanent) +{ + INEXACT REAL adx, bdx, cdx, ady, bdy, cdy; + REAL det, errbound; + + INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; + REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; + REAL bc[4], ca[4], ab[4]; + INEXACT REAL bc3, ca3, ab3; + REAL axbc[8], axxbc[16], aybc[8], ayybc[16], adet[32]; + int axbclen, axxbclen, aybclen, ayybclen, alen; + REAL bxca[8], bxxca[16], byca[8], byyca[16], bdet[32]; + int bxcalen, bxxcalen, bycalen, byycalen, blen; + REAL cxab[8], cxxab[16], cyab[8], cyyab[16], cdet[32]; + int cxablen, cxxablen, cyablen, cyyablen, clen; + REAL abdet[64]; + int ablen; + REAL fin1[1152], fin2[1152]; + REAL *finnow, *finother, *finswap; + int finlength; + + REAL adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail; + INEXACT REAL adxadx1, adyady1, bdxbdx1, bdybdy1, cdxcdx1, cdycdy1; + REAL adxadx0, adyady0, bdxbdx0, bdybdy0, cdxcdx0, cdycdy0; + REAL aa[4], bb[4], cc[4]; + INEXACT REAL aa3, bb3, cc3; + INEXACT REAL ti1, tj1; + REAL ti0, tj0; + REAL u[4], v[4]; + INEXACT REAL u3, v3; + REAL temp8[8], temp16a[16], temp16b[16], temp16c[16]; + REAL temp32a[32], temp32b[32], temp48[48], temp64[64]; + int temp8len, temp16alen, temp16blen, temp16clen; + int temp32alen, temp32blen, temp48len, temp64len; + REAL axtbb[8], axtcc[8], aytbb[8], aytcc[8]; + int axtbblen, axtcclen, aytbblen, aytcclen; + REAL bxtaa[8], bxtcc[8], bytaa[8], bytcc[8]; + int bxtaalen, bxtcclen, bytaalen, bytcclen; + REAL cxtaa[8], cxtbb[8], cytaa[8], cytbb[8]; + int cxtaalen, cxtbblen, cytaalen, cytbblen; + REAL axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8]; + int axtbclen = 0, aytbclen = 0; + int bxtcalen = 0, bytcalen = 0; + int cxtablen = 0, cytablen = 0; + REAL axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16]; + int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen; + REAL axtbctt[8], aytbctt[8], bxtcatt[8]; + REAL bytcatt[8], cxtabtt[8], cytabtt[8]; + int axtbcttlen, aytbcttlen, bxtcattlen, bytcattlen, cxtabttlen, cytabttlen; + REAL abt[8], bct[8], cat[8]; + int abtlen, bctlen, catlen; + REAL abtt[4], bctt[4], catt[4]; + int abttlen, bcttlen, cattlen; + INEXACT REAL abtt3, bctt3, catt3; + REAL negate; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + adx = (REAL) (pa[0] - pd[0]); + bdx = (REAL) (pb[0] - pd[0]); + cdx = (REAL) (pc[0] - pd[0]); + ady = (REAL) (pa[1] - pd[1]); + bdy = (REAL) (pb[1] - pd[1]); + cdy = (REAL) (pc[1] - pd[1]); + + Two_Product(bdx, cdy, bdxcdy1, bdxcdy0); + Two_Product(cdx, bdy, cdxbdy1, cdxbdy0); + Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]); + bc[3] = bc3; + axbclen = scale_expansion_zeroelim(4, bc, adx, axbc); + axxbclen = scale_expansion_zeroelim(axbclen, axbc, adx, axxbc); + aybclen = scale_expansion_zeroelim(4, bc, ady, aybc); + ayybclen = scale_expansion_zeroelim(aybclen, aybc, ady, ayybc); + alen = fast_expansion_sum_zeroelim(axxbclen, axxbc, ayybclen, ayybc, adet); + + Two_Product(cdx, ady, cdxady1, cdxady0); + Two_Product(adx, cdy, adxcdy1, adxcdy0); + Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]); + ca[3] = ca3; + bxcalen = scale_expansion_zeroelim(4, ca, bdx, bxca); + bxxcalen = scale_expansion_zeroelim(bxcalen, bxca, bdx, bxxca); + bycalen = scale_expansion_zeroelim(4, ca, bdy, byca); + byycalen = scale_expansion_zeroelim(bycalen, byca, bdy, byyca); + blen = fast_expansion_sum_zeroelim(bxxcalen, bxxca, byycalen, byyca, bdet); + + Two_Product(adx, bdy, adxbdy1, adxbdy0); + Two_Product(bdx, ady, bdxady1, bdxady0); + Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]); + ab[3] = ab3; + cxablen = scale_expansion_zeroelim(4, ab, cdx, cxab); + cxxablen = scale_expansion_zeroelim(cxablen, cxab, cdx, cxxab); + cyablen = scale_expansion_zeroelim(4, ab, cdy, cyab); + cyyablen = scale_expansion_zeroelim(cyablen, cyab, cdy, cyyab); + clen = fast_expansion_sum_zeroelim(cxxablen, cxxab, cyyablen, cyyab, cdet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1); + + det = estimate(finlength, fin1); + errbound = iccerrboundB * permanent; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pd[0], adx, adxtail); + Two_Diff_Tail(pa[1], pd[1], ady, adytail); + Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); + Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); + Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); + Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); + if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) + && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0)) { + return det; + } + + errbound = iccerrboundC * permanent + resulterrbound * Absolute(det); + det += ((adx * adx + ady * ady) * ((bdx * cdytail + cdy * bdxtail) + - (bdy * cdxtail + cdx * bdytail)) + + 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx)) + + ((bdx * bdx + bdy * bdy) * ((cdx * adytail + ady * cdxtail) + - (cdy * adxtail + adx * cdytail)) + + 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx)) + + ((cdx * cdx + cdy * cdy) * ((adx * bdytail + bdy * adxtail) + - (ady * bdxtail + bdx * adytail)) + + 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx)); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + finnow = fin1; + finother = fin2; + + if ((bdxtail != 0.0) || (bdytail != 0.0) + || (cdxtail != 0.0) || (cdytail != 0.0)) { + Square(adx, adxadx1, adxadx0); + Square(ady, adyady1, adyady0); + Two_Two_Sum(adxadx1, adxadx0, adyady1, adyady0, aa3, aa[2], aa[1], aa[0]); + aa[3] = aa3; + } + if ((cdxtail != 0.0) || (cdytail != 0.0) + || (adxtail != 0.0) || (adytail != 0.0)) { + Square(bdx, bdxbdx1, bdxbdx0); + Square(bdy, bdybdy1, bdybdy0); + Two_Two_Sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0, bb3, bb[2], bb[1], bb[0]); + bb[3] = bb3; + } + if ((adxtail != 0.0) || (adytail != 0.0) + || (bdxtail != 0.0) || (bdytail != 0.0)) { + Square(cdx, cdxcdx1, cdxcdx0); + Square(cdy, cdycdy1, cdycdy0); + Two_Two_Sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0, cc3, cc[2], cc[1], cc[0]); + cc[3] = cc3; + } + + if (adxtail != 0.0) { + axtbclen = scale_expansion_zeroelim(4, bc, adxtail, axtbc); + temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, 2.0 * adx, + temp16a); + + axtcclen = scale_expansion_zeroelim(4, cc, adxtail, axtcc); + temp16blen = scale_expansion_zeroelim(axtcclen, axtcc, bdy, temp16b); + + axtbblen = scale_expansion_zeroelim(4, bb, adxtail, axtbb); + temp16clen = scale_expansion_zeroelim(axtbblen, axtbb, -cdy, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (adytail != 0.0) { + aytbclen = scale_expansion_zeroelim(4, bc, adytail, aytbc); + temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, 2.0 * ady, + temp16a); + + aytbblen = scale_expansion_zeroelim(4, bb, adytail, aytbb); + temp16blen = scale_expansion_zeroelim(aytbblen, aytbb, cdx, temp16b); + + aytcclen = scale_expansion_zeroelim(4, cc, adytail, aytcc); + temp16clen = scale_expansion_zeroelim(aytcclen, aytcc, -bdx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdxtail != 0.0) { + bxtcalen = scale_expansion_zeroelim(4, ca, bdxtail, bxtca); + temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, 2.0 * bdx, + temp16a); + + bxtaalen = scale_expansion_zeroelim(4, aa, bdxtail, bxtaa); + temp16blen = scale_expansion_zeroelim(bxtaalen, bxtaa, cdy, temp16b); + + bxtcclen = scale_expansion_zeroelim(4, cc, bdxtail, bxtcc); + temp16clen = scale_expansion_zeroelim(bxtcclen, bxtcc, -ady, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdytail != 0.0) { + bytcalen = scale_expansion_zeroelim(4, ca, bdytail, bytca); + temp16alen = scale_expansion_zeroelim(bytcalen, bytca, 2.0 * bdy, + temp16a); + + bytcclen = scale_expansion_zeroelim(4, cc, bdytail, bytcc); + temp16blen = scale_expansion_zeroelim(bytcclen, bytcc, adx, temp16b); + + bytaalen = scale_expansion_zeroelim(4, aa, bdytail, bytaa); + temp16clen = scale_expansion_zeroelim(bytaalen, bytaa, -cdx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdxtail != 0.0) { + cxtablen = scale_expansion_zeroelim(4, ab, cdxtail, cxtab); + temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, 2.0 * cdx, + temp16a); + + cxtbblen = scale_expansion_zeroelim(4, bb, cdxtail, cxtbb); + temp16blen = scale_expansion_zeroelim(cxtbblen, cxtbb, ady, temp16b); + + cxtaalen = scale_expansion_zeroelim(4, aa, cdxtail, cxtaa); + temp16clen = scale_expansion_zeroelim(cxtaalen, cxtaa, -bdy, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdytail != 0.0) { + cytablen = scale_expansion_zeroelim(4, ab, cdytail, cytab); + temp16alen = scale_expansion_zeroelim(cytablen, cytab, 2.0 * cdy, + temp16a); + + cytaalen = scale_expansion_zeroelim(4, aa, cdytail, cytaa); + temp16blen = scale_expansion_zeroelim(cytaalen, cytaa, bdx, temp16b); + + cytbblen = scale_expansion_zeroelim(4, bb, cdytail, cytbb); + temp16clen = scale_expansion_zeroelim(cytbblen, cytbb, -adx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + if ((adxtail != 0.0) || (adytail != 0.0)) { + if ((bdxtail != 0.0) || (bdytail != 0.0) + || (cdxtail != 0.0) || (cdytail != 0.0)) { + Two_Product(bdxtail, cdy, ti1, ti0); + Two_Product(bdx, cdytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -bdy; + Two_Product(cdxtail, negate, ti1, ti0); + negate = -bdytail; + Two_Product(cdx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + bctlen = fast_expansion_sum_zeroelim(4, u, 4, v, bct); + + Two_Product(bdxtail, cdytail, ti1, ti0); + Two_Product(cdxtail, bdytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, bctt3, bctt[2], bctt[1], bctt[0]); + bctt[3] = bctt3; + bcttlen = 4; + } else { + bct[0] = 0.0; + bctlen = 1; + bctt[0] = 0.0; + bcttlen = 1; + } + + if (adxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, adxtail, temp16a); + axtbctlen = scale_expansion_zeroelim(bctlen, bct, adxtail, axtbct); + temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, 2.0 * adx, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + if (bdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, cc, adxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, bb, -adxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, adxtail, + temp32a); + axtbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adxtail, axtbctt); + temp16alen = scale_expansion_zeroelim(axtbcttlen, axtbctt, 2.0 * adx, + temp16a); + temp16blen = scale_expansion_zeroelim(axtbcttlen, axtbctt, adxtail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (adytail != 0.0) { + temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, adytail, temp16a); + aytbctlen = scale_expansion_zeroelim(bctlen, bct, adytail, aytbct); + temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, 2.0 * ady, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + + + temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, adytail, + temp32a); + aytbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adytail, aytbctt); + temp16alen = scale_expansion_zeroelim(aytbcttlen, aytbctt, 2.0 * ady, + temp16a); + temp16blen = scale_expansion_zeroelim(aytbcttlen, aytbctt, adytail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if ((bdxtail != 0.0) || (bdytail != 0.0)) { + if ((cdxtail != 0.0) || (cdytail != 0.0) + || (adxtail != 0.0) || (adytail != 0.0)) { + Two_Product(cdxtail, ady, ti1, ti0); + Two_Product(cdx, adytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -cdy; + Two_Product(adxtail, negate, ti1, ti0); + negate = -cdytail; + Two_Product(adx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + catlen = fast_expansion_sum_zeroelim(4, u, 4, v, cat); + + Two_Product(cdxtail, adytail, ti1, ti0); + Two_Product(adxtail, cdytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, catt3, catt[2], catt[1], catt[0]); + catt[3] = catt3; + cattlen = 4; + } else { + cat[0] = 0.0; + catlen = 1; + catt[0] = 0.0; + cattlen = 1; + } + + if (bdxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, bdxtail, temp16a); + bxtcatlen = scale_expansion_zeroelim(catlen, cat, bdxtail, bxtcat); + temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, 2.0 * bdx, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + if (cdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, aa, bdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (adytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, cc, -bdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, bdxtail, + temp32a); + bxtcattlen = scale_expansion_zeroelim(cattlen, catt, bdxtail, bxtcatt); + temp16alen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, 2.0 * bdx, + temp16a); + temp16blen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, bdxtail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdytail != 0.0) { + temp16alen = scale_expansion_zeroelim(bytcalen, bytca, bdytail, temp16a); + bytcatlen = scale_expansion_zeroelim(catlen, cat, bdytail, bytcat); + temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, 2.0 * bdy, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + + + temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, bdytail, + temp32a); + bytcattlen = scale_expansion_zeroelim(cattlen, catt, bdytail, bytcatt); + temp16alen = scale_expansion_zeroelim(bytcattlen, bytcatt, 2.0 * bdy, + temp16a); + temp16blen = scale_expansion_zeroelim(bytcattlen, bytcatt, bdytail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if ((cdxtail != 0.0) || (cdytail != 0.0)) { + if ((adxtail != 0.0) || (adytail != 0.0) + || (bdxtail != 0.0) || (bdytail != 0.0)) { + Two_Product(adxtail, bdy, ti1, ti0); + Two_Product(adx, bdytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -ady; + Two_Product(bdxtail, negate, ti1, ti0); + negate = -adytail; + Two_Product(bdx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + abtlen = fast_expansion_sum_zeroelim(4, u, 4, v, abt); + + Two_Product(adxtail, bdytail, ti1, ti0); + Two_Product(bdxtail, adytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, abtt3, abtt[2], abtt[1], abtt[0]); + abtt[3] = abtt3; + abttlen = 4; + } else { + abt[0] = 0.0; + abtlen = 1; + abtt[0] = 0.0; + abttlen = 1; + } + + if (cdxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, cdxtail, temp16a); + cxtabtlen = scale_expansion_zeroelim(abtlen, abt, cdxtail, cxtabt); + temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, 2.0 * cdx, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + if (adytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, bb, cdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, aa, -cdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, cdxtail, + temp32a); + cxtabttlen = scale_expansion_zeroelim(abttlen, abtt, cdxtail, cxtabtt); + temp16alen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, 2.0 * cdx, + temp16a); + temp16blen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, cdxtail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdytail != 0.0) { + temp16alen = scale_expansion_zeroelim(cytablen, cytab, cdytail, temp16a); + cytabtlen = scale_expansion_zeroelim(abtlen, abt, cdytail, cytabt); + temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, 2.0 * cdy, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + + + temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, cdytail, + temp32a); + cytabttlen = scale_expansion_zeroelim(abttlen, abtt, cdytail, cytabtt); + temp16alen = scale_expansion_zeroelim(cytabttlen, cytabtt, 2.0 * cdy, + temp16a); + temp16blen = scale_expansion_zeroelim(cytabttlen, cytabtt, cdytail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + + return finnow[finlength - 1]; +} + +REAL incircle(pa, pb, pc, pd) +REAL *pa; +REAL *pb; +REAL *pc; +REAL *pd; +{ + REAL adx, bdx, cdx, ady, bdy, cdy; + REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; + REAL alift, blift, clift; + REAL det; + REAL permanent, errbound; + REAL inc; + + FPU_ROUND_DOUBLE; + + adx = pa[0] - pd[0]; + bdx = pb[0] - pd[0]; + cdx = pc[0] - pd[0]; + ady = pa[1] - pd[1]; + bdy = pb[1] - pd[1]; + cdy = pc[1] - pd[1]; + + bdxcdy = bdx * cdy; + cdxbdy = cdx * bdy; + alift = adx * adx + ady * ady; + + cdxady = cdx * ady; + adxcdy = adx * cdy; + blift = bdx * bdx + bdy * bdy; + + adxbdy = adx * bdy; + bdxady = bdx * ady; + clift = cdx * cdx + cdy * cdy; + + det = alift * (bdxcdy - cdxbdy) + + blift * (cdxady - adxcdy) + + clift * (adxbdy - bdxady); + + permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift + + (Absolute(cdxady) + Absolute(adxcdy)) * blift + + (Absolute(adxbdy) + Absolute(bdxady)) * clift; + errbound = iccerrboundA * permanent; + if ((det > errbound) || (-det > errbound)) { + FPU_RESTORE; + return det; + } + + inc = incircleadapt(pa, pb, pc, pd, permanent); + FPU_RESTORE; + return inc; +} + +/*****************************************************************************/ +/* */ +/* inspherefast() Approximate 3D insphere test. Nonrobust. */ +/* insphereexact() Exact 3D insphere test. Robust. */ +/* insphereslow() Another exact 3D insphere test. Robust. */ +/* insphere() Adaptive exact 3D insphere test. Robust. */ +/* */ +/* Return a positive value if the point pe lies inside the */ +/* sphere passing through pa, pb, pc, and pd; a negative value */ +/* if it lies outside; and zero if the five points are */ +/* cospherical. The points pa, pb, pc, and pd must be ordered */ +/* so that they have a positive orientation (as defined by */ +/* orient3d()), or the sign of the result will be reversed. */ +/* */ +/* Only the first and last routine should be used; the middle two are for */ +/* timings. */ +/* */ +/* The last three use exact arithmetic to ensure a correct answer. The */ +/* result returned is the determinant of a matrix. In insphere() only, */ +/* this determinant is computed adaptively, in the sense that exact */ +/* arithmetic is used only to the degree it is needed to ensure that the */ +/* returned value has the correct sign. Hence, insphere() is usually quite */ +/* fast, but will run more slowly when the input points are cospherical or */ +/* nearly so. */ +/* */ +/*****************************************************************************/ + +static REAL insphereexact(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe) +{ + INEXACT REAL axby1, bxcy1, cxdy1, dxey1, exay1; + INEXACT REAL bxay1, cxby1, dxcy1, exdy1, axey1; + INEXACT REAL axcy1, bxdy1, cxey1, dxay1, exby1; + INEXACT REAL cxay1, dxby1, excy1, axdy1, bxey1; + REAL axby0, bxcy0, cxdy0, dxey0, exay0; + REAL bxay0, cxby0, dxcy0, exdy0, axey0; + REAL axcy0, bxdy0, cxey0, dxay0, exby0; + REAL cxay0, dxby0, excy0, axdy0, bxey0; + REAL ab[4], bc[4], cd[4], de[4], ea[4]; + REAL ac[4], bd[4], ce[4], da[4], eb[4]; + REAL temp8a[8], temp8b[8], temp16[16]; + int temp8alen, temp8blen, temp16len; + REAL abc[24], bcd[24], cde[24], dea[24], eab[24]; + REAL abd[24], bce[24], cda[24], deb[24], eac[24]; + int abclen, bcdlen, cdelen, dealen, eablen; + int abdlen, bcelen, cdalen, deblen, eaclen; + REAL temp48a[48], temp48b[48]; + int temp48alen, temp48blen; + REAL abcd[96], bcde[96], cdea[96], deab[96], eabc[96]; + int abcdlen, bcdelen, cdealen, deablen, eabclen; + REAL temp192[192]; + REAL det384x[384], det384y[384], det384z[384]; + int xlen, ylen, zlen; + REAL detxy[768]; + int xylen; + REAL adet[1152], bdet[1152], cdet[1152], ddet[1152], edet[1152]; + int alen, blen, clen, dlen, elen; + REAL abdet[2304], cddet[2304], cdedet[3456]; + int ablen, cdlen; + REAL deter[5760]; + int deterlen; + int i; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + Two_Product(pa[0], pb[1], axby1, axby0); + Two_Product(pb[0], pa[1], bxay1, bxay0); + Two_Two_Diff(axby1, axby0, bxay1, bxay0, ab[3], ab[2], ab[1], ab[0]); + + Two_Product(pb[0], pc[1], bxcy1, bxcy0); + Two_Product(pc[0], pb[1], cxby1, cxby0); + Two_Two_Diff(bxcy1, bxcy0, cxby1, cxby0, bc[3], bc[2], bc[1], bc[0]); + + Two_Product(pc[0], pd[1], cxdy1, cxdy0); + Two_Product(pd[0], pc[1], dxcy1, dxcy0); + Two_Two_Diff(cxdy1, cxdy0, dxcy1, dxcy0, cd[3], cd[2], cd[1], cd[0]); + + Two_Product(pd[0], pe[1], dxey1, dxey0); + Two_Product(pe[0], pd[1], exdy1, exdy0); + Two_Two_Diff(dxey1, dxey0, exdy1, exdy0, de[3], de[2], de[1], de[0]); + + Two_Product(pe[0], pa[1], exay1, exay0); + Two_Product(pa[0], pe[1], axey1, axey0); + Two_Two_Diff(exay1, exay0, axey1, axey0, ea[3], ea[2], ea[1], ea[0]); + + Two_Product(pa[0], pc[1], axcy1, axcy0); + Two_Product(pc[0], pa[1], cxay1, cxay0); + Two_Two_Diff(axcy1, axcy0, cxay1, cxay0, ac[3], ac[2], ac[1], ac[0]); + + Two_Product(pb[0], pd[1], bxdy1, bxdy0); + Two_Product(pd[0], pb[1], dxby1, dxby0); + Two_Two_Diff(bxdy1, bxdy0, dxby1, dxby0, bd[3], bd[2], bd[1], bd[0]); + + Two_Product(pc[0], pe[1], cxey1, cxey0); + Two_Product(pe[0], pc[1], excy1, excy0); + Two_Two_Diff(cxey1, cxey0, excy1, excy0, ce[3], ce[2], ce[1], ce[0]); + + Two_Product(pd[0], pa[1], dxay1, dxay0); + Two_Product(pa[0], pd[1], axdy1, axdy0); + Two_Two_Diff(dxay1, dxay0, axdy1, axdy0, da[3], da[2], da[1], da[0]); + + Two_Product(pe[0], pb[1], exby1, exby0); + Two_Product(pb[0], pe[1], bxey1, bxey0); + Two_Two_Diff(exby1, exby0, bxey1, bxey0, eb[3], eb[2], eb[1], eb[0]); + + temp8alen = scale_expansion_zeroelim(4, bc, pa[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, ac, -pb[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, ab, pc[2], temp8a); + abclen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + abc); + + temp8alen = scale_expansion_zeroelim(4, cd, pb[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, bd, -pc[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, bc, pd[2], temp8a); + bcdlen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + bcd); + + temp8alen = scale_expansion_zeroelim(4, de, pc[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, ce, -pd[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, cd, pe[2], temp8a); + cdelen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + cde); + + temp8alen = scale_expansion_zeroelim(4, ea, pd[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, da, -pe[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, de, pa[2], temp8a); + dealen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + dea); + + temp8alen = scale_expansion_zeroelim(4, ab, pe[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, eb, -pa[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, ea, pb[2], temp8a); + eablen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + eab); + + temp8alen = scale_expansion_zeroelim(4, bd, pa[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, da, pb[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, ab, pd[2], temp8a); + abdlen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + abd); + + temp8alen = scale_expansion_zeroelim(4, ce, pb[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, eb, pc[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, bc, pe[2], temp8a); + bcelen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + bce); + + temp8alen = scale_expansion_zeroelim(4, da, pc[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, ac, pd[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, cd, pa[2], temp8a); + cdalen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + cda); + + temp8alen = scale_expansion_zeroelim(4, eb, pd[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, bd, pe[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, de, pb[2], temp8a); + deblen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + deb); + + temp8alen = scale_expansion_zeroelim(4, ac, pe[2], temp8a); + temp8blen = scale_expansion_zeroelim(4, ce, pa[2], temp8b); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp8blen, temp8b, + temp16); + temp8alen = scale_expansion_zeroelim(4, ea, pc[2], temp8a); + eaclen = fast_expansion_sum_zeroelim(temp8alen, temp8a, temp16len, temp16, + eac); + + temp48alen = fast_expansion_sum_zeroelim(cdelen, cde, bcelen, bce, temp48a); + temp48blen = fast_expansion_sum_zeroelim(deblen, deb, bcdlen, bcd, temp48b); + for (i = 0; i < temp48blen; i++) { + temp48b[i] = -temp48b[i]; + } + bcdelen = fast_expansion_sum_zeroelim(temp48alen, temp48a, + temp48blen, temp48b, bcde); + xlen = scale_expansion_zeroelim(bcdelen, bcde, pa[0], temp192); + xlen = scale_expansion_zeroelim(xlen, temp192, pa[0], det384x); + ylen = scale_expansion_zeroelim(bcdelen, bcde, pa[1], temp192); + ylen = scale_expansion_zeroelim(ylen, temp192, pa[1], det384y); + zlen = scale_expansion_zeroelim(bcdelen, bcde, pa[2], temp192); + zlen = scale_expansion_zeroelim(zlen, temp192, pa[2], det384z); + xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); + alen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, adet); + + temp48alen = fast_expansion_sum_zeroelim(dealen, dea, cdalen, cda, temp48a); + temp48blen = fast_expansion_sum_zeroelim(eaclen, eac, cdelen, cde, temp48b); + for (i = 0; i < temp48blen; i++) { + temp48b[i] = -temp48b[i]; + } + cdealen = fast_expansion_sum_zeroelim(temp48alen, temp48a, + temp48blen, temp48b, cdea); + xlen = scale_expansion_zeroelim(cdealen, cdea, pb[0], temp192); + xlen = scale_expansion_zeroelim(xlen, temp192, pb[0], det384x); + ylen = scale_expansion_zeroelim(cdealen, cdea, pb[1], temp192); + ylen = scale_expansion_zeroelim(ylen, temp192, pb[1], det384y); + zlen = scale_expansion_zeroelim(cdealen, cdea, pb[2], temp192); + zlen = scale_expansion_zeroelim(zlen, temp192, pb[2], det384z); + xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); + blen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, bdet); + + temp48alen = fast_expansion_sum_zeroelim(eablen, eab, deblen, deb, temp48a); + temp48blen = fast_expansion_sum_zeroelim(abdlen, abd, dealen, dea, temp48b); + for (i = 0; i < temp48blen; i++) { + temp48b[i] = -temp48b[i]; + } + deablen = fast_expansion_sum_zeroelim(temp48alen, temp48a, + temp48blen, temp48b, deab); + xlen = scale_expansion_zeroelim(deablen, deab, pc[0], temp192); + xlen = scale_expansion_zeroelim(xlen, temp192, pc[0], det384x); + ylen = scale_expansion_zeroelim(deablen, deab, pc[1], temp192); + ylen = scale_expansion_zeroelim(ylen, temp192, pc[1], det384y); + zlen = scale_expansion_zeroelim(deablen, deab, pc[2], temp192); + zlen = scale_expansion_zeroelim(zlen, temp192, pc[2], det384z); + xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); + clen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, cdet); + + temp48alen = fast_expansion_sum_zeroelim(abclen, abc, eaclen, eac, temp48a); + temp48blen = fast_expansion_sum_zeroelim(bcelen, bce, eablen, eab, temp48b); + for (i = 0; i < temp48blen; i++) { + temp48b[i] = -temp48b[i]; + } + eabclen = fast_expansion_sum_zeroelim(temp48alen, temp48a, + temp48blen, temp48b, eabc); + xlen = scale_expansion_zeroelim(eabclen, eabc, pd[0], temp192); + xlen = scale_expansion_zeroelim(xlen, temp192, pd[0], det384x); + ylen = scale_expansion_zeroelim(eabclen, eabc, pd[1], temp192); + ylen = scale_expansion_zeroelim(ylen, temp192, pd[1], det384y); + zlen = scale_expansion_zeroelim(eabclen, eabc, pd[2], temp192); + zlen = scale_expansion_zeroelim(zlen, temp192, pd[2], det384z); + xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); + dlen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, ddet); + + temp48alen = fast_expansion_sum_zeroelim(bcdlen, bcd, abdlen, abd, temp48a); + temp48blen = fast_expansion_sum_zeroelim(cdalen, cda, abclen, abc, temp48b); + for (i = 0; i < temp48blen; i++) { + temp48b[i] = -temp48b[i]; + } + abcdlen = fast_expansion_sum_zeroelim(temp48alen, temp48a, + temp48blen, temp48b, abcd); + xlen = scale_expansion_zeroelim(abcdlen, abcd, pe[0], temp192); + xlen = scale_expansion_zeroelim(xlen, temp192, pe[0], det384x); + ylen = scale_expansion_zeroelim(abcdlen, abcd, pe[1], temp192); + ylen = scale_expansion_zeroelim(ylen, temp192, pe[1], det384y); + zlen = scale_expansion_zeroelim(abcdlen, abcd, pe[2], temp192); + zlen = scale_expansion_zeroelim(zlen, temp192, pe[2], det384z); + xylen = fast_expansion_sum_zeroelim(xlen, det384x, ylen, det384y, detxy); + elen = fast_expansion_sum_zeroelim(xylen, detxy, zlen, det384z, edet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); + cdelen = fast_expansion_sum_zeroelim(cdlen, cddet, elen, edet, cdedet); + deterlen = fast_expansion_sum_zeroelim(ablen, abdet, cdelen, cdedet, deter); + + return deter[deterlen - 1]; +} + +static REAL insphereadapt(REAL *pa, REAL *pb, REAL *pc, REAL *pd, REAL *pe, + REAL permanent) +{ + INEXACT REAL aex, bex, cex, dex, aey, bey, cey, dey, aez, bez, cez, dez; + REAL det, errbound; + + INEXACT REAL aexbey1, bexaey1, bexcey1, cexbey1; + INEXACT REAL cexdey1, dexcey1, dexaey1, aexdey1; + INEXACT REAL aexcey1, cexaey1, bexdey1, dexbey1; + REAL aexbey0, bexaey0, bexcey0, cexbey0; + REAL cexdey0, dexcey0, dexaey0, aexdey0; + REAL aexcey0, cexaey0, bexdey0, dexbey0; + REAL ab[4], bc[4], cd[4], da[4], ac[4], bd[4]; + INEXACT REAL ab3, bc3, cd3, da3, ac3, bd3; + REAL abeps, bceps, cdeps, daeps, aceps, bdeps; + REAL temp8a[8], temp8b[8], temp8c[8], temp16[16], temp24[24], temp48[48]; + int temp8alen, temp8blen, temp8clen, temp16len, temp24len, temp48len; + REAL xdet[96], ydet[96], zdet[96], xydet[192]; + int xlen, ylen, zlen, xylen; + REAL adet[288], bdet[288], cdet[288], ddet[288]; + int alen, blen, clen, dlen; + REAL abdet[576], cddet[576]; + int ablen, cdlen; + REAL fin1[1152]; + int finlength; + + REAL aextail, bextail, cextail, dextail; + REAL aeytail, beytail, ceytail, deytail; + REAL aeztail, beztail, ceztail, deztail; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + aex = (REAL) (pa[0] - pe[0]); + bex = (REAL) (pb[0] - pe[0]); + cex = (REAL) (pc[0] - pe[0]); + dex = (REAL) (pd[0] - pe[0]); + aey = (REAL) (pa[1] - pe[1]); + bey = (REAL) (pb[1] - pe[1]); + cey = (REAL) (pc[1] - pe[1]); + dey = (REAL) (pd[1] - pe[1]); + aez = (REAL) (pa[2] - pe[2]); + bez = (REAL) (pb[2] - pe[2]); + cez = (REAL) (pc[2] - pe[2]); + dez = (REAL) (pd[2] - pe[2]); + + Two_Product(aex, bey, aexbey1, aexbey0); + Two_Product(bex, aey, bexaey1, bexaey0); + Two_Two_Diff(aexbey1, aexbey0, bexaey1, bexaey0, ab3, ab[2], ab[1], ab[0]); + ab[3] = ab3; + + Two_Product(bex, cey, bexcey1, bexcey0); + Two_Product(cex, bey, cexbey1, cexbey0); + Two_Two_Diff(bexcey1, bexcey0, cexbey1, cexbey0, bc3, bc[2], bc[1], bc[0]); + bc[3] = bc3; + + Two_Product(cex, dey, cexdey1, cexdey0); + Two_Product(dex, cey, dexcey1, dexcey0); + Two_Two_Diff(cexdey1, cexdey0, dexcey1, dexcey0, cd3, cd[2], cd[1], cd[0]); + cd[3] = cd3; + + Two_Product(dex, aey, dexaey1, dexaey0); + Two_Product(aex, dey, aexdey1, aexdey0); + Two_Two_Diff(dexaey1, dexaey0, aexdey1, aexdey0, da3, da[2], da[1], da[0]); + da[3] = da3; + + Two_Product(aex, cey, aexcey1, aexcey0); + Two_Product(cex, aey, cexaey1, cexaey0); + Two_Two_Diff(aexcey1, aexcey0, cexaey1, cexaey0, ac3, ac[2], ac[1], ac[0]); + ac[3] = ac3; + + Two_Product(bex, dey, bexdey1, bexdey0); + Two_Product(dex, bey, dexbey1, dexbey0); + Two_Two_Diff(bexdey1, bexdey0, dexbey1, dexbey0, bd3, bd[2], bd[1], bd[0]); + bd[3] = bd3; + + temp8alen = scale_expansion_zeroelim(4, cd, bez, temp8a); + temp8blen = scale_expansion_zeroelim(4, bd, -cez, temp8b); + temp8clen = scale_expansion_zeroelim(4, bc, dez, temp8c); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, + temp8blen, temp8b, temp16); + temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, + temp16len, temp16, temp24); + temp48len = scale_expansion_zeroelim(temp24len, temp24, aex, temp48); + xlen = scale_expansion_zeroelim(temp48len, temp48, -aex, xdet); + temp48len = scale_expansion_zeroelim(temp24len, temp24, aey, temp48); + ylen = scale_expansion_zeroelim(temp48len, temp48, -aey, ydet); + temp48len = scale_expansion_zeroelim(temp24len, temp24, aez, temp48); + zlen = scale_expansion_zeroelim(temp48len, temp48, -aez, zdet); + xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); + alen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, adet); + + temp8alen = scale_expansion_zeroelim(4, da, cez, temp8a); + temp8blen = scale_expansion_zeroelim(4, ac, dez, temp8b); + temp8clen = scale_expansion_zeroelim(4, cd, aez, temp8c); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, + temp8blen, temp8b, temp16); + temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, + temp16len, temp16, temp24); + temp48len = scale_expansion_zeroelim(temp24len, temp24, bex, temp48); + xlen = scale_expansion_zeroelim(temp48len, temp48, bex, xdet); + temp48len = scale_expansion_zeroelim(temp24len, temp24, bey, temp48); + ylen = scale_expansion_zeroelim(temp48len, temp48, bey, ydet); + temp48len = scale_expansion_zeroelim(temp24len, temp24, bez, temp48); + zlen = scale_expansion_zeroelim(temp48len, temp48, bez, zdet); + xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); + blen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, bdet); + + temp8alen = scale_expansion_zeroelim(4, ab, dez, temp8a); + temp8blen = scale_expansion_zeroelim(4, bd, aez, temp8b); + temp8clen = scale_expansion_zeroelim(4, da, bez, temp8c); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, + temp8blen, temp8b, temp16); + temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, + temp16len, temp16, temp24); + temp48len = scale_expansion_zeroelim(temp24len, temp24, cex, temp48); + xlen = scale_expansion_zeroelim(temp48len, temp48, -cex, xdet); + temp48len = scale_expansion_zeroelim(temp24len, temp24, cey, temp48); + ylen = scale_expansion_zeroelim(temp48len, temp48, -cey, ydet); + temp48len = scale_expansion_zeroelim(temp24len, temp24, cez, temp48); + zlen = scale_expansion_zeroelim(temp48len, temp48, -cez, zdet); + xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); + clen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, cdet); + + temp8alen = scale_expansion_zeroelim(4, bc, aez, temp8a); + temp8blen = scale_expansion_zeroelim(4, ac, -bez, temp8b); + temp8clen = scale_expansion_zeroelim(4, ab, cez, temp8c); + temp16len = fast_expansion_sum_zeroelim(temp8alen, temp8a, + temp8blen, temp8b, temp16); + temp24len = fast_expansion_sum_zeroelim(temp8clen, temp8c, + temp16len, temp16, temp24); + temp48len = scale_expansion_zeroelim(temp24len, temp24, dex, temp48); + xlen = scale_expansion_zeroelim(temp48len, temp48, dex, xdet); + temp48len = scale_expansion_zeroelim(temp24len, temp24, dey, temp48); + ylen = scale_expansion_zeroelim(temp48len, temp48, dey, ydet); + temp48len = scale_expansion_zeroelim(temp24len, temp24, dez, temp48); + zlen = scale_expansion_zeroelim(temp48len, temp48, dez, zdet); + xylen = fast_expansion_sum_zeroelim(xlen, xdet, ylen, ydet, xydet); + dlen = fast_expansion_sum_zeroelim(xylen, xydet, zlen, zdet, ddet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + cdlen = fast_expansion_sum_zeroelim(clen, cdet, dlen, ddet, cddet); + finlength = fast_expansion_sum_zeroelim(ablen, abdet, cdlen, cddet, fin1); + + det = estimate(finlength, fin1); + errbound = isperrboundB * permanent; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pe[0], aex, aextail); + Two_Diff_Tail(pa[1], pe[1], aey, aeytail); + Two_Diff_Tail(pa[2], pe[2], aez, aeztail); + Two_Diff_Tail(pb[0], pe[0], bex, bextail); + Two_Diff_Tail(pb[1], pe[1], bey, beytail); + Two_Diff_Tail(pb[2], pe[2], bez, beztail); + Two_Diff_Tail(pc[0], pe[0], cex, cextail); + Two_Diff_Tail(pc[1], pe[1], cey, ceytail); + Two_Diff_Tail(pc[2], pe[2], cez, ceztail); + Two_Diff_Tail(pd[0], pe[0], dex, dextail); + Two_Diff_Tail(pd[1], pe[1], dey, deytail); + Two_Diff_Tail(pd[2], pe[2], dez, deztail); + if ((aextail == 0.0) && (aeytail == 0.0) && (aeztail == 0.0) + && (bextail == 0.0) && (beytail == 0.0) && (beztail == 0.0) + && (cextail == 0.0) && (ceytail == 0.0) && (ceztail == 0.0) + && (dextail == 0.0) && (deytail == 0.0) && (deztail == 0.0)) { + return det; + } + + errbound = isperrboundC * permanent + resulterrbound * Absolute(det); + abeps = (aex * beytail + bey * aextail) + - (aey * bextail + bex * aeytail); + bceps = (bex * ceytail + cey * bextail) + - (bey * cextail + cex * beytail); + cdeps = (cex * deytail + dey * cextail) + - (cey * dextail + dex * ceytail); + daeps = (dex * aeytail + aey * dextail) + - (dey * aextail + aex * deytail); + aceps = (aex * ceytail + cey * aextail) + - (aey * cextail + cex * aeytail); + bdeps = (bex * deytail + dey * bextail) + - (bey * dextail + dex * beytail); + det += (((bex * bex + bey * bey + bez * bez) + * ((cez * daeps + dez * aceps + aez * cdeps) + + (ceztail * da3 + deztail * ac3 + aeztail * cd3)) + + (dex * dex + dey * dey + dez * dez) + * ((aez * bceps - bez * aceps + cez * abeps) + + (aeztail * bc3 - beztail * ac3 + ceztail * ab3))) + - ((aex * aex + aey * aey + aez * aez) + * ((bez * cdeps - cez * bdeps + dez * bceps) + + (beztail * cd3 - ceztail * bd3 + deztail * bc3)) + + (cex * cex + cey * cey + cez * cez) + * ((dez * abeps + aez * bdeps + bez * daeps) + + (deztail * ab3 + aeztail * bd3 + beztail * da3)))) + + 2.0 * (((bex * bextail + bey * beytail + bez * beztail) + * (cez * da3 + dez * ac3 + aez * cd3) + + (dex * dextail + dey * deytail + dez * deztail) + * (aez * bc3 - bez * ac3 + cez * ab3)) + - ((aex * aextail + aey * aeytail + aez * aeztail) + * (bez * cd3 - cez * bd3 + dez * bc3) + + (cex * cextail + cey * ceytail + cez * ceztail) + * (dez * ab3 + aez * bd3 + bez * da3))); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + return insphereexact(pa, pb, pc, pd, pe); +} + +REAL insphere(pa, pb, pc, pd, pe) +REAL *pa; +REAL *pb; +REAL *pc; +REAL *pd; +REAL *pe; +{ + REAL aex, bex, cex, dex; + REAL aey, bey, cey, dey; + REAL aez, bez, cez, dez; + REAL aexbey, bexaey, bexcey, cexbey, cexdey, dexcey, dexaey, aexdey; + REAL aexcey, cexaey, bexdey, dexbey; + REAL alift, blift, clift, dlift; + REAL ab, bc, cd, da, ac, bd; + REAL abc, bcd, cda, dab; + REAL aezplus, bezplus, cezplus, dezplus; + REAL aexbeyplus, bexaeyplus, bexceyplus, cexbeyplus; + REAL cexdeyplus, dexceyplus, dexaeyplus, aexdeyplus; + REAL aexceyplus, cexaeyplus, bexdeyplus, dexbeyplus; + REAL det; + REAL permanent, errbound; + REAL ins; + + FPU_ROUND_DOUBLE; + + aex = pa[0] - pe[0]; + bex = pb[0] - pe[0]; + cex = pc[0] - pe[0]; + dex = pd[0] - pe[0]; + aey = pa[1] - pe[1]; + bey = pb[1] - pe[1]; + cey = pc[1] - pe[1]; + dey = pd[1] - pe[1]; + aez = pa[2] - pe[2]; + bez = pb[2] - pe[2]; + cez = pc[2] - pe[2]; + dez = pd[2] - pe[2]; + + aexbey = aex * bey; + bexaey = bex * aey; + ab = aexbey - bexaey; + bexcey = bex * cey; + cexbey = cex * bey; + bc = bexcey - cexbey; + cexdey = cex * dey; + dexcey = dex * cey; + cd = cexdey - dexcey; + dexaey = dex * aey; + aexdey = aex * dey; + da = dexaey - aexdey; + + aexcey = aex * cey; + cexaey = cex * aey; + ac = aexcey - cexaey; + bexdey = bex * dey; + dexbey = dex * bey; + bd = bexdey - dexbey; + + abc = aez * bc - bez * ac + cez * ab; + bcd = bez * cd - cez * bd + dez * bc; + cda = cez * da + dez * ac + aez * cd; + dab = dez * ab + aez * bd + bez * da; + + alift = aex * aex + aey * aey + aez * aez; + blift = bex * bex + bey * bey + bez * bez; + clift = cex * cex + cey * cey + cez * cez; + dlift = dex * dex + dey * dey + dez * dez; + + det = (dlift * abc - clift * dab) + (blift * cda - alift * bcd); + + aezplus = Absolute(aez); + bezplus = Absolute(bez); + cezplus = Absolute(cez); + dezplus = Absolute(dez); + aexbeyplus = Absolute(aexbey); + bexaeyplus = Absolute(bexaey); + bexceyplus = Absolute(bexcey); + cexbeyplus = Absolute(cexbey); + cexdeyplus = Absolute(cexdey); + dexceyplus = Absolute(dexcey); + dexaeyplus = Absolute(dexaey); + aexdeyplus = Absolute(aexdey); + aexceyplus = Absolute(aexcey); + cexaeyplus = Absolute(cexaey); + bexdeyplus = Absolute(bexdey); + dexbeyplus = Absolute(dexbey); + permanent = ((cexdeyplus + dexceyplus) * bezplus + + (dexbeyplus + bexdeyplus) * cezplus + + (bexceyplus + cexbeyplus) * dezplus) + * alift + + ((dexaeyplus + aexdeyplus) * cezplus + + (aexceyplus + cexaeyplus) * dezplus + + (cexdeyplus + dexceyplus) * aezplus) + * blift + + ((aexbeyplus + bexaeyplus) * dezplus + + (bexdeyplus + dexbeyplus) * aezplus + + (dexaeyplus + aexdeyplus) * bezplus) + * clift + + ((bexceyplus + cexbeyplus) * aezplus + + (cexaeyplus + aexceyplus) * bezplus + + (aexbeyplus + bexaeyplus) * cezplus) + * dlift; + errbound = isperrboundA * permanent; + if ((det > errbound) || (-det > errbound)) { + FPU_RESTORE; + return det; + } + + ins = insphereadapt(pa, pb, pc, pd, pe, permanent); + FPU_RESTORE; + return ins; +} Index: work/obsolete/toporouter/src_3rd/gts/predicates.h =================================================================== --- work/obsolete/toporouter/src_3rd/gts/predicates.h (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/predicates.h (revision 6803) @@ -0,0 +1,41 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +/* Header file for robust predicates by Jonathan Richard Shewchuk */ + +#ifndef __PREDICATES_H__ +#define __PREDICATES_H__ + +double orient2d (double * pa, + double * pb, + double * pc); +double orient3d (double * pa, + double * pb, + double * pc, + double * pd); +double incircle (double * pa, + double * pb, + double * pc, + double * pd); +double insphere (double * pa, + double * pb, + double * pc, + double * pd, + double * pe); + +#endif /* __PREDICATES_H__ */ Index: work/obsolete/toporouter/src_3rd/gts/psurface.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/psurface.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/psurface.c (revision 6803) @@ -0,0 +1,471 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include "gts.h" + +#define HEAP_INSERT_OBJECT(h, e) (GTS_OBJECT (e)->reserved =\ + gts_eheap_insert (h, e)) +#define HEAP_REMOVE_OBJECT(h, e) (gts_eheap_remove (h, GTS_OBJECT (e)->reserved),\ + GTS_OBJECT (e)->reserved = NULL) + +static void psurface_destroy (GtsObject * object) +{ + GtsPSurface * ps = GTS_PSURFACE (object); + guint i; + + if (!GTS_PSURFACE_IS_CLOSED (ps)) + gts_psurface_close (ps); + + for (i = 0; i < ps->split->len; i++) + if (g_ptr_array_index (ps->split, i)) + gts_object_destroy (GTS_OBJECT (g_ptr_array_index (ps->split, i))); + g_ptr_array_free (ps->split, TRUE); + + (* GTS_OBJECT_CLASS (gts_psurface_class ())->parent_class->destroy) (object); +} + +static void psurface_class_init (GtsObjectClass * klass) +{ + klass->destroy = psurface_destroy; +} + +static void psurface_init (GtsPSurface * psurface) +{ + psurface->s = NULL; + psurface->split = g_ptr_array_new (); + psurface->split_class = gts_split_class (); + psurface->pos = psurface->min = 0; + psurface->vertices = psurface->faces = NULL; +} + +/** + * gts_psurface_class: + * + * Returns: the #GtsPSurfaceClass. + */ +GtsPSurfaceClass * gts_psurface_class (void) +{ + static GtsPSurfaceClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo psurface_info = { + "GtsPSurface", + sizeof (GtsPSurface), + sizeof (GtsPSurfaceClass), + (GtsObjectClassInitFunc) psurface_class_init, + (GtsObjectInitFunc) psurface_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (gts_object_class (), + &psurface_info); + } + + return klass; +} + +static GtsVertex * edge_collapse (GtsPSurface * ps, + GtsEdge * e, + GtsEHeap * heap, + GtsCoarsenFunc coarsen_func, + gpointer coarsen_data, + gdouble maxcosine2) +{ + GtsVertex * v1 = GTS_SEGMENT (e)->v1, * v2 = GTS_SEGMENT (e)->v2, * mid; + GtsSplit * vs; + GtsObject * o1, * o2; + + /* if the edge is degenerate (i.e. v1 == v2), destroy and return */ + if (v1 == v2) { + gts_object_destroy (GTS_OBJECT (e)); + return NULL; + } + + if (!gts_edge_collapse_is_valid (e) || + /* check that a non-manifold edge is not a contact edge */ + (g_slist_length (e->triangles) > 2 && gts_edge_is_contact (e) > 1)) { + GTS_OBJECT (e)->reserved = + gts_eheap_insert_with_key (heap, e, G_MAXDOUBLE); + return NULL; + } + + mid = (*coarsen_func) (e, ps->s->vertex_class, coarsen_data); + + if (gts_edge_collapse_creates_fold (e, mid, maxcosine2)) { + GTS_OBJECT (e)->reserved = + gts_eheap_insert_with_key (heap, e, G_MAXDOUBLE); + gts_object_destroy (GTS_OBJECT (mid)); + return NULL; + } + + if (GTS_OBJECT (v1)->reserved) + o1 = GTS_OBJECT (v1)->reserved; + else + o1 = GTS_OBJECT (v1); + if (GTS_OBJECT (v2)->reserved) + o2 = GTS_OBJECT (v2)->reserved; + else + o2 = GTS_OBJECT (v2); + vs = gts_split_new (ps->split_class, mid, o1, o2); + gts_split_collapse (vs, ps->s->edge_class, heap); + GTS_OBJECT (vs->v)->reserved = vs; + g_ptr_array_add (ps->split, vs); + + return mid; +} + +static void update_2nd_closest_neighbors (GtsVertex * v, GtsEHeap * heap) +{ + GSList * i = v->segments; + GSList * list = NULL; + + while (i) { + GtsSegment * s = i->data; + if (GTS_IS_EDGE (s)) { + GtsVertex * v1 = s->v1 == v ? s->v2 : s->v1; + GSList * j = v1->segments; + while (j) { + GtsSegment * s1 = j->data; + if (GTS_IS_EDGE (s1) && !g_slist_find (list, s1)) + list = g_slist_prepend (list, s1); + j = j->next; + } + } + i = i->next; + } + + i = list; + while (i) { + GtsEdge * e = i->data; + if (GTS_OBJECT (e)->reserved) + HEAP_REMOVE_OBJECT (heap, e); + HEAP_INSERT_OBJECT (heap, e); + i = i->next; + } + + g_slist_free (list); +} + +static gdouble edge_length2 (GtsEdge * e) +{ + return gts_point_distance2 (GTS_POINT (GTS_SEGMENT (e)->v1), + GTS_POINT (GTS_SEGMENT (e)->v2)); +} + +static void create_heap_coarsen (GtsEdge * e, GtsEHeap * heap) +{ + HEAP_INSERT_OBJECT (heap, e); +} + +/* #define DEBUG_FOLD */ +/* #define DEBUG_CONTACT_VERTEX */ + +#ifdef DEBUG_FOLD +static void check_fold (GtsTriangle * t, gdouble * maxcosine2) +{ + GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3; + + + if (gts_triangles_are_folded (e1->triangles, + GTS_SEGMENT (e1)->v1, + GTS_SEGMENT (e1)->v2, + *maxcosine2) || + gts_triangles_are_folded (e2->triangles, + GTS_SEGMENT (e2)->v1, + GTS_SEGMENT (e2)->v2, + *maxcosine2) || + gts_triangles_are_folded (e3->triangles, + GTS_SEGMENT (e3)->v1, + GTS_SEGMENT (e3)->v2, + *maxcosine2)) { + fprintf (stderr, "triangle %p:(%p,%p,%p) is folded\n", t, e1, e2, e3); + g_assert_not_reached (); + } +} +#endif + +/** + * gts_psurface_new: + * @klass: a #GtsPSurfaceClass. + * @surface: a #GtsSurface. + * @split_class: a #GtsSplitClass to use for the new progressive surface. + * @cost_func: cost function for the edge collapse algorithm. + * @cost_data: data to pass to @cost_func. + * @coarsen_func: the function returning the vertex replacement for the edge + * collapse. + * @coarsen_data: data to pass to @coarsen_func. + * @stop_func: the function to call to decide whether to stop the coarsening + * process. + * @stop_data: data to pass to @stop_func. + * @minangle: the minimum angle allowable between two neighboring triangles. + * This is used to avoid introducing folds in the mesh during simplification. + * + * This function works in exactly the same way as the + * gts_surface_coarsen() function, except that the history of edge + * collapse is saved in an array of #GtsSplit objects. This allows for + * dynamic continuous multiresolution control of the input @surface. + * + * Returns: a new progressive surface. + */ +GtsPSurface * gts_psurface_new (GtsPSurfaceClass * klass, + GtsSurface * surface, + GtsSplitClass * split_class, + GtsKeyFunc cost_func, + gpointer cost_data, + GtsCoarsenFunc coarsen_func, + gpointer coarsen_data, + GtsStopFunc stop_func, + gpointer stop_data, + gdouble minangle) +{ + GtsPSurface * psurface; + GtsEHeap * heap; + GtsEdge * e; + gdouble top_cost, maxcosine2; + guint i; + + g_return_val_if_fail (klass != NULL, NULL); + g_return_val_if_fail (surface != NULL, NULL); + g_return_val_if_fail (split_class != NULL, NULL); + g_return_val_if_fail (stop_func != NULL, NULL); + + psurface = GTS_PSURFACE (gts_object_new (GTS_OBJECT_CLASS (klass))); + psurface->s = surface; + psurface->split_class = split_class; + + if (cost_func == NULL) + cost_func = (GtsKeyFunc) edge_length2; + if (coarsen_func == NULL) + coarsen_func = (GtsCoarsenFunc) gts_segment_midvertex; + + heap = gts_eheap_new (cost_func, cost_data); + maxcosine2 = cos (minangle); maxcosine2 *= maxcosine2; + + gts_eheap_freeze (heap); + gts_surface_foreach_edge (surface, (GtsFunc) create_heap_coarsen, heap); + gts_eheap_thaw (heap); + /* we want to control edge destruction manually */ + gts_allow_floating_edges = TRUE; + while ((e = gts_eheap_remove_top (heap, &top_cost)) && + (top_cost < G_MAXDOUBLE) && + !(*stop_func) (top_cost, gts_eheap_size (heap) - + gts_edge_face_number (e, surface), stop_data)) { + GtsVertex * v = edge_collapse (psurface, e, heap, + coarsen_func, coarsen_data, maxcosine2); + if (v != NULL) { + update_2nd_closest_neighbors (v, heap); +#ifdef DEBUG_FOLD + { + GSList * triangles = gts_vertex_triangles (v, NULL), * i; + fprintf (stderr, "\n---- Check for folds ----\n%p: ", v); + i = triangles; + while (i) { + GtsTriangle * t = i->data; + fprintf (stderr, "%p:(%p,%p,%p) ", t, t->e1, t->e2, t->e3); + i = i->next; + } + fprintf (stderr, "\n"); + g_slist_free (triangles); + gts_surface_foreach_face (surface, (GtsFunc) check_fold, &maxcosine2); + } +#endif +#ifdef DEBUG_CONTACT_VERTEX + if (gts_vertex_is_contact (v, FALSE) != 1) { + FILE * fptr = fopen ("after", "wt"); + GSList * triangles = gts_vertex_triangles (v, NULL), * i; + + fprintf (stderr, "collapse of %p created a contact vertex\n", e); + + fprintf (fptr, + "(geometry \"sphere\" { = SPHERE 0.1 0. 0. 0. })\n" + "(normalization \"sphere\" none)\n"); + i = triangles; + while (i) { + gts_write_triangle (i->data, GTS_POINT (v), fptr); + i = i->next; + } + g_assert_not_reached (); + } +#endif + } + } + gts_allow_floating_edges = FALSE; + + /* set reserved field of remaining edges back to NULL */ + if (e) GTS_OBJECT (e)->reserved = NULL; + gts_eheap_foreach (heap, (GFunc) gts_object_reset_reserved, NULL); + + gts_eheap_destroy (heap); + + psurface->pos = psurface->split->len; + psurface->min = gts_surface_vertex_number (psurface->s); + + /* set reserved field of vertices (used to build the hierarchy) + back to NULL */ + for (i = 0; i < psurface->split->len; i++) { + GtsSplit * vs = g_ptr_array_index (psurface->split, i); + gts_object_reset_reserved (GTS_OBJECT (vs->v)); + } + + return psurface; +} + +/** + * gts_psurface_add_vertex: + * @ps: a #GtsPSurface. + * + * Adds a vertex to the progressive surface @ps by expanding the next + * available #GtsSplit. + * + * Returns: the expanded #GtsSplit or %NULL if all the #GtsSplit have already + * been expanded. + */ +GtsSplit * gts_psurface_add_vertex (GtsPSurface * ps) +{ + GtsSplit * vs; + + g_return_val_if_fail (ps != NULL, NULL); + g_return_val_if_fail (GTS_PSURFACE_IS_CLOSED (ps), NULL); + + if (ps->pos == 0) + return NULL; + + vs = g_ptr_array_index (ps->split, --ps->pos); + gts_split_expand (vs, ps->s, ps->s->edge_class); + + return vs; +} + +/** + * gts_psurface_remove_vertex: + * @ps: a #GtsPSurface. + * + * Removes one vertex from the progressive surface @ps by collapsing the first + * available #GtsSplit. + * + * Returns: the collapsed #GtsSplit or %NULL if all the #GtsSplit have already + * been collapsed. + */ +GtsSplit * gts_psurface_remove_vertex (GtsPSurface * ps) +{ + GtsSplit * vs; + + g_return_val_if_fail (ps != NULL, NULL); + g_return_val_if_fail (GTS_PSURFACE_IS_CLOSED (ps), NULL); + + if (ps->pos == ps->split->len) + return NULL; + + vs = g_ptr_array_index (ps->split, ps->pos++); + gts_split_collapse (vs, ps->s->edge_class, NULL); + + return vs; +} + +/** + * gts_psurface_max_vertex_number: + * @ps: a #GtsPSurface. + * + * Returns: the maximum number of vertices of @ps i.e. the number of vertices + * if all the #GtsSplit were expanded. + */ +guint gts_psurface_max_vertex_number (GtsPSurface * ps) +{ + g_return_val_if_fail (ps != NULL, 0); + + return ps->min + ps->split->len; +} + +/** + * gts_psurface_min_vertex_number: + * @ps: a #GtsPSurface. + * + * Returns: the minimum number of vertices of @ps i.e. the number of vertices + * if all the #GtsSplit were collapsed. + */ +guint gts_psurface_min_vertex_number (GtsPSurface * ps) +{ + g_return_val_if_fail (ps != NULL, 0); + + return ps->min; +} + +/** + * gts_psurface_set_vertex_number: + * @ps: a #GtsPSurface. + * @n: a number of vertices. + * + * Performs the required number of collapses or expansions to set the number + * of vertices of @ps to @n. + */ +void gts_psurface_set_vertex_number (GtsPSurface * ps, guint n) +{ + g_return_if_fail (ps != NULL); + g_return_if_fail (GTS_PSURFACE_IS_CLOSED (ps)); + + n = ps->min + ps->split->len - n; + while (ps->pos > n && gts_psurface_add_vertex (ps)) + ; + while (ps->pos < n && gts_psurface_remove_vertex (ps)) + ; +} + +/** + * gts_psurface_get_vertex_number: + * @ps: a #GtsPSurface. + * + * Returns: the current number of vertices of @ps. + */ +guint gts_psurface_get_vertex_number (GtsPSurface * ps) +{ + g_return_val_if_fail (ps != NULL, 0); + + if (!GTS_PSURFACE_IS_CLOSED (ps)) + return ps->min + ps->pos; + else + return ps->min + ps->split->len - ps->pos; +} + +/** + * gts_psurface_foreach_vertex: + * @ps: a #GtsPSurface. + * @func: a function to call for each vertex of @ps. + * @data: data to be passed to @func. + * + * Calls @func for each (potential) vertex of @ps, whether actually used + * or not. The vertices are called in the order they were created during the + * edge collapse operation. + */ +void gts_psurface_foreach_vertex (GtsPSurface * ps, + GtsFunc func, + gpointer data) +{ + guint i; + + g_return_if_fail (ps != NULL); + g_return_if_fail (func != NULL); + g_return_if_fail (GTS_PSURFACE_IS_CLOSED (ps)); + + for (i = 0; i < ps->split->len; i++) { + GtsSplit * vs = g_ptr_array_index (ps->split, i); + (*func) (vs->v, data); + } +} Index: work/obsolete/toporouter/src_3rd/gts/refine.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/refine.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/refine.c (revision 6803) @@ -0,0 +1,418 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "gts.h" + +/** + * gts_vertex_encroaches_edge: + * @v: a #GtsVertex. + * @e: a #GtsEdge. + * + * Returns: %TRUE if @v is strictly contained in the diametral circle of @e, + * %FALSE otherwise. + */ +gboolean gts_vertex_encroaches_edge (GtsVertex * v, GtsEdge * e) +{ + GtsPoint * p, * p1, * p2; + + g_return_val_if_fail (v != NULL, FALSE); + g_return_val_if_fail (e != NULL, FALSE); + + p = GTS_POINT (v); + p1 = GTS_POINT (GTS_SEGMENT (e)->v1); + p2 = GTS_POINT (GTS_SEGMENT (e)->v2); + + if ((p1->x - p->x)*(p2->x - p->x) + (p1->y - p->y)*(p2->y - p->y) < 0.0) + return TRUE; + return FALSE; +} + +/** + * gts_edge_is_encroached: + * @e: a #GtsEdge. + * @s: a #GtsSurface describing a (constrained) Delaunay triangulation. + * @encroaches: a #GtsEncroachFunc. + * @data: user data to be passed to @encroaches. + * + * Returns: a #GtsVertex belonging to @s and encroaching upon @e + * (as defined by @encroaches) or %NULL if there is none. + */ +GtsVertex * gts_edge_is_encroached (GtsEdge * e, + GtsSurface * s, + GtsEncroachFunc encroaches, + gpointer data) +{ + GSList * i; + + g_return_val_if_fail (e != NULL, NULL); + g_return_val_if_fail (s != NULL, NULL); + g_return_val_if_fail (encroaches != NULL, NULL); + + 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 ((* encroaches) (v, e, s, data)) + return v; + } + i = i->next; + } + + return NULL; +} + +#define ALREADY_ENCROACHED(c) (GTS_OBJECT (c)->reserved) + +static void vertex_encroaches (GtsVertex * v, + GtsSurface * surface, + GtsFifo * encroached, + GtsEncroachFunc encroaches, + gpointer data) +{ + GSList * triangles, * i; + + g_return_if_fail (v != NULL); + g_return_if_fail (surface != NULL); + g_return_if_fail (encroached != NULL); + g_return_if_fail (encroaches != NULL); + + i = triangles = gts_vertex_triangles (v, NULL); + while (i) { + GtsFace * f = i->data; + if (GTS_IS_FACE (f) && gts_face_has_parent_surface (f, surface)) { + GtsEdge * e = gts_triangle_edge_opposite (i->data, v); + if (!ALREADY_ENCROACHED (e) && + GTS_IS_CONSTRAINT (e) && + (* encroaches) (v, e, surface, data)) { + gts_fifo_push (encroached, e); + ALREADY_ENCROACHED (e) = encroached; + } + } + i = i->next; + } + g_slist_free (triangles); +} + +static void make_encroached_fifo (GtsEdge * e, gpointer * datas) +{ + GtsFifo * fifo = datas[0]; + GtsSurface * s = datas[1]; + GtsEncroachFunc encroaches = (GtsEncroachFunc) datas[2]; + gpointer data = datas[3]; + + if (GTS_IS_CONSTRAINT (e) && + gts_edge_is_encroached (e, s, encroaches, data)) { + gts_fifo_push (fifo, e); + ALREADY_ENCROACHED (e) = fifo; + } +} + +#define SQUARE_ROOT_TWO 1.41421356237309504880168872420969807856967187 +#define DISTANCE_2D(v1, v2) (sqrt ((GTS_POINT (v2)->x - GTS_POINT (v1)->x)*\ + (GTS_POINT (v2)->x - GTS_POINT (v1)->x) +\ + (GTS_POINT (v2)->y - GTS_POINT (v1)->y)*\ + (GTS_POINT (v2)->y - GTS_POINT (v1)->y))) + +/* finds where to split the given edge to avoid infinite cycles. (see + Shewchuk's thesis for details */ +static GtsVertex * split_edge (GtsEdge * e, + GtsSurface * surface) +{ + GSList * i = e->triangles; + GtsEdge * c = NULL; + + /* look for constraints touching e */ + while (i && !c) { + GtsTriangle * t = i->data; + if (GTS_IS_FACE (t) && + gts_face_has_parent_surface (GTS_FACE (t), surface)) { + GtsEdge * e1, * e2; + if (t->e1 == e) { e1 = t->e2; e2 = t->e3; } + else if (t->e2 == e) { e1 = t->e1; e2 = t->e3; } + else { e1 = t->e1; e2 = t->e2; } + if (GTS_IS_CONSTRAINT (e1) && !GTS_IS_CONSTRAINT (e2)) + c = e1; + else if (GTS_IS_CONSTRAINT (e2) && !GTS_IS_CONSTRAINT (e1)) + c = e2; + } + i = i->next; + } + if (c) { + /* use power of two concentric shells */ + GtsVertex * v1 = GTS_SEGMENT (e)->v1; + GtsVertex * v2 = GTS_SEGMENT (e)->v2; + gdouble l = DISTANCE_2D (v1, v2); + gdouble nearestpower = 1., split; + + while (l > SQUARE_ROOT_TWO*nearestpower) + nearestpower *= 2.; + while (l < SQUARE_ROOT_TWO*nearestpower/2.) + nearestpower /= 2.; + split = nearestpower/l/2.; + + if (GTS_SEGMENT (c)->v1 == v2 || GTS_SEGMENT (c)->v2 == v2) + split = 1. - split; + return gts_vertex_new (surface->vertex_class, + (1. - split)*GTS_POINT (v1)->x + + split*GTS_POINT (v2)->x, + (1. - split)*GTS_POINT (v1)->y + + split*GTS_POINT (v2)->y, + (1. - split)*GTS_POINT (v1)->z + + split*GTS_POINT (v2)->z); + } + else + return gts_segment_midvertex (GTS_SEGMENT (e), surface->vertex_class); +} + +static gint split_encroached (GtsSurface * surface, + GtsFifo * encroached, + gint steiner_max, + GtsEncroachFunc encroaches, + gpointer data) +{ + GtsSegment * s; + + while (steiner_max-- != 0 && (s = gts_fifo_pop (encroached))) { + GtsVertex * v = split_edge (GTS_EDGE (s), surface); + GtsFace * boundary = gts_edge_is_boundary (GTS_EDGE (s), surface); + GtsFace * f = boundary; +#if 1 + GtsEdge * e1 = GTS_EDGE (gts_object_clone (GTS_OBJECT (s))); + GtsEdge * e2 = GTS_EDGE (gts_object_clone (GTS_OBJECT (s))); + + GTS_SEGMENT (e1)->v1 = s->v1; + s->v1->segments = g_slist_prepend (s->v1->segments, e1); + GTS_SEGMENT (e1)->v2 = v; + v->segments = g_slist_prepend (v->segments, e1); + + GTS_SEGMENT (e2)->v1 = v; + v->segments = g_slist_prepend (v->segments, e2); + GTS_SEGMENT (e2)->v2 = s->v2; + s->v2->segments = g_slist_prepend (s->v2->segments, e2); +#else + GtsEdge * e1 = gts_edge_new (GTS_EDGE_CLASS (GTS_OBJECT (s)->klass), + s->v1, v); + GtsEdge * e2 = gts_edge_new (GTS_EDGE_CLASS (GTS_OBJECT (s)->klass), + v, s->v2); +#endif + + GTS_OBJECT (s)->klass = GTS_OBJECT_CLASS (surface->edge_class); + + if (f == NULL) + g_assert ((f = gts_edge_has_parent_surface (GTS_EDGE (s), surface))); + g_assert (gts_delaunay_add_vertex_to_face (surface, v, f) == NULL); + + if (boundary) + gts_object_destroy (GTS_OBJECT (s)); + + vertex_encroaches (v, surface, encroached, encroaches, data); + + if (gts_edge_is_encroached (e1, surface, encroaches, data)) { + gts_fifo_push (encroached, e1); + ALREADY_ENCROACHED (e1) = encroached; + } + if (gts_edge_is_encroached (e2, surface, encroaches, data)) { + gts_fifo_push (encroached, e2); + ALREADY_ENCROACHED (e2) = encroached; + } + } + + return steiner_max; +} + +/** + * gts_delaunay_conform: + * @surface: a #GtsSurface describing a constrained Delaunay triangulation. + * @steiner_max: maximum number of Steiner points. + * @encroaches: a #GtsEncroachFunc. + * @data: user-data to pass to @encroaches. + * + * Recursively split constraints of @surface which are encroached by + * vertices of @surface (see Shewchuk 96 for details). The split + * constraints are destroyed and replaced by a set of new constraints + * of the same class. If gts_vertex_encroaches_edge() is used for + * @encroaches, the resulting surface will be Delaunay conforming. + * + * If @steiner_max is positive or nul, the recursive splitting + * procedure will stop when this maximum number of Steiner points is + * reached. In that case the resulting surface will not necessarily be + * Delaunay conforming. + * + * Returns: the number of remaining encroached edges. If @steiner_max + * is set to a negative value and gts_vertex_encroaches_edge() is used + * for @encroaches this should always be zero. + */ +guint gts_delaunay_conform (GtsSurface * surface, + gint steiner_max, + GtsEncroachFunc encroaches, + gpointer data) +{ + GtsFifo * encroached; + gpointer datas[4]; + guint encroached_number; + + g_return_val_if_fail (surface != NULL, 0); + g_return_val_if_fail (surface != NULL, 0); + g_return_val_if_fail (encroaches != NULL, 0); + + datas[0] = encroached = gts_fifo_new (); + datas[1] = surface; + datas[2] = encroaches; + datas[3] = data; + gts_surface_foreach_edge (surface, (GtsFunc) make_encroached_fifo, datas); + + split_encroached (surface, + encroached, + steiner_max, + encroaches, data); + gts_fifo_foreach (encroached, (GtsFunc) gts_object_reset_reserved, NULL); + encroached_number = gts_fifo_size (encroached); + gts_fifo_destroy (encroached); + return encroached_number; +} + +#define EHEAP_PAIR(f) (GTS_OBJECT (f)->reserved) + +static void heap_surface_add_face (GtsSurface * s, GtsFace * f) +{ + GtsEHeap * heap = GTS_OBJECT (s)->reserved; + gdouble key = gts_eheap_key (heap, f); + + if (key != 0.) + EHEAP_PAIR (f) = gts_eheap_insert_with_key (heap, f, key); + + if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass->parent_class)->add_face) + (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass->parent_class)->add_face) + (s, f); +} + +static void heap_surface_remove_face (GtsSurface * s, GtsFace * f) +{ + GtsEHeap * heap = GTS_OBJECT (s)->reserved; + + if (EHEAP_PAIR (f)) + gts_eheap_remove (heap, EHEAP_PAIR (f)); + + if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass->parent_class)->remove_face) + (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass->parent_class)->remove_face) + (s, f); +} + +static void heap_surface_class_init (GtsSurfaceClass * klass) +{ + klass->add_face = heap_surface_add_face; + klass->remove_face = heap_surface_remove_face; +} + +static GtsObjectClass * heap_surface_class_new (GtsObjectClass * parent_class) +{ + GtsObjectClassInfo heap_surface_info; + + heap_surface_info = parent_class->info; + heap_surface_info.class_init_func = (GtsObjectClassInitFunc) + heap_surface_class_init; + return gts_object_class_new (parent_class, + &heap_surface_info); +} + +static void make_face_heap (GtsFace * f, GtsEHeap * heap) +{ + gdouble key = gts_eheap_key (heap, f); + + if (key != 0.) + EHEAP_PAIR (f) = gts_eheap_insert_with_key (heap, f, key); +} + +/** + * gts_delaunay_refine: + * @surface: a #GtsSurface describing a conforming Delaunay triangulation. + * @steiner_max: maximum number of Steiner points. + * @encroaches: a #GtsEncroachFunc. + * @encroach_data: user-data to pass to @encroaches. + * @cost: a #GtsKeyFunc used to sort the faces during refinement. + * @cost_data: user-data to pass to @cost. + * + * An implementation of the refinement algorithm described in Ruppert + * (1995) and Shewchuk (1996). + * + * Returns: the number of unrefined faces of @surface left. Should be zero + * if @steiner_max is set to a negative value. + */ +guint gts_delaunay_refine (GtsSurface * surface, + gint steiner_max, + GtsEncroachFunc encroaches, + gpointer encroach_data, + GtsKeyFunc cost, + gpointer cost_data) +{ + GtsObjectClass * heap_surface_class; + GtsObjectClass * original_class; + GtsEHeap * heap; + GtsFifo * encroached; + GtsFace * f; + guint unrefined_number; + + g_return_val_if_fail (surface != NULL, 0); + g_return_val_if_fail (encroaches != NULL, 0); + g_return_val_if_fail (cost != NULL, 0); + + original_class = GTS_OBJECT (surface)->klass; + heap_surface_class = heap_surface_class_new (original_class); + GTS_OBJECT (surface)->klass = heap_surface_class; + + heap = gts_eheap_new (cost, cost_data); + gts_surface_foreach_face (surface, (GtsFunc) make_face_heap, heap); + encroached = gts_fifo_new (); + + GTS_OBJECT (surface)->reserved = heap; + + while (steiner_max-- != 0 && (f = gts_eheap_remove_top (heap, NULL))) { + GtsVertex * c = + GTS_VERTEX (gts_triangle_circumcircle_center (GTS_TRIANGLE (f), + GTS_POINT_CLASS (surface->vertex_class))); + EHEAP_PAIR (f) = NULL; + g_assert (c != NULL); + g_assert (gts_delaunay_add_vertex (surface, c, f) == NULL); + + vertex_encroaches (c, surface, encroached, encroaches, encroach_data); + if (!gts_fifo_is_empty (encroached)) { + gts_delaunay_remove_vertex (surface, c); + steiner_max = split_encroached (surface, + encroached, + steiner_max, + encroaches, + encroach_data); + } + } + + unrefined_number = gts_eheap_size (heap); + gts_eheap_foreach (heap, (GFunc) gts_object_reset_reserved, NULL); + gts_eheap_destroy (heap); + + gts_fifo_foreach (encroached, (GtsFunc) gts_object_reset_reserved, NULL); + gts_fifo_destroy (encroached); + + GTS_OBJECT (surface)->klass = original_class; + GTS_OBJECT (surface)->reserved = NULL; + g_free (heap_surface_class); + + return unrefined_number; +} Index: work/obsolete/toporouter/src_3rd/gts/rounding.h =================================================================== --- work/obsolete/toporouter/src_3rd/gts/rounding.h (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/rounding.h (revision 6803) @@ -0,0 +1,85 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#ifdef HAVE_FPU_CONTROL_H +# include +# ifdef _FPU_EXTENDED +# if !defined(__alpha__) || !defined(__GLIBC__) +# if defined(__arm__) + static fpu_control_t fpu_round_double = _FPU_DEFAULT; +# else + static fpu_control_t fpu_round_double = + (_FPU_DEFAULT & ~ _FPU_EXTENDED)|_FPU_DOUBLE; +# endif + static fpu_control_t fpu_init; +# define FPU_ROUND_DOUBLE { _FPU_GETCW(fpu_init);\ + _FPU_SETCW(fpu_round_double); } +# define FPU_RESTORE {_FPU_SETCW(fpu_init);} +# else /* __alpha__ && __GLIBC__ */ +# define FPU_ROUND_DOUBLE +# define FPU_RESTORE +# endif /* __alpha__ && __GLIBC__ */ +# else /* not FPU_EXTENDED */ +# define FPU_ROUND_DOUBLE +# define FPU_RESTORE +# endif /* not FPU_EXTENDED */ +#else /* not HAVE_FPU_CONTROL_H */ +# ifdef __FreeBSD__ +# include +# define FPU_ROUND_DOUBLE (fpsetprec(FP_PD)) +# define FPU_RESTORE (fpsetprec(FP_PE)) +# else /* not __FreeBSD__ */ +# ifdef WIN32 +# ifdef _MSC_VER +# include + static unsigned int fpu_init; +# define FPU_ROUND_DOUBLE (fpu_init = _controlfp (0, 0),\ + _controlfp (_PC_53, MCW_PC)) +# define FPU_RESTORE (_controlfp (fpu_init, 0xfffff)) +# elif __MINGW32__ +# include + static unsigned int fpu_init; +# define FPU_ROUND_DOUBLE (fpu_init = _controlfp (0, 0),\ + _controlfp (_PC_53, _MCW_PC)) +# define FPU_RESTORE (_controlfp (fpu_init, 0xfffff)) +# else /* not _MSC_VER or __MINGW32__ */ +# error "You need MSVC or MinGW for the Win32 version" +# endif /* not _MSC_VER or __MINGW32__ */ +# else /* not WIN32 */ +# ifdef __CYGWIN__ + typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__HI__))); + static fpu_control_t fpu_round_double = 0x027f; + static fpu_control_t fpu_init; +# define _FPU_GETCW(cw) __asm__ ("fnstcw %0" : "=m" (*&cw)) +# define _FPU_SETCW(cw) __asm__ ("fldcw %0" : : "m" (*&cw)) +# define FPU_ROUND_DOUBLE { _FPU_GETCW(fpu_init);\ + _FPU_SETCW(fpu_round_double); } +# define FPU_RESTORE { _FPU_SETCW(fpu_init);} +# else /* not __CYGWIN__ */ +# ifdef CPP_HAS_WARNING +# warning "Unknown CPU: assuming default double precision rounding" +# endif /* CPP_HAS_WARNING */ +# define FPU_ROUND_DOUBLE +# define FPU_RESTORE +# endif /* not __CYGWIN__ */ +# endif /* not WIN32 */ +# endif /* not __FreeBSD__ */ +#endif /* not HAVE_FPU_CONTROL_H */ Index: work/obsolete/toporouter/src_3rd/gts/segment.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/segment.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/segment.c (revision 6803) @@ -0,0 +1,233 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gts.h" + +static void segment_destroy (GtsObject * object) +{ + GtsSegment * segment = GTS_SEGMENT (object); + GtsVertex * v1 = segment->v1; + GtsVertex * v2 = segment->v2; + + v1->segments = g_slist_remove (v1->segments, segment); + if (!GTS_OBJECT_DESTROYED (v1) && + !gts_allow_floating_vertices && v1->segments == NULL) + gts_object_destroy (GTS_OBJECT (v1)); + + v2->segments = g_slist_remove (v2->segments, segment); + if (!GTS_OBJECT_DESTROYED (v2) && + !gts_allow_floating_vertices && v2->segments == NULL) + gts_object_destroy (GTS_OBJECT (v2)); + + (* GTS_OBJECT_CLASS (gts_segment_class ())->parent_class->destroy) (object); +} + +static void segment_class_init (GtsObjectClass * klass) +{ + klass->destroy = segment_destroy; +} + +static void segment_init (GtsSegment * segment) +{ + segment->v1 = segment->v2 = NULL; +} + +/** + * gts_segment_class: + * + * Returns: the #GtsSegmentClass. + */ +GtsSegmentClass * gts_segment_class (void) +{ + static GtsSegmentClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo segment_info = { + "GtsSegment", + sizeof (GtsSegment), + sizeof (GtsSegmentClass), + (GtsObjectClassInitFunc) segment_class_init, + (GtsObjectInitFunc) segment_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (gts_object_class (), + &segment_info); + } + + return klass; +} + +/** + * gts_segment_new: + * @klass: a #GtsSegmentClass. + * @v1: a #GtsVertex. + * @v2: another #GtsVertex different from @v1. + * + * Returns: a new #GtsSegment linking @v1 and @v2. + */ +GtsSegment * gts_segment_new (GtsSegmentClass * klass, + GtsVertex * v1, GtsVertex * v2) +{ + GtsSegment * s; + + g_return_val_if_fail (v1 != NULL, NULL); + g_return_val_if_fail (v2 != NULL, NULL); + g_return_val_if_fail (v1 != v2, NULL); + + s = GTS_SEGMENT (gts_object_new (GTS_OBJECT_CLASS (klass))); + s->v1 = v1; + s->v2 = v2; + v1->segments = g_slist_prepend (v1->segments, s); + v2->segments = g_slist_prepend (v2->segments, s); + + return s; +} + +/** + * gts_segment_is_duplicate: + * @s: a #GtsSegment. + * + * Returns: the first #GtsSegment different from @s which shares the + * same endpoints or %NULL if there is none. + */ +GtsSegment * gts_segment_is_duplicate (GtsSegment * s) +{ + GSList * i; + GtsVertex * v2; + + g_return_val_if_fail (s != NULL, NULL); + + v2 = s->v2; + i = s->v1->segments; + if (s->v1 == v2) /* s is degenerate: special treatment */ + while (i) { + GtsSegment * s1 = i->data; + if (s1 != s && s1->v1 == v2 && s1->v2 == v2) + return s1; + i = i->next; + } + else /* s is not degenerate */ + while (i) { + GtsSegment * s1 = i->data; + if (s1 != s && (s1->v1 == v2 || s1->v2 == v2)) + return s1; + i = i->next; + } + return NULL; +} + +/** + * gts_segments_are_intersecting: + * @s1: a #GtsSegment. + * @s2: a #GtsSegment. + * + * Returns: %GTS_IN if @s1 and @s2 are intersecting, %GTS_ON if one of the + * endpoints of @s1 (resp. @s2) lies on @s2 (resp. @s1), %GTS_OUT otherwise. + */ +GtsIntersect gts_segments_are_intersecting (GtsSegment * s1, GtsSegment * s2) +{ + GtsPoint * p1, * p2, * p3, * p4; + gdouble d1, d2, d3, d4; + + g_return_val_if_fail (s1 != NULL && s2 != NULL, FALSE); + + p1 = GTS_POINT (s1->v1); p2 = GTS_POINT (s1->v2); + p3 = GTS_POINT (s2->v1); p4 = GTS_POINT (s2->v2); + d1 = gts_point_orientation (p1, p2, p3); + d2 = gts_point_orientation (p1, p2, p4); + if ((d1 > 0.0 && d2 > 0.0) || + (d1 < 0.0 && d2 < 0.0)) + return GTS_OUT; + d3 = gts_point_orientation (p3, p4, p1); + d4 = gts_point_orientation (p3, p4, p2); + if ((d3 > 0.0 && d4 > 0.0) || + (d3 < 0.0 && d4 < 0.0)) + return GTS_OUT; + if (d1 == 0.0 || d2 == 0.0 || d3 == 0.0 || d4 == 0.0) + return GTS_ON; + return GTS_IN; +} + +/** + * gts_segment_midvertex: + * @s: a #GtsSegment. + * @klass: a #GtsVertexClass to be used for the new vertex. + * + * Returns: a new #GtsVertex, midvertex of @s. + */ +GtsVertex * gts_segment_midvertex (GtsSegment * s, GtsVertexClass * klass) +{ + GtsPoint * p1, * p2; + + g_return_val_if_fail (s != NULL, NULL); + g_return_val_if_fail (klass != NULL, NULL); + + p1 = GTS_POINT (s->v1); p2 = GTS_POINT (s->v2); + return gts_vertex_new (klass, + (p1->x + p2->x)/2., + (p1->y + p2->y)/2., + (p1->z + p2->z)/2.); +} + +/** + * gts_segments_from_vertices: + * @vertices: a list of #GtsVertex. + * + * Returns: a list of unique #GtsSegment which have one of their vertices in + * @vertices. + */ +GSList * gts_segments_from_vertices (GSList * vertices) +{ + GHashTable * hash; + GSList * segments = NULL, * i; + + hash = g_hash_table_new (NULL, NULL); + i = vertices; + while (i) { + GSList * j = GTS_VERTEX (i->data)->segments; + while (j) { + GtsSegment * s = j->data; + if (g_hash_table_lookup (hash, s) == NULL) { + segments = g_slist_prepend (segments, s); + g_hash_table_insert (hash, s, i); + } + j = j->next; + } + i = i->next; + } + g_hash_table_destroy (hash); + return segments; +} + +/** + * gts_segment_is_ok: + * @s: a #GtsSegment. + * + * Returns: %TRUE if @s is not degenerate (i.e. @s->v1 != @s->v2) and not + * duplicate, %FALSE otherwise. + */ +gboolean gts_segment_is_ok (GtsSegment * s) +{ + g_return_val_if_fail (s != NULL, FALSE); + g_return_val_if_fail (s->v1 != s->v2, FALSE); + g_return_val_if_fail (!gts_segment_is_duplicate (s), FALSE); + g_return_val_if_fail (GTS_OBJECT (s)->reserved == NULL, FALSE); + return TRUE; +} Index: work/obsolete/toporouter/src_3rd/gts/split.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/split.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/split.c (revision 6803) @@ -0,0 +1,1840 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include "gts.h" + +#define DYNAMIC_SPLIT +#define NEW + +/* #define DEBUG + #define DEBUG_HEXPAND + #define DEBUG_EXPAND */ + +struct _GtsSplitCFace { + GtsFace * f; + GtsTriangle ** a1, ** a2; +}; + +typedef struct _CFace CFace; +typedef struct _CFaceClass CFaceClass; + +struct _CFace { + GtsObject object; + + GtsSplit * parent_split; + GtsTriangle * t; + guint flags; +}; +/* the size of the CFace structure must be smaller or equal to the size + of the GtsFace structure as both structures use the same memory location */ + +struct _CFaceClass { + GtsObjectClass parent_class; +}; + +#define IS_CFACE(obj) (gts_object_is_from_class (obj, cface_class ())) +#define CFACE(obj) ((CFace *) obj) +#define CFACE_ORIENTATION(cf) ((cf)->flags & 0x1) +#define CFACE_ORIENTATION_DIRECT(cf) ((cf)->flags |= 0x1) +#define CFACE_VVS(cf) ((cf)->flags & 0x2) +#define CFACE_VVS_DIRECT(cf) ((cf)->flags |= 0x2) +#define CFACE_E1 0x4 +#define CFACE_E2 0x8 +#define CFACE_KEEP_VVS 0x10 + +#define ROTATE_ORIENT(e, e1, e2, e3) { if (e1 == e) { e1 = e2; e2 = e3; }\ + else if (e2 == e) { e2 = e1; e1 = e3; }\ + else g_assert (e3 == e); } +#define SEGMENT_USE_VERTEX(s, v) ((s)->v1 == v || (s)->v2 == v) +#define TRIANGLE_REPLACE_EDGE(t, e, with) { if ((t)->e1 == e)\ + (t)->e1 = with;\ + else if ((t)->e2 == e)\ + (t)->e2 = with;\ + else {\ + g_assert ((t)->e3 == e);\ + (t)->e3 = with;\ + }\ + } + +#define HEAP_INSERT_OBJECT(h, e) (GTS_OBJECT (e)->reserved =\ + gts_eheap_insert (h, e)) +#define HEAP_REMOVE_OBJECT(h, e) (gts_eheap_remove (h, GTS_OBJECT (e)->reserved),\ + GTS_OBJECT (e)->reserved = NULL) + +static GtsObjectClass * cface_class (void) +{ + static GtsObjectClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo cface_info = { + "GtsCFace", + sizeof (CFace), + sizeof (CFaceClass), + (GtsObjectClassInitFunc) NULL, + (GtsObjectInitFunc) NULL, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (gts_object_class (), &cface_info); + g_assert (sizeof (CFace) <= sizeof (GtsFace)); + } + + return klass; +} + +/* Replace @e with @with for all the triangles using @e but @f. + Destroys @e and removes it from @heap (if not %NULL). + Returns a triangle using e different from f or %NULL. */ +static GtsTriangle * replace_edge_collapse (GtsEdge * e, + GtsEdge * with, + CFace * cf, + GtsEHeap * heap +#ifdef DYNAMIC_SPLIT + , GtsTriangle *** a1 +#endif +#ifdef NEW + , guint edge_flag +#endif + ) +{ + GSList * i; + GtsTriangle * rt = NULL; +#ifdef DYNAMIC_SPLIT + guint size; + GtsTriangle ** a; +#endif + +#ifdef NEW + i = e->triangles; + e->triangles = NULL; + size = g_slist_length (i)*sizeof (GtsTriangle *); + *a1 = a = g_malloc (size > 0 ? size : sizeof (GtsTriangle *)); + while (i) { + GtsTriangle * t = i->data; + GSList * next = i->next; + if (t != ((GtsTriangle *) cf)) { + if (IS_CFACE (t)) { + i->next = e->triangles; + e->triangles = i; + /* set the edge given by edge_flag (CFACE_E1 or CFACE_E2) */ + GTS_OBJECT (t)->reserved = GUINT_TO_POINTER (edge_flag); + cf->flags |= CFACE_KEEP_VVS; + } + else { + TRIANGLE_REPLACE_EDGE (t, e, with); + i->next = with->triangles; + with->triangles = i; + rt = t; + *(a++) = t; + } + } + else + g_slist_free_1 (i); + i = next; + } + *a = NULL; + if (!e->triangles) { + if (heap) + HEAP_REMOVE_OBJECT (heap, e); + gts_object_destroy (GTS_OBJECT (e)); + } +#else /* not NEW */ + i = e->triangles; +#ifdef DYNAMIC_SPLIT + size = g_slist_length (i)*sizeof (GtsTriangle *); + *a1 = a = g_malloc (size > 0 ? size : sizeof (GtsTriangle *)); +#endif + while (i) { + GtsTriangle * t = i->data; + GSList * next = i->next; + if (t != ((GtsTriangle *) cf)) { + TRIANGLE_REPLACE_EDGE (t, e, with); + i->next = with->triangles; + with->triangles = i; + rt = t; +#ifdef DYNAMIC_SPLIT + *(a++) = t; +#endif + } + else + g_slist_free_1 (i); + i = next; + } +#ifdef DYNAMIC_SPLIT + *a = NULL; +#endif + if (heap) + HEAP_REMOVE_OBJECT (heap, e); + e->triangles = NULL; + gts_object_destroy (GTS_OBJECT (e)); +#endif /* NEW */ + + return rt; +} + +static CFace * cface_new (GtsFace * f, + GtsEdge * e, + GtsVertex * v1, + GtsVertex * v2, + GtsSplit * vs, + GtsEHeap * heap, + GtsEdgeClass * klass +#ifdef DYNAMIC_SPLIT + , GtsSplitCFace * scf +#endif + ) +{ + CFace * cf; + GtsVertex * v; + GtsEdge * e1, * e2, * e3, * vvs; + GSList * i; + GtsTriangle * t, * t1 = NULL, * t2 = NULL; + guint flags; + + g_return_val_if_fail (f != NULL, NULL); +#ifndef NEW + g_return_val_if_fail (GTS_IS_FACE (f), NULL); +#endif + g_return_val_if_fail (e != NULL, NULL); + g_return_val_if_fail (vs != NULL, NULL); + + t = ((GtsTriangle *) f); + if (heap) + g_return_val_if_fail (!gts_triangle_is_duplicate (t), NULL); + +#ifdef NEW + /* get CFACE_E1 and CFACE_E2 info */ + flags = GPOINTER_TO_UINT (GTS_OBJECT (f)->reserved); +#endif + GTS_OBJECT_SET_FLAGS (f, GTS_DESTROYED); + + i = f->surfaces; + while (i) { + GSList * next = i->next; + gts_surface_remove_face (i->data, f); + i = next; + } + g_slist_free (f->surfaces); + + e1 = t->e1; e2 = t->e2; e3 = t->e3; + ROTATE_ORIENT (e, e1, e2, e3); + + cf = (CFace *) f; +#ifndef NEW + GTS_OBJECT (cf)->klass = cface_class (); +#else + cf->flags = flags; +#endif + gts_object_init (GTS_OBJECT (cf), cface_class ()); + cf->parent_split = vs; + + if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1), v2)) { + CFACE_ORIENTATION_DIRECT (cf); /* v1->v2->v */ + e3 = e1; e1 = e2; e2 = e3; + } + v = GTS_SEGMENT (e1)->v1 == v1 ? + GTS_SEGMENT (e1)->v2 : GTS_SEGMENT (e1)->v1; +#ifdef NEW + if ((cf->flags & CFACE_E1) || (cf->flags & CFACE_E2)) + g_assert ((vvs = GTS_EDGE (gts_vertices_are_connected (vs->v, v)))); + else +#endif + vvs = gts_edge_new (klass, v, vs->v); + + t1 = replace_edge_collapse (e1, vvs, cf, heap +#ifdef DYNAMIC_SPLIT + , &scf->a1 +#endif +#ifdef NEW + , CFACE_E1 +#endif + ); + t2 = replace_edge_collapse (e2, vvs, cf, heap +#ifdef DYNAMIC_SPLIT + , &scf->a2 +#endif +#ifdef NEW + , CFACE_E2 +#endif + ); + t = cf->t = t1 ? t1 : t2; + g_assert (t); + + /* set up flags necessary to find vvs */ + if (t->e1 == vvs) e2 = t->e2; + else if (t->e2 == vvs) e2 = t->e3; + else { + g_assert (t->e3 == vvs); + e2 = t->e1; + } + if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e2), v)) + CFACE_VVS_DIRECT (cf); + + return cf; +} + +static void find_vvs (GtsVertex * vs, + GtsTriangle * t, + GtsVertex ** v, GtsEdge ** vvs, + gboolean orientation) +{ + GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3, * tmp; + + if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e2), vs)) { + tmp = e1; e1 = e2; e2 = e3; e3 = tmp; + } + else if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e3), vs)) { + tmp = e1; e1 = e3; e3 = e2; e2 = tmp; + } + else + g_assert (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1), vs)); + if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e2), vs) || + !gts_segments_touch (GTS_SEGMENT (e1), GTS_SEGMENT (e2))) { + tmp = e1; e1 = e2; e2 = e3; e3 = tmp; + g_assert (gts_segments_touch (GTS_SEGMENT (e1), GTS_SEGMENT (e2))); + } + + *vvs = orientation ? e1 : e3; + + if (GTS_SEGMENT (*vvs)->v1 != vs) { + g_assert (GTS_SEGMENT (*vvs)->v2 == vs); + *v = GTS_SEGMENT (*vvs)->v1; + } + else + *v = GTS_SEGMENT (*vvs)->v2; +} + +static void replace_edge_expand (GtsEdge * e, + GtsEdge * with, + GtsTriangle ** a, + GtsVertex * v) +{ + GtsTriangle ** i = a, * t; + + while ((t = *(i++))) { +#ifdef DEBUG_EXPAND + g_assert (!IS_CFACE (t)); + fprintf (stderr, "replacing %p->%d: e: %p->%d with: %p->%d\n", + t, id (t), e, id (e), with, id (with)); +#endif + TRIANGLE_REPLACE_EDGE (t, e, with); + with->triangles = g_slist_prepend (with->triangles, t); + if (GTS_OBJECT (t)->reserved) { + /* apart from the triangles having e as an edge, t is the only + triangle using v */ + g_assert (GTS_OBJECT (t)->reserved == v); + GTS_OBJECT (t)->reserved = NULL; + } + else + GTS_OBJECT (t)->reserved = v; + } +} + +static void cface_expand (CFace * cf, + GtsTriangle ** a1, + GtsTriangle ** a2, + GtsEdge * e, + GtsVertex * v1, + GtsVertex * v2, + GtsVertex * vs, + GtsEdgeClass * klass) +{ + GtsVertex * v; + GtsEdge * e1, * e2, * vvs; + gboolean orientation; + guint flags; + + g_return_if_fail (cf != NULL); + g_return_if_fail (IS_CFACE (cf)); + g_return_if_fail (e != NULL); + g_return_if_fail (vs != NULL); + + flags = cf->flags; + orientation = CFACE_ORIENTATION (cf); + + find_vvs (vs, cf->t, &v, &vvs, CFACE_VVS (cf)); + +#ifdef NEW + if (flags & CFACE_E1) + e1 = GTS_EDGE (gts_vertices_are_connected (v1, v)); + else + e1 = gts_edge_new (klass, v, v1); + if (flags & CFACE_E2) + e2 = GTS_EDGE (gts_vertices_are_connected (v2, v)); + else + e2 = gts_edge_new (klass, v, v2); +#else + e1 = gts_edge_new (v, v1); + e2 = gts_edge_new (v, v2); +#endif + + replace_edge_expand (vvs, e1, a1, v1); + replace_edge_expand (vvs, e2, a2, v2); + +#ifdef NEW + if (!(flags & CFACE_KEEP_VVS)) { + g_slist_free (vvs->triangles); + vvs->triangles = NULL; + gts_object_destroy (GTS_OBJECT (vvs)); + } +#else + g_slist_free (vvs->triangles); + vvs->triangles = NULL; + gts_object_destroy (GTS_OBJECT (vvs)); +#endif + + /* gts_face_new : because I am "creating" a face */ + GTS_OBJECT (cf)->klass = GTS_OBJECT_CLASS (gts_face_class ()); + gts_object_init (GTS_OBJECT (cf), GTS_OBJECT (cf)->klass); + + if (orientation) + gts_triangle_set (GTS_TRIANGLE (cf), e, e2, e1); + else + gts_triangle_set (GTS_TRIANGLE (cf), e, e1, e2); +} + +static void split_destroy (GtsObject * object) +{ + GtsSplit * vs = GTS_SPLIT (object); + guint i = vs->ncf; + GtsSplitCFace * cf = vs->cfaces; + + while (i--) { + if (IS_CFACE (cf->f)) + gts_object_destroy (GTS_OBJECT (cf->f)); + g_free (cf->a1); + g_free (cf->a2); + cf++; + } + g_free (vs->cfaces); + + if (!gts_allow_floating_vertices && vs->v && vs->v->segments == NULL) + gts_object_destroy (GTS_OBJECT (vs->v)); + + (* GTS_OBJECT_CLASS (gts_split_class ())->parent_class->destroy) (object); +} + +static void split_class_init (GtsObjectClass * klass) +{ + klass->destroy = split_destroy; +} + +static void split_init (GtsSplit * split) +{ + split->v1 = split->v2 = NULL; + split->v = NULL; + split->cfaces = NULL; + split->ncf = 0; +} + +/** + * gts_split_class: + * + * Returns: the #GtsSplitClass. + */ +GtsSplitClass * gts_split_class (void) +{ + static GtsSplitClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo split_info = { + "GtsSplit", + sizeof (GtsSplit), + sizeof (GtsSplitClass), + (GtsObjectClassInitFunc) split_class_init, + (GtsObjectInitFunc) split_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (gts_object_class (), + &split_info); + } + + return klass; +} + +#ifdef DEBUG +static gboolean edge_collapse_is_valid (GtsEdge * e) +{ + GSList * i; + + g_return_val_if_fail (e != NULL, FALSE); + + if (gts_segment_is_duplicate (GTS_SEGMENT (e))) { + g_warning ("collapsing duplicate edge"); + return FALSE; + } + + i = GTS_SEGMENT (e)->v1->segments; + while (i) { + GtsEdge * e1 = i->data; + if (e1 != e && GTS_IS_EDGE (e1)) { + GtsEdge * e2 = NULL; + GSList * j = GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e)->v1 ? + GTS_SEGMENT (e1)->v2->segments : GTS_SEGMENT (e1)->v1->segments; + while (j && !e2) { + GtsEdge * e1 = j->data; + if (GTS_IS_EDGE (e1) && + (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e)->v2 || + GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e)->v2)) + e2 = e1; + j = j->next; + } + if (e2 && !gts_triangle_use_edges (e, e1, e2)) { + g_warning ("collapsing empty triangle"); + return FALSE; + } + } + i = i->next; + } + + if (gts_edge_is_boundary (e, NULL)) { + GtsTriangle * t = e->triangles->data; + if (gts_edge_is_boundary (t->e1, NULL) && + gts_edge_is_boundary (t->e2, NULL) && + gts_edge_is_boundary (t->e3, NULL)) { + g_warning ("collapsing single triangle"); + return FALSE; + } + } + else { + if (gts_vertex_is_boundary (GTS_SEGMENT (e)->v1, NULL) && + gts_vertex_is_boundary (GTS_SEGMENT (e)->v2, NULL)) { + g_warning ("collapsing two sides of a strip"); + return FALSE; + } + if (gts_edge_belongs_to_tetrahedron (e)) { + g_warning ("collapsing tetrahedron"); + return FALSE; + } + } + + return TRUE; +} +#endif /* DEBUG */ + +/* Not currently used. May be useful for some debug code */ +#ifdef DEBUG +static void print_split (GtsSplit * vs, FILE * fptr) +{ + guint j; + GtsSplitCFace * cf; + + g_return_if_fail (vs != NULL); + g_return_if_fail (fptr != NULL); + + fprintf (fptr, "%p: v: %p v1: %p v2: %p ncf: %u cfaces: %p\n", + vs, vs->v, vs->v1, vs->v2, vs->ncf, vs->cfaces); + cf = vs->cfaces; + j = vs->ncf; + while (j--) { + fprintf (stderr, " f: %p a1: %p a2: %p\n", + cf->f, cf->a1, cf->a2); + cf++; + } +} +#endif + +/** + * gts_split_collapse: + * @vs: a #GtsSplit. + * @klass: a #GtsEdgeClass. + * @heap: a #GtsEHeap or %NULL. + * + * Collapses the vertex split @vs. Any new edge created during the process will + * be of class @klass. If heap is not %NULL, the new edges will be inserted + * into it and the destroyed edges will be removed from it. + */ +void gts_split_collapse (GtsSplit * vs, + GtsEdgeClass * klass, + GtsEHeap * heap) +{ + GtsEdge * e; + GtsVertex * v, * v1, * v2; + GSList * i, * end; +#ifdef DYNAMIC_SPLIT + GtsSplitCFace * cf; + guint j; +#endif +#ifdef DEBUG + gboolean invalid = FALSE; + static guint ninvalid = 0; +#endif + + g_return_if_fail (vs != NULL); + g_return_if_fail (klass != NULL); + + v = vs->v; + + g_return_if_fail (v->segments == NULL); + + /* we don't want to destroy vertices */ + gts_allow_floating_vertices = TRUE; + + v1 = GTS_SPLIT_V1 (vs); + v2 = GTS_SPLIT_V2 (vs); + g_assert ((e = GTS_EDGE (gts_vertices_are_connected (v1, v2)))); + +#ifdef DEBUG + fprintf (stderr, "collapsing %p: v1: %p v2: %p v: %p\n", vs, v1, v2, v); + if (!edge_collapse_is_valid (e)) { + char fname[80]; + FILE * fptr; + GSList * triangles, * i; + + g_warning ("invalid edge collapse"); + invalid = TRUE; + sprintf (fname, "invalid.%d", ninvalid); + fptr = fopen (fname, "wt"); + gts_write_segment (GTS_SEGMENT (e), GTS_POINT (v), fptr); + triangles = gts_vertex_triangles (v1, NULL); + triangles = gts_vertex_triangles (v2, triangles); + i = triangles; + while (i) { + gts_write_triangle (i->data, GTS_POINT (v), fptr); + i = i->next; + } + g_slist_free (triangles); + fclose (fptr); + } +#endif + + i = e->triangles; +#ifdef DYNAMIC_SPLIT + cf = vs->cfaces; + j = vs->ncf; + while (j--) { + g_free (cf->a1); + g_free (cf->a2); + cf++; + } + g_free (vs->cfaces); + + vs->ncf = g_slist_length (i); + g_assert (vs->ncf > 0); + cf = vs->cfaces = g_malloc (vs->ncf*sizeof (GtsSplitCFace)); +#endif /* DYNAMIC_SPLIT */ +#ifdef NEW + while (i) { + cf->f = i->data; + g_assert (GTS_IS_FACE (cf->f)); + GTS_OBJECT (cf->f)->klass = GTS_OBJECT_CLASS (cface_class ()); + cf++; + i = i->next; + } + i = e->triangles; + cf = vs->cfaces; + while (i) { + cface_new (i->data, e, v1, v2, vs, heap, klass, cf); +#ifdef DEBUG + fprintf (stderr, "cface: %p->%d t: %p->%d a1: ", + cf->f, id (cf->f), CFACE (cf->f)->t, id (CFACE (cf->f)->t)); + { + GtsTriangle * t, ** a; + a = cf->a1; + while ((t = *(a++))) + fprintf (stderr, "%p->%d ", t, id (t)); + fprintf (stderr, "a2: "); + a = cf->a2; + while ((t = *(a++))) + fprintf (stderr, "%p->%d ", t, id (t)); + fprintf (stderr, "\n"); + } +#endif + cf++; + i = i->next; + } +#else /* not NEW */ + while (i) { + cface_new (i->data, e, v1, v2, vs, heap +#ifdef DYNAMIC_SPLIT + , cf +#endif /* DYNAMIC_SPLIT */ + ); +#ifdef DYNAMIC_SPLIT + cf->f = i->data; + cf++; +#endif /* DYNAMIC_SPLIT */ + i = i->next; + } +#endif /* NEW */ + g_slist_free (e->triangles); + e->triangles = NULL; + gts_object_destroy (GTS_OBJECT (e)); + + gts_allow_floating_vertices = FALSE; + + end = NULL; + i = v1->segments; + while (i) { + GtsSegment * s = i->data; + if (s->v1 == v1) + s->v1 = v; + else + s->v2 = v; + end = i; + i = i->next; + } + if (end) { + end->next = v->segments; + v->segments = v1->segments; + v1->segments = NULL; + } + + end = NULL; + i = v2->segments; + while (i) { + GtsSegment * s = i->data; + if (s->v1 == v2) + s->v1 = v; + else + s->v2 = v; + end = i; + i = i->next; + } + if (end) { + end->next = v->segments; + v->segments = v2->segments; + v2->segments = NULL; + } + +#ifdef DEBUG + if (invalid) { + char fname[80]; + FILE * fptr; + GSList * triangles, * i; + GtsSurface * surface = NULL; + + sprintf (fname, "invalid_after.%d", ninvalid); + fptr = fopen (fname, "wt"); + triangles = gts_vertex_triangles (v, NULL); + i = triangles; + while (i) { + GtsTriangle * t = i->data; + fprintf (stderr, "checking %p->%d\n", t, id (t)); + g_assert (GTS_IS_FACE (t)); + gts_write_triangle (t, GTS_POINT (v), fptr); + surface = GTS_FACE (t)->surfaces->data; + if (gts_triangle_is_duplicate (t)) + fprintf (stderr, "%p->%d is duplicate\n", t, id (t)); + if (gts_segment_is_duplicate (GTS_SEGMENT (t->e1))) + fprintf (stderr, "e1 of %p->%d is duplicate\n", t, id (t)); + if (gts_segment_is_duplicate (GTS_SEGMENT (t->e2))) + fprintf (stderr, "e2 of %p->%d is duplicate\n", t, id (t)); + if (gts_segment_is_duplicate (GTS_SEGMENT (t->e3))) + fprintf (stderr, "e3 of %p->%d is duplicate\n", t, id (t)); + i = i->next; + } + fclose (fptr); + g_slist_free (triangles); +#if 0 + gts_split_expand (vs, surface); + + sprintf (fname, "invalid_after_after.%d", ninvalid); + fptr = fopen (fname, "wt"); + triangles = gts_vertex_triangles (v1, NULL); + triangles = gts_vertex_triangles (v2, triangles); + i = triangles; + while (i) { + GtsTriangle * t = i->data; + gts_write_triangle (t, GTS_POINT (v), fptr); + surface = GTS_FACE (t)->surfaces->data; + if (gts_triangle_is_duplicate (t)) + fprintf (stderr, "%p->%d is duplicate\n", t, id (t)); + if (gts_segment_is_duplicate (GTS_SEGMENT (t->e1))) + fprintf (stderr, "e1 of %p->%d is duplicate\n", t, id (t)); + if (gts_segment_is_duplicate (GTS_SEGMENT (t->e2))) + fprintf (stderr, "e2 of %p->%d is duplicate\n", t, id (t)); + if (gts_segment_is_duplicate (GTS_SEGMENT (t->e3))) + fprintf (stderr, "e3 of %p->%d is duplicate\n", t, id (t)); + i = i->next; + } + fclose (fptr); + g_slist_free (triangles); + + exit (1); +#endif + ninvalid++; + } +#endif +} + +/** + * gts_split_expand: + * @vs: a #GtsSplit. + * @s: a #GtsSurface. + * @klass: a #GtsEdgeClass. + * + * Expands the vertex split @vs adding the newly created faces to @s. Any + * new edge will be of class @klass. + */ +void gts_split_expand (GtsSplit * vs, + GtsSurface * s, + GtsEdgeClass * klass) +{ + GSList * i; + GtsEdge * e; + GtsVertex * v, * v1, * v2; + gboolean changed = FALSE; + GtsSplitCFace * cf; + guint j; + + g_return_if_fail (vs != NULL); + g_return_if_fail (s != NULL); + g_return_if_fail (klass != NULL); + + /* we don't want to destroy vertices */ + gts_allow_floating_vertices = TRUE; + + v1 = GTS_SPLIT_V1 (vs); + v2 = GTS_SPLIT_V2 (vs); + v = vs->v; +#ifdef DEBUG_EXPAND + fprintf (stderr, "expanding %p->%d: v1: %p->%d v2: %p->%d v: %p->%d\n", + vs, id (vs), v1, id (v1), v2, id (v2), v, id (v)); +#endif + e = gts_edge_new (klass, v1, v2); + cf = vs->cfaces; + j = vs->ncf; + while (j--) { + cface_expand (CFACE (cf->f), cf->a1, cf->a2, e, v1, v2, v, klass); + gts_surface_add_face (s, cf->f); + cf++; + } + + gts_allow_floating_vertices = FALSE; + + /* this part is described by figure "expand.fig" */ + i = v->segments; + while (i) { + GtsEdge * e1 = i->data; + GtsVertex * with = NULL; + GSList * j = e1->triangles, * next = i->next; + // fprintf (stderr, "e1: %p->%d\n", e1, id (e1)); + while (j && !with) { + with = GTS_OBJECT (j->data)->reserved; + j = j->next; + } + if (with) { + j = e1->triangles; + while (j) { + GtsTriangle * t = j->data; + if (GTS_OBJECT (t)->reserved) { + g_assert (GTS_OBJECT (t)->reserved == with); + GTS_OBJECT (t)->reserved = NULL; + } + else + GTS_OBJECT (t)->reserved = with; + j = j->next; + } + if (GTS_SEGMENT (e1)->v1 == v) + GTS_SEGMENT (e1)->v1 = with; + else + GTS_SEGMENT (e1)->v2 = with; + + v->segments = g_slist_remove_link (v->segments, i); + i->next = with->segments; + with->segments = i; + changed = TRUE; + } + if (next) + i = next; + else { + /* check for infinite loop (the crossed out case in + figure "expand.fig") */ + g_assert (changed); + changed = FALSE; + i = v->segments; + } + } +} + +#ifndef DYNAMIC_SPLIT +static void cface_neighbors (GtsSplitCFace * cf, + GtsEdge * e, + GtsVertex * v1, + GtsVertex * v2) +{ + GtsTriangle * t = GTS_TRIANGLE (cf->f), ** a; + GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3; + GSList * i; + guint size; + + ROTATE_ORIENT (e, e1, e2, e3); + if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1), v2)) { + e3 = e1; e1 = e2; e2 = e3; + } + + i = e1->triangles; + size = g_slist_length (i)*sizeof (GtsTriangle *); + a = cf->a1 = g_malloc (size > 0 ? size : sizeof (GtsTriangle *)); + while (i) { + if (i->data != t) + *(a++) = i->data; + i = i->next; + } + *a = NULL; + + i = e2->triangles; + size = g_slist_length (i)*sizeof (GtsTriangle *); + a = cf->a2 = g_malloc (size > 0 ? size : sizeof (GtsTriangle *)); + while (i) { + if (i->data != t) + *(a++) = i->data; + i = i->next; + } + *a = NULL; +} +#endif /*ifndef DYNAMIC_SPLIT */ + +/** + * gts_split_new: + * @klass: a #GtsSplitClass. + * @v: a #GtsVertex. + * @o1: either a #GtsVertex or a #GtsSplit. + * @o2: either a #GtsVertex or a #GtsSplit. + * + * Creates a new #GtsSplit which would collapse @o1 and @o2 into @v. The + * collapse itself is not performed. + * + * Returns: the new #GtsSplit. + */ +GtsSplit * gts_split_new (GtsSplitClass * klass, + GtsVertex * v, + GtsObject * o1, + GtsObject * o2) +{ + GtsSplit * vs; +#ifndef DYNAMIC_SPLIT + GtsVertex * v1, * v2; + GtsEdge * e; + GSList * i; + GtsSplitCFace * cf; +#endif + + g_return_val_if_fail (klass != NULL, NULL); + g_return_val_if_fail (v != NULL, NULL); + g_return_val_if_fail (GTS_IS_SPLIT (o1) || GTS_IS_VERTEX (o1), NULL); + g_return_val_if_fail (GTS_IS_SPLIT (o2) || GTS_IS_VERTEX (o2), NULL); + + vs = GTS_SPLIT (gts_object_new (GTS_OBJECT_CLASS (klass))); + vs->v = v; + vs->v1 = o1; + vs->v2 = o2; +#ifdef DYNAMIC_SPLIT + vs->ncf = 0; + vs->cfaces = NULL; +#else + v1 = GTS_SPLIT_V1 (vs); + v2 = GTS_SPLIT_V2 (vs); + g_assert ((e = GTS_EDGE (gts_vertices_are_connected (v1, v2)))); + i = e->triangles; + vs->ncf = g_slist_length (i); + g_assert (vs->ncf > 0); + cf = vs->cfaces = g_malloc (vs->ncf*sizeof (GtsSplitCFace)); + while (i) { + cf->f = i->data; + cface_neighbors (cf, e, v1, v2); + i = i->next; + cf++; + } +#endif + + return vs; +} + +static gboolean +split_traverse_pre_order (GtsSplit * vs, + GtsSplitTraverseFunc func, + gpointer data) +{ + if (func (vs, data)) + return TRUE; + if (GTS_IS_SPLIT (vs->v1) && + split_traverse_pre_order (GTS_SPLIT (vs->v1), func, data)) + return TRUE; + if (GTS_IS_SPLIT (vs->v2) && + split_traverse_pre_order (GTS_SPLIT (vs->v2), func, data)) + return TRUE; + return FALSE; +} + +static gboolean +split_depth_traverse_pre_order (GtsSplit * vs, + guint depth, + GtsSplitTraverseFunc func, + gpointer data) +{ + if (func (vs, data)) + return TRUE; + + depth--; + if (!depth) + return FALSE; + + if (GTS_IS_SPLIT (vs->v1) && + split_depth_traverse_pre_order (GTS_SPLIT (vs->v1), depth, func, data)) + return TRUE; + if (GTS_IS_SPLIT (vs->v2) && + split_depth_traverse_pre_order (GTS_SPLIT (vs->v2), depth, func, data)) + return TRUE; + return FALSE; +} + +static gboolean +split_traverse_post_order (GtsSplit * vs, + GtsSplitTraverseFunc func, + gpointer data) +{ + if (GTS_IS_SPLIT (vs->v1) && + split_traverse_post_order (GTS_SPLIT (vs->v1), func, data)) + return TRUE; + if (GTS_IS_SPLIT (vs->v2) && + split_traverse_post_order (GTS_SPLIT (vs->v2), func, data)) + return TRUE; + if (func (vs, data)) + return TRUE; + return FALSE; +} + +static gboolean +split_depth_traverse_post_order (GtsSplit * vs, + guint depth, + GtsSplitTraverseFunc func, + gpointer data) +{ + depth--; + if (depth) { + if (GTS_IS_SPLIT (vs->v1) && + split_depth_traverse_post_order (GTS_SPLIT (vs->v1), + depth, func, data)) + return TRUE; + if (GTS_IS_SPLIT (vs->v2) && + split_depth_traverse_post_order (GTS_SPLIT (vs->v2), + depth, func, data)) + return TRUE; + } + if (func (vs, data)) + return TRUE; + return FALSE; +} + +/** + * gts_split_traverse: + * @root: the #GtsSplit to start the traversal from. + * @order: the order in which nodes are visited - G_PRE_ORDER or G_POST_ORDER. + * @depth: the maximum depth of the traversal. Nodes below this depth + * will not be visited. If depth is -1 all nodes in the tree are + * visited. If depth is 1, only the root is visited. If depth is 2, + * the root and its children are visited. And so on. + * @func: the function to call for each visited #GtsHSplit. + * @data: user data to pass to the function. + * + * Traverses the #GtsSplit tree having @root as root. Calls @func for each + * #GtsSplit of the tree in the order specified by @order. If order is set + * to G_PRE_ORDER @func is called for the #GtsSplit then its children, if order + * is set to G_POST_ORDER @func is called for the children and then for the + * #GtsSplit. + */ +void gts_split_traverse (GtsSplit * root, + GTraverseType order, + gint depth, + GtsSplitTraverseFunc func, + gpointer data) +{ + g_return_if_fail (root != NULL); + g_return_if_fail (func != NULL); + g_return_if_fail (order < G_LEVEL_ORDER); + g_return_if_fail (depth == -1 || depth > 0); + + switch (order) { + case G_PRE_ORDER: + if (depth < 0) + split_traverse_pre_order (root, func, data); + else + split_depth_traverse_pre_order (root, depth, func, data); + break; + case G_POST_ORDER: + if (depth < 0) + split_traverse_post_order (root, func, data); + else + split_depth_traverse_post_order (root, depth, func, data); + break; + default: + g_assert_not_reached (); + } +} + +/** + * gts_split_height: + * @root: a #GtsSplit. + * + * Returns: the maximum height of the vertex split tree having @root as root. + */ +guint gts_split_height (GtsSplit * root) +{ + guint height = 0, tmp_height; + + g_return_val_if_fail (root != NULL, 0); + + if (GTS_IS_SPLIT (root->v1)) { + tmp_height = gts_split_height (GTS_SPLIT (root->v1)); + if (tmp_height > height) + height = tmp_height; + } + if (GTS_IS_SPLIT (root->v2)) { + tmp_height = gts_split_height (GTS_SPLIT (root->v2)); + if (tmp_height > height) + height = tmp_height; + } + + return height + 1; +} + +#ifndef DYNAMIC_SPLIT +static gboolean list_array_are_identical (GSList * list, + gpointer * array, + gpointer excluded) +{ + while (list) { + gpointer data = list->data; + if (data != excluded) { + gboolean found = FALSE; + gpointer * a = array; + + while (!found && *a) + if (*(a++) == data) + found = TRUE; + if (!found) + return FALSE; + } + list = list->next; + } + return TRUE; +} +#endif /* ifndef DYNAMIC_SPLIT */ + +#ifndef NEW +gboolean gts_split_is_collapsable (GtsSplit * vs) +{ + guint i; + GtsSplitCFace * cf; + GtsVertex * v1, * v2; + GtsEdge * e; + + g_return_val_if_fail (vs != NULL, FALSE); + + v1 = GTS_SPLIT_V1 (vs); + v2 = GTS_SPLIT_V2 (vs); + g_return_val_if_fail ((e = GTS_EDGE (gts_vertices_are_connected (v1, v2))), + FALSE); + +#ifdef DYNAMIC_SPLIT + if (!gts_edge_collapse_is_valid (e)) + return FALSE; +#else + i = vs->ncf; + cf = vs->cfaces; + while (i--) { + GtsTriangle * t = GTS_TRIANGLE (cf->f); + GtsEdge * e1 = t->e1, * e2 = t->e2, * e3 = t->e3; + + ROTATE_ORIENT (e, e1, e2, e3); + if (SEGMENT_USE_VERTEX (GTS_SEGMENT (e1), v2)) { + e3 = e1; e1 = e2; e2 = e3; + } + + if (!list_array_are_identical (e1->triangles, (gpointer *) cf->a1, t)) + return FALSE; + if (!list_array_are_identical (e2->triangles, (gpointer *) cf->a2, t)) + return FALSE; + + cf++; + } +#endif + return TRUE; +} +#endif /* not NEW */ + +#ifdef DEBUG_HEXPAND +static guint expand_level = 0; + +static void expand_indent (FILE * fptr) +{ + guint i = expand_level; + while (i--) + fputc (' ', fptr); +} +#endif + +/** + * gts_hsplit_force_expand: + * @hs: a #GtsHSplit. + * @hsurface: a #GtsHSurface. + * + * Forces the expansion of @hs by first expanding all its dependencies not + * already expanded. + */ +void gts_hsplit_force_expand (GtsHSplit * hs, + GtsHSurface * hsurface) +{ + guint i; + GtsSplitCFace * cf; + + g_return_if_fail (hs != NULL); + g_return_if_fail (hsurface != NULL); + g_return_if_fail (hs->nchild == 0); + +#ifdef DEBUG_HEXPAND + expand_level += 2; +#endif + + if (hs->parent && hs->parent->nchild == 0) { +#ifdef DEBUG_HEXPAND + expand_indent (stderr); + fprintf (stderr, "expand parent %p\n", hs->parent); +#endif + gts_hsplit_force_expand (hs->parent, hsurface); + } + + i = GTS_SPLIT (hs)->ncf; + cf = GTS_SPLIT (hs)->cfaces; + while (i--) { + GtsTriangle ** j, * t; + + j = cf->a1; + while ((t = *(j++))) + if (IS_CFACE (t)) { +#ifdef DEBUG_HEXPAND + expand_indent (stderr); + fprintf (stderr, "expand a1: cf->f: %p t: %p parent_split: %p\n", + cf->f, + t, + GTS_HSPLIT (CFACE (t)->parent_split)); +#endif + gts_hsplit_force_expand (GTS_HSPLIT (CFACE (t)->parent_split), + hsurface); +#ifdef DEBUG_HEXPAND + g_assert (!IS_CFACE (t)); +#endif + } + j = cf->a2; + while ((t = *(j++))) + if (IS_CFACE (t)) { +#ifdef DEBUG_HEXPAND + expand_indent (stderr); + fprintf (stderr, "expand a2: cf->f: %p t: %p parent_split: %p\n", + cf->f, + t, + GTS_HSPLIT (CFACE (t)->parent_split)); +#endif + gts_hsplit_force_expand (GTS_HSPLIT (CFACE (t)->parent_split), + hsurface); + } + cf++; + } + + gts_hsplit_expand (hs, hsurface); + +#ifdef DEBUG_HEXPAND + expand_level -= 2; + expand_indent (stderr); + fprintf (stderr, "%p expanded\n", hs); +#endif +} + +static void index_object (GtsObject * o, guint * n) +{ + o->reserved = GUINT_TO_POINTER ((*n)++); +} + +static void index_face (GtsFace * f, gpointer * data) +{ + guint * nf = data[1]; + + g_hash_table_insert (data[0], f, GUINT_TO_POINTER ((*nf)++)); +} + +/** + * gts_psurface_write: + * @ps: a #GtsPSurface. + * @fptr: a file pointer. + * + * Writes to @fptr a GTS progressive surface description. + */ +void gts_psurface_write (GtsPSurface * ps, FILE * fptr) +{ + guint nv = 1; + guint nf = 1; + GHashTable * hash; + gpointer data[2]; + + g_return_if_fail (ps != NULL); + g_return_if_fail (fptr != NULL); + g_return_if_fail (GTS_PSURFACE_IS_CLOSED (ps)); + + while (gts_psurface_remove_vertex (ps)) + ; + + GTS_POINT_CLASS (ps->s->vertex_class)->binary = FALSE; + gts_surface_write (ps->s, fptr); + + gts_surface_foreach_vertex (ps->s, (GtsFunc) index_object, &nv); + hash = g_hash_table_new (NULL, NULL); + data[0] = hash; + data[1] = &nf; + gts_surface_foreach_face (ps->s, (GtsFunc) index_face, data); + + fprintf (fptr, "%u\n", ps->split->len); + while (ps->pos) { + GtsSplit * vs = g_ptr_array_index (ps->split, --ps->pos); + GtsSplitCFace * scf = vs->cfaces; + GtsVertex * v1, * v2; + guint i = vs->ncf; + + fprintf (fptr, "%u %u", + GPOINTER_TO_UINT (GTS_OBJECT (vs->v)->reserved), + vs->ncf); + if (GTS_OBJECT (vs)->klass->write) + (*GTS_OBJECT (vs)->klass->write) (GTS_OBJECT (vs), fptr); + fputc ('\n', fptr); + + v1 = GTS_IS_SPLIT (vs->v1) ? GTS_SPLIT (vs->v1)->v : GTS_VERTEX (vs->v1); + GTS_OBJECT (v1)->reserved = GUINT_TO_POINTER (nv++); + v2 = GTS_IS_SPLIT (vs->v2) ? GTS_SPLIT (vs->v2)->v : GTS_VERTEX (vs->v2); + GTS_OBJECT (v2)->reserved = GUINT_TO_POINTER (nv++); + + (*GTS_OBJECT (v1)->klass->write) (GTS_OBJECT (v1), fptr); + fputc ('\n', fptr); + + (*GTS_OBJECT (v2)->klass->write) (GTS_OBJECT (v2), fptr); + fputc ('\n', fptr); + + while (i--) { + CFace * cf = CFACE (scf->f); + GtsTriangle ** a, * t; + + fprintf (fptr, "%u %u", + GPOINTER_TO_UINT (g_hash_table_lookup (hash, cf->t)), + cf->flags); + if (GTS_OBJECT_CLASS (ps->s->face_class)->write) + (*GTS_OBJECT_CLASS (ps->s->face_class)->write) (GTS_OBJECT (cf), fptr); + fputc ('\n', fptr); + + a = scf->a1; + while ((t = *(a++))) + fprintf (fptr, "%u ", + GPOINTER_TO_UINT (g_hash_table_lookup (hash, t))); + fprintf (fptr, "\n"); + + a = scf->a2; + while ((t = *(a++))) + fprintf (fptr, "%u ", + GPOINTER_TO_UINT (g_hash_table_lookup (hash, t))); + fprintf (fptr, "\n"); + + g_hash_table_insert (hash, cf, GUINT_TO_POINTER (nf++)); + + scf++; + } + + gts_split_expand (vs, ps->s, ps->s->edge_class); + } + + gts_surface_foreach_vertex (ps->s, + (GtsFunc) gts_object_reset_reserved, NULL); + g_hash_table_destroy (hash); +} + +static guint surface_read (GtsSurface * surface, + GtsFile * f, + GPtrArray * vertices, + GPtrArray * faces) +{ + GtsEdge ** edges; + guint n, nv, ne, nf; + + g_return_val_if_fail (surface != NULL, 1); + g_return_val_if_fail (f != NULL, 1); + + if (f->type != GTS_INT) { + gts_file_error (f, "expecting an integer (number of vertices)"); + return f->line; + } + nv = atoi (f->token->str); + + gts_file_next_token (f); + if (f->type != GTS_INT) { + gts_file_error (f, "expecting an integer (number of edges)"); + return f->line; + } + ne = atoi (f->token->str); + + gts_file_next_token (f); + if (f->type != GTS_INT) { + gts_file_error (f, "expecting an integer (number of faces)"); + return f->line; + } + nf = atoi (f->token->str); + + gts_file_next_token (f); + if (f->type == GTS_STRING) { + if (f->type != GTS_STRING) { + gts_file_error (f, "expecting a string (GtsSurfaceClass)"); + return f->line; + } + gts_file_next_token (f); + if (f->type != GTS_STRING) { + gts_file_error (f, "expecting a string (GtsFaceClass)"); + return f->line; + } + gts_file_next_token (f); + if (f->type != GTS_STRING) { + gts_file_error (f, "expecting a string (GtsEdgeClass)"); + return f->line; + } + gts_file_next_token (f); + if (f->type != GTS_STRING) { + gts_file_error (f, "expecting a string (GtsVertexClass)"); + return f->line; + } + if (!strcmp (f->token->str, "GtsVertexBinary")) + GTS_POINT_CLASS (surface->vertex_class)->binary = TRUE; + else + gts_file_first_token_after (f, '\n'); + } + else + gts_file_first_token_after (f, '\n'); + + g_ptr_array_set_size (vertices, nv); + g_ptr_array_set_size (faces, nf); + /* allocate nv + 1 just in case nv == 0 */ + edges = g_malloc ((ne + 1)*sizeof (GtsEdge *)); + + n = 0; + while (n < nv && f->type != GTS_ERROR) { + GtsObject * new_vertex = + gts_object_new (GTS_OBJECT_CLASS (surface->vertex_class)); + + (* GTS_OBJECT_CLASS (surface->vertex_class)->read) (&new_vertex, f); + if (f->type != GTS_ERROR) { + if (!GTS_POINT_CLASS (surface->vertex_class)->binary) + gts_file_first_token_after (f, '\n'); + g_ptr_array_index (vertices, n++) = new_vertex; + } + else + gts_object_destroy (new_vertex); + } + if (f->type == GTS_ERROR) + nv = n; + if (GTS_POINT_CLASS (surface->vertex_class)->binary) + gts_file_first_token_after (f, '\n'); + + n = 0; + while (n < ne && f->type != GTS_ERROR) { + guint p1, p2; + + if (f->type != GTS_INT) + gts_file_error (f, "expecting an integer (first vertex index)"); + else { + p1 = atoi (f->token->str); + if (p1 == 0 || p1 > nv) + gts_file_error (f, "vertex index `%d' is out of range `[1,%d]'", + p1, nv); + else { + gts_file_next_token (f); + if (f->type != GTS_INT) + gts_file_error (f, "expecting an integer (second vertex index)"); + else { + p2 = atoi (f->token->str); + if (p2 == 0 || p2 > nv) + gts_file_error (f, "vertex index `%d' is out of range `[1,%d]'", + p2, nv); + else { + GtsEdge * new_edge = + gts_edge_new (surface->edge_class, + g_ptr_array_index (vertices, p1 - 1), + g_ptr_array_index (vertices, p2 - 1)); + + gts_file_next_token (f); + if (f->type != '\n') + if (GTS_OBJECT_CLASS (surface->edge_class)->read) + (*GTS_OBJECT_CLASS (surface->edge_class)->read) + ((GtsObject **) &new_edge, f); + gts_file_first_token_after (f, '\n'); + edges[n++] = new_edge; + } + } + } + } + } + if (f->type == GTS_ERROR) + ne = n; + + n = 0; + while (n < nf && f->type != GTS_ERROR) { + guint s1, s2, s3; + + if (f->type != GTS_INT) + gts_file_error (f, "expecting an integer (first edge index)"); + else { + s1 = atoi (f->token->str); + if (s1 == 0 || s1 > ne) + gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", + s1, ne); + else { + gts_file_next_token (f); + if (f->type != GTS_INT) + gts_file_error (f, "expecting an integer (second edge index)"); + else { + s2 = atoi (f->token->str); + if (s2 == 0 || s2 > ne) + gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", + s2, ne); + else { + gts_file_next_token (f); + if (f->type != GTS_INT) + gts_file_error (f, "expecting an integer (third edge index)"); + else { + s3 = atoi (f->token->str); + if (s3 == 0 || s3 > ne) + gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", + s3, ne); + else { + GtsFace * new_face = gts_face_new (surface->face_class, + edges[s1 - 1], + edges[s2 - 1], + edges[s3 - 1]); + + gts_file_next_token (f); + if (f->type != '\n') + if (GTS_OBJECT_CLASS (surface->face_class)->read) + (*GTS_OBJECT_CLASS (surface->face_class)->read) + ((GtsObject **) &new_face, f); + gts_file_first_token_after (f, '\n'); + gts_surface_add_face (surface, new_face); + g_ptr_array_index (faces, n++) = new_face; + } + } + } + } + } + } + } + + g_free (edges); + + if (f->type == GTS_ERROR) { + gts_allow_floating_vertices = TRUE; + while (nv) + gts_object_destroy (GTS_OBJECT (g_ptr_array_index (vertices, nv-- - 1))); + gts_allow_floating_vertices = FALSE; + return f->line; + } + + return 0; +} + +/** + * gts_psurface_open: + * @klass: a #GtsPSurfaceClass. + * @s: a #GtsSurface. + * @split_class: a #GtsSplitClass to use for the #GtsSplit. + * @f: a #GtsFile. + * + * Creates a new #GtsPSurface prepared for input from the file @f + * containing a valid GTS representation of a progressive surface. The initial + * shape of the progressive surface is loaded into @s. + * + * Before being usable as such this progressive surface must be closed using + * gts_psurface_close(). While open however, the functions + * gts_psurface_get_vertex_number(), gts_psurface_min_vertex_number() and + * gts_psurface_max_vertex_number() can still be used. + * + * Returns: a new #GtsPSurface or %NULL if there was a format error while + * reading the file, in which case @f contains information about the error. + */ +GtsPSurface * gts_psurface_open (GtsPSurfaceClass * klass, + GtsSurface * s, + GtsSplitClass * split_class, + GtsFile * f) +{ + GtsPSurface * ps; + + g_return_val_if_fail (klass != NULL, NULL); + g_return_val_if_fail (s != NULL, NULL); + g_return_val_if_fail (split_class != NULL, NULL); + g_return_val_if_fail (f != NULL, NULL); + + ps = GTS_PSURFACE (gts_object_new (GTS_OBJECT_CLASS (klass))); + ps->s = s; + ps->split_class = split_class; + + ps->vertices = g_ptr_array_new (); + ps->faces = g_ptr_array_new (); + + if (surface_read (s, f, ps->vertices, ps->faces)) { + ps->s = NULL; + gts_object_destroy (GTS_OBJECT (ps)); + return NULL; + } + + ps->min = gts_surface_vertex_number (ps->s); + ps->pos = 0; + + if (f->type == GTS_INT) { + gint ns = atoi (f->token->str); + + if (ns > 0) { + g_ptr_array_set_size (ps->split, ns); + gts_file_first_token_after (f, '\n'); + } + } + + return ps; +} + +/** + * gts_psurface_read_vertex: + * @ps: a #GtsPSurface prealably created with gts_psurface_open(). + * @fp: a #GtsFile. + * + * Reads in one vertex split operation from @fp and performs the expansion. + * + * If an error occurs while reading the file, the @error field of @fp is set. + * + * Returns: the newly created #GtsSplit or %NULL if no vertex split could be + * read from @fp. + */ +GtsSplit * gts_psurface_read_vertex (GtsPSurface * ps, GtsFile * fp) +{ + guint nv, ncf; + GtsSplit * vs, * parent; + GtsSplitCFace * scf; + + g_return_val_if_fail (ps != NULL, NULL); + g_return_val_if_fail (fp != NULL, NULL); + g_return_val_if_fail (!GTS_PSURFACE_IS_CLOSED (ps), NULL); + + if (ps->pos >= ps->split->len) + return NULL; + + if (fp->type == GTS_NONE) + return NULL; + if (fp->type != GTS_INT) { + gts_file_error (fp, "expecting an integer (vertex index)"); + return NULL; + } + nv = atoi (fp->token->str); + if (nv == 0 || nv > ps->vertices->len) { + gts_file_error (fp, "vertex index `%d' is out of range `[1,%d]'", + nv, ps->vertices->len); + return NULL; + } + + gts_file_next_token (fp); + if (fp->type != GTS_INT) { + gts_file_error (fp, "expecting an integer (ncf)"); + return NULL; + } + ncf = atoi (fp->token->str); + + vs = GTS_SPLIT (gts_object_new (GTS_OBJECT_CLASS (ps->split_class))); + + vs->v = g_ptr_array_index (ps->vertices, nv - 1); + vs->v1 = vs->v2 = NULL; + vs->cfaces = NULL; + vs->ncf = 0; + + gts_file_next_token (fp); + if (fp->type != '\n') + if (GTS_OBJECT (vs)->klass->read) + (* GTS_OBJECT (vs)->klass->read) ((GtsObject **) &vs, fp); + gts_file_first_token_after (fp, '\n'); + + if (fp->type != GTS_ERROR) { + vs->v1 = gts_object_new (GTS_OBJECT_CLASS (ps->s->vertex_class)); + (* GTS_OBJECT_CLASS (ps->s->vertex_class)->read) (&(vs->v1), fp); + if (fp->type != GTS_ERROR) { + vs->v1->reserved = vs; + g_ptr_array_add (ps->vertices, vs->v1); + + gts_file_first_token_after (fp, '\n'); + + vs->v2 = gts_object_new (GTS_OBJECT_CLASS (ps->s->vertex_class)); + (*GTS_OBJECT_CLASS (ps->s->vertex_class)->read) (&(vs->v2), fp); + if (fp->type != GTS_ERROR) { + vs->v2->reserved = vs; + g_ptr_array_add (ps->vertices, vs->v2); + gts_file_first_token_after (fp, '\n'); + } + } + } + + if (fp->type != GTS_ERROR) { + scf = vs->cfaces = g_malloc (sizeof (GtsSplitCFace)*ncf); + while (fp->type != GTS_ERROR && ncf--) { + guint it, flags; + GtsFace * f; + CFace * cf; + GPtrArray * a; + + if (fp->type != GTS_INT) + gts_file_error (fp, "expecting an integer (face index)"); + else { + it = atoi (fp->token->str); + if (it == 0 || it > ps->faces->len) + gts_file_error (fp, "face index `%d' is out of range `[1,%d]'", + it, ps->faces->len); + else { + gts_file_next_token (fp); + if (fp->type != GTS_INT) + gts_file_error (fp, "expecting an integer (flags)"); + else { + flags = atoi (fp->token->str); + f = + GTS_FACE (gts_object_new (GTS_OBJECT_CLASS (ps->s->face_class))); + + gts_file_next_token (fp); + if (fp->type != '\n') + if (GTS_OBJECT (f)->klass->read) + (*GTS_OBJECT (f)->klass->read) ((GtsObject **) &f, fp); + gts_file_first_token_after (fp, '\n'); + if (fp->type != GTS_ERROR) { + scf->f = f; + + cf = (CFace *) f; + GTS_OBJECT (cf)->klass = GTS_OBJECT_CLASS (cface_class ()); + cf->parent_split = vs; + cf->t = g_ptr_array_index (ps->faces, it - 1); + cf->flags = flags; + + a = g_ptr_array_new (); + do { + if (fp->type != GTS_INT) + gts_file_error (fp, "expecting an integer (face index)"); + else { + it = atoi (fp->token->str); + if (it > ps->faces->len) + gts_file_error (fp, + "face index `%d' is out of range `[1,%d]'", + it, ps->faces->len); + else { + g_ptr_array_add (a, g_ptr_array_index (ps->faces, + it - 1)); + gts_file_next_token (fp); + } + } + } while (fp->type != GTS_ERROR && fp->type != '\n'); + gts_file_first_token_after (fp, '\n'); + g_ptr_array_add (a, NULL); + scf->a1 = (GtsTriangle **) a->pdata; + g_ptr_array_free (a, FALSE); + + if (fp->type != GTS_ERROR) { + a = g_ptr_array_new (); + do { + if (fp->type != GTS_INT) + gts_file_error (fp, "expecting an integer (face index)"); + else { + it = atoi (fp->token->str); + if (it > ps->faces->len) + gts_file_error (fp, + "face index `%d' is out of range `[1,%d]'", + it, ps->faces->len); + else { + g_ptr_array_add (a, g_ptr_array_index (ps->faces, + it - 1)); + gts_file_next_token (fp); + } + } + } while (fp->type != GTS_ERROR && fp->type != '\n'); + gts_file_first_token_after (fp, '\n'); + g_ptr_array_add (a, NULL); + scf->a2 = (GtsTriangle **) a->pdata; + g_ptr_array_free (a, FALSE); + + g_ptr_array_add (ps->faces, f); + + vs->ncf++; + scf++; + } + } + } + } + } + } + } + + if (fp->type != GTS_ERROR) { + if ((parent = GTS_OBJECT (vs->v)->reserved)) { + GTS_OBJECT (vs->v)->reserved = NULL; + if (parent->v1 == GTS_OBJECT (vs->v)) + parent->v1 = GTS_OBJECT (vs); + else { + g_assert (parent->v2 == GTS_OBJECT (vs->v)); + parent->v2 = GTS_OBJECT (vs); + } + } + g_ptr_array_index (ps->split, ps->pos++) = vs; + gts_split_expand (vs, ps->s, ps->s->edge_class); + + return vs; + } + + if (vs->v1) gts_object_destroy (vs->v1); + if (vs->v2) gts_object_destroy (vs->v2); + gts_object_destroy (GTS_OBJECT (vs)); + + return NULL; +} + +/** + * gts_psurface_close: + * @ps: a #GtsPSurface prealably created with gts_psurface_open(). + * + * Closes a progressive surface. + */ +void gts_psurface_close (GtsPSurface * ps) +{ + g_return_if_fail (ps != NULL); + g_return_if_fail (!GTS_PSURFACE_IS_CLOSED (ps)); + + g_ptr_array_free (ps->vertices, TRUE); + g_ptr_array_free (ps->faces, TRUE); + ps->faces = ps->vertices = NULL; + + gts_surface_foreach_vertex (ps->s, + (GtsFunc) gts_object_reset_reserved, NULL); + if (ps->pos > 0) + g_ptr_array_set_size (ps->split, ps->pos); + if (ps->split->len > 1) { + guint i, half = ps->split->len/2, n = ps->split->len - 1; + + for (i = 0; i < half; i++) { + gpointer p1 = g_ptr_array_index (ps->split, i); + gpointer p2 = g_ptr_array_index (ps->split, n - i); + g_ptr_array_index (ps->split, n - i) = p1; + g_ptr_array_index (ps->split, i) = p2; + } + } + ps->pos = 0; +} Index: work/obsolete/toporouter/src_3rd/gts/stripe.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/stripe.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/stripe.c (revision 6803) @@ -0,0 +1,766 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999-2003 Wagner Toledo Correa, Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gts.h" + +#define PRINT_HEAP_ELEMENTS 0 + +typedef struct { + GtsTriangle * t; + gboolean used; + GSList * neighbors; + GtsEHeapPair *pos; +} tri_data_t; + +typedef struct { + GHashTable * ht; +} map_t; + +typedef struct { + map_t * map; + GtsEHeap * heap; +} heap_t; + +static tri_data_t * tri_data_new (GtsTriangle * t); +static void tri_data_destroy (tri_data_t * td); +static guint tri_data_num_unused_neighbors2 (const tri_data_t * td, + const map_t * map); +static GHashTable * tri_data_unused_neighbors2 (const tri_data_t * td, + const map_t * map); + +static map_t * map_new (GtsSurface * s); +static void map_destroy (map_t * map); +static tri_data_t * map_lookup (const map_t * map, GtsTriangle * t); + + +static heap_t * heap_new (GtsSurface * s); +static void heap_destroy (heap_t * heap); +static gboolean heap_is_empty (const heap_t * heap); +static GtsTriangle * heap_top (const heap_t * heap); +static void heap_remove (heap_t * heap, GtsTriangle * t); + +/* helper functions */ + +static gboolean vertices_are_unique (GtsVertex * v1, + GtsVertex * v2, + GtsVertex * v3) +{ + g_assert (v1 && v2 && v3); + return (v1 != v2 && v1 != v3 && v2 != v3); +} + +static gboolean vertex_is_one_of (GtsVertex * v, + GtsVertex * v1, + GtsVertex * v2, + GtsVertex * v3) +{ + g_assert (v && v1 && v2 && v3); + return v == v1 || v == v2 || v == v3; +} + +static guint num_shared_vertices (GtsVertex * u1, + GtsVertex * u2, + GtsVertex * u3, + GtsVertex * v1, + GtsVertex * v2, + GtsVertex * v3) +{ + guint n = 0; + + g_assert (u1 && u2 && u3); + g_assert (v1 && v2 && v3); + g_assert (vertices_are_unique (u1, u2, u3)); + g_assert (vertices_are_unique (v1, v2, v3)); + + if (vertex_is_one_of (v1, u1, u2, u3)) + n++; + if (vertex_is_one_of (v2, u1, u2, u3)) + n++; + if (vertex_is_one_of (v3, u1, u2, u3)) + n++; + return n; +} + +static gboolean vertices_match (GtsVertex * v1, + GtsVertex * v2, + GtsVertex * v3, + GtsVertex ** v4, + GtsVertex ** v5, + GtsVertex ** v6) +{ + guint i; + + g_assert (v4 && v5 && v6); + g_assert (*v4 && *v5 && *v6); + g_assert (vertices_are_unique (*v4, *v5, *v6)); + + for (i = 0; i < 2; i++) { + if ((!v1 || (v1 == *v4)) && + (!v2 || (v2 == *v5)) && + (!v3 || (v3 == *v6))) + return TRUE; + else { + GtsVertex * v7 = * v4; + + *v4 = *v5; + *v5 = *v6; + *v6 = v7; + } + } + return ((!v1 || (v1 == *v4)) && + (!v2 || (v2 == *v5)) && + (!v3 || (v3 == *v6))); +} + +static GtsVertex * non_shared_vertex1 (GtsVertex * u1, + GtsVertex * u2, + GtsVertex * u3, + GtsVertex * v1, + GtsVertex * v2, + GtsVertex * v3) +{ + GtsVertex * u = NULL; + + g_assert (u1 && u2 && u3); + g_assert (v1 && v2 && v3); + g_assert (vertices_are_unique (u1, u2, u3)); + g_assert (vertices_are_unique (v1, v2, v3)); + g_assert (num_shared_vertices (u1, u2, u3, v1, v2, v3) == 2); + + if (!vertex_is_one_of (u1, v1, v2, v3)) { + g_assert (vertex_is_one_of (u2, v1, v2, v3)); + g_assert (vertex_is_one_of (u3, v1, v2, v3)); + u = u1; + } else if (!vertex_is_one_of (u2, v1, v2, v3)) { + g_assert (vertex_is_one_of (u1, v1, v2, v3)); + g_assert (vertex_is_one_of (u3, v1, v2, v3)); + u = u2; + } else if (!vertex_is_one_of (u3, v1, v2, v3)) { + g_assert (vertex_is_one_of (u1, v1, v2, v3)); + g_assert (vertex_is_one_of (u2, v1, v2, v3)); + u = u3; + } else + g_assert_not_reached (); + + return u; +} + +static void match_vertex (GtsVertex * v, + GtsVertex ** v1, + GtsVertex ** v2, + GtsVertex ** v3) +{ + g_assert (v && v1 && v2 && v3); + g_assert (*v1 && *v2 && *v3); + g_assert (vertex_is_one_of (v, *v1, *v2, *v3)); + while (*v1 != v) { + GtsVertex *v0 = *v1; + + *v1 = *v2; + *v2 = *v3; + *v3 = v0; + } +} + +/* tri_data_t functions */ + +static tri_data_t * tri_data_new (GtsTriangle * t) +{ + tri_data_t * td; + + td = g_malloc (sizeof (tri_data_t)); + td->t = t; + td->used = FALSE; + td->neighbors = gts_triangle_neighbors (t); + td->pos = NULL; + + return td; +} + +static void tri_data_destroy (tri_data_t * td) +{ + if (!td) + return; + g_slist_free (td->neighbors); + g_free (td); +} + +static guint tri_data_num_unused_neighbors2 (const tri_data_t * td, + const map_t * map) +{ + GHashTable *h; + guint n; + + g_assert (td); + g_assert (map); + h = tri_data_unused_neighbors2 (td, map); + n = g_hash_table_size (h); + g_hash_table_destroy (h); + return n; +} + +static void copy_key_to_array (gpointer key, + gpointer value, + gpointer user_data) +{ + GtsTriangle * t = key; + GtsTriangle *** p = user_data; + + (void) value; + g_assert (t); + g_assert (p && *p); + **p = t; + (*p)++; +} + +static gboolean are_neighbors_unique (GHashTable *h) +{ + GtsTriangle ** a; + GtsTriangle ** p; + gint i, j, n; /* guint won't work if n == 0 */ + + g_assert (h); + n = g_hash_table_size (h); +#ifdef DEBUG + if (n > 9) + g_warning ("triangle has %d 2-level neighbors", n); +#endif /* DEBUG */ + a = g_malloc(n*sizeof (GtsTriangle *)); + p = a; + g_hash_table_foreach (h, copy_key_to_array, &p); + for (i = 0; i < n - 1; i++) { + g_assert (a[i]); + for (j = i + 1; j < n; j++) { + g_assert (a[j]); + if (a[i] == a[j]) { + g_free (a); + return FALSE; + } + } + } + g_free (a); + return TRUE; +} + +static GHashTable * tri_data_unused_neighbors2 (const tri_data_t * td, + const map_t * map) +{ + GHashTable * h = g_hash_table_new (NULL, NULL); + GSList * li; + + g_assert (td); + g_assert (map); + for (li = td->neighbors; li != NULL; li = li->next) { + GtsTriangle * t2 = li->data; + tri_data_t * td2 = map_lookup (map, t2); + GSList * lj; + + g_assert (td2); + if (!td2->used) { + g_hash_table_insert (h, t2, td2); + for (lj = td2->neighbors; lj != NULL; lj = lj->next) { + GtsTriangle * t3 = lj->data; + tri_data_t * td3 = map_lookup (map, t3); + + g_assert (td3); + if (td3 != td && !td3->used) + g_hash_table_insert (h, t3, td3); + } + } + } + g_assert (are_neighbors_unique (h)); + return h; +} + +#if PRINT_HEAP_ELEMENTS +static void tri_data_print (const tri_data_t * td, FILE * fp) +{ + g_assert (td); + g_assert (fp); + fprintf(fp, "td=%p t=%p used=%d pos=%p key=%f\n", + td, td->t, td->used, td->pos, + td->pos ? td->pos->key : -1.0); +} +#endif /* PRINT_HEAP_ELEMENTS */ + +/* heap_t functions */ + +static gdouble triangle_priority (gpointer item, gpointer data) +{ + GtsTriangle * t = item; + map_t * map = data; + tri_data_t * td; + gdouble k; + + g_assert (t); + g_assert (map); + td = map_lookup (map, t); + g_assert (td); + k = tri_data_num_unused_neighbors2 (td, map); + return k; +} + +#if PRINT_HEAP_ELEMENTS +static void print_heap_element (gpointer data, gpointer user_data) +{ + GtsTriangle * t = data; + map_t * map = user_data; + tri_data_t * td; + + g_assert (t); + g_assert (map); + td = map_lookup (map, t); + g_assert (td); + g_assert (!td->used); + g_assert (td->pos); + tri_data_print (td, stderr); +} +#endif /* PRINT_HEAP_ELEMENTS */ + +static void insert_entry_into_heap (gpointer key, + gpointer value, + gpointer user_data) +{ + GtsTriangle * t = key; + tri_data_t * td = value; + GtsEHeap * heap = user_data; + + g_assert (!td->pos); + td->pos = gts_eheap_insert (heap, t); + g_assert (td->pos); +} + +static heap_t * heap_new (GtsSurface *s) +{ + heap_t * heap; + + g_assert (s); + heap = g_malloc (sizeof (heap_t)); + heap->map = map_new (s); + heap->heap = gts_eheap_new (triangle_priority, heap->map); + g_hash_table_foreach (heap->map->ht, + insert_entry_into_heap, + heap->heap); +#if PRINT_HEAP_ELEMENTS + gts_eheap_foreach (heap->heap, print_heap_element, heap->map); +#endif /* PRINT_HEAP_ELEMENTS */ + return heap; +} + +static void heap_destroy (heap_t * heap) +{ + if (!heap) + return; + map_destroy (heap->map); + gts_eheap_destroy (heap->heap); + g_free (heap); +} + +static gboolean heap_is_empty (const heap_t * heap) +{ + g_assert (heap); + g_assert (heap->heap); + return gts_eheap_size (heap->heap) == 0; +} + +typedef struct { + const heap_t * heap; + double min_key; +} min_key_t; + +static GtsTriangle * heap_top (const heap_t * heap) +{ + GtsTriangle * t; + + g_assert (heap); + g_assert (heap->heap); + t = gts_eheap_top (heap->heap, NULL); + return t; +} + +static void decrease_key (gpointer key, gpointer value, gpointer user_data) +{ + GtsTriangle * t = key; + tri_data_t * td = value; + heap_t *heap = user_data; + gdouble k; + + (void) t; + g_assert (heap); + g_assert (heap->map); + g_assert (heap->heap); + g_assert (td); + g_assert (!td->used); + g_assert (td->pos); + + k = tri_data_num_unused_neighbors2 (td, heap->map); + g_assert (k <= td->pos->key); +#ifdef DEBUG + if (k == td->pos->key) + g_warning ("same key: %f\n", k); +#endif /* DEBUG */ + if (k != td->pos->key) { + g_assert (k < td->pos->key); + g_assert (k >= 0.0); + gts_eheap_decrease_key (heap->heap, td->pos, k); + } +} + +static void heap_remove (heap_t * heap, GtsTriangle * t) +{ + tri_data_t * td; + GHashTable * h; + + g_assert (heap); + g_assert (t); + td = map_lookup (heap->map, t); + g_assert (td); + g_assert (!td->used); + g_assert (td->pos); + td->used = TRUE; + gts_eheap_remove (heap->heap, td->pos); + td->pos = NULL; + + /* fprintf(stderr, "td: %p\n", td); */ + h = tri_data_unused_neighbors2 (td, heap->map); + g_hash_table_foreach (h, decrease_key, heap); + g_hash_table_destroy (h); +} + +/* map_t functions */ + +static gint create_map_entry (gpointer item, gpointer data) +{ + GtsTriangle * t = item; + GHashTable * ht = data; + tri_data_t * td; + + g_assert (t); + g_assert (ht); + td = tri_data_new (t); + g_hash_table_insert (ht, t, td); + return 0; +} + +static void free_map_entry (gpointer key, gpointer value, gpointer user_data) +{ + GtsTriangle * t = key; + tri_data_t * td = value; + + (void) user_data; + g_assert (t); + g_assert (td); + g_assert (td->t == t); + tri_data_destroy (td); +} + +static map_t * map_new (GtsSurface * s) +{ + map_t * map; + + map = g_malloc (sizeof (map_t)); + map->ht = g_hash_table_new (NULL, NULL); + gts_surface_foreach_face (s, create_map_entry, map->ht); + return map; +} + +static void map_destroy (map_t * map) +{ + if (!map) + return; + g_hash_table_foreach (map->ht, free_map_entry, NULL); + g_hash_table_destroy (map->ht); + g_free (map); +} + +static tri_data_t * map_lookup (const map_t * map, GtsTriangle * t) +{ + tri_data_t * td; + + g_assert (map); + g_assert (map->ht); + g_assert (t); + td = g_hash_table_lookup (map->ht, t); + g_assert (td); + g_assert (td->t == t); + return td; +} + +/* other helper functions */ + +static GtsTriangle * find_min_neighbor (heap_t * heap, GtsTriangle * t) +{ + GtsTriangle * min_neighbor = NULL; + gdouble min_key = G_MAXDOUBLE; + tri_data_t * td; + GSList * li; + + g_assert (heap); + g_assert (t); + + td = map_lookup (heap->map, t); + for (li = td->neighbors; li != NULL; li = li->next) { + GtsTriangle * t2 = li->data; + tri_data_t * td2 = map_lookup (heap->map, t2); + gdouble k; + + g_assert (td2); + if (td2->used) + continue; + g_assert (td2->pos); + k = td2->pos->key; + if (k < min_key) { + min_key = k; + min_neighbor = t2; + } + } + return min_neighbor; +} + +static GtsTriangle * find_neighbor_forward (heap_t * heap, + GtsTriangle * t, + GtsVertex ** v1, + GtsVertex ** v2, + GtsVertex ** v3, + gboolean left_turn) +{ + GtsTriangle * neighbor = NULL; + tri_data_t * td; + GSList * li; + + g_assert (heap); + g_assert (t); + g_assert (v1 && v2 && v3); + g_assert (vertices_are_unique (*v1, *v2, *v3)); + + td = map_lookup (heap->map, t); + g_assert (td); + for (li = td->neighbors; li && !neighbor; li = li->next) { + GtsTriangle * t2 = li->data; + tri_data_t * td2 = map_lookup (heap->map, t2); + GtsVertex * v4, * v5, * v6; + + g_assert (td2); + if (t2 == t || td2->used) + continue; + gts_triangle_vertices (t2, &v4, &v5, &v6); + if (left_turn) { + if (!vertices_match (*v1, *v3, NULL, &v4, &v5, &v6)) + continue; + } else { + if (!vertices_match (*v3, *v2, NULL, &v4, &v5, &v6)) + continue; + } + neighbor = t2; + *v1 = v4; + *v2 = v5; + *v3 = v6; + } + return neighbor; +} + +static GtsTriangle * find_neighbor_backward (heap_t * heap, + GtsTriangle * t, + GtsVertex ** v1, + GtsVertex ** v2, + GtsVertex ** v3, + gboolean left_turn) +{ + GtsTriangle * neighbor = NULL; + tri_data_t * td; + GSList * li; + + g_assert (heap); + g_assert (t); + g_assert (v1 && v2 && v3); + g_assert (vertices_are_unique (*v1, *v2, *v3)); + + td = map_lookup (heap->map, t); + g_assert (td); + for (li = td->neighbors; li && !neighbor; li = li->next) { + GtsTriangle * t2 = li->data; + tri_data_t * td2 = map_lookup (heap->map, t2); + GtsVertex * v4, * v5, * v6; + + g_assert (td2); + if (t2 == t || td2->used) + continue; + gts_triangle_vertices (t2, &v4, &v5, &v6); + if (left_turn) { + if (!vertices_match (NULL, *v2, *v1, &v4, &v5, &v6)) + continue; + } else if (!vertices_match(*v1, NULL, *v2, &v4, &v5, &v6)) + continue; + neighbor = t2; + *v1 = v4; + *v2 = v5; + *v3 = v6; + } + return neighbor; +} + +static GSList * grow_strip_forward (heap_t * heap, + GSList * strip, + GtsTriangle * t, + GtsVertex * v1, + GtsVertex * v2, + GtsVertex * v3) +{ + gboolean left_turn; + + g_assert (heap); + g_assert (g_slist_length(strip) == 2); + g_assert (t); + g_assert (v1 && v2 && v3); + g_assert (vertices_are_unique (v1, v2, v3)); + + left_turn = TRUE; + while ((t = find_neighbor_forward (heap, t, &v1, &v2, &v3, + left_turn)) != NULL) { + heap_remove (heap, t); + strip = g_slist_prepend (strip, t); + left_turn = !left_turn; + } + return strip; +} + +static GSList * grow_strip_backward (heap_t * heap, + GSList * strip, + GtsTriangle * t, + GtsVertex * v1, + GtsVertex * v2, + GtsVertex * v3) +{ + /* we have to make sure we add an even number of triangles */ + GtsTriangle * t2; + + g_assert (heap); + g_assert (g_slist_length(strip) >= 2); + g_assert (t); + g_assert (v1 && v2 && v3); + g_assert (vertices_are_unique (v1, v2, v3)); + + while ((t2 = find_neighbor_backward (heap, t, &v1, &v2, &v3, + FALSE)) != NULL + && (t = find_neighbor_backward (heap, t2, &v1, &v2, &v3, + TRUE)) != NULL) { + heap_remove (heap, t2); + heap_remove (heap, t); + strip = g_slist_prepend (strip, t2); + strip = g_slist_prepend (strip, t); + } + return strip; +} + +static gboolean find_right_turn (GtsVertex ** v1, + GtsVertex ** v2, + GtsVertex ** v3, + GtsVertex ** v4, + GtsVertex ** v5, + GtsVertex ** v6) +{ + GtsVertex * v; + + g_assert (v1 && v2 && v3); + g_assert (v4 && v5 && v6); + g_assert (vertices_are_unique (*v1, *v2, *v3)); + g_assert (vertices_are_unique (*v4, *v5, *v6)); + g_assert (num_shared_vertices (*v1, *v2, *v3, *v4, *v5, *v6) == 2); + + v = non_shared_vertex1 (*v1, *v2, *v3, *v4, *v5, *v6); + match_vertex (v, v1, v2, v3); + match_vertex (*v3, v4, v5, v6); + + g_assert (v1 && v2 && v3); + g_assert (v4 && v5 && v6); + g_assert (*v4 == *v3); + + if (*v5 == *v2) { + g_assert (vertices_are_unique (*v1, *v2, *v3)); + g_assert (vertices_are_unique (*v4, *v5, *v6)); + g_assert (num_shared_vertices (*v1, *v2, *v3, + *v4, *v5, *v6) == 2); + return TRUE; + } else { +#ifdef DEBUG + g_warning ("couldn't find a right turn"); +#endif /* DEBUG */ + return FALSE; + } +} + +/** + * gts_surface_strip: + * @s: a #GtsSurface. + * + * Decompose @s into triangle strips for fast-rendering. + * + * Returns: a list of triangle strips containing all the triangles of @s. + * A triangle strip is itself a list of successive triangles having one edge + * in common. + */ +GSList * gts_surface_strip (GtsSurface *s) +{ + GSList * strips = NULL; + heap_t * heap; + + g_return_val_if_fail (s != NULL, NULL); + + heap = heap_new (s); + while (!heap_is_empty (heap)) { + GtsTriangle * t1, * t2; + GtsVertex * v1, * v2, * v3, * v4, * v5, * v6; + GSList * strip = NULL; + + /* remove heap top */ + t1 = heap_top (heap); + g_assert (t1); + heap_remove (heap, t1); + + /* start a new strip */ + strip = g_slist_prepend (strip, t1); + + /* find second triangle */ + t2 = find_min_neighbor (heap, t1); + if (t2) { + g_assert (t2 != t1); + + /* find right turn */ + gts_triangle_vertices (t1, &v1, &v2, &v3); + gts_triangle_vertices (t2, &v4, &v5, &v6); + if (find_right_turn (&v1, &v2, &v3, &v4, &v5, &v6)) { + heap_remove (heap, t2); + strip = g_slist_prepend (strip, t2); + + /* grow strip forward */ + strip = grow_strip_forward (heap, strip, t2, v4, v5, v6); + + strip = g_slist_reverse (strip); + + /* grow strip backward */ + strip = grow_strip_backward (heap, strip, t1, v1, v2, v3); + } + } + strips = g_slist_prepend (strips, strip); + } + strips = g_slist_reverse (strips); + heap_destroy (heap); + + return strips; +} Index: work/obsolete/toporouter/src_3rd/gts/surface.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/surface.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/surface.c (revision 6803) @@ -0,0 +1,2743 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include "gts.h" + +#include "gts-private.h" + +static void destroy_foreach_face (GtsFace * f, GtsSurface * s) +{ + f->surfaces = g_slist_remove (f->surfaces, s); + if (!GTS_OBJECT_DESTROYED (f) && + !gts_allow_floating_faces && f->surfaces == NULL) + gts_object_destroy (GTS_OBJECT (f)); +} + +static void surface_destroy (GtsObject * object) +{ + GtsSurface * surface = GTS_SURFACE (object); + + gts_surface_foreach_face (surface, (GtsFunc) destroy_foreach_face, surface); +#ifdef USE_SURFACE_BTREE + g_tree_destroy (surface->faces); +#else /* not USE_SURFACE_BTREE */ + g_hash_table_destroy (surface->faces); +#endif /* not USE_SURFACE_BTREE */ + + (* GTS_OBJECT_CLASS (gts_surface_class ())->parent_class->destroy) (object); +} + +static void surface_write (GtsObject * object, FILE * fptr) +{ + fprintf (fptr, " %s %s %s %s", + object->klass->info.name, + GTS_OBJECT_CLASS (GTS_SURFACE (object)->face_class)->info.name, + GTS_OBJECT_CLASS (GTS_SURFACE (object)->edge_class)->info.name, + GTS_POINT_CLASS (GTS_SURFACE (object)->vertex_class)->binary ? + "GtsVertexBinary" : + GTS_OBJECT_CLASS (GTS_SURFACE (object)->vertex_class)->info.name); +} + +static void surface_class_init (GtsSurfaceClass * klass) +{ + GTS_OBJECT_CLASS (klass)->destroy = surface_destroy; + GTS_OBJECT_CLASS (klass)->write = surface_write; + klass->add_face = NULL; + klass->remove_face = NULL; +} + +#ifdef USE_SURFACE_BTREE +static gint compare_pointers (gconstpointer a, gconstpointer b) +{ + if (GPOINTER_TO_UINT (a) < GPOINTER_TO_UINT (b)) + return -1; + if (GPOINTER_TO_UINT (a) > GPOINTER_TO_UINT (b)) + return 1; + return 0; +} +#endif /* USE_SURFACE_BTREE */ + +static void surface_init (GtsSurface * surface) +{ +#ifdef USE_SURFACE_BTREE + surface->faces = g_tree_new (compare_pointers); +#else /* not USE_SURFACE_BTREE */ + surface->faces = g_hash_table_new (NULL, NULL); +#endif /* not USE_SURFACE_BTREE */ + surface->vertex_class = gts_vertex_class (); + surface->edge_class = gts_edge_class (); + surface->face_class = gts_face_class (); + surface->keep_faces = FALSE; +} + +/** + * gts_surface_class: + * + * Returns: the #GtsSurfaceClass. + */ +GtsSurfaceClass * gts_surface_class (void) +{ + static GtsSurfaceClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo surface_info = { + "GtsSurface", + sizeof (GtsSurface), + sizeof (GtsSurfaceClass), + (GtsObjectClassInitFunc) surface_class_init, + (GtsObjectInitFunc) surface_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (gts_object_class (), &surface_info); + } + + return klass; +} + +/** + * gts_surface_new: + * @klass: a #GtsSurfaceClass. + * @face_class: a #GtsFaceClass. + * @edge_class: a #GtsEdgeClass. + * @vertex_class: a #GtsVertexClass. + * + * Returns: a new empty #GtsSurface. + */ +GtsSurface * gts_surface_new (GtsSurfaceClass * klass, + GtsFaceClass * face_class, + GtsEdgeClass * edge_class, + GtsVertexClass * vertex_class) +{ + GtsSurface * s; + + s = GTS_SURFACE (gts_object_new (GTS_OBJECT_CLASS (klass))); + s->vertex_class = vertex_class; + s->edge_class = edge_class; + s->face_class = face_class; + + return s; +} + +/** + * gts_surface_add_face: + * @s: a #GtsSurface. + * @f: a #GtsFace. + * + * Adds face @f to surface @s. + */ +void gts_surface_add_face (GtsSurface * s, GtsFace * f) +{ + g_return_if_fail (s != NULL); + g_return_if_fail (f != NULL); + + g_assert (s->keep_faces == FALSE); + +#ifdef USE_SURFACE_BTREE + if (!g_tree_lookup (s->faces, f)) { + f->surfaces = g_slist_prepend (f->surfaces, s); + g_tree_insert (s->faces, f, f); + } +#else /* not USE_SURFACE_BTREE */ + if (!g_hash_table_lookup (s->faces, f)) { + f->surfaces = g_slist_prepend (f->surfaces, s); + g_hash_table_insert (s->faces, f, f); + } +#endif /* not USE_SURFACE_BTREE */ + + if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->add_face) + (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->add_face) (s, f); +} + +/** + * gts_surface_remove_face: + * @s: a #GtsSurface. + * @f: a #GtsFace. + * + * Removes face @f from surface @s. + */ +void gts_surface_remove_face (GtsSurface * s, + GtsFace * f) +{ + g_return_if_fail (s != NULL); + g_return_if_fail (f != NULL); + + g_assert (s->keep_faces == FALSE); + +#ifdef USE_SURFACE_BTREE + g_tree_remove (s->faces, f); +#else /* not USE_SURFACE_BTREE */ + g_hash_table_remove (s->faces, f); +#endif /* not USE_SURFACE_BTREE */ + + f->surfaces = g_slist_remove (f->surfaces, s); + + if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face) + (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face) (s, f); + + if (!GTS_OBJECT_DESTROYED (f) && + !gts_allow_floating_faces && + f->surfaces == NULL) + gts_object_destroy (GTS_OBJECT (f)); +} + +/** + * gts_surface_read: + * @surface: a #GtsSurface. + * @f: a #GtsFile. + * + * Add to @surface the data read from @f. The format of the file pointed to + * by @f is as described in gts_surface_write(). + * + * Returns: 0 if successful or the line number at which the parsing + * stopped in case of error (in which case the @error field of @f is + * set to a description of the error which occured). + */ +/* Update split.c/surface_read() if modifying this function */ +guint gts_surface_read (GtsSurface * surface, GtsFile * f) +{ + GtsVertex ** vertices; + GtsEdge ** edges; + guint n, nv, ne, nf; + + g_return_val_if_fail (surface != NULL, 1); + g_return_val_if_fail (f != NULL, 1); + + if (f->type != GTS_INT) { + gts_file_error (f, "expecting an integer (number of vertices)"); + return f->line; + } + nv = atoi (f->token->str); + + gts_file_next_token (f); + if (f->type != GTS_INT) { + gts_file_error (f, "expecting an integer (number of edges)"); + return f->line; + } + ne = atoi (f->token->str); + + gts_file_next_token (f); + if (f->type != GTS_INT) { + gts_file_error (f, "expecting an integer (number of faces)"); + return f->line; + } + nf = atoi (f->token->str); + + gts_file_next_token (f); + if (f->type == GTS_STRING) { + if (f->type != GTS_STRING) { + gts_file_error (f, "expecting a string (GtsSurfaceClass)"); + return f->line; + } + gts_file_next_token (f); + if (f->type != GTS_STRING) { + gts_file_error (f, "expecting a string (GtsFaceClass)"); + return f->line; + } + gts_file_next_token (f); + if (f->type != GTS_STRING) { + gts_file_error (f, "expecting a string (GtsEdgeClass)"); + return f->line; + } + gts_file_next_token (f); + if (f->type != GTS_STRING) { + gts_file_error (f, "expecting a string (GtsVertexClass)"); + return f->line; + } + if (!strcmp (f->token->str, "GtsVertexBinary")) + GTS_POINT_CLASS (surface->vertex_class)->binary = TRUE; + else { + GTS_POINT_CLASS (surface->vertex_class)->binary = FALSE; + gts_file_first_token_after (f, '\n'); + } + } + else + gts_file_first_token_after (f, '\n'); + + if (nf <= 0) + return 0; + + /* allocate nv + 1 just in case nv == 0 */ + vertices = g_malloc ((nv + 1)*sizeof (GtsVertex *)); + edges = g_malloc ((ne + 1)*sizeof (GtsEdge *)); + + n = 0; + while (n < nv && f->type != GTS_ERROR) { + GtsObject * new_vertex = + gts_object_new (GTS_OBJECT_CLASS (surface->vertex_class)); + + (* GTS_OBJECT_CLASS (surface->vertex_class)->read) (&new_vertex, f); + if (f->type != GTS_ERROR) { + if (!GTS_POINT_CLASS (surface->vertex_class)->binary) + gts_file_first_token_after (f, '\n'); + vertices[n++] = GTS_VERTEX (new_vertex); + } + else + gts_object_destroy (new_vertex); + } + if (f->type == GTS_ERROR) + nv = n; + if (GTS_POINT_CLASS (surface->vertex_class)->binary) + gts_file_first_token_after (f, '\n'); + + n = 0; + while (n < ne && f->type != GTS_ERROR) { + guint p1, p2; + + if (f->type != GTS_INT) + gts_file_error (f, "expecting an integer (first vertex index)"); + else { + p1 = atoi (f->token->str); + if (p1 == 0 || p1 > nv) + gts_file_error (f, "vertex index `%d' is out of range `[1,%d]'", + p1, nv); + else { + gts_file_next_token (f); + if (f->type != GTS_INT) + gts_file_error (f, "expecting an integer (second vertex index)"); + else { + p2 = atoi (f->token->str); + if (p2 == 0 || p2 > nv) + gts_file_error (f, "vertex index `%d' is out of range `[1,%d]'", + p2, nv); + else { + GtsEdge * new_edge = + gts_edge_new (surface->edge_class, + vertices[p1 - 1], vertices[p2 - 1]); + + gts_file_next_token (f); + if (f->type != '\n') + if (GTS_OBJECT_CLASS (surface->edge_class)->read) + (*GTS_OBJECT_CLASS (surface->edge_class)->read) + ((GtsObject **) &new_edge, f); + gts_file_first_token_after (f, '\n'); + edges[n++] = new_edge; + } + } + } + } + } + if (f->type == GTS_ERROR) + ne = n; + + n = 0; + while (n < nf && f->type != GTS_ERROR) { + guint s1, s2, s3; + + if (f->type != GTS_INT) + gts_file_error (f, "expecting an integer (first edge index)"); + else { + s1 = atoi (f->token->str); + if (s1 == 0 || s1 > ne) + gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", + s1, ne); + else { + gts_file_next_token (f); + if (f->type != GTS_INT) + gts_file_error (f, "expecting an integer (second edge index)"); + else { + s2 = atoi (f->token->str); + if (s2 == 0 || s2 > ne) + gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", + s2, ne); + else { + gts_file_next_token (f); + if (f->type != GTS_INT) + gts_file_error (f, "expecting an integer (third edge index)"); + else { + s3 = atoi (f->token->str); + if (s3 == 0 || s3 > ne) + gts_file_error (f, "edge index `%d' is out of range `[1,%d]'", + s3, ne); + else { + GtsFace * new_face = gts_face_new (surface->face_class, + edges[s1 - 1], + edges[s2 - 1], + edges[s3 - 1]); + + gts_file_next_token (f); + if (f->type != '\n') + if (GTS_OBJECT_CLASS (surface->face_class)->read) + (*GTS_OBJECT_CLASS (surface->face_class)->read) + ((GtsObject **) &new_face, f); + gts_file_first_token_after (f, '\n'); + gts_surface_add_face (surface, new_face); + n++; + } + } + } + } + } + } + } + + if (f->type == GTS_ERROR) { + gts_allow_floating_vertices = TRUE; + while (nv) + gts_object_destroy (GTS_OBJECT (vertices[nv-- - 1])); + gts_allow_floating_vertices = FALSE; + } + + g_free (vertices); + g_free (edges); + + if (f->type == GTS_ERROR) + return f->line; + return 0; +} + +static void sum_area (GtsFace * f, gdouble * area) { + *area += gts_triangle_area (GTS_TRIANGLE (f)); +} + +/** + * gts_surface_area: + * @s: a #GtsSurface. + * + * Returns: the area of @s obtained as the sum of the signed areas of its + * faces. + */ +gdouble gts_surface_area (GtsSurface * s) +{ + gdouble area = 0.0; + gts_surface_foreach_face (s, (GtsFunc)sum_area, &area); + return area; +} + +/** + * gts_range_init: + * @r: a #GtsRange. + * + * Initializes a #GtsRange. + */ +void gts_range_init (GtsRange * r) +{ + g_return_if_fail (r != NULL); + + r->max = - G_MAXDOUBLE; + r->min = G_MAXDOUBLE; + r->sum = r->sum2 = 0.0; + r->n = 0; +} + +/** + * gts_range_reset: + * @r: a #GtsRange. + * + * Sets all the fields of @r to 0. + */ +void gts_range_reset (GtsRange * r) +{ + g_return_if_fail (r != NULL); + + r->max = 0.0; + r->min = 0.0; + r->sum = r->sum2 = 0.0; + r->n = 0; +} + +/** + * gts_range_add_value: + * @r: a #GtsRange. + * @val: a value to add to @r. + * + * Adds @val to @r. + */ +void gts_range_add_value (GtsRange * r, gdouble val) +{ + g_return_if_fail (r != NULL); + + if (val < r->min) r->min = val; + if (val > r->max) r->max = val; + r->sum += val; + r->sum2 += val*val; + r->n++; +} + +/** + * gts_range_update: + * @r: a #GtsRange. + * + * Updates the fields of @r. + */ +void gts_range_update (GtsRange * r) +{ + g_return_if_fail (r != NULL); + + if (r->n > 0) { + if (r->sum2 - r->sum*r->sum/(gdouble) r->n >= 0.) + r->stddev = sqrt ((r->sum2 - r->sum*r->sum/(gdouble) r->n) + /(gdouble) r->n); + else + r->stddev = 0.; + r->mean = r->sum/(gdouble) r->n; + } + else + r->min = r->max = r->mean = r->stddev = 0.; +} + +/** + * gts_range_print: + * @r: a #GtsRange. + * @fptr: a file pointer. + * + * Writes a text representation of @r in @fptr. + */ +void gts_range_print (GtsRange * r, FILE * fptr) +{ + g_return_if_fail (r != NULL); + g_return_if_fail (fptr != NULL); + fprintf (fptr, "min: %g mean: %g | %g max: %g", + r->min, r->mean, r->stddev, r->max); +} + +static void stats_foreach_vertex (GtsVertex * v, GtsSurfaceStats * stats) +{ + GSList * i = v->segments; + guint nedges = 0; + + while (i) { + if (GTS_IS_EDGE (i->data) && + gts_edge_has_parent_surface (i->data, stats->parent)) + nedges++; + i = i->next; + } + gts_range_add_value (&stats->edges_per_vertex, nedges); +} + +static void stats_foreach_edge (GtsEdge * e, GtsSurfaceStats * stats) +{ + guint nt = gts_edge_face_number (e, stats->parent); + + if (gts_segment_is_duplicate (GTS_SEGMENT (e))) + stats->n_duplicate_edges++; + if (nt == 1) + stats->n_boundary_edges++; + else if (nt > 2) + stats->n_non_manifold_edges++; + gts_range_add_value (&stats->faces_per_edge, nt); +} + +static void stats_foreach_face (GtsTriangle * t, GtsSurfaceStats * stats) +{ + if (!gts_face_is_compatible (GTS_FACE (t), stats->parent)) + stats->n_incompatible_faces++; + if (gts_triangle_is_duplicate (t)) + stats->n_duplicate_faces++; + stats->n_faces++; +} + +/** + * gts_surface_stats: + * @s: a #GtsSurface. + * @stats: a #GtsSurfaceStats. + * + * Fills @stats with the statistics relevant to surface @s. + */ +void gts_surface_stats (GtsSurface * s, GtsSurfaceStats * stats) +{ + g_return_if_fail (s != NULL); + g_return_if_fail (stats != NULL); + + stats->parent = s; + stats->n_faces = 0; + stats->n_incompatible_faces = 0; + stats->n_duplicate_faces = 0; + stats->n_duplicate_edges = 0; + stats->n_boundary_edges = 0; + stats->n_non_manifold_edges = 0; + gts_range_init (&stats->edges_per_vertex); + gts_range_init (&stats->faces_per_edge); + + gts_surface_foreach_vertex (s, (GtsFunc) stats_foreach_vertex, stats); + gts_surface_foreach_edge (s, (GtsFunc) stats_foreach_edge, stats); + gts_surface_foreach_face (s, (GtsFunc) stats_foreach_face, stats); + + gts_range_update (&stats->edges_per_vertex); + gts_range_update (&stats->faces_per_edge); +} + +static void quality_foreach_edge (GtsSegment * s, + GtsSurfaceQualityStats * stats) +{ + GSList * i = GTS_EDGE (s)->triangles; + + gts_range_add_value (&stats->edge_length, + gts_point_distance (GTS_POINT (s->v1), + GTS_POINT (s->v2))); + while (i) { + GSList * j = i->next; + while (j) { + gts_range_add_value (&stats->edge_angle, + fabs (gts_triangles_angle (i->data, j->data))); + j = j->next; + } + i = i->next; + } +} + +static void quality_foreach_face (GtsTriangle * t, + GtsSurfaceQualityStats * stats) +{ + gts_range_add_value (&stats->face_quality, gts_triangle_quality (t)); + gts_range_add_value (&stats->face_area, gts_triangle_area (t)); +} + +/** + * gts_surface_quality_stats: + * @s: a #GtsSurface. + * @stats: a #GtsSurfaceQualityStats. + * + * Fills @stats with quality statistics relevant to surface @s. + */ +void gts_surface_quality_stats (GtsSurface * s, GtsSurfaceQualityStats * stats) +{ + g_return_if_fail (s != NULL); + g_return_if_fail (stats != NULL); + + stats->parent = s; + gts_range_init (&stats->face_quality); + gts_range_init (&stats->face_area); + gts_range_init (&stats->edge_length); + gts_range_init (&stats->edge_angle); + + gts_surface_foreach_edge (s, (GtsFunc) quality_foreach_edge, stats); + gts_surface_foreach_face (s, (GtsFunc) quality_foreach_face, stats); + + gts_range_update (&stats->face_quality); + gts_range_update (&stats->face_area); + gts_range_update (&stats->edge_length); + gts_range_update (&stats->edge_angle); +} + +/** + * gts_surface_print_stats: + * @s: a #GtsSurface. + * @fptr: a file pointer. + * + * Writes in the file pointed to by @fptr the statistics for surface @s. + */ +void gts_surface_print_stats (GtsSurface * s, FILE * fptr) +{ + GtsSurfaceStats stats; + GtsSurfaceQualityStats qstats; + + g_return_if_fail (s != NULL); + g_return_if_fail (fptr != NULL); + + gts_surface_stats (s, &stats); + gts_surface_quality_stats (s, &qstats); + + fprintf (fptr, + "# vertices: %u edges: %u faces: %u\n" + "# Connectivity statistics\n" + "# incompatible faces: %u\n" + "# duplicate faces: %u\n" + "# boundary edges: %u\n" + "# duplicate edges: %u\n" + "# non-manifold edges: %u\n", + stats.edges_per_vertex.n, + stats.faces_per_edge.n, + stats.n_faces, + stats.n_incompatible_faces, + stats.n_duplicate_faces, + stats.n_boundary_edges, + stats.n_duplicate_edges, + stats.n_non_manifold_edges); + fputs ("# edges per vertex: ", fptr); + gts_range_print (&stats.edges_per_vertex, fptr); + fputs ("\n# faces per edge: ", fptr); + gts_range_print (&stats.faces_per_edge, fptr); + fputs ("\n# Geometric statistics\n# face quality: ", fptr); + gts_range_print (&qstats.face_quality, fptr); + fputs ("\n# face area : ", fptr); + gts_range_print (&qstats.face_area, fptr); + fputs ("\n# edge length : ", fptr); + gts_range_print (&qstats.edge_length, fptr); + fputc ('\n', fptr); +} + +static void write_vertex (GtsPoint * p, gpointer * data) +{ + (*GTS_OBJECT (p)->klass->write) (GTS_OBJECT (p), (FILE *) data[0]); + if (!GTS_POINT_CLASS (GTS_OBJECT (p)->klass)->binary) + fputc ('\n', (FILE *) data[0]); + g_hash_table_insert (data[2], p, + GUINT_TO_POINTER (++(*((guint *) data[1])))); +} + +static void write_edge (GtsSegment * s, gpointer * data) +{ + fprintf ((FILE *) data[0], "%u %u", + GPOINTER_TO_UINT (g_hash_table_lookup (data[2], s->v1)), + GPOINTER_TO_UINT (g_hash_table_lookup (data[2], s->v2))); + if (GTS_OBJECT (s)->klass->write) + (*GTS_OBJECT (s)->klass->write) (GTS_OBJECT (s), (FILE *) data[0]); + fputc ('\n', (FILE *) data[0]); + g_hash_table_insert (data[3], s, + GUINT_TO_POINTER (++(*((guint *) data[1])))); +} + +static void write_face (GtsTriangle * t, gpointer * data) +{ + fprintf (data[0], "%u %u %u", + GPOINTER_TO_UINT (g_hash_table_lookup (data[3], t->e1)), + GPOINTER_TO_UINT (g_hash_table_lookup (data[3], t->e2)), + GPOINTER_TO_UINT (g_hash_table_lookup (data[3], t->e3))); + if (GTS_OBJECT (t)->klass->write) + (*GTS_OBJECT (t)->klass->write) (GTS_OBJECT (t), data[0]); + fputc ('\n', data[0]); +} + +/** + * gts_surface_write: + * @s: a #GtsSurface. + * @fptr: a file pointer. + * + * Writes in the file @fptr an ASCII representation of @s. The file + * format is as follows. + * + * All the lines beginning with #GTS_COMMENTS are ignored. The first line + * contains three unsigned integers separated by spaces. The first + * integer is the number of vertices, nv, the second is the number of + * edges, ne and the third is the number of faces, nf. + * + * Follows nv lines containing the x, y and z coordinates of the + * vertices. Follows ne lines containing the two indices (starting + * from one) of the vertices of each edge. Follows nf lines containing + * the three ordered indices (also starting from one) of the edges of + * each face. + * + * The format described above is the least common denominator to all + * GTS files. Consistent with an object-oriented approach, the GTS + * file format is extensible. Each of the lines of the file can be + * extended with user-specific attributes accessible through the + * read() and write() virtual methods of each of the objects written + * (surface, vertices, edges or faces). When read with different + * object classes, these extra attributes are just ignored. + */ +void gts_surface_write (GtsSurface * s, FILE * fptr) +{ + guint n; + gpointer data[4]; + GHashTable * vindex, * eindex; + GtsSurfaceStats stats; + + g_return_if_fail (s != NULL); + g_return_if_fail (fptr != NULL); + + data[0] = fptr; + data[1] = &n; + data[2] = vindex = g_hash_table_new (NULL, NULL); + data[3] = eindex = g_hash_table_new (NULL, NULL); + + gts_surface_stats (s, &stats); + fprintf (fptr, "%u %u %u", + stats.edges_per_vertex.n, + stats.faces_per_edge.n, + stats.n_faces); + if (GTS_OBJECT (s)->klass->write) + (*GTS_OBJECT (s)->klass->write) (GTS_OBJECT (s), fptr); + fputc ('\n', fptr); + n = 0; + gts_surface_foreach_vertex (s, (GtsFunc) write_vertex, data); + n = 0; + if (GTS_POINT_CLASS (s->vertex_class)->binary) + fputc ('\n', fptr); + gts_surface_foreach_edge (s, (GtsFunc) write_edge, data); + gts_surface_foreach_face (s, (GtsFunc) write_face, data); + g_hash_table_destroy (vindex); + g_hash_table_destroy (eindex); +} + +static void write_vertex_oogl (GtsPoint * p, gpointer * data) +{ + FILE * fp = data[0]; + + fprintf (fp, "%g %g %g", p->x, p->y, p->z); + if (GTS_OBJECT (p)->klass->color) { + GtsColor c = (* GTS_OBJECT (p)->klass->color) (GTS_OBJECT (p)); + fprintf (fp, " %g %g %g 1.0\n", c.r, c.g, c.b); + } + else + fputc ('\n', fp); + GTS_OBJECT (p)->reserved = GUINT_TO_POINTER ((*((guint *) data[1]))++); +} + +static void write_face_oogl (GtsTriangle * t, FILE * fp) +{ + GtsVertex * v1, * v2, * v3; + gts_triangle_vertices (t, &v1, &v2, &v3); + fprintf (fp, "3 %u %u %u", + GPOINTER_TO_UINT (GTS_OBJECT (v1)->reserved), + GPOINTER_TO_UINT (GTS_OBJECT (v2)->reserved), + GPOINTER_TO_UINT (GTS_OBJECT (v3)->reserved)); + if (GTS_OBJECT (t)->klass->color) { + GtsColor c = (* GTS_OBJECT (t)->klass->color) (GTS_OBJECT (t)); + fprintf (fp, " %g %g %g\n", c.r, c.g, c.b); + } + else + fputc ('\n', fp); +} + +/** + * gts_surface_write_oogl: + * @s: a #GtsSurface. + * @fptr: a file pointer. + * + * Writes in the file @fptr an OOGL (Geomview) representation of @s. + */ +void gts_surface_write_oogl (GtsSurface * s, FILE * fptr) +{ + guint n = 0; + gpointer data[2]; + GtsSurfaceStats stats; + + g_return_if_fail (s != NULL); + g_return_if_fail (fptr != NULL); + + data[0] = fptr; + data[1] = &n; + + gts_surface_stats (s, &stats); + if (GTS_OBJECT_CLASS (s->vertex_class)->color) + fputs ("COFF ", fptr); + else + fputs ("OFF ", fptr); + fprintf (fptr, "%u %u %u\n", + stats.edges_per_vertex.n, + stats.n_faces, + stats.faces_per_edge.n); + gts_surface_foreach_vertex (s, (GtsFunc) write_vertex_oogl, data); + gts_surface_foreach_face (s, (GtsFunc) write_face_oogl, fptr); + gts_surface_foreach_vertex (s, (GtsFunc) gts_object_reset_reserved, NULL); +} + +static void write_vertex_vtk (GtsPoint * p, gpointer * data) +{ + FILE * fp = data[0]; + + fprintf (fp, "%g %g %g\n", p->x, p->y, p->z); + GTS_OBJECT (p)->reserved = GUINT_TO_POINTER ((*((guint *) data[1]))++); +} + +static void write_face_vtk (GtsTriangle * t, FILE * fp) +{ + GtsVertex * v1, * v2, * v3; + gts_triangle_vertices (t, &v1, &v2, &v3); + fprintf (fp, "3 %u %u %u\n", + GPOINTER_TO_UINT (GTS_OBJECT (v1)->reserved), + GPOINTER_TO_UINT (GTS_OBJECT (v2)->reserved), + GPOINTER_TO_UINT (GTS_OBJECT (v3)->reserved)); +} + +/** + * gts_surface_write_vtk: + * @s: a #GtsSurface. + * @fptr: a file pointer. + * + * Writes in the file @fptr a VTK representation of @s. + */ +void gts_surface_write_vtk (GtsSurface * s, FILE * fptr) +{ + guint n = 0; + gpointer data[2]; + GtsSurfaceStats stats; + + g_return_if_fail (s != NULL); + g_return_if_fail (fptr != NULL); + + data[0] = fptr; + data[1] = &n; + + gts_surface_stats (s, &stats); + fprintf (fptr, + "# vtk DataFile Version 2.0\n" + "Generated by GTS\n" + "ASCII\n" + "DATASET POLYDATA\n" + "POINTS %u float\n", + stats.edges_per_vertex.n); + gts_surface_foreach_vertex (s, (GtsFunc) write_vertex_vtk, data); + fprintf (fptr, + "POLYGONS %u %u\n", + stats.n_faces, stats.n_faces*4); + gts_surface_foreach_face (s, (GtsFunc) write_face_vtk, fptr); + gts_surface_foreach_vertex (s, (GtsFunc) gts_object_reset_reserved, NULL); +} + +static void write_edge_oogl_boundary (GtsSegment * s, gpointer * data) +{ + if (!gts_edge_is_boundary (GTS_EDGE (s), data[1])) + return; + + if (GTS_OBJECT (s)->klass->color) { + GtsColor c = (* GTS_OBJECT (s)->klass->color) (GTS_OBJECT (s)); + fprintf (data[0], "VECT 1 2 1 2 1 %g %g %g %g %g %g %g %g %g 1.\n", + GTS_POINT (s->v1)->x, GTS_POINT (s->v1)->y, GTS_POINT (s->v1)->z, + GTS_POINT (s->v2)->x, GTS_POINT (s->v2)->y, GTS_POINT (s->v2)->z, + c.r, c.g, c.b); + } + else + fprintf (data[0], "VECT 1 2 0 2 0 %g %g %g %g %g %g\n", + GTS_POINT (s->v1)->x, GTS_POINT (s->v1)->y, GTS_POINT (s->v1)->z, + GTS_POINT (s->v2)->x, GTS_POINT (s->v2)->y, GTS_POINT (s->v2)->z); +} + +/** + * gts_surface_write_oogl_boundary: + * @s: a #GtsSurface. + * @fptr: a file pointer. + * + * Writes in the file @fptr an OOGL (Geomview) representation of the + * boundary of @s. + */ +void gts_surface_write_oogl_boundary (GtsSurface * s, FILE * fptr) +{ + gpointer data[2]; + + g_return_if_fail (s != NULL); + g_return_if_fail (fptr != NULL); + + data[0] = fptr; + data[1] = s; + fputs ("LIST {\n", fptr); + gts_surface_foreach_edge (s, (GtsFunc) write_edge_oogl_boundary, data); + fputs ("}\n", fptr); +} + +#ifdef USE_SURFACE_BTREE +static gint vertex_foreach_face (GtsTriangle * t, + gpointer t_data, + gpointer * info) +#else /* not USE_SURFACE_BTREE */ +static void vertex_foreach_face (GtsTriangle * t, + gpointer t_data, + gpointer * info) +#endif /* not USE_SURFACE_BTREE */ +{ + GHashTable * hash = info[0]; + gpointer data = info[1]; + GtsFunc func = (GtsFunc) info[2]; + GtsSegment + * s1 = GTS_SEGMENT (t->e1); + + if (!g_hash_table_lookup (hash, s1->v1)) { + (*func) (s1->v1, data); + g_hash_table_insert (hash, s1->v1, GINT_TO_POINTER (-1)); + } + if (!g_hash_table_lookup (hash, s1->v2)) { + (*func) (s1->v2, data); + g_hash_table_insert (hash, s1->v2, GINT_TO_POINTER (-1)); + } + if (!g_hash_table_lookup (hash, gts_triangle_vertex (t))) { + (*func) (gts_triangle_vertex (t), data); + g_hash_table_insert (hash, gts_triangle_vertex (t), + GINT_TO_POINTER (-1)); + } +#ifdef USE_SURFACE_BTREE + return FALSE; +#endif /* USE_SURFACE_BTREE */ +} + +/** + * gts_surface_foreach_vertex: + * @s: a #GtsSurface. + * @func: a #GtsFunc. + * @data: user data to be passed to @func. + * + * Calls @func once for each vertex of @s. + */ +void gts_surface_foreach_vertex (GtsSurface * s, GtsFunc func, gpointer data) +{ + gpointer info[3]; + + g_return_if_fail (s != NULL); + g_return_if_fail (func != NULL); + + /* forbid removal of faces */ + s->keep_faces = TRUE; + info[0] = g_hash_table_new (NULL, NULL); + info[1] = data; + info[2] = func; +#ifdef USE_SURFACE_BTREE + g_tree_traverse (s->faces, (GTraverseFunc) vertex_foreach_face, G_IN_ORDER, + info); +#else /* not USE_SURFACE_BTREE */ + g_hash_table_foreach (s->faces, (GHFunc) vertex_foreach_face, info); +#endif /* not USE_SURFACE_BTREE */ + g_hash_table_destroy (info[0]); + /* allow removal of faces */ + s->keep_faces = FALSE; +} + +#ifdef USE_SURFACE_BTREE +static gint edge_foreach_face (GtsTriangle * t, + gpointer t_data, + gpointer * info) +#else /* not USE_SURFACE_BTREE */ +static void edge_foreach_face (GtsTriangle * t, + gpointer t_data, + gpointer * info) +#endif /* not USE_SURFACE_BTREE */ +{ + GHashTable * hash = info[0]; + gpointer data = info[1]; + GtsFunc func = (GtsFunc) info[2]; + + if (!g_hash_table_lookup (hash, t->e1)) { + (*func) (t->e1, data); + g_hash_table_insert (hash, t->e1, GINT_TO_POINTER (-1)); + } + if (!g_hash_table_lookup (hash, t->e2)) { + (*func) (t->e2, data); + g_hash_table_insert (hash, t->e2, GINT_TO_POINTER (-1)); + } + if (!g_hash_table_lookup (hash, t->e3)) { + (*func) (t->e3, data); + g_hash_table_insert (hash, t->e3, GINT_TO_POINTER (-1)); + } +#ifdef USE_SURFACE_BTREE + return FALSE; +#endif /* not USE_SURFACE_BTREE */ +} + +/** + * gts_surface_foreach_edge: + * @s: a #GtsSurface. + * @func: a #GtsFunc. + * @data: user data to be passed to @func. + * + * Calls @func once for each edge of @s. + */ +void gts_surface_foreach_edge (GtsSurface * s, GtsFunc func, gpointer data) +{ + gpointer info[3]; + + g_return_if_fail (s != NULL); + g_return_if_fail (func != NULL); + + /* forbid removal of faces */ + s->keep_faces = TRUE; + info[0] = g_hash_table_new (NULL, NULL); + info[1] = data; + info[2] = func; +#ifdef USE_SURFACE_BTREE + g_tree_traverse (s->faces, (GTraverseFunc) edge_foreach_face, G_IN_ORDER, + info); +#else /* not USE_SURFACE_BTREE */ + g_hash_table_foreach (s->faces, (GHFunc) edge_foreach_face, info); +#endif /* not USE_SURFACE_BTREE */ + g_hash_table_destroy (info[0]); + /* allow removal of faces */ + s->keep_faces = FALSE; +} + +#ifdef USE_SURFACE_BTREE +static gint foreach_face (GtsFace * f, + gpointer t_data, + gpointer * info) +#else /* not USE_SURFACE_BTREE */ +static void foreach_face (GtsFace * f, + gpointer t_data, + gpointer * info) +#endif /* not USE_SURFACE_BTREE */ +{ + (*((GtsFunc) info[0])) (f, info[1]); +#ifdef USE_SURFACE_BTREE + return FALSE; +#endif /* USE_SURFACE_BTREE */ +} + +/** + * gts_surface_foreach_face: + * @s: a #GtsSurface. + * @func: a #GtsFunc. + * @data: user data to be passed to @func. + * + * Calls @func once for each face of @s. + */ +void gts_surface_foreach_face (GtsSurface * s, + GtsFunc func, + gpointer data) +{ + gpointer info[2]; + + g_return_if_fail (s != NULL); + g_return_if_fail (func != NULL); + + /* forbid removal of faces */ + s->keep_faces = TRUE; + info[0] = func; + info[1] = data; +#ifdef USE_SURFACE_BTREE + g_tree_traverse (s->faces, (GTraverseFunc) foreach_face, G_IN_ORDER, + info); +#else /* not USE_SURFACE_BTREE */ + g_hash_table_foreach (s->faces, (GHFunc) foreach_face, info); +#endif /* not USE_SURFACE_BTREE */ + /* allow removal of faces */ + s->keep_faces = FALSE; +} + +#ifdef USE_SURFACE_BTREE +static gint foreach_face_remove (GtsFace * f, + gpointer t_data, + gpointer * info) +{ + if ((*((GtsFunc) info[0])) (f, info[1])) { + GtsSurface * s = info[2]; + guint * n = info[3]; + + f->surfaces = g_slist_remove (f->surfaces, s); + if (!GTS_OBJECT_DESTROYED (f) && + !gts_allow_floating_faces && + f->surfaces == NULL) + gts_object_destroy (GTS_OBJECT (f)); + + if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face) + (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face) (s, f); + + g_tree_remove (s->faces, f); + (*n)++; + } + return FALSE; +} +#else /* not USE_SURFACE_BTREE */ +static gboolean foreach_face_remove (GtsFace * f, + gpointer t_data, + gpointer * info) +{ + if ((*((GtsFunc) info[0])) (f, info[1])) { + GtsSurface * s = info[2]; + + f->surfaces = g_slist_remove (f->surfaces, s); + if (!GTS_OBJECT_DESTROYED (f) && + !gts_allow_floating_faces && + f->surfaces == NULL) + gts_object_destroy (GTS_OBJECT (f)); + + if (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face) + (* GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass)->remove_face) (s, f); + + return TRUE; + } + return FALSE; +} +#endif /* not USE_SURFACE_BTREE */ + +/** + * gts_surface_foreach_face_remove: + * @s: a #GtsSurface. + * @func: a #GtsFunc. + * @data: user data to be passed to @func. + * + * Calls @func once for each face of @s. If @func returns %TRUE the + * corresponding face is removed from @s (and destroyed if it does not + * belong to any other surface and #gts_allow_floating_faces is set to + * %FALSE). + * + * Returns: the number of faces removed from @s. + */ +guint gts_surface_foreach_face_remove (GtsSurface * s, + GtsFunc func, + gpointer data) +{ + gpointer info[4]; + guint n = 0; + + g_return_val_if_fail (s != NULL, 0); + g_return_val_if_fail (func != NULL, 0); + + /* forbid removal of faces */ + s->keep_faces = TRUE; + info[0] = func; + info[1] = data; + info[2] = s; +#ifdef USE_SURFACE_BTREE + info[3] = &n; + g_tree_traverse (s->faces, (GTraverseFunc) foreach_face_remove, G_PRE_ORDER, + info); +#else /* not USE_SURFACE_BTREE */ + n = g_hash_table_foreach_remove (s->faces, + (GHRFunc) foreach_face_remove, + info); +#endif /* not USE_SURFACE_BTREE */ + /* allow removal of faces */ + s->keep_faces = FALSE; + + return n; +} + +static void midvertex_insertion (GtsEdge * e, + GtsSurface * surface, + GtsEHeap * heap, + GtsRefineFunc refine_func, + gpointer refine_data, + GtsVertexClass * vertex_class, + GtsEdgeClass * edge_class) +{ + GtsVertex * midvertex; + GtsEdge * e1, * e2; + GSList * i; + + midvertex = (*refine_func) (e, vertex_class, refine_data); + e1 = gts_edge_new (edge_class, GTS_SEGMENT (e)->v1, midvertex); + gts_eheap_insert (heap, e1); + e2 = gts_edge_new (edge_class, GTS_SEGMENT (e)->v2, midvertex); + gts_eheap_insert (heap, e2); + + /* creates new faces and modifies old ones */ + i = e->triangles; + while (i) { + GtsTriangle * t = i->data; + GtsVertex * v1, * v2, * v3; + GtsEdge * te2, * te3, * ne, * tmp; + + gts_triangle_vertices_edges (t, e, &v1, &v2, &v3, &e, &te2, &te3); + ne = gts_edge_new (edge_class, midvertex, v3); + gts_eheap_insert (heap, ne); + if (GTS_SEGMENT (e1)->v1 == v2) { + tmp = e1; e1 = e2; e2 = tmp; + } + e1->triangles = g_slist_prepend (e1->triangles, t); + ne->triangles = g_slist_prepend (ne->triangles, t); + te2->triangles = g_slist_remove (te2->triangles, t); + t->e1 = e1; t->e2 = ne; t->e3 = te3; + gts_surface_add_face (surface, + gts_face_new (surface->face_class, e2, te2, ne)); + i = i->next; + } + /* destroys edge */ + g_slist_free (e->triangles); + e->triangles = NULL; + gts_object_destroy (GTS_OBJECT (e)); +} + +static gdouble edge_length2_inverse (GtsSegment * s) +{ + return - gts_point_distance2 (GTS_POINT (s->v1), GTS_POINT (s->v2)); +} + +static void create_heap_refine (GtsEdge * e, GtsEHeap * heap) +{ + gts_eheap_insert (heap, e); +} + +/** + * gts_surface_refine: + * @surface: a #GtsSurface. + * @cost_func: a function returning the cost for a given edge. + * @cost_data: user data to be passed to @cost_func. + * @refine_func: a #GtsRefineFunc. + * @refine_data: user data to be passed to @refine_func. + * @stop_func: a #GtsStopFunc. + * @stop_data: user data to be passed to @stop_func. + * + * Refine @surface using a midvertex insertion technique. All the + * edges of @surface are ordered according to @cost_func. The edges + * are then processed in order until @stop_func returns %TRUE. Each + * edge is split in two and new edges and faces are created. + * + * If @cost_func is set to %NULL, the edges are sorted according + * to their length squared (the longest is on top). + * + * If @refine_func is set to %NULL gts_segment_midvertex() is used. + * + */ +void gts_surface_refine (GtsSurface * surface, + GtsKeyFunc cost_func, + gpointer cost_data, + GtsRefineFunc refine_func, + gpointer refine_data, + GtsStopFunc stop_func, + gpointer stop_data) +{ + GtsEHeap * heap; + GtsEdge * e; + gdouble top_cost; + + g_return_if_fail (surface != NULL); + g_return_if_fail (stop_func != NULL); + + if (cost_func == NULL) + cost_func = (GtsKeyFunc) edge_length2_inverse; + if (refine_func == NULL) + refine_func = (GtsRefineFunc) gts_segment_midvertex; + + heap = gts_eheap_new (cost_func, cost_data); + gts_eheap_freeze (heap); + gts_surface_foreach_edge (surface, (GtsFunc) create_heap_refine, heap); + gts_eheap_thaw (heap); + while ((e = gts_eheap_remove_top (heap, &top_cost)) && + !(*stop_func) (top_cost, + gts_eheap_size (heap) + + gts_edge_face_number (e, surface) + 2, + stop_data)) + midvertex_insertion (e, surface, heap, refine_func, refine_data, + surface->vertex_class, surface->edge_class); + gts_eheap_destroy (heap); +} + +static GSList * edge_triangles (GtsEdge * e1, GtsEdge * e) +{ + GSList * i = e1->triangles; + GSList * triangles = NULL; + + while (i) { + GtsTriangle * t = i->data; + if (t->e1 == e || t->e2 == e || t->e3 == e) { + GtsEdge * e2; + GSList * j; + if (t->e1 == e) { + if (t->e2 == e1) + e2 = t->e3; + else + e2 = t->e2; + } + else if (t->e2 == e) { + if (t->e3 == e1) + e2 = t->e1; + else + e2 = t->e3; + } + else { + if (t->e2 == e1) + e2 = t->e1; + else + e2 = t->e2; + } + j = e2->triangles; + while (j) { + GtsTriangle * t = j->data; + if (t->e1 != e && t->e2 != e && t->e3 != e) + triangles = g_slist_prepend (triangles, t); + j = j->next; + } + } + else + triangles = g_slist_prepend (triangles, t); + i = i->next; + } + return triangles; +} + +static void replace_vertex (GSList * i, GtsVertex * v1, GtsVertex * v) +{ + while (i) { + GtsSegment * s = i->data; + if (s->v1 == v1) + s->v1 = v; + else + s->v2 = v; + i = i->next; + } +} + +/** + * gts_edge_collapse_creates_fold: + * @e: a #GtsEdge. + * @v: a #GtsVertex. + * @max: the maximum value of the square of the cosine of the angle between + * two triangles. + * + * Returns: %TRUE if collapsing edge @e to vertex @v would create + * faces making an angle the cosine squared of which would be larger than max, + * %FALSE otherwise. + */ +gboolean gts_edge_collapse_creates_fold (GtsEdge * e, + GtsVertex * v, + gdouble max) +{ + GtsVertex * v1, * v2; + GtsSegment * s; + GSList * i; + gboolean folded = FALSE; + + g_return_val_if_fail (e != NULL, TRUE); + g_return_val_if_fail (v != NULL, TRUE); + + s = GTS_SEGMENT (e); + v1 = s->v1; + v2 = s->v2; + replace_vertex (v1->segments, v1, v); + replace_vertex (v2->segments, v2, v); + + i = v1->segments; + while (i && !folded) { + GtsSegment * s = i->data; + if (GTS_IS_EDGE (s)) { + GtsEdge * e1 = GTS_EDGE (s); + if (e1 != e) { + GSList * triangles = edge_triangles (e1, e); + folded = gts_triangles_are_folded (triangles, s->v1, s->v2, max); + g_slist_free (triangles); + } + } + i = i->next; + } + + i = v2->segments; + while (i && !folded) { + GtsSegment * s = i->data; + if (GTS_IS_EDGE (s)) { + GtsEdge * e1 = GTS_EDGE (s); + if (e1 != e) { + GSList * triangles = edge_triangles (e1, e); + folded = gts_triangles_are_folded (triangles, s->v1, s->v2, max); + g_slist_free (triangles); + } + } + i = i->next; + } +#if 1 + if (!folded) { + GSList * triangles = gts_vertex_triangles (v1, NULL); + i = triangles = gts_vertex_triangles (v2, triangles); + while (i && !folded) { + GtsTriangle * t = i->data; + if (t->e1 != e && t->e2 != e && t->e3 != e) { + GtsEdge * e1 = gts_triangle_edge_opposite (t, v); + g_assert (e1); + folded = gts_triangles_are_folded (e1->triangles, + GTS_SEGMENT (e1)->v1, + GTS_SEGMENT (e1)->v2, + max); + } + i = i->next; + } + g_slist_free (triangles); + } +#endif + replace_vertex (v1->segments, v, v1); + replace_vertex (v2->segments, v, v2); + return folded; +} + +/** + * gts_edge_collapse_is_valid: + * @e: a #GtsEdge. + * + * An implementation of the topological constraints described in the + * "Mesh Optimization" article of Hoppe et al (1993). + * + * Returns: %TRUE if @e can be collapsed without violation of the topological + * constraints, %FALSE otherwise. + */ +gboolean gts_edge_collapse_is_valid (GtsEdge * e) +{ + GSList * i; + + g_return_val_if_fail (e != NULL, FALSE); + + i = GTS_SEGMENT (e)->v1->segments; + while (i) { + GtsEdge * e1 = i->data; + if (e1 != e && GTS_IS_EDGE (e1)) { + GtsEdge * e2 = NULL; + GSList * j = GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e)->v1 ? + GTS_SEGMENT (e1)->v2->segments : GTS_SEGMENT (e1)->v1->segments; + while (j && !e2) { + GtsEdge * e1 = j->data; + if (GTS_IS_EDGE (e1) && + (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e)->v2 || + GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e)->v2)) + e2 = e1; + j = j->next; + } + if (e2 && !gts_triangle_use_edges (e, e1, e2)) + return FALSE; + } + i = i->next; + } + + if (gts_edge_is_boundary (e, NULL)) { + GtsTriangle * t = e->triangles->data; + if (gts_edge_is_boundary (t->e1, NULL) && + gts_edge_is_boundary (t->e2, NULL) && + gts_edge_is_boundary (t->e3, NULL)) + return FALSE; + } + else { + if (gts_vertex_is_boundary (GTS_SEGMENT (e)->v1, NULL) && + gts_vertex_is_boundary (GTS_SEGMENT (e)->v2, NULL)) + return FALSE; + if (gts_edge_belongs_to_tetrahedron (e)) + return FALSE; + } + + return TRUE; +} + +#define HEAP_INSERT_EDGE(h, e) (GTS_OBJECT (e)->reserved = gts_eheap_insert (h, e)) +#define HEAP_REMOVE_EDGE(h, e) (gts_eheap_remove (h, GTS_OBJECT (e)->reserved),\ + GTS_OBJECT (e)->reserved = NULL) + +static GtsVertex * edge_collapse (GtsEdge * e, + GtsEHeap * heap, + GtsCoarsenFunc coarsen_func, + gpointer coarsen_data, + GtsVertexClass * klass, + gdouble maxcosine2) +{ + GSList * i; + GtsVertex * v1 = GTS_SEGMENT (e)->v1, * v2 = GTS_SEGMENT (e)->v2, * mid; + + /* if the edge is degenerate (i.e. v1 == v2), destroy and return */ + if (v1 == v2) { + gts_object_destroy (GTS_OBJECT (e)); + return NULL; + } + + if (!gts_edge_collapse_is_valid (e)) { + GTS_OBJECT (e)->reserved = + gts_eheap_insert_with_key (heap, e, G_MAXDOUBLE); + return NULL; + } + + mid = (*coarsen_func) (e, klass, coarsen_data); + + if (gts_edge_collapse_creates_fold (e, mid, maxcosine2)) { + GTS_OBJECT (e)->reserved = + gts_eheap_insert_with_key (heap, e, G_MAXDOUBLE); + gts_object_destroy (GTS_OBJECT (mid)); + return NULL; + } + + gts_object_destroy (GTS_OBJECT (e)); + + gts_vertex_replace (v1, mid); + gts_object_destroy (GTS_OBJECT (v1)); + gts_vertex_replace (v2, mid); + gts_object_destroy (GTS_OBJECT (v2)); + + /* destroy duplicate edges */ + i = mid->segments; + while (i) { + GtsEdge * e1 = i->data; + GtsEdge * duplicate; + while ((duplicate = gts_edge_is_duplicate (e1))) { + gts_edge_replace (duplicate, GTS_EDGE (e1)); + HEAP_REMOVE_EDGE (heap, duplicate); + gts_object_destroy (GTS_OBJECT (duplicate)); + } + i = i->next; + if (!e1->triangles) { + /* e1 is the result of the collapse of one edge of a pair of identical + faces (it should not happen unless duplicate triangles are present in + the initial surface) */ + g_warning ("file %s: line %d (%s): probably duplicate triangle.", + __FILE__, __LINE__, G_GNUC_PRETTY_FUNCTION); + HEAP_REMOVE_EDGE (heap, e1); + gts_object_destroy (GTS_OBJECT (e1)); + if (i == NULL) /* mid has been destroyed */ + mid = NULL; + } + } + + return mid; +} + +/* + * I don't see where this code is ever used, but keep it for a bit + * in case it is needed for debugging + */ +#ifdef GTS_NEED_UPDATE_CLOSEST_NEIGHBORS +static void update_closest_neighbors (GtsVertex * v, GtsEHeap * heap) +{ + GSList * i = v->segments; + + while (i) { + GtsSegment * s = i->data; + if (GTS_IS_EDGE (s)) { + HEAP_REMOVE_EDGE (heap, GTS_EDGE (s)); + HEAP_INSERT_EDGE (heap, GTS_EDGE (s)); + } + i = i->next; + } +} +#endif + +static void update_2nd_closest_neighbors (GtsVertex * v, GtsEHeap * heap) +{ + GSList * i = v->segments; + GSList * list = NULL; + + while (i) { + GtsSegment * s = i->data; + if (GTS_IS_EDGE (s)) { + GtsVertex * v1 = s->v1 == v ? s->v2 : s->v1; + GSList * j = v1->segments; + while (j) { + GtsSegment * s1 = j->data; + if (GTS_IS_EDGE (s1) && !g_slist_find (list, s1)) + list = g_slist_prepend (list, s1); + j = j->next; + } + } + i = i->next; + } + + i = list; + while (i) { + GtsEdge * e = i->data; + HEAP_REMOVE_EDGE (heap, e); + HEAP_INSERT_EDGE (heap, e); + i = i->next; + } + + g_slist_free (list); +} + +static gdouble edge_length2 (GtsEdge * e) +{ + return gts_point_distance2 (GTS_POINT (GTS_SEGMENT (e)->v1), + GTS_POINT (GTS_SEGMENT (e)->v2)); +} + +static void create_heap_coarsen (GtsEdge * e, GtsEHeap * heap) +{ + HEAP_INSERT_EDGE (heap, e); +} + +/** + * gts_surface_coarsen: + * @surface: a #GtsSurface. + * @cost_func: a function returning the cost for a given edge. + * @cost_data: user data to be passed to @cost_func. + * @coarsen_func: a #GtsCoarsenVertexFunc. + * @coarsen_data: user data to be passed to @coarsen_func. + * @stop_func: a #GtsStopFunc. + * @stop_data: user data to be passed to @stop_func. + * @minangle: minimum angle between two neighboring triangles. + * + * The edges of @surface are sorted according to @cost_func to + * create a priority heap (a #GtsEHeap). The edges are extracted in + * turn from the top of the heap and collapsed (i.e. the vertices are + * replaced by the vertex returned by the @coarsen_func function) + * until the @stop_func functions returns %TRUE. + * + * If @cost_func is set to %NULL, the edges are sorted according + * to their length squared (the shortest is on top). + * + * If @coarsen_func is set to %NULL gts_segment_midvertex() is used. + * + * The minimum angle is used to avoid introducing faces which would be folded. + */ +void gts_surface_coarsen (GtsSurface * surface, + GtsKeyFunc cost_func, + gpointer cost_data, + GtsCoarsenFunc coarsen_func, + gpointer coarsen_data, + GtsStopFunc stop_func, + gpointer stop_data, + gdouble minangle) +{ + GtsEHeap * heap; + GtsEdge * e; + gdouble top_cost; + gdouble maxcosine2; + + g_return_if_fail (surface != NULL); + g_return_if_fail (stop_func != NULL); + + if (cost_func == NULL) + cost_func = (GtsKeyFunc) edge_length2; + if (coarsen_func == NULL) + coarsen_func = (GtsCoarsenFunc) gts_segment_midvertex; + + heap = gts_eheap_new (cost_func, cost_data); + maxcosine2 = cos (minangle); maxcosine2 *= maxcosine2; + + gts_eheap_freeze (heap); + gts_surface_foreach_edge (surface, (GtsFunc) create_heap_coarsen, heap); + gts_eheap_thaw (heap); + /* we want to control edge destruction manually */ + gts_allow_floating_edges = TRUE; + while ((e = gts_eheap_remove_top (heap, &top_cost)) && + (top_cost < G_MAXDOUBLE) && + !(*stop_func) (top_cost, gts_eheap_size (heap) - + gts_edge_face_number (e, surface), stop_data)) + { + GtsVertex * v = edge_collapse (e, heap, coarsen_func, coarsen_data, + surface->vertex_class, maxcosine2); + if (v != NULL) + update_2nd_closest_neighbors (v, heap); + } + gts_allow_floating_edges = FALSE; + + /* set reserved field of remaining edges back to NULL */ + if (e) GTS_OBJECT (e)->reserved = NULL; + gts_eheap_foreach (heap, (GFunc) gts_object_reset_reserved, NULL); + + gts_eheap_destroy (heap); +} + +/** + * gts_coarsen_stop_number: + * @cost: the cost of the edge collapse considered. + * @nedge: the current number of edges of the surface being simplified. + * @min_number: a pointer to the minimum number of edges desired for the + * surface being simplified. + * + * This function is to be used as the @stop_func argument of + * gts_surface_coarsen() or gts_psurface_new(). + * + * Returns: %TRUE if the edge collapse would create a surface with a smaller + * number of edges than given by @min_number, %FALSE otherwise. + */ +gboolean gts_coarsen_stop_number (gdouble cost, + guint nedge, + guint * min_number) +{ + g_return_val_if_fail (min_number != NULL, TRUE); + + if (nedge < *min_number) + return TRUE; + return FALSE; +} + +/** + * gts_coarsen_stop_cost: + * @cost: the cost of the edge collapse considered. + * @nedge: the current number of edges of the surface being simplified. + * @max_cost: a pointer to the maximum cost allowed for an edge collapse. + * + * This function is to be used as the @stop_func argument of + * gts_surface_coarsen() or gts_psurface_new(). + * + * Returns: %TRUE if the cost of the edge collapse considered is larger than + * given by @max_cost, %FALSE otherwise. + */ +gboolean gts_coarsen_stop_cost (gdouble cost, + guint nedge, + gdouble * max_cost) +{ + g_return_val_if_fail (max_cost != NULL, TRUE); + + if (cost > *max_cost) + return TRUE; + return FALSE; +} + +#define GTS_M_ICOSAHEDRON_X /* sqrt(sqrt(5)+1)/sqrt(2*sqrt(5)) */ \ + 0.850650808352039932181540497063011072240401406 +#define GTS_M_ICOSAHEDRON_Y /* sqrt(2)/sqrt(5+sqrt(5)) */ \ + 0.525731112119133606025669084847876607285497935 +#define GTS_M_ICOSAHEDRON_Z 0.0 + +static guint generate_icosahedron (GtsSurface * s) +{ + GtsVertex * v01 = gts_vertex_new (s->vertex_class, + +GTS_M_ICOSAHEDRON_Z, +GTS_M_ICOSAHEDRON_X, -GTS_M_ICOSAHEDRON_Y); + GtsVertex * v02 = gts_vertex_new (s->vertex_class, + +GTS_M_ICOSAHEDRON_X, +GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z); + GtsVertex * v03 = gts_vertex_new (s->vertex_class, + +GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z, -GTS_M_ICOSAHEDRON_X); + GtsVertex * v04 = gts_vertex_new (s->vertex_class, + +GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z, +GTS_M_ICOSAHEDRON_X); + GtsVertex * v05 = gts_vertex_new (s->vertex_class, + +GTS_M_ICOSAHEDRON_X, -GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z); + GtsVertex * v06 = gts_vertex_new (s->vertex_class, + +GTS_M_ICOSAHEDRON_Z, +GTS_M_ICOSAHEDRON_X, +GTS_M_ICOSAHEDRON_Y); + GtsVertex * v07 = gts_vertex_new (s->vertex_class, + -GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z, +GTS_M_ICOSAHEDRON_X); + GtsVertex * v08 = gts_vertex_new (s->vertex_class, + +GTS_M_ICOSAHEDRON_Z, -GTS_M_ICOSAHEDRON_X, -GTS_M_ICOSAHEDRON_Y); + GtsVertex * v09 = gts_vertex_new (s->vertex_class, + -GTS_M_ICOSAHEDRON_X, +GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z); + GtsVertex * v10 = gts_vertex_new (s->vertex_class, + -GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z, -GTS_M_ICOSAHEDRON_X); + GtsVertex * v11 = gts_vertex_new (s->vertex_class, + -GTS_M_ICOSAHEDRON_X, -GTS_M_ICOSAHEDRON_Y, +GTS_M_ICOSAHEDRON_Z); + GtsVertex * v12 = gts_vertex_new (s->vertex_class, + +GTS_M_ICOSAHEDRON_Z, -GTS_M_ICOSAHEDRON_X, +GTS_M_ICOSAHEDRON_Y); + + GtsEdge * e01 = gts_edge_new (s->edge_class, v01, v02); + GtsEdge * e02 = gts_edge_new (s->edge_class, v03, v02); + GtsEdge * e03 = gts_edge_new (s->edge_class, v01, v03); + GtsEdge * e04 = gts_edge_new (s->edge_class, v04, v05); + GtsEdge * e05 = gts_edge_new (s->edge_class, v02, v05); + GtsEdge * e06 = gts_edge_new (s->edge_class, v04, v02); + GtsEdge * e07 = gts_edge_new (s->edge_class, v06, v07); + GtsEdge * e08 = gts_edge_new (s->edge_class, v04, v07); + GtsEdge * e09 = gts_edge_new (s->edge_class, v06, v04); + GtsEdge * e10 = gts_edge_new (s->edge_class, v08, v03); + GtsEdge * e11 = gts_edge_new (s->edge_class, v03, v05); + GtsEdge * e12 = gts_edge_new (s->edge_class, v08, v05); + GtsEdge * e13 = gts_edge_new (s->edge_class, v06, v09); + GtsEdge * e14 = gts_edge_new (s->edge_class, v07, v09); + GtsEdge * e15 = gts_edge_new (s->edge_class, v08, v10); + GtsEdge * e16 = gts_edge_new (s->edge_class, v03, v10); + GtsEdge * e17 = gts_edge_new (s->edge_class, v06, v01); + GtsEdge * e18 = gts_edge_new (s->edge_class, v01, v09); + GtsEdge * e19 = gts_edge_new (s->edge_class, v08, v11); + GtsEdge * e20 = gts_edge_new (s->edge_class, v10, v11); + GtsEdge * e21 = gts_edge_new (s->edge_class, v06, v02); + GtsEdge * e22 = gts_edge_new (s->edge_class, v12, v11); + GtsEdge * e23 = gts_edge_new (s->edge_class, v12, v08); + GtsEdge * e24 = gts_edge_new (s->edge_class, v12, v07); + GtsEdge * e25 = gts_edge_new (s->edge_class, v07, v11); + GtsEdge * e26 = gts_edge_new (s->edge_class, v12, v04); + GtsEdge * e27 = gts_edge_new (s->edge_class, v09, v11); + GtsEdge * e28 = gts_edge_new (s->edge_class, v10, v09); + GtsEdge * e29 = gts_edge_new (s->edge_class, v12, v05); + GtsEdge * e30 = gts_edge_new (s->edge_class, v01, v10); + + gts_surface_add_face (s, gts_face_new (s->face_class, e01, e02, e03)); + gts_surface_add_face (s, gts_face_new (s->face_class, e04, e05, e06)); + gts_surface_add_face (s, gts_face_new (s->face_class, e07, e08, e09)); + gts_surface_add_face (s, gts_face_new (s->face_class, e10, e11, e12)); + gts_surface_add_face (s, gts_face_new (s->face_class, e13, e14, e07)); + gts_surface_add_face (s, gts_face_new (s->face_class, e15, e16, e10)); + gts_surface_add_face (s, gts_face_new (s->face_class, e17, e18, e13)); + gts_surface_add_face (s, gts_face_new (s->face_class, e19, e20, e15)); + gts_surface_add_face (s, gts_face_new (s->face_class, e21, e01, e17)); + gts_surface_add_face (s, gts_face_new (s->face_class, e22, e19, e23)); + gts_surface_add_face (s, gts_face_new (s->face_class, e09, e06, e21)); + gts_surface_add_face (s, gts_face_new (s->face_class, e24, e25, e22)); + gts_surface_add_face (s, gts_face_new (s->face_class, e26, e08, e24)); + gts_surface_add_face (s, gts_face_new (s->face_class, e20, e27, e28)); + gts_surface_add_face (s, gts_face_new (s->face_class, e29, e04, e26)); + gts_surface_add_face (s, gts_face_new (s->face_class, e14, e27, e25)); + gts_surface_add_face (s, gts_face_new (s->face_class, e23, e12, e29)); + gts_surface_add_face (s, gts_face_new (s->face_class, e02, e05, e11)); + gts_surface_add_face (s, gts_face_new (s->face_class, e30, e28, e18)); + gts_surface_add_face (s, gts_face_new (s->face_class, e03, e16, e30)); + + return 0; +} + +static GtsVertex * unit_sphere_arc_midvertex (GtsSegment * s, + GtsVertexClass * vertex_class) +{ + GtsPoint * p1, * p2; + gdouble x, y, z, norm; + + p1 = GTS_POINT (s->v1); p2 = GTS_POINT (s->v2); + + x = 0.5*(p1->x + p2->x); + y = 0.5*(p1->y + p2->y); + z = 0.5*(p1->z + p2->z); + + norm = x*x + y*y + z*z; + norm = sqrt (norm); + + x /= norm; y /= norm; z /= norm; + + return gts_vertex_new (vertex_class, x, y, z); +} + +static void tessellate_face (GtsFace * f, + GtsSurface * s, + GtsRefineFunc refine_func, + gpointer refine_data, + GtsVertexClass * vertex_class, + GtsEdgeClass * edge_class) +{ + GtsTriangle * t; + GtsEdge * e1, * e2, * e3; /* former edges */ + GtsVertex * v1, * v2, * v3; /* initial vertices */ + GtsVertex * v4, * v5, * v6; /* new vertices */ + GtsEdge * e56, * e64, * e45; /* new inside edges */ + GtsEdge * e24, * e34, * e35, * e15, * e16, * e26; /* new border edges */ + GSList * dum; + GtsEdge * edum; + + t = GTS_TRIANGLE (f); + e1 = t->e1; e2 = t->e2; e3 = t->e3; + + if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v1) { + v1 = GTS_SEGMENT (e2)->v2; + v2 = GTS_SEGMENT (e1)->v1; + v3 = GTS_SEGMENT (e1)->v2; + } + else if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v2) { + v1 = GTS_SEGMENT (e2)->v1; + v2 = GTS_SEGMENT (e1)->v1; + v3 = GTS_SEGMENT (e1)->v2; + } + else if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v1) { + v1 = GTS_SEGMENT (e2)->v2; + v2 = GTS_SEGMENT (e1)->v2; + v3 = GTS_SEGMENT (e1)->v1; + } + else if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v2) { + v1 = GTS_SEGMENT (e2)->v1; + v2 = GTS_SEGMENT (e1)->v2; + v3 = GTS_SEGMENT (e1)->v1; + } + else { + v1 = v2 = v3 = NULL; + g_assert_not_reached (); + } + + e1->triangles = g_slist_remove (e1->triangles, t); + e2->triangles = g_slist_remove (e2->triangles, t); + e3->triangles = g_slist_remove (e3->triangles, t); + + if (GTS_OBJECT (e1)->reserved) { + dum = (GTS_OBJECT (e1)->reserved); + e24 = dum->data; + e34 = dum->next->data; + v4 = GTS_SEGMENT (e24)->v2; + if (GTS_SEGMENT (e24)->v1 == v3) { + edum = e34; e34 = e24; e24 = edum; + } + } + else { + v4 = (*refine_func) (e1, vertex_class, refine_data); + e24 = gts_edge_new (edge_class, v2, v4); + e34 = gts_edge_new (edge_class, v3, v4); + dum = g_slist_append (NULL, e24); + dum = g_slist_append (dum, e34); + GTS_OBJECT (e1)->reserved = dum; + } + if (GTS_OBJECT (e2)->reserved) { + dum = (GTS_OBJECT (e2)->reserved); + e35 = dum->data; + e15 = dum->next->data; + v5 = GTS_SEGMENT (e35)->v2; + if (GTS_SEGMENT (e35)->v1 == v1) { + edum = e15; e15 = e35; e35 = edum; + } + } + else { + v5 = (*refine_func) (e2, vertex_class, refine_data); + e35 = gts_edge_new (edge_class, v3, v5); + e15 = gts_edge_new (edge_class, v1, v5); + dum = g_slist_append (NULL, e35); + dum = g_slist_append (dum, e15); + GTS_OBJECT (e2)->reserved = dum; + } + if (GTS_OBJECT (e3)->reserved) { + dum = (GTS_OBJECT (e3)->reserved); + e16 = dum->data; + e26 = dum->next->data; + v6 = GTS_SEGMENT (e16)->v2; + if (GTS_SEGMENT (e16)->v1 == v2) { + edum = e16; e16 = e26; e26 = edum; + } + } + else { + v6 = (*refine_func) (e3, vertex_class, refine_data); + e16 = gts_edge_new (edge_class, v1, v6); + e26 = gts_edge_new (edge_class, v2, v6); + dum = g_slist_append (NULL, e16); + dum = g_slist_append (dum, e26); + GTS_OBJECT (e3)->reserved = dum; + } + + if (e1->triangles == NULL) { + g_slist_free (GTS_OBJECT (e1)->reserved); + GTS_OBJECT (e1)->reserved = NULL; + gts_object_destroy (GTS_OBJECT (e1)); + e1 = NULL; + } + if (e2->triangles == NULL) { + g_slist_free (GTS_OBJECT (e2)->reserved); + GTS_OBJECT (e2)->reserved = NULL; + gts_object_destroy (GTS_OBJECT (e2)); + e2 = NULL; + } + if (e3->triangles == NULL) { + g_slist_free (GTS_OBJECT (e3)->reserved); + GTS_OBJECT (e3)->reserved = NULL; + gts_object_destroy (GTS_OBJECT (e3)); + e3 = NULL; + } + + e56 = gts_edge_new (edge_class, v5, v6); + e64 = gts_edge_new (edge_class, v6, v4); + e45 = gts_edge_new (edge_class, v4, v5); + t->e1 = e56; e56->triangles = g_slist_prepend (e56->triangles, t); + t->e2 = e64; e64->triangles = g_slist_prepend (e64->triangles, t); + t->e3 = e45; e45->triangles = g_slist_prepend (e45->triangles, t); + + gts_surface_add_face (s, gts_face_new (s->face_class, e16, e56, e15)); + gts_surface_add_face (s, gts_face_new (s->face_class, e26, e24, e64)); + gts_surface_add_face (s, gts_face_new (s->face_class, e45, e34, e35)); +} + +static void create_array_tessellate (GtsFace * f, GPtrArray * array) +{ + g_ptr_array_add (array, f); +} + +/** + * gts_surface_tessellate: + * @s: a #GtsSurface. + * @refine_func: a #GtsRefineFunc. + * @refine_data: user data to be passed to @refine_func. + * + * Tessellate each triangle of @s with 4 triangles: + * the number of triangles is increased by a factor of 4. + * http://mathworld.wolfram.com/GeodesicDome.html + * + * If @refine_func is set to %NULL a mid arc function is used: if + * the surface is a polyhedron with the unit sphere as circum sphere, + * then gts_surface_tessellate() corresponds to a geodesation step + * (see gts_surface_generate_sphere()). + * + */ +void gts_surface_tessellate (GtsSurface * s, + GtsRefineFunc refine_func, + gpointer refine_data) +{ + GPtrArray * array; + guint i; + + g_return_if_fail (s != NULL); + + if (refine_func == NULL) /* tessellate_surface == geodesate_surface */ + refine_func = (GtsRefineFunc) unit_sphere_arc_midvertex; + + array = g_ptr_array_new (); + gts_surface_foreach_face (s, (GtsFunc) create_array_tessellate, array); + for(i = 0; i < array->len; i++) + tessellate_face (g_ptr_array_index (array, i), + s, refine_func, refine_data, + s->vertex_class, s->edge_class); + g_ptr_array_free (array, TRUE); +} + +/** + * gts_surface_generate_sphere: + * @s: a #GtsSurface. + * @geodesation_order: a #guint. + * + * Add a triangulated unit sphere generated by recursive subdivision to @s. + * First approximation is an isocahedron; each level of refinement + * (@geodesation_order) increases the number of triangles by a factor of 4. + * http://mathworld.wolfram.com/GeodesicDome.html + * + * Returns: @s. + */ +GtsSurface * gts_surface_generate_sphere (GtsSurface * s, + guint geodesation_order) +{ + guint cgo; + + g_return_val_if_fail (s != NULL, NULL); + g_return_val_if_fail (geodesation_order != 0, NULL); + + generate_icosahedron (s); + + for (cgo = 1; cgo < geodesation_order; cgo++) + gts_surface_tessellate (s, NULL, NULL); + + return s; +} + +static void foreach_vertex_copy (GtsPoint * p, GtsVertexClass * klass) +{ + GTS_OBJECT (p)->reserved = gts_vertex_new (klass, p->x, p->y, p->z); +} + +static void foreach_edge_copy (GtsSegment * s, GtsEdgeClass * klass) +{ + GTS_OBJECT (s)->reserved = gts_edge_new (klass, + GTS_OBJECT (s->v1)->reserved, + GTS_OBJECT (s->v2)->reserved); +} + +static void foreach_face_copy (GtsTriangle * t, + GtsSurface * s) +{ + gts_surface_add_face (s, gts_face_new (s->face_class, + GTS_OBJECT (t->e1)->reserved, + GTS_OBJECT (t->e2)->reserved, + GTS_OBJECT (t->e3)->reserved)); +} + +/** + * gts_surface_copy: + * @s1: a #GtsSurface. + * @s2: a #GtsSurface. + * + * Add a copy of all the faces, edges and vertices of @s2 to @s1. + * + * Returns: @s1. + */ +GtsSurface * gts_surface_copy (GtsSurface * s1, GtsSurface * s2) +{ + g_return_val_if_fail (s1 != NULL, NULL); + g_return_val_if_fail (s2 != NULL, NULL); + + gts_surface_foreach_vertex (s2, (GtsFunc) foreach_vertex_copy, + s1->vertex_class); + gts_surface_foreach_edge (s2, (GtsFunc) foreach_edge_copy, s1->edge_class); + gts_surface_foreach_face (s2, (GtsFunc) foreach_face_copy, s1); + + gts_surface_foreach_vertex (s2, (GtsFunc) gts_object_reset_reserved, NULL); + gts_surface_foreach_edge (s2, (GtsFunc) gts_object_reset_reserved, NULL); + + return s1; +} + +static void merge_foreach_face (GtsFace * f, + GtsSurface * s) +{ + gts_surface_add_face (s, f); +} + +/** + * gts_surface_merge: + * @s: a #GtsSurface. + * @with: another #GtsSurface. + * + * Adds all the faces of @with which do not already belong to @s + * to @s. + */ +void gts_surface_merge (GtsSurface * s, GtsSurface * with) +{ + g_return_if_fail (s != NULL); + g_return_if_fail (with != NULL); + + gts_surface_foreach_face (with, (GtsFunc) merge_foreach_face, s); +} + +static void manifold_foreach_edge (GtsEdge * e, gpointer * data) +{ + gboolean * is_manifold = data[0]; + + if (*is_manifold) { + if (gts_edge_face_number (e, data[1]) > 2) + *is_manifold = FALSE; + } +} + +/** + * gts_surface_is_manifold: + * @s: a #GtsSurface. + * + * Returns: %TRUE if the surface is a manifold, %FALSE otherwise. + */ +gboolean gts_surface_is_manifold (GtsSurface * s) +{ + gboolean is_manifold = TRUE; + gpointer data[2]; + + g_return_val_if_fail (s != NULL, FALSE); + + data[0] = &is_manifold; + data[1] = s; + gts_surface_foreach_edge (s, (GtsFunc) manifold_foreach_edge, data); + return is_manifold; +} + +static void closed_foreach_edge (GtsEdge * e, gpointer * data) +{ + gboolean * is_closed = data[0]; + + if (*is_closed) { + if (gts_edge_face_number (e, data[1]) != 2) + *is_closed = FALSE; + } +} + +/** + * gts_surface_is_closed: + * @s: a #GtsSurface. + * + * Returns: %TRUE if @s is a closed surface, %FALSE otherwise. Note that a + * closed surface is also a manifold. + */ +gboolean gts_surface_is_closed (GtsSurface * s) +{ + gboolean is_closed = TRUE; + gpointer data[2]; + + g_return_val_if_fail (s != NULL, FALSE); + + data[0] = &is_closed; + data[1] = s; + gts_surface_foreach_edge (s, (GtsFunc) closed_foreach_edge, data); + return is_closed; +} + +static void orientable_foreach_edge (GtsEdge * e, gpointer * data) +{ + gboolean * is_orientable = data[0]; + + if (*is_orientable) { + GtsSurface * surface = data[1]; + GtsFace * f1 = NULL, * f2 = NULL; + GSList * i = e->triangles; + while (i && *is_orientable) { + GtsFace * f = i->data; + if (GTS_IS_FACE (f) && gts_face_has_parent_surface (f, surface)) { + if (!f1) f1 = f; + else if (!f2) f2 = f; + else *is_orientable = FALSE; + } + i = i->next; + } + if (f1 && f2 && !gts_triangles_are_compatible (GTS_TRIANGLE (f1), + GTS_TRIANGLE (f2), e)) + *is_orientable = FALSE; + } +} + +/** + * gts_surface_is_orientable: + * @s: a #GtsSurface. + * + * Returns: %TRUE if all the faces of @s have compatible orientation + * as checked by gts_faces_are_compatible(), %FALSE otherwise. Note that + * an orientable surface is also a manifold. + */ +gboolean gts_surface_is_orientable (GtsSurface * s) +{ + gboolean is_orientable = TRUE; + gpointer data[2]; + + g_return_val_if_fail (s != NULL, FALSE); + + data[0] = &is_orientable; + data[1] = s; + gts_surface_foreach_edge (s, (GtsFunc) orientable_foreach_edge, data); + return is_orientable; +} + +static void volume_foreach_face (GtsTriangle * t, + gdouble * volume) +{ + GtsVertex * va, * vb, * vc; + GtsPoint * pa, * pb, * pc; + + gts_triangle_vertices (t, &va, &vb, &vc); + pa = GTS_POINT (va); + pb = GTS_POINT (vb); + pc = GTS_POINT (vc); + + *volume += (pa->x * (pb->y * pc->z - pb->z * pc->y) + + pb->x * (pc->y * pa->z - pc->z * pa->y) + + pc->x * (pa->y * pb->z - pa->z * pb->y)); +} + +/** + * gts_surface_volume: + * @s: a #GtsSurface. + * + * Returns: the signed volume of the domain bounded by the surface @s. It + * makes sense only if @s is a closed and orientable manifold. + */ +gdouble gts_surface_volume (GtsSurface * s) +{ + gdouble volume = 0.0; + + g_return_val_if_fail (s != NULL, 0.0); + + gts_surface_foreach_face (s, (GtsFunc) volume_foreach_face, &volume); + + return volume/6.; +} + +static void center_of_mass_foreach_face (GtsTriangle * t, + gpointer * data) +{ + GtsVertex * v1, * v2, * v3; + GtsPoint * p1, * p2, * p3; + gdouble x1, y1, z1, x2, y2, z2, nx, ny, nz; + gdouble * volume = data[0]; + gdouble * cm = data[1]; + + gts_triangle_vertices (t, &v1, &v2, &v3); + p1 = GTS_POINT (v1); + p2 = GTS_POINT (v2); + p3 = GTS_POINT (v3); + + x1 = p2->x - p1->x; + y1 = p2->y - p1->y; + z1 = p2->z - p1->z; + + x2 = p3->x - p1->x; + y2 = p3->y - p1->y; + z2 = p3->z - p1->z; + + nx = y1*z2 - z1*y2; + ny = z1*x2 - x1*z2; + nz = x1*y2 - y1*x2; + + cm[0] += nx*(p1->x*p1->x + p2->x*p2->x + p3->x*p3->x + + p1->x*p2->x + p1->x*p3->x + p2->x*p3->x); + cm[1] += ny*(p1->y*p1->y + p2->y*p2->y + p3->y*p3->y + + p1->y*p2->y + p1->y*p3->y + p2->y*p3->y); + cm[2] += nz*(p1->z*p1->z + p2->z*p2->z + p3->z*p3->z + + p1->z*p2->z + p1->z*p3->z + p2->z*p3->z); + + *volume += nx*(p1->x + p2->x + p3->x); +} + + +/** + * gts_surface_center_of_mass: + * @s: a #GtsSurface. + * @cm: a #GtsVector. + * + * Fills @cm with the coordinates of the center of mass of @s. + * + * Returns: the signed volume of the domain bounded by the surface @s. + */ +gdouble gts_surface_center_of_mass (GtsSurface * s, + GtsVector cm) +{ + gdouble volume = 0.; + gpointer data[2]; + + g_return_val_if_fail (s != NULL, 0.0); + + data[0] = &volume; + data[1] = &(cm[0]); + cm[0] = cm[1] = cm[2] = 0.; + gts_surface_foreach_face (s, (GtsFunc) center_of_mass_foreach_face, data); + + if (volume != 0.) { + cm[0] /= 4.*volume; + cm[1] /= 4.*volume; + cm[2] /= 4.*volume; + } + + return volume/6.; +} + +static void center_of_area_foreach_face (GtsTriangle * t, + gpointer * data) +{ + GtsVertex * v1, * v2, * v3; + GtsPoint * p1, * p2, * p3; + gdouble a; + gdouble * area = data[0]; + gdouble * cm = data[1]; + + gts_triangle_vertices (t, &v1, &v2, &v3); + p1 = GTS_POINT (v1); + p2 = GTS_POINT (v2); + p3 = GTS_POINT (v3); + + a = gts_triangle_area (t); + cm[0] += a*(p1->x + p2->x + p3->x); + cm[1] += a*(p1->y + p2->y + p3->y); + cm[2] += a*(p1->z + p2->z + p3->z); + *area += a; +} + + +/** + * gts_surface_center_of_area: + * @s: a #GtsSurface. + * @cm: a #GtsVector. + * + * Fills @cm with the coordinates of the center of area of @s. + * + * Returns: the area of surface @s. + */ +gdouble gts_surface_center_of_area (GtsSurface * s, + GtsVector cm) +{ + gdouble area = 0.; + gpointer data[2]; + + g_return_val_if_fail (s != NULL, 0.0); + + data[0] = &area; + data[1] = &(cm[0]); + cm[0] = cm[1] = cm[2] = 0.; + gts_surface_foreach_face (s, (GtsFunc) center_of_area_foreach_face, data); + + if (area != 0.) { + cm[0] /= 3.*area; + cm[1] /= 3.*area; + cm[2] /= 3.*area; + } + + return area; +} + +static void number_foreach (gpointer data, guint * n) +{ + (*n)++; +} + +/** + * gts_surface_vertex_number: + * @s: a #GtsSurface. + * + * Returns: the number of vertices of @s. + */ +guint gts_surface_vertex_number (GtsSurface * s) +{ + guint n = 0; + + g_return_val_if_fail (s != NULL, 0); + + gts_surface_foreach_vertex (s, (GtsFunc) number_foreach, &n); + + return n; +} + +/** + * gts_surface_edge_number: + * @s: a #GtsSurface. + * + * Returns: the number of edges of @s. + */ +guint gts_surface_edge_number (GtsSurface * s) +{ + guint n = 0; + + g_return_val_if_fail (s != NULL, 0); + + gts_surface_foreach_edge (s, (GtsFunc) number_foreach, &n); + + return n; +} + +/** + * gts_surface_face_number: + * @s: a #GtsSurface. + * + * Returns: the number of faces of @s + */ +guint gts_surface_face_number (GtsSurface * s) +{ + g_return_val_if_fail (s != NULL, 0); + +#ifdef USE_SURFACE_BTREE + return g_tree_nnodes (s->faces); +#else /* not USE_SURFACE_BTREE */ + return g_hash_table_size (s->faces); +#endif /* not USE_SURFACE_BTREE */ +} + +static void build_list_face (GtsTriangle * t, GSList ** list) +{ + *list = g_slist_prepend (*list, gts_bbox_triangle (gts_bbox_class (), t)); +} + +static void build_list_boundary (GtsEdge * e, GSList ** list) +{ + if (gts_edge_is_boundary (e, NULL)) + *list = g_slist_prepend (*list, gts_bbox_segment (gts_bbox_class (), + GTS_SEGMENT (e))); +} + +/** + * gts_surface_distance: + * @s1: a #GtsSurface. + * @s2: a #GtsSurface. + * @delta: a spatial increment defined as the percentage of the diagonal + * of the bounding box of @s2. + * @face_range: a #GtsRange. + * @boundary_range: a #GtsRange. + * + * Using the gts_bb_tree_surface_distance() and + * gts_bb_tree_surface_boundary_distance() functions fills @face_range + * and @boundary_range with the min, max and average Euclidean + * (minimum) distances between the faces of @s1 and the faces of @s2 + * and between the boundary edges of @s1 and @s2. + */ +void gts_surface_distance (GtsSurface * s1, GtsSurface * s2, gdouble delta, + GtsRange * face_range, GtsRange * boundary_range) +{ + GNode * face_tree, * boundary_tree; + GSList * bboxes; + + g_return_if_fail (s1 != NULL); + g_return_if_fail (s2 != NULL); + g_return_if_fail (delta > 0. && delta < 1.); + g_return_if_fail (face_range != NULL); + g_return_if_fail (boundary_range != NULL); + + bboxes = NULL; + gts_surface_foreach_face (s2, (GtsFunc) build_list_face, &bboxes); + if (bboxes != NULL) { + face_tree = gts_bb_tree_new (bboxes); + g_slist_free (bboxes); + + gts_bb_tree_surface_distance (face_tree, s1, + (GtsBBoxDistFunc) gts_point_triangle_distance, + delta, face_range); + gts_bb_tree_destroy (face_tree, TRUE); + + bboxes = NULL; + gts_surface_foreach_edge (s2, (GtsFunc) build_list_boundary, &bboxes); + if (bboxes != NULL) { + boundary_tree = gts_bb_tree_new (bboxes); + g_slist_free (bboxes); + + gts_bb_tree_surface_boundary_distance (boundary_tree, + s1, + (GtsBBoxDistFunc) gts_point_segment_distance, + delta, boundary_range); + gts_bb_tree_destroy (boundary_tree, TRUE); + } + else + gts_range_reset (boundary_range); + } + else { + gts_range_reset (face_range); + gts_range_reset (boundary_range); + } +} + +static void surface_boundary (GtsEdge * e, gpointer * data) +{ + GSList ** list = data[0]; + + if (gts_edge_is_boundary (e, data[1])) + *list = g_slist_prepend (*list, e); +} + +/** + * gts_surface_boundary: + * @surface: a #GtsSurface. + * + * Returns: a list of #GtsEdge boundary of @surface. + */ +GSList * gts_surface_boundary (GtsSurface * surface) +{ + GSList * list = NULL; + gpointer data[2]; + + g_return_val_if_fail (surface != NULL, NULL); + + data[0] = &list; + data[1] = surface; + gts_surface_foreach_edge (surface, (GtsFunc) surface_boundary, data); + + return list; +} + +struct _GtsSurfaceTraverse { + GtsFifo * q; + GtsSurface * s; +}; + +/** + * gts_surface_traverse_new: + * @s: a #GtsSurface. + * @f: a #GtsFace belonging to @s. + * + * Returns: a new #GtsSurfaceTraverse, initialized to start traversing + * from face @f of surface @s. + */ +GtsSurfaceTraverse * gts_surface_traverse_new (GtsSurface * s, + GtsFace * f) +{ + GtsSurfaceTraverse * t; + + g_return_val_if_fail (s != NULL, NULL); + g_return_val_if_fail (f != NULL, NULL); + g_return_val_if_fail (gts_face_has_parent_surface (f, s), NULL); + + t = g_malloc (sizeof (GtsSurfaceTraverse)); + t->q = gts_fifo_new (); + t->s = s; + GTS_OBJECT (f)->reserved = GUINT_TO_POINTER (1); + gts_fifo_push (t->q, f); + return t; +} + +static void push_neighbor (GtsFace * v, gpointer * data) +{ + if (!GTS_OBJECT (v)->reserved) { + GTS_OBJECT (v)->reserved = + GUINT_TO_POINTER (GPOINTER_TO_UINT (GTS_OBJECT (data[1])->reserved) + 1); + gts_fifo_push (data[0], v); + } +} + +/** + * gts_surface_traverse_next: + * @t: a #GtsSurfaceTraverse. + * @level: a pointer to a guint or %NULL. + * + * Returns: the next face of the traversal in breadth-first order or + * %NULL if no faces are left. If @level if not %NULL, it is filled + * with the level of the returned face (0 for the initial face, 1 for + * its neighbors and so on). + */ +GtsFace * gts_surface_traverse_next (GtsSurfaceTraverse * t, + guint * level) +{ + GtsFace * u; + + g_return_val_if_fail (t != NULL, NULL); + + u = gts_fifo_pop (t->q); + if (u) { + gpointer data[2]; + + if (level) + *level = GPOINTER_TO_UINT (GTS_OBJECT (u)->reserved); + data[0] = t->q; + data[1] = u; + gts_face_foreach_neighbor (u, t->s, (GtsFunc) push_neighbor, data); + } + return u; +} + +/** + * gts_surface_traverse_destroy: + * @t: a #GtsSurfaceTraverse. + * + * Frees all the memory allocated for @t. + */ +void gts_surface_traverse_destroy (GtsSurfaceTraverse * t) +{ + g_return_if_fail (t != NULL); + + gts_surface_foreach_face (t->s, (GtsFunc) gts_object_reset_reserved, NULL); + gts_fifo_destroy (t->q); + g_free (t); +} + +static void traverse_manifold (GtsTriangle * t, GtsSurface * s) +{ + if (g_slist_length (GTS_FACE (t)->surfaces) > 1) + return; + + gts_surface_add_face (s, GTS_FACE (t)); + if (g_slist_length (t->e1->triangles) == 2) { + if (t->e1->triangles->data != t) + traverse_manifold (t->e1->triangles->data, s); + else + traverse_manifold (t->e1->triangles->next->data, s); + } + if (g_slist_length (t->e2->triangles) == 2) { + if (t->e2->triangles->data != t) + traverse_manifold (t->e2->triangles->data, s); + else + traverse_manifold (t->e2->triangles->next->data, s); + } + if (g_slist_length (t->e3->triangles) == 2) { + if (t->e3->triangles->data != t) + traverse_manifold (t->e3->triangles->data, s); + else + traverse_manifold (t->e3->triangles->next->data, s); + } +} + +static void non_manifold_edges (GtsEdge * e, gpointer * data) +{ + GtsSurface * s = data[0]; + GSList ** non_manifold = data[1]; + + if (gts_edge_face_number (e, s) > 2) { + GSList * i = e->triangles; + + while (i) { + if (gts_face_has_parent_surface (i->data, s) && + !g_slist_find (*non_manifold, i->data)) + *non_manifold = g_slist_prepend (*non_manifold, i->data); + i = i->next; + } + } +} + +static void traverse_boundary (GtsEdge * e, gpointer * data) +{ + GtsSurface * orig = data[0]; + GSList ** components = data[1]; + GtsFace * f = gts_edge_is_boundary (e, orig); + + if (f != NULL && g_slist_length (f->surfaces) == 1) { + GtsSurface * s = + gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (orig)->klass), + orig->face_class, + orig->edge_class, + orig->vertex_class); + GSList * non_manifold = NULL, * i; + gpointer data[2]; + + *components = g_slist_prepend (*components, s); + data[0] = s; + data[1] = &non_manifold; + traverse_manifold (GTS_TRIANGLE (f), s); + + gts_surface_foreach_edge (s, (GtsFunc) non_manifold_edges, data); + i = non_manifold; + while (i) { + gts_surface_remove_face (s, i->data); + i = i->next; + } + g_slist_free (non_manifold); + } +} + +static void traverse_remaining (GtsFace * f, gpointer * data) +{ + GtsSurface * orig = data[0]; + GSList ** components = data[1]; + + if (g_slist_length (f->surfaces) == 1) { + GtsSurface * s = + gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (orig)->klass), + orig->face_class, + orig->edge_class, + orig->vertex_class); + GSList * non_manifold = NULL, * i; + gpointer data[2]; + + *components = g_slist_prepend (*components, s); + data[0] = s; + data[1] = &non_manifold; + traverse_manifold (GTS_TRIANGLE (f), s); + + gts_surface_foreach_edge (s, (GtsFunc) non_manifold_edges, data); + i = non_manifold; + while (i) { + gts_surface_remove_face (s, i->data); + i = i->next; + } + g_slist_free (non_manifold); + } +} + +/** + * gts_surface_split: + * @s: a #GtsSurface. + * + * Splits a surface into connected and manifold components. + * + * Returns: a list of new #GtsSurface. + */ +GSList * gts_surface_split (GtsSurface * s) +{ + gpointer data[2]; + GSList * components = NULL; + + g_return_val_if_fail (s != NULL, NULL); + + data[0] = s; + data[1] = &components; + + /* boundary components */ + gts_surface_foreach_edge (s, (GtsFunc) traverse_boundary, data); + + /* remaining components */ + gts_surface_foreach_face (s, (GtsFunc) traverse_remaining, data); + + return components; +} Index: work/obsolete/toporouter/src_3rd/gts/triangle.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/triangle.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/triangle.c (revision 6803) @@ -0,0 +1,1094 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "gts.h" + +static void triangle_destroy (GtsObject * object) +{ + GtsTriangle * triangle = GTS_TRIANGLE (object); + GtsEdge * e1 = triangle->e1; + GtsEdge * e2 = triangle->e2; + GtsEdge * e3 = triangle->e3; + + e1->triangles = g_slist_remove (e1->triangles, triangle); + if (!GTS_OBJECT_DESTROYED (e1) && + !gts_allow_floating_edges && e1->triangles == NULL) + gts_object_destroy (GTS_OBJECT (e1)); + + e2->triangles = g_slist_remove (e2->triangles, triangle); + if (!GTS_OBJECT_DESTROYED (e2) && + !gts_allow_floating_edges && e2->triangles == NULL) + gts_object_destroy (GTS_OBJECT (e2)); + + e3->triangles = g_slist_remove (e3->triangles, triangle); + if (!GTS_OBJECT_DESTROYED (e3) && + !gts_allow_floating_edges && e3->triangles == NULL) + gts_object_destroy (GTS_OBJECT (e3)); + + (* GTS_OBJECT_CLASS (gts_triangle_class ())->parent_class->destroy) (object); +} + +static void triangle_class_init (GtsObjectClass * klass) +{ + klass->destroy = triangle_destroy; +} + +static void triangle_init (GtsTriangle * triangle) +{ + triangle->e1 = triangle->e2 = triangle->e3 = NULL; +} + +/** + * gts_triangle_class: + * + * Returns: the #GtsTriangleClass. + */ +GtsTriangleClass * gts_triangle_class (void) +{ + static GtsTriangleClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo triangle_info = { + "GtsTriangle", + sizeof (GtsTriangle), + sizeof (GtsTriangleClass), + (GtsObjectClassInitFunc) triangle_class_init, + (GtsObjectInitFunc) triangle_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (gts_object_class (), + &triangle_info); + } + + return klass; +} + +/** + * gts_triangle_set: + * @triangle: a #GtsTriangle. + * @e1: a #GtsEdge. + * @e2: another #GtsEdge touching @e1. + * @e3: another #GtsEdge touching both @e1 and @e2. + * + * Sets the edge of @triangle to @e1, @e2 and @e3 while checking that they + * define a valid triangle. + */ +void gts_triangle_set (GtsTriangle * triangle, + GtsEdge * e1, + GtsEdge * e2, + GtsEdge * e3) +{ + g_return_if_fail (e1 != NULL); + g_return_if_fail (e2 != NULL); + g_return_if_fail (e3 != NULL); + g_return_if_fail (e1 != e2 && e1 != e3 && e2 != e3); + + triangle->e1 = e1; + triangle->e2 = e2; + triangle->e3 = e3; + + if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v1) + g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), + GTS_SEGMENT (e1)->v2, + GTS_SEGMENT (e2)->v2)); + else if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v1) + g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), + GTS_SEGMENT (e1)->v1, + GTS_SEGMENT (e2)->v2)); + else if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v2) + g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), + GTS_SEGMENT (e1)->v1, + GTS_SEGMENT (e2)->v1)); + else if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v2) + g_return_if_fail (gts_segment_connect (GTS_SEGMENT (e3), + GTS_SEGMENT (e1)->v2, + GTS_SEGMENT (e2)->v1)); + else + g_assert_not_reached (); + + e1->triangles = g_slist_prepend (e1->triangles, triangle); + e2->triangles = g_slist_prepend (e2->triangles, triangle); + e3->triangles = g_slist_prepend (e3->triangles, triangle); +} + +/** + * gts_triangle_new: + * @klass: a #GtsTriangleClass. + * @e1: a #GtsEdge. + * @e2: another #GtsEdge touching @e1. + * @e3: another #GtsEdge touching both @e1 and @e2. + * + * Returns: a new #GtsTriangle having @e1, @e2 and @e3 as edges. + */ +GtsTriangle * gts_triangle_new (GtsTriangleClass * klass, + GtsEdge * e1, + GtsEdge * e2, + GtsEdge * e3) +{ + GtsTriangle * t; + + t = GTS_TRIANGLE (gts_object_new (GTS_OBJECT_CLASS (klass))); + gts_triangle_set (t, e1, e2, e3); + + return t; +} + +/** + * gts_triangle_vertex_opposite: + * @t: a #GtsTriangle. + * @e: a #GtsEdge used by @t. + * + * This function fails if @e is not an edge of @t. + * + * Returns: a #GtsVertex, vertex of @t which does not belong to @e. + */ +GtsVertex * gts_triangle_vertex_opposite (GtsTriangle * t, GtsEdge * e) +{ + g_return_val_if_fail (t != NULL, NULL); + g_return_val_if_fail (e != NULL, NULL); + + if (t->e1 == e) { + GtsVertex * v = GTS_SEGMENT (t->e2)->v1; + if (v != GTS_SEGMENT (e)->v1 && v != GTS_SEGMENT (e)->v2) + return v; + return GTS_SEGMENT (t->e2)->v2; + } + if (t->e2 == e) { + GtsVertex * v = GTS_SEGMENT (t->e1)->v1; + if (v != GTS_SEGMENT (e)->v1 && v != GTS_SEGMENT (e)->v2) + return v; + return GTS_SEGMENT (t->e1)->v2; + } + if (t->e3 == e) { + GtsVertex * v = GTS_SEGMENT (t->e2)->v1; + if (v != GTS_SEGMENT (e)->v1 && v != GTS_SEGMENT (e)->v2) + return v; + return GTS_SEGMENT (t->e2)->v2; + } + g_assert_not_reached (); + return NULL; +} + +/** + * gts_triangle_edge_opposite: + * @t: a #GtsTriangle. + * @v: a #GtsVertex of @t. + * + * Returns: the edge of @t opposite @v or %NULL if @v is not a vertice of @t. + */ +GtsEdge * gts_triangle_edge_opposite (GtsTriangle * t, GtsVertex * v) +{ + GtsSegment * s1, * s2, * s3; + + g_return_val_if_fail (t != NULL, NULL); + g_return_val_if_fail (v != NULL, NULL); + + s1 = GTS_SEGMENT (t->e1); + s2 = GTS_SEGMENT (t->e2); + + if (s1->v1 != v && s1->v2 != v) { + if (s2->v1 != v && s2->v2 != v) + return NULL; + return t->e1; + } + if (s2->v1 != v && s2->v2 != v) + return t->e2; + s3 = GTS_SEGMENT (t->e3); + g_assert (s3->v1 != v && s3->v2 != v); + return t->e3; +} + +/** + * gts_triangles_angle: + * @t1: a #GtsTriangle. + * @t2: a #GtsTriangle. + * + * Returns: the value (in radians) of the angle between @t1 and @t2. + */ +gdouble gts_triangles_angle (GtsTriangle * t1, + GtsTriangle * t2) +{ + gdouble nx1, ny1, nz1, nx2, ny2, nz2; + gdouble pvx, pvy, pvz; + gdouble theta; + + g_return_val_if_fail (t1 != NULL && t2 != NULL, 0.0); + + gts_triangle_normal (t1, &nx1, &ny1, &nz1); + gts_triangle_normal (t2, &nx2, &ny2, &nz2); + + pvx = ny1*nz2 - nz1*ny2; + pvy = nz1*nx2 - nx1*nz2; + pvz = nx1*ny2 - ny1*nx2; + + theta = atan2 (sqrt (pvx*pvx + pvy*pvy + pvz*pvz), + nx1*nx2 + ny1*ny2 + nz1*nz2) - M_PI; + return theta < - M_PI ? theta + 2.*M_PI : theta; +} + +/** + * gts_triangles_are_compatible: + * @t1: a #GtsTriangle. + * @t2: a #GtsTriangle. + * @e: a #GtsEdge used by both @t1 and @t2. + * + * Checks if @t1 and @t2 have compatible orientations i.e. if @t1 and + * @t2 can be part of the same surface without conflict in the surface + * normal orientation. + * + * Returns: %TRUE if @t1 and @t2 are compatible, %FALSE otherwise. + */ +gboolean gts_triangles_are_compatible (GtsTriangle * t1, + GtsTriangle * t2, + GtsEdge * e) +{ + GtsEdge * e1 = NULL, * e2 = NULL; + + g_return_val_if_fail (t1 != NULL, FALSE); + g_return_val_if_fail (t2 != NULL, FALSE); + g_return_val_if_fail (e != NULL, FALSE); + + if (t1->e1 == e) e1 = t1->e2; + else if (t1->e2 == e) e1 = t1->e3; + else if (t1->e3 == e) e1 = t1->e1; + else + g_assert_not_reached (); + if (t2->e1 == e) e2 = t2->e2; + else if (t2->e2 == e) e2 = t2->e3; + else if (t2->e3 == e) e2 = t2->e1; + else + g_assert_not_reached (); + if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v1 || + GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v2 || + GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v1 || + GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v2) + return FALSE; + return TRUE; +} + +/** + * gts_triangle_area: + * @t: a #GtsTriangle. + * + * Returns: the area of the triangle @t. + */ +gdouble gts_triangle_area (GtsTriangle * t) +{ + gdouble x, y, z; + + g_return_val_if_fail (t != NULL, 0.0); + + gts_triangle_normal (t, &x, &y, &z); + + return sqrt (x*x + y*y + z*z)/2.; +} + +/** + * gts_triangle_perimeter: + * @t: a #GtsTriangle. + * + * Returns: the perimeter of the triangle @t. + */ +gdouble gts_triangle_perimeter (GtsTriangle * t) +{ + GtsVertex * v; + + g_return_val_if_fail (t != NULL, 0.0); + + v = gts_triangle_vertex (t); + return + gts_point_distance (GTS_POINT (GTS_SEGMENT (t->e1)->v1), + GTS_POINT (GTS_SEGMENT (t->e1)->v2)) + + gts_point_distance (GTS_POINT (GTS_SEGMENT (t->e1)->v1), + GTS_POINT (v)) + + gts_point_distance (GTS_POINT (GTS_SEGMENT (t->e1)->v2), + GTS_POINT (v)); +} + +/* perimeter of the equilateral triangle of area unity */ +#define GOLDEN_PERIMETER 4.5590141139 + +/** + * gts_triangle_quality: + * @t: a #GtsTriangle. + * + * The quality of a triangle is defined as the ratio of the square + * root of its surface area to its perimeter relative to this same + * ratio for an equilateral triangle with the same area. The quality + * is then one for an equilateral triangle and tends to zero for a + * very stretched triangle. + * + * Returns: the quality of the triangle @t. + */ +gdouble gts_triangle_quality (GtsTriangle * t) +{ + gdouble perimeter; + + g_return_val_if_fail (t != NULL, 0.0); + + perimeter = gts_triangle_perimeter (t); + return perimeter > 0.0 ? + GOLDEN_PERIMETER*sqrt (gts_triangle_area (t))/perimeter : + 0.0; +} + +/** + * gts_triangle_normal: + * @t: a #GtsTriangle. + * @x: the x coordinate of the normal. + * @y: the y coordinate of the normal. + * @z: the z coordinate of the normal. + * + * Computes the coordinates of the oriented normal of @t as the + * cross-product of two edges, using the left-hand rule. The normal is + * not normalized. If this triangle is part of a closed and oriented + * surface, the normal points to the outside of the surface. + */ +void gts_triangle_normal (GtsTriangle * t, + gdouble * x, + gdouble * y, + gdouble * z) +{ + GtsVertex * v1, * v2 = NULL, * v3 = NULL; + GtsPoint * p1, * p2, * p3; + gdouble x1, y1, z1, x2, y2, z2; + + g_return_if_fail (t != NULL); + + v1 = GTS_SEGMENT (t->e1)->v1; + if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v1) { + v2 = GTS_SEGMENT (t->e2)->v2; + v3 = GTS_SEGMENT (t->e1)->v2; + } + else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v2) { + v2 = GTS_SEGMENT (t->e1)->v2; + v3 = GTS_SEGMENT (t->e2)->v1; + } + else if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v2) { + v2 = GTS_SEGMENT (t->e2)->v1; + v3 = GTS_SEGMENT (t->e1)->v2; + } + else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v1) { + v2 = GTS_SEGMENT (t->e1)->v2; + v3 = GTS_SEGMENT (t->e2)->v2; + } + else { + fprintf (stderr, "t: %p t->e1: %p t->e2: %p t->e3: %p t->e1->v1: %p t->e1->v2: %p t->e2->v1: %p t->e2->v2: %p t->e3->v1: %p t->e3->v2: %p\n", + t, t->e1, t->e2, + t->e3, GTS_SEGMENT (t->e1)->v1, GTS_SEGMENT (t->e1)->v2, + GTS_SEGMENT (t->e2)->v1, GTS_SEGMENT (t->e2)->v2, + GTS_SEGMENT (t->e3)->v1, GTS_SEGMENT (t->e3)->v2); + g_assert_not_reached (); + } + + p1 = GTS_POINT (v1); + p2 = GTS_POINT (v2); + p3 = GTS_POINT (v3); + + x1 = p2->x - p1->x; + y1 = p2->y - p1->y; + z1 = p2->z - p1->z; + + x2 = p3->x - p1->x; + y2 = p3->y - p1->y; + z2 = p3->z - p1->z; + + *x = y1*z2 - z1*y2; + *y = z1*x2 - x1*z2; + *z = x1*y2 - y1*x2; +} + +/** + * gts_triangle_orientation: + * @t: a #GtsTriangle. + * + * Checks for the orientation of the plane (x,y) projection of a + * triangle. See gts_point_orientation() for details. This function + * is geometrically robust. + * + * Returns: a number depending on the orientation of the vertices of @t. + */ +gdouble gts_triangle_orientation (GtsTriangle * t) +{ + GtsVertex * v1, * v2 = NULL, * v3 = NULL; + + g_return_val_if_fail (t != NULL, 0.0); + + v1 = GTS_SEGMENT (t->e1)->v1; + if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v1) { + v2 = GTS_SEGMENT (t->e2)->v2; + v3 = GTS_SEGMENT (t->e1)->v2; + } + else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v2) { + v2 = GTS_SEGMENT (t->e1)->v2; + v3 = GTS_SEGMENT (t->e2)->v1; + } + else if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v2) { + v2 = GTS_SEGMENT (t->e2)->v1; + v3 = GTS_SEGMENT (t->e1)->v2; + } + else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v1) { + v2 = GTS_SEGMENT (t->e1)->v2; + v3 = GTS_SEGMENT (t->e2)->v2; + } + else + g_assert_not_reached (); + return gts_point_orientation (GTS_POINT (v1), + GTS_POINT (v2), + GTS_POINT (v3)); +} + +/** + * gts_triangle_revert: + * @t: a #GtsTriangle. + * + * Changes the orientation of triangle @t, turning it inside out. + */ +void gts_triangle_revert (GtsTriangle * t) +{ + GtsEdge * e; + + g_return_if_fail (t != NULL); + + e = t->e1; + t->e1 = t->e2; + t->e2 = e; +} + +/** + * gts_triangles_from_edges: + * @edges: a list of #GtsEdge. + * + * Builds a list of unique triangles which have one of their edges in @edges. + * + * Returns: the list of triangles. + */ +GSList * gts_triangles_from_edges (GSList * edges) +{ + GHashTable * hash; + GSList * triangles = NULL, * i; + + hash = g_hash_table_new (NULL, NULL); + i = edges; + while (i) { + GSList * j = GTS_EDGE (i->data)->triangles; + while (j) { + GtsTriangle * t = j->data; + if (g_hash_table_lookup (hash, t) == NULL) { + triangles = g_slist_prepend (triangles, t); + g_hash_table_insert (hash, t, i); + } + j = j->next; + } + i = i->next; + } + g_hash_table_destroy (hash); + + return triangles; +} + +/** + * gts_triangle_vertices_edges: + * @t: a #GtsTriangle. + * @e: a #GtsEdge belonging to the edges of @t or %NULL. + * @v1: a #GtsVertex used by @t. + * @v2: a #GtsVertex used by @t. + * @v3: a #GtsVertex used by @t. + * @e1: a #GtsEdge used by @t. + * @e2: a #GtsEdge used by @t. + * @e3: a #GtsEdge used by @t. + * + * Given @t and @e, returns @v1, @v2, @v3, @e1, @e2 and @e3. @e1 + * has @v1 and @v2 as vertices, @e2 has @v2 and @v3 as vertices + * and @e3 has @v3 and @v1 as vertices. @v1, @v2 and @v3 respects + * the orientation of @t. If @e is not NULL, @e1 and @e are + * identical. + */ +void gts_triangle_vertices_edges (GtsTriangle * t, + GtsEdge * e, + GtsVertex ** v1, + GtsVertex ** v2, + GtsVertex ** v3, + GtsEdge ** e1, + GtsEdge ** e2, + GtsEdge ** e3) +{ + GtsEdge * ee1, * ee2; + + g_return_if_fail (t != NULL); + + if (e == t->e1 || e == NULL) { + *e1 = ee1 = t->e1; *e2 = ee2 = t->e2; *e3 = t->e3; + } + else if (e == t->e2) { + *e1 = ee1 = e; *e2 = ee2 = t->e3; *e3 = t->e1; + } + else if (e == t->e3) { + *e1 = ee1 = e; *e2 = ee2 = t->e1; *e3 = t->e2; + } + else { + g_assert_not_reached (); + ee1 = ee2 = NULL; /* to avoid complaints from the compiler */ + } + if (GTS_SEGMENT (ee1)->v2 == GTS_SEGMENT (ee2)->v1) { + *v1 = GTS_SEGMENT (ee1)->v1; + *v2 = GTS_SEGMENT (ee1)->v2; + *v3 = GTS_SEGMENT (ee2)->v2; + } + else if (GTS_SEGMENT (ee1)->v2 == GTS_SEGMENT (ee2)->v2) { + *v1 = GTS_SEGMENT (ee1)->v1; + *v2 = GTS_SEGMENT (ee1)->v2; + *v3 = GTS_SEGMENT (ee2)->v1; + } + else if (GTS_SEGMENT (ee1)->v1 == GTS_SEGMENT (ee2)->v1) { + *v1 = GTS_SEGMENT (ee1)->v2; + *v2 = GTS_SEGMENT (ee1)->v1; + *v3 = GTS_SEGMENT (ee2)->v2; + } + else if (GTS_SEGMENT (ee1)->v1 == GTS_SEGMENT (ee2)->v2) { + *v1 = GTS_SEGMENT (ee1)->v2; + *v2 = GTS_SEGMENT (ee1)->v1; + *v3 = GTS_SEGMENT (ee2)->v1; + } + else + g_assert_not_reached (); +} + +/* sqrt(3) */ +#define SQRT3 1.73205080757 + +/** + * gts_triangle_enclosing: + * @klass: the class of the new triangle. + * @points: a list of #GtsPoint. + * @scale: a scaling factor (must be larger than one). + * + * Builds a new triangle (including new vertices and edges) enclosing + * the plane projection of all the points in @points. This triangle is + * equilateral and encloses a rectangle defined by the maximum and + * minimum x and y coordinates of the points. @scale is an homothetic + * scaling factor. If equal to one, the triangle encloses exactly the + * enclosing rectangle. + * + * Returns: a new #GtsTriangle. + */ +GtsTriangle * gts_triangle_enclosing (GtsTriangleClass * klass, + GSList * points, gdouble scale) +{ + gdouble xmax, xmin, ymax, ymin; + gdouble xo, yo, r; + GtsVertex * v1, * v2, * v3; + GtsEdge * e1, * e2, * e3; + + if (points == NULL) + return NULL; + + xmax = xmin = GTS_POINT (points->data)->x; + ymax = ymin = GTS_POINT (points->data)->y; + points = points->next; + while (points) { + GtsPoint * p = points->data; + if (p->x > xmax) xmax = p->x; + else if (p->x < xmin) xmin = p->x; + if (p->y > ymax) ymax = p->y; + else if (p->y < ymin) ymin = p->y; + points = points->next; + } + xo = (xmax + xmin)/2.; + yo = (ymax + ymin)/2.; + r = scale*sqrt((xmax - xo)*(xmax - xo) + (ymax - yo)*(ymax - yo)); + if (r == 0.0) r = scale; + v1 = gts_vertex_new (gts_vertex_class (), + xo + r*SQRT3, yo - r, 0.0); + v2 = gts_vertex_new (gts_vertex_class (), + xo, yo + 2.*r, 0.0); + v3 = gts_vertex_new (gts_vertex_class (), + xo - r*SQRT3, yo - r, 0.0); + e1 = gts_edge_new (gts_edge_class (), v1, v2); + e2 = gts_edge_new (gts_edge_class (), v2, v3); + e3 = gts_edge_new (gts_edge_class (), v3, v1); + return gts_triangle_new (gts_triangle_class (), e1, e2, e3); +} + +/** + * gts_triangle_neighbor_number: + * @t: a #GtsTriangle. + * + * Returns: the number of triangles neighbors of @t. + */ +guint gts_triangle_neighbor_number (GtsTriangle * t) +{ + GSList * i; + guint nn = 0; + GtsEdge * ee[4], ** e = ee; + + g_return_val_if_fail (t != NULL, 0); + + ee[0] = t->e1; ee[1] = t->e2; ee[2] = t->e3; ee[3] = NULL; + while (*e) { + i = (*e++)->triangles; + while (i) { + GtsTriangle * t1 = i->data; + if (t1 != t) + nn++; + i = i->next; + } + } + return nn; +} + +/** + * gts_triangle_neighbors: + * @t: a #GtsTriangle. + * + * Returns: a list of #GtsTriangle neighbors of @t. + */ +GSList * gts_triangle_neighbors (GtsTriangle * t) +{ + GSList * i, * list = NULL; + GtsEdge * ee[4], ** e = ee; + + g_return_val_if_fail (t != NULL, NULL); + + ee[0] = t->e1; ee[1] = t->e2; ee[2] = t->e3; ee[3] = NULL; + while (*e) { + i = (*e++)->triangles; + while (i) { + GtsTriangle * t1 = i->data; + if (t1 != t) + list = g_slist_prepend (list, t1); + i = i->next; + } + } + return list; +} + +/** + * gts_triangles_common_edge: + * @t1: a #GtsTriangle. + * @t2: a #GtsTriangle. + * + * Returns: a #GtsEdge common to both @t1 and @t2 or %NULL if @t1 and @t2 + * do not share any edge. + */ +GtsEdge * gts_triangles_common_edge (GtsTriangle * t1, + GtsTriangle * t2) +{ + g_return_val_if_fail (t1 != NULL, NULL); + g_return_val_if_fail (t2 != NULL, NULL); + + if (t1->e1 == t2->e1 || t1->e1 == t2->e2 || t1->e1 == t2->e3) + return t1->e1; + if (t1->e2 == t2->e1 || t1->e2 == t2->e2 || t1->e2 == t2->e3) + return t1->e2; + if (t1->e3 == t2->e1 || t1->e3 == t2->e2 || t1->e3 == t2->e3) + return t1->e3; + return NULL; +} + +/** + * gts_triangle_is_duplicate: + * @t: a #GtsTriangle. + * + * Returns: a #GtsTriangle different from @t but sharing all its edges + * with @t or %NULL if there is none. + */ +GtsTriangle * gts_triangle_is_duplicate (GtsTriangle * t) +{ + GSList * i; + GtsEdge * e2, * e3; + + g_return_val_if_fail (t != NULL, NULL); + + e2 = t->e2; + e3 = t->e3; + i = t->e1->triangles; + while (i) { + GtsTriangle * t1 = i->data; + if (t1 != t && + (t1->e1 == e2 || t1->e2 == e2 || t1->e3 == e2) && + (t1->e1 == e3 || t1->e2 == e3 || t1->e3 == e3)) + return t1; + i = i->next; + } + + return NULL; +} + +/** + * gts_triangle_use_edges: + * @e1: a #GtsEdge. + * @e2: a #GtsEdge. + * @e3: a #GtsEdge. + * + * Returns: a #GtsTriangle having @e1, @e2 and @e3 as edges or %NULL if @e1, + * @e2 and @e3 are not part of any triangle. + */ +GtsTriangle * gts_triangle_use_edges (GtsEdge * e1, + GtsEdge * e2, + GtsEdge * e3) +{ + GSList * i; + + g_return_val_if_fail (e1 != NULL, NULL); + g_return_val_if_fail (e2 != NULL, NULL); + g_return_val_if_fail (e3 != NULL, NULL); + + i = e1->triangles; + while (i) { + GtsTriangle * t = i->data; + if ((t->e1 == e2 && (t->e2 == e3 || t->e3 == e3)) || + (t->e2 == e2 && (t->e1 == e3 || t->e3 == e3)) || + (t->e3 == e2 && (t->e1 == e3 || t->e2 == e3))) + return t; + i = i->next; + } + + return NULL; +} + +/** + * gts_triangle_is_ok: + * @t: a #GtsTriangle. + * + * Returns: %TRUE if @t is a non-degenerate, non-duplicate triangle, + * %FALSE otherwise. + */ +gboolean gts_triangle_is_ok (GtsTriangle * t) +{ + g_return_val_if_fail (t != NULL, FALSE); + g_return_val_if_fail (t->e1 != NULL, FALSE); + g_return_val_if_fail (t->e2 != NULL, FALSE); + g_return_val_if_fail (t->e3 != NULL, FALSE); + g_return_val_if_fail (t->e1 != t->e2 && t->e1 != t->e3 && t->e2 != t->e3, + FALSE); + g_return_val_if_fail (gts_segments_touch (GTS_SEGMENT (t->e1), + GTS_SEGMENT (t->e2)), + FALSE); + g_return_val_if_fail (gts_segments_touch (GTS_SEGMENT (t->e1), + GTS_SEGMENT (t->e3)), + FALSE); + g_return_val_if_fail (gts_segments_touch (GTS_SEGMENT (t->e2), + GTS_SEGMENT (t->e3)), + FALSE); + g_return_val_if_fail (GTS_SEGMENT (t->e1)->v1 != GTS_SEGMENT (t->e1)->v2, + FALSE); + g_return_val_if_fail (GTS_SEGMENT (t->e2)->v1 != GTS_SEGMENT (t->e2)->v2, + FALSE); + g_return_val_if_fail (GTS_SEGMENT (t->e3)->v1 != GTS_SEGMENT (t->e3)->v2, + FALSE); + g_return_val_if_fail (GTS_OBJECT (t)->reserved == NULL, FALSE); + g_return_val_if_fail (!gts_triangle_is_duplicate (t), FALSE); + return TRUE; +} + +/** + * gts_triangle_vertices: + * @t: a #GtsTriangle. + * @v1: a pointer on a #GtsVertex. + * @v2: a pointer on a #GtsVertex. + * @v3: a pointer on a #GtsVertex. + * + * Fills @v1, @v2 and @v3 with the oriented set of vertices, summits of @t. + */ +void gts_triangle_vertices (GtsTriangle * t, + GtsVertex ** v1, GtsVertex ** v2, GtsVertex ** v3) +{ + GtsSegment * e1, * e2; + + g_return_if_fail (t != NULL); + g_return_if_fail (v1 != NULL && v2 != NULL && v3 != NULL); + + e1 = GTS_SEGMENT (t->e1); + e2 = GTS_SEGMENT (t->e2); + + if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v1) { + *v1 = GTS_SEGMENT (e1)->v1; + *v2 = GTS_SEGMENT (e1)->v2; + *v3 = GTS_SEGMENT (e2)->v2; + } + else if (GTS_SEGMENT (e1)->v2 == GTS_SEGMENT (e2)->v2) { + *v1 = GTS_SEGMENT (e1)->v1; + *v2 = GTS_SEGMENT (e1)->v2; + *v3 = GTS_SEGMENT (e2)->v1; + } + else if (GTS_SEGMENT (e1)->v1 == GTS_SEGMENT (e2)->v1) { + *v1 = GTS_SEGMENT (e1)->v2; + *v2 = GTS_SEGMENT (e1)->v1; + *v3 = GTS_SEGMENT (e2)->v2; + } + else { + *v1 = GTS_SEGMENT (e1)->v2; + *v2 = GTS_SEGMENT (e1)->v1; + *v3 = GTS_SEGMENT (e2)->v1; + } +} + +/** + * gts_triangle_circumcircle_center: + * @t: a #GtsTriangle. + * @point_class: a #GtsPointClass. + * + * Returns: a new #GtsPoint, center of the circumscribing circle of @t or + * %NULL if the circumscribing circle is not defined. + */ +GtsPoint * gts_triangle_circumcircle_center (GtsTriangle * t, + GtsPointClass * point_class) +{ + GtsVertex * v1, * v2, * v3; + gdouble xa, ya, xb, yb, xc, yc; + gdouble xd, yd, xe, ye; + gdouble xad, yad, xae, yae; + gdouble det; + + g_return_val_if_fail (t != NULL, NULL); + g_return_val_if_fail (point_class != NULL, NULL); + + gts_triangle_vertices (t, &v1, &v2, &v3); + + xa = GTS_POINT (v1)->x; ya = GTS_POINT (v1)->y; + xb = GTS_POINT (v2)->x; yb = GTS_POINT (v2)->y; + xc = GTS_POINT (v3)->x; yc = GTS_POINT (v3)->y; + xd = (xa + xb)/2.; yd = (ya + yb)/2.; + xe = (xa + xc)/2.; ye = (ya + yc)/2.; + xad = xd - xa; yad = yd - ya; + xae = xe - xa; yae = ye - ya; + det = xad*yae - xae*yad; + if (det == 0.) + return NULL; + return gts_point_new (point_class, + (yae*yad*(yd - ye) + xad*yae*xd - xae*yad*xe)/det, + -(xae*xad*(xd - xe) + yad*xae*yd - yae*xad*ye)/det, + 0.); +} + +/* square of the maximum area ratio admissible */ +#define AREA_RATIO_MAX2 1e8 + +static gboolean points_are_folded (GtsPoint * A, + GtsPoint * B, + GtsPoint * C, + GtsPoint * D, + gdouble max) +{ + GtsVector AB, AC, AD; + GtsVector n1, n2; + gdouble nn1, nn2, n1n2; + + gts_vector_init (AB, A, B); + gts_vector_init (AC, A, C); + gts_vector_init (AD, A, D); + gts_vector_cross (n1, AB, AC); + gts_vector_cross (n2, AD, AB); + + nn1 = gts_vector_scalar (n1, n1); + nn2 = gts_vector_scalar (n2, n2); + if (nn1 >= AREA_RATIO_MAX2*nn2 || nn2 >= AREA_RATIO_MAX2*nn1) + return TRUE; + n1n2 = gts_vector_scalar (n1, n2); + if (n1n2 > 0.) + return FALSE; + if (n1n2*n1n2/(nn1*nn2) > max) + return TRUE; + return FALSE; +} + +static GtsVertex * triangle_use_vertices (GtsTriangle * t, + GtsVertex * A, + GtsVertex * B) +{ + GtsVertex + * v1 = GTS_SEGMENT (t->e1)->v1, + * v2 = GTS_SEGMENT (t->e1)->v2, + * v3 = gts_triangle_vertex (t); + + if (v1 == A) { + if (v2 == B) + return v3; + g_assert (v3 == B); + return v2; + } + if (v2 == A) { + if (v1 == B) + return v3; + g_assert (v3 == B); + return v1; + } + if (v3 == A) { + if (v1 == B) + return v2; + g_assert (v2 == B); + return v1; + } + g_assert_not_reached (); + return NULL; +} + +/** + * gts_triangles_are_folded: + * @triangles: a list of #GtsTriangle. + * @A: a #GtsVertex. + * @B: another #GtsVertex. + * @max: the maximum value of the square of the cosine of the angle between + * two triangles. + * + * Given a list of triangles sharing @A and @B as vertices, checks if any + * two triangles in the list make an angle larger than a given value defined + * by @max. + * + * Returns: %TRUE if any pair of triangles in @triangles makes an angle larger + * than the maximum value, %FALSE otherwise. + */ +gboolean gts_triangles_are_folded (GSList * triangles, + GtsVertex * A, GtsVertex * B, + gdouble max) +{ + GSList * i; + + g_return_val_if_fail (A != NULL, TRUE); + g_return_val_if_fail (B != NULL, TRUE); + + i = triangles; + while (i) { + GtsVertex * C = triangle_use_vertices (i->data, A, B); + GSList * j = i->next; + while (j) { + GtsVertex * D = triangle_use_vertices (j->data, A, B); + if (points_are_folded (GTS_POINT (A), + GTS_POINT (B), + GTS_POINT (C), + GTS_POINT (D), + max)) + return TRUE; + j = j->next; + } + i = i->next; + } + return FALSE; +} + +/** + * 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); +} + +/** + * gts_triangle_interpolate_height: + * @t: a #GtsTriangle. + * @p: a #GtsPoint. + * + * Fills the z-coordinate of point @p belonging to the plane + * projection of triangle @t with the linearly interpolated value of + * the z-coordinates of the vertices of @t. + */ +void gts_triangle_interpolate_height (GtsTriangle * t, GtsPoint * p) +{ + GtsPoint * p1, * p2, * p3; + gdouble x1, x2, y1, y2, det; + + g_return_if_fail (t != NULL); + g_return_if_fail (p != NULL); + + p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1); + p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); + p3 = GTS_POINT (gts_triangle_vertex (t)); + + x1 = p2->x - p1->x; + y1 = p2->y - p1->y; + x2 = p3->x - p1->x; + y2 = p3->y - p1->y; + det = x1*y2 - x2*y1; + if (det == 0.) + p->z = (p1->z + p2->z + p3->z)/3.; + else { + gdouble x = p->x - p1->x; + gdouble y = p->y - p1->y; + gdouble a = (x*y2 - y*x2)/det; + gdouble b = (y*x1 - x*y1)/det; + + p->z = (1. - a - b)*p1->z + a*p2->z + b*p3->z; + } +} Index: work/obsolete/toporouter/src_3rd/gts/tribox3.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/tribox3.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/tribox3.c (revision 6803) @@ -0,0 +1,192 @@ +/** + * History: + * 2004-10-27 Stephane Popinet: changed float to double + */ + +/********************************************************/ +/* AABB-triangle overlap test code */ +/* by Tomas Akenine-Möller */ +/* Function: int triBoxOverlap(float boxcenter[3], */ +/* float boxhalfsize[3],float triverts[3][3]); */ +/* History: */ +/* 2001-03-05: released the code in its first version */ +/* 2001-06-18: changed the order of the tests, faster */ +/* */ +/* Acknowledgement: Many thanks to Pierre Terdiman for */ +/* suggestions and discussions on how to optimize code. */ +/* Thanks to David Hunt for finding a ">="-bug! */ +/********************************************************/ +#include +#include + +#define X 0 +#define Y 1 +#define Z 2 + +#define CROSS(dest,v1,v2) \ + dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \ + dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \ + dest[2]=v1[0]*v2[1]-v1[1]*v2[0]; + +#define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]) + +#define SUB(dest,v1,v2) \ + dest[0]=v1[0]-v2[0]; \ + dest[1]=v1[1]-v2[1]; \ + dest[2]=v1[2]-v2[2]; + +#define FINDMINMAX(x0,x1,x2,min,max) \ + min = max = x0; \ + if(x1max) max=x1;\ + if(x2max) max=x2; + +int planeBoxOverlap(double normal[3], double vert[3], double maxbox[3]) // -NJMP- +{ + int q; + double vmin[3],vmax[3],v; + for(q=X;q<=Z;q++) + { + v=vert[q]; // -NJMP- + if(normal[q]>0.0f) + { + vmin[q]=-maxbox[q] - v; // -NJMP- + vmax[q]= maxbox[q] - v; // -NJMP- + } + else + { + vmin[q]= maxbox[q] - v; // -NJMP- + vmax[q]=-maxbox[q] - v; // -NJMP- + } + } + if(DOT(normal,vmin)>0.0f) return 0; // -NJMP- + if(DOT(normal,vmax)>=0.0f) return 1; // -NJMP- + + return 0; +} + + +/*======================== X-tests ========================*/ +#define AXISTEST_X01(a, b, fa, fb) \ + p0 = a*v0[Y] - b*v0[Z]; \ + p2 = a*v2[Y] - b*v2[Z]; \ + if(p0rad || max<-rad) return 0; + +#define AXISTEST_X2(a, b, fa, fb) \ + p0 = a*v0[Y] - b*v0[Z]; \ + p1 = a*v1[Y] - b*v1[Z]; \ + if(p0rad || max<-rad) return 0; + +/*======================== Y-tests ========================*/ +#define AXISTEST_Y02(a, b, fa, fb) \ + p0 = -a*v0[X] + b*v0[Z]; \ + p2 = -a*v2[X] + b*v2[Z]; \ + if(p0rad || max<-rad) return 0; + +#define AXISTEST_Y1(a, b, fa, fb) \ + p0 = -a*v0[X] + b*v0[Z]; \ + p1 = -a*v1[X] + b*v1[Z]; \ + if(p0rad || max<-rad) return 0; + +/*======================== Z-tests ========================*/ + +#define AXISTEST_Z12(a, b, fa, fb) \ + p1 = a*v1[X] - b*v1[Y]; \ + p2 = a*v2[X] - b*v2[Y]; \ + if(p2rad || max<-rad) return 0; + +#define AXISTEST_Z0(a, b, fa, fb) \ + p0 = a*v0[X] - b*v0[Y]; \ + p1 = a*v1[X] - b*v1[Y]; \ + if(p0rad || max<-rad) return 0; + +int triBoxOverlap(double boxcenter[3],double boxhalfsize[3],double triverts[3][3]) +{ + + /* use separating axis theorem to test overlap between triangle and box */ + /* need to test for overlap in these directions: */ + /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */ + /* we do not even need to test these) */ + /* 2) normal of the triangle */ + /* 3) crossproduct(edge from tri, {x,y,z}-directin) */ + /* this gives 3x3=9 more tests */ + double v0[3],v1[3],v2[3]; +// double axis[3]; + double min,max,p0,p1,p2,rad,fex,fey,fez; // -NJMP- "d" local variable removed + double normal[3],e0[3],e1[3],e2[3]; + + /* This is the fastest branch on Sun */ + /* move everything so that the boxcenter is in (0,0,0) */ + SUB(v0,triverts[0],boxcenter); + SUB(v1,triverts[1],boxcenter); + SUB(v2,triverts[2],boxcenter); + + /* compute triangle edges */ + SUB(e0,v1,v0); /* tri edge 0 */ + SUB(e1,v2,v1); /* tri edge 1 */ + SUB(e2,v0,v2); /* tri edge 2 */ + + /* Bullet 3: */ + /* test the 9 tests first (this was faster) */ + fex = fabsf(e0[X]); + fey = fabsf(e0[Y]); + fez = fabsf(e0[Z]); + AXISTEST_X01(e0[Z], e0[Y], fez, fey); + AXISTEST_Y02(e0[Z], e0[X], fez, fex); + AXISTEST_Z12(e0[Y], e0[X], fey, fex); + + fex = fabsf(e1[X]); + fey = fabsf(e1[Y]); + fez = fabsf(e1[Z]); + AXISTEST_X01(e1[Z], e1[Y], fez, fey); + AXISTEST_Y02(e1[Z], e1[X], fez, fex); + AXISTEST_Z0(e1[Y], e1[X], fey, fex); + + fex = fabsf(e2[X]); + fey = fabsf(e2[Y]); + fez = fabsf(e2[Z]); + AXISTEST_X2(e2[Z], e2[Y], fez, fey); + AXISTEST_Y1(e2[Z], e2[X], fez, fex); + AXISTEST_Z12(e2[Y], e2[X], fey, fex); + + /* Bullet 1: */ + /* first test overlap in the {x,y,z}-directions */ + /* find min, max of the triangle each direction, and test for overlap in */ + /* that direction -- this is equivalent to testing a minimal AABB around */ + /* the triangle against the AABB */ + + /* test in X-direction */ + FINDMINMAX(v0[X],v1[X],v2[X],min,max); + if(min>boxhalfsize[X] || max<-boxhalfsize[X]) return 0; + + /* test in Y-direction */ + FINDMINMAX(v0[Y],v1[Y],v2[Y],min,max); + if(min>boxhalfsize[Y] || max<-boxhalfsize[Y]) return 0; + + /* test in Z-direction */ + FINDMINMAX(v0[Z],v1[Z],v2[Z],min,max); + if(min>boxhalfsize[Z] || max<-boxhalfsize[Z]) return 0; + + /* Bullet 2: */ + /* test if the box intersects the plane of the triangle */ + /* compute plane equation of triangle: normal*x+d=0 */ + CROSS(normal,e0,e1); + // -NJMP- (line removed here) + if(!planeBoxOverlap(normal,v0,boxhalfsize)) return 0; // -NJMP- + + return 1; /* box and triangle overlaps */ +} + Index: work/obsolete/toporouter/src_3rd/gts/vertex.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/vertex.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/vertex.c (revision 6803) @@ -0,0 +1,780 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "gts.h" + +gboolean gts_allow_floating_vertices = FALSE; + +static void vertex_destroy (GtsObject * object) +{ + GtsVertex * vertex = GTS_VERTEX (object); + GSList * i; + + i = vertex->segments; + while (i) { + GTS_OBJECT_SET_FLAGS (i->data, GTS_DESTROYED); + i = i->next; + } + i = vertex->segments; + while (i) { + GSList * next = i->next; + gts_object_destroy (i->data); + i = next; + } + g_assert (vertex->segments == NULL); + + (* GTS_OBJECT_CLASS (gts_vertex_class ())->parent_class->destroy) (object); +} + +static void vertex_clone (GtsObject * clone, GtsObject * object) +{ + (* GTS_OBJECT_CLASS (gts_vertex_class ())->parent_class->clone) (clone, + object); + GTS_VERTEX (clone)->segments = NULL; +} + +static void vertex_class_init (GtsVertexClass * klass) +{ + klass->intersection_attributes = NULL; + GTS_OBJECT_CLASS (klass)->clone = vertex_clone; + GTS_OBJECT_CLASS (klass)->destroy = vertex_destroy; +} + +static void vertex_init (GtsVertex * vertex) +{ + vertex->segments = NULL; +} + +/** + * gts_vertex_class: + * + * Returns: the #GtsVertexClass. + */ +GtsVertexClass * gts_vertex_class (void) +{ + static GtsVertexClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo vertex_info = { + "GtsVertex", + sizeof (GtsVertex), + sizeof (GtsVertexClass), + (GtsObjectClassInitFunc) vertex_class_init, + (GtsObjectInitFunc) vertex_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_point_class ()), + &vertex_info); + } + + return klass; +} + +/** + * gts_vertex_new: + * @klass: a #GtsVertexClass. + * @x: the x-coordinate of the vertex to create. + * @y: the y-coordinate of the vertex to create. + * @z: the y-coordinate of the vertex to create. + * + * Returns: a new #GtsVertex with @x, @y and @z as coordinates. + */ +GtsVertex * gts_vertex_new (GtsVertexClass * klass, + gdouble x, gdouble y, gdouble z) +{ + GtsVertex * v; + + v = GTS_VERTEX (gts_object_new (GTS_OBJECT_CLASS (klass))); + gts_point_set (GTS_POINT (v), x, y, z); + + return v; +} + +/** + * gts_vertex_replace: + * @v: a #GtsVertex. + * @with: another #GtsVertex. + * + * Replaces vertex @v with vertex @with. @v and @with must be + * different. All the #GtsSegment which have @v has one of their + * vertices are updated. The segments list of vertex @v is freed and + * @v->segments is set to %NULL. + */ +void gts_vertex_replace (GtsVertex * v, GtsVertex * with) +{ + GSList * i; + + g_return_if_fail (v != NULL); + g_return_if_fail (with != NULL); + g_return_if_fail (v != with); + + i = v->segments; + while (i) { + GtsSegment * s = i->data; + if (s->v1 != with && s->v2 != with) + with->segments = g_slist_prepend (with->segments, s); + if (s->v1 == v) s->v1 = with; + if (s->v2 == v) s->v2 = with; + i = i->next; + } + g_slist_free (v->segments); + v->segments = NULL; +} + +/** + * gts_vertex_is_unattached: + * @v: a #GtsVertex. + * + * Returns: %TRUE if @v is not the endpoint of any #GtsSegment, + * %FALSE otherwise. + */ +gboolean gts_vertex_is_unattached (GtsVertex * v) +{ + g_return_val_if_fail (v != NULL, FALSE); + if (v->segments == NULL) + return TRUE; + return FALSE; +} + +/** + * gts_vertices_are_connected: + * @v1: a #GtsVertex. + * @v2: another #GtsVertex. + * + * Returns: if @v1 and @v2 are the vertices of the same #GtsSegment + * this segment else %NULL. + */ +GtsSegment * gts_vertices_are_connected (GtsVertex * v1, GtsVertex * v2) +{ + GSList * i; + + g_return_val_if_fail (v1 != NULL, FALSE); + g_return_val_if_fail (v2 != NULL, FALSE); + + i = v1->segments; + while (i) { + GtsSegment * s = i->data; + + if (s->v1 == v2 || s->v2 == v2) + return s; + i = i->next; + } + return NULL; +} + +/** + * gts_vertices_from_segments: + * @segments: a list of #GtsSegment. + * + * Returns: a list of #GtsVertex, vertices of a #GtsSegment in @segments. + * Each element in the list is unique (no duplicates). + */ +GSList * gts_vertices_from_segments (GSList * segments) +{ + GHashTable * hash; + GSList * vertices = NULL, * i; + + hash = g_hash_table_new (NULL, NULL); + i = segments; + while (i) { + GtsSegment * s = i->data; + if (g_hash_table_lookup (hash, s->v1) == NULL) { + vertices = g_slist_prepend (vertices, s->v1); + g_hash_table_insert (hash, s->v1, s); + } + if (g_hash_table_lookup (hash, s->v2) == NULL) { + vertices = g_slist_prepend (vertices, s->v2); + g_hash_table_insert (hash, s->v2, s); + } + i = i->next; + } + g_hash_table_destroy (hash); + return vertices; +} + +/** + * gts_vertex_triangles: + * @v: a #GtsVertex. + * @list: a list of #GtsTriangle. + * + * Adds all the #GtsTriangle which share @v as a vertex and do not + * already belong to @list. + * + * Returns: the new list of unique #GtsTriangle which share @v as a + * vertex. + */ +GSList * gts_vertex_triangles (GtsVertex * v, + GSList * list) +{ + GSList * i; + + g_return_val_if_fail (v != NULL, NULL); + + i = v->segments; + while (i) { + GtsSegment * s = i->data; + if (GTS_IS_EDGE (s)) { + GSList * j = GTS_EDGE (s)->triangles; + while (j) { + if (!g_slist_find (list, j->data)) + list = g_slist_prepend (list, j->data); + j = j->next; + } + } + i = i->next; + } + return list; +} + +/** + * gts_vertex_faces: + * @v: a #GtsVertex. + * @surface: a #GtsSurface or %NULL. + * @list: a list of #GtsFace. + * + * Adds all the #GtsFace belonging to @surface (if not %NULL) which share + * @v as a vertex and do not already belong to @list. + * + * Returns: the new list of unique #GtsFace belonging to @surface + * which share @v as a vertex. + */ +GSList * gts_vertex_faces (GtsVertex * v, + GtsSurface * surface, + GSList * list) +{ + GSList * i; + + g_return_val_if_fail (v != NULL, NULL); + + i = v->segments; + while (i) { + GtsSegment * s = i->data; + if (GTS_IS_EDGE (s)) { + GSList * j = GTS_EDGE (s)->triangles; + while (j) { + GtsTriangle * t = j->data; + if (GTS_IS_FACE (t) + && + (!surface || gts_face_has_parent_surface (GTS_FACE (t), surface)) + && + !g_slist_find (list, t)) + list = g_slist_prepend (list, t); + j = j->next; + } + } + i = i->next; + } + return list; +} + +/** + * gts_vertex_neighbors: + * @v: a #GtsVertex. + * @list: a list of #GtsVertex. + * @surface: a #GtsSurface or %NULL. + * + * Adds to @list all the #GtsVertex connected to @v by a #GtsSegment and not + * already in @list. If @surface is not %NULL only the vertices connected to + * @v by an edge belonging to @surface are considered. + * + * Returns: the new list of unique #GtsVertex. + */ +GSList * gts_vertex_neighbors (GtsVertex * v, + GSList * list, + GtsSurface * surface) +{ + GSList * i; + + g_return_val_if_fail (v != NULL, NULL); + + i = v->segments; + while (i) { + GtsSegment * s = i->data; + GtsVertex * v1 = s->v1 == v ? s->v2 : s->v1; + if (v1 != v && + (!surface || + (GTS_IS_EDGE (s) && + gts_edge_has_parent_surface (GTS_EDGE (s), surface))) && + !g_slist_find (list, v1)) + list = g_slist_prepend (list, v1); + i = i->next; + } + return list; +} + +/** + * gts_vertex_is_boundary: + * @v: a #GtsVertex. + * @surface: a #GtsSurface or %NULL. + * + * Returns: %TRUE if @v is used by a #GtsEdge boundary of @surface as + * determined by gts_edge_is_boundary(), %FALSE otherwise. + */ +gboolean gts_vertex_is_boundary (GtsVertex * v, GtsSurface * surface) +{ + GSList * i; + + g_return_val_if_fail (v != NULL, FALSE); + + i = v->segments; + while (i) { + if (GTS_IS_EDGE (i->data) && + gts_edge_is_boundary (i->data, surface)) + return TRUE; + i = i->next; + } + + return FALSE; +} + +/** + * gts_vertices_merge: + * @vertices: a list of #GtsVertex. + * @epsilon: half the size of the bounding box to consider for each vertex. + * @check: function called for each pair of vertices about to be merged + * or %NULL. + * + * For each vertex v in @vertices look if there are any vertex of + * @vertices contained in a box centered on v of size 2*@epsilon. If + * there are and if @check is not %NULL and returns %TRUE, replace + * them with v (using gts_vertex_replace()), destroy them and remove + * them from list. This is done efficiently using Kd-Trees. + * + * Returns: the updated list of vertices. + */ +GList * gts_vertices_merge (GList * vertices, + gdouble epsilon, + gboolean (* check) (GtsVertex *, GtsVertex *)) +{ + GPtrArray * array; + GList * i; + GNode * kdtree; + + g_return_val_if_fail (vertices != NULL, 0); + + array = g_ptr_array_new (); + i = vertices; + while (i) { + g_ptr_array_add (array, i->data); + i = i->next; + } + kdtree = gts_kdtree_new (array, NULL); + g_ptr_array_free (array, TRUE); + + i = vertices; + while (i) { + GtsVertex * v = i->data; + if (!GTS_OBJECT (v)->reserved) { /* Do something only if v is active */ + GtsBBox * bbox; + GSList * selected, * j; + + /* build bounding box */ + bbox = gts_bbox_new (gts_bbox_class (), + v, + GTS_POINT (v)->x - epsilon, + GTS_POINT (v)->y - epsilon, + GTS_POINT (v)->z - epsilon, + GTS_POINT (v)->x + epsilon, + GTS_POINT (v)->y + epsilon, + GTS_POINT (v)->z + epsilon); + + /* select vertices which are inside bbox using kdtree */ + j = selected = gts_kdtree_range (kdtree, bbox, NULL); + while (j) { + GtsVertex * sv = j->data; + if (sv != v && !GTS_OBJECT (sv)->reserved && (!check || (*check) (sv, v))) { + /* sv is not v and is active */ + gts_vertex_replace (sv, v); + GTS_OBJECT (sv)->reserved = sv; /* mark sv as inactive */ + } + j = j->next; + } + g_slist_free (selected); + gts_object_destroy (GTS_OBJECT (bbox)); + } + i = i->next; + } + + gts_kdtree_destroy (kdtree); + + /* destroy inactive vertices and removes them from list */ + + /* we want to control vertex destruction */ + gts_allow_floating_vertices = TRUE; + + i = vertices; + while (i) { + GtsVertex * v = i->data; + GList * next = i->next; + if (GTS_OBJECT (v)->reserved) { /* v is inactive */ + gts_object_destroy (GTS_OBJECT (v)); + vertices = g_list_remove_link (vertices, i); + g_list_free_1 (i); + } + i = next; + } + gts_allow_floating_vertices = FALSE; + + return vertices; +} + +/* returns the list of edges belonging to @surface turning around @v */ +static GSList * edge_fan_list (GtsVertex * v, + GtsSurface * surface, + GtsFace * f, + GtsEdge * e, + GtsFace * first) +{ + GSList * i = e->triangles; + GtsFace * neighbor = NULL; + GtsEdge * next = NULL, * enext = NULL; + + while (i) { + GtsFace * f1 = i->data; + if (GTS_IS_FACE (f1) && + f1 != f && + gts_face_has_parent_surface (f1, surface)) { + g_return_val_if_fail (neighbor == NULL, NULL); /* non-manifold edge */ + neighbor = f1; + } + i = i->next; + } + if (neighbor == NULL || neighbor == first) /* end of fan */ + return NULL; + + if (GTS_TRIANGLE (neighbor)->e1 == e) { + next = GTS_TRIANGLE (neighbor)->e2; + enext = GTS_TRIANGLE (neighbor)->e3; + } + else if (GTS_TRIANGLE (neighbor)->e2 == e) { + next = GTS_TRIANGLE (neighbor)->e3; + enext = GTS_TRIANGLE (neighbor)->e1; + } + else if (GTS_TRIANGLE (neighbor)->e3 == e) { + next = GTS_TRIANGLE (neighbor)->e1; + enext = GTS_TRIANGLE (neighbor)->e2; + } + else + g_assert_not_reached (); + + /* checking for correct orientation */ + g_return_val_if_fail (GTS_SEGMENT (enext)->v1 == v || + GTS_SEGMENT (enext)->v2 == v, NULL); + + return g_slist_prepend (edge_fan_list (v, surface, neighbor, enext, first), + next); +} + +/** + * gts_vertex_fan_oriented: + * @v: a #GtsVertex. + * @surface: a #GtsSurface. + * + * Returns: a list of #GtsEdge describing in counterclockwise order the + * boundary of the fan of summit @v, the faces of the fan belonging to + * @surface. + */ +GSList * gts_vertex_fan_oriented (GtsVertex * v, GtsSurface * surface) +{ + GtsFace * f = NULL; + guint d = 2; + GSList * i; + GtsVertex * v1, * v2, * v3; + GtsEdge * e1, * e2, * e3; + + g_return_val_if_fail (v != NULL, NULL); + g_return_val_if_fail (surface != NULL, NULL); + + i = v->segments; + while (i) { + GtsEdge * e = i->data; + if (GTS_IS_EDGE (e)) { + GSList * j = e->triangles; + GtsFace * f1 = NULL; + guint degree = 0; + while (j) { + if (GTS_IS_FACE (j->data) && + gts_face_has_parent_surface (j->data, surface)) { + f1 = j->data; + degree++; + } + j = j->next; + } + if (f1 != NULL) { + g_return_val_if_fail (degree <= 2, NULL); /* non-manifold edge */ + if (degree == 1) { + gts_triangle_vertices_edges (GTS_TRIANGLE (f1), NULL, + &v1, &v2, &v3, &e1, &e2, &e3); + if (v == v2) { + e2 = e3; + e3 = e1; + } + else if (v == v3) { + e3 = e2; + e2 = e1; + } + if (e3 != e) { + d = 1; + f = f1; + } + } + else if (degree <= d) + f = f1; + } + } + i = i->next; + } + + if (f == NULL) + return NULL; + + gts_triangle_vertices_edges (GTS_TRIANGLE (f), NULL, + &v1, &v2, &v3, &e1, &e2, &e3); + if (v == v2) { + e2 = e3; + e3 = e1; + } + else if (v == v3) { + e3 = e2; + e2 = e1; + } + + return g_slist_prepend (edge_fan_list (v, surface, f, e3, f), e2); +} + +#define edge_use_vertex(e, v) (GTS_SEGMENT(e)->v1 == v ||\ + GTS_SEGMENT(e)->v2 == v) + +static GtsEdge * replace_vertex (GtsTriangle * t, + GtsEdge * e1, + GtsVertex * v, + GtsVertex * with) +{ + GtsEdge * e = NULL; + + if (t->e1 != e1 && edge_use_vertex (t->e1, v)) + e = t->e1; + else if (t->e2 != e1 && edge_use_vertex (t->e2, v)) + e = t->e2; + else if (t->e3 != e1 && edge_use_vertex (t->e3, v)) + e = t->e3; + else + return NULL; + + if (with != v) { + GtsSegment * s = GTS_SEGMENT (e); + if (s->v1 == v) s->v1 = with; + if (s->v2 == v) s->v2 = with; + with->segments = g_slist_prepend (with->segments, s); + v->segments = g_slist_remove (v->segments, s); + } + + return e; +} + +static void triangle_next (GtsEdge * e, GtsVertex * v, GtsVertex * with) +{ + GSList * i; + + if (e == NULL) + return; + + i = e->triangles; + while (i) { + GtsTriangle * t = i->data; + if (GTS_OBJECT (t)->reserved) { + GTS_OBJECT (t)->reserved = NULL; + triangle_next (replace_vertex (t, e, v, with), v, with); + } + i = i->next; + } +} + +/** + * gts_vertex_is_contact: + * @v: a #GtsVertex. + * @sever: if %TRUE and if @v is a contact vertex between two or more + * sets of connected triangles replaces it with as many vertices, + * clones of @v. + * + * Returns: the number of sets of connected triangles sharing @v as a + * contact vertex. + */ +guint gts_vertex_is_contact (GtsVertex * v, gboolean sever) +{ + GSList * triangles, * i; + GtsVertex * with = v; + guint ncomponent = 0; + + g_return_val_if_fail (v != NULL, 0); + + triangles = gts_vertex_triangles (v, NULL); + i = triangles; + while (i) { + GTS_OBJECT (i->data)->reserved = i; + i = i->next; + } + + i = triangles; + while (i) { + GtsTriangle * t = i->data; + if (GTS_OBJECT (t)->reserved) { + GtsEdge * e; + if (ncomponent && sever) + with = GTS_VERTEX (gts_object_clone (GTS_OBJECT (v))); + GTS_OBJECT (t)->reserved = NULL; + e = replace_vertex (t, NULL, v, with); + triangle_next (e, v, with); + triangle_next (replace_vertex (t, e, v, with), v, with); + ncomponent++; + } + i = i->next; + } + g_slist_free (triangles); + + return ncomponent; +} + +/* GtsVertexNormal: Object */ + +static void vertex_normal_attributes (GtsVertex * v, + GtsObject * e, + GtsObject * t) +{ + g_return_if_fail (GTS_IS_EDGE (e)); + g_return_if_fail (GTS_IS_TRIANGLE (t)); + + if (GTS_IS_VERTEX_NORMAL (GTS_SEGMENT (e)->v1) && + GTS_IS_VERTEX_NORMAL (GTS_SEGMENT (e)->v2)) { + GtsPoint * p1 = GTS_POINT (GTS_SEGMENT (e)->v1); + GtsPoint * p2 = GTS_POINT (GTS_SEGMENT (e)->v2); + GtsPoint * p = GTS_POINT (v); + gdouble a, b, lambda; + guint i; + + a = p2->x - p1->x; b = p->x - p1->x; + if (fabs (p2->y - p1->y) > fabs (a)) { + a = p2->y - p1->y; b = p->y - p1->y; + } + if (fabs (p2->z - p1->z) > fabs (a)) { + a = p2->z - p1->z; b = p->z - p1->z; + } + lambda = a != 0. ? b/a : 0.; + for (i = 0; i < 3; i++) + GTS_VERTEX_NORMAL (v)->n[i] = + (1. - lambda)*GTS_VERTEX_NORMAL (GTS_SEGMENT (e)->v1)->n[i] + + lambda*GTS_VERTEX_NORMAL (GTS_SEGMENT (e)->v2)->n[i]; + } + else { + GtsVertex * v1, * v2, * v3; + + gts_triangle_vertices (GTS_TRIANGLE (t), &v1, &v2, &v3); + if (GTS_IS_VERTEX_NORMAL (v1) && + GTS_IS_VERTEX_NORMAL (v2) && + GTS_IS_VERTEX_NORMAL (v3)) { + GtsVector a1, a2, a3, det; + guint i, j = 0; + gdouble l1, l2; + + gts_vector_init (a1, GTS_POINT (v1), GTS_POINT (v)); + gts_vector_init (a2, GTS_POINT (v1), GTS_POINT (v2)); + gts_vector_init (a3, GTS_POINT (v1), GTS_POINT (v3)); + gts_vector_cross (det, a2, a3); + if (fabs (det[1]) > fabs (det[0])) j = 1; + if (fabs (det[2]) > fabs (det[j])) j = 2; + if (det[j] == 0.) { + g_warning ("vertex_normal_attributes: det[%d] == 0.", j); + return; + } + switch (j) { + case 0: + l1 = (a1[1]*a3[2] - a1[2]*a3[1])/det[0]; + l2 = (a1[2]*a2[1] - a1[1]*a2[2])/det[0]; + break; + case 1: + l1 = (a1[2]*a3[0] - a1[0]*a3[2])/det[1]; + l2 = (a1[0]*a2[2] - a1[2]*a2[0])/det[1]; + break; + case 2: + l1 = (a1[0]*a3[1] - a1[1]*a3[0])/det[2]; + l2 = (a1[1]*a2[0] - a1[0]*a2[1])/det[2]; + break; + default: + l1 = l2 = 0.; + } + for (i = 0; i < 3; i++) + GTS_VERTEX_NORMAL (v)->n[i] = + GTS_VERTEX_NORMAL (v1)->n[i]*(1. - l1 - l2) + + GTS_VERTEX_NORMAL (v2)->n[i]*l1 + + GTS_VERTEX_NORMAL (v3)->n[i]*l2; + } + } +} + +static void gts_vertex_normal_class_init (GtsVertexClass * klass) +{ + klass->intersection_attributes = vertex_normal_attributes; +} + +GtsVertexClass * gts_vertex_normal_class (void) +{ + static GtsVertexClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo gts_vertex_normal_info = { + "GtsVertexNormal", + sizeof (GtsVertexNormal), + sizeof (GtsVertexClass), + (GtsObjectClassInitFunc) gts_vertex_normal_class_init, + (GtsObjectInitFunc) NULL, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_vertex_class ()), + >s_vertex_normal_info); + } + + return klass; +} + +/* GtsColorVertex: Object */ + +GtsVertexClass * gts_color_vertex_class (void) +{ + static GtsVertexClass * klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo gts_color_vertex_info = { + "GtsColorVertex", + sizeof (GtsColorVertex), + sizeof (GtsVertexClass), + (GtsObjectClassInitFunc) NULL, + (GtsObjectInitFunc) NULL, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = gts_object_class_new (GTS_OBJECT_CLASS (gts_vertex_class ()), + >s_color_vertex_info); + } + + return klass; +} + Index: work/obsolete/toporouter/src_3rd/gts/vopt.c =================================================================== --- work/obsolete/toporouter/src_3rd/gts/vopt.c (nonexistent) +++ work/obsolete/toporouter/src_3rd/gts/vopt.c (revision 6803) @@ -0,0 +1,521 @@ +/* GTS - Library for the manipulation of triangulated surfaces + * Copyright (C) 1999 Stéphane Popinet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gts.h" + +/* #define DEBUG_VOPT */ + +/* compute the normal (nx, ny, nz) as the cross-product of the first two + oriented edges and the norm nt = |t| as (v1xv2).v3 */ +static void triangle_normal (GtsTriangle * t, + gdouble * nx, + gdouble * ny, + gdouble * nz, + gdouble * nt) +{ + GtsPoint * p1, * p2 = NULL, * p3 = NULL; + gdouble x1, y1, z1, x2, y2, z2; + + g_return_if_fail (t != NULL); + + p1 = GTS_POINT (GTS_SEGMENT (t->e1)->v1); + if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v1) { + p2 = GTS_POINT (GTS_SEGMENT (t->e2)->v2); + p3 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); + } + else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v2) { + p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); + p3 = GTS_POINT (GTS_SEGMENT (t->e2)->v1); + } + else if (GTS_SEGMENT (t->e1)->v1 == GTS_SEGMENT (t->e2)->v2) { + p2 = GTS_POINT (GTS_SEGMENT (t->e2)->v1); + p3 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); + } + else if (GTS_SEGMENT (t->e1)->v2 == GTS_SEGMENT (t->e2)->v1) { + p2 = GTS_POINT (GTS_SEGMENT (t->e1)->v2); + p3 = GTS_POINT (GTS_SEGMENT (t->e2)->v2); + } + else + g_assert_not_reached (); + + x1 = p2->x - p1->x; + y1 = p2->y - p1->y; + z1 = p2->z - p1->z; + + x2 = p3->x - p1->x; + y2 = p3->y - p1->y; + z2 = p3->z - p1->z; + + *nt = ((p1->y*p2->z - p1->z*p2->y)*p3->x + + (p1->z*p2->x - p1->x*p2->z)*p3->y + + (p1->x*p2->y - p1->y*p2->x)*p3->z); + *nx = y1*z2 - z1*y2; + *ny = z1*x2 - x1*z2; + *nz = x1*y2 - y1*x2; +} + +static void boundary_preservation (GtsEdge * edge, + GtsFace * f, + GtsVector e1, GtsVector e2, + GtsMatrix * H, GtsVector c) +{ + GtsTriangle * t = GTS_TRIANGLE (f); + GtsEdge * edge2; + GtsVertex * v1 = GTS_SEGMENT (edge)->v1, * v2 = GTS_SEGMENT (edge)->v2; + GtsPoint * p1, * p2; + GtsVector e, e3; + + /* find orientation of segment */ + edge2 = edge == t->e1 ? t->e2 : edge == t->e2 ? t->e3 : t->e1; + if (v2 != GTS_SEGMENT (edge2)->v1 && v2 != GTS_SEGMENT (edge2)->v2) { + v2 = v1; v1 = GTS_SEGMENT (edge)->v2; + } + p1 = GTS_POINT (v1); + p2 = GTS_POINT (v2); + + e[0] = p2->x - p1->x; + e[1] = p2->y - p1->y; + e[2] = p2->z - p1->z; + + e1[0] += e[0]; + e1[1] += e[1]; + e1[2] += e[2]; + + e3[0] = p2->y*p1->z - p2->z*p1->y; + e3[1] = p2->z*p1->x - p2->x*p1->z; + e3[2] = p2->x*p1->y - p2->y*p1->x; + + e2[0] += e3[0]; + e2[1] += e3[1]; + e2[2] += e3[2]; + + H[0][0] += e[1]*e[1] + e[2]*e[2]; + H[0][1] -= e[0]*e[1]; + H[0][2] -= e[0]*e[2]; + H[1][0] = H[0][1]; + H[1][1] += e[0]*e[0] + e[2]*e[2]; + H[1][2] -= e[1]*e[2]; + H[2][0] = H[0][2]; + H[2][1] = H[1][2]; + H[2][2] += e[0]*e[0] + e[1]*e[1]; + + c[0] += e[1]*e3[2] - e[2]*e3[1]; + c[1] += e[2]*e3[0] - e[0]*e3[2]; + c[2] += e[0]*e3[1] - e[1]*e3[0]; +} + +static gdouble boundary_cost (GtsEdge * edge, + GtsFace * f, + GtsVertex * v) +{ + GtsTriangle * t = GTS_TRIANGLE (f); + GtsEdge * edge2; + GtsVertex * v1 = GTS_SEGMENT (edge)->v1, * v2 = GTS_SEGMENT (edge)->v2; + GtsPoint * p1, * p2; + GtsVector e; + GtsPoint * p = GTS_POINT (v); + + /* find orientation of segment */ + edge2 = edge == t->e1 ? t->e2 : edge == t->e2 ? t->e3 : t->e1; + if (v2 != GTS_SEGMENT (edge2)->v1 && v2 != GTS_SEGMENT (edge2)->v2) { + v2 = v1; v1 = GTS_SEGMENT (edge)->v2; + } + p1 = GTS_POINT (v1); + p2 = GTS_POINT (v2); + + e[0] = (p2->y - p1->y)*(p->z - p2->z) - (p2->z - p1->z)*(p->y - p2->y); + e[1] = (p2->z - p1->z)*(p->x - p2->x) - (p2->x - p1->x)*(p->z - p2->z); + e[2] = (p2->x - p1->x)*(p->y - p2->y) - (p2->y - p1->y)*(p->x - p2->x); + + return e[0]*e[0] + e[1]*e[1] + e[2]*e[2]; +} + +static gdouble edge_boundary_cost (GtsEdge * e, GtsVertex * v) +{ + gdouble cost = 0.; + GSList * i; + + i = GTS_SEGMENT (e)->v1->segments; + while (i) { + GtsFace * f; + if (GTS_IS_EDGE (i->data) && + (f = gts_edge_is_boundary (i->data, NULL))) + cost += boundary_cost (i->data, f, v); + i = i->next; + } + i = GTS_SEGMENT (e)->v2->segments; + while (i) { + GtsFace * f; + if (i->data != e && + GTS_IS_EDGE (i->data) && + (f = gts_edge_is_boundary (i->data, NULL))) + cost += boundary_cost (i->data, f, v); + i = i->next; + } + + return cost/4.; +} + +static gdouble edge_volume_cost (GtsEdge * e, GtsVertex * v) +{ + GSList * i, * triangles; + gdouble n1, n2, n3, nt; + gdouble cost = 0.0, a; + + triangles = gts_vertex_triangles (GTS_SEGMENT (e)->v1, NULL); + triangles = gts_vertex_triangles (GTS_SEGMENT (e)->v2, triangles); + + i = triangles; + while (i) { + if (GTS_IS_FACE (i->data)) { + triangle_normal (i->data, &n1, &n2, &n3, &nt); + a = GTS_POINT (v)->x*n1 + + GTS_POINT (v)->y*n2 + + GTS_POINT (v)->z*n3 - nt; + cost += a*a; + } + i = i->next; + } + g_slist_free (triangles); + + return cost/36.; +} + +static gdouble edge_shape_cost (GtsEdge * e, GtsVertex * v) +{ + GSList * list, * i; + GtsVertex + * v1 = GTS_SEGMENT (e)->v1, + * v2 = GTS_SEGMENT (e)->v2; + gdouble cost = 0.; + + list = gts_vertex_neighbors (v1, NULL, NULL); + list = gts_vertex_neighbors (v2, list, NULL); + i = list; + while (i) { + GtsPoint * p = i->data; + if (p != GTS_POINT (v1) && p != GTS_POINT (v2)) + cost += gts_point_distance2 (p, GTS_POINT (v)); + i = i->next; + } + g_slist_free (list); + + return cost; +} + +/** + * gts_volume_optimized_vertex: + * @edge: a #GtsEdge. + * @klass: a #GtsVertexClass to be used for the new vertex. + * @params: a #GtsVolumeOptimizedParms. + * + * Returns: a #GtsVertex which can be used to replace @edge for an + * edge collapse operation. The position of the vertex is optimized in + * order to minimize the changes in area and volume for the surface + * using @edge. The volume enclosed by the surface is locally + * preserved. For more details see "Fast and memory efficient + * polygonal simplification" (1998) and "Evaluation of memoryless + * simplification" (1999) by Lindstrom and Turk. + */ +GtsVertex * gts_volume_optimized_vertex (GtsEdge * edge, + GtsVertexClass * klass, + GtsVolumeOptimizedParams * params) +{ + GSList * triangles, * i; + gdouble sn1 = 0., sn2 = 0., sn3 = 0.; + gdouble sn11 = 0., sn22 = 0., sn33 = 0.; + gdouble sn12 = 0., sn13 = 0., sn23 = 0.; + gdouble st = 0., stn1 = 0., stn2 = 0., stn3 = 0.; + gdouble n1, n2, n3, nt; + GtsMatrix * A, * Ai; + GtsVector A1, b; + GtsVector e1 = {0., 0., 0.}, e2 = {0., 0., 0.}; + GtsMatrix * Hb; + GtsVector cb = {0., 0., 0.}; + GtsVertex * v; + GtsVertex * v1, * v2; + guint n = 0, nb = 0; +#ifdef DEBUG_VOPT + guint nold = 0; +#endif + + g_return_val_if_fail (edge != NULL, NULL); + g_return_val_if_fail (klass != NULL, NULL); + g_return_val_if_fail (params != NULL, NULL); + + A = gts_matrix_zero (NULL); + Hb = gts_matrix_zero (NULL); + v1 = GTS_SEGMENT (edge)->v1; + v2 = GTS_SEGMENT (edge)->v2; + + /* boundary preservation */ + i = v1->segments; + while (i) { + GtsEdge * edge1 = i->data; + GtsFace * f; + if (GTS_IS_EDGE (edge1) && + (f = gts_edge_is_boundary (edge1, NULL))) { + boundary_preservation (edge1, f, e1, e2, Hb, cb); + nb++; + } + i = i->next; + } + i = v2->segments; + while (i) { + GtsEdge * edge1 = i->data; + GtsFace * f; + if (edge1 != edge && + GTS_IS_EDGE (edge1) && + (f = gts_edge_is_boundary (edge1, NULL))) { + boundary_preservation (edge1, f, e1, e2, Hb, cb); + nb++; + } + i = i->next; + } + if (nb > 0) { + GtsMatrix * H = gts_matrix_new ( + e1[2]*e1[2] + e1[1]*e1[1], - e1[0]*e1[1], - e1[0]*e1[2], 0., + - e1[0]*e1[1], e1[2]*e1[2] + e1[0]*e1[0], - e1[1]*e1[2], 0., + - e1[0]*e1[2], - e1[1]*e1[2], e1[1]*e1[1] + e1[0]*e1[0], 0., + 0., 0., 0., 0.); + GtsVector c; + + c[0] = e1[1]*e2[2] - e1[2]*e2[1]; + c[1] = e1[2]*e2[0] - e1[0]*e2[2]; + c[2] = e1[0]*e2[1] - e1[1]*e2[0]; + n = gts_matrix_quadratic_optimization (A, b, n, H, c); + gts_matrix_destroy (H); + } + + g_assert (n <= 2); + +#ifdef DEBUG_VOPT + if (n != nold) { + fprintf (stderr, "--- boundary preservation ---\n"); + gts_matrix_print (A, stderr); + gts_vector_print (b, stderr); + nold = n; + } +#endif + + /* volume preservation */ + triangles = gts_vertex_triangles (v1, NULL); + triangles = gts_vertex_triangles (v2, triangles); + + i = triangles; + while (i) { + if (GTS_IS_FACE (i->data)) { + triangle_normal (i->data, &n1, &n2, &n3, &nt); + sn1 += n1; sn2 += n2; sn3 += n3; + sn11 += n1*n1; sn22 += n2*n2; sn33 += n3*n3; + sn12 += n1*n2; sn13 += n1*n3; sn23 += n2*n3; + st += nt; stn1 += nt*n1; stn2 += nt*n2; stn3 += nt*n3; + } + i = i->next; + } + g_slist_free (triangles); + + A1[0] = sn1; A1[1] = sn2; A1[2] = sn3; + n = gts_matrix_compatible_row (A, b, n, A1, st); + +#ifdef DEBUG_VOPT + if (n != nold) { + fprintf (stderr, "--- volume preservation ---\n"); + gts_matrix_print (A, stderr); + gts_vector_print (b, stderr); + nold = n; + } +#endif + +#if 1 /* Weighted average of volume and boundary optimization */ + if (n < 3) { + /* volume optimization and boundary optimization */ + GtsMatrix * H = gts_matrix_new (sn11, sn12, sn13, 0., + sn12, sn22, sn23, 0., + sn13, sn23, sn33, 0., + 0., 0., 0., 0.); + GtsVector c; + gdouble le = 9.*params->boundary_weight* + gts_point_distance2 (GTS_POINT (v1), + GTS_POINT (v2)); + guint i, j; + + c[0] = - stn1; c[1] = - stn2; c[2] = - stn3; + if (nb > 0) + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) + H[i][j] = params->volume_weight*H[i][j] + le*Hb[i][j]; + c[i] = params->volume_weight*c[i] + le*cb[i]; + } + n = gts_matrix_quadratic_optimization (A, b, n, H, c); + gts_matrix_destroy (H); + } + +#ifdef DEBUG_VOPT + if (n != nold) { + fprintf (stderr, "--- volume and boundary optimization ---\n"); + gts_matrix_print (A, stderr); + gts_vector_print (b, stderr); + nold = n; + } +#endif + + if (n < 3) { + /* triangle shape optimization */ + gdouble nv = 0.0; + GtsMatrix * H; + GtsVector c = {0., 0., 0.}; + GSList * list, * i; + + list = gts_vertex_neighbors (v1, NULL, NULL); + list = gts_vertex_neighbors (v2, list, NULL); + + i = list; + while (i) { + GtsPoint * p1 = i->data; + if (p1 != GTS_POINT (v1) && p1 != GTS_POINT (v2)) { + nv += 1.0; + c[0] -= p1->x; + c[1] -= p1->y; + c[2] -= p1->z; + } + i = i->next; + } + g_slist_free (list); + + H = gts_matrix_new (nv, 0., 0., 0., + 0., nv, 0., 0., + 0., 0., nv, 0., + 0., 0., 0., 0.); + n = gts_matrix_quadratic_optimization (A, b, n, H, c); + gts_matrix_destroy (H); + } + +#ifdef DEBUG_VOPT + if (n != nold) { + fprintf (stderr, "--- triangle shape optimization ---\n"); + gts_matrix_print (A, stderr); + gts_vector_print (b, stderr); + nold = n; + } +#endif +#else /* Weighted average of volume, boundary and shape optimization */ + if (n < 3) { + /* volume optimization, boundary and shape optimization */ + GtsMatrix * H; + GtsVector c; + gdouble l2 = gts_point_distance2 (GTS_POINT (v1), + GTS_POINT (v2)); + gdouble wv = params->volume_weight/32.; + gdouble wb = params->boundary_weight/4.*l2; + gdouble ws = params->shape_weight*l2*l2; + + gdouble nv = 0.0; + GtsVector cs = {0., 0., 0.}; + GSList * list, * i; + + list = gts_vertex_neighbors (v1, NULL, NULL); + list = gts_vertex_neighbors (v2, list, NULL); + + i = list; + while (i) { + GtsPoint * p1 = i->data; + if (p1 != GTS_POINT (v1) && p1 != GTS_POINT (v2)) { + nv += 1.0; + cs[0] -= p1->x; + cs[1] -= p1->y; + cs[2] -= p1->z; + } + i = i->next; + } + g_slist_free (list); + + H = gts_matrix_new (wv*sn11 + wb*Hb[0][0] + ws*nv, + wv*sn12 + wb*Hb[0][1], + wv*sn13 + wb*Hb[0][2], + wv*sn12 + wb*Hb[1][0], + wv*sn22 + wb*Hb[1][1] + ws*nv, + wv*sn23 + wb*Hb[1][2], + wv*sn13 + wb*Hb[2][0], + wv*sn23 + wb*Hb[2][1], + wv*sn33 + wb*Hb[2][2] + ws*nv); + + c[0] = - wv*stn1 + wb*cb[0] + ws*cs[0]; + c[1] = - wv*stn2 + wb*cb[1] + ws*cs[1]; + c[2] = - wv*stn3 + wb*cb[2] + ws*cs[2]; + + n = gts_matrix_quadratic_optimization (A, b, n, H, c); + gts_matrix_destroy (H); + } + +#ifdef DEBUG_VOPT + if (n != nold) { + fprintf (stderr, "--- volume, boundary and shape optimization ---\n"); + gts_matrix_print (A, stderr); + gts_vector_print (b, stderr); + nold = n; + } +#endif +#endif /* Weighted average of volume, boundary and shape optimization */ + + g_assert (n == 3); + g_assert ((Ai = gts_matrix3_inverse (A))); + + v = gts_vertex_new (klass, + Ai[0][0]*b[0] + Ai[0][1]*b[1] + Ai[0][2]*b[2], + Ai[1][0]*b[0] + Ai[1][1]*b[1] + Ai[1][2]*b[2], + Ai[2][0]*b[0] + Ai[2][1]*b[1] + Ai[2][2]*b[2]); + + gts_matrix_destroy (A); + gts_matrix_destroy (Ai); + gts_matrix_destroy (Hb); + + return v; +} + +/** + * gts_volume_optimized_cost: + * @e: a #GtsEdge. + * @params: a #GtsVolumeOptimizedParams. + * + * Returns: the cost for the collapse of @e as minimized by the function + * gts_volume_optimized_vertex(). + */ +gdouble gts_volume_optimized_cost (GtsEdge * e, + GtsVolumeOptimizedParams * params) +{ + GtsVertex * v; + gdouble cost; + gdouble length2; + + g_return_val_if_fail (e != NULL, G_MAXDOUBLE); + g_return_val_if_fail (params != NULL, G_MAXDOUBLE); + + v = gts_volume_optimized_vertex (e, gts_vertex_class (), params); + + length2 = gts_point_distance2 (GTS_POINT (GTS_SEGMENT (e)->v1), + GTS_POINT (GTS_SEGMENT (e)->v2)); + cost = + params->volume_weight*edge_volume_cost (e, v) + + params->boundary_weight*length2*edge_boundary_cost (e, v) + + params->shape_weight*length2*length2*edge_shape_cost (e, v); + gts_object_destroy (GTS_OBJECT (v)); + + return cost; +} Index: work/obsolete/toporouter/src_plugins/toporouter/Makefile =================================================================== --- work/obsolete/toporouter/src_plugins/toporouter/Makefile (nonexistent) +++ work/obsolete/toporouter/src_plugins/toporouter/Makefile (revision 6803) @@ -0,0 +1,6 @@ +all: + cd ../../src && $(MAKE) mod_toporouter + +clean: + rm *.o *.so 2>/dev/null ; true + Index: work/obsolete/toporouter/src_plugins/toporouter/Plug.tmpasm =================================================================== --- work/obsolete/toporouter/src_plugins/toporouter/Plug.tmpasm (nonexistent) +++ work/obsolete/toporouter/src_plugins/toporouter/Plug.tmpasm (revision 6803) @@ -0,0 +1,28 @@ +put /local/pcb/mod {toporouter} +put /local/pcb/mod/OBJS [@ $(PLUGDIR)/toporouter/toporouter.o @] + + +put /local/pcb/toporouter_rules [@ +../src_3rd/gts/libgts.a: + cd ../src_3rd/gts && make +@] + +switch /local/pcb/toporouter/controls + case {buildin} + append /local/pcb/CFLAGS {-I../src_3rd/gts} + append /local/pcb/RULES /local/pcb/toporouter_rules + append /local/pcb/LIBS { ../src_3rd/gts/libgts.a } + append /local/pcb/EXEDEPS { ../src_3rd/gts/libgts.a } + include /local/pcb/tmpasm/buildin + end; + case {plugin} + append /local/mod/CFLAGS {-I../src_3rd/gts} + append /local/pcb/RULES /local/pcb/toporouter_rules + append /local/pcb/toporouter/OBJS { ../src_3rd/gts/libgts.a } + include /local/pcb/tmpasm/plugin + end + case {disable} + put /local/pcb/mod/OBJS {} + include /local/pcb/tmpasm/disable + end +end Index: work/obsolete/toporouter/src_plugins/toporouter/README =================================================================== --- work/obsolete/toporouter/src_plugins/toporouter/README (nonexistent) +++ work/obsolete/toporouter/src_plugins/toporouter/README (revision 6803) @@ -0,0 +1,7 @@ +Automatically route selected or all rats using a topological algorithm. This +is the new autorouter from 2009. + +#state: fails +#lstate: infinite loop in gts +#default: disabled +#implements: (feature) Index: work/obsolete/toporouter/src_plugins/toporouter/toporouter.c =================================================================== --- work/obsolete/toporouter/src_plugins/toporouter/toporouter.c (nonexistent) +++ work/obsolete/toporouter/src_plugins/toporouter/toporouter.c (revision 6803) @@ -0,0 +1,8249 @@ +/* + * COPYRIGHT + * + * Topological Autorouter for + * PCB, interactive printed circuit board design + * Copyright (C) 2009 Anthony Blake + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Contact addresses for email: + * Anthony Blake, tonyb33@gmail.com + * + * + * + * This is *EXPERIMENTAL* code. + * + * As the code is experimental, the algorithms and code + * are likely to change. Which means it isn't documented + * or optimized. If you would like to learn about Topological + * Autorouters, the following papers are good starting points: + * + * This file implements a topological autorouter, and uses techniques from the + * following publications: + * + * Dayan, T. and Dai, W.W.M., "Layer Assignment for a Rubber Band Router" Tech + * Report UCSC-CRL-92-50, Univ. of California, Santa Cruz, 1992. + * + * Dai, W.W.M and Dayan, T. and Staepelaere, D., "Topological Routing in SURF: + * Generating a Rubber-Band Sketch" Proc. 28th ACM/IEEE Design Automation + * Conference, 1991, pp. 39-44. + * + * David Staepelaere, Jeffrey Jue, Tal Dayan, Wayne Wei-Ming Dai, "SURF: + * Rubber-Band Routing System for Multichip Modules," IEEE Design and Test of + * Computers ,vol. 10, no. 4, pp. 18-26, October/December, 1993. + * + * Dayan, T., "Rubber-band based topological router" PhD Thesis, Univ. of + * California, Santa Cruz, 1997. + * + * David Staepelaere, "Geometric transformations for a rubber-band sketch" + * Master's thesis, Univ. of California, Santa Cruz, September 1992. + * + */ + +#include "config.h" +#include "toporouter.h" +#include "pcb-printf.h" +#include "compat_nls.h" + +static void toporouter_edge_init(toporouter_edge_t * edge) +{ + edge->routing = NULL; + edge->flags = 0; +} + +toporouter_edge_class_t *toporouter_edge_class(void) +{ + static toporouter_edge_class_t *klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo constraint_info = { + "toporouter_edge_t", + sizeof(toporouter_edge_t), + sizeof(toporouter_edge_class_t), + (GtsObjectClassInitFunc) NULL, + (GtsObjectInitFunc) toporouter_edge_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = (toporouter_edge_class_t *) gts_object_class_new(GTS_OBJECT_CLASS(gts_edge_class()), &constraint_info); + } + + return klass; +} + +static void toporouter_bbox_init(toporouter_bbox_t * box) +{ + box->data = NULL; + box->type = OTHER; + box->constraints = NULL; + box->cluster = NULL; +} + +toporouter_bbox_class_t *toporouter_bbox_class(void) +{ + static toporouter_bbox_class_t *klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo constraint_info = { + "toporouter_bbox_t", + sizeof(toporouter_bbox_t), + sizeof(toporouter_bbox_class_t), + (GtsObjectClassInitFunc) NULL, + (GtsObjectInitFunc) toporouter_bbox_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = (toporouter_bbox_class_t *) gts_object_class_new(GTS_OBJECT_CLASS(gts_bbox_class()), &constraint_info); + } + + return klass; +} + +static void toporouter_vertex_class_init(toporouter_vertex_class_t * klass) +{ + +} + +static void toporouter_vertex_init(toporouter_vertex_t * vertex) +{ + vertex->bbox = NULL; + vertex->parent = NULL; + vertex->child = NULL; + vertex->flags = 0; + vertex->routingedge = NULL; + vertex->arc = NULL; + vertex->oproute = NULL; + vertex->route = NULL; + + vertex->gcost = 0.; + vertex->hcost = 0.; + vertex->gn = 0; +} + +toporouter_vertex_class_t *toporouter_vertex_class(void) +{ + static toporouter_vertex_class_t *klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo constraint_info = { + "toporouter_vertex_t", + sizeof(toporouter_vertex_t), + sizeof(toporouter_vertex_class_t), + (GtsObjectClassInitFunc) toporouter_vertex_class_init, + (GtsObjectInitFunc) toporouter_vertex_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = (toporouter_vertex_class_t *) gts_object_class_new(GTS_OBJECT_CLASS(gts_vertex_class()), &constraint_info); + } + + return klass; +} + +static void toporouter_constraint_class_init(toporouter_constraint_class_t * klass) +{ + +} + +static void toporouter_constraint_init(toporouter_constraint_t * constraint) +{ + constraint->box = NULL; + constraint->routing = NULL; +} + +toporouter_constraint_class_t *toporouter_constraint_class(void) +{ + static toporouter_constraint_class_t *klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo constraint_info = { + "toporouter_constraint_t", + sizeof(toporouter_constraint_t), + sizeof(toporouter_constraint_class_t), + (GtsObjectClassInitFunc) toporouter_constraint_class_init, + (GtsObjectInitFunc) toporouter_constraint_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = (toporouter_constraint_class_t *) gts_object_class_new(GTS_OBJECT_CLASS(gts_constraint_class()), &constraint_info); + } + + return klass; +} + +static void toporouter_arc_init(toporouter_arc_t * arc) +{ + arc->x0 = -1.; + arc->y0 = -1.; + arc->x1 = -1.; + arc->y1 = -1.; + arc->centre = NULL; + arc->v = NULL; + arc->v1 = NULL; + arc->v2 = NULL; + arc->r = -1.; + arc->dir = 31337; + arc->clearance = NULL; + arc->oproute = NULL; +} + +toporouter_arc_class_t *toporouter_arc_class(void) +{ + static toporouter_arc_class_t *klass = NULL; + + if (klass == NULL) { + GtsObjectClassInfo constraint_info = { + "toporouter_arc_t", + sizeof(toporouter_arc_t), + sizeof(toporouter_arc_class_t), + (GtsObjectClassInitFunc) NULL, + (GtsObjectInitFunc) toporouter_arc_init, + (GtsArgSetFunc) NULL, + (GtsArgGetFunc) NULL + }; + klass = (toporouter_arc_class_t *) gts_object_class_new(GTS_OBJECT_CLASS(gts_constraint_class()), &constraint_info); + } + + return klass; +} + +#define MARGIN 10.0f + +drawing_context_t *toporouter_output_init(int w, int h, char *filename) +{ + drawing_context_t *dc; + + dc = (drawing_context_t *) malloc(sizeof(drawing_context_t)); + + dc->iw = w; + dc->ih = h; + dc->filename = filename; + + /* Calculate scaling to maintain aspect ratio */ + if (PCB->MaxWidth > PCB->MaxHeight) { + /* Scale board width to match image width minus 2xMARGIN */ + dc->s = ((double) dc->iw - (2 * MARGIN)) / (double) PCB->MaxWidth; + dc->ih = (double) PCB->MaxHeight * dc->s + (2 * MARGIN); + } + else { + /* Scale board height to match image height minus 2xMARGIN */ + dc->s = ((double) dc->ih - (2 * MARGIN)) / (double) PCB->MaxHeight; + dc->iw = (double) PCB->MaxWidth * dc->s + (2 * MARGIN); + } + +#if TOPO_OUTPUT_ENABLED + dc->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, dc->iw, dc->ih); + dc->cr = cairo_create(dc->surface); + + cairo_rectangle(dc->cr, 0, 0, dc->iw, dc->ih); + cairo_set_source_rgb(dc->cr, 0, 0, 0); + cairo_fill(dc->cr); + +#endif + + return dc; +} + +void toporouter_output_close(drawing_context_t * dc) +{ +#if TOPO_OUTPUT_ENABLED + cairo_surface_write_to_png(dc->surface, dc->filename); + cairo_destroy(dc->cr); + cairo_surface_destroy(dc->surface); +#endif +} + +gdouble lookup_clearance(char *name) +{ + if (name) { + int idx = pcb_route_style_lookup(&PCB->RouteStyle, 0, 0, 0, 0, menu->Style); + if (idx >= 0) + return PCB->RouteStyle.array[idx].Clearance; + } + return Settings.Clearance; +} + +gdouble lookup_thickness(char *name) +{ + if (name) { + int idx = pcb_route_style_lookup(&PCB->RouteStyle, 0, 0, 0, 0, menu->Style); + if (idx >= 0) + return PCB->RouteStyle.array[idx].Thick; + } + return Settings.LineThickness; +} + +static inline gdouble cluster_clearance(toporouter_cluster_t * cluster) +{ + if (cluster) + return lookup_clearance(cluster->netlist->style); + return lookup_clearance(NULL); +} + +static inline gdouble cluster_thickness(toporouter_cluster_t * cluster) +{ + if (cluster) + return lookup_thickness(cluster->netlist->style); + return lookup_thickness(NULL); +} + +gint toporouter_draw_vertex(gpointer item, gpointer data) +{ +#if TOPO_OUTPUT_ENABLED + drawing_context_t *dc = (drawing_context_t *) data; + toporouter_vertex_t *tv; + pcb_pin_t *pin; + pcb_pad_t *pad; + gdouble blue; + + if (TOPOROUTER_IS_VERTEX((GtsObject *) item)) { + tv = TOPOROUTER_VERTEX((GtsObject *) item); + + if (tv->flags & VERTEX_FLAG_RED) { + cairo_set_source_rgba(dc->cr, 1., 0., 0., 0.8f); + cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + + } + else if (tv->flags & VERTEX_FLAG_GREEN) { + cairo_set_source_rgba(dc->cr, 0., 1., 0., 0.8f); + cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + + } + else if (tv->flags & VERTEX_FLAG_BLUE) { + cairo_set_source_rgba(dc->cr, 0., 0., 1., 0.8f); + cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + + + } + /* printf("tv->type = %d\n", tv->type); */ + if (!dc->mode) { + if (tv->bbox) { + pin = (pcb_pin_t *) tv->bbox->data; + pad = (pcb_pad_t *) tv->bbox->data; + + blue = 0.0f; + switch (tv->bbox->type) { + case PIN: + cairo_set_source_rgba(dc->cr, 1.0f, 0., 0.0f, 0.2f); + cairo_arc(dc->cr, + tv->v.p.x * dc->s + MARGIN, + tv->v.p.y * dc->s + MARGIN, + (((gdouble) pin->Thickness / 2.0f) + (gdouble) lookup_clearance(pin->Name)) * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + + cairo_set_source_rgba(dc->cr, 1.0f, 0., 0., 0.4f); + cairo_arc(dc->cr, + tv->v.p.x * dc->s + MARGIN, + tv->v.p.y * dc->s + MARGIN, (gdouble) (pin->Thickness) / 2.0f * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + + break; + case VIA: + cairo_set_source_rgba(dc->cr, 0.0f, 0., 1., 0.2f); + cairo_arc(dc->cr, + tv->v.p.x * dc->s + MARGIN, + tv->v.p.y * dc->s + MARGIN, + (((gdouble) pin->Thickness / 2.0f) + (gdouble) lookup_clearance(pin->Name)) * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + + cairo_set_source_rgba(dc->cr, 0.0f, 0., 1., 0.4f); + cairo_arc(dc->cr, + tv->v.p.x * dc->s + MARGIN, + tv->v.p.y * dc->s + MARGIN, (gdouble) (pin->Thickness) / 2.0f * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + + break; + case PAD: + cairo_set_source_rgba(dc->cr, 0.0f, 1., 0., 0.5f); + cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 400. * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + + break; + default: + break; + } + } + } + else { + if (tv->flags & VERTEX_FLAG_BLUE) { + cairo_set_source_rgba(dc->cr, 0., 0., 1., 0.8f); + cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + } + else if (tv->flags & VERTEX_FLAG_RED) { + cairo_set_source_rgba(dc->cr, 1., 0., 0., 0.8f); + cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + + } + else if (tv->flags & VERTEX_FLAG_GREEN) { + cairo_set_source_rgba(dc->cr, 0., 1., 0., 0.8f); + cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + } + + } + } + else { + fprintf(stderr, "Unknown data passed to toporouter_draw_vertex, aborting foreach\n"); + return -1; + } + return 0; +#else + return -1; +#endif +} + +gint toporouter_draw_edge(gpointer item, gpointer data) +{ +#if TOPO_OUTPUT_ENABLED + drawing_context_t *dc = (drawing_context_t *) data; + toporouter_edge_t *te; + toporouter_constraint_t *tc; + + if (TOPOROUTER_IS_EDGE((GtsObject *) item)) { + te = TOPOROUTER_EDGE((GtsObject *) item); + cairo_set_source_rgba(dc->cr, 1.0f, 1.0f, 1.0f, 0.5f); + cairo_move_to(dc->cr, te->e.segment.v1->p.x * dc->s + MARGIN, te->e.segment.v1->p.y * dc->s + MARGIN); + cairo_line_to(dc->cr, te->e.segment.v2->p.x * dc->s + MARGIN, te->e.segment.v2->p.y * dc->s + MARGIN); + cairo_stroke(dc->cr); + } + else if (TOPOROUTER_IS_CONSTRAINT((GtsObject *) item)) { + tc = TOPOROUTER_CONSTRAINT((GtsObject *) item); + if (tc->box) { + switch (tc->box->type) { + case BOARD: + cairo_set_source_rgba(dc->cr, 1.0f, 0.0f, 1.0f, 0.9f); + cairo_move_to(dc->cr, tc->c.edge.segment.v1->p.x * dc->s + MARGIN, tc->c.edge.segment.v1->p.y * dc->s + MARGIN); + cairo_line_to(dc->cr, tc->c.edge.segment.v2->p.x * dc->s + MARGIN, tc->c.edge.segment.v2->p.y * dc->s + MARGIN); + cairo_stroke(dc->cr); + break; + case PIN: + case PAD: + cairo_set_source_rgba(dc->cr, 1.0f, 0.0f, 0.0f, 0.9f); + cairo_move_to(dc->cr, tc->c.edge.segment.v1->p.x * dc->s + MARGIN, tc->c.edge.segment.v1->p.y * dc->s + MARGIN); + cairo_line_to(dc->cr, tc->c.edge.segment.v2->p.x * dc->s + MARGIN, tc->c.edge.segment.v2->p.y * dc->s + MARGIN); + cairo_stroke(dc->cr); + break; + case LINE: + cairo_set_source_rgba(dc->cr, 0.0f, 1.0f, 0.0f, 0.9f); + cairo_move_to(dc->cr, tc->c.edge.segment.v1->p.x * dc->s + MARGIN, tc->c.edge.segment.v1->p.y * dc->s + MARGIN); + cairo_line_to(dc->cr, tc->c.edge.segment.v2->p.x * dc->s + MARGIN, tc->c.edge.segment.v2->p.y * dc->s + MARGIN); + cairo_stroke(dc->cr); + break; + + default: + cairo_set_source_rgba(dc->cr, 1.0f, 1.0f, 0.0f, 0.9f); + cairo_move_to(dc->cr, tc->c.edge.segment.v1->p.x * dc->s + MARGIN, tc->c.edge.segment.v1->p.y * dc->s + MARGIN); + cairo_line_to(dc->cr, tc->c.edge.segment.v2->p.x * dc->s + MARGIN, tc->c.edge.segment.v2->p.y * dc->s + MARGIN); + cairo_stroke(dc->cr); + break; + } + } + else { + printf("CONSTRAINT without box\n"); + + } + } + else { + fprintf(stderr, "Unknown data passed to toporouter_draw_edge, aborting foreach\n"); + return -1; + } + + return 0; +#else + return -1; +#endif +} + + +/*#define vertex_bbox(v) (v->bbox)*/ +toporouter_bbox_t *vertex_bbox(toporouter_vertex_t * v) +{ + return v ? v->bbox : NULL; +} + + +char *vertex_netlist(toporouter_vertex_t * v) +{ + toporouter_bbox_t *box = vertex_bbox(v); + + if (box && box->cluster) + return box->cluster->netlist->netlist; + + return NULL; +} + +char *constraint_netlist(toporouter_constraint_t * c) +{ + toporouter_bbox_t *box = c->box; + + if (box && box->cluster) + return box->cluster->netlist->netlist; + + return NULL; +} + +static inline guint epsilon_equals(gdouble a, gdouble b) +{ + if (a > b - EPSILON && a < b + EPSILON) + return 1; + return 0; +} + +void print_bbox(toporouter_bbox_t * box) +{ + printf("[BBOX "); + switch (box->type) { + case PAD: + printf("PAD "); + break; + case PIN: + printf("PIN "); + break; + case VIA: + printf("VIA "); + break; + case LINE: + printf("LINE "); + break; + case BOARD: + printf("BOARD "); + break; + case POLYGON: + printf("POLYGON "); + break; + default: + printf("UNKNOWN "); + break; + } + + if (box->point) + printf("P: %f,%f,%f ", vx(box->point), vy(box->point), vz(box->point)); + else + printf("P: NONE "); + + printf("LAYER: %d ", box->layer); + printf("CLUSTER: %d]\n", box->cluster ? box->cluster->c : -1); + +} + +void print_vertex(toporouter_vertex_t * v) +{ + if (v) + printf("[V %f,%f,%f ", vx(v), vy(v), vz(v)); + else + printf("[V (null) "); + + printf("%s ", vertex_netlist(v)); + if (v->route && v->route->netlist) + printf("%s ", v->route->netlist->netlist); + + if (v->routingedge) { + guint n = g_list_length(edge_routing(v->routingedge)); + guint pos = g_list_index(edge_routing(v->routingedge), v); + + if (TOPOROUTER_IS_CONSTRAINT(v->routingedge)) + printf("[CONST "); + else + printf("[EDGE "); + + printf("%d/%d] ", pos, n); + + } + + + if (v->flags & VERTEX_FLAG_TEMP) + printf("TEMP "); + if (v->flags & VERTEX_FLAG_ROUTE) + printf("ROUTE "); + if (v->flags & VERTEX_FLAG_SPECCUT) + printf("SPECCUT "); + if (v->flags & VERTEX_FLAG_FAKE) + printf("FAKE "); + + printf("]\n"); + +} + +gdouble vertex_net_thickness(toporouter_vertex_t * v) +{ + toporouter_bbox_t *box = vertex_bbox(v); + + if (!box) { + + while (v && (v->flags & VERTEX_FLAG_TEMP || v->flags & VERTEX_FLAG_ROUTE)) { + v = v->parent; + } + + box = vertex_bbox(v); + + } + else { + if (box->type == PIN || box->type == VIA) { + pcb_pin_t *pin = (pcb_pin_t *) box->data; + if (PCB_FLAG_TEST(PCB_FLAG_SQUARE, pin) || PCB_FLAG_TEST(PCB_FLAG_OCTAGON, pin)) { + return 0.; + } +/* return ((pcb_pin_t *)box->data)->Thickness + 1.;*/ + return ((pcb_pin_t *) box->data)->Thickness; + } + else if (box->type == PAD) { + pcb_pad_t *pad = (pcb_pad_t *) box->data; + if (pad->Point1.X == pad->Point2.X && pad->Point1.Y == pad->Point2.Y && !PCB_FLAG_TEST(PCB_FLAG_SQUARE, pad)) { + return pad->Thickness; + } + return 0.; + } + else if (box->type == BOARD) { + return 0.; + } + else if (box->type == LINE) { + pcb_line_t *line = (pcb_line_t *) box->data; + return line->Thickness; + } + else if (box->type == POLYGON) { + return 0.; + } + + printf("Unrecognized type in thickness lookup..\n"); + } + +/* if(!box || !box->cluster) return Settings.LineThickness + 1.;*/ + if (!box || !box->cluster) + return Settings.LineThickness; + + return cluster_thickness(box->cluster); +} + +gdouble vertex_net_clearance(toporouter_vertex_t * v) +{ + toporouter_bbox_t *box = vertex_bbox(v); + if (!box) { + + while (v && (v->flags & VERTEX_FLAG_TEMP || v->flags & VERTEX_FLAG_ROUTE)) { + v = v->parent; + } + box = vertex_bbox(v); + } + else { + /* if(box->type == PIN || box->type == VIA) + return ((pcb_pin_t *)box->data)->Clearance; + else if(box->type == PAD) + return ((pcb_pad_t *)box->data)->Clearance; */ + + } + +/* if(!box || !box->cluster) return Settings.Clearance + 1.; */ + if (!box || !box->cluster) + return Settings.Clearance; + return cluster_clearance(box->cluster); +} + +/* +void +print_trace (void) +{ + void *array[10]; + size_t size; + char **strings; + size_t i; + + size = backtrace (array, 10); + strings = backtrace_symbols (array, size); + + printf ("Obtained %zd stack frames.\n", size); + + for (i = 0; i < size; i++) + printf ("%s\n", strings[i]); + + free (strings); +} +*/ +/* fills in x and y with coordinates of point from a towards b of distance d */ +void point_from_point_to_point(toporouter_vertex_t * a, toporouter_vertex_t * b, gdouble d, gdouble * x, gdouble * y) +{ + gdouble dx = vx(b) - vx(a); + gdouble dy = vy(b) - vy(a); + gdouble theta = atan(fabs(dy / dx)); + +/*#ifdef DEBUG_EXPORT */ + if (!finite(theta)) { +/* printf("!finte(theta): a = %f,%f b = %f,%f d = %f\n", vx(a), vy(a), vx(b), vy(b), d); + print_trace(); */ + /*TODO: this shouldn't happen, fix the hack */ + *x = vx(a); + *y = vy(a); + return; + } +/*#endif*/ + + g_assert(finite(theta)); + + *x = vx(a); + *y = vy(a); + + if (dx >= 0.) { + + if (dy >= 0.) { + *x += d * cos(theta); + *y += d * sin(theta); + } + else { + *x += d * cos(theta); + *y -= d * sin(theta); + } + + } + else { + + if (dy >= 0.) { + *x -= d * cos(theta); + *y += d * sin(theta); + } + else { + *x -= d * cos(theta); + *y -= d * sin(theta); + } + + } +} + + +static inline gint coord_wind(gdouble ax, gdouble ay, gdouble bx, gdouble by, gdouble cx, gdouble cy) +{ + gdouble rval, dx1, dx2, dy1, dy2; + dx1 = bx - ax; + dy1 = by - ay; + dx2 = cx - bx; + dy2 = cy - by; + rval = (dx1 * dy2) - (dy1 * dx2); + return (rval > EPSILON) ? 1 : ((rval < -EPSILON) ? -1 : 0); +} + +/* wind_v: + * returns 1,0,-1 for counterclockwise, collinear or clockwise, respectively. + */ +int point_wind(GtsPoint * a, GtsPoint * b, GtsPoint * c) +{ + gdouble rval, dx1, dx2, dy1, dy2; + dx1 = b->x - a->x; + dy1 = b->y - a->y; + dx2 = c->x - b->x; + dy2 = c->y - b->y; + rval = (dx1 * dy2) - (dy1 * dx2); + return (rval > EPSILON) ? 1 : ((rval < -EPSILON) ? -1 : 0); +} + +static inline int vertex_wind(GtsVertex * a, GtsVertex * b, GtsVertex * c) +{ + return point_wind(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c)); +} + +static inline int tvertex_wind(toporouter_vertex_t * a, toporouter_vertex_t * b, toporouter_vertex_t * c) +{ + return point_wind(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c)); +} + +int sloppy_point_wind(GtsPoint * a, GtsPoint * b, GtsPoint * c) +{ + gdouble rval, dx1, dx2, dy1, dy2; + dx1 = b->x - a->x; + dy1 = b->y - a->y; + dx2 = c->x - b->x; + dy2 = c->y - b->y; + rval = (dx1 * dy2) - (dy1 * dx2); + return (rval > 10.) ? 1 : ((rval < -10.) ? -1 : 0); +} + +static inline int sloppy_vertex_wind(GtsVertex * a, GtsVertex * b, GtsVertex * c) +{ + return point_wind(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c)); +} + +/* moves vertex v d units in the direction of vertex p */ +void coord_move_towards_coord_values(gdouble ax, gdouble ay, gdouble px, gdouble py, gdouble d, gdouble * x, gdouble * y) +{ + gdouble dx = px - ax; + gdouble dy = py - ay; + gdouble theta = atan(fabs(dy / dx)); + + + if (!finite(theta)) { + printf("!finite(theta) a = %f,%f p = %f,%f d = %f\n", ax, ay, px, py, d); + + } + + g_assert(finite(theta)); + + if (dx >= 0.) { + + if (dy >= 0.) { + *x = ax + (d * cos(theta)); + *y = ay + (d * sin(theta)); + } + else { + *x = ax + (d * cos(theta)); + *y = ay - (d * sin(theta)); + } + + } + else { + + if (dy >= 0.) { + *x = ax - (d * cos(theta)); + *y = ay + (d * sin(theta)); + } + else { + *x = ax - (d * cos(theta)); + *y = ay - (d * sin(theta)); + } + + } + +} + +/* moves vertex v d units in the direction of vertex p */ +void vertex_move_towards_point_values(GtsVertex * v, gdouble px, gdouble py, gdouble d, gdouble * x, gdouble * y) +{ + gdouble dx = px - GTS_POINT(v)->x; + gdouble dy = py - GTS_POINT(v)->y; + gdouble theta = atan(fabs(dy / dx)); + + g_assert(finite(theta)); + + if (dx >= 0.) { + + if (dy >= 0.) { + *x = GTS_POINT(v)->x + (d * cos(theta)); + *y = GTS_POINT(v)->y + (d * sin(theta)); + } + else { + *x = GTS_POINT(v)->x + (d * cos(theta)); + *y = GTS_POINT(v)->y - (d * sin(theta)); + } + + } + else { + + if (dy >= 0.) { + *x = GTS_POINT(v)->x - (d * cos(theta)); + *y = GTS_POINT(v)->y + (d * sin(theta)); + } + else { + *x = GTS_POINT(v)->x - (d * cos(theta)); + *y = GTS_POINT(v)->y - (d * sin(theta)); + } + + } + +} + +/* moves vertex v d units in the direction of vertex p */ +void vertex_move_towards_vertex_values(GtsVertex * v, GtsVertex * p, gdouble d, gdouble * x, gdouble * y) +{ + gdouble dx = GTS_POINT(p)->x - GTS_POINT(v)->x; + gdouble dy = GTS_POINT(p)->y - GTS_POINT(v)->y; + gdouble theta = atan(fabs(dy / dx)); + + g_assert(finite(theta)); + + if (dx >= 0.) { + + if (dy >= 0.) { + *x = GTS_POINT(v)->x + (d * cos(theta)); + *y = GTS_POINT(v)->y + (d * sin(theta)); + } + else { + *x = GTS_POINT(v)->x + (d * cos(theta)); + *y = GTS_POINT(v)->y - (d * sin(theta)); + } + + } + else { + + if (dy >= 0.) { + *x = GTS_POINT(v)->x - (d * cos(theta)); + *y = GTS_POINT(v)->y + (d * sin(theta)); + } + else { + *x = GTS_POINT(v)->x - (d * cos(theta)); + *y = GTS_POINT(v)->y - (d * sin(theta)); + } + + } + +} + +#define tv_on_layer(v,l) (l == TOPOROUTER_BBOX(TOPOROUTER_VERTEX(v)->boxes->data)->layer) + +static inline gdouble min_spacing(toporouter_vertex_t * v1, toporouter_vertex_t * v2) +{ + + gdouble v1halfthick, v2halfthick, v1clearance, v2clearance, ms; +/* toporouter_edge_t *e = v1->routingedge;*/ + + v1halfthick = vertex_net_thickness(TOPOROUTER_VERTEX(v1)) / 2.; + v2halfthick = vertex_net_thickness(TOPOROUTER_VERTEX(v2)) / 2.; + + v1clearance = vertex_net_clearance(TOPOROUTER_VERTEX(v1)); + v2clearance = vertex_net_clearance(TOPOROUTER_VERTEX(v2)); + + ms = v1halfthick + v2halfthick + MAX(v1clearance, v2clearance); + +#ifdef SPACING_DEBUG + printf("v1halfthick = %f v2halfthick = %f v1clearance = %f v2clearance = %f ms = %f\n", + v1halfthick, v2halfthick, v1clearance, v2clearance, ms); +#endif + + return ms; +} + +/* v1 is a vertex in the CDT, and v2 is a net... other way around?*/ +static inline gdouble min_vertex_net_spacing(toporouter_vertex_t * v1, toporouter_vertex_t * v2) +{ + + gdouble v1halfthick, v2halfthick, v1clearance, v2clearance, ms; + + v1halfthick = vertex_net_thickness(TOPOROUTER_VERTEX(v1)) / 2.; + v2halfthick = cluster_thickness(vertex_bbox(v2)->cluster) / 2.; + + v1clearance = vertex_net_clearance(TOPOROUTER_VERTEX(v1)); + v2clearance = cluster_clearance(vertex_bbox(v2)->cluster); + + ms = v1halfthick + v2halfthick + MAX(v1clearance, v2clearance); + + return ms; +} + +static inline gdouble min_oproute_vertex_spacing(toporouter_oproute_t * oproute, toporouter_vertex_t * v2) +{ + + gdouble v1halfthick, v2halfthick, v1clearance, v2clearance, ms; + + v1halfthick = lookup_thickness(oproute->style) / 2.; + v2halfthick = vertex_net_thickness(v2) / 2.; + + v1clearance = lookup_clearance(oproute->style); + v2clearance = vertex_net_clearance(v2); + + ms = v1halfthick + v2halfthick + MAX(v1clearance, v2clearance); + + return ms; +} + +gdouble min_oproute_net_spacing(toporouter_oproute_t * oproute, toporouter_vertex_t * v2) +{ + + gdouble v1halfthick, v2halfthick, v1clearance, v2clearance, ms; + + v1halfthick = lookup_thickness(oproute->style) / 2.; + v2halfthick = cluster_thickness(v2->route->src) / 2.; + + v1clearance = lookup_clearance(oproute->style); + v2clearance = cluster_clearance(v2->route->src); + + ms = v1halfthick + v2halfthick + MAX(v1clearance, v2clearance); + + return ms; +} + +gdouble min_net_net_spacing(toporouter_vertex_t * v1, toporouter_vertex_t * v2) +{ + + gdouble v1halfthick, v2halfthick, v1clearance, v2clearance, ms; + + v1halfthick = cluster_thickness(v1->route->src) / 2.; + v2halfthick = cluster_thickness(v2->route->src) / 2.; + + v1clearance = cluster_clearance(v1->route->src); + v2clearance = cluster_clearance(v2->route->src); + + ms = v1halfthick + v2halfthick + MAX(v1clearance, v2clearance); + + return ms; +} + +void +toporouter_draw_cluster(toporouter_t * r, drawing_context_t * dc, toporouter_cluster_t * cluster, gdouble red, gdouble green, + gdouble blue, guint layer) +{ +#if TOPO_OUTPUT_ENABLED +/*GList *i = cluster->i; + + while(i) { + toporouter_bbox_t *box = TOPOROUTER_BBOX(i->data); + + if(box->point && vz(box->point) == layer) { + cairo_set_source_rgba(dc->cr, red, green, blue, 0.8f); + cairo_arc(dc->cr, vx(box->point) * dc->s + MARGIN, vy(box->point) * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + } + + i = i->next; + } +*/ +#endif +} + +void +toporouter_draw_surface(toporouter_t * r, GtsSurface * s, char *filename, int w, int h, int mode, GList * datas, int layer, + GList * candidatepoints) +{ +#if TOPO_OUTPUT_ENABLED + drawing_context_t *dc; + GList *i; + toporouter_vertex_t *tv, *tv2 = NULL; + + dc = toporouter_output_init(w, h, filename); + dc->mode = mode; + dc->data = NULL; + + gts_surface_foreach_edge(s, toporouter_draw_edge, dc); + gts_surface_foreach_vertex(s, toporouter_draw_vertex, dc); + + i = r->routednets; + while (i) { + GList *j = TOPOROUTER_ROUTE(i->data)->path; + tv2 = NULL; + while (j) { + tv = TOPOROUTER_VERTEX(j->data); + if (GTS_POINT(tv)->z == layer) { + if (tv && tv2) { + cairo_set_source_rgba(dc->cr, 0.0f, 1.0f, 0.0f, 0.8f); + cairo_move_to(dc->cr, GTS_POINT(tv)->x * dc->s + MARGIN, GTS_POINT(tv)->y * dc->s + MARGIN); + cairo_line_to(dc->cr, GTS_POINT(tv2)->x * dc->s + MARGIN, GTS_POINT(tv2)->y * dc->s + MARGIN); + cairo_stroke(dc->cr); + } + + if (tv->flags & VERTEX_FLAG_RED) { + cairo_set_source_rgba(dc->cr, 1., 0., 0., 0.8f); + cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + + } + else if (tv->flags & VERTEX_FLAG_GREEN) { + cairo_set_source_rgba(dc->cr, 0., 1., 0., 0.8f); + cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + + } + else if (tv->flags & VERTEX_FLAG_BLUE) { + cairo_set_source_rgba(dc->cr, 0., 0., 1., 0.8f); + cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + + } + else { + + cairo_set_source_rgba(dc->cr, 1., 1., 1., 0.8f); + cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + + + } + + if (tv->routingedge && !TOPOROUTER_IS_CONSTRAINT(tv->routingedge)) { + gdouble tempx, tempy, nms, pms; + GList *i = g_list_find(edge_routing(tv->routingedge), tv); + toporouter_vertex_t *nextv, *prevv; + + nextv = edge_routing_next(tv->routingedge, i); + prevv = edge_routing_prev(tv->routingedge, i); + + nms = min_spacing(tv, nextv); + pms = min_spacing(tv, prevv); + + g_assert(finite(nms)); + g_assert(finite(pms)); + + point_from_point_to_point(tv, nextv, nms, &tempx, &tempy); + + cairo_set_source_rgba(dc->cr, 0.0f, 1.0f, 1.0f, 0.8f); + cairo_move_to(dc->cr, vx(tv) * dc->s + MARGIN, vy(tv) * dc->s + MARGIN); + cairo_line_to(dc->cr, tempx * dc->s + MARGIN, tempy * dc->s + MARGIN); + cairo_stroke(dc->cr); + + point_from_point_to_point(tv, prevv, pms, &tempx, &tempy); + + cairo_move_to(dc->cr, vx(tv) * dc->s + MARGIN, vy(tv) * dc->s + MARGIN); + cairo_line_to(dc->cr, tempx * dc->s + MARGIN, tempy * dc->s + MARGIN); + cairo_stroke(dc->cr); + + + + + } + + + } + tv2 = tv; + j = j->next; + } + i = i->next; + } + + while (datas) { + toporouter_route_t *routedata = (toporouter_route_t *) datas->data; + + GList *i; /*, *k; */ + + toporouter_draw_cluster(r, dc, routedata->src, 1., 0., 0., layer); + toporouter_draw_cluster(r, dc, routedata->dest, 0., 0., 1., layer); + + tv2 = NULL; + i = routedata->path; + while (i) { + tv = TOPOROUTER_VERTEX(i->data); + if (GTS_POINT(tv)->z == layer) { + if (tv && tv2) { + cairo_set_source_rgba(dc->cr, 0.0f, 1.0f, 0.0f, 0.8f); + cairo_move_to(dc->cr, GTS_POINT(tv)->x * dc->s + MARGIN, GTS_POINT(tv)->y * dc->s + MARGIN); + cairo_line_to(dc->cr, GTS_POINT(tv2)->x * dc->s + MARGIN, GTS_POINT(tv2)->y * dc->s + MARGIN); + cairo_stroke(dc->cr); + } + } + tv2 = tv; + i = i->next; + } + + + if (routedata->alltemppoints) { + GList *i, *j; + i = j = g_hash_table_get_keys(routedata->alltemppoints); + while (i) { + toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data); + + if (GTS_POINT(tv)->z != layer) { + i = i->next; + continue; + } + if (tv->flags & VERTEX_FLAG_BLUE) { + cairo_set_source_rgba(dc->cr, 0., 0., 1., 0.8f); + cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + } + else if (tv->flags & VERTEX_FLAG_RED) { + cairo_set_source_rgba(dc->cr, 1., 0., 0., 0.8f); + cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + + } + else if (tv->flags & VERTEX_FLAG_GREEN) { + cairo_set_source_rgba(dc->cr, 0., 1., 0., 0.8f); + cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + } + else { + cairo_set_source_rgba(dc->cr, 1., 1., 1., 0.8f); + cairo_arc(dc->cr, tv->v.p.x * dc->s + MARGIN, tv->v.p.y * dc->s + MARGIN, 500. * dc->s, 0, 2 * M_PI); + cairo_fill(dc->cr); + } + i = i->next; + } + g_list_free(j); + } + datas = datas->next; + } + toporouter_output_close(dc); +#endif +} + + +void toporouter_layer_free(toporouter_layer_t * l) +{ + g_list_free(l->vertices); + g_list_free(l->constraints); + +} + +guint groupcount(void) +{ + int group; + guint count = 0; + + for (group = 0; group < pcb_max_group; group++) { + if (PCB->LayerGroups.Number[group] > 0) + count++; + } + + return count; +} + +void toporouter_free(toporouter_t * r) +{ + struct timeval endtime; + int secs, usecs; + + int i; + for (i = 0; i < groupcount(); i++) { + toporouter_layer_free(&r->layers[i]); + } + + + gettimeofday(&endtime, NULL); + + secs = (int) (endtime.tv_sec - r->starttime.tv_sec); + usecs = (int) ((endtime.tv_usec - r->starttime.tv_usec) / 1000); + + if (usecs < 0) { + secs -= 1; + usecs += 1000; + } + + pcb_message(PCB_MSG_INFO, _("Elapsed time: %d.%02d seconds\n"), secs, usecs); + free(r->layers); + free(r); + +} + +/* wind: + * returns 1,0,-1 for counterclockwise, collinear or clockwise, respectively. + */ +int wind(toporouter_spoint_t * p1, toporouter_spoint_t * p2, toporouter_spoint_t * p3) +{ + double rval, dx1, dx2, dy1, dy2; + dx1 = p2->x - p1->x; + dy1 = p2->y - p1->y; + dx2 = p3->x - p2->x; + dy2 = p3->y - p2->y; + rval = (dx1 * dy2) - (dy1 * dx2); + return (rval > 0.0001) ? 1 : ((rval < -0.0001) ? -1 : 0); +} + +/* wind_double: + * returns 1,0,-1 for counterclockwise, collinear or clockwise, respectively. + */ +int wind_double(gdouble p1_x, gdouble p1_y, gdouble p2_x, gdouble p2_y, gdouble p3_x, gdouble p3_y) +{ + double rval, dx1, dx2, dy1, dy2; + dx1 = p2_x - p1_x; + dy1 = p2_y - p1_y; + dx2 = p3_x - p2_x; + dy2 = p3_y - p2_y; + rval = (dx1 * dy2) - (dy1 * dx2); + return (rval > 0.0001) ? 1 : ((rval < -0.0001) ? -1 : 0); +} + +static inline void print_toporouter_constraint(toporouter_constraint_t * tc) +{ + printf("%f,%f -> %f,%f ", + tc->c.edge.segment.v1->p.x, tc->c.edge.segment.v1->p.y, tc->c.edge.segment.v2->p.x, tc->c.edge.segment.v2->p.y); +} + +static inline void print_toporouter_vertex(toporouter_vertex_t * tv) +{ + printf("%f,%f ", tv->v.p.x, tv->v.p.y); +} + + +/** + * vertices_on_line: + * Given vertex a, gradient m, and radius r: + * + * Return vertices on line of a & m at r from a + */ +void vertices_on_line(toporouter_spoint_t * a, gdouble m, gdouble r, toporouter_spoint_t * b0, toporouter_spoint_t * b1) +{ + + gdouble c, temp; + + if (m == INFINITY || m == -INFINITY) { + b0->y = a->y + r; + b1->y = a->y - r; + + b0->x = a->x; + b1->x = a->x; + + return; + } + + c = a->y - (m * a->x); + + temp = sqrt(pow(r, 2) / (1 + pow(m, 2))); + + b0->x = a->x + temp; + b1->x = a->x - temp; + + b0->y = b0->x * m + c; + b1->y = b1->x * m + c; + +} + +/** + * vertices_on_line: + * Given vertex a, gradient m, and radius r: + * + * Return vertices on line of a & m at r from a + */ +void coords_on_line(gdouble ax, gdouble ay, gdouble m, gdouble r, gdouble * b0x, gdouble * b0y, gdouble * b1x, gdouble * b1y) +{ + + gdouble c, temp; + + if (m == INFINITY || m == -INFINITY) { + *b0y = ay + r; + *b1y = ay - r; + + *b0x = ax; + *b1x = ax; + + return; + } + + c = ay - (m * ax); + + temp = sqrt(pow(r, 2) / (1 + pow(m, 2))); + + *b0x = ax + temp; + *b1x = ax - temp; + + *b0y = *b0x * m + c; + *b1y = *b1x * m + c; + +} + +/** + * vertices_on_line: + * Given vertex a, gradient m, and radius r: + * + * Return vertices on line of a & m at r from a + */ +void points_on_line(GtsPoint * a, gdouble m, gdouble r, GtsPoint * b0, GtsPoint * b1) +{ + + gdouble c, temp; + + if (m == INFINITY || m == -INFINITY) { + b0->y = a->y + r; + b1->y = a->y - r; + + b0->x = a->x; + b1->x = a->x; + + return; + } + + c = a->y - (m * a->x); + + temp = sqrt(pow(r, 2) / (1 + pow(m, 2))); + + b0->x = a->x + temp; + b1->x = a->x - temp; + + b0->y = b0->x * m + c; + b1->y = b1->x * m + c; + +} + +/* + * Returns gradient of segment given by a & b + */ +gdouble vertex_gradient(toporouter_spoint_t * a, toporouter_spoint_t * b) +{ + if (a->x == b->x) + return INFINITY; + + return ((b->y - a->y) / (b->x - a->x)); +} + +/* + * Returns gradient of segment given by (x0,y0) & (x1,y1) + */ +static inline gdouble cartesian_gradient(gdouble x0, gdouble y0, gdouble x1, gdouble y1) +{ + if (epsilon_equals(x0, x1)) + return INFINITY; + + return ((y1 - y0) / (x1 - x0)); +} + +/* + * Returns gradient of segment given by (x0,y0) & (x1,y1) + */ +static inline gdouble point_gradient(GtsPoint * a, GtsPoint * b) +{ + return cartesian_gradient(a->x, a->y, b->x, b->y); +} + +gdouble segment_gradient(GtsSegment * s) +{ + return cartesian_gradient(GTS_POINT(s->v1)->x, GTS_POINT(s->v1)->y, GTS_POINT(s->v2)->x, GTS_POINT(s->v2)->y); +} + +/* + * Returns gradient perpendicular to m + */ +gdouble perpendicular_gradient(gdouble m) +{ + if (isinf(m)) + return 0.0f; + if (m < EPSILON && m > -EPSILON) + return INFINITY; + return -1.0f / m; +} + +/* + * Returns the distance between two vertices in the x-y plane + */ +gdouble vertices_plane_distance(toporouter_spoint_t * a, toporouter_spoint_t * b) +{ + return sqrt(pow(a->x - b->x, 2) + pow(a->y - b->y, 2)); +} + +/* + * Finds the point p distance r away from a on the line segment of a & b + */ +static inline void vertex_outside_segment(toporouter_spoint_t * a, toporouter_spoint_t * b, gdouble r, toporouter_spoint_t * p) +{ + toporouter_spoint_t temp[2]; + + vertices_on_line(a, vertex_gradient(a, b), r, &temp[0], &temp[1]); + + if (vertices_plane_distance(&temp[0], b) > vertices_plane_distance(&temp[1], b)) { + p->x = temp[0].x; + p->y = temp[0].y; + } + else { + p->x = temp[1].x; + p->y = temp[1].y; + } + +} + +/* proper intersection: + * AB and CD must share a point interior to both segments. + * returns TRUE if AB properly intersects CD. + */ +gint coord_intersect_prop(gdouble ax, gdouble ay, gdouble bx, gdouble by, gdouble cx, gdouble cy, gdouble dx, gdouble dy) +{ + gint wind_abc = coord_wind(ax, ay, bx, by, cx, cy); + gint wind_abd = coord_wind(ax, ay, bx, by, dx, dy); + gint wind_cda = coord_wind(cx, cy, dx, dy, ax, ay); + gint wind_cdb = coord_wind(cx, cy, dx, dy, bx, by); + + if (!wind_abc || !wind_abd || !wind_cda || !wind_cdb) + return 0; + + return (wind_abc ^ wind_abd) && (wind_cda ^ wind_cdb); +} + +/* proper intersection: + * AB and CD must share a point interior to both segments. + * returns TRUE if AB properly intersects CD. + */ +int point_intersect_prop(GtsPoint * a, GtsPoint * b, GtsPoint * c, GtsPoint * d) +{ + + if (point_wind(a, b, c) == 0 || point_wind(a, b, d) == 0 || point_wind(c, d, a) == 0 || point_wind(c, d, b) == 0) + return 0; + + return (point_wind(a, b, c) ^ point_wind(a, b, d)) && (point_wind(c, d, a) ^ point_wind(c, d, b)); +} + +static inline int vertex_intersect_prop(GtsVertex * a, GtsVertex * b, GtsVertex * c, GtsVertex * d) +{ + return point_intersect_prop(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c), GTS_POINT(d)); +} + +static inline int +tvertex_intersect_prop(toporouter_vertex_t * a, toporouter_vertex_t * b, toporouter_vertex_t * c, toporouter_vertex_t * d) +{ + return point_intersect_prop(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c), GTS_POINT(d)); +} + +/* +static inline int +tvertex_intersect(toporouter_vertex_t *a, toporouter_vertex_t *b, toporouter_vertex_t *c, toporouter_vertex_t *d) +{ + if( !point_wind(GTS_POINT(a), GTS_POINT(d), GTS_POINT(b)) || !point_wind(GTS_POINT(a), GTS_POINT(c), GTS_POINT(b)) ) return 1; + + return + ( point_wind(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c)) ^ point_wind(GTS_POINT(a), GTS_POINT(b), GTS_POINT(d)) ) && + ( point_wind(GTS_POINT(c), GTS_POINT(d), GTS_POINT(a)) ^ point_wind(GTS_POINT(c), GTS_POINT(d), GTS_POINT(b)) ); +} +*/ + +/* intersection vertex: + * AB and CD must share a point interior to both segments. + * returns vertex at intersection of AB and CD. + */ +GtsVertex *vertex_intersect(GtsVertex * a, GtsVertex * b, GtsVertex * c, GtsVertex * d) +{ + GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class()); + GtsVertex *rval; + gdouble ua_top, ua_bot, ua, rx, ry; + + /* TODO: this could be done more efficiently without duplicating computation */ + if (!vertex_intersect_prop(a, b, c, d)) + return NULL; + + ua_top = ((d->p.x - c->p.x) * (a->p.y - c->p.y)) - ((d->p.y - c->p.y) * (a->p.x - c->p.x)); + ua_bot = ((d->p.y - c->p.y) * (b->p.x - a->p.x)) - ((d->p.x - c->p.x) * (b->p.y - a->p.y)); + ua = ua_top / ua_bot; + rx = a->p.x + (ua * (b->p.x - a->p.x)); + ry = a->p.y + (ua * (b->p.y - a->p.y)); + + rval = gts_vertex_new(vertex_class, rx, ry, 0.0f); + + return rval; +} + +/* intersection vertex: + * AB and CD must share a point interior to both segments. + * returns vertex at intersection of AB and CD. + */ +void +coord_intersect(gdouble ax, gdouble ay, gdouble bx, gdouble by, gdouble cx, gdouble cy, gdouble dx, gdouble dy, gdouble * rx, + gdouble * ry) +{ + gdouble ua_top, ua_bot, ua; + + ua_top = ((dx - cx) * (ay - cy)) - ((dy - cy) * (ax - cx)); + ua_bot = ((dy - cy) * (bx - ax)) - ((dx - cx) * (by - ay)); + ua = ua_top / ua_bot; + *rx = ax + (ua * (bx - ax)); + *ry = ay + (ua * (by - ay)); + +} + + +/* + * returns true if c is between a and b + */ +int point_between(GtsPoint * a, GtsPoint * b, GtsPoint * c) +{ + if (point_wind(a, b, c) != 0) + return 0; + + if (a->x != b->x) { + return ((a->x <= c->x) && (c->x <= b->x)) || ((a->x >= c->x) && (c->x >= b->x)); + } + return ((a->y <= c->y) && (c->y <= b->y)) || ((a->y >= c->y) && (c->y >= b->y)); +} + +static inline int vertex_between(GtsVertex * a, GtsVertex * b, GtsVertex * c) +{ + return point_between(GTS_POINT(a), GTS_POINT(b), GTS_POINT(c)); +} + +void delaunay_create_from_vertices(GList * vertices, GtsSurface ** surface, GtsTriangle ** t) +{ + GList *i = vertices; + GtsVertex *v1, *v2, *v3; + GSList *vertices_slist = NULL; + + while (i) { + vertices_slist = g_slist_prepend(vertices_slist, i->data); + i = i->next; + } + + /* TODO: just work this out from the board outline */ + *t = gts_triangle_enclosing(gts_triangle_class(), vertices_slist, 100000.0f); + gts_triangle_vertices(*t, &v1, &v2, &v3); + + *surface = gts_surface_new(gts_surface_class(), gts_face_class(), + GTS_EDGE_CLASS(toporouter_edge_class()), GTS_VERTEX_CLASS(toporouter_vertex_class())); + + gts_surface_add_face(*surface, gts_face_new(gts_face_class(), (*t)->e1, (*t)->e2, (*t)->e3)); + + i = vertices; + while (i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(gts_delaunay_add_vertex(*surface, (GtsVertex *) i->data, NULL)); + + if (v) { + printf("ERROR: vertex could not be added to CDT "); + print_vertex(v); + } + + i = i->next; + } + + gts_allow_floating_vertices = TRUE; + gts_object_destroy(GTS_OBJECT(v1)); + gts_object_destroy(GTS_OBJECT(v2)); + gts_object_destroy(GTS_OBJECT(v3)); + gts_allow_floating_vertices = FALSE; + + g_slist_free(vertices_slist); +/* return surface;*/ +} + +GSList *list_to_slist(GList * i) +{ + GSList *rval = NULL; + while (i) { + rval = g_slist_prepend(rval, i->data); + i = i->next; + } + return rval; +} + +toporouter_bbox_t *toporouter_bbox_create_from_points(int layer, GList * vertices, toporouter_term_t type, gpointer data) +{ + toporouter_bbox_t *bbox; + GSList *vertices_slist = list_to_slist(vertices); + +/* delaunay_create_from_vertices(vertices, &s, &t);*/ + bbox = TOPOROUTER_BBOX(gts_bbox_points(GTS_BBOX_CLASS(toporouter_bbox_class()), vertices_slist)); + bbox->type = type; + bbox->data = data; + + bbox->surface = NULL; + bbox->enclosing = NULL; + + bbox->layer = layer; + + bbox->point = NULL; + bbox->realpoint = NULL; + + g_slist_free(vertices_slist); + return bbox; +} + +toporouter_bbox_t *toporouter_bbox_create(int layer, GList * vertices, toporouter_term_t type, gpointer data) +{ + toporouter_bbox_t *bbox; + GtsSurface *s; + GtsTriangle *t; + + delaunay_create_from_vertices(vertices, &s, &t); + bbox = TOPOROUTER_BBOX(gts_bbox_surface(GTS_BBOX_CLASS(toporouter_bbox_class()), s)); + bbox->type = type; + bbox->data = data; + + bbox->surface = s; + bbox->enclosing = t; + + bbox->layer = layer; + + return bbox; +} + +GtsVertex *insert_vertex(toporouter_t * r, toporouter_layer_t * l, gdouble x, gdouble y, toporouter_bbox_t * box) +{ + GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class()); + GtsVertex *v; + GList *i; + + i = l->vertices; + while (i) { + v = (GtsVertex *) i->data; + if (v->p.x == x && v->p.y == y) { + TOPOROUTER_VERTEX(v)->bbox = box; + return v; + } + i = i->next; + } + + v = gts_vertex_new(vertex_class, x, y, l - r->layers); + TOPOROUTER_VERTEX(v)->bbox = box; + l->vertices = g_list_prepend(l->vertices, v); + + return v; +} + +GList *insert_constraint_edge(toporouter_t * r, toporouter_layer_t * l, gdouble x1, gdouble y1, guint flags1, + gdouble x2, gdouble y2, guint flags2, toporouter_bbox_t * box) +{ + GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class()); + GtsEdgeClass *edge_class = GTS_EDGE_CLASS(toporouter_constraint_class()); + GtsVertex *p[2]; + GtsVertex *v; + GList *i; + GtsEdge *e; + + p[0] = p[1] = NULL; + + /* insert or find points */ + + i = l->vertices; + while (i) { + v = (GtsVertex *) i->data; + if (v->p.x == x1 && v->p.y == y1) + p[0] = v; + if (v->p.x == x2 && v->p.y == y2) + p[1] = v; + i = i->next; + } + + if (p[0] == NULL) { + p[0] = gts_vertex_new(vertex_class, x1, y1, l - r->layers); + TOPOROUTER_VERTEX(p[0])->bbox = box; + l->vertices = g_list_prepend(l->vertices, p[0]); + } + if (p[1] == NULL) { + p[1] = gts_vertex_new(vertex_class, x2, y2, l - r->layers); + TOPOROUTER_VERTEX(p[1])->bbox = box; + l->vertices = g_list_prepend(l->vertices, p[1]); + } + + TOPOROUTER_VERTEX(p[0])->flags = flags1; + TOPOROUTER_VERTEX(p[1])->flags = flags2; + + e = gts_edge_new(edge_class, p[0], p[1]); + TOPOROUTER_CONSTRAINT(e)->box = box; + l->constraints = g_list_prepend(l->constraints, e); +/* return insert_constraint_edge_rec(r, l, p, box);*/ + return g_list_prepend(NULL, e); + +} + +void insert_constraints_from_list(toporouter_t * r, toporouter_layer_t * l, GList * vlist, toporouter_bbox_t * box) +{ + GList *i = vlist; + toporouter_vertex_t *pv = NULL, *v; + + while (i) { + v = TOPOROUTER_VERTEX(i->data); + + if (pv) { + box->constraints = + g_list_concat(box->constraints, insert_constraint_edge(r, l, vx(v), vy(v), v->flags, vx(pv), vy(pv), pv->flags, box)); + } + + pv = v; + i = i->next; + } + + v = TOPOROUTER_VERTEX(vlist->data); + box->constraints = + g_list_concat(box->constraints, insert_constraint_edge(r, l, vx(v), vy(v), v->flags, vx(pv), vy(pv), pv->flags, box)); + +} + +void insert_centre_point(toporouter_t * r, toporouter_layer_t * l, gdouble x, gdouble y) +{ + GList *i; + GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class()); + + i = l->vertices; + while (i) { + GtsPoint *p = GTS_POINT(i->data); + if (p->x == x && p->y == y) + return; + i = i->next; + } + + l->vertices = g_list_prepend(l->vertices, gts_vertex_new(vertex_class, x, y, 0.0f)); +} + +GtsPoint *midpoint(GtsPoint * a, GtsPoint * b) +{ + return gts_point_new(gts_point_class(), (a->x + b->x) / 2., (a->y + b->y) / 2., 0.); +} + +static inline gdouble pad_rad(pcb_pad_t * pad) +{ + return (lookup_thickness(pad->Name) / 2.) + lookup_clearance(pad->Name); +} + +static inline gdouble pin_rad(pcb_pin_t * pin) +{ + return (lookup_thickness(pin->Name) / 2.) + lookup_clearance(pin->Name); +} + +GList *rect_with_attachments(gdouble rad, + gdouble x0, gdouble y0, + gdouble x1, gdouble y1, gdouble x2, gdouble y2, gdouble x3, gdouble y3, gdouble z) +{ + GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class()); + GList *r = NULL, *rr = NULL, *i; + toporouter_vertex_t *curpoint, *temppoint; + + + curpoint = TOPOROUTER_VERTEX(gts_vertex_new(vertex_class, x0, y0, z)); + + r = g_list_prepend(NULL, curpoint); + r = g_list_prepend(r, gts_vertex_new(vertex_class, x1, y1, z)); + r = g_list_prepend(r, gts_vertex_new(vertex_class, x2, y2, z)); + r = g_list_prepend(r, gts_vertex_new(vertex_class, x3, y3, z)); + + i = r; + while (i) { + temppoint = TOPOROUTER_VERTEX(i->data); + rr = g_list_prepend(rr, curpoint); + + curpoint = temppoint; + i = i->next; + } + + g_list_free(r); + + return rr; +} + +#define VERTEX_CENTRE(x) TOPOROUTER_VERTEX( vertex_bbox(x)->point ) + +/* + * Read pad data from layer into toporouter_layer_t struct + * + * Inserts points and constraints into GLists + */ +int read_pads(toporouter_t * r, toporouter_layer_t * l, guint layer) +{ + toporouter_spoint_t p[2], rv[5]; + gdouble x[2], y[2], t, m; + + GList *vlist = NULL; + toporouter_bbox_t *bbox = NULL; + + back = front = -1; + if (pcb_layer_group_list(PCB_LYT_BOTTOM | PCB_LYT_COPPER, &back, 1) <= 0) + return -1; + if (pcb_layer_group_list(PCB_LYT_TOP | PCB_LYT_COPPER, &front, 1) <= 0) + return -1; + +/* printf("read_pads: front = %d back = %d layer = %d\n", + front, back, layer);*/ + + /* If its not the top or bottom layer, there are no pads to read */ + if (l - r->layers != front && l - r->layers != back) + return 0; + + PCB_ELEMENT_LOOP(PCB->Data); + { + PCB_PAD_LOOP(element); + { + if ((l - r->layers == back && PCB_FLAG_TEST(PCB_FLAG_ONSOLDER, pad)) || (l - r->layers == front && !PCB_FLAG_TEST(PCB_FLAG_ONSOLDER, pad))) { + + t = (gdouble) pad->Thickness / 2.0f; + x[0] = pad->Point1.X; + x[1] = pad->Point2.X; + y[0] = pad->Point1.Y; + y[1] = pad->Point2.Y; + + + if (PCB_FLAG_TEST(PCB_FLAG_SQUARE, pad)) { + /* Square or oblong pad. Four points and four constraint edges are + * used */ + + if (x[0] == x[1] && y[0] == y[1]) { + /* Pad is square */ + +/* vlist = g_list_prepend(NULL, gts_vertex_new (vertex_class, x[0]-t, y[0]-t, 0.)); + vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, x[0]-t, y[0]+t, 0.)); + vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, x[0]+t, y[0]+t, 0.)); + vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, x[0]+t, y[0]-t, 0.)); */ + vlist = rect_with_attachments(pad_rad(pad), + x[0] - t, y[0] - t, + x[0] - t, y[0] + t, x[0] + t, y[0] + t, x[0] + t, y[0] - t, l - r->layers); + bbox = toporouter_bbox_create(l - r->layers, vlist, PAD, pad); + r->bboxes = g_slist_prepend(r->bboxes, bbox); + insert_constraints_from_list(r, l, vlist, bbox); + g_list_free(vlist); + + /*bbox->point = GTS_POINT( gts_vertex_new(vertex_class, x[0], y[0], 0.) ); */ + bbox->point = GTS_POINT(insert_vertex(r, l, x[0], y[0], bbox)); + g_assert(TOPOROUTER_VERTEX(bbox->point)->bbox == bbox); + } + else { + /* Pad is diagonal oblong or othogonal oblong */ + + m = cartesian_gradient(x[0], y[0], x[1], y[1]); + + p[0].x = x[0]; + p[0].y = y[0]; + p[1].x = x[1]; + p[1].y = y[1]; + + vertex_outside_segment(&p[0], &p[1], t, &rv[0]); + vertices_on_line(&rv[0], perpendicular_gradient(m), t, &rv[1], &rv[2]); + + vertex_outside_segment(&p[1], &p[0], t, &rv[0]); + vertices_on_line(&rv[0], perpendicular_gradient(m), t, &rv[3], &rv[4]); + + if (wind(&rv[1], &rv[2], &rv[3]) != wind(&rv[2], &rv[3], &rv[4])) { + rv[0].x = rv[3].x; + rv[0].y = rv[3].y; + rv[3].x = rv[4].x; + rv[3].y = rv[4].y; + rv[4].x = rv[0].x; + rv[4].y = rv[0].y; + } + +/* vlist = g_list_prepend(NULL, gts_vertex_new (vertex_class, rv[1].x, rv[1].y, 0.)); + vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, rv[2].x, rv[2].y, 0.)); + vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, rv[3].x, rv[3].y, 0.)); + vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, rv[4].x, rv[4].y, 0.));*/ + vlist = rect_with_attachments(pad_rad(pad), + rv[1].x, rv[1].y, + rv[2].x, rv[2].y, rv[3].x, rv[3].y, rv[4].x, rv[4].y, l - r->layers); + bbox = toporouter_bbox_create(l - r->layers, vlist, PAD, pad); + r->bboxes = g_slist_prepend(r->bboxes, bbox); + insert_constraints_from_list(r, l, vlist, bbox); + g_list_free(vlist); + + /*bbox->point = GTS_POINT( gts_vertex_new(vertex_class, (x[0] + x[1]) / 2., (y[0] + y[1]) / 2., 0.) ); */ + bbox->point = GTS_POINT(insert_vertex(r, l, (x[0] + x[1]) / 2., (y[0] + y[1]) / 2., bbox)); + g_assert(TOPOROUTER_VERTEX(bbox->point)->bbox == bbox); + + } + + } + else { + /* Either round pad or pad with curved edges */ + + if (x[0] == x[1] && y[0] == y[1]) { + /* One point */ + + /* bounding box same as square pad */ + vlist = rect_with_attachments(pad_rad(pad), + x[0] - t, y[0] - t, + x[0] - t, y[0] + t, x[0] + t, y[0] + t, x[0] + t, y[0] - t, l - r->layers); + bbox = toporouter_bbox_create(l - r->layers, vlist, PAD, pad); + r->bboxes = g_slist_prepend(r->bboxes, bbox); + g_list_free(vlist); + + /*bbox->point = GTS_POINT( insert_vertex(r, l, x[0], y[0], bbox) ); */ + bbox->point = GTS_POINT(insert_vertex(r, l, x[0], y[0], bbox)); + + } + else { + /* Two points and one constraint edge */ + + /* the rest is just for bounding box */ + m = cartesian_gradient(x[0], y[0], x[1], y[1]); + + p[0].x = x[0]; + p[0].y = y[0]; + p[1].x = x[1]; + p[1].y = y[1]; + + vertex_outside_segment(&p[0], &p[1], t, &rv[0]); + vertices_on_line(&rv[0], perpendicular_gradient(m), t, &rv[1], &rv[2]); + + vertex_outside_segment(&p[1], &p[0], t, &rv[0]); + vertices_on_line(&rv[0], perpendicular_gradient(m), t, &rv[3], &rv[4]); + + if (wind(&rv[1], &rv[2], &rv[3]) != wind(&rv[2], &rv[3], &rv[4])) { + rv[0].x = rv[3].x; + rv[0].y = rv[3].y; + rv[3].x = rv[4].x; + rv[3].y = rv[4].y; + rv[4].x = rv[0].x; + rv[4].y = rv[0].y; + } + + vlist = rect_with_attachments(pad_rad(pad), + rv[1].x, rv[1].y, + rv[2].x, rv[2].y, rv[3].x, rv[3].y, rv[4].x, rv[4].y, l - r->layers); + bbox = toporouter_bbox_create(l - r->layers, vlist, PAD, pad); + r->bboxes = g_slist_prepend(r->bboxes, bbox); + insert_constraints_from_list(r, l, vlist, bbox); + g_list_free(vlist); + + /*bbox->point = GTS_POINT( gts_vertex_new(vertex_class, (x[0] + x[1]) / 2., (y[0] + y[1]) / 2., 0.) ); */ + bbox->point = GTS_POINT(insert_vertex(r, l, (x[0] + x[1]) / 2., (y[0] + y[1]) / 2., bbox)); + + /*bbox->constraints = g_list_concat(bbox->constraints, insert_constraint_edge(r, l, x[0], y[0], x[1], y[1], bbox)); */ + + } + + + } + + } + } + PCB_END_LOOP; + } + PCB_END_LOOP; + + return 0; +} + +/* + * Read points data (all layers) into GList + * + * Inserts pin and via points + */ +int read_points(toporouter_t * r, toporouter_layer_t * l, int layer) +{ + gdouble x, y, t; + + GList *vlist = NULL; + toporouter_bbox_t *bbox = NULL; + + PCB_ELEMENT_LOOP(PCB->Data); + { + PCB_PIN_LOOP(element); + { + + t = (gdouble) pin->Thickness / 2.0f; + x = pin->X; + y = pin->Y; + + if (PCB_FLAG_TEST(PCB_FLAG_SQUARE, pin)) { + + vlist = rect_with_attachments(pin_rad(pin), x - t, y - t, x - t, y + t, x + t, y + t, x + t, y - t, l - r->layers); + bbox = toporouter_bbox_create(l - r->layers, vlist, PIN, pin); + r->bboxes = g_slist_prepend(r->bboxes, bbox); + insert_constraints_from_list(r, l, vlist, bbox); + g_list_free(vlist); + bbox->point = GTS_POINT(insert_vertex(r, l, x, y, bbox)); + + } + else if (PCB_FLAG_TEST(PCB_FLAG_OCTAGON, pin)) { + /* TODO: Handle octagon pins */ + fprintf(stderr, "No support for octagon pins yet\n"); + } + else { + vlist = rect_with_attachments(pin_rad(pin), x - t, y - t, x - t, y + t, x + t, y + t, x + t, y - t, l - r->layers); + bbox = toporouter_bbox_create(l - r->layers, vlist, PIN, pin); + r->bboxes = g_slist_prepend(r->bboxes, bbox); + g_list_free(vlist); + bbox->point = GTS_POINT(insert_vertex(r, l, x, y, bbox)); + } + } + PCB_END_LOOP; + } + PCB_END_LOOP; + + PCB_VIA_LOOP(PCB->Data); + { + + t = (gdouble) via->Thickness / 2.0f; + x = via->X; + y = via->Y; + + if (PCB_FLAG_TEST(PCB_FLAG_SQUARE, via)) { + + vlist = rect_with_attachments(pin_rad((pcb_pin_t *) via), + x - t, y - t, x - t, y + t, x + t, y + t, x + t, y - t, l - r->layers); + bbox = toporouter_bbox_create(l - r->layers, vlist, VIA, via); + r->bboxes = g_slist_prepend(r->bboxes, bbox); + insert_constraints_from_list(r, l, vlist, bbox); + g_list_free(vlist); + bbox->point = GTS_POINT(insert_vertex(r, l, x, y, bbox)); + + } + else if (PCB_FLAG_TEST(PCB_FLAG_OCTAGON, via)) { + /* TODO: Handle octagon vias */ + fprintf(stderr, "No support for octagon vias yet\n"); + } + else { + + vlist = rect_with_attachments(pin_rad((pcb_pin_t *) via), + x - t, y - t, x - t, y + t, x + t, y + t, x + t, y - t, l - r->layers); + bbox = toporouter_bbox_create(l - r->layers, vlist, VIA, via); + r->bboxes = g_slist_prepend(r->bboxes, bbox); + g_list_free(vlist); + + bbox->point = GTS_POINT(insert_vertex(r, l, x, y, bbox)); + + } + } + PCB_END_LOOP; + return 0; +} + +/* + * Read line data from layer into toporouter_layer_t struct + * + * Inserts points and constraints into GLists + */ +int read_lines(toporouter_t * r, toporouter_layer_t * l, pcb_layer_t * layer, int ln) +{ + gdouble xs[2], ys[2]; + + GList *vlist = NULL; + toporouter_bbox_t *bbox = NULL; + + GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class()); + + PCB_LINE_LOOP(layer); + { + xs[0] = line->Point1.X; + xs[1] = line->Point2.X; + ys[0] = line->Point1.Y; + ys[1] = line->Point2.Y; + if (!(xs[0] == xs[1] && ys[0] == ys[1])) { + vlist = g_list_prepend(NULL, gts_vertex_new(vertex_class, xs[0], ys[0], l - r->layers)); + vlist = g_list_prepend(vlist, gts_vertex_new(vertex_class, xs[1], ys[1], l - r->layers)); + /* TODO: replace this with surface version */ + bbox = toporouter_bbox_create_from_points(pcb_layer_get_group(ln), vlist, LINE, line); + r->bboxes = g_slist_prepend(r->bboxes, bbox); + /*new;; + //insert_constraints_from_list(r, l, vlist, bbox); */ + g_list_free(vlist); +/* bbox->point = GTS_POINT( insert_vertex(r, l, (xs[0]+xs[1])/2., (ys[0]+ys[1])/2., bbox) );*/ + + bbox->constraints = + g_list_concat(bbox->constraints, insert_constraint_edge(r, l, xs[0], ys[0], 0, xs[1], ys[1], 0, bbox)); + } + } + PCB_END_LOOP; + + return 0; +} + +void create_board_edge(gdouble x0, gdouble y0, gdouble x1, gdouble y1, gdouble max, gint layer, GList ** vlist) +{ + GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class()); + gdouble d = sqrt(pow(x0 - x1, 2) + pow(y0 - y1, 2)); + guint n = d / max, count = 1; + gdouble inc = n ? d / n : d; + gdouble x = x0, y = y0; + + *vlist = g_list_prepend(*vlist, gts_vertex_new(vertex_class, x0, y0, layer)); + + while (count < n) { + coord_move_towards_coord_values(x0, y0, x1, y1, inc, &x, &y); + *vlist = g_list_prepend(*vlist, gts_vertex_new(vertex_class, x, y, layer)); + + x0 = x; + y0 = y; + count++; + } + +} + + +int read_board_constraints(toporouter_t * r, toporouter_layer_t * l, int layer) +{ +/* GtsVertexClass *vertex_class = GTS_VERTEX_CLASS (toporouter_vertex_class ());*/ + GList *vlist = NULL; + toporouter_bbox_t *bbox = NULL; + + /* Add points for corners of board, and constrain those edges */ +/* vlist = g_list_prepend(NULL, gts_vertex_new (vertex_class, 0., 0., layer)); + vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, PCB->MaxWidth, 0., layer)); + vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, PCB->MaxWidth, PCB->MaxHeight, layer)); + vlist = g_list_prepend(vlist, gts_vertex_new (vertex_class, 0., PCB->MaxHeight, layer));*/ + + create_board_edge(0., 0., PCB->MaxWidth, 0., 10000., layer, &vlist); + create_board_edge(PCB->MaxWidth, 0., PCB->MaxWidth, PCB->MaxHeight, 10000., layer, &vlist); + create_board_edge(PCB->MaxWidth, PCB->MaxHeight, 0., PCB->MaxHeight, 10000., layer, &vlist); + create_board_edge(0., PCB->MaxHeight, 0., 0., 10000., layer, &vlist); + + bbox = toporouter_bbox_create(layer, vlist, BOARD, NULL); + r->bboxes = g_slist_prepend(r->bboxes, bbox); + insert_constraints_from_list(r, l, vlist, bbox); + g_list_free(vlist); + + return 0; +} + +gdouble triangle_cost(GtsTriangle * t, gpointer * data) +{ + + gdouble *min_quality = (gdouble *) data[0]; + gdouble *max_area = (gdouble *) data[1]; + gdouble quality = gts_triangle_quality(t); + gdouble area = gts_triangle_area(t); + + if (quality < *min_quality || area > *max_area) + return quality; + return 0.0; +} + + +void print_constraint(toporouter_constraint_t * e) +{ + printf("CONSTRAINT:\n"); + print_vertex(tedge_v1(e)); + print_vertex(tedge_v2(e)); +} + +void print_edge(toporouter_edge_t * e) +{ + GList *i = edge_routing(e); + + printf("EDGE:\n"); + + print_vertex(tedge_v1(e)); + + while (i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); + print_vertex(v); + i = i->next; + } + + print_vertex(tedge_v2(e)); +} + +static void pick_first_face(GtsFace * f, GtsFace ** first) +{ + if (*first == NULL) + *first = f; +} + +void unconstrain(toporouter_layer_t * l, toporouter_constraint_t * c) +{ + toporouter_edge_t *e; + + gts_allow_floating_vertices = TRUE; + e = TOPOROUTER_EDGE(gts_edge_new(GTS_EDGE_CLASS(toporouter_edge_class()), GTS_SEGMENT(c)->v1, GTS_SEGMENT(c)->v2)); + gts_edge_replace(GTS_EDGE(c), GTS_EDGE(e)); + l->constraints = g_list_remove(l->constraints, c); + c->box->constraints = g_list_remove(c->box->constraints, c); + c->box = NULL; + gts_object_destroy(GTS_OBJECT(c)); + gts_allow_floating_vertices = FALSE; +} + +void build_cdt(toporouter_t * r, toporouter_layer_t * l) +{ + /* TODO: generalize into surface *cdt_create(vertices, constraints) */ + GList *i; + /*GtsEdge *temp; + GtsVertex *v; */ + GtsTriangle *t; + GtsVertex *v1, *v2, *v3; + GSList *vertices_slist; + + vertices_slist = list_to_slist(l->vertices); + + if (l->surface) { + GtsFace *first = NULL; + gts_surface_foreach_face(l->surface, (GtsFunc) pick_first_face, &first); + gts_surface_traverse_destroy(gts_surface_traverse_new(l->surface, first)); + } + + t = gts_triangle_enclosing(gts_triangle_class(), vertices_slist, 1000.0f); + gts_triangle_vertices(t, &v1, &v2, &v3); + + g_slist_free(vertices_slist); + + l->surface = gts_surface_new(gts_surface_class(), gts_face_class(), + GTS_EDGE_CLASS(toporouter_edge_class()), GTS_VERTEX_CLASS(toporouter_vertex_class())); + + gts_surface_add_face(l->surface, gts_face_new(gts_face_class(), t->e1, t->e2, t->e3)); + + +/* fprintf(stderr, "ADDED VERTICES\n");*/ +/* + GtsFace *debugface; + + if((debugface = gts_delaunay_check(l->surface))) { + fprintf(stderr, "WARNING: Delaunay check failed\n"); + fprintf(stderr, "\tViolating triangle:\n"); + fprintf(stderr, "\t%f,%f %f,%f\n", + debugface->triangle.e1->segment.v1->p.x, + debugface->triangle.e1->segment.v1->p.y, + debugface->triangle.e1->segment.v2->p.x, + debugface->triangle.e1->segment.v2->p.y + ); + fprintf(stderr, "\t%f,%f %f,%f\n", + debugface->triangle.e2->segment.v1->p.x, + debugface->triangle.e2->segment.v1->p.y, + debugface->triangle.e2->segment.v2->p.x, + debugface->triangle.e2->segment.v2->p.y + ); + fprintf(stderr, "\t%f,%f %f,%f\n", + debugface->triangle.e3->segment.v1->p.x, + debugface->triangle.e3->segment.v1->p.y, + debugface->triangle.e3->segment.v2->p.x, + debugface->triangle.e3->segment.v2->p.y + ); +/* toporouter_draw_surface(r, l->surface, "debug.png", 4096, 4096); */ + { + int i; + for (i = 0; i < groupcount(); i++) { + char buffer[256]; + sprintf(buffer, "debug-%d.png", i); + toporouter_draw_surface(r, r->layers[i].surface, buffer, 2048, 2048, 2, NULL, i, NULL); + } + } + +/* }*/ + +check_cons_continuation: + i = l->constraints; + while (i) { + toporouter_constraint_t *c1 = TOPOROUTER_CONSTRAINT(i->data); + GList *j = i->next; + /* printf("adding cons: "); print_constraint(c1); */ + + while (j) { + toporouter_constraint_t *c2 = TOPOROUTER_CONSTRAINT(j->data); + guint rem = 0; + GList *temp; + + /* printf("\tconflict: "); print_constraint(c2); */ + toporouter_bbox_t *c1box = c1->box, *c2box = c2->box; + toporouter_vertex_t *c1v1 = tedge_v1(c1); + toporouter_vertex_t *c1v2 = tedge_v2(c1); + toporouter_vertex_t *c2v1 = tedge_v1(c2); + toporouter_vertex_t *c2v2 = tedge_v2(c2); + + if (gts_segments_are_intersecting(GTS_SEGMENT(c1), GTS_SEGMENT(c2)) == GTS_IN) { + toporouter_vertex_t *v; + unconstrain(l, c1); + unconstrain(l, c2); + rem = 1; + /* proper intersection */ + v = TOPOROUTER_VERTEX(vertex_intersect(GTS_VERTEX(c1v1), GTS_VERTEX(c1v2), GTS_VERTEX(c2v1), GTS_VERTEX(c2v2))); + + /* remove both constraints + replace with 4x constraints + insert new intersection vertex */ + GTS_POINT(v)->z = vz(c1v1); + + l->vertices = g_list_prepend(l->vertices, v); +/* gts_delaunay_add_vertex (l->surface, GTS_VERTEX(v), NULL); */ + + v->bbox = c1box; + + temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(v), vy(v), 0, c1box); + c1box->constraints = g_list_concat(c1box->constraints, temp); + + temp = insert_constraint_edge(r, l, vx(c1v2), vy(c1v2), 0, vx(v), vy(v), 0, c1box); + c1box->constraints = g_list_concat(c1box->constraints, temp); + + temp = insert_constraint_edge(r, l, vx(c2v1), vy(c2v1), 0, vx(v), vy(v), 0, c2box); + c2box->constraints = g_list_concat(c2box->constraints, temp); + + temp = insert_constraint_edge(r, l, vx(c2v2), vy(c2v2), 0, vx(v), vy(v), 0, c2box); + c2box->constraints = g_list_concat(c2box->constraints, temp); + + } + else if (gts_segments_are_intersecting(GTS_SEGMENT(c1), GTS_SEGMENT(c2)) == GTS_ON || + gts_segments_are_intersecting(GTS_SEGMENT(c2), GTS_SEGMENT(c1)) == GTS_ON) { + + if (vertex_between(edge_v1(c2), edge_v2(c2), edge_v1(c1)) && vertex_between(edge_v1(c2), edge_v2(c2), edge_v2(c1))) { + unconstrain(l, c1); + unconstrain(l, c2); + rem = 1; + /* remove c1 */ + temp = insert_constraint_edge(r, l, vx(c2v1), vy(c2v1), 0, vx(c2v2), vy(c2v2), 0, c2box); + c2box->constraints = g_list_concat(c2box->constraints, temp); + + } + else if (vertex_between(edge_v1(c1), edge_v2(c1), edge_v1(c2)) && vertex_between(edge_v1(c1), edge_v2(c1), edge_v2(c2))) { + unconstrain(l, c1); + unconstrain(l, c2); + rem = 1; + /* remove c2 */ + temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c1v2), vy(c1v2), 0, c1box); + c1box->constraints = g_list_concat(c1box->constraints, temp); + + /*}else if(!vertex_wind(edge_v1(c1), edge_v2(c1), edge_v1(c2)) && !vertex_wind(edge_v1(c1), edge_v2(c1), edge_v2(c2))) { */ + /* }else if(vertex_between(edge_v1(c1), edge_v2(c1), edge_v1(c2)) || vertex_between(edge_v1(c1), edge_v2(c1), edge_v2(c2))) { + unconstrain(l, c1); unconstrain(l, c2); + rem = 1; + printf("all colinear\n"); + // exit(1); + temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c1v2), vy(c1v2), 0, c1box); + c1box->constraints = g_list_concat(c1box->constraints, temp); + + if(vertex_between(GTS_VERTEX(c1v1), GTS_VERTEX(c1v2), GTS_VERTEX(c2v2))) { + // v2 of c2 is inner + if(vertex_between(GTS_VERTEX(c2v1), GTS_VERTEX(c2v2), GTS_VERTEX(c1v2))) { + // v2 of c1 is inner + // c2 = c1.v2 -> c2.v1 + temp = insert_constraint_edge(r, l, vx(c1v2), vy(c1v2), 0, vx(c2v1), vy(c2v1), 0, c2box); + c2box->constraints = g_list_concat(c2box->constraints, temp); + }else{ + // v1 of c1 is inner + // c2 = c1.v1 -> c2.v1 + temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c2v1), vy(c2v1), 0, c2box); + c2box->constraints = g_list_concat(c2box->constraints, temp); + } + }else{ + // v1 of c2 is inner + if(vertex_between(GTS_VERTEX(c2v1), GTS_VERTEX(c2v2), GTS_VERTEX(c1v2))) { + // v2 of c1 is inner + // c2 = c1.v2 -> c2.v2 + temp = insert_constraint_edge(r, l, vx(c1v2), vy(c1v2), 0, vx(c2v2), vy(c2v2), 0, c2box); + c2box->constraints = g_list_concat(c2box->constraints, temp); + }else{ + // v1 of c1 is inner + // c2 = c1.v1 -> c2.v2 + temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c2v2), vy(c2v2), 0, c2box); + c2box->constraints = g_list_concat(c2box->constraints, temp); + } + } */ + } + else if (vertex_between(edge_v1(c2), edge_v2(c2), edge_v1(c1)) && c1v1 != c2v1 && c1v1 != c2v2) { + unconstrain(l, c1); + unconstrain(l, c2); + rem = 1; + /*v1 of c1 is on c2 */ + printf("v1 of c1 on c2\n"); + + /* replace with 2x constraints */ + temp = insert_constraint_edge(r, l, vx(c2v1), vy(c2v1), 0, vx(c1v1), vy(c1v1), 0, c2box); + c2box->constraints = g_list_concat(c2box->constraints, temp); + temp = insert_constraint_edge(r, l, vx(c2v2), vy(c2v2), 0, vx(c1v1), vy(c1v1), 0, c2box); + c2box->constraints = g_list_concat(c2box->constraints, temp); + + temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c1v2), vy(c1v2), 0, c1box); + c1box->constraints = g_list_concat(c1box->constraints, temp); + + /* restore c1 + temp = insert_constraint_edge(r, l, vx(tedge_v2(c1)), vy(tedge_v2(c1)), 0, vx(tedge_v1(c1)), vy(tedge_v1(c1)), 0, c1->box); + c2->box->constraints = g_list_concat(c2->box->constraints, temp); */ + + } + else if (vertex_between(edge_v1(c2), edge_v2(c2), edge_v2(c1)) && c1v2 != c2v1 && c1v2 != c2v2) { + unconstrain(l, c1); + unconstrain(l, c2); + rem = 1; + /*v2 of c1 is on c2 */ + printf("v2 of c1 on c2\n"); + + /* replace with 2x constraints */ + temp = insert_constraint_edge(r, l, vx(c2v1), vy(c2v1), 0, vx(c1v2), vy(c1v2), 0, c2box); + c2box->constraints = g_list_concat(c2box->constraints, temp); + temp = insert_constraint_edge(r, l, vx(c2v2), vy(c2v2), 0, vx(c1v2), vy(c1v2), 0, c2box); + c2box->constraints = g_list_concat(c2box->constraints, temp); + + temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c1v2), vy(c1v2), 0, c1box); + c1box->constraints = g_list_concat(c1box->constraints, temp); + + } + else if (vertex_between(edge_v1(c1), edge_v2(c1), edge_v1(c2)) && c2v1 != c1v1 && c2v1 != c1v2) { + unconstrain(l, c1); + unconstrain(l, c2); + rem = 1; + /*v1 of c2 is on c1 */ + printf("v1 of c2 on c1\n"); + + /* replace with 2x constraints */ + temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c2v1), vy(c2v1), 0, c1box); + c1box->constraints = g_list_concat(c1box->constraints, temp); + temp = insert_constraint_edge(r, l, vx(c1v2), vy(c1v2), 0, vx(c2v1), vy(c2v1), 0, c1box); + c1box->constraints = g_list_concat(c1box->constraints, temp); + + temp = insert_constraint_edge(r, l, vx(c2v1), vy(c2v1), 0, vx(c2v2), vy(c2v2), 0, c2box); + c2box->constraints = g_list_concat(c2box->constraints, temp); + } + else if (vertex_between(edge_v1(c1), edge_v2(c1), edge_v2(c2)) && c2v2 != c1v1 && c2v2 != c1v2) { + unconstrain(l, c1); + unconstrain(l, c2); + rem = 1; + /*v2 of c2 is on c1 */ + printf("v2 of c2 on c1\n"); + + /* replace with 2x constraints */ + temp = insert_constraint_edge(r, l, vx(c1v1), vy(c1v1), 0, vx(c2v2), vy(c2v2), 0, c1box); + c1box->constraints = g_list_concat(c1box->constraints, temp); + temp = insert_constraint_edge(r, l, vx(c1v2), vy(c1v2), 0, vx(c2v2), vy(c2v2), 0, c1box); + c1box->constraints = g_list_concat(c1box->constraints, temp); + + temp = insert_constraint_edge(r, l, vx(c2v1), vy(c2v1), 0, vx(c2v2), vy(c2v2), 0, c2box); + c2box->constraints = g_list_concat(c2box->constraints, temp); + } + } + if (rem) + goto check_cons_continuation; + + j = j->next; + } + + i = i->next; + } + + i = l->vertices; + while (i) { + /*v = i->data; + if(r->flags & TOPOROUTER_FLAG_DEBUG_CDTS) + fprintf(stderr, "\tadding vertex %f,%f\n", v->p.x, v->p.y); */ + toporouter_vertex_t *v = TOPOROUTER_VERTEX(gts_delaunay_add_vertex(l->surface, (GtsVertex *) i->data, NULL)); + if (v) { + printf("conflict: "); + print_vertex(v); + } + + i = i->next; + } + i = l->constraints; + while (i) { + + /* toporouter_constraint_t *c1 = TOPOROUTER_CONSTRAINT(i->data); + printf("adding cons: "); print_constraint(c1); */ + + GSList *conflicts = gts_delaunay_add_constraint(l->surface, (GtsConstraint *) i->data); + GSList *j = conflicts; + while (j) { + if (TOPOROUTER_IS_CONSTRAINT(j->data)) { + toporouter_constraint_t *c2 = TOPOROUTER_CONSTRAINT(j->data); + + printf("\tconflict: "); + print_constraint(c2); + + } + j = j->next; + } + g_slist_free(conflicts); + + i = i->next; + } + +/* if(rerun) + goto build_cdt_continuation; + fprintf(stderr, "ADDED CONSTRAINTS\n");*/ + gts_allow_floating_vertices = TRUE; + gts_object_destroy(GTS_OBJECT(v1)); + gts_object_destroy(GTS_OBJECT(v2)); + gts_object_destroy(GTS_OBJECT(v3)); + gts_allow_floating_vertices = FALSE; + +/* + { + gpointer data[2]; + gdouble quality = 0.50, area = G_MAXDOUBLE; + guint num = gts_delaunay_conform(l->surface, -1, (GtsEncroachFunc) gts_vertex_encroaches_edge, NULL); + + if (num == 0){ + data[0] = &quality; + data[1] = &area; + num = gts_delaunay_refine(l->surface, -1, (GtsEncroachFunc) gts_vertex_encroaches_edge, NULL, (GtsKeyFunc) triangle_cost, data); + } + } +*/ +#ifdef DEBUG_IMPORT + gts_surface_print_stats(l->surface, stderr); +#endif + +#if 0 + { + char buffer[64]; + FILE *fout2; + sprintf(buffer, "surface%d.gts", l - r->layers); + fout2 = fopen(buffer, "w"); + gts_surface_write(l->surface, fout2); + } +#endif + +} + +gint visited_cmp(gconstpointer a, gconstpointer b) +{ + if (a < b) + return -1; + if (a > b) + return 1; + return 0; +} + +gdouble coord_xangle(gdouble ax, gdouble ay, gdouble bx, gdouble by) +{ + gdouble dx, dy, theta; + + dx = fabs(ax - bx); + dy = fabs(ay - by); + + if (dx < EPSILON) { + theta = M_PI / 2.; + } + else + theta = atan(dy / dx); + + if (by <= ay) { + if (bx < ax) + theta = M_PI - theta; + } + else { + if (bx < ax) + theta += M_PI; + else + theta = (2 * M_PI) - theta; + } + + return theta; +} + +gdouble point_xangle(GtsPoint * a, GtsPoint * b) +{ + gdouble dx, dy, theta; + + dx = fabs(a->x - b->x); + dy = fabs(a->y - b->y); + + if (dx < EPSILON) { + theta = M_PI / 2.; + } + else + theta = atan(dy / dx); + + if (b->y >= a->y) { + if (b->x < a->x) + theta = M_PI - theta; + } + else { + if (b->x < a->x) + theta += M_PI; + else + theta = (2 * M_PI) - theta; + } + + return theta; +} + + +GList *cluster_vertices(toporouter_t * r, toporouter_cluster_t * c) +{ + GList *rval = NULL; + + if (!c) + return NULL; + + FOREACH_CLUSTER(c->netlist->clusters) { + if ((r->flags & TOPOROUTER_FLAG_AFTERRUBIX && cluster->c == c->c) + || (!(r->flags & TOPOROUTER_FLAG_AFTERRUBIX) && cluster == c)) { + FOREACH_BBOX(cluster->boxes) { + if (box->type == LINE) { + g_assert(box->constraints->data); + rval = g_list_prepend(rval, tedge_v1(box->constraints->data)); + rval = g_list_prepend(rval, tedge_v2(box->constraints->data)); + } + else if (box->point) { + rval = g_list_prepend(rval, TOPOROUTER_VERTEX(box->point)); + /*g_assert(vertex_bbox(TOPOROUTER_VERTEX(box->point)) == box); */ + } + else { + printf("WARNING: cluster_vertices: unhandled bbox type\n"); + } + + } + FOREACH_END; + + + } + + } + FOREACH_END; + + return rval; +} + +void print_cluster(toporouter_cluster_t * c) +{ + + if (!c) { + printf("[CLUSTER (NULL)]\n"); + return; + } + + printf("CLUSTER %d: NETLIST = %s STYLE = %s\n", c->c, c->netlist->netlist, c->netlist->style); + + FOREACH_BBOX(c->boxes) { + print_bbox(box); + } + FOREACH_END; +} + + +toporouter_cluster_t *cluster_create(toporouter_t * r, toporouter_netlist_t * netlist) +{ + toporouter_cluster_t *c = (toporouter_cluster_t *) malloc(sizeof(toporouter_cluster_t)); + + c->c = c->pc = netlist->clusters->len; + g_ptr_array_add(netlist->clusters, c); + c->netlist = netlist; + c->boxes = g_ptr_array_new(); + + return c; +} + +toporouter_bbox_t *toporouter_bbox_locate(toporouter_t * r, toporouter_term_t type, void *data, gdouble x, gdouble y, + guint layergroup) +{ + GtsPoint *p = gts_point_new(gts_point_class(), x, y, layergroup); + GSList *boxes = gts_bb_tree_stabbed(r->bboxtree, p), *i = boxes; + + gts_object_destroy(GTS_OBJECT(p)); + + while (i) { + toporouter_bbox_t *box = TOPOROUTER_BBOX(i->data); + + if (box->type == type && box->data == data) { + g_slist_free(boxes); + return box; + } + + i = i->next; + } + + g_slist_free(boxes); + return NULL; +} + +void cluster_join_bbox(toporouter_cluster_t * cluster, toporouter_bbox_t * box) +{ + if (box) { + g_ptr_array_add(cluster->boxes, box); + box->cluster = cluster; + } +} + +toporouter_netlist_t *netlist_create(toporouter_t * r, char *netlist, char *style) +{ + toporouter_netlist_t *nl = (toporouter_netlist_t *) malloc(sizeof(toporouter_netlist_t)); + nl->netlist = netlist; + nl->style = style; + nl->clusters = g_ptr_array_new(); + nl->routes = g_ptr_array_new(); + nl->routed = NULL; + nl->pair = NULL; + g_ptr_array_add(r->netlists, nl); + return nl; +} + +void import_clusters(toporouter_t * r) +{ + pcb_netlist_list_t nets; + pcb_reset_conns(pcb_false); + nets = pcb_rat_collect_subnets(pcb_false); + PCB_NETLIST_LOOP(&nets); + { + if (netlist->NetN > 0) { + toporouter_netlist_t *nl = netlist_create(r, netlist->Net->Connection->menu->Name, netlist->Net->Connection->menu->Style); + + PCB_NET_LOOP(netlist); + { + + toporouter_cluster_t *cluster = cluster_create(r, nl); +#ifdef DEBUG_MERGING + printf("NET:\n"); +#endif + PCB_CONNECTION_LOOP(net); + { + + if (connection->type == PCB_TYPE_LINE) { + pcb_line_t *line = (pcb_line_t *) connection->ptr2; + toporouter_bbox_t *box = toporouter_bbox_locate(r, LINE, line, connection->X, connection->Y, connection->group); + cluster_join_bbox(cluster, box); + +#ifdef DEBUG_MERGING + pcb_printf("\tLINE %#mD\n", connection->X, connection->Y); +#endif + } + else if (connection->type == PCB_TYPE_PAD) { + pcb_pad_t *pad = (pcb_pad_t *) connection->ptr2; + toporouter_bbox_t *box = toporouter_bbox_locate(r, PAD, pad, connection->X, connection->Y, connection->group); + cluster_join_bbox(cluster, box); + +#ifdef DEBUG_MERGING + pcb_printf("\tPAD %#mD\n", connection->X, connection->Y); +#endif + } + else if (connection->type == PCB_TYPE_PIN) { + guint m; + for (m = 0; m < groupcount(); m++) { + pcb_pin_t *pin = (pcb_pin_t *) connection->ptr2; + toporouter_bbox_t *box = toporouter_bbox_locate(r, PIN, pin, connection->X, connection->Y, m); + cluster_join_bbox(cluster, box); + } + +#ifdef DEBUG_MERGING + pcb_printf("\tPIN %#mD\n", connection->X, connection->Y); +#endif + } + else if (connection->type == PCB_TYPE_VIA) { + guint m; + for (m = 0; m < groupcount(); m++) { + pcb_pin_t *pin = (pcb_pin_t *) connection->ptr2; + toporouter_bbox_t *box = toporouter_bbox_locate(r, VIA, pin, connection->X, connection->Y, m); + cluster_join_bbox(cluster, box); + } + +#ifdef DEBUG_MERGING + pcb_printf("\tVIA %#mD\n", connection->X, connection->Y); +#endif + } + else if (connection->type == PCB_TYPE_POLYGON) { + pcb_polygon_t *polygon = (pcb_polygon_t *) connection->ptr2; + toporouter_bbox_t *box = + toporouter_bbox_locate(r, POLYGON, polygon, connection->X, connection->Y, connection->group); + cluster_join_bbox(cluster, box); + +#ifdef DEBUG_MERGING + pcb_printf("\tPOLYGON %#mD\n", connection->X, connection->Y); +#endif + + } + } + PCB_END_LOOP; +#ifdef DEBUG_MERGING + printf("\n"); +#endif + } + PCB_END_LOOP; + + } + } + PCB_END_LOOP; + pcb_netlist_list_free(&nets); +} + +void import_geometry(toporouter_t * r) +{ + toporouter_layer_t *cur_layer; + + int group; + +#ifdef DEBUG_IMPORT + for (group = 0; group < pcb_max_group; group++) { + printf("Group %d: Number %d:\n", group, PCB->LayerGroups.Number[group]); + + for (int entry = 0; entry < PCB->LayerGroups.Number[group]; entry++) { + printf("\tEntry %d\n", PCB->LayerGroups.Entries[group][entry]); + } + } +#endif + /* Allocate space for per layer struct */ + cur_layer = r->layers = (toporouter_layer_t *) malloc(groupcount() * sizeof(toporouter_layer_t)); + + /* Foreach layer, read in pad vertices and constraints, and build CDT */ + for (group = 0; group < pcb_max_group; group++) { +#ifdef DEBUG_IMPORT + printf("*** LAYER GROUP %d ***\n", group); +#endif + if (PCB->LayerGroups.Number[group] > 0) { + cur_layer->vertices = NULL; + cur_layer->constraints = NULL; + +#ifdef DEBUG_IMPORT + printf("reading board constraints from layer %d into group %d\n", PCB->LayerGroups.Entries[group][0], group); +#endif + read_board_constraints(r, cur_layer, PCB->LayerGroups.Entries[group][0]); +#ifdef DEBUG_IMPORT + printf("reading points from layer %d into group %d \n", PCB->LayerGroups.Entries[group][0], group); +#endif + read_points(r, cur_layer, PCB->LayerGroups.Entries[group][0]); + +/*#ifdef DEBUG_IMPORT + printf("reading pads from layer %d into group %d\n", number, group); + #endif*/ + read_pads(r, cur_layer, group); + + PCB_COPPER_GROUP_LOOP(PCB->Data, group) { + +#ifdef DEBUG_IMPORT + printf("reading lines from layer %d into group %d\n", number, group); +#endif + read_lines(r, cur_layer, layer, number); + + } + PCB_END_LOOP; + + + +#ifdef DEBUG_IMPORT + printf("building CDT\n"); +#endif + build_cdt(r, cur_layer); + printf("finished\n"); +/* { + int i; + for(i=0;ilayers[i].surface, buffer, 2048, 2048, 2, NULL, i, NULL); + } + }*/ +#ifdef DEBUG_IMPORT + printf("finished building CDT\n"); +#endif + cur_layer++; + } + } + + r->bboxtree = gts_bb_tree_new(r->bboxes); + + import_clusters(r); + +#ifdef DEBUG_IMPORT + printf("finished import!\n"); +#endif +} + + +gint compare_points(gconstpointer a, gconstpointer b) +{ + GtsPoint *i = GTS_POINT(a); + GtsPoint *j = GTS_POINT(b); + + if (i->x == j->x) { + if (i->y == j->y) + return 0; + if (i->y < j->y) + return -1; + return 1; + } + if (i->x < j->x) + return -1; + return 1; +} + +gint compare_segments(gconstpointer a, gconstpointer b) +{ + if (a == b) + return 0; + if (a < b) + return -1; + return 1; +} + +#define DEBUG_CLUSTER_FIND 1 +toporouter_cluster_t *cluster_find(toporouter_t * r, gdouble x, gdouble y, gdouble z) +{ + GtsPoint *p = gts_point_new(gts_point_class(), x, y, z); + GSList *hits = gts_bb_tree_stabbed(r->bboxtree, p); + toporouter_cluster_t *rval = NULL; + +#ifdef DEBUG_CLUSTER_FIND + printf("FINDING %f,%f,%f\n\n", x, y, z); +#endif + + while (hits) { + toporouter_bbox_t *box = TOPOROUTER_BBOX(hits->data); + +#ifdef DEBUG_CLUSTER_FIND + printf("HIT BOX: "); + print_bbox(box); +#endif + + if (box->layer == (int) z) { + if (box->type != BOARD) { + if (box->type == LINE) { + pcb_line_t *line = (pcb_line_t *) box->data; + gint linewind = coord_wind(line->Point1.X, line->Point1.Y, x, y, line->Point2.X, line->Point2.Y); + + if (line->Point1.X > x - EPSILON && line->Point1.X < x + EPSILON && + line->Point1.Y > y - EPSILON && line->Point1.Y < y + EPSILON) { + rval = box->cluster; + /* break; */ + } + if (line->Point2.X > x - EPSILON && line->Point2.X < x + EPSILON && + line->Point2.Y > y - EPSILON && line->Point2.Y < y + EPSILON) { + rval = box->cluster; + /* break; */ + } + if (!linewind) { + rval = box->cluster; + /* break; */ + } + + } + else if (box->surface) { + + if (gts_point_locate(p, box->surface, NULL)) { + rval = box->cluster; + break; + } + + } + } + } + hits = hits->next; + } + + gts_object_destroy(GTS_OBJECT(p)); + + +#ifdef DEBUG_CLUSTER_FIND + printf("cluster_find: %f,%f,%f: ", x, y, z); + print_cluster(rval); +#endif + + return rval; +} + +gdouble simple_h_cost(toporouter_t * r, toporouter_vertex_t * curpoint, toporouter_vertex_t * destpoint) +{ + gdouble layerpenalty = (vz(curpoint) == vz(destpoint)) ? 0. : r->viacost; + + return gts_point_distance(GTS_POINT(curpoint), GTS_POINT(destpoint)) + layerpenalty; +} + +#define FCOST(x) (x->gcost + x->hcost) +gdouble route_heap_cmp(gpointer item, gpointer data) +{ + return FCOST(TOPOROUTER_VERTEX(item)); +} + +#define closelist_insert(p) closelist = g_list_prepend(closelist, p) + +typedef struct { + toporouter_vertex_t *key; + toporouter_vertex_t *result; +} toporouter_heap_search_data_t; + +void toporouter_heap_search(gpointer data, gpointer user_data) +{ + toporouter_vertex_t *v = TOPOROUTER_VERTEX(data); + toporouter_heap_search_data_t *heap_search_data = (toporouter_heap_search_data_t *) user_data; + if (v == heap_search_data->key) + heap_search_data->result = v; +} + +/* +void +toporouter_heap_color(gpointer data, gpointer user_data) +{ + toporouter_vertex_t *v = TOPOROUTER_VERTEX(data); + v->flags |= (guint) user_data; +} +*/ +static inline gdouble angle_span(gdouble a1, gdouble a2) +{ + if (a1 > a2) + return ((2 * M_PI) - a1 + a2); + return a2 - a1; +} + +gdouble region_span(toporouter_vertex_region_t * region) +{ + gdouble a1, a2; + + g_assert(region->v1 != NULL); + g_assert(region->v2 != NULL); + g_assert(region->origin != NULL); + + a1 = point_xangle(GTS_POINT(region->origin), GTS_POINT(region->v1)); + a2 = point_xangle(GTS_POINT(region->origin), GTS_POINT(region->v2)); + + return angle_span(a1, a2); +} + +gdouble edge_capacity(toporouter_edge_t * e) +{ + return gts_point_distance(GTS_POINT(edge_v1(e)), GTS_POINT(edge_v2(e))); +} + +gdouble edge_flow(toporouter_edge_t * e, toporouter_vertex_t * v1, toporouter_vertex_t * v2, toporouter_vertex_t * dest) +{ + GList *i = edge_routing(e); + toporouter_vertex_t *pv = tedge_v1(e), *v = NULL; + gdouble flow = 0.; + guint waiting = 1; + + if ((pv == v1 || pv == v2) && waiting) { + flow += min_vertex_net_spacing(pv, dest); + pv = dest; + waiting = 0; + } + + g_assert(v1 != v2); + + while (i) { + v = TOPOROUTER_VERTEX(i->data); + + + if (pv == dest) + flow += min_vertex_net_spacing(v, pv); + else + flow += min_spacing(v, pv); + + if ((v == v1 || v == v2) && waiting) { + flow += min_vertex_net_spacing(v, dest); + pv = dest; + waiting = 0; + } + else { + pv = v; + } + i = i->next; + } + + if (pv == dest) + flow += min_vertex_net_spacing(tedge_v2(e), pv); + else + flow += min_spacing(tedge_v2(e), pv); + + return flow; +} + +void print_path(GList * path) +{ + GList *i = path; + + printf("PATH:\n"); + while (i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); +/* printf("[V %f,%f,%f]\n", vx(v), vy(v), vz(v));*/ + print_vertex(v); + + if (v->child && !g_list_find(path, v->child)) + printf("\t CHILD NOT IN LIST\n"); + if (v->parent && !g_list_find(path, v->parent)) + printf("\t parent NOT IN LIST\n"); + i = i->next; + } + + +} + +GList *split_path(GList * path) +{ + toporouter_vertex_t *pv = NULL; + GList *curpath = NULL, *i, *paths = NULL; +#ifdef DEBUG_ROUTE + printf("PATH:\n"); +#endif + i = path; + while (i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); + +#ifdef DEBUG_ROUTE + printf("v = %f,%f ", vx(v), vy(v)); + if (v->parent) + printf("parent = %f,%f ", vx(v->parent), vy(v->parent)); + if (v->child) + printf("child = %f,%f ", vx(v->child), vy(v->child)); + printf("\n"); +#endif +/* printf("***\n"); + if(v) printf("v = %f,%f\n", GTS_POINT(v)->x, GTS_POINT(v)->y); + if(pv) printf("pv = %f,%f\n", GTS_POINT(pv)->x, GTS_POINT(pv)->y);*/ + + + if (pv) + if (GTS_POINT(v)->x == GTS_POINT(pv)->x && GTS_POINT(v)->y == GTS_POINT(pv)->y) { + if (g_list_length(curpath) > 1) + paths = g_list_prepend(paths, curpath); + curpath = NULL; + + pv->child = NULL; + v->parent = NULL; + } + + curpath = g_list_append(curpath, v); + + pv = v; + i = i->next; + } + + if (g_list_length(curpath) > 1) + paths = g_list_prepend(paths, curpath); + + return paths; +} + + + +#define edge_gradient(e) (cartesian_gradient(GTS_POINT(GTS_SEGMENT(e)->v1)->x, GTS_POINT(GTS_SEGMENT(e)->v1)->y, \ + GTS_POINT(GTS_SEGMENT(e)->v2)->x, GTS_POINT(GTS_SEGMENT(e)->v2)->y)) + + +/* sorting into ascending distance from v1 */ +gint routing_edge_insert(gconstpointer a, gconstpointer b, gpointer user_data) +{ + GtsPoint *v1 = GTS_POINT(edge_v1(user_data)); + + if (gts_point_distance2(v1, GTS_POINT(a)) < gts_point_distance2(v1, GTS_POINT(b)) - EPSILON) + return -1; + if (gts_point_distance2(v1, GTS_POINT(a)) > gts_point_distance2(v1, GTS_POINT(b)) + EPSILON) + return 1; +/* + printf("a = %x b = %x\n", (int) a, (int) b); + + printf("WARNING: routing_edge_insert() with same points..\n \ + v1 @ %f,%f\n\ + a @ %f,%f\n\ + b @ %f,%f\n", + v1->x, v1->y, + vx(a), vy(a), + vx(a), vy(b)); + printf("A: "); print_vertex(TOPOROUTER_VERTEX(a)); + printf("B: "); print_vertex(TOPOROUTER_VERTEX(b)); + + TOPOROUTER_VERTEX(a)->flags |= VERTEX_FLAG_RED; + TOPOROUTER_VERTEX(b)->flags |= VERTEX_FLAG_RED; +*/ + return 0; +} + + +toporouter_vertex_t *new_temp_toporoutervertex(gdouble x, gdouble y, toporouter_edge_t * e) +{ + GtsVertexClass *vertex_class = GTS_VERTEX_CLASS(toporouter_vertex_class()); + GList *i = edge_routing(e); + toporouter_vertex_t *r; + + while (i) { + r = TOPOROUTER_VERTEX(i->data); + if (epsilon_equals(vx(r), x) && epsilon_equals(vy(r), y)) { + if (r->flags & VERTEX_FLAG_TEMP) + return r; + } + i = i->next; + } + + r = TOPOROUTER_VERTEX(gts_vertex_new(vertex_class, x, y, vz(edge_v1(e)))); + r->flags |= VERTEX_FLAG_TEMP; + r->routingedge = e; + + if (TOPOROUTER_IS_CONSTRAINT(e)) + TOPOROUTER_CONSTRAINT(e)->routing = g_list_insert_sorted_with_data(edge_routing(e), r, routing_edge_insert, e); + else + e->routing = g_list_insert_sorted_with_data(edge_routing(e), r, routing_edge_insert, e); + + return r; +} + + +/* create vertex on edge e at radius r from v, closest to ref */ +toporouter_vertex_t *new_temp_toporoutervertex_in_segment(toporouter_edge_t * e, toporouter_vertex_t * v, gdouble r, + toporouter_vertex_t * ref) +{ + gdouble m = edge_gradient(e); + toporouter_spoint_t p, np1, np2; +/* toporouter_vertex_t *b = TOPOROUTER_VERTEX((GTS_VERTEX(v) == edge_v1(e)) ? edge_v2(e) : edge_v1(e)); */ + toporouter_vertex_t *rval = NULL; + p.x = vx(v); + p.y = vy(v); + + vertices_on_line(&p, m, r, &np1, &np2); + + if ((pow(np1.x - vx(ref), 2) + pow(np1.y - vy(ref), 2)) < (pow(np2.x - vx(ref), 2) + pow(np2.y - vy(ref), 2))) + rval = new_temp_toporoutervertex(np1.x, np1.y, e); + else + rval = new_temp_toporoutervertex(np2.x, np2.y, e); + + return rval; +} + +gint vertex_keepout_test(toporouter_t * r, toporouter_vertex_t * v) +{ + GList *i = r->keepoutlayers; + while (i) { + gdouble keepout = *((double *) i->data); + if (vz(v) == keepout) + return 1; + i = i->next; + } + return 0; +} + +void +closest_cluster_pair(toporouter_t * r, GList * src_vertices, GList * dest_vertices, toporouter_vertex_t ** a, + toporouter_vertex_t ** b) +{ + GList *i = src_vertices, *j = dest_vertices; + + gdouble min = 0.; + *a = NULL; + *b = NULL; + + i = src_vertices; + while (i) { + toporouter_vertex_t *v1 = TOPOROUTER_VERTEX(i->data); + + if (vertex_keepout_test(r, v1)) { + i = i->next; + continue; + } + + j = dest_vertices; + while (j) { + toporouter_vertex_t *v2 = TOPOROUTER_VERTEX(j->data); + if (vertex_keepout_test(r, v2) || vz(v2) != vz(v1)) { + j = j->next; + continue; + } + + if (!*a) { + *a = v1; + *b = v2; + min = simple_h_cost(r, *a, *b); + } + else { + gdouble tempd = simple_h_cost(r, v1, v2); + if (r->flags & TOPOROUTER_FLAG_GOFAR && tempd > min) { + *a = v1; + *b = v2; + min = tempd; + } + else if (tempd < min) { + *a = v1; + *b = v2; + min = tempd; + } + } + + j = j->next; + } + + i = i->next; + } + +/* g_list_free(src_vertices); + g_list_free(dest_vertices);*/ +} + + +toporouter_vertex_t *closest_dest_vertex(toporouter_t * r, toporouter_vertex_t * v, toporouter_route_t * routedata) +{ + GList /* *vertices = cluster_vertices(r, routedata->dest), */ + * i = routedata->destvertices; + toporouter_vertex_t *closest = NULL; + gdouble closest_distance = 0.; + +/* if(routedata->flags & TOPOROUTER_FLAG_FLEX) i = r->destboxes; */ + + while (i) { + toporouter_vertex_t *cv = TOPOROUTER_VERTEX(i->data); + + if (vz(cv) != vz(v)) { + i = i->next; + continue; + } + + if (!closest) { + closest = cv; + closest_distance = simple_h_cost(r, v, closest); + } + else { + gdouble tempd = simple_h_cost(r, v, cv); + if (r->flags & TOPOROUTER_FLAG_GOFAR && tempd > closest_distance) { + closest = cv; + closest_distance = tempd; + } + else if (tempd < closest_distance) { + closest = cv; + closest_distance = tempd; + } + } + i = i->next; + } + +/* g_list_free(vertices); */ + +#ifdef DEBUG_ROUTE + printf("CLOSEST = %f,%f,%f\n", vx(closest), vy(closest), vz(closest)); +#endif + return closest; +} + +#define toporouter_edge_gradient(e) (cartesian_gradient(vx(edge_v1(e)), vy(edge_v1(e)), vx(edge_v2(e)), vy(edge_v2(e)))) + + +/* returns the capacity of the triangle cut through v */ +gdouble triangle_interior_capacity(GtsTriangle * t, toporouter_vertex_t * v) +{ + toporouter_edge_t *e = TOPOROUTER_EDGE(gts_triangle_edge_opposite(t, GTS_VERTEX(v))); + gdouble x, y, m1, m2, c2, c1; +#ifdef DEBUG_ROUTE + gdouble len; +#endif + + g_assert(e); + + m1 = toporouter_edge_gradient(e); + m2 = perpendicular_gradient(m1); + c2 = (isinf(m2)) ? vx(v) : vy(v) - (m2 * vx(v)); + c1 = (isinf(m1)) ? vx(edge_v1(e)) : vy(edge_v1(e)) - (m1 * vx(edge_v1(e))); + + if (isinf(m2)) + x = vx(v); + else if (isinf(m1)) + x = vx(edge_v1(e)); + else + x = (c2 - c1) / (m1 - m2); + + y = (isinf(m2)) ? vy(edge_v1(e)) : (m2 * x) + c2; + +#ifdef DEBUG_ROUTE + len = gts_point_distance2(GTS_POINT(edge_v1(e)), GTS_POINT(edge_v2(e))); + printf("%f,%f len = %f v = %f,%f\n", x, y, len, vx(v), vy(v)); +#endif + + if (epsilon_equals(x, vx(edge_v1(e))) && epsilon_equals(y, vy(edge_v1(e)))) + return INFINITY; + if (epsilon_equals(x, vx(edge_v2(e))) && epsilon_equals(y, vy(edge_v2(e)))) + return INFINITY; + + if (x >= MIN(vx(edge_v1(e)), vx(edge_v2(e))) && + x <= MAX(vx(edge_v1(e)), vx(edge_v2(e))) && + y >= MIN(vy(edge_v1(e)), vy(edge_v2(e))) && y <= MAX(vy(edge_v1(e)), vy(edge_v2(e)))) + +/* if( (pow(vx(edge_v1(e)) - x, 2) + pow(vy(edge_v1(e)) - y, 2)) < len && (pow(vx(edge_v2(e)) - x, 2) + pow(vy(edge_v2(e)) - y, 2)) < len ) */ + return sqrt(pow(vx(v) - x, 2) + pow(vy(v) - y, 2)); + + return INFINITY; +} + +static inline toporouter_vertex_t *segment_common_vertex(GtsSegment * s1, GtsSegment * s2) +{ + if (!s1 || !s2) + return NULL; + if (s1->v1 == s2->v1) + return TOPOROUTER_VERTEX(s1->v1); + if (s1->v2 == s2->v1) + return TOPOROUTER_VERTEX(s1->v2); + if (s1->v1 == s2->v2) + return TOPOROUTER_VERTEX(s1->v1); + if (s1->v2 == s2->v2) + return TOPOROUTER_VERTEX(s1->v2); + return NULL; +} + +static inline toporouter_vertex_t *route_vertices_common_vertex(toporouter_vertex_t * v1, toporouter_vertex_t * v2) +{ + return segment_common_vertex(GTS_SEGMENT(v1->routingedge), GTS_SEGMENT(v2->routingedge)); +} + + +static inline guint edges_third_edge(GtsSegment * s1, GtsSegment * s2, toporouter_vertex_t ** v1, toporouter_vertex_t ** v2) +{ + if (!s1 || !s2) + return 0; + if (s1->v1 == s2->v1) { + *v1 = TOPOROUTER_VERTEX(s1->v2); + *v2 = TOPOROUTER_VERTEX(s2->v2); + return 1; + } + if (s1->v2 == s2->v1) { + *v1 = TOPOROUTER_VERTEX(s1->v1); + *v2 = TOPOROUTER_VERTEX(s2->v2); + return 1; + } + if (s1->v1 == s2->v2) { + *v1 = TOPOROUTER_VERTEX(s1->v2); + *v2 = TOPOROUTER_VERTEX(s2->v1); + return 1; + } + if (s1->v2 == s2->v2) { + *v1 = TOPOROUTER_VERTEX(s1->v1); + *v2 = TOPOROUTER_VERTEX(s2->v1); + return 1; + } + return 0; +} + +/* returns the flow from e1 to e2, and the flow from the vertex oppisate e1 to + * e1 and the vertex oppisate e2 to e2 */ +gdouble +flow_from_edge_to_edge(GtsTriangle * t, toporouter_edge_t * e1, toporouter_edge_t * e2, + toporouter_vertex_t * common_v, toporouter_vertex_t * curpoint) +{ + gdouble r = 0.; + toporouter_vertex_t *pv = common_v, *v; + toporouter_edge_t *op_edge; + + GList *i = edge_routing(e1); + while (i) { + v = TOPOROUTER_VERTEX(i->data); + + if (v == curpoint) { + r += min_spacing(v, pv); + pv = v; + i = i->next; + continue; + } +/* if(!(v->flags & VERTEX_FLAG_TEMP)) { */ + if ((v->flags & VERTEX_FLAG_ROUTE)) { + if (v->parent) + if (v->parent->routingedge == e2) { + r += min_spacing(v, pv); + pv = v; + i = i->next; + continue; + } + + if (v->child) + if (v->child->routingedge == e2) { + r += min_spacing(v, pv); + pv = v; + i = i->next; + continue; + } + } + i = i->next; + } + + op_edge = TOPOROUTER_EDGE(gts_triangle_edge_opposite(t, GTS_VERTEX(common_v))); + + g_assert(op_edge); + g_assert(e1); + g_assert(e2); + + v = segment_common_vertex(GTS_SEGMENT(e2), GTS_SEGMENT(op_edge)); + g_assert(v); + + /*v = TOPOROUTER_VERTEX(gts_triangle_vertex_opposite(t, GTS_EDGE(e1))); */ + if (v->flags & VERTEX_FLAG_ROUTE && v->parent && v->parent->routingedge) { + if (v->parent->routingedge == e1) + r += min_spacing(v, pv); + } + + v = segment_common_vertex(GTS_SEGMENT(e1), GTS_SEGMENT(op_edge)); + g_assert(v); + + /*v = TOPOROUTER_VERTEX(gts_triangle_vertex_opposite(t, GTS_EDGE(e2))); */ + if (v->flags & VERTEX_FLAG_ROUTE && v->parent && v->parent->routingedge) { + if (v->parent->routingedge == e1) + r += min_spacing(v, pv); + } + + if (TOPOROUTER_IS_CONSTRAINT(op_edge)) { + toporouter_bbox_t *box = vertex_bbox(TOPOROUTER_VERTEX(edge_v1(op_edge))); + r += vertex_net_thickness(v) / 2.; + if (box) { + r += MAX(vertex_net_clearance(v), cluster_clearance(box->cluster)); + r += cluster_thickness(box->cluster) / 2.; + } + else { + r += vertex_net_clearance(v); + + } + } + + return r; +} + + + +guint +check_triangle_interior_capacity(GtsTriangle * t, toporouter_vertex_t * v, toporouter_vertex_t * curpoint, + toporouter_edge_t * op_edge, toporouter_edge_t * adj_edge1, toporouter_edge_t * adj_edge2) +{ + gdouble ic = triangle_interior_capacity(t, v); + gdouble flow = flow_from_edge_to_edge(t, adj_edge1, adj_edge2, v, curpoint); + + if (TOPOROUTER_IS_CONSTRAINT(adj_edge1) || TOPOROUTER_IS_CONSTRAINT(adj_edge2)) + return 1; + + + if (flow > ic) { +#ifdef DEBUG_ROUTE + printf("fail interior capacity flow = %f ic = %f\n", flow, ic); +#endif + return 0; + } + + return 1; +} + +toporouter_vertex_t *edge_routing_next_not_temp(toporouter_edge_t * e, GList * list) +{ + if (!TOPOROUTER_IS_CONSTRAINT(e)) { + while (list) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(list->data); + if (!(v->flags & VERTEX_FLAG_TEMP)) + return v; + + list = list->next; + } + } + return tedge_v2(e); +} + +toporouter_vertex_t *edge_routing_prev_not_temp(toporouter_edge_t * e, GList * list) +{ + if (!TOPOROUTER_IS_CONSTRAINT(e)) { + while (list) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(list->data); + if (!(v->flags & VERTEX_FLAG_TEMP)) + return v; + + list = list->prev; + } + } + return tedge_v1(e); +} + +void +edge_adjacent_vertices(toporouter_edge_t * e, toporouter_vertex_t * v, toporouter_vertex_t ** v1, toporouter_vertex_t ** v2) +{ + GList *r = g_list_find(edge_routing(e), v); + + if (v == tedge_v1(e)) { + *v1 = NULL; + *v2 = edge_routing_next_not_temp(e, edge_routing(e)); + } + else if (v == tedge_v2(e)) { + *v1 = edge_routing_prev_not_temp(e, g_list_last(edge_routing(e))); + *v2 = NULL; + } + else { +/* r = g_list_find(r, v);*/ + *v1 = edge_routing_prev_not_temp(e, r); + *v2 = edge_routing_next_not_temp(e, r); + + } + +} + + +GList *candidate_vertices(toporouter_vertex_t * v1, toporouter_vertex_t * v2, toporouter_vertex_t * dest, toporouter_edge_t * e) +{ + gdouble totald, v1ms, v2ms, flow, capacity, ms; + GList *vs = NULL; + + g_assert(v1); + g_assert(v2); + g_assert(dest); + + g_assert(!(v1->flags & VERTEX_FLAG_TEMP)); + g_assert(!(v2->flags & VERTEX_FLAG_TEMP)); +#ifdef DEBUG_ROUTE + printf("starting candidate vertices\n"); + printf("v1 = %f,%f v2 = %f,%f dest = %f,%f\n", vx(v1), vy(v1), vx(v2), vy(v2), vx(dest), vy(dest)); +#endif + totald = gts_point_distance(GTS_POINT(v1), GTS_POINT(v2)); + v1ms = min_spacing(v1, dest); + v2ms = min_spacing(v2, dest); + ms = min_spacing(dest, dest); + flow = TOPOROUTER_IS_CONSTRAINT(e) ? 0. : edge_flow(e, v1, v2, dest); + capacity = edge_capacity(e); + +#ifdef DEBUG_ROUTE + g_assert(totald > 0); + + printf("v1ms = %f v2ms = %f totald = %f ms = %f capacity = %f flow = %f\n", v1ms, v2ms, totald, ms, capacity, flow); +#endif + + if (flow >= capacity) + return NULL; + + + if (v1ms + v2ms + ms >= totald) { + vs = g_list_prepend(vs, new_temp_toporoutervertex((vx(v1) + vx(v2)) / 2., (vy(v1) + vy(v2)) / 2., e)); + } + else { + gdouble x0, y0, x1, y1, d; + + vertex_move_towards_vertex_values(GTS_VERTEX(v1), GTS_VERTEX(v2), v1ms, &x0, &y0); + + vs = g_list_prepend(vs, new_temp_toporoutervertex(x0, y0, e)); + + vertex_move_towards_vertex_values(GTS_VERTEX(v2), GTS_VERTEX(v1), v2ms, &x1, &y1); + + vs = g_list_prepend(vs, new_temp_toporoutervertex(x1, y1, e)); + + d = sqrt(pow(x0 - x1, 2) + pow(y0 - y1, 2)); + + if (ms < d) { +/* guint nint = d / ms; + gdouble dif = d / (nint + 1); */ + gdouble dif = d / 2; + +/* for(guint j=0;jdata); + if (!(v->flags & VERTEX_FLAG_TEMP)) + return i; + + i = i->next; + } + + return NULL; +} + +GList *edge_routing_last_not_temp(toporouter_edge_t * e) +{ + GList *i = edge_routing(e), *last = NULL; + toporouter_vertex_t *v; + + while (i) { + v = TOPOROUTER_VERTEX(i->data); + if (!(v->flags & VERTEX_FLAG_TEMP)) + last = i; + + i = i->next; + } + + return last; +} + +void delete_vertex(toporouter_vertex_t * v) +{ + + if (v->flags & VERTEX_FLAG_TEMP) { + if (v->routingedge) { + if (TOPOROUTER_IS_CONSTRAINT(v->routingedge)) + TOPOROUTER_CONSTRAINT(v->routingedge)->routing = g_list_remove(TOPOROUTER_CONSTRAINT(v->routingedge)->routing, v); + else + v->routingedge->routing = g_list_remove(v->routingedge->routing, v); + } + + gts_object_destroy(GTS_OBJECT(v)); + } +} + +#define edge_is_blocked(e) (TOPOROUTER_IS_EDGE(e) ? (e->flags & EDGE_FLAG_DIRECTCONNECTION) : 0) + +GList *triangle_candidate_points_from_vertex(GtsTriangle * t, toporouter_vertex_t * v, toporouter_vertex_t * dest, + toporouter_route_t * routedata) +{ + toporouter_edge_t *op_e = TOPOROUTER_EDGE(gts_triangle_edge_opposite(t, GTS_VERTEX(v))); + toporouter_vertex_t *vv1, *vv2, *constraintv = NULL; + toporouter_edge_t *e1, *e2; + GList *i; + GList *rval = NULL; + +#ifdef DEBUG_ROUTE + printf("\tTRIANGLE CAND POINT FROM VERTEX\n"); + + g_assert(op_e); +#endif + + e1 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(v), edge_v1(op_e))); + e2 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(v), edge_v2(op_e))); + + + if (TOPOROUTER_IS_CONSTRAINT(op_e)) { + if (TOPOROUTER_CONSTRAINT(op_e)->box->type == BOARD) { +#ifdef DEBUG_ROUTE + printf("BOARD constraint\n"); +#endif + return NULL; + } + if (constraint_netlist(TOPOROUTER_CONSTRAINT(op_e)) != vertex_netlist(dest)) { /* || TOPOROUTER_CONSTRAINT(op_e)->routing) { */ +#ifdef DEBUG_ROUTE + printf("op_e routing:\n"); + print_edge(op_e); +#endif + return NULL; + } +#ifdef DEBUG_ROUTE + printf("RETURNING CONSTRAINT POING\n"); +#endif + constraintv = new_temp_toporoutervertex_in_segment(op_e, TOPOROUTER_VERTEX(edge_v1(op_e)), + gts_point_distance(GTS_POINT(edge_v1(op_e)), + GTS_POINT(edge_v2(op_e))) / 2., + TOPOROUTER_VERTEX(edge_v2(op_e))); +/* return g_list_prepend(NULL, vv1); */ + + + } + + if (edge_is_blocked(op_e)) { + goto triangle_candidate_points_from_vertex_exit; + } +/* v1 = tedge_v1(op_e); + v2 = tedge_v2(op_e);*/ + + if (v == tedge_v1(e1)) { + i = edge_routing_first_not_temp(e1); + } + else { + i = edge_routing_last_not_temp(e1); + } + + if (i) { + toporouter_vertex_t *temp = TOPOROUTER_VERTEX(i->data); + + if (temp->parent == tedge_v2(op_e) || temp->child == tedge_v2(op_e)) { +#ifdef DEBUG_ROUTE + printf("temp -> op_e->v2\n"); +#endif + goto triangle_candidate_points_from_vertex_exit; + } + if (temp->parent->routingedge == op_e) { + vv1 = temp->parent; +#ifdef DEBUG_ROUTE + printf("vv1->parent\n"); +#endif + + } + else if (temp->child->routingedge == op_e) { + vv1 = temp->child; +#ifdef DEBUG_ROUTE + printf("vv1->child\n"); +#endif + + } + else { + /* must be to e2 */ +#ifdef DEBUG_ROUTE + printf("temp -> e2?\n"); + printf("op_e = %f,%f\t\t%f,%f\n", vx(edge_v1(op_e)), vy(edge_v1(op_e)), vx(edge_v2(op_e)), vy(edge_v2(op_e))); + if (temp->parent->routingedge) + printf("temp->parent->routingedge = %f,%f \t\t %f,%f\n", + vx(edge_v1(temp->parent->routingedge)), vy(edge_v1(temp->parent->routingedge)), + vx(edge_v2(temp->parent->routingedge)), vy(edge_v2(temp->parent->routingedge)) + ); + else + printf("temp->parent->routingedge = NULL\n"); + + if (temp->child->routingedge) + printf("temp->child->routingedge = %f,%f \t\t %f,%f\n", + vx(edge_v1(temp->child->routingedge)), vy(edge_v1(temp->child->routingedge)), + vx(edge_v2(temp->child->routingedge)), vy(edge_v2(temp->child->routingedge)) + ); + else + printf("temp->child->routingedge = NULL\n"); +#endif + goto triangle_candidate_points_from_vertex_exit; + } + + } + else { + vv1 = tedge_v1(op_e); +#ifdef DEBUG_ROUTE + printf("nothing on e1\n"); +#endif + } + + if (v == tedge_v1(e2)) { + i = edge_routing_first_not_temp(e2); + } + else { + i = edge_routing_last_not_temp(e2); + } + + if (i) { + toporouter_vertex_t *temp = TOPOROUTER_VERTEX(i->data); + + if (temp->parent == tedge_v1(op_e) || temp->child == tedge_v1(op_e)) { +#ifdef DEBUG_ROUTE + printf("temp -> op_e->v2\n"); +#endif + goto triangle_candidate_points_from_vertex_exit; + } + + if (temp->parent->routingedge == op_e) { + vv2 = temp->parent; +#ifdef DEBUG_ROUTE + printf("vv2->parent\n"); +#endif + } + else if (temp->child->routingedge == op_e) { + vv2 = temp->child; +#ifdef DEBUG_ROUTE + printf("vv2->child\n"); +#endif + + } + else { + /* must be to e1 */ +#ifdef DEBUG_ROUTE + printf("temp -> e1?\n"); + printf("op_e = %f,%f\t\t%f,%f\n", vx(edge_v1(op_e)), vy(edge_v1(op_e)), vx(edge_v2(op_e)), vy(edge_v2(op_e))); + if (temp->parent->routingedge) + printf("temp->parent->routingedge = %f,%f \t\t %f,%f\n", + vx(edge_v1(temp->parent->routingedge)), vy(edge_v1(temp->parent->routingedge)), + vx(edge_v2(temp->parent->routingedge)), vy(edge_v2(temp->parent->routingedge)) + ); + else + printf("temp->parent->routingedge = NULL\n"); + + if (temp->child->routingedge) + printf("temp->child->routingedge = %f,%f \t\t %f,%f\n", + vx(edge_v1(temp->child->routingedge)), vy(edge_v1(temp->child->routingedge)), + vx(edge_v2(temp->child->routingedge)), vy(edge_v2(temp->child->routingedge)) + ); + else + printf("temp->child->routingedge = NULL\n"); +#endif + goto triangle_candidate_points_from_vertex_exit; + } + + } + else { + vv2 = tedge_v2(op_e); +#ifdef DEBUG_ROUTE + printf("nothing on e2\n"); +#endif + } + +#ifdef DEBUG_ROUTE + printf("size of e1 routing = %d e2 routing = %d op_e routing = %d\n", + g_list_length(edge_routing(e1)), g_list_length(edge_routing(e2)), g_list_length(edge_routing(op_e))); +#endif + + if (constraintv) { +#ifdef DEBUG_ROUTE + print_vertex(constraintv); + printf("constraintv %f,%f returning\n", vx(constraintv), vy(constraintv)); +#endif + return g_list_prepend(NULL, constraintv); + } + + i = edge_routing(op_e); + while (i) { + toporouter_vertex_t *temp = TOPOROUTER_VERTEX(i->data); + + if (temp->parent == v || temp->child == v) { + rval = g_list_concat(rval, candidate_vertices(vv1, temp, dest, op_e)); + vv1 = temp; + } + + i = i->next; + } + + rval = g_list_concat(rval, candidate_vertices(vv1, vv2, dest, op_e)); + + return rval; + + + +triangle_candidate_points_from_vertex_exit: + if (constraintv) /*delete_vertex(constraintv); */ + g_hash_table_insert(routedata->alltemppoints, constraintv, constraintv); + + g_list_free(rval); + + return NULL; +} + +void routedata_insert_temppoints(toporouter_route_t * data, GList * temppoints) +{ + GList *j = temppoints; + while (j) { + g_hash_table_insert(data->alltemppoints, j->data, j->data); + j = j->next; + } +} + + +static inline gint constraint_route_test(toporouter_constraint_t * c, toporouter_route_t * routedata) +{ + if (c->box->cluster && c->box->cluster->netlist == routedata->src->netlist) { + if (c->box->cluster->c == routedata->dest->c || c->box->cluster->c == routedata->src->c) + return 1; + } + return 0; +} + +GList *all_candidates_on_edge(toporouter_edge_t * e, toporouter_route_t * routedata) +{ + GList *rval = NULL; + if (edge_is_blocked(e)) + return NULL; + + if (!TOPOROUTER_IS_CONSTRAINT(e)) { + GList *i = edge_routing(e); + toporouter_vertex_t *pv = tedge_v1(e); + + while (i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); + if (!(v->flags & VERTEX_FLAG_TEMP)) { + rval = g_list_concat(rval, candidate_vertices(pv, v, TOPOROUTER_VERTEX(routedata->destvertices->data), e)); + pv = v; + } + i = i->next; + } + + rval = g_list_concat(rval, candidate_vertices(pv, tedge_v2(e), TOPOROUTER_VERTEX(routedata->destvertices->data), e)); + } + else if (TOPOROUTER_CONSTRAINT(e)->box->type == BOARD) { + return NULL; + } + else if (constraint_route_test(TOPOROUTER_CONSTRAINT(e), routedata)) { + toporouter_vertex_t *consv = + new_temp_toporoutervertex_in_segment(e, tedge_v1(e), tvdistance(tedge_v1(e), tedge_v2(e)) / 2., tedge_v2(e)); + rval = g_list_prepend(rval, consv); +/* g_hash_table_insert(routedata->alltemppoints, consv, consv); */ + } + + return rval; +} + +GList *triangle_all_candidate_points_from_vertex(GtsTriangle * t, toporouter_vertex_t * v, toporouter_route_t * routedata) +{ + toporouter_edge_t *op_e = TOPOROUTER_EDGE(gts_triangle_edge_opposite(t, GTS_VERTEX(v))); + return all_candidates_on_edge(op_e, routedata); +} + +GList *triangle_all_candidate_points_from_edge(toporouter_t * r, GtsTriangle * t, toporouter_edge_t * e, + toporouter_route_t * routedata, toporouter_vertex_t ** dest, + toporouter_vertex_t * curpoint) +{ + toporouter_vertex_t *op_v; + toporouter_edge_t *e1, *e2; + GList *i, *rval = NULL, *rval2 = NULL; + toporouter_vertex_t *boxpoint = NULL; + guint e1intcap, e2intcap; + + op_v = TOPOROUTER_VERTEX(gts_triangle_vertex_opposite(t, GTS_EDGE(e))); + + + if (vertex_bbox(op_v)) + boxpoint = TOPOROUTER_VERTEX(vertex_bbox(op_v)->point); + + if (g_list_find(routedata->destvertices, op_v)) { + rval = g_list_prepend(rval, op_v); + *dest = op_v; + return rval; + } + else if (g_list_find(routedata->destvertices, boxpoint)) { + *dest = boxpoint; + } + else if (g_list_find(routedata->srcvertices, op_v)) { + rval = g_list_prepend(rval, op_v); + } + + e1 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(op_v), edge_v1(e))); + e2 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(op_v), edge_v2(e))); + + rval = g_list_concat(rval, all_candidates_on_edge(e1, routedata)); + rval = g_list_concat(rval, all_candidates_on_edge(e2, routedata)); + + e1intcap = check_triangle_interior_capacity(t, tedge_v1(e), curpoint, e2, e, e1); + e2intcap = check_triangle_interior_capacity(t, tedge_v2(e), curpoint, e1, e, e2); + + i = rval; + while (i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); + + if (!v->routingedge) + rval2 = g_list_prepend(rval2, v); + else if (v->routingedge == e1 && !(!TOPOROUTER_IS_CONSTRAINT(e1) && !e1intcap)) + rval2 = g_list_prepend(rval2, v); + else if (v->routingedge == e2 && !(!TOPOROUTER_IS_CONSTRAINT(e2) && !e2intcap)) + rval2 = g_list_prepend(rval2, v); + + i = i->next; + } + g_list_free(rval); + + return rval2; +} + +GList *triangle_candidate_points_from_edge(toporouter_t * r, GtsTriangle * t, toporouter_edge_t * e, toporouter_vertex_t * v, + toporouter_vertex_t ** dest, toporouter_route_t * routedata) +{ + toporouter_vertex_t *v1, *v2, *op_v, *vv = NULL, *e1constraintv = NULL, *e2constraintv = NULL; + toporouter_edge_t *e1, *e2; + GList *e1cands = NULL, *e2cands = NULL, *rval = NULL; + guint noe1 = 0, noe2 = 0; + + op_v = TOPOROUTER_VERTEX(gts_triangle_vertex_opposite(t, GTS_EDGE(e))); + + e1 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(op_v), edge_v1(e))); + e2 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(op_v), edge_v2(e))); + + g_assert(*dest); + + /* v1 is prev dir, v2 is next dir */ + edge_adjacent_vertices(e, v, &v1, &v2); + + if (TOPOROUTER_IS_CONSTRAINT(e1)) { + GList *i = edge_routing(e1); + + if (TOPOROUTER_CONSTRAINT(e1)->box->type == BOARD) { + noe1 = 1; + } + else if (!constraint_route_test(TOPOROUTER_CONSTRAINT(e1), routedata)) { + noe1 = 1; +#ifdef DEBUG_ROUTE + printf("noe1 netlist\n"); +#endif + } + else + if (v1 == tedge_v1(e) || + (v1->parent->routingedge && v1->parent->routingedge == e1) || + (v1->child->routingedge && v1->child->routingedge == e1)) { + e1constraintv = + new_temp_toporoutervertex_in_segment(e1, tedge_v1(e1), + gts_point_distance(GTS_POINT(edge_v1(e1)), GTS_POINT(edge_v2(e1))) / 2., + tedge_v2(e1)); + } + + while (i) { + toporouter_vertex_t *temp = TOPOROUTER_VERTEX(i->data); + + if ((temp->child == tedge_v2(e) || temp->parent == tedge_v2(e)) && !(temp->flags & VERTEX_FLAG_TEMP)) + noe2 = 1; + + i = i->next; + } + + goto triangle_candidate_points_e2; + } + + if (edge_is_blocked(e1)) { + noe1 = 1; + goto triangle_candidate_points_e2; + } + + if (v1 == tedge_v1(e)) { + /* continue up e1 */ + toporouter_vertex_t *vv1, *vv2; + edge_adjacent_vertices(e1, v1, &vv1, &vv2); + +#ifdef DEBUG_ROUTE + printf("v1 == e->v1\n"); +#endif + + if (vv1) { + /* candidates from v1 until vv1 */ + vv = vv1; + } + else { + /* candidates from v1 until vv2 */ + vv = vv2; + } + + if (!e1constraintv) + e1cands = candidate_vertices(v1, vv, *dest, e1); + + if (vv != op_v) { + if (vv->parent == tedge_v2(e) || vv->child == tedge_v2(e)) { +#ifdef DEBUG_ROUTE + printf("noe2 0\n"); +#endif + noe2 = 1; + } + } + + } + else if (v1->parent != op_v && v1->child != op_v) { + toporouter_vertex_t *vv1 = NULL, *vv2 = NULL; + +#ifdef DEBUG_ROUTE + printf("v1 != e->v1\n"); +#endif + + if (v1->parent->routingedge == e1) { + vv1 = v1->parent; +#ifdef DEBUG_ROUTE + printf("v1 parent = e1\n"); +#endif + if (op_v == tedge_v1(e1)) { + /* candidates from v1->parent until prev vertex */ + vv2 = edge_routing_prev_not_temp(e1, g_list_find(edge_routing(e1), v1->parent)->prev); + } + else { + /* candidates from v1->parent until next vertex */ + vv2 = edge_routing_next_not_temp(e1, g_list_find(edge_routing(e1), v1->parent)->next); + } + + } + else if (v1->child->routingedge == e1) { + vv1 = v1->child; +#ifdef DEBUG_ROUTE + printf("v1 child = e1\n"); +#endif + if (op_v == tedge_v1(e1)) { + /* candidates from v1->child until prev vertex */ + vv2 = edge_routing_prev_not_temp(e1, g_list_find(edge_routing(e1), v1->child)->prev); + } + else { + /* candidates from v1->child until next vertex */ + vv2 = edge_routing_next_not_temp(e1, g_list_find(edge_routing(e1), v1->child)->next); + } + + } + else { +#ifdef DEBUG_ROUTE + printf("v1 ? \n"); +#endif + goto triangle_candidate_points_e2; + } + + if (vv1 && vv2) { + if (vv2->parent == tedge_v2(e) || vv2->child == tedge_v2(e)) { +#ifdef DEBUG_ROUTE + printf("noe2 1\n"); +#endif + noe2 = 1; + } + + if (!e1constraintv) + e1cands = candidate_vertices(vv1, vv2, *dest, e1); + + vv = vv2; + } + } + + if (vv && vv == op_v) { + toporouter_vertex_t *boxpoint = NULL; + + if (vertex_bbox(op_v)) + boxpoint = TOPOROUTER_VERTEX(vertex_bbox(op_v)->point); + + if (g_list_find(routedata->destvertices, op_v)) { + rval = g_list_prepend(rval, op_v); + *dest = op_v; + } + else if (g_list_find(routedata->destvertices, boxpoint)) { + *dest = boxpoint; + } + else if (g_list_find(routedata->srcvertices, op_v)) { + rval = g_list_prepend(rval, op_v); + } + } + +triangle_candidate_points_e2: + + if (noe2) { +/* printf("noe2\n"); */ + goto triangle_candidate_points_finish; + } + + if (TOPOROUTER_IS_CONSTRAINT(e2)) { + GList *i = edge_routing(e2); + + if (TOPOROUTER_CONSTRAINT(e2)->box->type == BOARD) { + noe2 = 1; +/* goto triangle_candidate_points_finish; */ + } + else if (!constraint_route_test(TOPOROUTER_CONSTRAINT(e2), routedata)) { +#ifdef DEBUG_ROUTE + printf("noe2 netlist\n"); +#endif + noe2 = 1; +/* goto triangle_candidate_points_finish; */ + } + else if (v2 == tedge_v2(e) || + (v2->parent->routingedge && v2->parent->routingedge == e2) || + (v2->child->routingedge && v2->child->routingedge == e2)) { + + e2constraintv = + new_temp_toporoutervertex_in_segment(e2, tedge_v1(e2), + gts_point_distance(GTS_POINT(edge_v1(e2)), GTS_POINT(edge_v2(e2))) / 2., + tedge_v2(e2)); + + } + + while (i) { + toporouter_vertex_t *temp = TOPOROUTER_VERTEX(i->data); + + if ((temp->child == tedge_v1(e) || temp->parent == tedge_v1(e)) && !(temp->flags & VERTEX_FLAG_TEMP)) + noe1 = 1; + + i = i->next; + } + + + + goto triangle_candidate_points_finish; + } + + if (edge_is_blocked(e2)) { + noe2 = 1; + goto triangle_candidate_points_finish; + } + + if (v2 == tedge_v2(e)) { + /* continue up e2 */ + toporouter_vertex_t *vv1 = NULL, *vv2 = NULL; + edge_adjacent_vertices(e2, v2, &vv1, &vv2); + +#ifdef DEBUG_ROUTE + printf("v2 == e->v2\n"); +#endif + + if (vv1) { + /* candidates from v2 until vv1 */ + vv = vv1; + } + else { + /* candidates from v2 until vv2 */ + vv = vv2; + } + + if (!e2constraintv) + e2cands = candidate_vertices(v2, vv, *dest, e2); + + if (vv != op_v) { + if (vv->parent == tedge_v1(e) || vv->child == tedge_v1(e)) { +#ifdef DEBUG_ROUTE + printf("noe1 0\n"); +#endif + noe1 = 1; + } + } + + } + else if (v2->parent != op_v && v2->child != op_v) { + toporouter_vertex_t *vv1 = NULL, *vv2 = NULL; + +#ifdef DEBUG_ROUTE + printf("v2 == e->v2\n"); +#endif + + if (v2->parent->routingedge == e2) { + vv1 = v2->parent; + if (op_v == tedge_v1(e2)) { + /* candidates from v2->parent until prev vertex */ + vv2 = edge_routing_prev_not_temp(e2, g_list_find(edge_routing(e2), vv1)->prev); + } + else { + /* candidates from v2->parent until next vertex */ + vv2 = edge_routing_next_not_temp(e2, g_list_find(edge_routing(e2), vv1)->next); + } + + } + else if (v2->child->routingedge == e2) { + vv1 = v2->child; + if (op_v == tedge_v1(e2)) { + /* candidates from v2->child until prev vertex */ + vv2 = edge_routing_prev_not_temp(e2, g_list_find(edge_routing(e2), vv1)->prev); + } + else { + /* candidates from v2->child until next vertex */ + vv2 = edge_routing_next_not_temp(e2, g_list_find(edge_routing(e2), vv1)->next); + } + + } + else { + goto triangle_candidate_points_finish; + } + + if (vv1 && vv2) { + if (vv2->parent == tedge_v1(e) || vv2->child == tedge_v1(e)) { +#ifdef DEBUG_ROUTE + printf("noe1 1\n"); +#endif + noe1 = 1; + } + + if (!e2constraintv) + e2cands = candidate_vertices(vv1, vv2, *dest, e2); + } + } + +triangle_candidate_points_finish: + + v1 = segment_common_vertex(GTS_SEGMENT(e), GTS_SEGMENT(e1)); + v2 = segment_common_vertex(GTS_SEGMENT(e), GTS_SEGMENT(e2)); + + if (noe1 || !check_triangle_interior_capacity(t, v1, v, e2, e, e1)) { +#ifdef DEBUG_ROUTE + printf("freeing e1cands\n"); +#endif + routedata_insert_temppoints(routedata, e1cands); + g_list_free(e1cands); + e1cands = NULL; + } + + if (noe2 || !check_triangle_interior_capacity(t, v2, v, e1, e, e2)) { +#ifdef DEBUG_ROUTE + printf("freeing e2cands\n"); +#endif + routedata_insert_temppoints(routedata, e2cands); + g_list_free(e2cands); + e2cands = NULL; + } + + if (!noe1 && e1constraintv) { + e1cands = g_list_prepend(e1cands, e1constraintv); + } + else if (e1constraintv) { + g_hash_table_insert(routedata->alltemppoints, e1constraintv, e1constraintv); +/* delete_vertex(e1constraintv); */ + } + + if (!noe2 && e2constraintv) { + e2cands = g_list_prepend(e2cands, e2constraintv); + } + else if (e2constraintv) { + g_hash_table_insert(routedata->alltemppoints, e2constraintv, e2constraintv); +/* delete_vertex(e2constraintv); */ + } + + if (!noe1 && !noe2) + return g_list_concat(rval, g_list_concat(e1cands, e2cands)); + + return g_list_concat(e1cands, e2cands); +} + +GList *compute_candidate_points(toporouter_t * tr, toporouter_layer_t * l, toporouter_vertex_t * curpoint, + toporouter_route_t * data, toporouter_vertex_t ** closestdest) +{ + GList *r = NULL, *j; + toporouter_edge_t *edge = curpoint->routingedge, *tempedge; + + if (vertex_keepout_test(tr, curpoint)) + goto compute_candidate_points_finish; + + /* direct connection */ +/* if(curpoint == TOPOROUTER_VERTEX(data->src->point)) */ + if ((tempedge = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(curpoint), GTS_VERTEX(*closestdest))))) { + + if (TOPOROUTER_IS_CONSTRAINT(tempedge)) { + goto compute_candidate_points_finish; + } + else { + if (!tempedge->routing) { + r = g_list_prepend(NULL, *closestdest); + tempedge->flags |= EDGE_FLAG_DIRECTCONNECTION; + goto compute_candidate_points_finish; + } + else { +#ifdef DEBUG_ROUTE + printf("Direct connection, but has routing\n"); +#endif + } + + } + /* if we get to here, there is routing blocking the direct connection, + * continue as per normal */ + } + + /* a real point origin */ + if (!(curpoint->flags & VERTEX_FLAG_TEMP)) { + GSList *triangles, *i; + i = triangles = gts_vertex_triangles(GTS_VERTEX(curpoint), NULL); +#ifdef DEBUG_ROUTE + printf("triangle count = %d\n", g_slist_length(triangles)); +#endif + while (i) { + GtsTriangle *t = GTS_TRIANGLE(i->data); + GList *temppoints; + + if (tr->flags & TOPOROUTER_FLAG_LEASTINVALID) + temppoints = triangle_all_candidate_points_from_vertex(t, curpoint, data); + else + temppoints = triangle_candidate_points_from_vertex(t, curpoint, *closestdest, data); + +#ifdef DEBUG_ROUTE + printf("\treturned %d points\n", g_list_length(temppoints)); +#endif + routedata_insert_temppoints(data, temppoints); + + r = g_list_concat(r, temppoints); + i = i->next; + } + g_slist_free(triangles); + } + else { /* a temp point */ + + int prevwind = vertex_wind(GTS_SEGMENT(edge)->v1, GTS_SEGMENT(edge)->v2, GTS_VERTEX(curpoint->parent)); +/* printf("tempoint\n"); */ + + GSList *i = GTS_EDGE(edge)->triangles; + + while (i) { + GtsVertex *oppv = gts_triangle_vertex_opposite(GTS_TRIANGLE(i->data), GTS_EDGE(edge)); + if (prevwind != vertex_wind(GTS_SEGMENT(edge)->v1, GTS_SEGMENT(edge)->v2, oppv)) { + GList *temppoints; + + if (tr->flags & TOPOROUTER_FLAG_LEASTINVALID) + temppoints = triangle_all_candidate_points_from_edge(tr, GTS_TRIANGLE(i->data), edge, data, closestdest, curpoint); + else + temppoints = triangle_candidate_points_from_edge(tr, GTS_TRIANGLE(i->data), edge, curpoint, closestdest, data); + + j = temppoints; + while (j) { + toporouter_vertex_t *tempj = TOPOROUTER_VERTEX(j->data); + if (tempj->flags & VERTEX_FLAG_TEMP) + g_hash_table_insert(data->alltemppoints, j->data, j->data); +#ifdef DEBUG_ROUTE + else + printf("got cand not a temp\n"); +#endif + j = j->next; + } + r = g_list_concat(r, temppoints); + + break; + } + i = i->next; + } + } + +compute_candidate_points_finish: + + if (vertex_bbox(curpoint) && vertex_bbox(curpoint)->cluster) { + if (vertex_bbox(curpoint)->cluster->c == data->src->c) { + r = g_list_concat(r, g_list_copy(data->srcvertices)); + } + } + + return r; +} + +gboolean temp_point_clean(gpointer key, gpointer value, gpointer user_data) +{ + toporouter_vertex_t *tv = TOPOROUTER_VERTEX(value); + if (tv->flags & VERTEX_FLAG_TEMP) { + if (TOPOROUTER_IS_CONSTRAINT(tv->routingedge)) + TOPOROUTER_CONSTRAINT(tv->routingedge)->routing = g_list_remove(TOPOROUTER_CONSTRAINT(tv->routingedge)->routing, tv); + else + tv->routingedge->routing = g_list_remove(tv->routingedge->routing, tv); + gts_object_destroy(GTS_OBJECT(tv)); + } + return TRUE; +} + +void clean_routing_edges(toporouter_t * r, toporouter_route_t * data) +{ + g_hash_table_foreach_remove(data->alltemppoints, temp_point_clean, NULL); + g_hash_table_destroy(data->alltemppoints); + data->alltemppoints = NULL; +} + +gdouble path_score(toporouter_t * r, GList * path) +{ + gdouble score = 0.; + toporouter_vertex_t *pv = NULL; + toporouter_vertex_t *v0 = NULL; + + if (!path) + return INFINITY; + + v0 = TOPOROUTER_VERTEX(path->data); + + while (path) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(path->data); + + if (pv) { + score += gts_point_distance(GTS_POINT(pv), GTS_POINT(v)); + if (pv != v0 && vz(pv) != vz(v)) + if (path->next) + score += r->viacost; + + } + + pv = v; + path = path->next; + } + + return score; +} + +void print_vertices(GList * vertices) +{ + while (vertices) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(vertices->data); + print_vertex(v); + print_bbox(vertex_bbox(v)); + if (vertex_bbox(v)) { + printf("has bbox\n"); + if (vertex_bbox(v)->cluster) + printf("has cluster\n"); + else + printf("no cluster\n"); + } + else + printf("no bbox\n"); + vertices = vertices->next; + } +} + +gint space_edge(gpointer item, gpointer data) +{ + toporouter_edge_t *e = TOPOROUTER_EDGE(item); + GList *i; + gdouble *forces; + guint j; + + if (TOPOROUTER_IS_CONSTRAINT(e)) + return 0; + + if (!edge_routing(e) || !g_list_length(edge_routing(e))) + return 0; + + forces = (gdouble *) malloc(sizeof(double) * g_list_length(edge_routing(e))); + + for (j = 0; j < 100; j++) { + guint k = 0; + guint equilibrium = 1; + + i = edge_routing(e); + while (i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); + gdouble ms, d; + + if (i->prev) { +/* ms = min_net_net_spacing(TOPOROUTER_VERTEX(i->prev->data), v); */ + ms = min_spacing(TOPOROUTER_VERTEX(i->prev->data), v); + d = gts_point_distance(GTS_POINT(i->prev->data), GTS_POINT(v)); + } + else { +/* ms = min_vertex_net_spacing(v, tedge_v1(e)); */ + ms = min_spacing(v, tedge_v1(e)); + d = gts_point_distance(GTS_POINT(edge_v1(e)), GTS_POINT(v)); + } + + if (d < ms) + forces[k] = ms - d; + else + forces[k] = 0.; + + if (i->next) { +/* ms = min_net_net_spacing(TOPOROUTER_VERTEX(i->next->data), v); */ + ms = min_spacing(TOPOROUTER_VERTEX(i->next->data), v); + d = gts_point_distance(GTS_POINT(i->next->data), GTS_POINT(v)); + } + else { +/* ms = min_vertex_net_spacing(v, tedge_v2(e)); */ + ms = min_spacing(v, tedge_v2(e)); + d = gts_point_distance(GTS_POINT(edge_v2(e)), GTS_POINT(v)); + } + + if (d < ms) + forces[k] += d - ms; + + k++; + i = i->next; + } + + k = 0; + i = edge_routing(e); + while (i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); + if (forces[k] > EPSILON || forces[k] < -EPSILON) + equilibrium = 0; + vertex_move_towards_vertex_values(GTS_VERTEX(v), edge_v2(e), forces[k] * 0.1, &(GTS_POINT(v)->x), &(GTS_POINT(v)->y)); + k++; + i = i->next; + } + + if (equilibrium) { +/* printf("reached equilibriium at %d\n", j); */ + break; + } + + } + + free(forces); + return 0; +} + +void swap_vertices(toporouter_vertex_t ** v1, toporouter_vertex_t ** v2) +{ + toporouter_vertex_t *tempv = *v1; + *v1 = *v2; + *v2 = tempv; +} + +void split_edge_routing(toporouter_vertex_t * v, GList ** l1, GList ** l2) +{ + GList *base, *i; + + g_assert(v); + g_assert(v->routingedge); + + base = g_list_find(vrouting(v), v); + + *l1 = g_list_prepend(*l1, tedge_v1(v->routingedge)); + *l2 = g_list_prepend(*l2, tedge_v2(v->routingedge)); + + g_assert(base); + + i = base->next; + while (i) { + if (!(TOPOROUTER_VERTEX(i->data)->flags & VERTEX_FLAG_TEMP)) + *l2 = g_list_prepend(*l2, i->data); + i = i->next; + } + + i = base->prev; + while (i) { + if (!(TOPOROUTER_VERTEX(i->data)->flags & VERTEX_FLAG_TEMP)) + *l1 = g_list_prepend(*l1, i->data); + i = i->prev; + } +} + +GList *vertices_routing_conflicts(toporouter_vertex_t * v, toporouter_vertex_t * pv) +{ + toporouter_edge_t *e; + GList *rval = NULL, *l1 = NULL, *l2 = NULL, *i; + + if (vz(v) != vz(pv)) + return NULL; + g_assert(v != pv); + + if (!v->routingedge && !pv->routingedge) { + e = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(v), GTS_VERTEX(pv))); + if (!e) + return NULL; + i = edge_routing(e); + while (i) { + rval = g_list_prepend(rval, TOPOROUTER_VERTEX(i->data)->route); + i = i->next; + } + return rval; + } + + if (TOPOROUTER_IS_CONSTRAINT(v->routingedge) && TOPOROUTER_IS_CONSTRAINT(pv->routingedge)) + return NULL; + + if (TOPOROUTER_IS_CONSTRAINT(pv->routingedge)) + swap_vertices(&pv, &v); + + if (!v->routingedge) + swap_vertices(&pv, &v); + + e = v->routingedge; + + split_edge_routing(v, &l1, &l2); + g_assert(l2); + g_assert(l1); + + if (!pv->routingedge) { + toporouter_edge_t *e1, *e2; + e1 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(pv), edge_v1(e))); + e2 = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(pv), edge_v2(e))); + + l1 = g_list_concat(l1, g_list_copy(edge_routing(e1))); + l2 = g_list_concat(l2, g_list_copy(edge_routing(e2))); + + } + else { + GList *pvlist1 = NULL, *pvlist2 = NULL; + toporouter_vertex_t *commonv = route_vertices_common_vertex(v, pv); + + g_assert(commonv); + + split_edge_routing(pv, &pvlist1, &pvlist2); + + if (commonv == tedge_v1(e)) { + toporouter_edge_t *ope; + + if (commonv == tedge_v1(pv->routingedge)) { + l1 = g_list_concat(l1, pvlist1); + l2 = g_list_concat(l2, pvlist2); + ope = TOPOROUTER_EDGE(gts_vertices_are_connected(edge_v2(e), edge_v2(pv->routingedge))); + } + else { + l1 = g_list_concat(l1, pvlist2); + l2 = g_list_concat(l2, pvlist1); + ope = TOPOROUTER_EDGE(gts_vertices_are_connected(edge_v2(e), edge_v1(pv->routingedge))); + } + g_assert(ope); + l2 = g_list_concat(l2, g_list_copy(edge_routing(ope))); + + } + else { + toporouter_edge_t *ope; + if (commonv == tedge_v1(pv->routingedge)) { + l1 = g_list_concat(l1, pvlist2); + l2 = g_list_concat(l2, pvlist1); + ope = TOPOROUTER_EDGE(gts_vertices_are_connected(edge_v1(e), edge_v2(pv->routingedge))); + } + else { + l1 = g_list_concat(l1, pvlist1); + l2 = g_list_concat(l2, pvlist2); + ope = TOPOROUTER_EDGE(gts_vertices_are_connected(edge_v1(e), edge_v1(pv->routingedge))); + } + g_assert(ope); + l1 = g_list_concat(l1, g_list_copy(edge_routing(ope))); + } + } + + i = l1; + while (i) { + toporouter_vertex_t *curv = TOPOROUTER_VERTEX(i->data); + + if (curv->flags & VERTEX_FLAG_ROUTE && (g_list_find(l2, curv->parent) || g_list_find(l2, curv->child))) { + if (!g_list_find(rval, curv->route)) + rval = g_list_prepend(rval, curv->route); + } + i = i->next; + } + i = l2; + while (i) { + toporouter_vertex_t *curv = TOPOROUTER_VERTEX(i->data); + + if (curv->flags & VERTEX_FLAG_ROUTE && (g_list_find(l1, curv->parent) || g_list_find(l1, curv->child))) { + if (!g_list_find(rval, curv->route)) + rval = g_list_prepend(rval, curv->route); + } + i = i->next; + } + + g_list_free(l1); + g_list_free(l2); + + return rval; +} + +gdouble vertices_routing_conflict_cost(toporouter_t * r, toporouter_vertex_t * v, toporouter_vertex_t * pv, guint * n) +{ + GList *conflicts = vertices_routing_conflicts(v, pv), *i; + gdouble penalty = 0.; + + i = conflicts; + while (i) { + (*n) += 1; + penalty += TOPOROUTER_ROUTE(i->data)->score; + i = i->next; + } + g_list_free(conflicts); +/* if(penalty > 0.) printf("conflict penalty of %f with %f,%f %f,%f\n", penalty, vx(v), vy(v), vx(pv), vy(pv)); */ + return penalty; +} + +gdouble +gcost(toporouter_t * r, toporouter_route_t * data, toporouter_vertex_t * srcv, toporouter_vertex_t * v, + toporouter_vertex_t * pv, guint * n, toporouter_netlist_t * pair) +{ + gdouble cost = 0., segcost; + + *n = pv->gn; + + if (g_list_find(data->srcvertices, v)) + return 0.; + + segcost = tvdistance(pv, v); + + if (pair && !TOPOROUTER_IS_CONSTRAINT(v->routingedge) && v->routingedge) { + GList *list = g_list_find(v->routingedge->routing, v); + toporouter_vertex_t *pv = edge_routing_prev_not_temp(v->routingedge, list); + toporouter_vertex_t *nv = edge_routing_next_not_temp(v->routingedge, list); + + if (pv->route && pv->route->netlist == pair) { + } + else if (nv->route && nv->route->netlist == pair) { + } + else { + segcost *= 10.; + } + } + + cost = pv->gcost + segcost; + + if (r->flags & TOPOROUTER_FLAG_LEASTINVALID) { + gdouble conflictcost = 0.; + + if (pv && v != pv && vz(v) == vz(pv)) + conflictcost = vertices_routing_conflict_cost(r, v, pv, n); + + if (!(r->flags & TOPOROUTER_FLAG_DETOUR && *n == 1)) { + cost += conflictcost * (pow(*n, 2)); + } + } + + return cost; +} + +#define vlayer(x) (&r->layers[(int)vz(x)]) + +guint candidate_is_available(toporouter_vertex_t * pv, toporouter_vertex_t * v) +{ + /* TODO: still needed? */ + while (pv) { + if (pv == v) + return 0; + pv = pv->parent; + } + + return 1; +} + +GList *route(toporouter_t * r, toporouter_route_t * data, guint debug) +{ + GtsEHeap *openlist = gts_eheap_new(route_heap_cmp, NULL); + GList *closelist = NULL; + GList *i, *rval = NULL; + toporouter_netlist_t *pair = NULL; + gint count = 0; + + toporouter_vertex_t *srcv = NULL, *destv = NULL, *curpoint = NULL; + toporouter_layer_t *cur_layer; /*, *dest_layer; */ + + g_assert(data->src->c != data->dest->c); + + if (data->destvertices) + g_list_free(data->destvertices); + if (data->srcvertices) + g_list_free(data->srcvertices); + + data->destvertices = cluster_vertices(r, data->dest); + data->srcvertices = cluster_vertices(r, data->src); + + closest_cluster_pair(r, data->srcvertices, data->destvertices, &curpoint, &destv); + + if (!curpoint || !destv) + goto routing_return; + + srcv = curpoint; + cur_layer = vlayer(curpoint); + /*dest_layer = vlayer(destv); */ + + data->path = NULL; + + data->alltemppoints = g_hash_table_new(g_direct_hash, g_direct_equal); + + curpoint->parent = NULL; + curpoint->child = NULL; + curpoint->gcost = 0.; + curpoint->gn = 0; + curpoint->hcost = simple_h_cost(r, curpoint, destv); + + if (data->netlist && data->netlist->pair) { + GList *i = r->routednets; + while (i) { + toporouter_route_t *curroute = TOPOROUTER_ROUTE(i->data); + if (curroute->netlist == data->netlist->pair) { + pair = data->netlist->pair; + break; + } + i = i->next; + } + } + + gts_epcb_heap_insert(openlist, curpoint); + + while (gts_epcb_heap_size(openlist) > 0) { + GList *candidatepoints; + data->curpoint = curpoint; + /*draw_route_status(r, closelist, openlist, curpoint, data, count++); */ + + curpoint = TOPOROUTER_VERTEX(gts_eheap_remove_top(openlist, NULL)); + if (curpoint->parent && !(curpoint->flags & VERTEX_FLAG_TEMP)) { + if (vz(curpoint) != vz(destv)) { + toporouter_vertex_t *tempv; + cur_layer = vlayer(curpoint); /*&r->layers[(int)vz(curpoint)]; */ + tempv = closest_dest_vertex(r, curpoint, data); + if (tempv) { + destv = tempv; + /*dest_layer = vlayer(destv);//&r->layers[(int)vz(destv)]; */ + + } + } + } + +/* destpoint = closest_dest_vertex(r, curpoint, data); + dest_layer = &r->layers[(int)vz(destpoint)];*/ + + if (g_list_find(data->destvertices, curpoint)) { + toporouter_vertex_t *temppoint = curpoint; + srcv = NULL; + destv = curpoint; + + data->path = NULL; + + while (temppoint) { + data->path = g_list_prepend(data->path, temppoint); + if (g_list_find(data->srcvertices, temppoint)) { + srcv = temppoint; + if (r->flags & TOPOROUTER_FLAG_AFTERORDER) + break; + } + temppoint = temppoint->parent; + } + rval = data->path; + data->score = path_score(r, data->path); +#ifdef DEBUG_ROUTE + printf("ROUTE: path score = %f computation cost = %d\n", data->score, count); +#endif + + if (srcv->bbox->cluster != data->src) { + data->src = srcv->bbox->cluster; + } + + if (destv->bbox->cluster != data->dest) { + data->dest = destv->bbox->cluster; + } + goto route_finish; + } + closelist_insert(curpoint); +#ifdef DEBUG_ROUTE + printf("\n\n\n*** ROUTE COUNT = %d\n", count); +#endif + candidatepoints = compute_candidate_points(r, cur_layer, curpoint, data, &destv); + +/*#ifdef DEBUG_ROUTE */ + /********************* + if(debug && !strcmp(data->dest->netlist, " unnamed_net2")) + { + unsigned int mask = ~(VERTEX_FLAG_RED | VERTEX_FLAG_GREEN | VERTEX_FLAG_BLUE); + char buffer[256]; + int j; + + for(j=0;jlayers[j].vertices; + while(i) { + TOPOROUTER_VERTEX(i->data)->flags &= mask; + i = i->next; + } + } + + i = candidatepoints; + while(i) { + TOPOROUTER_VERTEX(i->data)->flags |= VERTEX_FLAG_GREEN; +// printf("flagged a candpoint @ %f,%f\n", +// vx(i->data), vy(i->data)); + i = i->next; + } + + curpoint->flags |= VERTEX_FLAG_BLUE; + if(curpoint->parent) + curpoint->parent->flags |= VERTEX_FLAG_RED; + + + for(j=0;jlayers[j].surface, buffer, 1024, 1024, 2, datas, j, candidatepoints); + g_list_free(datas); + } + } +//#endif + *********************/ + count++; +/* if(count > 100) exit(0);*/ + i = candidatepoints; + while (i) { + toporouter_vertex_t *temppoint = TOPOROUTER_VERTEX(i->data); + if (!g_list_find(closelist, temppoint) && candidate_is_available(curpoint, temppoint)) { /*&& temppoint != curpoint) { */ + toporouter_heap_search_data_t heap_search_data = { temppoint, NULL }; + + guint temp_gn; + gdouble temp_g_cost = gcost(r, data, srcv, temppoint, curpoint, &temp_gn, pair); + + + gts_eheap_foreach(openlist, toporouter_heap_search, &heap_search_data); + + if (heap_search_data.result) { + if (temp_g_cost < temppoint->gcost) { + + temppoint->gcost = temp_g_cost; + temppoint->gn = temp_gn; + + temppoint->parent = curpoint; + curpoint->child = temppoint; + + gts_eheap_update(openlist); + } + } + else { + temppoint->parent = curpoint; + curpoint->child = temppoint; + + temppoint->gcost = temp_g_cost; + temppoint->gn = temp_gn; + + temppoint->hcost = simple_h_cost(r, temppoint, destv); +/* if(cur_layer != dest_layer) temppoint->hcost += r->viacost;*/ + gts_epcb_heap_insert(openlist, temppoint); + } + + } + i = i->next; + } + g_list_free(candidatepoints); + + } +#ifdef DEBUG_ROUTE + printf("ROUTE: could not find path!\n"); +#endif + + data->score = INFINITY; + clean_routing_edges(r, data); + + data->path = NULL; + /*TOPOROUTER_VERTEX(data->src->point)->parent = NULL; + TOPOROUTER_VERTEX(data->src->point)->child = NULL; */ + goto routing_return; + +/* + { + int i; + for(i=0;iroutecount, i); + toporouter_draw_surface(r, r->layers[i].surface, buffer, 1280, 1280, 2, data, i, NULL); + } + r->routecount++; + } + exit(0); +*/ +route_finish: +/* printf(" * finished a*\n");*/ +/* + { + int i; + for(i=0;iroutecount); + toporouter_draw_surface(r, r->layers[i].surface, buffer, 1024, 1024, 2, data, i, NULL); + } + r->routecount++; + } +*/ +/* { + i = data->path; + while(i) { + toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data); + + if(tv->routingedge) { + GList *list = g_list_find(edge_routing(tv->routingedge), tv); + toporouter_vertex_t *restartv = NULL, *boxpoint; + + g_assert(list); + + if(!list->next) { + if(vertex_bbox(tedge_v2(tv->routingedge))) + boxpoint = TOPOROUTER_VERTEX(vertex_bbox(tedge_v2(tv->routingedge))->point); + else + boxpoint = NULL; + + if(tedge_v2(tv->routingedge) != srcv && g_list_find(data->srcvertices, tedge_v2(tv->routingedge))) + restartv = tedge_v2(tv->routingedge); + else if(boxpoint != srcv && g_list_find(data->srcvertices, boxpoint)) + restartv = boxpoint; + } + + if(!list->prev) { + if(vertex_bbox(tedge_v1(tv->routingedge))) + boxpoint = TOPOROUTER_VERTEX(vertex_bbox(tedge_v1(tv->routingedge))->point); + else + boxpoint = NULL; + + if(tedge_v1(tv->routingedge) != srcv && g_list_find(data->srcvertices, tedge_v1(tv->routingedge))) + restartv = tedge_v1(tv->routingedge); + else if(boxpoint != srcv && g_list_find(data->srcvertices, boxpoint)) + restartv = boxpoint; + + } + + if(restartv) { + clean_routing_edges(r, data); + gts_epcb_heap_destroy(openlist); + g_list_free(closelist); + openlist = gts_eheap_new(route_heap_cmp, NULL); + closelist = NULL; + g_list_free(data->path); + printf("ROUTING RESTARTING with new src %f,%f,%f\n", vx(restartv), vy(restartv), vz(restartv)); + curpoint = restartv; + goto route_begin; + } + } + + i = i->next; + } + }*/ + + { + toporouter_vertex_t *pv = NULL; + GList *i = data->path; + while (i) { + toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data); + + if (pv && g_list_find(data->srcvertices, tv)) { + GList *temp = g_list_copy(i); + g_list_free(data->path); + data->path = temp; + i = data->path; + } + pv = tv; + i = i->next; + } + } + + { + toporouter_vertex_t *pv = NULL; + GList *i = data->path; + while (i) { + toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data); + if (tv->flags & VERTEX_FLAG_TEMP) { + tv->flags ^= VERTEX_FLAG_TEMP; + tv->flags |= VERTEX_FLAG_ROUTE; + } + if (pv) + pv->child = tv; + + if (tv->routingedge) + tv->route = data; + +/* if(tv->routingedge && !TOPOROUTER_IS_CONSTRAINT(tv->routingedge)) space_edge(tv->routingedge, NULL);*/ + + pv = tv; + i = i->next; + } + } + + { + toporouter_vertex_t *pv = NULL, *v = NULL; + + GList *i = data->path; + while (i) { + v = TOPOROUTER_VERTEX(i->data); + + if (pv) { + v->parent = pv; + pv->child = v; + } + else { + v->parent = NULL; + } + + pv = v; + i = i->next; + } + + if (v) + v->child = NULL; + } + + clean_routing_edges(r, data); + { + GList *i = data->path; + while (i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); + + if (v->routingedge && !TOPOROUTER_IS_CONSTRAINT(v->routingedge)) + space_edge(v->routingedge, NULL); + i = i->next; + } + } +routing_return: + + g_list_free(data->destvertices); + g_list_free(data->srcvertices); + data->destvertices = NULL; + data->srcvertices = NULL; + gts_epcb_heap_destroy(openlist); + g_list_free(closelist); + + data->alltemppoints = NULL; + + return rval; +} + +/* moves vertex v d units in the direction of vertex p */ +void vertex_move_towards_point(GtsVertex * v, gdouble px, gdouble py, gdouble d) +{ + gdouble dx = px - GTS_POINT(v)->x; + gdouble dy = py - GTS_POINT(v)->y; + gdouble theta = atan(fabs(dy / dx)); + + g_assert(finite(theta)); + + if (dx >= 0.) { + + if (dy >= 0.) { + GTS_POINT(v)->x += d * cos(theta); + GTS_POINT(v)->y += d * sin(theta); + } + else { + GTS_POINT(v)->x += d * cos(theta); + GTS_POINT(v)->y -= d * sin(theta); + } + + } + else { + + if (dy >= 0.) { + GTS_POINT(v)->x -= d * cos(theta); + GTS_POINT(v)->y += d * sin(theta); + } + else { + GTS_POINT(v)->x -= d * cos(theta); + GTS_POINT(v)->y -= d * sin(theta); + } + + } + +} + +/* moves vertex v d units in the direction of vertex p */ +void vertex_move_towards_vertex(GtsVertex * v, GtsVertex * p, gdouble d) +{ + gdouble dx = GTS_POINT(p)->x - GTS_POINT(v)->x; + gdouble dy = GTS_POINT(p)->y - GTS_POINT(v)->y; + gdouble theta = atan(fabs(dy / dx)); + + g_assert(finite(theta)); + + if (dx >= 0.) { + + if (dy >= 0.) { + GTS_POINT(v)->x += d * cos(theta); + GTS_POINT(v)->y += d * sin(theta); + } + else { + GTS_POINT(v)->x += d * cos(theta); + GTS_POINT(v)->y -= d * sin(theta); + } + + } + else { + + if (dy >= 0.) { + GTS_POINT(v)->x -= d * cos(theta); + GTS_POINT(v)->y += d * sin(theta); + } + else { + GTS_POINT(v)->x -= d * cos(theta); + GTS_POINT(v)->y -= d * sin(theta); + } + + } + +} + + +gdouble pathvertex_arcing_through_constraint(toporouter_vertex_t * pathv, toporouter_vertex_t * arcv) +{ + toporouter_vertex_t *v = pathv->child; + + if (!v || !v->routingedge) + return 0.; + + while (v->flags & VERTEX_FLAG_ROUTE && (tedge_v1(v->routingedge) == arcv || tedge_v2(v->routingedge) == arcv)) { + if (TOPOROUTER_IS_CONSTRAINT(v->routingedge)) + return gts_point_distance(GTS_POINT(tedge_v1(v->routingedge)), GTS_POINT(tedge_v2(v->routingedge))); + v = v->child; + } + + v = pathv->parent; + while (v->flags & VERTEX_FLAG_ROUTE && (tedge_v1(v->routingedge) == arcv || tedge_v2(v->routingedge) == arcv)) { + if (TOPOROUTER_IS_CONSTRAINT(v->routingedge)) + return gts_point_distance(GTS_POINT(tedge_v1(v->routingedge)), GTS_POINT(tedge_v2(v->routingedge))); + v = v->parent; + } + + return 0.; +} + +gint vertices_connected(toporouter_vertex_t * a, toporouter_vertex_t * b) +{ + return ((a->route->netlist == b->route->netlist && a->route->src->c == b->route->src->c) ? 1 : 0); +} + +gdouble edge_min_spacing(GList * list, toporouter_edge_t * e, toporouter_vertex_t * v, guint debug) +{ + toporouter_vertex_t *origin; + GList *i = list; + gdouble space = 0.; + toporouter_vertex_t *nextv, *prevv; + /*toporouter_vertex_t *edgev; + gdouble constraint_spacing; */ + + if (!list) + return INFINITY; + +/* printf("\t CMS %f,%f - %f,%f\n", vx(tedge_v1(e)), vy(tedge_v1(e)), vx(tedge_v2(e)), vy(tedge_v2(e))); */ + + prevv = origin = TOPOROUTER_VERTEX(list->data); + +/* print_edge(e); */ + + i = list; + if (gts_point_distance2(GTS_POINT(origin), GTS_POINT(edge_v1(e))) < gts_point_distance2(GTS_POINT(v), GTS_POINT(edge_v1(e)))) { + + /* towards v2 */ + while (i) { + nextv = edge_routing_next(e, i); + if (nextv->route && vertices_connected(nextv, prevv)) { + i = i->next; + continue; + } + if (!(nextv->flags & VERTEX_FLAG_TEMP)) { + gdouble ms = min_spacing(prevv, nextv); + if (nextv == tedge_v2(e)) { + gdouble cms = pathvertex_arcing_through_constraint(TOPOROUTER_VERTEX(i->data), tedge_v2(e)); +/* printf("\t CMS to %f,%f = %f \t ms = %f\n", vx(tedge_v2(e)), vy(tedge_v2(e)), cms, ms); + if(vx(tedge_v2(e)) > -EPSILON && vx(tedge_v2(e)) < EPSILON) { + printf("\t\tPROB: "); + print_vertex(tedge_v2(e)); + }*/ + if (cms > EPSILON) + space += MIN(ms, cms / 2.); + else + space += ms; + } + else + space += ms; + + prevv = nextv; + } +/* printf("%f ", space);*/ + i = i->next; + } + } + else { + + /* towards v1 */ + while (i) { + nextv = edge_routing_prev(e, i); + if (nextv->route && vertices_connected(nextv, prevv)) { + i = i->prev; + continue; + } + if (!(nextv->flags & VERTEX_FLAG_TEMP)) { + gdouble ms = min_spacing(prevv, nextv); + if (nextv == tedge_v1(e)) { + gdouble cms = pathvertex_arcing_through_constraint(TOPOROUTER_VERTEX(i->data), tedge_v1(e)); +/* printf("\t CMS to %f,%f = %f \t ms = %f\n", vx(tedge_v1(e)), vy(tedge_v1(e)), cms, ms); + if(vx(tedge_v1(e)) > -EPSILON && vx(tedge_v1(e)) < EPSILON) { + printf("\t\tPROB: "); + print_vertex(tedge_v1(e)); + }*/ + if (cms > EPSILON) + space += MIN(ms, cms / 2.); + else + space += ms; + } + else + space += ms; + + prevv = nextv; + } +/* printf("%f ", space);*/ + i = i->prev; + } + } + + if (TOPOROUTER_IS_CONSTRAINT(e) && space > gts_point_distance(GTS_POINT(edge_v1(e)), GTS_POINT(edge_v2(e))) / 2.) + space = gts_point_distance(GTS_POINT(edge_v1(e)), GTS_POINT(edge_v2(e))) / 2.; + +/* if(debug) printf("\tedge_min_spacing: %f\n", space);*/ + return space; +} + +/* line segment is 1 & 2, point is 3 + returns 0 if v3 is outside seg +*/ +guint +vertex_line_normal_intersection(gdouble x1, gdouble y1, gdouble x2, gdouble y2, gdouble x3, gdouble y3, gdouble * x, + gdouble * y) +{ + gdouble m1 = cartesian_gradient(x1, y1, x2, y2); + gdouble m2 = perpendicular_gradient(m1); + gdouble c2 = (isinf(m2)) ? x3 : y3 - (m2 * x3); + gdouble c1 = (isinf(m1)) ? x1 : y1 - (m1 * x1); + + if (isinf(m2)) + *x = x3; + else if (isinf(m1)) + *x = x1; + else + *x = (c2 - c1) / (m1 - m2); + + *y = (isinf(m2)) ? y1 : (m2 * (*x)) + c2; + + if (*x >= MIN(x1, x2) - EPSILON && *x <= MAX(x1, x2) + EPSILON && *y >= MIN(y1, y2) - EPSILON && *y <= MAX(y1, y2) + EPSILON) + return 1; + return 0; +} + +void print_toporouter_arc(toporouter_arc_t * arc) +{ +/* GList *i = arc->vs;*/ + + printf("ARC CENTRE: %f,%f ", vx(arc->centre), vy(arc->centre)); /* print_vertex(arc->centre); */ + printf("RADIUS: %f", arc->r); + + if (arc->dir > 0) + printf(" COUNTERCLOCKWISE "); + else if (arc->dir < 0) + printf(" CLOCKWISE "); + else + printf(" COLINEAR(ERROR) "); +/* + printf("\n\tVS: "); + + while(i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); + printf("%f,%f ", vx(v), vy(v)); + + i = i->next; + } +*/ +} + +void toporouter_arc_remove(toporouter_oproute_t * oproute, toporouter_arc_t * arc) +{ + oproute->arcs = g_list_remove(oproute->arcs, arc); + + if (arc->v) + arc->v->arc = NULL; +} + +toporouter_arc_t *toporouter_arc_new(toporouter_oproute_t * oproute, toporouter_vertex_t * v1, toporouter_vertex_t * v2, + toporouter_vertex_t * centre, gdouble r, gint dir) +{ + toporouter_arc_t *arc = TOPOROUTER_ARC(gts_object_new(GTS_OBJECT_CLASS(toporouter_arc_class()))); + arc->centre = centre; + arc->v = v1; + arc->v1 = v1; + arc->v2 = v2; + arc->r = r; + arc->dir = dir; + + if (v1) + v1->arc = arc; + arc->oproute = oproute; + + arc->clearance = NULL; + + return arc; +} + +void path_set_oproute(GList * path, toporouter_oproute_t * oproute) +{ + while (path) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(path->data); + + if (v->flags & VERTEX_FLAG_ROUTE) + v->oproute = oproute; + + path = path->next; + } +} + +void print_oproute(toporouter_oproute_t * oproute) +{ + GList *i = oproute->arcs; + + printf("Optimized Route:\n"); + printf("\tNetlist:\t\t%s\n\tStyle:\t\t%s\n", oproute->netlist, oproute->style); + /* printf("%s\n", oproute->netlist); */ +/* + i = oproute->term1->zlink; + while(i) { + toporouter_vertex_t *thisv = TOPOROUTER_VERTEX(i->data); + printf("\tNetlist:\t\t%s\n\tStyle:\t\t%s\n", vertex_bbox(thisv)->netlist, vertex_bbox(thisv)->style); + i = i->next; + } +*/ + printf("\t"); + print_vertex(oproute->term1); + printf("\n"); + i = oproute->arcs; + while (i) { + toporouter_arc_t *arc = (toporouter_arc_t *) i->data; + printf("\t"); + print_toporouter_arc(arc); + printf("\n"); + i = i->next; + } + printf("\t"); + print_vertex(oproute->term2); + printf("\n"); +} + +gdouble export_pcb_drawline(guint layer, guint x0, guint y0, guint x1, guint y1, guint thickness, guint clearance) +{ + gdouble d = 0.; + pcb_line_t *line; + line = pcb_line_new_merge(LAYER_PTR(layer), x0, y0, x1, y1, + thickness, clearance, pcb_flag_make(PCB_FLAG_AUTO | (PCB_FLAG_TEST(PCB_CLEARNEWFLAG, PCB) ? PCB_FLAG_CLEARLINE : 0))); + + if (line) { + pcb_undo_add_obj_to_create(PCB_TYPE_LINE, LAYER_PTR(layer), line, line); + d = coord_distance((double) x0, (double) y0, (double) x1, (double) y1) / 100.; + } + return d; +} + +gdouble arc_angle(toporouter_arc_t * arc) +{ + gdouble x0, x1, y0, y1; + + x0 = arc->x0 - vx(arc->centre); + x1 = arc->x1 - vx(arc->centre); + y0 = arc->y0 - vy(arc->centre); + y1 = arc->y1 - vy(arc->centre); + + return fabs(acos(((x0 * x1) + (y0 * y1)) / (sqrt(pow(x0, 2) + pow(y0, 2)) * sqrt(pow(x1, 2) + pow(y1, 2))))); +} + +gdouble export_pcb_drawarc(guint layer, toporouter_arc_t * a, guint thickness, guint clearance) +{ + gdouble sa, da, theta; + gdouble d = 0.; + pcb_arc_t *arc; + gint wind; + + wind = coord_wind(a->x0, a->y0, a->x1, a->y1, vx(a->centre), vy(a->centre)); + + sa = coord_xangle(a->x0, a->y0, vx(a->centre), vy(a->centre)) * 180. / M_PI; + + theta = arc_angle(a); + + if (!a->dir || !wind) + return 0.; + + if (a->dir != wind) + theta = 2. * M_PI - theta; + + da = -a->dir * theta * 180. / M_PI; + + if (da < 1. && da > -1.) + return 0.; + if (da > 359. || da < -359.) + return 0.; + + arc = pcb_arc_new(LAYER_PTR(layer), vx(a->centre), vy(a->centre), a->r, a->r, + sa, da, thickness, clearance, + pcb_flag_make(PCB_FLAG_AUTO | (PCB_FLAG_TEST(PCB_CLEARNEWFLAG, PCB) ? PCB_FLAG_CLEARLINE : 0))); + + if (arc) { + pcb_undo_add_obj_to_create(PCB_TYPE_ARC, LAYER_PTR(layer), arc, arc); + d = a->r * theta / 100.; + } + + return d; +} + +void calculate_term_to_arc(toporouter_vertex_t * v, toporouter_arc_t * arc, guint dir) +{ + gdouble theta, a, b, bx, by, a0x, a0y, a1x, a1y; + gint winddir; + + theta = acos(arc->r / gts_point_distance(GTS_POINT(v), GTS_POINT(arc->centre))); + a = arc->r * sin(theta); + b = arc->r * cos(theta); +#ifdef DEBUG_EXPORT + printf("drawing arc with r %f theta %f d %f centre = %f,%f\n", arc->r, theta, + gts_point_distance(GTS_POINT(v), GTS_POINT(arc->centre)), vx(arc->centre), vy(arc->centre)); +#endif + point_from_point_to_point(arc->centre, v, b, &bx, &by); + + coords_on_line(bx, by, perpendicular_gradient(point_gradient(GTS_POINT(v), GTS_POINT(arc->centre))), a, &a0x, &a0y, &a1x, + &a1y); + + winddir = coord_wind(vx(v), vy(v), a0x, a0y, vx(arc->centre), vy(arc->centre)); + + if (!winddir) { + printf("!winddir @ v %f,%f arc->centre %f,%f\n", vx(v), vy(v), vx(arc->centre), vy(arc->centre)); + /*TODO: fix hack: this shouldn't happen */ + arc->x0 = vx(v); + arc->y0 = vy(v); + arc->x1 = vx(v); + arc->y1 = vy(v); + return; + } + + g_assert(winddir); + + if (dir) + winddir = -winddir; + + if (winddir == arc->dir) { + if (!dir) { + arc->x0 = a0x; + arc->y0 = a0y; + } + else { + arc->x1 = a0x; + arc->y1 = a0y; + } + } + else { + if (!dir) { + arc->x0 = a1x; + arc->y0 = a1y; + } + else { + arc->x1 = a1x; + arc->y1 = a1y; + } + } + +} + + + +/* b1 is the projection in the direction of narc, while b2 is the perpendicular projection*/ +void arc_ortho_projections(toporouter_arc_t * arc, toporouter_arc_t * narc, gdouble * b1, gdouble * b2) +{ + gdouble nax, nay, ax, ay, alen2, c; + gdouble b1x, b1y, b2x, b2y; + +#ifdef DEBUG_EXPORT + printf("arc c = %f,%f narc c = %f,%f arc->0 = %f,%f\n", + vx(arc->centre), vy(arc->centre), vx(narc->centre), vy(narc->centre), arc->x0, arc->y0); +#endif + + nax = vx(narc->centre) - vx(arc->centre); + nay = vy(narc->centre) - vy(arc->centre); + alen2 = pow(nax, 2) + pow(nay, 2); + + + ax = arc->x0 - vx(arc->centre); + ay = arc->y0 - vy(arc->centre); + +#ifdef DEBUG_EXPORT + printf("norm narc = %f,%f - %f\tA=%f,%f\n", nax, nay, sqrt(alen2), ax, ay); +#endif + + c = ((ax * nax) + (ay * nay)) / alen2; + + b1x = c * nax; + b1y = c * nay; + b2x = ax - b1x; + b2y = ay - b1y; + +#ifdef DEBUG_EXPORT + printf("proj = %f,%f perp proj = %f,%f\n", b1x, b1y, b2x, b2y); +#endif + + *b1 = sqrt(pow(b1x, 2) + pow(b1y, 2)); + *b2 = sqrt(pow(b2x, 2) + pow(b2y, 2)); + +} + +guint calculate_arc_to_arc(toporouter_t * ar, toporouter_arc_t * parc, toporouter_arc_t * arc) +{ + gdouble theta, a, b, bx, by, a0x, a0y, a1x, a1y, m, preva, prevb; + gint winddir; + toporouter_arc_t *bigr, *smallr; + + if (parc->r > arc->r) { + bigr = parc; + smallr = arc; + } + else { + bigr = arc; + smallr = parc; + } +#ifdef DEBUG_EXPORT + printf("bigr centre = %f,%f smallr centre = %f,%f\n", vx(bigr->centre), vy(bigr->centre), + vx(smallr->centre), vy(smallr->centre)); +#endif + + m = perpendicular_gradient(point_gradient(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre))); + + if (bigr->centre == smallr->centre) { + + printf("bigr->centre == smallr->centre @ %f,%f\n", vx(smallr->centre), vy(smallr->centre)); + } + + g_assert(bigr->centre != smallr->centre); + + if (parc->dir == arc->dir) { +/*export_arc_straight:*/ + + theta = acos((bigr->r - smallr->r) / gts_point_distance(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre))); + a = bigr->r * sin(theta); + b = bigr->r * cos(theta); + + point_from_point_to_point(bigr->centre, smallr->centre, b, &bx, &by); + + coords_on_line(bx, by, m, a, &a0x, &a0y, &a1x, &a1y); + + winddir = coord_wind(vx(smallr->centre), vy(smallr->centre), a0x, a0y, vx(bigr->centre), vy(bigr->centre)); + + arc_ortho_projections(parc, arc, &prevb, &preva); +/*#ifdef DEBUG_EXPORT */ + if (!winddir) { + + printf("STRAIGHT:\n"); + printf("bigr centre = %f,%f smallr centre = %f,%f\n", vx(bigr->centre), vy(bigr->centre), + vx(smallr->centre), vy(smallr->centre)); + printf("theta = %f a = %f b = %f bigrr = %f d = %f po = %f\n", theta, a, b, bigr->r, + gts_point_distance(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre)), + bigr->r / gts_point_distance(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre))); + printf("bigr-r = %f smallr-r = %f ratio = %f\n", + bigr->r, smallr->r, (bigr->r - smallr->r) / gts_point_distance(GTS_POINT(bigr->centre), + GTS_POINT(smallr->centre))); + printf("preva = %f prevb = %f\n\n", preva, prevb); + + } +/*#endif*/ + g_assert(winddir); + + if (bigr == parc) + winddir = -winddir; + + if (winddir == bigr->dir) { + if (bigr == arc) { + bigr->x0 = a0x; + bigr->y0 = a0y; + } + else { + bigr->x1 = a0x; + bigr->y1 = a0y; + } + } + else { + if (bigr == arc) { + bigr->x0 = a1x; + bigr->y0 = a1y; + } + else { + bigr->x1 = a1x; + bigr->y1 = a1y; + } + } + + a = smallr->r * sin(theta); + b = smallr->r * cos(theta); + +#ifdef DEBUG_EXPORT + printf("a = %f b = %f\n", a, b); +#endif + point_from_point_to_point(smallr->centre, bigr->centre, -b, &bx, &by); + + coords_on_line(bx, by, m, a, &a0x, &a0y, &a1x, &a1y); + + if (winddir == bigr->dir) { + if (bigr == arc) { + smallr->x1 = a0x; + smallr->y1 = a0y; + } + else { + smallr->x0 = a0x; + smallr->y0 = a0y; + } + } + else { + if (bigr == arc) { + smallr->x1 = a1x; + smallr->y1 = a1y; + } + else { + smallr->x0 = a1x; + smallr->y0 = a1y; + } + } + + } + else { + +/*export_arc_twist: */ + + theta = acos((bigr->r + smallr->r) / gts_point_distance(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre))); + a = bigr->r * sin(theta); + b = bigr->r * cos(theta); + + point_from_point_to_point(bigr->centre, smallr->centre, b, &bx, &by); + + coords_on_line(bx, by, m, a, &a0x, &a0y, &a1x, &a1y); + + winddir = coord_wind(vx(smallr->centre), vy(smallr->centre), a0x, a0y, vx(bigr->centre), vy(bigr->centre)); +/*#ifdef DEBUG_EXPORT */ + if (!winddir) { + printf("TWIST:\n"); + printf("theta = %f a = %f b = %f r = %f d = %f po = %f\n", theta, a, b, bigr->r + smallr->r, + gts_point_distance(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre)), + (bigr->r + smallr->r) / gts_point_distance(GTS_POINT(bigr->centre), GTS_POINT(smallr->centre))); + + printf("bigr centre = %f,%f smallr centre = %f,%f\n\n", vx(bigr->centre), vy(bigr->centre), + vx(smallr->centre), vy(smallr->centre)); + + printf("big wind = %d small wind = %d\n", bigr->dir, smallr->dir); + return 1; + } +/*#endif */ +/* if(!winddir) { + smallr->centre->flags |= VERTEX_FLAG_RED; + bigr->centre->flags |= VERTEX_FLAG_GREEN; + //bigr->centre->flags |= VERTEX_FLAG_RED; + { + int i; + for(i=0;ilayers[i].surface, buffer, 2096, 2096, 2, NULL, i, NULL); + } + } + return; + } +*/ + g_assert(winddir); + + if (bigr == parc) + winddir = -winddir; + + if (winddir == bigr->dir) { + if (bigr == arc) { + bigr->x0 = a0x; + bigr->y0 = a0y; + } + else { + bigr->x1 = a0x; + bigr->y1 = a0y; + } + } + else { + if (bigr == arc) { + bigr->x0 = a1x; + bigr->y0 = a1y; + } + else { + bigr->x1 = a1x; + bigr->y1 = a1y; + } + } + + a = smallr->r * sin(theta); + b = smallr->r * cos(theta); + + point_from_point_to_point(smallr->centre, bigr->centre, b, &bx, &by); + + coords_on_line(bx, by, m, a, &a0x, &a0y, &a1x, &a1y); + + winddir = coord_wind(vx(smallr->centre), vy(smallr->centre), a0x, a0y, vx(bigr->centre), vy(bigr->centre)); + + g_assert(winddir); + + if (bigr == parc) + winddir = -winddir; + + if (winddir == smallr->dir) { + if (bigr == arc) { + smallr->x1 = a0x; + smallr->y1 = a0y; + } + else { + smallr->x0 = a0x; + smallr->y0 = a0y; + } + } + else { + if (bigr == arc) { + smallr->x1 = a1x; + smallr->y1 = a1y; + } + else { + smallr->x0 = a1x; + smallr->y0 = a1y; + } + } + + } + + return 0; +} + +void export_oproutes(toporouter_t * ar, toporouter_oproute_t * oproute) +{ + guint layer = PCB->LayerGroups.Entries[oproute->layergroup][0]; + guint thickness = lookup_thickness(oproute->style); + guint clearance = lookup_clearance(oproute->style); + GList *arcs = oproute->arcs; + toporouter_arc_t *arc, *parc = NULL; + + if (!arcs) { + ar->wiring_score += + export_pcb_drawline(layer, vx(oproute->term1), vy(oproute->term1), vx(oproute->term2), vy(oproute->term2), thickness, + clearance); + return; + } + + +/* calculate_term_to_arc(oproute->term1, TOPOROUTER_ARC(arcs->data), 0, layer);*/ + + while (arcs) { + arc = TOPOROUTER_ARC(arcs->data); + + if (parc && arc) { + ar->wiring_score += export_pcb_drawarc(layer, parc, thickness, clearance); + ar->wiring_score += export_pcb_drawline(layer, parc->x1, parc->y1, arc->x0, arc->y0, thickness, clearance); + } + else if (!parc) { + ar->wiring_score += + export_pcb_drawline(layer, vx(oproute->term1), vy(oproute->term1), arc->x0, arc->y0, thickness, clearance); + } + + parc = arc; + arcs = arcs->next; + } + ar->wiring_score += export_pcb_drawarc(layer, arc, thickness, clearance); + ar->wiring_score += export_pcb_drawline(layer, arc->x1, arc->y1, vx(oproute->term2), vy(oproute->term2), thickness, clearance); + +} + + + +void oproute_free(toporouter_oproute_t * oproute) +{ + GList *i = oproute->arcs; + while (i) { + toporouter_arc_t *arc = (toporouter_arc_t *) i->data; + if (arc->centre->flags & VERTEX_FLAG_TEMP) + gts_object_destroy(GTS_OBJECT(arc->centre)); + + i = i->next; + } + + g_list_free(oproute->arcs); + free(oproute); +} + +void oproute_calculate_tof(toporouter_oproute_t * oproute) +{ + GList *arcs = oproute->arcs; + toporouter_arc_t *parc = NULL, *arc; + + oproute->tof = 0.; + + if (!arcs) { + oproute->tof = gts_point_distance(GTS_POINT(oproute->term1), GTS_POINT(oproute->term2)); + return; + } + + while (arcs) { + arc = TOPOROUTER_ARC(arcs->data); + + if (parc && arc) { + oproute->tof += arc_angle(parc) * parc->r; + oproute->tof += sqrt(pow(parc->x1 - arc->x0, 2) + pow(parc->y1 - arc->y0, 2)); + } + else if (!parc) { + oproute->tof += sqrt(pow(arc->x0 - vx(oproute->term1), 2) + pow(arc->y0 - vy(oproute->term1), 2)); + } + + parc = arc; + arcs = arcs->next; + } + + oproute->tof += arc_angle(parc) * parc->r; + oproute->tof += sqrt(pow(arc->x1 - vx(oproute->term2), 2) + pow(arc->y1 - vy(oproute->term2), 2)); + +} + +gdouble +line_line_distance_at_normal(gdouble line1_x1, gdouble line1_y1, + gdouble line1_x2, gdouble line1_y2, + gdouble line2_x1, gdouble line2_y1, gdouble line2_x2, gdouble line2_y2, gdouble x, gdouble y) +{ + gdouble m1 = perpendicular_gradient(cartesian_gradient(line1_x1, line1_y1, line1_x2, line1_y2)); + gdouble m2 = cartesian_gradient(line2_x1, line2_y1, line2_x2, line2_y2); + gdouble c1 = (isinf(m1)) ? x : y - (m1 * x); + gdouble c2 = (isinf(m2)) ? line2_x1 : line2_y1 - (m2 * line2_x1); + + gdouble intx, inty; + + if (isinf(m2)) + intx = line2_x1; + else if (isinf(m1)) + intx = x; + else + intx = (c2 - c1) / (m1 - m2); + + inty = (isinf(m2)) ? (m1 * intx) + c1 : (m2 * intx) + c2; + + return sqrt(pow(x - intx, 2) + pow(y - inty, 2)); +} + +void calculate_serpintine(gdouble delta, gdouble r, gdouble initiala, gdouble * a, guint * nhalfcycles) +{ + gdouble lhalfcycle = 2. * (initiala - r) + (M_PI * r); + guint n; + + printf("lhalfcycle = %f r = %f\n", lhalfcycle, r); + + n = (delta - M_PI * r) / (lhalfcycle - 2. * r) + 1; + *a = (delta + 4. * n * r - n * M_PI * r + 4. * r - M_PI * r) / (2. * n); + *nhalfcycles = n; +} + +gdouble oproute_min_spacing(toporouter_oproute_t * a, toporouter_oproute_t * b) +{ + return lookup_thickness(a->style) / 2. + lookup_thickness(b->style) / 2. + MAX(lookup_clearance(a->style), + lookup_clearance(b->style)); +} + +gdouble vector_angle(gdouble ox, gdouble oy, gdouble ax, gdouble ay, gdouble bx, gdouble by) +{ + gdouble alen = sqrt(pow(ax - ox, 2) + pow(ay - oy, 2)); + gdouble blen = sqrt(pow(bx - ox, 2) + pow(by - oy, 2)); + return acos(((ax - ox) * (bx - ox) + (ay - oy) * (by - oy)) / (alen * blen)); +} + +toporouter_serpintine_t *toporouter_serpintine_new(gdouble x, gdouble y, gdouble x0, gdouble y0, gdouble x1, gdouble y1, + gpointer start, gdouble halfa, gdouble radius, guint nhalfcycles) +{ + toporouter_serpintine_t *serp = (toporouter_serpintine_t *) malloc(sizeof(toporouter_serpintine_t)); + serp->x = x; + serp->y = y; + serp->x0 = x0; + serp->y0 = y0; + serp->x1 = x1; + serp->y1 = y1; + serp->start = start; + serp->halfa = halfa; + serp->radius = radius; + serp->nhalfcycles = nhalfcycles; + serp->arcs = NULL; + return serp; +} + +/*#define DEBUG_RUBBERBAND 1*/ + +gdouble +check_non_intersect_vertex(gdouble x0, gdouble y0, gdouble x1, gdouble y1, toporouter_vertex_t * pathv, + toporouter_vertex_t * arcv, toporouter_vertex_t * opv, gint wind, gint * arcwind, gdouble * arcr, + guint debug) +{ + gdouble ms, line_int_x, line_int_y, x, y, d = 0., m; + gdouble tx0, ty0, tx1, ty1; + gint wind1, wind2; + + g_assert(pathv->routingedge); + + if (TOPOROUTER_IS_CONSTRAINT(pathv->routingedge)) { + gdouble d = tvdistance(tedge_v1(pathv->routingedge), tedge_v2(pathv->routingedge)) / 2.; + ms = min_spacing(pathv, arcv); + if (ms > d) + ms = d; + } + else { + ms = edge_min_spacing(g_list_find(edge_routing(pathv->routingedge), pathv), pathv->routingedge, arcv, debug); + } + + + if (!vertex_line_normal_intersection(x0, y0, x1, y1, vx(arcv), vy(arcv), &line_int_x, &line_int_y)) { + + if (coord_distance2(x0, y0, line_int_x, line_int_y) < coord_distance2(x1, y1, line_int_x, line_int_y)) { + line_int_x = x0; + line_int_y = y0; + } + else { + line_int_x = x1; + line_int_y = y1; + } + + m = perpendicular_gradient(cartesian_gradient(vx(arcv), vy(arcv), line_int_x, line_int_y)); + } + else { + m = cartesian_gradient(x0, y0, x1, y1); + } + + coords_on_line(vx(arcv), vy(arcv), m, 100., &tx0, &ty0, &tx1, &ty1); + + wind1 = coord_wind(tx0, ty0, tx1, ty1, line_int_x, line_int_y); + wind2 = coord_wind(tx0, ty0, tx1, ty1, vx(opv), vy(opv)); + + if (!wind2 || wind1 == wind2) + return -1.; + + if (!wind) { + coords_on_line(line_int_x, line_int_y, perpendicular_gradient(m), ms, &tx0, &ty0, &tx1, &ty1); + if (coord_distance2(tx0, ty0, vx(opv), vy(opv)) < coord_distance2(tx1, ty1, vx(opv), vy(opv))) { + x = tx0; + y = ty0; + } + else { + x = tx1; + y = ty1; + } + } + else { + toporouter_vertex_t *parent = pathv->parent, *child = pathv->child; + guint windtests = 0; + + d = coord_distance(vx(arcv), vy(arcv), line_int_x, line_int_y); + coord_move_towards_coord_values(line_int_x, line_int_y, vx(arcv), vy(arcv), ms + d, &x, &y); + rewind_test: + wind1 = coord_wind(line_int_x, line_int_y, x, y, vx(parent), vy(parent)); + wind2 = coord_wind(line_int_x, line_int_y, x, y, vx(child), vy(child)); + if (wind1 && wind2 && wind1 == wind2) { +/* return -1.;*/ + if (windtests++ == 2) + return -1.; + + if (parent->flags & VERTEX_FLAG_ROUTE) + parent = parent->parent; + if (child->flags & VERTEX_FLAG_ROUTE) + child = child->child; + goto rewind_test; + } + } + + + *arcr = ms; + *arcwind = tvertex_wind(pathv->parent, pathv, arcv); + +#ifdef DEBUG_RUBBERBAND +/*if(debug) + printf("non-int check %f,%f ms %f d %f arcv %f,%f opv %f,%f\n", vx(arcv), vy(arcv), ms, d + ms, + vx(arcv), vy(arcv), vx(opv), vy(opv));*/ +#endif + + return d + ms; +} + +gdouble +check_intersect_vertex(gdouble x0, gdouble y0, gdouble x1, gdouble y1, toporouter_vertex_t * pathv, toporouter_vertex_t * arcv, + toporouter_vertex_t * opv, gint wind, gint * arcwind, gdouble * arcr, guint debug) +{ + gdouble ms, line_int_x, line_int_y, x, y, d = 0.; + + if (TOPOROUTER_IS_CONSTRAINT(pathv->routingedge)) { + gdouble d = tvdistance(tedge_v1(pathv->routingedge), tedge_v2(pathv->routingedge)) / 2.; + ms = min_spacing(pathv, arcv); + if (ms > d) + ms = d; + } + else { + ms = edge_min_spacing(g_list_find(edge_routing(pathv->routingedge), pathv), pathv->routingedge, arcv, debug); + } + + if (!vertex_line_normal_intersection(x0, y0, x1, y1, vx(arcv), vy(arcv), &line_int_x, &line_int_y)) + return -1.; + + d = coord_distance(line_int_x, line_int_y, vx(arcv), vy(arcv)); + + + if (d > ms - EPSILON) + return -1.; + + coord_move_towards_coord_values(vx(arcv), vy(arcv), line_int_x, line_int_y, ms, &x, &y); + + *arcr = ms; + *arcwind = tvertex_wind(pathv->parent, pathv, arcv); +/* *arcwind = coord_wind(x0, y0, x, y, x1, y1);*/ +#ifdef DEBUG_RUBBERBAND +/*if(debug) + printf("int check %f,%f ms %f d %f arcv %f,%f opv %f,%f\n", vx(arcv), vy(arcv), ms, ms - d, + vx(arcv), vy(arcv), vx(opv), vy(opv));*/ +#endif + + return ms - d; +} + +/* returns non-zero if arc has loops */ +guint check_arc_for_loops(gpointer t1, toporouter_arc_t * arc, gpointer t2) +{ + gdouble x0, y0, x1, y1; + + if (TOPOROUTER_IS_VERTEX(t1)) { + x0 = vx(TOPOROUTER_VERTEX(t1)); + y0 = vy(TOPOROUTER_VERTEX(t1)); + } + else { + x0 = TOPOROUTER_ARC(t1)->x1; + y0 = TOPOROUTER_ARC(t1)->y1; + } + + if (TOPOROUTER_IS_VERTEX(t2)) { + x1 = vx(TOPOROUTER_VERTEX(t2)); + y1 = vy(TOPOROUTER_VERTEX(t2)); + } + else { + x1 = TOPOROUTER_ARC(t2)->x0; + y1 = TOPOROUTER_ARC(t2)->y0; + } + + if (coord_intersect_prop(x0, y0, arc->x0, arc->y0, arc->x1, arc->y1, x1, y1)) { +/* || + (arc->x0 > arc->x1 - EPSILON && arc->x0 < arc->x1 + EPSILON && + arc->y0 > arc->y1 - EPSILON && arc->y0 < arc->y1 + EPSILON) + ) {*/ +#ifdef DEBUG_RUBBERBAND + printf("LOOPS %f %f -> %f %f & %f %f -> %f %f\n", x0, y0, arc->x0, arc->y0, arc->x1, arc->y1, x1, y1); +#endif + return 1; + } + return 0; +} + +toporouter_rubberband_arc_t *new_rubberband_arc(toporouter_vertex_t * pathv, toporouter_vertex_t * arcv, gdouble r, gdouble d, + gint wind, GList * list) +{ + toporouter_rubberband_arc_t *rba = (toporouter_rubberband_arc_t *) malloc(sizeof(toporouter_rubberband_arc_t)); + rba->pathv = pathv; + rba->arcv = arcv; + rba->r = r; + rba->d = d; + rba->wind = wind; + rba->list = list; + return rba; +} + +gint compare_rubberband_arcs(toporouter_rubberband_arc_t * a, toporouter_rubberband_arc_t * b) +{ + return b->d - a->d; +} + +void free_list_elements(gpointer data, gpointer user_data) +{ + free(data); +} + + +/* returns the edge opposite v from the triangle facing (x,y), or NULL if v is colinear with an edge between v and a neighbor */ +/* +GtsEdge * +vertex_edge_facing_vertex(GtsVertex *v, gdouble x, gdouble y) +{ + GSList *ts = gts_vertex_triangles(GTS_VERTEX(n), NULL); + GSList *i = ts; + + while(i) { + GtsTriangle *t = GTS_TRIANGLE(i->data); + GtsEdge *e = gts_triangle_edge_opposite(t, v); + + if(coord_wind(vx(edge_v1(e)), vy(edge_v1(e)), vx(v), vy(v), x, y) == vertex_wind(edge_v1(e), v, edge_v2(e)) && + coord_wind(vx(edge_v2(e)), vy(edge_v2(e)), vx(v), vy(v), x, y) == vertex_wind(edge_v2(e), v, edge_v1(e)) + ) { + g_slist_free(ts); + return e; + } + + i = i->next; + } + + g_slist_free(ts); + return NULL; +} +*/ + +gdouble +check_adj_pushing_vertex(toporouter_oproute_t * oproute, gdouble x0, gdouble y0, gdouble x1, gdouble y1, + toporouter_vertex_t * v, gdouble * arcr, gint * arcwind, toporouter_vertex_t ** arc) +{ + GSList *ns = gts_vertex_neighbors(GTS_VERTEX(v), NULL, NULL); + GSList *i = ns; + gdouble maxd = 0.; + + while (i) { + toporouter_vertex_t *n = TOPOROUTER_VERTEX(i->data); + gdouble segintx, seginty; + if (vertex_line_normal_intersection(x0, y0, x1, y1, vx(n), vy(n), &segintx, &seginty)) { + toporouter_edge_t *e = tedge(n, v); + gdouble ms = 0., d = coord_distance(segintx, seginty, vx(n), vy(n)); + /*toporouter_vertex_t *a; */ + toporouter_vertex_t *b; + GList *closestnet = NULL; + + g_assert(e); + + if (v == tedge_v1(e)) { + /*a = tedge_v1(e); */ + b = tedge_v2(e); + closestnet = edge_routing(e); + } + else { + /*a = tedge_v2(e); */ + b = tedge_v1(e); + closestnet = g_list_last(edge_routing(e)); + } + + if (closestnet) { + ms = edge_min_spacing(closestnet, e, b, 0); + ms += min_oproute_net_spacing(oproute, TOPOROUTER_VERTEX(closestnet->data)); + } + else { + ms = min_oproute_vertex_spacing(oproute, b); + } + + if (ms - d > maxd) { + *arcr = ms; + *arc = n; + maxd = ms - d; + if (vx(v) == x0 && vy(v) == y0) { + *arcwind = coord_wind(x0, y0, vx(n), vy(n), x1, y1); + } + else if (vx(v) == x1 && vy(v) == y1) { + *arcwind = coord_wind(x1, y1, vx(n), vy(n), x0, y0); + } + else { + fprintf(stderr, "ERROR: check_adj_pushing_vertex encountered bad vertex v (coordinates don't match)\n"); + } + } + } + + i = i->next; + } + + g_slist_free(ns); + return maxd; +} + + +/* path is t1 path*/ +GList *oproute_rubberband_segment(toporouter_t * r, toporouter_oproute_t * oproute, GList * path, gpointer t1, gpointer t2, + guint debug) +{ + gdouble x0, y0, x1, y1; + toporouter_vertex_t *v1, *v2, *av1, *av2; /* v{1,2} are the vertex terminals of the segment, or arc terminal centres */ + toporouter_arc_t *arc1 = NULL, *arc2 = NULL, *newarc = NULL; /* arc{1,2} are the arc terminals of the segment, if they exist */ + GList *i = path; + GList *list1, *list2; + + GList *arcs = NULL; + toporouter_rubberband_arc_t *max = NULL; + + gdouble d, arcr; + gint v1wind, v2wind, arcwind; + + if (TOPOROUTER_IS_VERTEX(t1)) { + v1 = TOPOROUTER_VERTEX(t1); + x0 = vx(v1); + y0 = vy(v1); + } + else { + g_assert(TOPOROUTER_IS_ARC(t1)); + arc1 = TOPOROUTER_ARC(t1); + v1 = TOPOROUTER_VERTEX(arc1->v1); + x0 = arc1->x1; + y0 = arc1->y1; + } + + if (TOPOROUTER_IS_VERTEX(t2)) { + v2 = TOPOROUTER_VERTEX(t2); + x1 = vx(v2); + y1 = vy(v2); + } + else { + g_assert(TOPOROUTER_IS_ARC(t2)); + arc2 = TOPOROUTER_ARC(t2); + v2 = TOPOROUTER_VERTEX(arc2->v2); + x1 = arc2->x0; + y1 = arc2->y0; + } + +#define TEST_AND_INSERT(z) if(d > EPSILON) arcs = g_list_prepend(arcs, new_rubberband_arc(v, z, arcr, d, arcwind, i)); +#define ARC_CHECKS(z) (!(arc1 && arc1->centre == z) && !(arc2 && arc2->centre == z) && \ + !(TOPOROUTER_IS_VERTEX(t1) && z == v1) && !(TOPOROUTER_IS_VERTEX(t2) && z == v2)) + + if (v1 == v2 || !i->next || TOPOROUTER_VERTEX(i->data) == v2) + return NULL; + +/*#ifdef DEBUG_RUBBERBAND*/ + if (debug) { + printf("\nRB: line %f,%f %f,%f v1 = %f,%f v2 = %f,%f \n ", x0, y0, x1, y1, vx(v1), vy(v1), vx(v2), vy(v2)); +/* if(v1->routingedge) print_edge(v1->routingedge); + if(v2->routingedge) print_edge(v2->routingedge);*/ + + } +/*#endif*/ + + /* check the vectices adjacent to the terminal vectices for push against the segment */ +/*if(TOPOROUTER_IS_VERTEX(t1)) { + toporouter_vertex_t *arcc = NULL; + d = check_adj_pushing_vertex(oproute, x0, y0, x1, y1, v1, &arcr, &arcwind, &arcc); + g_assert(arcc != v1); + if(ARC_CHECKS(arcc) && d > EPSILON) arcs = g_list_prepend(arcs, new_rubberband_arc(v1, arcc, arcr, d, arcwind, path->next)); + } + + if(TOPOROUTER_IS_VERTEX(t2)) { + toporouter_vertex_t *arcc = NULL; + d = check_adj_pushing_vertex(oproute, x0, y0, x1, y1, v2, &arcr, &arcwind, &arcc); + g_assert(arcc != v2); + if(ARC_CHECKS(arcc) && d > EPSILON) arcs = g_list_prepend(arcs, new_rubberband_arc(v2, arcc, arcr, d, arcwind, g_list_last(path)->prev)); + }*/ + + i = i->next; + while (i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); + + if (v == v2 || v == v1 || !v->routingedge) + break; + +#ifdef DEBUG_RUBBERBAND +/* if(debug) + printf("current v %f,%f - edge %f,%f %f,%f\n", vx(v), vy(v), + vx(tedge_v1(v->routingedge)), vy(tedge_v1(v->routingedge)), + vx(tedge_v2(v->routingedge)), vy(tedge_v2(v->routingedge)) + );*/ +#endif + g_assert(v->routingedge); + + v1wind = coord_wind(x0, y0, x1, y1, vx(tedge_v1(v->routingedge)), vy(tedge_v1(v->routingedge))); + v2wind = coord_wind(x0, y0, x1, y1, vx(tedge_v2(v->routingedge)), vy(tedge_v2(v->routingedge))); +/* if(debug) printf("\twinds: %d %d\n", v1wind, v2wind);*/ + if (!v1wind && !v2wind) { + i = i->next; + continue; + } + + + if (v1wind && v2wind && v1wind != v2wind) { /* edge is cutting through the current segment */ + + if (ARC_CHECKS(tedge_v1(v->routingedge))) { /* edge v1 is not the centre of an arc terminal */ + d = + check_intersect_vertex(x0, y0, x1, y1, v, tedge_v1(v->routingedge), tedge_v2(v->routingedge), v1wind, &arcwind, &arcr, + debug); + TEST_AND_INSERT(tedge_v1(v->routingedge)); + } + + if (ARC_CHECKS(tedge_v2(v->routingedge))) { /* edge v2 is not the centre of an arc terminal */ + d = + check_intersect_vertex(x0, y0, x1, y1, v, tedge_v2(v->routingedge), tedge_v1(v->routingedge), v2wind, &arcwind, &arcr, + debug); + TEST_AND_INSERT(tedge_v2(v->routingedge)); + } + } + else { /* edge is on one side of the segment */ + + if (ARC_CHECKS(tedge_v1(v->routingedge))) { /* edge v1 is not the centre of an arc terminal */ + d = + check_non_intersect_vertex(x0, y0, x1, y1, v, tedge_v1(v->routingedge), tedge_v2(v->routingedge), v1wind, &arcwind, + &arcr, debug); + TEST_AND_INSERT(tedge_v1(v->routingedge)); + } + + if (ARC_CHECKS(tedge_v2(v->routingedge))) { /* edge v2 is not the centre of an arc terminal */ + d = + check_non_intersect_vertex(x0, y0, x1, y1, v, tedge_v2(v->routingedge), tedge_v1(v->routingedge), v2wind, &arcwind, + &arcr, debug); + TEST_AND_INSERT(tedge_v2(v->routingedge)); + } + } + + i = i->next; + } + + arcs = g_list_sort(arcs, (GCompareFunc) compare_rubberband_arcs); +/*rubberband_insert_maxarc:*/ + if (!arcs) + return NULL; + max = TOPOROUTER_RUBBERBAND_ARC(arcs->data); + + av2 = max->pathv; + i = max->list->next; + while (i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); + if (v->routingedge && (tedge_v1(v->routingedge) == max->arcv || tedge_v2(v->routingedge) == max->arcv)) { + av2 = v; + i = i->next; + continue; + } + break; + } + + av1 = max->pathv; + i = max->list->prev; + while (i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); + if (v->routingedge && (tedge_v1(v->routingedge) == max->arcv || tedge_v2(v->routingedge) == max->arcv)) { + av1 = v; + i = i->prev; + continue; + } + break; + } +/*#ifdef DEBUG_RUBBERBAND*/ + if (debug) + printf("newarc @ %f,%f \t v1 = %f,%f v2 = %f,%f r = %f\n", vx(max->arcv), vy(max->arcv), vx(av1), vy(av1), vx(av2), vy(av2), + max->r); +/*#endif*/ + newarc = toporouter_arc_new(oproute, av1, av2, max->arcv, max->r, max->wind); + + if (TOPOROUTER_IS_VERTEX(t1)) + calculate_term_to_arc(TOPOROUTER_VERTEX(t1), newarc, 0); + else if (calculate_arc_to_arc(r, TOPOROUTER_ARC(t1), newarc)) { + printf("\tERROR: best: r = %f d = %f\n", max->r, max->d); + printf("\tOPROUTE: %s\n", oproute->netlist); + print_vertex(oproute->term1); + print_vertex(oproute->term2); + return NULL; + } + + if (TOPOROUTER_IS_VERTEX(t2)) + calculate_term_to_arc(TOPOROUTER_VERTEX(t2), newarc, 1); + else if (calculate_arc_to_arc(r, newarc, TOPOROUTER_ARC(t2))) { + printf("\tERROR: best: r = %f d = %f\n", max->r, max->d); + printf("\tOPROUTE: %s\n", oproute->netlist); + print_vertex(oproute->term1); + print_vertex(oproute->term2); + return NULL; + } + +/*if(check_arc_for_loops(t1, newarc, t2)) { + if(arc1 && arc2) calculate_arc_to_arc(r, arc1, arc2); + else if(arc1) calculate_term_to_arc(TOPOROUTER_VERTEX(t2), arc1, 1); + else if(arc2) calculate_term_to_arc(TOPOROUTER_VERTEX(t1), arc2, 0);*/ + +/*#ifdef DEBUG_RUBBERBAND + printf("REMOVING NEW ARC @ %f,%f\n", vx(newarc->centre), vy(newarc->centre)); + TODO: properly remove newarc + #endif*/ + +/* arcs = g_list_remove(arcs, max); + free(max); + goto rubberband_insert_maxarc; + }*/ + + + list1 = oproute_rubberband_segment(r, oproute, path, t1, newarc, debug); + list2 = oproute_rubberband_segment(r, oproute, i->next, newarc, t2, debug); + + if (list1) { + GList *list = g_list_last(list1); + toporouter_arc_t *testarc = TOPOROUTER_ARC(list->data); + toporouter_arc_t *parc = list->prev ? TOPOROUTER_ARC(list->prev->data) : arc1; + gdouble px = parc ? parc->x1 : vx(TOPOROUTER_VERTEX(t1)), py = parc ? parc->y1 : vy(TOPOROUTER_VERTEX(t1)); + + if (coord_intersect_prop(px, py, testarc->x0, testarc->y0, testarc->x1, testarc->y1, newarc->x0, newarc->y0)) { + list1 = g_list_remove(list1, testarc); + if (parc) + calculate_arc_to_arc(r, parc, newarc); + else + calculate_term_to_arc(TOPOROUTER_VERTEX(t1), newarc, 0); +/*#ifdef DEBUG_RUBBERBAND*/ + if (debug) + printf("REMOVING ARC @ %f,%f\n", vx(testarc->centre), vy(testarc->centre)); +/*#endif*/ + } + } + if (list2) { + toporouter_arc_t *testarc = TOPOROUTER_ARC(list2->data); + toporouter_arc_t *narc = list2->next ? TOPOROUTER_ARC(list2->next->data) : arc2; + gdouble nx = narc ? narc->x0 : vx(TOPOROUTER_VERTEX(t2)), ny = narc ? narc->y0 : vy(TOPOROUTER_VERTEX(t2)); + + if (coord_intersect_prop(newarc->x1, newarc->y1, testarc->x0, testarc->y0, testarc->x1, testarc->y1, nx, ny)) { + list2 = g_list_remove(list2, testarc); + if (narc) + calculate_arc_to_arc(r, newarc, narc); + else + calculate_term_to_arc(TOPOROUTER_VERTEX(t2), newarc, 1); + +/*#ifdef DEBUG_RUBBERBAND*/ + if (debug) + printf("REMOVING ARC @ %f,%f\n", vx(testarc->centre), vy(testarc->centre)); +/*#endif*/ + } + } + + g_list_foreach(arcs, free_list_elements, NULL); + g_list_free(arcs); + + return g_list_concat(list1, g_list_prepend(list2, newarc)); +} + +void oproute_check_all_loops(toporouter_t * r, toporouter_oproute_t * oproute) +{ + GList *i; + gpointer t1; + +loopcheck_restart: + t1 = oproute->term1; + i = oproute->arcs; + while (i) { + toporouter_arc_t *arc = TOPOROUTER_ARC(i->data); + gpointer t2 = i->next ? i->next->data : oproute->term2; + + if (check_arc_for_loops(t1, arc, t2)) { + + if (TOPOROUTER_IS_ARC(t1) && TOPOROUTER_IS_ARC(t2)) + calculate_arc_to_arc(r, TOPOROUTER_ARC(t1), TOPOROUTER_ARC(t2)); + else if (TOPOROUTER_IS_ARC(t1)) + calculate_term_to_arc(TOPOROUTER_VERTEX(t2), TOPOROUTER_ARC(t1), 1); + else if (TOPOROUTER_IS_ARC(t2)) + calculate_term_to_arc(TOPOROUTER_VERTEX(t1), TOPOROUTER_ARC(t2), 0); + + oproute->arcs = g_list_remove(oproute->arcs, arc); + goto loopcheck_restart; + } + + t1 = arc; + + i = i->next; + } + +} + +GtsTriangle *opposite_triangle(GtsTriangle * t, toporouter_edge_t * e) +{ + GSList *i = GTS_EDGE(e)->triangles; + + g_assert(e && t); + + while (i) { + if (GTS_TRIANGLE(i->data) != t) + return GTS_TRIANGLE(i->data); + i = i->next; + } + + return NULL; +} + + +void speccut_edge_routing_from_edge(GList * i, toporouter_edge_t * e) +{ + g_assert(TOPOROUTER_IS_EDGE(e)); + while (i) { + toporouter_vertex_t *curv = TOPOROUTER_VERTEX(i->data); + + if (!(curv->flags & VERTEX_FLAG_TEMP)) { + toporouter_vertex_t *newv = tvertex_intersect(curv, curv->parent, tedge_v1(e), tedge_v2(e)); + +/* printf("\nCURV:\n"); + print_vertex(curv); + + printf("CURV child:\n"); + if(curv->child) + print_vertex(curv->child); + else + printf("NULL\n"); + + printf("CURV parent:\n"); + if(curv->parent) + print_vertex(curv->parent); + else + printf("NULL\n");*/ + + if (newv) { + gint index; + newv->flags |= VERTEX_FLAG_ROUTE; + newv->flags |= VERTEX_FLAG_SPECCUT; + e->routing = g_list_insert_sorted_with_data(e->routing, newv, routing_edge_insert, e); + newv->route = curv->route; + newv->oproute = curv->oproute; + newv->routingedge = e; + GTS_POINT(newv)->z = vz(curv); + + newv->parent = curv->parent; + newv->child = curv; + +/* curv->parent = newv;*/ + + index = g_list_index(newv->route->path, curv); + + newv->route->path = g_list_insert(newv->route->path, newv, index); + + + if (newv->oproute) + newv->oproute->path = newv->route->path; + } + + if (!(curv->child->routingedge)) { + newv = tvertex_intersect(curv, curv->child, tedge_v1(e), tedge_v2(e)); + + if (newv) { + gint index; + newv->flags |= VERTEX_FLAG_ROUTE; + newv->flags |= VERTEX_FLAG_SPECCUT; + e->routing = g_list_insert_sorted_with_data(e->routing, newv, routing_edge_insert, e); + newv->route = curv->route; + newv->oproute = curv->oproute; + newv->routingedge = e; + GTS_POINT(newv)->z = vz(curv); + + newv->parent = curv; + newv->child = curv->child; + +/* curv->child = newv;*/ + + index = g_list_index(newv->route->path, curv); + + newv->route->path = g_list_insert(newv->route->path, newv, index + 1); + + + if (newv->oproute) + newv->oproute->path = newv->route->path; + } + + } + + } + i = i->next; + } + +} + +void speccut_edge_patch_links(toporouter_edge_t * e) +{ + GList *i = e->routing; + g_assert(TOPOROUTER_IS_EDGE(e)); + while (i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); + v->parent->child = v; + v->child->parent = v; + i = i->next; + } +} + +gint +check_speccut(toporouter_oproute_t * oproute, toporouter_vertex_t * v1, toporouter_vertex_t * v2, toporouter_edge_t * e, + toporouter_edge_t * e1, toporouter_edge_t * e2) +{ + GtsTriangle *t, *opt; + toporouter_vertex_t *opv, *opv2; + toporouter_edge_t *ope1, *ope2; + gdouble cap, flow, line_int_x, line_int_y; + + if (TOPOROUTER_IS_CONSTRAINT(e)) + return 0; + + if (!(t = gts_triangle_use_edges(GTS_EDGE(e), GTS_EDGE(e1), GTS_EDGE(e2)))) { + printf("check_speccut: NULL t\n"); + return 0; + } + + if (!(opt = opposite_triangle(t, e))) { +/* printf("check_speccut: NULL opt\n");*/ + return 0; + } + + if (!(opv = segment_common_vertex(GTS_SEGMENT(e1), GTS_SEGMENT(e2)))) { + printf("check_speccut: NULL opv\n"); + return 0; + } + + if (!(opv2 = TOPOROUTER_VERTEX(gts_triangle_vertex_opposite(opt, GTS_EDGE(e))))) { + printf("check_speccut: NULL opv2\n"); + return 0; + } + + /*TODO: shifting it out of the way would be better */ + if (e->routing) { + GList *i = e->routing; + while (i) { + toporouter_vertex_t *ev = TOPOROUTER_VERTEX(i->data); + if (!tvertex_wind(opv, ev, opv2)) + return 0; + i = i->next; + } + + } + + ope1 = tedge(opv2, tedge_v1(e)); + ope2 = tedge(opv2, tedge_v2(e)); + + /*this fixes the weird pad exits in r8c board + if(TOPOROUTER_IS_CONSTRAINT(ope1)) return 0; */ + if (TOPOROUTER_IS_CONSTRAINT(ope2)) + return 0; + + if (!tvertex_wind(opv2, tedge_v1(e), opv)) + return 0; + if (!tvertex_wind(opv2, tedge_v2(e), opv)) + return 0; + + if (!vertex_line_normal_intersection(vx(tedge_v1(e)), vy(tedge_v1(e)), + vx(tedge_v2(e)), vy(tedge_v2(e)), vx(opv2), vy(opv2), &line_int_x, &line_int_y)) + return 0; + + +/* return 0; + if(vertex_line_normal_intersection(tev1x(e), tev1y(e), tev2x(e), tev2y(e), vx(opv), vy(opv), &line_int_x, &line_int_y)) + return 0;*/ + + g_assert(opt && opv2); + + /* this is just temp, for the purposes of determining flow */ + if (tedge_v1(ope1) == opv2) { + if (TOPOROUTER_IS_CONSTRAINT(ope1)) + TOPOROUTER_CONSTRAINT(ope1)->routing = g_list_append(TOPOROUTER_CONSTRAINT(ope1)->routing, v1); + else + ope1->routing = g_list_append(ope1->routing, v1); + } + else { + if (TOPOROUTER_IS_CONSTRAINT(ope1)) + TOPOROUTER_CONSTRAINT(ope1)->routing = g_list_prepend(TOPOROUTER_CONSTRAINT(ope1)->routing, v1); + else + ope1->routing = g_list_prepend(ope1->routing, v1); + } + + cap = triangle_interior_capacity(opt, opv2); + flow = flow_from_edge_to_edge(opt, tedge(opv2, tedge_v1(e)), tedge(opv2, tedge_v2(e)), opv2, v1); + + /* temp v1 removed */ + if (TOPOROUTER_IS_CONSTRAINT(ope1)) + TOPOROUTER_CONSTRAINT(ope1)->routing = g_list_remove(TOPOROUTER_CONSTRAINT(ope1)->routing, v1); + else + ope1->routing = g_list_remove(ope1->routing, v1); + + if (flow >= cap) { + toporouter_edge_t *newe = + TOPOROUTER_EDGE(gts_edge_new(GTS_EDGE_CLASS(toporouter_edge_class()), GTS_VERTEX(opv), GTS_VERTEX(opv2))); + + speccut_edge_routing_from_edge(edge_routing(e1), newe); + speccut_edge_routing_from_edge(edge_routing(e2), newe); + speccut_edge_routing_from_edge(edge_routing(ope1), newe); + speccut_edge_routing_from_edge(edge_routing(ope2), newe); + + speccut_edge_patch_links(newe); +/* + printf("SPECCUT WITH v %f,%f for seg %f,%f %f,%f detected\n", vx(opv2), vy(opv2), + vx(v1), vy(v1), + vx(v2), vy(v2)); + printf("\tflow %f cap %f\n", flow, cap); + print_edge(newe); + */ + if (newe->routing) + return 1; + } + + + return 0; +} + + +gint oproute_path_speccut(toporouter_oproute_t * oproute) +{ + GList *i; + toporouter_vertex_t *pv; +path_speccut_restart: + i = oproute->path; + pv = NULL; + while (i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); + + + if (pv && (v->routingedge || pv->routingedge) && !(pv->flags & VERTEX_FLAG_SPECCUT) && !(v->flags & VERTEX_FLAG_SPECCUT)) { + + if (!v->routingedge) { + if (check_speccut + (oproute, pv, v, tedge(tedge_v1(pv->routingedge), v), pv->routingedge, tedge(tedge_v2(pv->routingedge), v))) + goto path_speccut_restart; + if (check_speccut + (oproute, pv, v, tedge(tedge_v2(pv->routingedge), v), pv->routingedge, tedge(tedge_v1(pv->routingedge), v))) + goto path_speccut_restart; + } + else if (!pv->routingedge) { + if (check_speccut + (oproute, v, pv, tedge(tedge_v1(v->routingedge), pv), v->routingedge, tedge(tedge_v2(v->routingedge), pv))) + goto path_speccut_restart; + if (check_speccut + (oproute, v, pv, tedge(tedge_v2(v->routingedge), pv), v->routingedge, tedge(tedge_v1(v->routingedge), pv))) + goto path_speccut_restart; + } + else { + toporouter_vertex_t *v1 = NULL, *v2 = NULL; + edges_third_edge(GTS_SEGMENT(v->routingedge), GTS_SEGMENT(pv->routingedge), &v1, &v2); + if (check_speccut(oproute, v, pv, tedge(v1, v2), v->routingedge, pv->routingedge)) + goto path_speccut_restart; + } + } + + + pv = v; + i = i->next; + } + + return 0; +} + +toporouter_oproute_t *oproute_rubberband(toporouter_t * r, GList * path) +{ + toporouter_oproute_t *oproute = (toporouter_oproute_t *) malloc(sizeof(toporouter_oproute_t)); + + g_assert(path); + + oproute->term1 = TOPOROUTER_VERTEX(path->data); + oproute->term2 = TOPOROUTER_VERTEX(g_list_last(path)->data); + oproute->arcs = NULL; + oproute->style = vertex_bbox(oproute->term1)->cluster->netlist->style; + oproute->netlist = vertex_bbox(oproute->term1)->cluster->netlist->netlist; + oproute->layergroup = vz(oproute->term1); + oproute->path = path; + oproute->serp = NULL; + + oproute->term1->parent = NULL; + oproute->term2->child = NULL; + + path_set_oproute(path, oproute); + +/* if(!strcmp(oproute->netlist, " unnamed_net1")) */ + oproute_path_speccut(oproute); + +#ifdef DEBUG_RUBBERBAND + if (!strcmp(oproute->netlist, " VCC3V3") && vx(oproute->term1) == 95700. && vy(oproute->term1) == 70800. && + vx(oproute->term2) == 196700. && vy(oproute->term2) == 67300.) { +/* printf("OPROUTE %s - %f,%f %f,%f\n", oproute->netlist, vx(oproute->term1), vy(oproute->term1), vx(oproute->term2), vy(oproute->term2)); + print_path(path);*/ + oproute->arcs = oproute_rubberband_segment(r, oproute, path, oproute->term1, oproute->term2, 1); + } + else +#endif + oproute->arcs = oproute_rubberband_segment(r, oproute, path, oproute->term1, oproute->term2, 0); + + oproute_check_all_loops(r, oproute); + return oproute; + +} + +void toporouter_export(toporouter_t * r) +{ + GList *i = r->routednets; + GList *oproutes = NULL; + + while (i) { + toporouter_route_t *routedata = TOPOROUTER_ROUTE(i->data); + toporouter_oproute_t *oproute = oproute_rubberband(r, routedata->path); + oproutes = g_list_prepend(oproutes, oproute); + i = i->next; + } + + i = oproutes; + while (i) { + toporouter_oproute_t *oproute = (toporouter_oproute_t *) i->data; + export_oproutes(r, oproute); + oproute_free(oproute); + i = i->next; + } + + pcb_message(PCB_MSG_INFO, _("Reticulating splines... successful\n\n")); + pcb_message(PCB_MSG_INFO, _("Wiring cost: %f inches\n"), r->wiring_score / 1000.); + printf("Wiring cost: %f inches\n", r->wiring_score / 1000.); + + g_list_free(oproutes); + +} + +toporouter_route_t *routedata_create(void) +{ + toporouter_route_t *routedata = (toporouter_route_t *) malloc(sizeof(toporouter_route_t)); + routedata->netlist = NULL; + routedata->alltemppoints = NULL; + routedata->path = NULL; + routedata->curpoint = NULL; + routedata->pscore = routedata->score = 0.; + routedata->flags = 0; + routedata->src = routedata->dest = NULL; + routedata->psrc = routedata->pdest = NULL; + routedata->ppath = routedata->topopath = NULL; + + routedata->ppathindices = NULL; + + routedata->destvertices = routedata->srcvertices = NULL; + return routedata; +} + +/* +void +print_routedata(toporouter_route_t *routedata) +{ + GList *srcvertices = cluster_vertices(routedata->src); + GList *destvertices = cluster_vertices(routedata->dest); + + printf("ROUTEDATA:\n"); + printf("SRCVERTICES:\n"); + print_vertices(srcvertices); + printf("DESTVERTICES:\n"); + print_vertices(destvertices); + + g_list_free(srcvertices); + g_list_free(destvertices); +}*/ + +toporouter_route_t *import_route(toporouter_t * r, pcb_rat_t * line) +{ + toporouter_route_t *routedata = routedata_create(); + + routedata->src = cluster_find(r, line->Point1.X, line->Point1.Y, line->group1); + routedata->dest = cluster_find(r, line->Point2.X, line->Point2.Y, line->group2); + + if (!routedata->src) + printf("couldn't locate src\n"); + if (!routedata->dest) + printf("couldn't locate dest\n"); + + if (!routedata->src || !routedata->dest) { + pcb_printf("PROBLEM: couldn't locate rat src or dest for rat %#mD, %d -> %#mD, %d\n", + line->Point1.X, line->Point1.Y, line->group1, line->Point2.X, line->Point2.Y, line->group2); + free(routedata); + return NULL; + } + + routedata->netlist = routedata->src->netlist; + + g_assert(routedata->src->netlist == routedata->dest->netlist); + + g_ptr_array_add(r->routes, routedata); + g_ptr_array_add(routedata->netlist->routes, routedata); + + r->failednets = g_list_prepend(r->failednets, routedata); + + return routedata; +} + +void delete_route(toporouter_route_t * routedata, guint destroy) +{ + GList *i = routedata->path; + toporouter_vertex_t *pv = NULL; + + while (i) { + toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data); + + g_assert(tv); + + if (tv && pv && !(tv->flags & VERTEX_FLAG_ROUTE) && !(pv->flags & VERTEX_FLAG_ROUTE)) { + toporouter_edge_t *e = TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(tv), GTS_VERTEX(pv))); + + if (e && (e->flags & EDGE_FLAG_DIRECTCONNECTION)) { + e->flags ^= EDGE_FLAG_DIRECTCONNECTION; + } + } + pv = tv; + i = i->next; + } + + i = routedata->path; + while (i) { + toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data); + + tv->parent = NULL; + tv->child = NULL; + + if (tv->routingedge) { + if (TOPOROUTER_IS_CONSTRAINT(tv->routingedge)) + TOPOROUTER_CONSTRAINT(tv->routingedge)->routing = g_list_remove(TOPOROUTER_CONSTRAINT(tv->routingedge)->routing, tv); + else + tv->routingedge->routing = g_list_remove(tv->routingedge->routing, tv); + if (destroy) + gts_object_destroy(GTS_OBJECT(tv)); + } + + i = i->next; + } + + if (routedata->path) + g_list_free(routedata->path); + routedata->path = NULL; + routedata->curpoint = NULL; + routedata->score = INFINITY; + routedata->alltemppoints = NULL; +} + +/* remove route can be later reapplied */ +void remove_route(GList * path) +{ + GList *i = path; + + while (i) { + toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data); + + tv->parent = NULL; + tv->child = NULL; + +/* if(tv->flags & VERTEX_FLAG_ROUTE) g_assert(tv->route == routedata);*/ + + if (tv->routingedge) { + + if (TOPOROUTER_IS_CONSTRAINT(tv->routingedge)) + TOPOROUTER_CONSTRAINT(tv->routingedge)->routing = g_list_remove(TOPOROUTER_CONSTRAINT(tv->routingedge)->routing, tv); + else + tv->routingedge->routing = g_list_remove(tv->routingedge->routing, tv); + } + i = i->next; + } + +} + +gint apply_route(GList * path, toporouter_route_t * routedata) +{ + GList *i = path; + toporouter_vertex_t *pv = NULL; + gint count = 0; + + if (!path) + return 0; +/* g_assert(path);*/ + + while (i) { + toporouter_vertex_t *tv = TOPOROUTER_VERTEX(i->data); + + if (tv->routingedge) { + if (TOPOROUTER_IS_CONSTRAINT(tv->routingedge)) + TOPOROUTER_CONSTRAINT(tv->routingedge)->routing = + g_list_insert_sorted_with_data(TOPOROUTER_CONSTRAINT(tv->routingedge)->routing, tv, routing_edge_insert, + tv->routingedge); + else + tv->routingedge->routing = g_list_insert_sorted_with_data(tv->routingedge->routing, + tv, routing_edge_insert, tv->routingedge); + + count++; + } + + if (pv) { + pv->child = tv; + tv->parent = pv; + } + + if (tv->flags & VERTEX_FLAG_ROUTE) + g_assert(tv->route == routedata); + + pv = tv; + i = i->next; + } + + TOPOROUTER_VERTEX(path->data)->parent = NULL; + pv->child = NULL; + + return count; +} + + +gint compare_routedata_ascending(gconstpointer a, gconstpointer b) +{ + toporouter_route_t *ra = (toporouter_route_t *) a; + toporouter_route_t *rb = (toporouter_route_t *) b; + return ra->score - rb->score; +} + +void print_costmatrix(gdouble * m, guint n) +{ + guint i; + printf("COST MATRIX:\n"); + for (i = 0; i < n; i++) { + guint j; + for (j = 0; j < n; j++) { + printf("%f ", m[(i * n) + j]); + } + printf("\n"); + } +} + + +static inline void init_cost_matrix(gdouble * m, guint n) +{ + guint i; + for (i = 0; i < n; i++) { + guint j; + for (j = 0; j < n; j++) { + m[(i * n) + j] = INFINITY; + } + } +} + + +toporouter_netscore_t *netscore_create(toporouter_t * r, toporouter_route_t * routedata, guint n, guint id) +{ + toporouter_netscore_t *netscore = (toporouter_netscore_t *) malloc(sizeof(toporouter_netscore_t)); + GList *path = route(r, routedata, 0); + guint i; + + netscore->id = id; + + netscore->routedata = routedata; + routedata->detourscore = netscore->score = routedata->score; + + if (!finite(routedata->detourscore)) { + printf("WARNING: !finite(detourscore)\n"); + print_cluster(routedata->src); + print_cluster(routedata->dest); + return NULL; + } + + netscore->pairwise_nodetour = (guint *) malloc(n * sizeof(guint)); + + for (i = 0; i < n; i++) { + netscore->pairwise_nodetour[i] = 0; + } + + netscore->pairwise_detour_sum = 0.; + netscore->pairwise_fails = 0; + + netscore->r = r; + + if (path) { + routedata->topopath = g_list_copy(routedata->path); + delete_route(routedata, 0); + } + + return netscore; +} + +static inline void netscore_destroy(toporouter_netscore_t * netscore) +{ + free(netscore->pairwise_nodetour); + free(netscore); +} + +void print_netscores(GPtrArray * netscores) +{ + toporouter_netscore_t **i; + printf("NETSCORES: \n\n"); + printf(" %15s %15s %15s\n----------------------------------------------------\n", "Score", "Detour Sum", + "Pairwise Fails"); + + for (i = (toporouter_netscore_t **) netscores->pdata; i < (toporouter_netscore_t **) netscores->pdata + netscores->len; i++) { +#ifdef DEBUG_NETSCORES + printf("%4d %15f %15f %15d %15x\n", (*i)->id, (*i)->score, (*i)->pairwise_detour_sum, (*i)->pairwise_fails, (guint) * i); +#endif + } + + printf("\n"); +} + +void netscore_pairwise_calculation(toporouter_netscore_t * netscore, GPtrArray * netscores) +{ + toporouter_netscore_t **i; + toporouter_netscore_t **netscores_base = (toporouter_netscore_t **) (netscores->pdata); + toporouter_route_t *temproutedata = routedata_create(); + + /*route(netscore->r, netscore->routedata, 0); */ + apply_route(netscore->routedata->topopath, netscore->routedata); + + for (i = netscores_base; i < netscores_base + netscores->len; i++) { + + if (!netscore->pairwise_nodetour[i - netscores_base] && *i != netscore + && (*i)->routedata->netlist != netscore->routedata->netlist) { + + temproutedata->src = (*i)->routedata->src; + temproutedata->dest = (*i)->routedata->dest; + + route(netscore->r, temproutedata, 0); + + if (temproutedata->score == (*i)->score) { + netscore->pairwise_nodetour[i - netscores_base] = 1; + (*i)->pairwise_nodetour[netscore->id] = 1; + } + else if (!finite(temproutedata->score)) { + netscore->pairwise_fails += 1; + } + else { + netscore->pairwise_detour_sum += temproutedata->score - (*i)->score; + } + + delete_route(temproutedata, 1); + } + + } + +/* delete_route(netscore->routedata, 1);*/ + remove_route(netscore->routedata->topopath); + + free(temproutedata); +} + +gint netscore_pairwise_size_compare(toporouter_netscore_t ** a, toporouter_netscore_t ** b) +{ + /* infinite scores are last */ + if (!finite((*a)->score) && !finite((*b)->score)) + return 0; + if (finite((*a)->score) && !finite((*b)->score)) + return -1; + if (finite((*b)->score) && !finite((*a)->score)) + return 1; + + /* order by pairwise fails */ + if ((*a)->pairwise_fails < (*b)->pairwise_fails) + return -1; + if ((*b)->pairwise_fails < (*a)->pairwise_fails) + return 1; + + /* order by pairwise detour */ + if ((*a)->pairwise_detour_sum < (*b)->pairwise_detour_sum) + return -1; + if ((*b)->pairwise_detour_sum < (*a)->pairwise_detour_sum) + return 1; + + /* order by score */ + if ((*a)->score < (*b)->score) + return -1; + if ((*b)->score < (*a)->score) + return 1; + + return 0; +} + +gint netscore_pairwise_compare(toporouter_netscore_t ** a, toporouter_netscore_t ** b) +{ + /* infinite scores are last */ + if (!finite((*a)->score) && !finite((*b)->score)) + return 0; + if (finite((*a)->score) && !finite((*b)->score)) + return -1; + if (finite((*b)->score) && !finite((*a)->score)) + return 1; + + /* order by pairwise fails */ + if ((*a)->pairwise_fails < (*b)->pairwise_fails) + return -1; + if ((*b)->pairwise_fails < (*a)->pairwise_fails) + return 1; + + /* order by pairwise detour */ + if ((*a)->pairwise_detour_sum < (*b)->pairwise_detour_sum) + return -1; + if ((*b)->pairwise_detour_sum < (*a)->pairwise_detour_sum) + return 1; + + return 0; +} + +guint order_nets_preroute_greedy(toporouter_t * r, GList * nets, GList ** rnets) +{ + gint len = g_list_length(nets); + GPtrArray *netscores = g_ptr_array_sized_new(len); + guint failcount = 0; + + while (nets) { + toporouter_netscore_t *ns = netscore_create(r, TOPOROUTER_ROUTE(nets->data), len, failcount++); + if (ns) + g_ptr_array_add(netscores, ns); + nets = nets->next; + } + + failcount = 0; + + g_ptr_array_foreach(netscores, (GFunc) netscore_pairwise_calculation, netscores); + + g_ptr_array_sort(netscores, (GCompareFunc) r->netsort); + +#ifdef DEBUG_ORDERING + print_netscores(netscores); +#endif + + *rnets = NULL; + FOREACH_NETSCORE(netscores) { + *rnets = g_list_prepend(*rnets, netscore->routedata); + if (!finite(netscore->score)) + failcount++; + netscore_destroy(netscore); + } + FOREACH_END; + + g_ptr_array_free(netscores, TRUE); + + return failcount; +} + +toporouter_vertex_t *edge_closest_vertex(toporouter_edge_t * e, toporouter_vertex_t * v) +{ + GList *i = v->routingedge ? edge_routing(v->routingedge) : NULL; + gdouble closestd = 0.; + toporouter_vertex_t *closestv = NULL; + + while (i) { + toporouter_vertex_t *ev = TOPOROUTER_VERTEX(i->data); + gdouble tempd = gts_point_distance2(GTS_POINT(ev), GTS_POINT(v)); + + if (!closestv || (tempd < closestd)) { + closestd = tempd; + closestv = ev; + } + + i = i->next; + } + + return closestv; +} + +void snapshot(toporouter_t * r, char *name, GList * datas) +{ + { + int i; + for (i = 0; i < groupcount(); i++) { + char buffer[256]; + sprintf(buffer, "route-%s-%d.png", name, i); + toporouter_draw_surface(r, r->layers[i].surface, buffer, 2048, 2048, 2, datas, i, NULL); + } + } +} + +/* +gdouble +route_conflict(toporouter_t *r, toporouter_route_t *route, guint *n) +{ + GList *i = route->path; + toporouter_vertex_t *pv = NULL; + gdouble cost = 0.; + + while(i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); + if(pv && vz(v) == vz(pv)) + cost += vertices_routing_conflict_cost(r, v, pv, n); + pv = v; + i = i->next; + } + + return cost; +} +*/ +GList *route_conflicts(toporouter_route_t * route) +{ + GList *conflicts = NULL, *i = route->path; + toporouter_vertex_t *pv = NULL; + + while (i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); + + if (pv && vz(pv) == vz(v)) { + GList *temp = vertices_routing_conflicts(pv, v), *j; + + j = temp; + while (j) { + toporouter_route_t *conroute = TOPOROUTER_ROUTE(j->data); + if (!g_list_find(conflicts, conroute)) + conflicts = g_list_prepend(conflicts, conroute); + j = j->next; + } + + if (temp) + g_list_free(temp); + } + + pv = v; + i = i->next; + } + return conflicts; +} + +gint spread_edge(gpointer item, gpointer data) +{ + toporouter_edge_t *e = TOPOROUTER_EDGE(item); + toporouter_vertex_t *v; + gdouble spacing, s; + GList *i; + + if (TOPOROUTER_IS_CONSTRAINT(e)) + return 0; + + i = edge_routing(e); + + if (!g_list_length(i)) + return 0; + + if (g_list_length(i) == 1) { + v = TOPOROUTER_VERTEX(i->data); + GTS_POINT(v)->x = (vx(edge_v1(e)) + vx(edge_v2(e))) / 2.; + GTS_POINT(v)->y = (vy(edge_v1(e)) + vy(edge_v2(e))) / 2.; + return 0; + } + + s = spacing = (gts_point_distance(GTS_POINT(edge_v1(e)), GTS_POINT(edge_v2(e)))) / (g_list_length(i) + 1); + + while (i) { + v = TOPOROUTER_VERTEX(i->data); + vertex_move_towards_vertex_values(edge_v1(e), edge_v2(e), s, &(GTS_POINT(v)->x), &(GTS_POINT(v)->y)); + + s += spacing; + i = i->next; + } + + return 0; +} + +void route_checkpoint(toporouter_route_t * route, toporouter_route_t * temproute) +{ + GList *i = g_list_last(route->path); + gint n = g_list_length(route->path); + + if (route->ppathindices) + free(route->ppathindices); + route->ppathindices = (gint *) malloc(sizeof(gint) * n); + +/* n = 0;*/ + while (i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); + n--; + + if (v->routingedge) { + GList *j = g_list_find(edge_routing(v->routingedge), v)->prev; + gint tempindex = g_list_index(edge_routing(v->routingedge), v); + + while (j) { + if (TOPOROUTER_VERTEX(j->data)->route == temproute) + tempindex--; + j = j->prev; + } + + route->ppathindices[n] = tempindex; + + if (TOPOROUTER_IS_CONSTRAINT(v->routingedge)) + TOPOROUTER_CONSTRAINT(v->routingedge)->routing = g_list_remove(TOPOROUTER_CONSTRAINT(v->routingedge)->routing, v); + else + v->routingedge->routing = g_list_remove(v->routingedge->routing, v); + } + + i = i->prev; + } + + route->pscore = route->score; + route->ppath = route->path; + remove_route(route->path); + route->path = NULL; + route->psrc = route->src; + route->pdest = route->dest; +/*route->src->pc = route->src->c; + route->dest->pc = route->dest->c;*/ +} + +void route_restore(toporouter_route_t * route) +{ + GList *i; + toporouter_vertex_t *pv = NULL; + gint n = 0; + + g_assert(route->ppath); + g_assert(route->ppathindices); + + route->path = route->ppath; + i = route->ppath; + while (i) { + toporouter_vertex_t *v = TOPOROUTER_VERTEX(i->data); + + if (v->routingedge) { + if (TOPOROUTER_IS_CONSTRAINT(v->routingedge)) + TOPOROUTER_CONSTRAINT(v->routingedge)->routing = + g_list_insert(TOPOROUTER_CONSTRAINT(v->routingedge)->routing, v, route->ppathindices[n]); + else + v->routingedge->routing = g_list_insert(v->routingedge->routing, v, route->ppathindices[n]); + + /* space_edge(v->routingedge, NULL); */ + } + + if (pv) { + pv->child = v; + v->parent = pv; + } + + n++; + pv = v; + i = i->next; + } + + route->score = route->pscore; + route->src = route->psrc; + route->dest = route->pdest; +/*route->src->c = route->src->pc; + route->dest->c = route->dest->pc;*/ + +} + +void cluster_merge(toporouter_route_t * routedata) +{ + gint oldc = routedata->dest->c, newc = routedata->src->c; + + FOREACH_CLUSTER(routedata->netlist->clusters) { + if (cluster->c == oldc) + cluster->c = newc; + } + FOREACH_END; + +} + +void netlist_recalculate(toporouter_netlist_t * netlist, GList * ignore) +{ + GList *i = g_list_last(netlist->routed); + gint n = netlist->clusters->len - 1; + + FOREACH_CLUSTER(netlist->clusters) { + cluster->c = n--; + } FOREACH_END; + + while (i) { + if (!ignore || !g_list_find(ignore, i->data)) + cluster_merge(TOPOROUTER_ROUTE(i->data)); + i = i->prev; + } + +} + +void netlists_recalculate(GList * netlists, GList * ignore) +{ + GList *i = netlists; + while (i) { + netlist_recalculate(TOPOROUTER_NETLIST(i->data), ignore); + i = i->next; + } +} + +void netlists_rollback(GList * netlists) +{ +/* netlists_recalculate(netlists, NULL);*/ + while (netlists) { + toporouter_netlist_t *netlist = TOPOROUTER_NETLIST(netlists->data); + + FOREACH_CLUSTER(netlist->clusters) { + cluster->c = cluster->pc; + } + FOREACH_END; + + netlists = netlists->next; + } +} + +void print_netlist(toporouter_netlist_t * netlist) +{ + + printf("NETLIST %s: ", netlist->netlist); + + FOREACH_CLUSTER(netlist->clusters) { + printf("%d ", cluster->c); + + } FOREACH_END; + printf("\n"); +} + +#define REMOVE_ROUTING(x) x->netlist->routed = g_list_remove(x->netlist->routed, x); \ + r->routednets = g_list_remove(r->routednets, x); \ + r->failednets = g_list_prepend(r->failednets, x) + +#define INSERT_ROUTING(x) x->netlist->routed = g_list_prepend(x->netlist->routed, x); \ + r->routednets = g_list_prepend(r->routednets, x); \ + r->failednets = g_list_remove(r->failednets, x) + +gint roar_route(toporouter_t * r, toporouter_route_t * routedata, gint threshold) +{ + gint intfails = 0; + GList *netlists = NULL, *routed = NULL; + + g_assert(!routedata->path); + + if (routedata->src->c == routedata->dest->c) { + printf("ERROR: attempt to route already complete route\n"); + g_assert(routedata->src->c != routedata->dest->c); + } + + routedata->src->pc = routedata->src->c; + routedata->dest->pc = routedata->dest->c; + routedata->psrc = routedata->src; + routedata->pdest = routedata->dest; + + r->flags |= TOPOROUTER_FLAG_LEASTINVALID; + if (route(r, routedata, 0)) { + GList *conflicts, *j; + + INSERT_ROUTING(routedata); + + conflicts = route_conflicts(routedata); + cluster_merge(routedata); + + r->flags &= ~TOPOROUTER_FLAG_LEASTINVALID; + + j = conflicts; + while (j) { + toporouter_route_t *conflict = TOPOROUTER_ROUTE(j->data); + if (!g_list_find(netlists, conflict->netlist)) + netlists = g_list_prepend(netlists, conflict->netlist); + + route_checkpoint(conflict, routedata); + + REMOVE_ROUTING(conflict); + j = j->next; + } + + netlists = g_list_prepend(netlists, routedata->netlist); + netlists_recalculate(netlists, NULL); + + j = conflicts; + while (j) { + toporouter_route_t *conflict = TOPOROUTER_ROUTE(j->data); + g_assert(conflict->src->c != conflict->dest->c); + if (route(r, conflict, 0)) { + cluster_merge(conflict); + + routed = g_list_prepend(routed, conflict); + + INSERT_ROUTING(conflict); + + netlist_recalculate(conflict->netlist, NULL); + + } + else { + if (++intfails >= threshold) { + GList *i = routed; + while (i) { + toporouter_route_t *intconflict = TOPOROUTER_ROUTE(i->data); + REMOVE_ROUTING(intconflict); + delete_route(intconflict, 1); + i = i->next; + } + delete_route(routedata, 1); + i = g_list_last(conflicts); + while (i) { + toporouter_route_t *intconflict = TOPOROUTER_ROUTE(i->data); + + route_restore(intconflict); + INSERT_ROUTING(intconflict); + + i = i->prev; + } + REMOVE_ROUTING(routedata); + intfails = 0; + netlists_recalculate(netlists, NULL); + goto roar_route_end; + } + + } + j = j->next; + } + + + netlists_recalculate(netlists, NULL); + + intfails--; + roar_route_end: + g_list_free(conflicts); + g_list_free(netlists); + + } + else { + r->flags &= ~TOPOROUTER_FLAG_LEASTINVALID; + } + + g_list_free(routed); + return intfails; +} + +gint roar_router(toporouter_t * r, gint failcount, gint threshold) +{ + guint j; + gint pfailcount = failcount + 1; + + pcb_message(PCB_MSG_INFO, _("ROAR router: ")); + for (j = 0; j < 6; j++) { + GList *failed = g_list_copy(r->failednets), *k = failed; + + k = failed; + while (k) { + failcount += roar_route(r, TOPOROUTER_ROUTE(k->data), threshold); + k = k->next; + } + g_list_free(failed); + + printf("\tROAR pass %d - %d routed - %d failed\n", j, g_list_length(r->routednets), g_list_length(r->failednets)); + + if (!failcount || failcount >= pfailcount) { + pcb_message(PCB_MSG_INFO, _("%d nets remaining\n"), failcount); + break; + } + pcb_message(PCB_MSG_INFO, _("%d -> "), failcount); + pfailcount = failcount; + } + + return failcount; +} + +gint route_detour_compare(toporouter_route_t ** a, toporouter_route_t ** b) +{ + return ((*b)->score - (*b)->detourscore) - ((*a)->score - (*a)->detourscore); +} + + + +void roar_detour_route(toporouter_t * r, toporouter_route_t * data) +{ + gdouble pscore = data->score, nscore = 0.; + GList *netlists = NULL; + + route_checkpoint(data, NULL); + + REMOVE_ROUTING(data); + + netlists = g_list_prepend(NULL, data->netlist); + netlists_recalculate(netlists, NULL); + + r->flags |= TOPOROUTER_FLAG_LEASTINVALID; + if (route(r, data, 0)) { + GList *conflicts, *j; + + nscore = data->score; + conflicts = route_conflicts(data); + + INSERT_ROUTING(data); + + r->flags &= ~TOPOROUTER_FLAG_LEASTINVALID; + + j = conflicts; + while (j) { + toporouter_route_t *conflict = TOPOROUTER_ROUTE(j->data); + + if (!g_list_find(netlists, conflict->netlist)) + netlists = g_list_prepend(netlists, conflict->netlist); + pscore += conflict->score; + + route_checkpoint(conflict, NULL); + REMOVE_ROUTING(conflict); + + j = j->next; + } + netlists_recalculate(netlists, NULL); + + j = conflicts; + while (j) { + toporouter_route_t *conflict = TOPOROUTER_ROUTE(j->data); + + if (route(r, conflict, 0)) { + cluster_merge(conflict); + INSERT_ROUTING(conflict); + nscore += conflict->score; + } + else { + j = j->prev; + goto roar_detour_route_rollback_int; + } + j = j->next; + } + + if (nscore > pscore) { + j = g_list_last(conflicts); + roar_detour_route_rollback_int: + REMOVE_ROUTING(data); + + while (j) { + toporouter_route_t *conflict = TOPOROUTER_ROUTE(j->data); + REMOVE_ROUTING(conflict); + delete_route(conflict, 1); + j = j->prev; + } + + j = g_list_last(conflicts); + while (j) { + toporouter_route_t *conflict = TOPOROUTER_ROUTE(j->data); + route_restore(conflict); + INSERT_ROUTING(conflict); + j = j->prev; + } + delete_route(data, 1); + + goto roar_detour_route_rollback_exit; + + } + + g_list_free(conflicts); + } + else { + r->flags &= ~TOPOROUTER_FLAG_LEASTINVALID; + roar_detour_route_rollback_exit: + route_restore(data); + INSERT_ROUTING(data); + } + netlists_recalculate(netlists, NULL); + + g_list_free(netlists); +} + +void detour_router(toporouter_t * r) +{ + GList *i = r->routednets; + guint n = g_list_length(r->routednets); + GPtrArray *scores = g_ptr_array_sized_new(n); + + while (i) { + toporouter_route_t *curroute = TOPOROUTER_ROUTE(i->data); + curroute->score = path_score(r, curroute->path); + g_ptr_array_add(scores, i->data); + i = i->next; + } + + g_ptr_array_sort(scores, (GCompareFunc) route_detour_compare); + + r->flags |= TOPOROUTER_FLAG_DETOUR; + + { + toporouter_route_t **i; + for (i = (toporouter_route_t **) scores->pdata; i < (toporouter_route_t **) scores->pdata + scores->len; i++) { + toporouter_route_t *curroute = (*i); + + if (finite(curroute->score) && finite(curroute->detourscore)) { +/* printf("%15s %15f \t %8f,%8f - %8f,%8f\n", (*i)->src->netlist + 2, (*i)->score - (*i)->detourscore, + vx(curroute->mergebox1->point), vy(curroute->mergebox1->point), + vx(curroute->mergebox2->point), vy(curroute->mergebox2->point));*/ + + if (curroute->score - curroute->detourscore > 1000.) { + roar_detour_route(r, curroute); + } + else + break; + + } + } + } + printf("\n"); + + r->flags ^= TOPOROUTER_FLAG_DETOUR; + + g_ptr_array_free(scores, TRUE); + +} + +gint rubix_router(toporouter_t * r, gint failcount) +{ + GList *i, *ordering; + order_nets_preroute_greedy(r, r->failednets, &ordering); + + i = ordering; + while (i) { + toporouter_route_t *data = TOPOROUTER_ROUTE(i->data); + + if (route(r, data, 0)) { + INSERT_ROUTING(data); + cluster_merge(data); + failcount--; + } + + i = i->next; + } + + g_list_free(ordering); + + return failcount; +} + +guint hybrid_router(toporouter_t * r) +{ + guint i; + gint failcount = g_list_length(r->failednets); + r->flags |= TOPOROUTER_FLAG_AFTERORDER; + r->flags |= TOPOROUTER_FLAG_AFTERRUBIX; + failcount = rubix_router(r, failcount); + + pcb_message(PCB_MSG_INFO, _("RUBIX router: %d nets remaining\n"), failcount); + printf("RUBIX router: %d nets remaining\n", failcount); + + r->flags |= TOPOROUTER_FLAG_GOFAR; + + for (i = 0; i < 6 && failcount; i++) { + if (i % 2 == 1) { + failcount = roar_router(r, failcount, 5); + /* printf("THRESH 5\n"); */ + } + else { + failcount = roar_router(r, failcount, 2); + /* printf("THRESH 2\n"); */ + } + + detour_router(r); + } + + failcount = roar_router(r, failcount, 2); + detour_router(r); + + return failcount; +} + +void parse_arguments(toporouter_t * r, int argc, char **argv) +{ + int i, tempint; + guint group; + + for (i = 0; i < argc; i++) { + if (sscanf(argv[i], "viacost=%d", &tempint)) { + r->viacost = (double) tempint; + } + else if (sscanf(argv[i], "l%d", &tempint)) { + gdouble *layer = (gdouble *) malloc(sizeof(gdouble)); + *layer = (double) tempint; + r->keepoutlayers = g_list_prepend(r->keepoutlayers, layer); + } + } + + for (group = 0; group < pcb_max_group; group++) + for (i = 0; i < PCB->LayerGroups.Number[group]; i++) + pcb_layer_id_t lid = PCB->LayerGroups.Entries[group][i]; + flg = pcb_layer_flag(lid); + if ((lid & PCB_LYT_COPPER) && !(PCB->Data->Layer[lid].On)) { + gdouble *layer = (gdouble *) malloc(sizeof(gdouble)); + *layer = (double) group; + r->keepoutlayers = g_list_prepend(r->keepoutlayers, layer); + } + +} + +toporouter_t *toporouter_new(void) +{ + toporouter_t *r = (toporouter_t *) calloc(1, sizeof(toporouter_t)); + time_t ltime; + + gettimeofday(&r->starttime, NULL); + + r->netsort = netscore_pairwise_compare; + + r->destboxes = NULL; + r->consumeddestboxes = NULL; + + r->paths = NULL; + + r->layers = NULL; + r->flags = 0; + r->viamax = 3; + r->viacost = 10000.; + r->stublength = 300.; + r->serpintine_half_amplitude = 1500.; + + r->wiring_score = 0.; + + r->bboxes = NULL; + r->bboxtree = NULL; + + r->netlists = g_ptr_array_new(); + r->routes = g_ptr_array_new(); + + r->keepoutlayers = NULL; + + r->routednets = NULL; + r->failednets = NULL; + + ltime = time(NULL); + + gts_predicates_init(); + + pcb_message(PCB_MSG_INFO, _("Topological Autorouter\n")); + pcb_message(PCB_MSG_INFO, _("Started %s"), asctime(localtime(<ime))); + pcb_message(PCB_MSG_INFO, _("-------------------------------------\n")); + pcb_message(PCB_MSG_INFO, _("Copyright 2009 Anthony Blake (tonyb33@gmail.com)\n\n")); + return r; +} + +void acquire_twonets(toporouter_t * r) +{ + PCB_RAT_LOOP(PCB->Data); + if (PCB_FLAG_TEST(PCB_FLAG_SELECTED, line)) + import_route(r, line); + PCB_END_LOOP; + + if (!r->routes->len) { + PCB_RAT_LOOP(PCB->Data); + import_route(r, line); + PCB_END_LOOP; + } +} + +toporouter_netlist_t *find_netlist_by_name(toporouter_t * r, char *name) +{ + FOREACH_NETLIST(r->netlists) { + if (!strcmp(netlist->netlist, name)) + return netlist; + } + FOREACH_END; + return NULL; +} + +gint toporouter_set_pair(toporouter_t * r, toporouter_netlist_t * n1, toporouter_netlist_t * n2) +{ + if (!n1 || !n2) + return 0; + n1->pair = n2; + n2->pair = n1; + return 1; +} + +static int toporouter(int argc, char **argv, pcb_coord_t x, pcb_coord_t y) +{ + toporouter_t *r = toporouter_new(); + parse_arguments(r, argc, argv); + import_geometry(r); + acquire_twonets(r); + +/*if(!toporouter_set_pair(r, find_netlist_by_name(r, " DRAM_DQS_N"), find_netlist_by_name(r, " DRAM_DQS"))) { + printf("Couldn't associate pair\n"); + }*/ + + hybrid_router(r); +/* + for(gint i=0;ilayers[i].surface, space_edge, NULL); + } + { + int i; + for(i=0;ilayers[i].surface, buffer, 1024, 1024, 2, NULL, i, NULL); + } + } +*/ + toporouter_export(r); + toporouter_free(r); + + pcb_undo_save_serial(); + pcb_rats_destroy(pcb_false); + pcb_undo_restore_serial(); + pcb_rat_add_all(pcb_false, NULL); + pcb_undo_restore_serial(); + pcb_undo_inc_serial(); + pcb_redraw(); + + return 0; +} + +static int escape(int argc, char **argv, pcb_coord_t x, pcb_coord_t y) +{ + guint dir, viax, viay; + gdouble pitch, length, dx, dy; + + if (argc != 1) + return 0; + + dir = atoi(argv[0]); + + + PCB_PAD_ALL_LOOP(PCB->Data); + { + if (PCB_FLAG_TEST(PCB_FLAG_SELECTED, pad)) { + pcb_pin_t *via; + pcb_line_t *line; + + pcb_pad_t *pad0 = element->Pad->data; + pcb_pad_t *pad1 = g_list_next(element->Pad)->data; + + pitch = sqrt(pow(abs(pad0->Point1.X - pad1->Point1.X), 2) + pow(abs(pad0->Point1.Y - pad1->Point1.Y), 2)); + length = sqrt(pow(pitch, 2) + pow(pitch, 2)) / 2.; + + dx = length * sin(M_PI / 4.); + dy = length * cos(M_PI / 4.); + + switch (dir) { + case 1: + viax = pad->Point1.X - dx; + viay = pad->Point1.Y + dy; + break; + case 3: + viax = pad->Point1.X + dx; + viay = pad->Point1.Y + dy; + break; + case 9: + viax = pad->Point1.X + dx; + viay = pad->Point1.Y - dy; + break; + case 7: + viax = pad->Point1.X - dx; + viay = pad->Point1.Y - dy; + break; + case 2: + viax = pad->Point1.X; + viay = pad->Point1.Y + (pitch / 2); + break; + case 8: + viax = pad->Point1.X; + viay = pad->Point1.Y - (pitch / 2); + break; + case 4: + viax = pad->Point1.X - (pitch / 2); + viay = pad->Point1.Y; + break; + case 6: + viax = pad->Point1.X + (pitch / 2); + viay = pad->Point1.Y; + break; + default: + printf("ERROR: escape() with bad direction (%d)\n", dir); + return 1; + } + + if ((via = pcb_via_new(PCB->Data, viax, viay, + Settings.ViaThickness, 2 * Settings.Clearance, + 0, Settings.ViaDrillingHole, NULL, pcb_no_flags())) != NULL) { + pcb_undo_add_obj_to_create(PCB_TYPE_VIA, via, via, via); +/* if (gui->shift_is_pressed ()) + pcb_chg_obj_thermal(PCB_TYPE_VIA, via, via, via, PCB->ThermStyle);*/ + DrawVia(via); + if ((line = pcb_line_new_merge(CURRENT, pad->Point1.X + 1., pad->Point1.Y + 1., viax + 1., viay + 1., + Settings.LineThickness, 2 * Settings.Clearance, pcb_no_flags()))) { + + pcb_undo_add_obj_to_create(PCB_TYPE_LINE, CURRENT, line, line); + DrawLine(CURRENT, line); + + } + + } + + } + } + PCB_END_LOOP; + PCB_END_LOOP; + + pcb_undo_inc_serial(); + pcb_draw(); + return 0; +} + +static pcb_hid_action_t toporouter_action_list[] = { + {"Escape", "Select a set of pads", escape, "Pad escape", "Escape()"}, + {"Toporouter", "Select net(s)", toporouter, "Topological autorouter", "Toporouter()"} +}; + +PCB_REGISTER_ACTIONS(toporouter_action_list, toporouter_cookie) + +static void hid_toporouter_uninit(void) +{ + pcb_hid_remove_actions_by_cookie(toporouter_cookie); +} + +pcb_uninit_t hid_toporouter_init() +{ + register_toporouter_action_list(); + return hid_toporouter_uninit; +} Index: work/obsolete/toporouter/src_plugins/toporouter/toporouter.h =================================================================== --- work/obsolete/toporouter/src_plugins/toporouter/toporouter.h (nonexistent) +++ work/obsolete/toporouter/src_plugins/toporouter/toporouter.h (revision 6803) @@ -0,0 +1,489 @@ +/* + * COPYRIGHT + * + * Topological Autorouter for + * PCB, interactive printed circuit board design + * Copyright (C) 2009 Anthony Blake + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Contact addresses for email: + * Anthony Blake, tonyb33@gmail.com + * + */ + +#ifndef PCB_TOPOROUTER_H +#define PCB_TOPOROUTER_H + +#include +#include +#include "data.h" +#include "macro.h" +#include "../autoroute/autoroute.h" +#include "box.h" +#include "draw.h" +#include "error.h" +#include "find.h" +#include "heap.h" +#include "rtree.h" +#include "polygon.h" +#include "rats.h" +#include "remove.h" +#include "obj_pinvia_therm.h" +#include "undo.h" +#include "config.h" + +#include "gts.h" + +#include +#include + +#include + +#define TOPOROUTER_FLAG_VERBOSE (1<<0) +#define TOPOROUTER_FLAG_HARDDEST (1<<1) +#define TOPOROUTER_FLAG_HARDSRC (1<<2) +#define TOPOROUTER_FLAG_MATCH (1<<3) +#define TOPOROUTER_FLAG_LAYERHINT (1<<4) +#define TOPOROUTER_FLAG_LEASTINVALID (1<<5) +#define TOPOROUTER_FLAG_AFTERORDER (1<<6) +#define TOPOROUTER_FLAG_AFTERRUBIX (1<<7) +#define TOPOROUTER_FLAG_GOFAR (1<<8) +#define TOPOROUTER_FLAG_DETOUR (1<<9) + +/* Define to 1 to enable toporouter graphical output - wait, we don't link cairo?! */ +#define TOPO_OUTPUT_ENABLED 0 + + +#if TOPO_OUTPUT_ENABLED +#include +#endif + +#define EPSILON 0.0001f + +/*#define DEBUG_ROAR 1*/ + +#define coord_distance(a,b,c,d) sqrt(pow(a-c,2)+pow(b-d,2)) +#define coord_distance2(a,b,c,d) (pow(a-c,2)+pow(b-d,2)) + +#define tvdistance(a,b) sqrt(pow(vx(a)-vx(b),2)+pow(vy(a)-vy(b),2)) +#define tvdistance2(a,b) (pow(vx(a)-vx(b),2)+pow(vy(a)-vy(b),2)) + +#define edge_v1(e) (GTS_SEGMENT(e)->v1) +#define edge_v2(e) (GTS_SEGMENT(e)->v2) +#define tedge_v1(e) (TOPOROUTER_VERTEX(GTS_SEGMENT(e)->v1)) +#define tedge_v2(e) (TOPOROUTER_VERTEX(GTS_SEGMENT(e)->v2)) + +#define tedge(v1,v2) TOPOROUTER_EDGE(gts_vertices_are_connected(GTS_VERTEX(v1), GTS_VERTEX(v2))) + +#define edge_routing(e) (TOPOROUTER_IS_CONSTRAINT(e) ? TOPOROUTER_CONSTRAINT(e)->routing : e->routing) +#define vrouting(v) (edge_routing(v->routingedge)) + +#define edge_routing_next(e,list) ((list->next) ? TOPOROUTER_VERTEX(list->next->data) : TOPOROUTER_VERTEX(edge_v2(e))) +#define edge_routing_prev(e,list) ((list->prev) ? TOPOROUTER_VERTEX(list->prev->data) : TOPOROUTER_VERTEX(edge_v1(e))) + +#define vx(v) (GTS_POINT(v)->x) +#define vy(v) (GTS_POINT(v)->y) +#define vz(v) (GTS_POINT(v)->z) + +#define close_enough_xy(a,b) (vx(a) > vx(b) - EPSILON && vx(a) < vx(b) + EPSILON && vy(a) > vy(b) - EPSILON && vy(a) < vy(b) + EPSILON) + +#define tev1x(e) (vx(tedge_v1(e)) +#define tev1y(e) (vy(tedge_v1(e)) +#define tev1z(e) (vz(tedge_v1(e)) +#define tev2x(e) (vx(tedge_v2(e)) +#define tev2y(e) (vy(tedge_v2(e)) +#define tev2z(e) (vz(tedge_v2(e)) + +#define tvertex_intersect(a,b,c,d) (TOPOROUTER_VERTEX(vertex_intersect(GTS_VERTEX(a),GTS_VERTEX(b),GTS_VERTEX(c),GTS_VERTEX(d)))) + +#define TOPOROUTER_IS_BBOX(obj) (gts_object_is_from_class (obj, toporouter_bbox_class ())) +#define TOPOROUTER_BBOX(obj) GTS_OBJECT_CAST (obj, toporouter_bbox_t, toporouter_bbox_class ()) +#define TOPOROUTER_BBOX_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass, toporouter_bbox_class_t, toporouter_bbox_class ()) + +typedef enum { + PAD, + PIN, + VIA, + ARC, + VIA_SHADOW, + LINE, + OTHER, + BOARD, + EXPANSION_AREA, + POLYGON, + TEMP +} toporouter_term_t; + +struct _toporouter_bbox_t { + GtsBBox b; + + toporouter_term_t type; + void *data; + int layer; + + GtsSurface *surface; + GtsTriangle *enclosing; + + GList *constraints; + GtsPoint *point, *realpoint; + +/* char *netlist, *style;*/ + + struct _toporouter_cluster_t *cluster; + +}; + +struct _toporouter_bbox_class_t { + GtsBBoxClass parent_class; +}; + +typedef struct _toporouter_bbox_t toporouter_bbox_t; +typedef struct _toporouter_bbox_class_t toporouter_bbox_class_t; + +#define TOPOROUTER_IS_EDGE(obj) (gts_object_is_from_class (obj, toporouter_edge_class ())) +#define TOPOROUTER_EDGE(obj) GTS_OBJECT_CAST (obj, toporouter_edge_t, toporouter_edge_class ()) +#define TOPOROUTER_EDGE_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass, toporouter_edge_class_t, toporouter_edge_class ()) + +#define EDGE_FLAG_DIRECTCONNECTION (1<<0) + +struct _toporouter_edge_t { + GtsEdge e; + /*pcb_netlist_t *netlist; */ + + guint flags; + + GList *routing; +}; + +struct _toporouter_edge_class_t { + GtsEdgeClass parent_class; +}; + +typedef struct _toporouter_edge_t toporouter_edge_t; +typedef struct _toporouter_edge_class_t toporouter_edge_class_t; + +#define TOPOROUTER_IS_VERTEX(obj) (gts_object_is_from_class (obj, toporouter_vertex_class ())) +#define TOPOROUTER_VERTEX(obj) GTS_OBJECT_CAST (obj, toporouter_vertex_t, toporouter_vertex_class ()) +#define TOPOROUTER_VERTEX_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass, toporouter_vertex_class_t, toporouter_vertex_class ()) + +#define VERTEX_FLAG_VIZ (1<<1) +#define VERTEX_FLAG_CCW (1<<2) +#define VERTEX_FLAG_CW (1<<3) +#define VERTEX_FLAG_RED (1<<4) +#define VERTEX_FLAG_GREEN (1<<5) +#define VERTEX_FLAG_BLUE (1<<6) +#define VERTEX_FLAG_TEMP (1<<7) +#define VERTEX_FLAG_ROUTE (1<<8) +#define VERTEX_FLAG_FAKE (1<<10) +#define VERTEX_FLAG_SPECCUT (1<<11) + +struct _toporouter_vertex_t { + GtsVertex v; + /*GList *boxes; */ + struct _toporouter_bbox_t *bbox; + + struct _toporouter_vertex_t *parent; + struct _toporouter_vertex_t *child; + + toporouter_edge_t *routingedge; + + guint flags; + + gdouble gcost, hcost; + guint gn; + + struct _toporouter_arc_t *arc; + + struct _toporouter_oproute_t *oproute; + struct _toporouter_route_t *route; + + gdouble thickness; + +}; + +struct _toporouter_vertex_class_t { + GtsVertexClass parent_class; +}; + +typedef struct _toporouter_vertex_t toporouter_vertex_t; +typedef struct _toporouter_vertex_class_t toporouter_vertex_class_t; + +#define TOPOROUTER_IS_CONSTRAINT(obj) (gts_object_is_from_class (obj, toporouter_constraint_class ())) +#define TOPOROUTER_CONSTRAINT(obj) GTS_OBJECT_CAST (obj, toporouter_constraint_t, toporouter_constraint_class ()) +#define TOPOROUTER_CONSTRAINT_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass, toporouter_constraint_class_t, toporouter_constraint_class ()) + +struct _toporouter_constraint_t { + GtsConstraint c; + toporouter_bbox_t *box; + GList *routing; +}; + +struct _toporouter_constraint_class_t { + GtsConstraintClass parent_class; +}; + +typedef struct { + gdouble x, y; +} toporouter_spoint_t; + +typedef struct _toporouter_constraint_t toporouter_constraint_t; +typedef struct _toporouter_constraint_class_t toporouter_constraint_class_t; + +typedef struct { + GtsSurface *surface; +/* GtsTriangle *t;*/ +/* GtsVertex *v1, *v2, *v3;*/ + + GList *vertices; + GList *constraints; + GList *edges; + +} toporouter_layer_t; + +#define TOPOROUTER_VERTEX_REGION(x) ((toporouter_vertex_region_t *)x) +typedef struct { + + GList *points; + toporouter_vertex_t *v1, *v2; + toporouter_vertex_t *origin; + +} toporouter_vertex_region_t; + +struct _toporouter_rubberband_arc_t { + toporouter_vertex_t *pathv, *arcv; + gdouble r, d; + gint wind; + GList *list; +}; + +typedef struct _toporouter_rubberband_arc_t toporouter_rubberband_arc_t; +#define TOPOROUTER_RUBBERBAND_ARC(x) ((toporouter_rubberband_arc_t *)x) + +struct _toporouter_route_t { + + struct _toporouter_netlist_t *netlist; + + struct _toporouter_cluster_t *src, *dest; + struct _toporouter_cluster_t *psrc, *pdest; + + gdouble score, detourscore; + + toporouter_vertex_t *curpoint; + GHashTable *alltemppoints; + + GList *path; + + guint flags; + + GList *destvertices, *srcvertices; + + GList *topopath; + + gdouble pscore; + GList *ppath; + + gint *ppathindices; +}; + +typedef struct _toporouter_route_t toporouter_route_t; + +#define TOPOROUTER_ROUTE(x) ((toporouter_route_t *)x) + +struct _toporouter_netlist_t { + GPtrArray *clusters, *routes; + char *netlist, *style; + GList *routed; + + struct _toporouter_netlist_t *pair; +}; + +typedef struct _toporouter_netlist_t toporouter_netlist_t; + +#define TOPOROUTER_NETLIST(x) ((toporouter_netlist_t *)x) + +struct _toporouter_cluster_t { + gint c, pc; + GPtrArray *boxes; + toporouter_netlist_t *netlist; +}; + +typedef struct _toporouter_cluster_t toporouter_cluster_t; + +#define TOPOROUTER_CLUSTER(x) ((toporouter_cluster_t *)x) + +#define TOPOROUTER_OPROUTE(x) ((toporouter_oproute_t *)x) + +#define oproute_next(a,b) (b->next ? TOPOROUTER_ARC(b->next->data) : a->term2) +#define oproute_prev(a,b) (b->prev ? TOPOROUTER_ARC(b->prev->data) : a->term1) + +#define TOPOROUTER_SERPINTINE(x) ((toporouter_serpintine_t *)x) + +struct _toporouter_serpintine_t { + GList *arcs; + gdouble x, y; + gdouble x0, y0, x1, y1; + + gpointer start; + gdouble halfa, radius; + guint nhalfcycles; + +}; +typedef struct _toporouter_serpintine_t toporouter_serpintine_t; + +struct _toporouter_oproute_t { + GList *arcs; + toporouter_vertex_t *term1, *term2; + char *style; + char *netlist; + guint layergroup; + gdouble tof; + GList *path; + + toporouter_serpintine_t *serp; +}; + +typedef struct _toporouter_oproute_t toporouter_oproute_t; + + +#define TOPOROUTER_IS_ARC(obj) (gts_object_is_from_class (obj, toporouter_arc_class())) +#define TOPOROUTER_ARC(obj) GTS_OBJECT_CAST (obj, toporouter_arc_t, toporouter_arc_class()) +#define TOPOROUTER_ARC_CLASS(klass) GTS_OBJECT_CLASS_CAST (klass, toporouter_arc_class_t, toporouter_arc_class()) + +struct _toporouter_arc_t { + GtsObject object; + + gdouble x0, y0, x1, y1; + toporouter_vertex_t *centre, *v; + gdouble r; + gint dir; + + GList *clearance; + + toporouter_oproute_t *oproute; + + toporouter_vertex_t *v1, *v2; +}; + +struct _toporouter_arc_class_t { + GtsObjectClass parent_class; + gboolean binary; +}; + +typedef struct _toporouter_arc_t toporouter_arc_t; +typedef struct _toporouter_arc_class_t toporouter_arc_class_t; + +typedef struct _toporouter_t toporouter_t; + + + +typedef struct { + guint id; + + guint *pairwise_nodetour; + gdouble pairwise_detour_sum; + gdouble score; + guint pairwise_fails; + + toporouter_route_t *routedata; + + toporouter_t *r; + +} toporouter_netscore_t; + +#define TOPOROUTER_NETSCORE(x) ((toporouter_netscore_t *)x) + +struct _toporouter_t { + GSList *bboxes; + GNode *bboxtree; + + toporouter_layer_t *layers; + + GList *paths; + + GList *keepoutlayers; + + guint flags; + + GList *destboxes, *consumeddestboxes; + + /* settings: */ + guint viamax; + gdouble viacost; + gdouble stublength; + gdouble serpintine_half_amplitude; + + gdouble wiring_score; + + GPtrArray *routes; + GPtrArray *netlists; + + GList *routednets, *failednets; + + gint(*netsort) (toporouter_netscore_t **, toporouter_netscore_t **); + + struct timeval starttime; + + FILE *debug; +}; + +typedef gint(*oproute_adjseg_func) + + (toporouter_t *, + GList **, GList **, guint *, gdouble, gdouble, gdouble, gdouble, toporouter_oproute_t *, toporouter_oproute_t *); + +typedef struct { +#ifdef CAIRO_H + cairo_t *cr; + cairo_surface_t *surface; +#endif + + double s; /* scale factor */ + + int mode; + void *data; + + char *filename; + double iw, ih; /* image dimensions */ +} drawing_context_t; + +#define FOREACH_CLUSTER(clusters) do { \ + toporouter_cluster_t **i; \ + for(i = ((toporouter_cluster_t **)clusters->pdata) + clusters->len - 1; i >= (toporouter_cluster_t **)clusters->pdata && clusters->len > 0; --i) { \ + toporouter_cluster_t *cluster = *i; + +#define FOREACH_BBOX(boxes) do { \ + toporouter_bbox_t **i; \ + for(i = ((toporouter_bbox_t **)boxes->pdata) + boxes->len - 1; i >= (toporouter_bbox_t **)boxes->pdata && boxes->len > 0; --i) { \ + toporouter_bbox_t *box = *i; + +#define FOREACH_ROUTE(routes) do { \ + toporouter_route_t **i; \ + for(i = ((toporouter_route_t **)routes->pdata) + routes->len - 1; i >= (toporouter_route_t **)routes->pdata && routes->len > 0; --i) { \ + toporouter_route_t *routedata = *i; + +#define FOREACH_NETSCORE(netscores) do { \ + toporouter_netscore_t **i; \ + for(i = ((toporouter_netscore_t **)netscores->pdata) + netscores->len - 1; i >= (toporouter_netscore_t **)netscores->pdata && netscores->len > 0; --i) { \ + toporouter_netscore_t *netscore = *i; + +#define FOREACH_NETLIST(netlists) do { \ + toporouter_netlist_t **i; \ + for(i = ((toporouter_netlist_t **)netlists->pdata) + netlists->len - 1; i >= (toporouter_netlist_t **)netlists->pdata && netlists->len > 0; --i) { \ + toporouter_netlist_t *netlist = *i; + +#define FOREACH_END }} while(0) + +#endif /* PCB_TOPOROUTER_H */