v_data *delaunay_triangulation(double *x, double *y, int n) { v_data *delaunay; GtsSurface* s = tri(x, y, n, NULL, 0, 1); int i, nedges; int* edges; estats stats; if (!s) return NULL; delaunay = N_GNEW(n, v_data); for (i = 0; i < n; i++) { delaunay[i].ewgts = NULL; delaunay[i].nedges = 1; } stats.n = 0; stats.delaunay = delaunay; edgeStats (s, &stats); nedges = stats.n; edges = N_GNEW(2 * nedges + n, int); for (i = 0; i < n; i++) { delaunay[i].edges = edges; edges += delaunay[i].nedges; delaunay[i].edges[0] = i; delaunay[i].nedges = 1; } gts_surface_foreach_edge (s, (GtsFunc) add_edge, delaunay); gts_object_destroy (GTS_OBJECT (s)); return delaunay; }
/* delaunay_tri: * Given n points whose coordinates are in the x[] and y[] * arrays, compute a Delaunay triangulation of the points. * The number of edges in the triangulation is returned in pnedges. * The return value itself is an array e of 2*(*pnedges) integers, * with edge i having points whose indices are e[2*i] and e[2*i+1]. * * If the points are collinear, GTS fails with 0 edges. * In this case, we sort the points by x coordinates (or y coordinates * if the points form a vertical line). We then return a "triangulation" * consisting of the n-1 pairs of adjacent points. */ int *delaunay_tri(double *x, double *y, int n, int* pnedges) { GtsSurface* s = tri(x, y, n, NULL, 0, 1); int nedges; int* edges; estats stats; estate state; if (!s) return NULL; stats.n = 0; stats.delaunay = NULL; edgeStats (s, &stats); *pnedges = nedges = stats.n; if (nedges) { edges = N_GNEW(2 * nedges, int); state.n = 0; state.edges = edges; gts_surface_foreach_edge (s, (GtsFunc) addEdge, &state); } else {
/** * 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.; }
static void surface_optimize (GtsSurface * surface, gdouble max_cost) { GtsEHeap * heap; GtsEdge * e; gdouble top_cost; heap = gts_eheap_new ((GtsKeyFunc) edge_swap_cost, NULL); gts_eheap_freeze (heap); gts_surface_foreach_edge (surface, (GtsFunc) create_heap_optimize, heap); gts_eheap_thaw (heap); gts_allow_floating_edges = TRUE; while ((e = gts_eheap_remove_top (heap, &top_cost)) && top_cost < max_cost) edge_swap (e, surface, heap); gts_allow_floating_edges = FALSE; if (e) GTS_OBJECT (e)->reserved = NULL; gts_eheap_foreach (heap, (GFunc) gts_object_reset_reserved, NULL); gts_eheap_destroy (heap); }
int main (int argc, char * argv[]) { GtsSurface * s; guint i; GtsFile * fp; guint nv = 1, ne = 1, nf = 1; if (!setlocale (LC_ALL, "POSIX")) g_warning ("cannot set locale to POSIX"); s = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); fp = gts_file_new (stdin); if (gts_surface_read (s, fp)) { fputs ("gtstoc: file on standard input is not a valid GTS file\n", stderr); fprintf (stderr, "stdin:%d:%d: %s\n", fp->line, fp->pos, fp->error); return 1; /* failure */ } printf (" GtsSurface * surface = gts_surface_new (gts_surface_class (),\n" " gts_face_class (),\n" " gts_edge_class (),\n" " gts_vertex_class ());\n\n"); gts_surface_foreach_vertex (s, (GtsFunc) write_vertex, &nv); printf ("\n"); gts_surface_foreach_edge (s, (GtsFunc) write_edge, &ne); printf ("\n"); gts_surface_foreach_face (s, (GtsFunc) write_face, &nf); printf (" \n"); for (i = 1; i < nf; i++) printf (" gts_surface_add_face (surface, f%u);\n", i); return 0; }
void pygts_edge_cleanup(GtsSurface *s) { GSList *edges = NULL; GSList *i, *ii, *cur, *parents=NULL; PygtsEdge *edge; GtsEdge *e, *duplicate; g_return_if_fail(s != NULL); /* build list of edges */ gts_surface_foreach_edge(s, (GtsFunc)build_list, &edges); /* remove degenerate and duplicate edges. Note: we could use gts_edges_merge() to remove the duplicates and then remove the degenerate edges but it is more efficient to do everything at once (and it's more pedagogical too ...) */ /* We want to control manually the destruction of edges */ gts_allow_floating_edges = TRUE; i = edges; while(i) { e = (GtsEdge*)i->data; if(GTS_SEGMENT(e)->v1 == GTS_SEGMENT(e)->v2) { /* edge is degenerate */ if( !g_hash_table_lookup(obj_table,GTS_OBJECT(e)) ) { /* destroy e */ gts_object_destroy(GTS_OBJECT(e)); } } else { if((duplicate = gts_edge_is_duplicate(e))) { /* Detach and save any parent triangles */ if( (edge = PYGTS_EDGE(g_hash_table_lookup(obj_table,GTS_OBJECT(e)))) !=NULL ) { ii = e->triangles; while(ii!=NULL) { cur = ii; ii = g_slist_next(ii); if(PYGTS_IS_PARENT_TRIANGLE(cur->data)) { e->triangles = g_slist_remove_link(e->triangles, cur); parents = g_slist_prepend(parents,cur->data); g_slist_free_1(cur); } } } /* replace e with its duplicate */ gts_edge_replace(e, duplicate); /* Reattach the parent segments */ if( edge != NULL ) { ii = parents; while(ii!=NULL) { e->triangles = g_slist_prepend(e->triangles, ii->data); ii = g_slist_next(ii); } g_slist_free(parents); parents = NULL; } if( !g_hash_table_lookup(obj_table,GTS_OBJECT(e)) ) { /* destroy e */ gts_object_destroy(GTS_OBJECT (e)); } } } i = g_slist_next(i); } /* don't forget to reset to default */ gts_allow_floating_edges = FALSE; /* free list of edges */ g_slist_free (edges); }
static GtsSurface * cartesian_grid_triangulate_holes (CartesianGrid * grid, GtsSurface * s) { GtsVertex * v1, * v2, * v3, * v4; GtsEdge * e1, * e2, * e3, * e4, * e5; gdouble w, h; GtsSurface * box; GSList * constraints = NULL, * vertices = NULL, * i; gpointer data[2]; g_return_val_if_fail (grid != NULL, NULL); g_return_val_if_fail (s != NULL, NULL); /* build enclosing box */ w = grid->xmax - grid->xmin; h = grid->ymax - grid->ymin; v1 = gts_vertex_new (s->vertex_class, grid->xmin - w, grid->ymin - h, 0.); v2 = gts_vertex_new (s->vertex_class, grid->xmax + w, grid->ymin - h, 0.); v3 = gts_vertex_new (s->vertex_class, grid->xmax + w, grid->ymax + h, 0.); v4 = gts_vertex_new (s->vertex_class, grid->xmin - w, grid->ymax + h, 0.); e1 = gts_edge_new (s->edge_class, v1, v2); e2 = gts_edge_new (s->edge_class, v2, v3); e3 = gts_edge_new (s->edge_class, v3, v4); e4 = gts_edge_new (s->edge_class, v4, v1); e5 = gts_edge_new (s->edge_class, v1, v3); box = gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (s)->klass), s->face_class, s->edge_class, s->vertex_class); gts_surface_add_face (box, gts_face_new (s->face_class, e1, e2, e5)); gts_surface_add_face (box, gts_face_new (s->face_class, e3, e4, e5)); /* build vertex and constraint list from the boundaries of the input surface s */ data[0] = s; data[1] = &constraints; gts_surface_foreach_edge (s, (GtsFunc) build_constraint_list, data); vertices = gts_vertices_from_segments (constraints); /* triangulate holes */ i = vertices; while (i) { g_assert (!gts_delaunay_add_vertex (box, i->data, NULL)); i = i->next; } g_slist_free (vertices); i = constraints; while (i) { g_assert (!gts_delaunay_add_constraint (box, i->data)); i = i->next; } /* destroy corners of the enclosing box */ gts_allow_floating_vertices = TRUE; gts_object_destroy (GTS_OBJECT (v1)); gts_object_destroy (GTS_OBJECT (v2)); gts_object_destroy (GTS_OBJECT (v3)); gts_object_destroy (GTS_OBJECT (v4)); gts_allow_floating_vertices = FALSE; /* remove parts of the mesh which are not holes */ i = constraints; while (i) { edge_mark_as_hole (i->data, box); i = i->next; } g_slist_free (constraints); /* remove marked and duplicate faces */ gts_surface_foreach_face_remove (box, (GtsFunc) face_is_marked, NULL); /* box now contains only the triangulated holes. */ return box; }
static void edgeStats (GtsSurface* s, estats* sp) { gts_surface_foreach_edge (s, (GtsFunc) cnt_edge, sp); }
int main (int argc, char * argv[]) { GtsSurface * s; gboolean verbose = FALSE; gdouble threshold; int c = 0; GtsFile * fp; GtsRange angle; if (!setlocale (LC_ALL, "POSIX")) g_warning ("cannot set locale to POSIX"); /* parse options using getopt */ while (c != EOF) { #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'}, { NULL } }; int option_index = 0; switch ((c = getopt_long (argc, argv, "hv", long_options, &option_index))) { #else /* not HAVE_GETOPT_LONG */ switch ((c = getopt (argc, argv, "hv"))) { #endif /* not HAVE_GETOPT_LONG */ case 'v': /* verbose */ verbose = TRUE; break; case 'h': /* help */ fprintf (stderr, "Usage: optimize [OPTION] THRESHOLD < FILE\n" "\n" " -v --verbose print statistics about the surface\n" " -h --help display this help and exit\n" "\n" "Report bugs to %s\n", GTS_MAINTAINER); return 0; /* success */ break; case '?': /* wrong options */ fprintf (stderr, "Try `optimize --help' for more information.\n"); return 1; /* failure */ } } if (optind >= argc) { /* missing threshold */ fprintf (stderr, "optimize: missing THRESHOLD\n" "Try `optimize --help' for more information.\n"); return 1; /* failure */ } threshold = strtod (argv[optind], NULL); if (threshold < 0.0) { /* threshold must be positive */ fprintf (stderr, "optimize: THRESHOLD must be >= 0.0\n" "Try `optimize --help' for more information.\n"); return 1; /* failure */ } /* read surface in */ s = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); fp = gts_file_new (stdin); if (gts_surface_read (s, fp)) { fputs ("optimize: file on standard input is not a valid GTS file\n", stderr); fprintf (stderr, "stdin:%d:%d: %s\n", fp->line, fp->pos, fp->error); return 1; /* failure */ } /* if verbose on print stats */ if (verbose) { gts_surface_print_stats (s, stderr); gts_range_init (&angle); gts_surface_foreach_edge (s, (GtsFunc) angle_stats, &angle); gts_range_update (&angle); fputs ("# angle : ", stderr); gts_range_print (&angle, stderr); fputc ('\n', stderr); } surface_optimize (s, -threshold); /* if verbose on print stats */ if (verbose) { gts_surface_print_stats (s, stderr); gts_range_init (&angle); gts_surface_foreach_edge (s, (GtsFunc) angle_stats, &angle); gts_range_update (&angle); fputs ("# angle : ", stderr); gts_range_print (&angle, stderr); fputc ('\n', stderr); } /* write surface */ gts_surface_write (s, stdout); return 0; /* success */ }