static GtsSurface * happrox_list (GSList * points, gboolean keep_enclosing, gboolean closed, CostFunc cost_func, gpointer cost_data, GtsStopFunc stop_func, gpointer stop_data) { GtsSurface * s = gts_surface_new (gts_surface_class (), GTS_FACE_CLASS (list_face_class ()), gts_edge_class (), gts_vertex_class ()); GtsTriangle * t; GtsVertex * w1, * w2, * w3; GtsListFace * f; /* creates enclosing triangle */ t = gts_triangle_enclosing (gts_triangle_class (), points, 10.); gts_triangle_vertices (t, &w1, &w2, &w3); GTS_POINT (w1)->z = GTS_POINT (w2)->z = GTS_POINT (w3)->z = keep_enclosing ? -10. : -1e30; f = GTS_LIST_FACE (gts_face_new (s->face_class, t->e1, t->e2, t->e3)); gts_surface_add_face (s, GTS_FACE (f)); f->points = points; /* refine surface */ surface_hf_refine (s, cost_func, cost_data, stop_func, stop_data); /* destroy unused vertices */ gts_surface_foreach_face (s, (GtsFunc) destroy_unused, NULL); /* destroy enclosing triangle */ if (!keep_enclosing) { gts_allow_floating_vertices = TRUE; gts_object_destroy (GTS_OBJECT (w1)); gts_object_destroy (GTS_OBJECT (w2)); gts_object_destroy (GTS_OBJECT (w3)); gts_allow_floating_vertices = FALSE; } else if (closed) { GSList * l = gts_surface_boundary (s); GtsFace * f; g_assert (g_slist_length (l) == 3); f = gts_face_new (s->face_class, l->data, l->next->data, l->next->next->data); gts_surface_add_face (s, f); if (!gts_face_is_compatible (f, s)) gts_triangle_revert (GTS_TRIANGLE (f)); g_slist_free (l); gts_object_destroy (GTS_OBJECT (t)); } else gts_object_destroy (GTS_OBJECT (t)); return s; }
/** * 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); }
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 GtsSurface * happrox (gray ** g, gint width, gint height, CostFunc cost_func, gpointer cost_data, GtsStopFunc stop_func, gpointer stop_data) { GtsSurface * s = gts_surface_new (gts_surface_class (), GTS_FACE_CLASS (list_face_class ()), gts_edge_class (), gts_vertex_class ()); GtsVertex * v1 = gts_vertex_new (s->vertex_class, 0., 0., g[0][0]); GtsVertex * v2 = gts_vertex_new (s->vertex_class, 0., height - 1, g[height - 1][0]); GtsVertex * v3 = gts_vertex_new (s->vertex_class, width - 1, 0., g[0][width - 1]); GtsVertex * v4 = gts_vertex_new (s->vertex_class, width - 1, height - 1, g[height - 1][width - 1]); guint i, j; GSList * corners = NULL; GtsTriangle * t; GtsVertex * w1, * w2, * w3; GtsListFace * f; /* creates enclosing triangle */ corners = g_slist_prepend (corners, v1); corners = g_slist_prepend (corners, v2); corners = g_slist_prepend (corners, v3); corners = g_slist_prepend (corners, v4); t = gts_triangle_enclosing (gts_triangle_class (), corners, 100.); g_slist_free (corners); gts_triangle_vertices (t, &w1, &w2, &w3); f = GTS_LIST_FACE (gts_face_new (s->face_class, t->e1, t->e2, t->e3)); gts_surface_add_face (s, GTS_FACE (f)); /* add PGM vertices (corners excepted) to point list of f */ for (i = 1; i < width - 1; i++) { for (j = 1; j < height - 1; j++) prepend (f, g, i, j); prepend (f, g, i, 0); prepend (f, g, i, height - 1); } for (j = 1; j < height - 1; j++) { prepend (f, g, 0, j); prepend (f, g, width - 1, j); } pgm_freearray (g, height); /* add four corners to initial triangulation */ g_assert (gts_delaunay_add_vertex_to_face (s, v1, GTS_FACE (f)) == NULL); f = GTS_LIST_FACE (gts_point_locate (GTS_POINT (v2), s, NULL)); g_assert (gts_delaunay_add_vertex_to_face (s, v2, GTS_FACE (f)) == NULL); f = GTS_LIST_FACE (gts_point_locate (GTS_POINT (v3), s, NULL)); g_assert (gts_delaunay_add_vertex_to_face (s, v3, GTS_FACE (f)) == NULL); f = GTS_LIST_FACE (gts_point_locate (GTS_POINT (v4), s, NULL)); g_assert (gts_delaunay_add_vertex_to_face (s, v4, GTS_FACE (f)) == NULL); /* refine surface */ surface_hf_refine (s, cost_func, cost_data, stop_func, stop_data); /* destroy unused vertices */ gts_surface_foreach_face (s, (GtsFunc) destroy_unused, NULL); /* destroy enclosing triangle */ gts_allow_floating_vertices = TRUE; gts_object_destroy (GTS_OBJECT (w1)); gts_object_destroy (GTS_OBJECT (w2)); gts_object_destroy (GTS_OBJECT (w3)); gts_allow_floating_vertices = FALSE; return s; }
int main (int argc, char * argv[]) { guint i, j, nx, ny; gdouble cosa, sina; GtsSurface * surface; GSList * l, * vertices = NULL; GtsTriangle * t; GtsVertex * v1, * v2, * v3; GTimer * timer; if (argc != 4) { fprintf (stderr, "usage: cartesian nx ny angle\n"); return 0; } nx = strtol (argv[1], NULL, 0); ny = strtol (argv[2], NULL, 0); cosa = cos (strtod (argv[3], NULL)); sina = sin (strtod (argv[3], NULL)); timer = g_timer_new (); g_timer_start (timer); for (i = 0; i < nx; i++) { gdouble x = (gdouble) i/(gdouble) (nx - 1); for (j = 0; j < ny; j++) { gdouble y = (gdouble) j/(gdouble) (nx - 1); vertices = g_slist_prepend (vertices, gts_vertex_new (gts_vertex_class (), cosa*x - sina*y, sina*x + cosa*y, 0.)); } } t = gts_triangle_enclosing (gts_triangle_class (), vertices, 100.); gts_triangle_vertices (t, &v1, &v2, &v3); surface = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); gts_surface_add_face (surface, gts_face_new (gts_face_class (), t->e1, t->e2, t->e3)); g_timer_stop (timer); fprintf (stderr, "Input: %g s\n", g_timer_elapsed (timer, NULL)); g_timer_reset (timer); g_timer_start (timer); l = vertices; while (l) { g_assert (gts_delaunay_add_vertex (surface, l->data, NULL) == NULL); l = l->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_timer_stop (timer); fprintf (stderr, "Triangulation: %g s speed: %.0f vertex/s\n", g_timer_elapsed (timer, NULL), g_slist_length (vertices)/g_timer_elapsed (timer, NULL)); g_timer_reset (timer); g_timer_start (timer); gts_surface_write (surface, stdout); g_timer_stop (timer); fprintf (stderr, "Output: %g s\n", g_timer_elapsed (timer, NULL)); if (gts_delaunay_check (surface)) { fprintf (stderr, "WARNING: surface is not Delaunay\n"); return 0; } return 1; }
int main (int argc, char * argv[]) { GPtrArray * vertices; GtsFifo * edges; guint i, line; GtsTriangle * t; GtsVertex * v1, * v2, * v3; GtsSurface * surface; gboolean keep_hull = TRUE; gboolean verbose = FALSE; gboolean add_constraints = TRUE; gboolean remove_holes = FALSE; gboolean check_delaunay = FALSE; gboolean conform = FALSE; gboolean refine = FALSE; gboolean split_constraints = FALSE; gboolean randomize = FALSE; gboolean remove_duplicates = FALSE; gint steiner_max = -1; gdouble quality = 0., area = G_MAXDOUBLE; int c = 0, status = 0; const char * fname = NULL; GTimer * timer; /* parse options using getopt */ while (c != EOF) { #ifdef HAVE_GETOPT_LONG static struct option long_options[] = { {"duplicates", no_argument, NULL, 'd'}, {"help", no_argument, NULL, 'h'}, {"verbose", no_argument, NULL, 'v'}, {"randomize", no_argument, NULL, 'r'}, {"hull", no_argument, NULL, 'b'}, {"noconst", no_argument, NULL, 'e'}, {"holes", no_argument, NULL, 'H'}, {"split", no_argument, NULL, 'S'}, {"check", no_argument, NULL, 'c'}, {"files", required_argument, NULL, 'f'}, {"conform", no_argument, NULL, 'o'}, {"steiner", required_argument, NULL, 's'}, {"quality", required_argument, NULL, 'q'}, {"area", required_argument, NULL, 'a'} }; int option_index = 0; switch ((c = getopt_long (argc, argv, "hvbecf:os:q:a:HSrd", long_options, &option_index))) { #else /* not HAVE_GETOPT_LONG */ switch ((c = getopt (argc, argv, "hvbecf:os:q:a:HSrd"))) { #endif /* not HAVE_GETOPT_LONG */ case 'd': /* duplicates */ remove_duplicates = TRUE; break; case 'b': /* do not keep convex hull */ keep_hull = FALSE; break; case 'e': /* do not add constrained edges */ add_constraints = FALSE; break; case 'H': /* remove holes */ remove_holes = TRUE; break; case 'S': /* split constraints */ split_constraints = TRUE; break; case 'r': /* randomize */ randomize = TRUE; break; case 'c': /* check Delaunay property */ check_delaunay = TRUE; break; case 'f': /* generates files */ fname = optarg; break; case 'v': /* verbose */ verbose = TRUE; break; case 'o': /* conform */ conform = TRUE; break; case 's': /* steiner */ steiner_max = atoi (optarg); break; case 'q': /* quality */ conform = TRUE; refine = TRUE; quality = atof (optarg); break; case 'a': /* area */ conform = TRUE; refine = TRUE; area = atof (optarg); break; case 'h': /* help */ fprintf (stderr, "Usage: delaunay [OPTION] < file.gts\n" "Construct the constrained Delaunay triangulation of the input\n" "\n" " -b --hull do not keep convex hull\n" " -e --noconst do not add constrained edges\n" " -S --split split constraints (experimental)\n" " -H --holes remove holes from the triangulation\n" " -d --duplicates remove duplicate vertices\n" " -r --randomize shuffle input vertex list\n" " -c --check check Delaunay property\n" " -f FNAME --files=FNAME generate evolution files\n" " -o --conform generate conforming triangulation\n" " -s N --steiner=N maximum number of Steiner points for\n" " conforming triangulation (default is no limit)\n" " -q Q --quality=Q Set the minimum acceptable face quality\n" " -a A --area=A Set the maximum acceptable face area\n" " -v --verbose print statistics about the triangulation\n" " -h --help display this help and exit\n" "\n" "Reports bugs to %s\n", GTS_MAINTAINER); return 0; /* success */ break; case '?': /* wrong options */ fprintf (stderr, "Try `delaunay --help' for more information.\n"); return 1; /* failure */ } } /* read file => two lists: vertices and constraints */ edges = gts_fifo_new (); vertices = g_ptr_array_new (); if (add_constraints) /* the edge class is a GtsConstraintClass */ line = read_list (vertices, edges, GTS_EDGE_CLASS (gts_constraint_class ()), stdin); else /* the edge class is a "normal" edge: GtsEdgeClass */ line = read_list (vertices, edges, gts_edge_class (), stdin); if (line > 0) { fprintf (stderr, "delaunay: error in input file at line %u\n", line); return 1; } timer = g_timer_new (); g_timer_start (timer); if (randomize) shuffle_array (vertices); /* create triangle enclosing all the vertices */ { GSList * list = NULL; for (i = 0; i < vertices->len; i++) list = g_slist_prepend (list, g_ptr_array_index (vertices, i)); t = gts_triangle_enclosing (gts_triangle_class (), list, 100.); g_slist_free (list); } gts_triangle_vertices (t, &v1, &v2, &v3); /* create surface with one face: the enclosing triangle */ surface = gts_surface_new (gts_surface_class (), gts_face_class (), gts_edge_class (), gts_vertex_class ()); gts_surface_add_face (surface, gts_face_new (gts_face_class (), t->e1, t->e2, t->e3)); /* add vertices */ for (i = 0; i < vertices->len; i++) { GtsVertex * v1 = g_ptr_array_index (vertices, i); GtsVertex * v = gts_delaunay_add_vertex (surface, v1, NULL); g_assert (v != v1); if (v != NULL) { if (!remove_duplicates) { fprintf (stderr, "delaunay: duplicate vertex (%g,%g) in input file\n", GTS_POINT (v)->x, GTS_POINT (v)->y); return 1; /* Failure */ } else gts_vertex_replace (v1, v); } if (fname) { static guint nf = 1; char s[80]; FILE * fp; g_snprintf (s, 80, "%s.%u", fname, nf++); fp = fopen (s, "wt"); gts_surface_write_oogl (surface, fp); fclose (fp); if (check_delaunay && gts_delaunay_check (surface)) { fprintf (stderr, "delaunay: triangulation is not Delaunay\n"); return 1; } } } g_ptr_array_free (vertices, TRUE); /* add remaining constraints */ if (add_constraints) gts_fifo_foreach (edges, (GtsFunc) add_constraint, surface); /* destroy enclosing triangle */ 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; if (!keep_hull) gts_delaunay_remove_hull (surface); if (remove_holes) delaunay_remove_holes (surface); if (split_constraints) { gpointer data[2]; data[0] = surface; data[1] = edges; gts_fifo_foreach (edges, (GtsFunc) split_constraint, data); } if (conform) { guint encroached_number = gts_delaunay_conform (surface, steiner_max, (GtsEncroachFunc) gts_vertex_encroaches_edge, NULL); if (encroached_number == 0 && refine) { guint unrefined_number; gpointer data[2]; data[0] = &quality; data[1] = &area; unrefined_number = gts_delaunay_refine (surface, steiner_max, (GtsEncroachFunc) gts_vertex_encroaches_edge, NULL, (GtsKeyFunc) triangle_cost, data); if (verbose && unrefined_number > 0) fprintf (stderr, "delaunay: ran out of Steiner points (max: %d) during refinement\n" "%d unrefined faces left\n", steiner_max, unrefined_number); } else if (verbose && encroached_number > 0) fprintf (stderr, "delaunay: ran out of Steiner points (max: %d) during conforming\n" "Delaunay triangulation: %d encroached constraints left\n", steiner_max, encroached_number); } g_timer_stop (timer); if (verbose) { gts_surface_print_stats (surface, stderr); fprintf (stderr, "# Triangulation time: %g s speed: %.0f vertex/s\n", g_timer_elapsed (timer, NULL), gts_surface_vertex_number (surface)/g_timer_elapsed (timer, NULL)); } if (check_delaunay && gts_delaunay_check (surface)) { fprintf (stderr, "delaunay: triangulation is not Delaunay\n"); status = 1; /* failure */ } /* write triangulation */ gts_surface_write (surface, stdout); return status; }
/* tri: * Main entry point to using GTS for triangulation. * Input is npt points with x and y coordinates stored either separately * in x[] and y[] (sepArr != 0) or consecutively in x[] (sepArr == 0). * Optionally, the input can include nsegs line segments, whose endpoint * indices are supplied in segs[2*i] and segs[2*i+1] yielding a constrained * triangulation. * * The return value is the corresponding gts surface, which can be queries for * the triangles and line segments composing the triangulation. */ static GtsSurface* tri(double *x, double *y, int npt, int *segs, int nsegs, int sepArr) { int i; GtsSurface *surface; GVertex **vertices = N_GNEW(npt, GVertex *); GtsEdge **edges = N_GNEW(nsegs, GtsEdge*); GSList *list = NULL; GtsVertex *v1, *v2, *v3; GtsTriangle *t; GtsVertexClass *vcl = (GtsVertexClass *) g_vertex_class(); GtsEdgeClass *ecl = GTS_EDGE_CLASS (gts_constraint_class ()); if (sepArr) { for (i = 0; i < npt; i++) { GVertex *p = (GVertex *) gts_vertex_new(vcl, x[i], y[i], 0); p->idx = i; vertices[i] = p; } } else { for (i = 0; i < npt; i++) { GVertex *p = (GVertex *) gts_vertex_new(vcl, x[2*i], x[2*i+1], 0); p->idx = i; vertices[i] = p; } } /* N.B. Edges need to be created here, presumably before the * the vertices are added to the face. In particular, they cannot * be added created and added vi gts_delaunay_add_constraint() below. */ for (i = 0; i < nsegs; i++) { edges[i] = gts_edge_new(ecl, (GtsVertex *) (vertices[ segs[ 2 * i]]), (GtsVertex *) (vertices[ segs[ 2 * i + 1]])); } for (i = 0; i < npt; i++) list = g_slist_prepend(list, vertices[i]); t = gts_triangle_enclosing(gts_triangle_class(), list, 100.); g_slist_free(list); gts_triangle_vertices(t, &v1, &v2, &v3); surface = gts_surface_new(gts_surface_class(), (GtsFaceClass *) g_face_class(), gts_edge_class(), gts_vertex_class()); gts_surface_add_face(surface, gts_face_new(gts_face_class(), t->e1, t->e2, t->e3)); for (i = 0; i < npt; i++) { GtsVertex *v1 = (GtsVertex *) vertices[i]; GtsVertex *v = gts_delaunay_add_vertex(surface, v1, NULL); /* if v != NULL, it is a previously added pt with the same * coordinates as v1, in which case we replace v1 with v */ if (v) { /* agerr (AGWARN, "Duplicate point %d %d\n", i, ((GVertex*)v)->idx); */ gts_vertex_replace (v1, v); } } for (i = 0; i < nsegs; i++) { gts_delaunay_add_constraint(surface,GTS_CONSTRAINT(edges[i])); } /* destroy enclosing triangle */ gts_allow_floating_vertices = TRUE; gts_allow_floating_edges = TRUE; /* gts_object_destroy(GTS_OBJECT(v1)); gts_object_destroy(GTS_OBJECT(v2)); gts_object_destroy(GTS_OBJECT(v3)); */ destroy(v1); destroy(v2); destroy(v3); gts_allow_floating_edges = FALSE; gts_allow_floating_vertices = FALSE; if (nsegs) delaunay_remove_holes(surface); free (edges); free(vertices); return surface; }