Graphviz 13.0.0~dev.20250121.0651
Loading...
Searching...
No Matches
delaunay.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "config.h"
12
13#include <stdbool.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <math.h>
18#include <cgraph/cgraph.h> /* for agerr() and friends */
19#include <neatogen/delaunay.h>
20#include <util/alloc.h>
21#include <util/sort.h>
22
23#ifdef HAVE_GTS
24#include <gts.h>
25
26static int triangle_is_hole(void *triangle, void *ignored) {
27 GtsTriangle *t = triangle;
28 (void)ignored;
29
30 GtsEdge *e1, *e2, *e3;
31 GtsVertex *v1, *v2, *v3;
32
33 gts_triangle_vertices_edges(t, NULL, &v1, &v2, &v3, &e1, &e2, &e3);
34
35 if ((GTS_IS_CONSTRAINT(e1) && GTS_SEGMENT(e1)->v1 != v1) ||
36 (GTS_IS_CONSTRAINT(e2) && GTS_SEGMENT(e2)->v1 != v2) ||
37 (GTS_IS_CONSTRAINT(e3) && GTS_SEGMENT(e3)->v1 != v3))
38 return TRUE;
39
40 return FALSE;
41}
42
43static unsigned delaunay_remove_holes(GtsSurface *surface) {
44 return gts_surface_foreach_face_remove(surface, triangle_is_hole, NULL);
45}
46
47/* Derived classes for vertices and faces so we can assign integer ids
48 * to make it easier to identify them. In particular, this allows the
49 * segments and faces to refer to vertices using the order in which
50 * they were passed in.
51 */
52typedef struct {
53 GtsVertex v;
54 int idx;
55} GVertex;
56
57typedef struct {
58 GtsVertexClass parent_class;
59} GVertexClass;
60
61static GtsVertexClass *g_vertex_class(void) {
62 static GVertexClass *klass = NULL;
63
64 if (klass == NULL) {
65 GtsObjectClassInfo vertex_info = {
66 .name = "GVertex",
67 .object_size = sizeof(GVertex),
68 .class_size = sizeof(GVertexClass),
69 };
70 klass = gts_object_class_new(GTS_OBJECT_CLASS(gts_vertex_class()),
71 &vertex_info);
72 }
73
74 return &klass->parent_class;
75}
76
77typedef struct {
78 GtsFace v;
79 int idx;
80} GFace;
81
82typedef struct {
83 GtsFaceClass parent_class;
84} GFaceClass;
85
86static GtsFaceClass *g_face_class(void) {
87 static GFaceClass *klass = NULL;
88
89 if (klass == NULL) {
90 GtsObjectClassInfo face_info = {
91 .name = "GFace",
92 .object_size = sizeof(GFace),
93 .class_size = sizeof(GFaceClass),
94 };
95 klass = gts_object_class_new(GTS_OBJECT_CLASS(gts_face_class()),
96 &face_info);
97 }
98
99 return &klass->parent_class;
100}
101
102/* destroy:
103 * Destroy each edge using v, then destroy v
104 */
105static void
106destroy (GtsVertex* v)
107{
108 GSList * i;
109
110 i = v->segments;
111 while (i) {
112 GSList * next = i->next;
113 gts_object_destroy (i->data);
114 i = next;
115 }
116 g_assert (v->segments == NULL);
117 gts_object_destroy(GTS_OBJECT(v));
118}
119
120/* tri:
121 * Main entry point to using GTS for triangulation.
122 * Input is npt points with x and y coordinates stored either separately
123 * in x[] and y[] (sepArr != 0) or consecutively in x[] (sepArr == 0).
124 * Optionally, the input can include nsegs line segments, whose endpoint
125 * indices are supplied in segs[2*i] and segs[2*i+1] yielding a constrained
126 * triangulation.
127 *
128 * The return value is the corresponding gts surface, which can be queries for
129 * the triangles and line segments composing the triangulation.
130 */
131static GtsSurface*
132tri(double *x, double *y, int npt, int *segs, int nsegs, int sepArr)
133{
134 int i;
135 GtsSurface *surface;
136 GVertex **vertices = gv_calloc(npt, sizeof(GVertex *));
137 GtsEdge **edges = gv_calloc(nsegs, sizeof(GtsEdge *));
138 GSList *list = NULL;
139 GtsVertex *v1, *v2, *v3;
140 GtsTriangle *t;
141 GtsVertexClass *vcl = g_vertex_class();
142 GtsEdgeClass *ecl = GTS_EDGE_CLASS (gts_constraint_class ());
143
144 if (sepArr) {
145 for (i = 0; i < npt; i++) {
146 GVertex *p = (GVertex *) gts_vertex_new(vcl, x[i], y[i], 0);
147 p->idx = i;
148 vertices[i] = p;
149 }
150 }
151 else {
152 for (i = 0; i < npt; i++) {
153 GVertex *p = (GVertex *) gts_vertex_new(vcl, x[2*i], x[2*i+1], 0);
154 p->idx = i;
155 vertices[i] = p;
156 }
157 }
158
159 /* N.B. Edges need to be created here, presumably before the
160 * the vertices are added to the face. In particular, they cannot
161 * be added created and added vi gts_delaunay_add_constraint() below.
162 */
163 for (i = 0; i < nsegs; i++) {
164 edges[i] = gts_edge_new(ecl,
165 (GtsVertex *)vertices[segs[2 * i]],
166 (GtsVertex *)vertices[segs[2 * i + 1]]);
167 }
168
169 for (i = 0; i < npt; i++)
170 list = g_slist_prepend(list, vertices[i]);
171 t = gts_triangle_enclosing(gts_triangle_class(), list, 100.);
172 g_slist_free(list);
173
174 gts_triangle_vertices(t, &v1, &v2, &v3);
175
176 surface = gts_surface_new(gts_surface_class(), g_face_class(),
177 gts_edge_class(), gts_vertex_class());
178 gts_surface_add_face(surface, gts_face_new(gts_face_class(),
179 t->e1, t->e2, t->e3));
180
181 for (i = 0; i < npt; i++) {
182 GtsVertex *v4 = (GtsVertex *)vertices[i];
183 GtsVertex *v = gts_delaunay_add_vertex(surface, v4, NULL);
184
185 /* if v != NULL, it is a previously added pt with the same
186 * coordinates as v4, in which case we replace v4 with v
187 */
188 if (v && v4 != v) {
189 gts_vertex_replace(v4, v);
190 }
191 }
192
193 for (i = 0; i < nsegs; i++) {
194 gts_delaunay_add_constraint(surface,GTS_CONSTRAINT(edges[i]));
195 }
196
197 /* destroy enclosing triangle */
198 gts_allow_floating_vertices = TRUE;
199 gts_allow_floating_edges = TRUE;
200 destroy(v1);
201 destroy(v2);
202 destroy(v3);
203 gts_allow_floating_edges = FALSE;
204 gts_allow_floating_vertices = FALSE;
205
206 if (nsegs)
207 delaunay_remove_holes(surface);
208
209 free (edges);
210 free(vertices);
211 return surface;
212}
213
214typedef struct {
215 int n;
216 v_data *delaunay;
217} estats;
218
219static int cnt_edge(void *edge, void *stats) {
220 GtsSegment *e = edge;
221 estats *sp = stats;
222
223 sp->n++;
224 if (sp->delaunay) {
225 sp->delaunay[((GVertex*)e->v1)->idx].nedges++;
226 sp->delaunay[((GVertex*)e->v2)->idx].nedges++;
227 }
228
229 return 0;
230}
231
232static void
233edgeStats (GtsSurface* s, estats* sp)
234{
235 gts_surface_foreach_edge(s, cnt_edge, sp);
236}
237
238static int add_edge(void *edge, void *data) {
239 GtsSegment *e = edge;
240 v_data *delaunay = data;
241
242 int source = ((GVertex*)e->v1)->idx;
243 int dest = ((GVertex*)e->v2)->idx;
244
245 delaunay[source].edges[delaunay[source].nedges++] = dest;
246 delaunay[dest].edges[delaunay[dest].nedges++] = source;
247
248 return 0;
249}
250
251static v_data *delaunay_triangulation(double *x, double *y, int n) {
252 GtsSurface* s = tri(x, y, n, NULL, 0, 1);
253 int i, nedges;
254 estats stats;
255
256 if (!s) return NULL;
257
258 v_data *delaunay = gv_calloc(n, sizeof(v_data));
259
260 for (i = 0; i < n; i++) {
261 delaunay[i].ewgts = NULL;
262 delaunay[i].nedges = 1;
263 }
264
265 stats.n = 0;
266 stats.delaunay = delaunay;
267 edgeStats (s, &stats);
268 nedges = stats.n;
269 int *edges = gv_calloc(2 * nedges + n, sizeof(int));
270
271 for (i = 0; i < n; i++) {
272 delaunay[i].edges = edges;
273 edges += delaunay[i].nedges;
274 delaunay[i].edges[0] = i;
275 delaunay[i].nedges = 1;
276 }
277 gts_surface_foreach_edge(s, add_edge, delaunay);
278
279 gts_object_destroy (GTS_OBJECT (s));
280
281 return delaunay;
282}
283
284typedef struct {
285 int n;
286 int* edges;
287} estate;
288
289static int addEdge(void *edge, void *state) {
290 GtsSegment *e = edge;
291 estate *es = state;
292
293 int source = ((GVertex*)e->v1)->idx;
294 int dest = ((GVertex*)e->v2)->idx;
295
296 es->edges[2 * es->n] = source;
297 es->edges[2 * es->n + 1] = dest;
298 es->n += 1;
299
300 return 0;
301}
302
303static int vcmp(const void *x, const void *y, void *values) {
304 const int *a = x;
305 const int *b = y;
306 const double *_vals = values;
307 double va = _vals[*a];
308 double vb = _vals[*b];
309
310 if (va < vb) return -1;
311 if (va > vb) return 1;
312 return 0;
313}
314
315/* delaunay_tri:
316 * Given n points whose coordinates are in the x[] and y[]
317 * arrays, compute a Delaunay triangulation of the points.
318 * The number of edges in the triangulation is returned in pnedges.
319 * The return value itself is an array e of 2*(*pnedges) integers,
320 * with edge i having points whose indices are e[2*i] and e[2*i+1].
321 *
322 * If the points are collinear, GTS fails with 0 edges.
323 * In this case, we sort the points by x coordinates (or y coordinates
324 * if the points form a vertical line). We then return a "triangulation"
325 * consisting of the n-1 pairs of adjacent points.
326 */
327int *delaunay_tri(double *x, double *y, int n, int* pnedges)
328{
329 GtsSurface* s = tri(x, y, n, NULL, 0, 1);
330 int nedges;
331 int* edges;
332 estats stats;
333 estate state;
334
335 if (!s) return NULL;
336
337 stats.n = 0;
338 stats.delaunay = NULL;
339 edgeStats (s, &stats);
340 *pnedges = nedges = stats.n;
341
342 if (nedges) {
343 edges = gv_calloc(2 * nedges, sizeof(int));
344 state.n = 0;
345 state.edges = edges;
346 gts_surface_foreach_edge(s, addEdge, &state);
347 }
348 else {
349 int* vs = gv_calloc(n, sizeof(int));
350 int* ip;
351 int i, hd, tl;
352
353 *pnedges = nedges = n-1;
354 ip = edges = gv_calloc(2 * nedges, sizeof(int));
355
356 for (i = 0; i < n; i++)
357 vs[i] = i;
358
359 gv_sort(vs, n, sizeof(int), vcmp, x[0] == x[1] /* vertical line? */ ? y : x);
360
361 tl = vs[0];
362 for (i = 1; i < n; i++) {
363 hd = vs[i];
364 *ip++ = tl;
365 *ip++ = hd;
366 tl = hd;
367 }
368
369 free (vs);
370 }
371
372 gts_object_destroy (GTS_OBJECT (s));
373
374 return edges;
375}
376
377static int cntFace(void *face, void *data) {
378 GFace *fp = face;
379 int *ip = data;
380
381 fp->idx = *ip;
382 *ip += 1;
383
384 return 0;
385}
386
387typedef struct {
388 GtsSurface* s;
389 int* faces;
390 int* neigh;
391} fstate;
392
393typedef struct {
394 int nneigh;
395 int* neigh;
396} ninfo;
397
398static int addNeighbor(void *face, void *ni) {
399 GFace *f = face;
400 ninfo *es = ni;
401
402 es->neigh[es->nneigh] = f->idx;
403 es->nneigh++;
404
405 return 0;
406}
407
408static int addFace(void *face, void *state) {
409 GFace *f = face;
410 fstate *es = state;
411
412 int i, myid = f->idx;
413 int* ip = es->faces + 3*myid;
414 int* neigh = es->neigh + 3*myid;
415 ninfo ni;
416 GtsVertex *v1, *v2, *v3;
417
418 gts_triangle_vertices (&f->v.triangle, &v1, &v2, &v3);
419 *ip++ = ((GVertex*)v1)->idx;
420 *ip++ = ((GVertex*)v2)->idx;
421 *ip++ = ((GVertex*)v3)->idx;
422
423 ni.nneigh = 0;
424 ni.neigh = neigh;
425 gts_face_foreach_neighbor((GtsFace*)f, 0, addNeighbor, &ni);
426 for (i = ni.nneigh; i < 3; i++)
427 neigh[i] = -1;
428
429 return 0;
430}
431
432static int addTri(void *face, void *state) {
433 GFace *f = face;
434 fstate *es = state;
435
436 int myid = f->idx;
437 int* ip = es->faces + 3*myid;
438 GtsVertex *v1, *v2, *v3;
439
440 gts_triangle_vertices (&f->v.triangle, &v1, &v2, &v3);
441 *ip++ = ((GVertex*)v1)->idx;
442 *ip++ = ((GVertex*)v2)->idx;
443 *ip++ = ((GVertex*)v3)->idx;
444
445 return 0;
446}
447
448/* mkSurface:
449 * Given n points whose coordinates are in x[] and y[], and nsegs line
450 * segments whose end point indices are given in segs, return a surface
451 * corresponding the constrained Delaunay triangulation.
452 * The surface records the line segments, the triangles, and the neighboring
453 * triangles.
454 */
455surface_t*
456mkSurface (double *x, double *y, int n, int* segs, int nsegs)
457{
458 GtsSurface* s = tri(x, y, n, segs, nsegs, 1);
459 estats stats;
460 estate state;
461 fstate statf;
462 int nfaces = 0;
463
464 if (!s) return NULL;
465
466 surface_t *sf = gv_alloc(sizeof(surface_t));
467 stats.n = 0;
468 stats.delaunay = NULL;
469 edgeStats (s, &stats);
470 nsegs = stats.n;
471 segs = gv_calloc(2 * nsegs, sizeof(int));
472
473 state.n = 0;
474 state.edges = segs;
475 gts_surface_foreach_edge(s, addEdge, &state);
476
477 gts_surface_foreach_face(s, cntFace, &nfaces);
478
479 int *faces = gv_calloc(3 * nfaces, sizeof(int));
480 int *neigh = gv_calloc(3 * nfaces, sizeof(int));
481
482 statf.faces = faces;
483 statf.neigh = neigh;
484 gts_surface_foreach_face(s, addFace, &statf);
485
486 sf->nedges = nsegs;
487 sf->edges = segs;
488 sf->nfaces = nfaces;
489 sf->faces = faces;
490 sf->neigh = neigh;
491
492 gts_object_destroy (GTS_OBJECT (s));
493
494 return sf;
495}
496
497/* get_triangles:
498 * Given n points whose coordinates are stored as (x[2*i],x[2*i+1]),
499 * compute a Delaunay triangulation of the points.
500 * The number of triangles in the triangulation is returned in tris.
501 * The return value t is an array of 3*(*tris) integers,
502 * with triangle i having points whose indices are t[3*i], t[3*i+1] and t[3*i+2].
503 */
504int*
505get_triangles (double *x, int n, int* tris)
506{
507 GtsSurface* s;
508 int nfaces = 0;
509 fstate statf;
510
511 if (n <= 2) return NULL;
512
513 s = tri(x, NULL, n, NULL, 0, 0);
514 if (!s) return NULL;
515
516 gts_surface_foreach_face(s, cntFace, &nfaces);
517 statf.faces = gv_calloc(3 * nfaces, sizeof(int));
518 gts_surface_foreach_face(s, addTri, &statf);
519
520 gts_object_destroy (GTS_OBJECT (s));
521
522 *tris = nfaces;
523 return statf.faces;
524}
525
526void
528{
529 free (s->edges);
530 free (s->faces);
531 free (s->neigh);
532 free(s);
533}
534#elif defined(HAVE_TRIANGLE)
535#define TRILIBRARY
536#include <triangle.c>
537#include <assert.h>
538#include <sparse/general.h>
539
540int*
541get_triangles (double *x, int n, int* tris)
542{
543 struct triangulateio mid, vorout;
544 int i;
545
546 if (n <= 2) return NULL;
547
548 struct triangulateio in = {.numberofpoints = n};
549 in.pointlist = gv_calloc(in.numberofpoints * 2, sizeof(REAL));
550
551 for (i = 0; i < n; i++){
552 in.pointlist[i*2] = x[i*2];
553 in.pointlist[i*2 + 1] = x[i*2 + 1];
554 }
555 mid.pointlist = NULL; // Not needed if -N switch used.
556 mid.pointattributelist = NULL;
557 mid.pointmarkerlist = NULL; /* Not needed if -N or -B switch used. */
558 mid.trianglelist = NULL; // Not needed if -E switch used.
559 mid.triangleattributelist = NULL;
560 mid.neighborlist = NULL; // Needed only if -n switch used.
561 mid.segmentlist = NULL;
562 mid.segmentmarkerlist = NULL;
563 mid.edgelist = NULL; // Needed only if -e switch used.
564 mid.edgemarkerlist = NULL; // Needed if -e used and -B not used.
565 vorout.pointlist = NULL; // Needed only if -v switch used.
566 vorout.pointattributelist = NULL;
567 vorout.edgelist = NULL; // Needed only if -v switch used.
568 vorout.normlist = NULL; // Needed only if -v switch used.
569
570 /* Triangulate the points. Switches are chosen to read and write a */
571 /* PSLG (p), preserve the convex hull (c), number everything from */
572 /* zero (z), assign a regional attribute to each element (A), and */
573 /* produce an edge list (e), a Voronoi diagram (v), and a triangle */
574 /* neighbor list (n). */
575
576 triangulate("Qenv", &in, &mid, &vorout);
577 assert (mid.numberofcorners == 3);
578
579 *tris = mid.numberoftriangles;
580
581 free(in.pointlist);
582 free(in.pointattributelist);
583 free(in.pointmarkerlist);
584 free(in.regionlist);
585 free(mid.pointlist);
586 free(mid.pointattributelist);
587 free(mid.pointmarkerlist);
588 free(mid.triangleattributelist);
589 free(mid.neighborlist);
590 free(mid.segmentlist);
591 free(mid.segmentmarkerlist);
592 free(mid.edgelist);
593 free(mid.edgemarkerlist);
594 free(vorout.pointlist);
595 free(vorout.pointattributelist);
596 free(vorout.edgelist);
597 free(vorout.normlist);
598
599 return mid.trianglelist;
600}
601
602// maybe it should be replaced by RNG - relative neighborhood graph, or by GG - gabriel graph
603int*
604delaunay_tri (double *x, double *y, int n, int* nedges)
605{
606 int i;
607
608 struct triangulateio in = {
609 .numberofpoints = n,
610 .pointlist = gv_calloc(2 * n, sizeof(REAL))
611 };
612 for (i = 0; i < n; i++) {
613 in.pointlist[2 * i] = x[i];
614 in.pointlist[2 * i + 1] = y[i];
615 }
616
617 struct triangleio out = {.numberofpoints = n};
618
619 triangulate("zQNEeB", &in, &out, NULL);
620
621 *nedges = out.numberofedges;
622 free (in.pointlist);
623 free (in.pointattributelist);
624 free (in.pointmarkerlist);
625 free (in.trianglearealist);
626 free (in.triangleattributelist);
627 free (in.neighborlist);
628 free (in.segmentlist);
629 free (in.segmentmarkerlist);
630 free (in.holelist);
631 free (in.regionlist);
632 free (in.edgemarkerlist);
633 free (in.normlist);
634 free (out.pointattributelist);
635 free (out.pointmarkerlist);
636 free (out.trianglearealist);
637 free (out.triangleattributelist);
638 free (out.neighborlist);
639 free (out.segmentlist);
640 free (out.segmentmarkerlist);
641 free (out.holelist);
642 free (out.regionlist);
643 free (out.edgemarkerlist);
644 free (out.normlist);
645 return out.edgelist;
646}
647
648static v_data *delaunay_triangulation(double *x, double *y, int n) {
649 int nedges;
650 int source, dest;
651 int* edgelist = delaunay_tri (x, y, n, &nedges);
652 int i;
653
654 v_data *delaunay = gv_calloc(n, sizeof(v_data));
655 int *edges = gv_calloc(2 * nedges + n, sizeof(int));
656
657 for (i = 0; i < n; i++) {
658 delaunay[i].ewgts = NULL;
659 delaunay[i].nedges = 1;
660 }
661
662 for (i = 0; i < 2 * nedges; i++)
663 delaunay[edgelist[i]].nedges++;
664
665 for (i = 0; i < n; i++) {
666 delaunay[i].edges = edges;
667 edges += delaunay[i].nedges;
668 delaunay[i].edges[0] = i;
669 delaunay[i].nedges = 1;
670 }
671 for (i = 0; i < nedges; i++) {
672 source = edgelist[2 * i];
673 dest = edgelist[2 * i + 1];
674 delaunay[source].edges[delaunay[source].nedges++] = dest;
675 delaunay[dest].edges[delaunay[dest].nedges++] = source;
676 }
677
678 free(edgelist);
679 return delaunay;
680}
681
682surface_t*
683mkSurface (double *x, double *y, int n, int* segs, int nsegs)
684{
685 agerrorf("mkSurface not yet implemented using Triangle library\n");
686 assert (0);
687 return 0;
688}
689void
691{
692 agerrorf("freeSurface not yet implemented using Triangle library\n");
693 assert (0);
694}
695#else
696static char* err = "Graphviz built without any triangulation library\n";
697int* get_triangles (double *x, int n, int* tris)
698{
699 (void)x;
700 (void)n;
701 (void)tris;
702
703 agerrorf("get_triangles: %s\n", err);
704 return 0;
705}
706static v_data *delaunay_triangulation(double *x, double *y, int n) {
707 (void)x;
708 (void)y;
709 (void)n;
710
711 agerrorf("delaunay_triangulation: %s\n", err);
712 return 0;
713}
714int *delaunay_tri(double *x, double *y, int n, int* nedges)
715{
716 (void)x;
717 (void)y;
718 (void)n;
719 (void)nedges;
720
721 agerrorf("delaunay_tri: %s\n", err);
722 return 0;
723}
724surface_t*
725mkSurface (double *x, double *y, int n, int* segs, int nsegs)
726{
727 (void)x;
728 (void)y;
729 (void)n;
730 (void)segs;
731 (void)nsegs;
732
733 agerrorf("mkSurface: %s\n", err);
734 return 0;
735}
736void
738{
739 (void)s;
740
741 agerrorf("freeSurface: %s\n", err);
742}
743#endif
744
745static void remove_edge(v_data * graph, int source, int dest)
746{
747 int i;
748 for (i = 1; i < graph[source].nedges; i++) {
749 if (graph[source].edges[i] == dest) {
750 graph[source].edges[i] = graph[source].edges[--graph[source].nedges];
751 break;
752 }
753 }
754}
755
756v_data *UG_graph(double *x, double *y, int n) {
757 v_data *delaunay;
758 int i;
759 double dist_ij, dist_ik, dist_jk, x_i, y_i, x_j, y_j;
760 int j, k, neighbor_j, neighbor_k;
761
762 if (n == 2) {
763 int *edges = gv_calloc(4, sizeof(int));
764 delaunay = gv_calloc(n, sizeof(v_data));
765 delaunay[0].ewgts = NULL;
766 delaunay[0].edges = edges;
767 delaunay[0].nedges = 2;
768 delaunay[0].edges[0] = 0;
769 delaunay[0].edges[1] = 1;
770 delaunay[1].edges = edges + 2;
771 delaunay[1].ewgts = NULL;
772 delaunay[1].nedges = 2;
773 delaunay[1].edges[0] = 1;
774 delaunay[1].edges[1] = 0;
775 return delaunay;
776 } else if (n == 1) {
777 int *edges = gv_calloc(1, sizeof(int));
778 delaunay = gv_calloc(n, sizeof(v_data));
779 delaunay[0].ewgts = NULL;
780 delaunay[0].edges = edges;
781 delaunay[0].nedges = 1;
782 delaunay[0].edges[0] = 0;
783 return delaunay;
784 }
785
786 delaunay = delaunay_triangulation(x, y, n);
787
788 // remove all edges v-u if there is w, neighbor of u or v, that is closer to both u and v than dist(u,v)
789 for (i = 0; i < n; i++) {
790 x_i = x[i];
791 y_i = y[i];
792 for (j = 1; j < delaunay[i].nedges;) {
793 neighbor_j = delaunay[i].edges[j];
794 x_j = x[neighbor_j];
795 y_j = y[neighbor_j];
796 dist_ij = (x_j - x_i) * (x_j - x_i) + (y_j - y_i) * (y_j - y_i);
797 // now look at i'th neighbors to see whether there is a node in the "forbidden region"
798 // we will also go through neighbor_j's neighbors when we traverse the edge from its other side
799 bool removed = false;
800 for (k = 1; k < delaunay[i].nedges && !removed; k++) {
801 neighbor_k = delaunay[i].edges[k];
802 dist_ik = (x[neighbor_k] - x_i) * (x[neighbor_k] - x_i) +
803 (y[neighbor_k] - y_i) * (y[neighbor_k] - y_i);
804 if (dist_ik < dist_ij) {
805 dist_jk = (x[neighbor_k] - x_j) * (x[neighbor_k] - x_j) +
806 (y[neighbor_k] - y_j) * (y[neighbor_k] - y_j);
807 if (dist_jk < dist_ij) {
808 // remove the edge beteween i and neighbor j
809 delaunay[i].edges[j] = delaunay[i].edges[--delaunay[i].nedges];
810 remove_edge(delaunay, neighbor_j, i);
811 removed = true;
812 }
813 }
814 }
815 if (!removed) {
816 j++;
817 }
818 }
819 }
820 return delaunay;
821}
822
824{
825 if (graph != NULL) {
826 free(graph[0].edges);
827 free(graph[0].ewgts);
828 free(graph);
829 }
830}
831
833{
834 if (graph != NULL) {
835 free(graph[0].edges);
836 free(graph[0].ewgts);
837#ifdef DIGCOLA
838 free(graph[0].edists);
839#endif
840 free(graph);
841 }
842}
843
static void out(agerrlevel_t level, const char *fmt, va_list args)
Report messages using a user-supplied or default write function.
Definition agerror.c:84
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
static void * gv_alloc(size_t size)
Definition alloc.h:47
abstract graph C library, Cgraph API
int * get_triangles(double *x, int n, int *tris)
Definition delaunay.c:697
void freeGraph(v_data *graph)
Definition delaunay.c:823
v_data * UG_graph(double *x, double *y, int n)
Definition delaunay.c:756
void freeGraphData(vtx_data *graph)
Definition delaunay.c:832
static char * err
Definition delaunay.c:696
static v_data * delaunay_triangulation(double *x, double *y, int n)
Definition delaunay.c:706
surface_t * mkSurface(double *x, double *y, int n, int *segs, int nsegs)
Definition delaunay.c:725
static void remove_edge(v_data *graph, int source, int dest)
Definition delaunay.c:745
int * delaunay_tri(double *x, double *y, int n, int *nedges)
Definition delaunay.c:714
void freeSurface(surface_t *s)
Definition delaunay.c:737
void add_edge(edgelist *list, Agedge_t *e)
Definition edgelist.c:57
#define REAL
Definition gmlparse.c:374
void free(void *)
edge
Definition gmlparse.y:240
node NULL
Definition grammar.y:163
void agerrorf(const char *fmt,...)
Definition agerror.c:165
Agraph_t * graph(char *name)
Definition gv.cpp:30
static void addEdge(edge_t *de, edge_t *e)
Definition layout.c:349
struct _tri tri
static tri * addTri(int i, int j, tri *oldp)
static int nedges
total no. of edges used in routing
Definition routespl.c:31
static int triangulate(pointnlink_t **, size_t)
Definition shortest.c:318
static triangles_t tris
Definition shortest.c:55
qsort with carried along context
static void gv_sort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *, void *), void *arg)
qsort with an extra state parameter, ala qsort_r
Definition sort.h:35
Definition legal.c:50
Definition cdt.h:100
int nedges
Definition delaunay.h:16
int * edges
Definition delaunay.h:17
int * faces
Definition delaunay.h:19
int nfaces
Definition delaunay.h:18
int * neigh
Definition delaunay.h:20
int nedges
Definition sparsegraph.h:22
int * edges
Definition sparsegraph.h:23
float * ewgts
Definition sparsegraph.h:24
Definition grammar.c:93