Bug Summary

File:chull.c
Warning:line 714, column 9
Access to field 'next' results in a dereference of a null pointer (loaded from variable 'faces')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple arm64-apple-macosx14.0.0 -Wundef-prefix=TARGET_OS_ -Werror=undef-prefix -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name chull.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=osx -analyzer-checker=security.insecureAPI.decodeValueOfObjCType -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=non-leaf -ffp-contract=on -fno-rounding-math -funwind-tables=1 -target-sdk-version=15.0 -fcompatibility-qualified-id-block-type-checking -fvisibility-inlines-hidden-static-local-var -fbuiltin-headers-in-system-modules -fdefine-target-os-macros -target-cpu apple-m1 -target-feature +zcm -target-feature +zcz -target-feature +v8.5a -target-feature +aes -target-feature +crc -target-feature +dotprod -target-feature +complxnum -target-feature +fp-armv8 -target-feature +fullfp16 -target-feature +fp16fml -target-feature +jsconv -target-feature +lse -target-feature +pauth -target-feature +ras -target-feature +rcpc -target-feature +rdm -target-feature +sha2 -target-feature +sha3 -target-feature +neon -target-abi darwinpcs -debugger-tuning=lldb -fdebug-compilation-dir=/Users/nicklas/dev/grass/vector/v.hull -target-linker-version 1022.1 -fcoverage-compilation-dir=/Users/nicklas/dev/grass/vector/v.hull -resource-dir /opt/local/libexec/llvm-18/lib/clang/18 -isystem /opt/local/include -isystem /opt/local/include/libomp -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -I /opt/local/include -I /opt/local/include -D _FORTIFY_SOURCE=3 -D GL_SILENCE_DEPRECATION -I /Users/nicklas/dev/grass/dist.aarch64-apple-darwin23.6.0/include -I /Users/nicklas/dev/grass/dist.aarch64-apple-darwin23.6.0/include -I /opt/local/include -I /opt/local/include -D PACKAGE="grassmods" -I /opt/local/include/postgresql16 -I /Users/nicklas/dev/grass/dist.aarch64-apple-darwin23.6.0/include -I /Users/nicklas/dev/grass/dist.aarch64-apple-darwin23.6.0/include -D RELDIR="vector/v.hull" -I/usr/local/include -internal-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/local/include -internal-isystem /opt/local/libexec/llvm-18/lib/clang/18/include -internal-externc-isystem /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include -O0 -Wno-error=strict-prototypes -std=c11 -ferror-limit 19 -stack-protector 1 -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fmax-type-align=16 -analyzer-output=html -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/folders/41/b45_b8253jn3rxtr4cd0bd7c0000gn/T/scan-build-2024-10-16-105627-63060-1 -x c chull.c
1/*
2 This code is described in "Computational Geometry in C" (Second Edition),
3 Chapter 4. It is not written to be comprehensible without the
4 explanation in that book.
5
6 Input: 3n integer coordinates for the points.
7 Output: the 3D convex hull, in postscript with embedded comments
8 showing the vertices and faces.
9
10 Compile: gcc -o chull chull.c
11
12 Written by Joseph O'Rourke, with contributions by
13 Kristy Anderson, John Kutcher, Catherine Schevon, Susan Weller.
14 Last modified: March 1998
15 Questions to orourke@cs.smith.edu.
16 --------------------------------------------------------------------
17 This code is Copyright 1998 by Joseph O'Rourke. It may be freely
18 redistributed in its entirety provided that this copyright notice is
19 not removed.
20 --------------------------------------------------------------------
21 */
22#include <stdio.h>
23#include <stdlib.h>
24#include <math.h>
25
26#include <grass/gis.h>
27#include <grass/vector.h>
28#include <grass/glocale.h>
29
30#include "globals.h"
31
32/* Define vertex indices. */
33#define X0 0
34#define Y1 1
35#define Z2 2
36
37/* Define structures for vertices, edges and faces */
38typedef struct tVertexStructure tsVertex;
39typedef tsVertex *tVertex;
40
41typedef struct tEdgeStructure tsEdge;
42typedef tsEdge *tEdge;
43
44typedef struct tFaceStructure tsFace;
45typedef tsFace *tFace;
46
47struct tVertexStructure {
48 double v[3];
49 int vnum;
50 tEdge duplicate; /* pointer to incident cone edge (or NULL) */
51 bool_Bool onhull; /* T iff point on hull. */
52 bool_Bool mark; /* T iff point already processed. */
53 tVertex next, prev;
54};
55
56struct tEdgeStructure {
57 tFace adjface[2];
58 tVertex endpts[2];
59 tFace newface; /* pointer to incident cone face. */
60 bool_Bool delete; /* T iff edge should be delete. */
61 tEdge next, prev;
62};
63
64struct tFaceStructure {
65 tEdge edge[3];
66 tVertex vertex[3];
67 bool_Bool visible; /* T iff face visible from new point. */
68 tFace next, prev;
69};
70
71/* Define flags */
72#define ONHULL1 true1
73#define REMOVED1 true1
74#define VISIBLE1 true1
75#define PROCESSED1 true1
76
77/* Global variable definitions */
78tVertex vertices = NULL((void*)0);
79tEdge edges = NULL((void*)0);
80tFace faces = NULL((void*)0);
81
82/* Function declarations */
83tVertex MakeNullVertex(void);
84void ReadVertices(double *px, double *py, double *pz, int num_points);
85void writeVertices(struct Map_info *Map);
86int DoubleTriangle(void);
87void ConstructHull(void);
88bool_Bool AddOne(tVertex p);
89int VolumeSign(tFace f, tVertex p);
90tFace MakeConeFace(tEdge e, tVertex p);
91void MakeCcw(tFace f, tEdge e, tVertex p);
92tEdge MakeNullEdge(void);
93tFace MakeNullFace(void);
94tFace MakeFace(tVertex v0, tVertex v1, tVertex v2, tFace f);
95void CleanUp(void);
96void CleanEdges(void);
97void CleanFaces(void);
98void CleanVertices(void);
99bool_Bool Collinear(tVertex a, tVertex b, tVertex c);
100
101#include "macros.h"
102
103/*
104
105 Release all memory allocated for edges, faces and vertices
106
107 */
108void freeMem(void)
109{
110 tEdge e; /* Primary index into edge list. */
111 tFace f; /* Primary pointer into face list. */
112 tVertex v;
113 tEdge te; /* Temporary edge pointer. */
114 tFace tf; /* Temporary face pointer. */
115 tVertex tv; /* Temporary vertex pointer. */
116
117 e = edges;
118 do {
119 te = e;
120 e = e->next;
121 DELETE(edges, te)if (edges) { if (edges == edges->next) edges = ((void*)0);
else if (te == edges) edges = edges->next; te->next->
prev = te->prev; te->prev->next = te->next; if (te
) { free((char *)te); te = ((void*)0); }; }
;
122 } while (e != edges);
123
124 f = faces;
125 do {
126 tf = f;
127 f = f->next;
128 DELETE(faces, tf)if (faces) { if (faces == faces->next) faces = ((void*)0);
else if (tf == faces) faces = faces->next; tf->next->
prev = tf->prev; tf->prev->next = tf->next; if (tf
) { free((char *)tf); tf = ((void*)0); }; }
;
129 } while (f != faces);
130
131 v = vertices;
132 do {
133 tv = v;
134 v = v->next;
135 DELETE(vertices, tv)if (vertices) { if (vertices == vertices->next) vertices =
((void*)0); else if (tv == vertices) vertices = vertices->
next; tv->next->prev = tv->prev; tv->prev->next
= tv->next; if (tv) { free((char *)tv); tv = ((void*)0); }
; }
;
136 } while (v != vertices);
137
138 FREE(te)if (te) { free((char *)te); te = ((void*)0); };
139 FREE(tf)if (tf) { free((char *)tf); tf = ((void*)0); };
140 FREE(tv)if (tv) { free((char *)tv); tv = ((void*)0); };
141
142 DELETE(edges, e)if (edges) { if (edges == edges->next) edges = ((void*)0);
else if (e == edges) edges = edges->next; e->next->
prev = e->prev; e->prev->next = e->next; if (e) {
free((char *)e); e = ((void*)0); }; }
;
143 DELETE(faces, f)if (faces) { if (faces == faces->next) faces = ((void*)0);
else if (f == faces) faces = faces->next; f->next->
prev = f->prev; f->prev->next = f->next; if (f) {
free((char *)f); f = ((void*)0); }; }
;
144 DELETE(vertices, v)if (vertices) { if (vertices == vertices->next) vertices =
((void*)0); else if (v == vertices) vertices = vertices->
next; v->next->prev = v->prev; v->prev->next =
v->next; if (v) { free((char *)v); v = ((void*)0); }; }
;
145
146 FREE(edges)if (edges) { free((char *)edges); edges = ((void*)0); };
147 FREE(faces)if (faces) { free((char *)faces); faces = ((void*)0); };
148 FREE(vertices)if (vertices) { free((char *)vertices); vertices = ((void*)0)
; }
;
149}
150
151/*-------------------------------------------------------------------*/
152int make3DHull(double *px, double *py, double *pz, int num_points,
153 struct Map_info *Map)
154{
155 int error;
156
157 ReadVertices(px, py, pz, num_points);
158
159 error = DoubleTriangle();
160 if (error
0.1
'error' is >= 0
< 0) {
1
Taking false branch
161 G_fatal_error("All points of 3D input map are in the same plane.\n "
162 "Cannot create a 3D hull.");
163 }
164
165 ConstructHull();
2
Calling 'ConstructHull'
166
167 writeVertices(Map);
168
169 freeMem();
170
171 return (0);
172}
173
174/*---------------------------------------------------------------------
175MakeNullVertex: Makes a vertex, nulls out fields.
176---------------------------------------------------------------------*/
177tVertex MakeNullVertex(void)
178{
179 tVertex v;
180
181 NEW(v, tsVertex)if ((v = (tsVertex *)malloc(sizeof(tsVertex))) == ((void*)0))
{ printf("Out of Memory!\n"); exit(0); }
;
182 v->duplicate = NULL((void*)0);
183 v->onhull = !ONHULL1;
184 v->mark = !PROCESSED1;
185 ADD(vertices, v)if (vertices) { v->next = vertices; v->prev = vertices->
prev; vertices->prev = v; v->prev->next = v; } else {
vertices = v; vertices->next = vertices->prev = v; }
;
186
187 return v;
188}
189
190/*---------------------------------------------------------------------
191ReadVertices: Reads in the vertices, and links them into a circular
192list with MakeNullVertex. There is no need for the # of vertices to be
193the first line: the function looks for EOF instead. Sets the global
194variable vertices via the ADD macro.
195---------------------------------------------------------------------*/
196void ReadVertices(double *px, double *py, double *pz, int num_points)
197{
198 tVertex v;
199 int vnum = 0;
200 int i;
201
202 G_important_message(_("Reading 3D vertices...")G_gettext("grassmods", ("Reading 3D vertices...")));
203 for (i = 0; i < num_points; i++) {
204 v = MakeNullVertex();
205 v->v[X0] = px[i];
206 v->v[Y1] = py[i];
207 v->v[Z2] = pz[i];
208 v->vnum = vnum++;
209 G_percent(i, (num_points - 1), 1);
210 }
211 fflush(stdout__stdoutp);
212}
213
214/*---------------------------------------------------------------------
215Outputs the 3D triangles to a GRASS 3d vector map.
216---------------------------------------------------------------------*/
217void writeVertices(struct Map_info *Map)
218{
219 /* Pointers to vertices, edges, faces. */
220 tFace f;
221 double *px, *py, *pz;
222 double fx, fy, fz;
223 double kx, ky, kz;
224
225 long int cat, num_faces;
226
227 struct line_pnts *Points;
228 struct line_cats *Cats;
229
230 Points = Vect_new_line_struct();
231 Cats = Vect_new_cats_struct();
232
233 px = G_malloc(sizeof(double) * 4)G__malloc("vector/v.hull" "/" "chull.c", 233, (sizeof(double)
* 4))
;
234 py = G_malloc(sizeof(double) * 4)G__malloc("vector/v.hull" "/" "chull.c", 234, (sizeof(double)
* 4))
;
235 pz = G_malloc(sizeof(double) * 4)G__malloc("vector/v.hull" "/" "chull.c", 235, (sizeof(double)
* 4))
;
236
237 f = faces;
238 num_faces = 0;
239 cat = 0;
240 kx = 0.0;
241 ky = 0.0;
242 kz = 0.0;
243
244 G_message("Writing faces and kernel to output map ...");
245
246 do {
247
248 num_faces++;
249
250 /* write one triangular face */
251 px[0] = ((double)(f->vertex[0]->v[X0]));
252 py[0] = ((double)(f->vertex[0]->v[Y1]));
253 pz[0] = ((double)(f->vertex[0]->v[Z2]));
254
255 px[1] = ((double)(f->vertex[1]->v[X0]));
256 py[1] = ((double)(f->vertex[1]->v[Y1]));
257 pz[1] = ((double)(f->vertex[1]->v[Z2]));
258
259 px[2] = ((double)(f->vertex[2]->v[X0]));
260 py[2] = ((double)(f->vertex[2]->v[Y1]));
261 pz[2] = ((double)(f->vertex[2]->v[Z2]));
262
263 px[3] = ((double)(f->vertex[0]->v[X0]));
264 py[3] = ((double)(f->vertex[0]->v[Y1]));
265 pz[3] = ((double)(f->vertex[0]->v[Z2]));
266
267 /* kernel position: 1st get 3D center of this face */
268 fx = (px[0] + px[1] + px[2]) / 3.0;
269 fy = (py[0] + py[1] + py[2]) / 3.0;
270 fz = (pz[0] + pz[1] + pz[2]) / 3.0;
271
272 /* kernel position: now add this to kernel coordinates */
273 kx = kx + fx;
274 ky = ky + fy;
275 kz = kz + fz;
276
277 /* write out face */
278 Vect_copy_xyz_to_pnts(Points, px, py, pz, 4);
279 cat++;
280 Vect_cat_set(Cats, 1, cat);
281 Vect_write_line(Map, GV_FACE0x10, Points, Cats);
282
283 f = f->next;
284
285 } while (f != faces);
286
287 /* write kernel for the center of the whole hull */
288 kx = kx / num_faces;
289 ky = ky / num_faces;
290 kz = kz / num_faces;
291 Vect_cat_set(Cats, 1, cat + 1);
292 Vect_copy_xyz_to_pnts(Points, &kx, &ky, &kz, 1);
293 Vect_write_line(Map, GV_KERNEL0x20, Points, Cats);
294
295 Vect_destroy_line_struct(Points);
296
297 fflush(stdout__stdoutp);
298
299 G_free(px);
300 G_free(py);
301 G_free(pz);
302}
303
304/*---------------------------------------------------------------------
305 DoubleTriangle builds the initial double triangle. It first finds 3
306 noncollinear points and makes two faces out of them, in opposite order.
307 It then finds a fourth point that is not coplanar with that face. The
308 vertices are stored in the face structure in counterclockwise order so
309 that the volume between the face and the point is negative. Lastly, the
310 3 newfaces to the fourth point are constructed and the data structures
311 are cleaned up.
312---------------------------------------------------------------------*/
313
314/* RETURN: 0 if OK */
315/* -1 if all points collinear */
316/* -2 if all points coplanar */
317
318int DoubleTriangle(void)
319{
320 tVertex v0, v1, v2, v3;
321 tFace f0, f1 = NULL((void*)0);
322 long int vol;
323
324 /* Find 3 noncollinear points. */
325 v0 = vertices;
326 while (Collinear(v0, v0->next, v0->next->next)) {
327 if ((v0 = v0->next) == vertices) {
328 G_warning("DoubleTriangle: All points are collinear!\n");
329 return (-1);
330 }
331 }
332 v1 = v0->next;
333 v2 = v1->next;
334
335 /* Mark the vertices as processed. */
336 v0->mark = PROCESSED1;
337 v1->mark = PROCESSED1;
338 v2->mark = PROCESSED1;
339
340 /* Create the two "twin" faces. */
341 f0 = MakeFace(v0, v1, v2, f1);
342 f1 = MakeFace(v2, v1, v0, f0);
343
344 /* Link adjacent face fields. */
345 f0->edge[0]->adjface[1] = f1;
346 f0->edge[1]->adjface[1] = f1;
347 f0->edge[2]->adjface[1] = f1;
348 f1->edge[0]->adjface[1] = f0;
349 f1->edge[1]->adjface[1] = f0;
350 f1->edge[2]->adjface[1] = f0;
351
352 /* Find a fourth, noncoplanar point to form tetrahedron. */
353 v3 = v2->next;
354 vol = VolumeSign(f0, v3);
355 while (!vol) {
356 if ((v3 = v3->next) == v0) {
357 G_warning("DoubleTriangle: All points are coplanar!\n");
358 return (-2);
359 }
360 vol = VolumeSign(f0, v3);
361 }
362
363 /* Insure that v3 will be the first added. */
364 vertices = v3;
365
366 return (0);
367}
368
369/*---------------------------------------------------------------------
370ConstructHull adds the vertices to the hull one at a time. The hull
371vertices are those in the list marked as onhull.
372---------------------------------------------------------------------*/
373void ConstructHull(void)
374{
375 tVertex v, vnext;
376
377 /* bool changed; */ /* T if addition changes hull; not used. */
378 int i;
379 int numVertices;
380
381 G_important_message(_("Constructing 3D hull...")G_gettext("grassmods", ("Constructing 3D hull...")));
382
383 v = vertices;
384 i = 0;
385 do {
4
Loop condition is false. Exiting loop
386 vnext = v->next;
387 v = vnext;
388 i++;
389 } while (v != vertices);
3
Assuming 'v' is equal to 'vertices'
390 numVertices = i;
391
392 v = vertices;
393 i = 0;
394 do {
395 vnext = v->next;
396 if (!v->mark) {
5
Assuming field 'mark' is false
6
Taking true branch
397 v->mark = PROCESSED1;
398 /* changed = */ AddOne(v);
7
Calling 'AddOne'
12
Returning from 'AddOne'
399 CleanUp();
13
Calling 'CleanUp'
400 }
401 v = vnext;
402 i++;
403
404 G_percent(i, numVertices, 1);
405
406 } while (v != vertices);
407
408 fflush(stdout__stdoutp);
409}
410
411/*---------------------------------------------------------------------
412AddOne is passed a vertex. It first determines all faces visible from
413that point. If none are visible then the point is marked as not
414onhull. Next is a loop over edges. If both faces adjacent to an edge
415are visible, then the edge is marked for deletion. If just one of the
416adjacent faces is visible then a new face is constructed.
417---------------------------------------------------------------------*/
418bool_Bool AddOne(tVertex p)
419{
420 tFace f;
421 tEdge e, temp;
422 long int vol;
423 bool_Bool vis = false0;
424
425 /* Mark faces visible from p. */
426 f = faces;
427 do {
10
Loop condition is false. Exiting loop
428 vol = VolumeSign(f, p);
429
430 if (vol
7.1
'vol' is >= 0
< 0) {
8
Taking false branch
431 f->visible = VISIBLE1;
432 vis = true1;
433 }
434 f = f->next;
435 } while (f != faces);
9
Assuming 'f' is equal to 'faces'
436
437 /* If no faces are visible from p, then p is inside the hull. */
438 if (!vis
10.1
'vis' is false
) {
11
Taking true branch
439 p->onhull = !ONHULL1;
440 return false0;
441 }
442
443 /* Mark edges in interior of visible region for deletion.
444 Erect a newface based on each border edge. */
445 e = edges;
446 do {
447 temp = e->next;
448 if (e->adjface[0]->visible && e->adjface[1]->visible)
449 /* e interior: mark for deletion. */
450 e->delete = REMOVED1;
451 else if (e->adjface[0]->visible || e->adjface[1]->visible)
452 /* e border: make a new face. */
453 e->newface = MakeConeFace(e, p);
454 e = temp;
455 } while (e != edges);
456 return true1;
457}
458
459/*---------------------------------------------------------------------
460VolumeSign returns the sign of the volume of the tetrahedron determined by f
461and p. VolumeSign is +1 iff p is on the negative side of f,
462where the positive side is determined by the rh-rule. So the volume
463is positive if the ccw normal to f points outside the tetrahedron.
464The final fewer-multiplications form is due to Bob Williamson.
465---------------------------------------------------------------------*/
466int VolumeSign(tFace f, tVertex p)
467{
468 double vol;
469 double ax, ay, az, bx, by, bz, cx, cy, cz;
470
471 ax = f->vertex[0]->v[X0] - p->v[X0];
472 ay = f->vertex[0]->v[Y1] - p->v[Y1];
473 az = f->vertex[0]->v[Z2] - p->v[Z2];
474 bx = f->vertex[1]->v[X0] - p->v[X0];
475 by = f->vertex[1]->v[Y1] - p->v[Y1];
476 bz = f->vertex[1]->v[Z2] - p->v[Z2];
477 cx = f->vertex[2]->v[X0] - p->v[X0];
478 cy = f->vertex[2]->v[Y1] - p->v[Y1];
479 cz = f->vertex[2]->v[Z2] - p->v[Z2];
480
481 vol = ax * (by * cz - bz * cy) + ay * (bz * cx - bx * cz) +
482 az * (bx * cy - by * cx);
483
484 /* The volume should be an integer. */
485 if (vol > 0.0)
486 return 1;
487 else if (vol < -0.0)
488 return -1;
489 else
490 return 0;
491}
492
493/*---------------------------------------------------------------------
494MakeConeFace makes a new face and two new edges between the
495edge and the point that are passed to it. It returns a pointer to
496the new face.
497---------------------------------------------------------------------*/
498tFace MakeConeFace(tEdge e, tVertex p)
499{
500 tEdge new_edge[2];
501 tFace new_face;
502 int i, j;
503
504 /* Make two new edges (if don't already exist). */
505 for (i = 0; i < 2; ++i)
506 /* If the edge exists, copy it into new_edge. */
507 if (!(new_edge[i] = e->endpts[i]->duplicate)) {
508 /* Otherwise (duplicate is NULL), MakeNullEdge. */
509 new_edge[i] = MakeNullEdge();
510 new_edge[i]->endpts[0] = e->endpts[i];
511 new_edge[i]->endpts[1] = p;
512 e->endpts[i]->duplicate = new_edge[i];
513 }
514
515 /* Make the new face. */
516 new_face = MakeNullFace();
517 new_face->edge[0] = e;
518 new_face->edge[1] = new_edge[0];
519 new_face->edge[2] = new_edge[1];
520 MakeCcw(new_face, e, p);
521
522 /* Set the adjacent face pointers. */
523 for (i = 0; i < 2; ++i)
524 for (j = 0; j < 2; ++j)
525 /* Only one NULL link should be set to new_face. */
526 if (!new_edge[i]->adjface[j]) {
527 new_edge[i]->adjface[j] = new_face;
528 break;
529 }
530
531 return new_face;
532}
533
534/*---------------------------------------------------------------------
535MakeCcw puts the vertices in the face structure in counterclock wise
536order. We want to store the vertices in the same
537order as in the visible face. The third vertex is always p.
538---------------------------------------------------------------------*/
539void MakeCcw(tFace f, tEdge e, tVertex p)
540{
541 tFace fv; /* The visible face adjacent to e */
542 int i; /* Index of e->endpoint[0] in fv. */
543 tEdge s; /* Temporary, for swapping */
544
545 if (e->adjface[0]->visible)
546 fv = e->adjface[0];
547 else
548 fv = e->adjface[1];
549
550 /* Set vertex[0] & [1] of f to have the same orientation
551 as do the corresponding vertices of fv. */
552 for (i = 0; fv->vertex[i] != e->endpts[0]; ++i)
553 ;
554 /* Orient f the same as fv. */
555 if (fv->vertex[(i + 1) % 3] != e->endpts[1]) {
556 f->vertex[0] = e->endpts[1];
557 f->vertex[1] = e->endpts[0];
558 }
559 else {
560 f->vertex[0] = e->endpts[0];
561 f->vertex[1] = e->endpts[1];
562 SWAP(s, f->edge[1], f->edge[2]){ s = f->edge[1]; f->edge[1] = f->edge[2]; f->edge
[2] = s; }
;
563 }
564 /* This swap is tricky. e is edge[0]. edge[1] is based on endpt[0],
565 edge[2] on endpt[1]. So if e is oriented "forwards," we
566 need to move edge[1] to follow [0], because it precedes. */
567
568 f->vertex[2] = p;
569}
570
571/*---------------------------------------------------------------------
572MakeNullEdge creates a new cell and initializes all pointers to NULL
573and sets all flags to off. It returns a pointer to the empty cell.
574---------------------------------------------------------------------*/
575tEdge MakeNullEdge(void)
576{
577 tEdge e;
578
579 NEW(e, tsEdge)if ((e = (tsEdge *)malloc(sizeof(tsEdge))) == ((void*)0)) { printf
("Out of Memory!\n"); exit(0); }
;
580 e->adjface[0] = e->adjface[1] = e->newface = NULL((void*)0);
581 e->endpts[0] = e->endpts[1] = NULL((void*)0);
582 e->delete = !REMOVED1;
583 ADD(edges, e)if (edges) { e->next = edges; e->prev = edges->prev;
edges->prev = e; e->prev->next = e; } else { edges =
e; edges->next = edges->prev = e; }
;
584 return e;
585}
586
587/*--------------------------------------------------------------------
588MakeNullFace creates a new face structure and initializes all of its
589flags to NULL and sets all the flags to off. It returns a pointer
590to the empty cell.
591---------------------------------------------------------------------*/
592tFace MakeNullFace(void)
593{
594 tFace f;
595 int i;
596
597 NEW(f, tsFace)if ((f = (tsFace *)malloc(sizeof(tsFace))) == ((void*)0)) { printf
("Out of Memory!\n"); exit(0); }
;
598 for (i = 0; i < 3; ++i) {
599 f->edge[i] = NULL((void*)0);
600 f->vertex[i] = NULL((void*)0);
601 }
602 f->visible = !VISIBLE1;
603 ADD(faces, f)if (faces) { f->next = faces; f->prev = faces->prev;
faces->prev = f; f->prev->next = f; } else { faces =
f; faces->next = faces->prev = f; }
;
604 return f;
605}
606
607/*---------------------------------------------------------------------
608MakeFace creates a new face structure from three vertices (in ccw
609order). It returns a pointer to the face.
610---------------------------------------------------------------------*/
611tFace MakeFace(tVertex v0, tVertex v1, tVertex v2, tFace fold)
612{
613 tFace f;
614 tEdge e0, e1, e2;
615
616 /* Create edges of the initial triangle. */
617 if (!fold) {
618 e0 = MakeNullEdge();
619 e1 = MakeNullEdge();
620 e2 = MakeNullEdge();
621 }
622 else { /* Copy from fold, in reverse order. */
623 e0 = fold->edge[2];
624 e1 = fold->edge[1];
625 e2 = fold->edge[0];
626 }
627 e0->endpts[0] = v0;
628 e0->endpts[1] = v1;
629 e1->endpts[0] = v1;
630 e1->endpts[1] = v2;
631 e2->endpts[0] = v2;
632 e2->endpts[1] = v0;
633
634 /* Create face for triangle. */
635 f = MakeNullFace();
636 f->edge[0] = e0;
637 f->edge[1] = e1;
638 f->edge[2] = e2;
639 f->vertex[0] = v0;
640 f->vertex[1] = v1;
641 f->vertex[2] = v2;
642
643 /* Link edges to face. */
644 e0->adjface[0] = e1->adjface[0] = e2->adjface[0] = f;
645
646 return f;
647}
648
649/*---------------------------------------------------------------------
650CleanUp goes through each data structure list and clears all
651flags and NULLs out some pointers. The order of processing
652(edges, faces, vertices) is important.
653---------------------------------------------------------------------*/
654void CleanUp(void)
655{
656 CleanEdges();
657 CleanFaces();
14
Calling 'CleanFaces'
658 CleanVertices();
659}
660
661/*---------------------------------------------------------------------
662CleanEdges runs through the edge list and cleans up the structure.
663If there is a newface then it will put that face in place of the
664visible face and NULL out newface. It also deletes so marked edges.
665---------------------------------------------------------------------*/
666void CleanEdges(void)
667{
668 tEdge e; /* Primary index into edge list. */
669 tEdge t; /* Temporary edge pointer. */
670
671 /* Integrate the newface's into the data structure. */
672 /* Check every edge. */
673 e = edges;
674 do {
675 if (e->newface) {
676 if (e->adjface[0]->visible)
677 e->adjface[0] = e->newface;
678 else
679 e->adjface[1] = e->newface;
680 e->newface = NULL((void*)0);
681 }
682 e = e->next;
683 } while (e != edges);
684
685 /* Delete any edges marked for deletion. */
686 while (edges && edges->delete) {
687 e = edges;
688 DELETE(edges, e)if (edges) { if (edges == edges->next) edges = ((void*)0);
else if (e == edges) edges = edges->next; e->next->
prev = e->prev; e->prev->next = e->next; if (e) {
free((char *)e); e = ((void*)0); }; }
;
689 }
690 e = edges->next;
691 do {
692 if (e->delete) {
693 t = e;
694 e = e->next;
695 DELETE(edges, t)if (edges) { if (edges == edges->next) edges = ((void*)0);
else if (t == edges) edges = edges->next; t->next->
prev = t->prev; t->prev->next = t->next; if (t) {
free((char *)t); t = ((void*)0); }; }
;
696 }
697 else
698 e = e->next;
699 } while (e != edges);
700}
701
702/*---------------------------------------------------------------------
703CleanFaces runs through the face list and deletes any face marked visible.
704---------------------------------------------------------------------*/
705void CleanFaces(void)
706{
707 tFace f; /* Primary pointer into face list. */
708 tFace t; /* Temporary pointer, for deleting. */
709
710 while (faces
14.1
'faces' is non-null
20.1
'faces' is null
&& faces->visible) {
15
Loop condition is true. Entering loop body
711 f = faces;
712 DELETE(faces, f)if (faces) { if (faces == faces->next) faces = ((void*)0);
else if (f == faces) faces = faces->next; f->next->
prev = f->prev; f->prev->next = f->next; if (f) {
free((char *)f); f = ((void*)0); }; }
;
16
Taking true branch
17
Assuming 'faces' is equal to field 'next'
18
Taking true branch
19
Null pointer value stored to 'faces'
20
Taking true branch
713 }
714 f = faces->next;
21
Access to field 'next' results in a dereference of a null pointer (loaded from variable 'faces')
715 do {
716 if (f->visible) {
717 t = f;
718 f = f->next;
719 DELETE(faces, t)if (faces) { if (faces == faces->next) faces = ((void*)0);
else if (t == faces) faces = faces->next; t->next->
prev = t->prev; t->prev->next = t->next; if (t) {
free((char *)t); t = ((void*)0); }; }
;
720 }
721 else
722 f = f->next;
723 } while (f != faces);
724}
725
726/*---------------------------------------------------------------------
727CleanVertices runs through the vertex list and deletes the
728vertices that are marked as processed but are not incident to any
729undeleted edges.
730---------------------------------------------------------------------*/
731void CleanVertices(void)
732{
733 tEdge e;
734 tVertex v, t;
735
736 /* Mark all vertices incident to some undeleted edge as on the hull. */
737 e = edges;
738 do {
739 e->endpts[0]->onhull = e->endpts[1]->onhull = ONHULL1;
740 e = e->next;
741 } while (e != edges);
742
743 /* Delete all vertices that have been processed but
744 are not on the hull. */
745 while (vertices && vertices->mark && !vertices->onhull) {
746 v = vertices;
747 DELETE(vertices, v)if (vertices) { if (vertices == vertices->next) vertices =
((void*)0); else if (v == vertices) vertices = vertices->
next; v->next->prev = v->prev; v->prev->next =
v->next; if (v) { free((char *)v); v = ((void*)0); }; }
;
748 }
749 v = vertices->next;
750 do {
751 if (v->mark && !v->onhull) {
752 t = v;
753 v = v->next;
754 DELETE(vertices, t)if (vertices) { if (vertices == vertices->next) vertices =
((void*)0); else if (t == vertices) vertices = vertices->
next; t->next->prev = t->prev; t->prev->next =
t->next; if (t) { free((char *)t); t = ((void*)0); }; }
755 }
756 else
757 v = v->next;
758 } while (v != vertices);
759
760 /* Reset flags. */
761 v = vertices;
762 do {
763 v->duplicate = NULL((void*)0);
764 v->onhull = !ONHULL1;
765 v = v->next;
766 } while (v != vertices);
767}
768
769/*---------------------------------------------------------------------
770Collinear checks to see if the three points given are collinear,
771by checking to see if each element of the cross product is zero.
772---------------------------------------------------------------------*/
773bool_Bool Collinear(tVertex a, tVertex b, tVertex c)
774{
775 return (c->v[Z2] - a->v[Z2]) * (b->v[Y1] - a->v[Y1]) -
776 (b->v[Z2] - a->v[Z2]) * (c->v[Y1] - a->v[Y1]) ==
777 0 &&
778 (b->v[Z2] - a->v[Z2]) * (c->v[X0] - a->v[X0]) -
779 (b->v[X0] - a->v[X0]) * (c->v[Z2] - a->v[Z2]) ==
780 0 &&
781 (b->v[X0] - a->v[X0]) * (c->v[Y1] - a->v[Y1]) -
782 (b->v[Y1] - a->v[Y1]) * (c->v[X0] - a->v[X0]) ==
783 0;
784}