Index: src_3rd/gts/face.c =================================================================== --- src_3rd/gts/face.c (revision 6802) +++ 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: src_3rd/gts/Makefile.in =================================================================== --- src_3rd/gts/Makefile.in (revision 6802) +++ 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: src_3rd/gts/segment.c =================================================================== --- src_3rd/gts/segment.c (revision 6802) +++ 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: src_3rd/gts/oocs.c =================================================================== --- src_3rd/gts/oocs.c (revision 6802) +++ 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: src_3rd/gts/triangle.c =================================================================== --- src_3rd/gts/triangle.c (revision 6802) +++ 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: src_3rd/gts/stripe.c =================================================================== --- src_3rd/gts/stripe.c (revision 6802) +++ 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: src_3rd/gts/object.c =================================================================== --- src_3rd/gts/object.c (revision 6802) +++ 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: src_3rd/gts/refine.c =================================================================== --- src_3rd/gts/refine.c (revision 6802) +++ 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: src_3rd/gts/cdt.c =================================================================== --- src_3rd/gts/cdt.c (revision 6802) +++ 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: src_3rd/gts/vertex.c =================================================================== --- src_3rd/gts/vertex.c (revision 6802) +++ 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: src_3rd/gts/heap.c =================================================================== --- src_3rd/gts/heap.c (revision 6802) +++ 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: src_3rd/gts/kdtree.c =================================================================== --- src_3rd/gts/kdtree.c (revision 6802) +++ 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: src_3rd/gts/curvature.c =================================================================== --- src_3rd/gts/curvature.c (revision 6802) +++ 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: src_3rd/gts/pgraph.c =================================================================== --- src_3rd/gts/pgraph.c (revision 6802) +++ 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: src_3rd/gts/named.c =================================================================== --- src_3rd/gts/named.c (revision 6802) +++ 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: src_3rd/gts/vopt.c =================================================================== --- src_3rd/gts/vopt.c (revision 6802) +++ 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: src_3rd/gts/point.c =================================================================== --- src_3rd/gts/point.c (revision 6802) +++ 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: src_3rd/gts/isotetra.c =================================================================== --- src_3rd/gts/isotetra.c (revision 6802) +++ 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: src_3rd/gts/tribox3.c =================================================================== --- src_3rd/gts/tribox3.c (revision 6802) +++ 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: src_3rd/gts/rounding.h =================================================================== --- src_3rd/gts/rounding.h (revision 6802) +++ 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: src_3rd/gts/split.c =================================================================== --- src_3rd/gts/split.c (revision 6802) +++ 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: src_3rd/gts/hsurface.c =================================================================== --- src_3rd/gts/hsurface.c (revision 6802) +++ 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: src_3rd/gts/graph.c =================================================================== --- src_3rd/gts/graph.c (revision 6802) +++ 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: src_3rd/gts/gts.h =================================================================== --- src_3rd/gts/gts.h (revision 6802) +++ 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: src_3rd/gts/bbtree.c =================================================================== --- src_3rd/gts/bbtree.c (revision 6802) +++ 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: src_3rd/gts/Makefile.dep =================================================================== --- src_3rd/gts/Makefile.dep (revision 6802) +++ 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: src_3rd/gts/edge.c =================================================================== --- src_3rd/gts/edge.c (revision 6802) +++ 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: src_3rd/gts/matrix.c =================================================================== --- src_3rd/gts/matrix.c (revision 6802) +++ 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: src_3rd/gts/psurface.c =================================================================== --- src_3rd/gts/psurface.c (revision 6802) +++ 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: src_3rd/gts/partition.c =================================================================== --- src_3rd/gts/partition.c (revision 6802) +++ 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: src_3rd/gts/gts-private.h =================================================================== --- src_3rd/gts/gts-private.h (revision 6802) +++ 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: src_3rd/gts/boolean.c =================================================================== --- src_3rd/gts/boolean.c (revision 6802) +++ 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: src_3rd/gts/container.c =================================================================== --- src_3rd/gts/container.c (revision 6802) +++ 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: src_3rd/gts/eheap.c =================================================================== --- src_3rd/gts/eheap.c (revision 6802) +++ 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: src_3rd/gts/fifo.c =================================================================== --- src_3rd/gts/fifo.c (revision 6802) +++ 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: src_3rd/gts/predicates.c =================================================================== --- src_3rd/gts/predicates.c (revision 6802) +++ 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: src_3rd/gts/surface.c =================================================================== --- src_3rd/gts/surface.c (revision 6802) +++ 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: src_3rd/gts/predicates.h =================================================================== --- src_3rd/gts/predicates.h (revision 6802) +++ 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: src_3rd/gts/iso.c =================================================================== --- src_3rd/gts/iso.c (revision 6802) +++ 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: src_3rd/gts/misc.c =================================================================== --- src_3rd/gts/misc.c (revision 6802) +++ 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: src_plugins/toporouter/toporouter.c =================================================================== --- src_plugins/toporouter/toporouter.c (revision 6802) +++ 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: src_plugins/toporouter/Plug.tmpasm =================================================================== --- src_plugins/toporouter/Plug.tmpasm (revision 6802) +++ 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: src_plugins/toporouter/toporouter.h =================================================================== --- src_plugins/toporouter/toporouter.h (revision 6802) +++ 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: src_plugins/toporouter/README =================================================================== --- src_plugins/toporouter/README (revision 6802) +++ 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: src_plugins/toporouter/Makefile =================================================================== --- src_plugins/toporouter/Makefile (revision 6802) +++ src_plugins/toporouter/Makefile (nonexistent) @@ -1,6 +0,0 @@ -all: - cd ../../src && $(MAKE) mod_toporouter - -clean: - rm *.o *.so 2>/dev/null ; true -