2
/* Little cms - profiler construction set */
3
/* Copyright (C) 1998-2001 Marti Maria <marti@littlecms.com> */
5
/* THIS SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, */
6
/* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY */
7
/* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. */
9
/* IN NO EVENT SHALL MARTI MARIA BE LIABLE FOR ANY SPECIAL, INCIDENTAL, */
10
/* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, */
11
/* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, */
12
/* WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF */
13
/* LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE */
14
/* OF THIS SOFTWARE. */
16
/* This file is free software; you can redistribute it and/or modify it */
17
/* under the terms of the GNU General Public License as published by */
18
/* the Free Software Foundation; either version 2 of the License, or */
19
/* (at your option) any later version. */
21
/* This program is distributed in the hope that it will be useful, but */
22
/* WITHOUT ANY WARRANTY; without even the implied warranty of */
23
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
24
/* General Public License for more details. */
26
/* You should have received a copy of the GNU General Public License */
27
/* along with this program; if not, write to the Free Software */
28
/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
30
/* As a special exception to the GNU General Public License, if you */
31
/* distribute this file as part of a program that contains a */
32
/* configuration script generated by Autoconf, you may include it under */
33
/* the same distribution terms that you use for the rest of that program. */
40
/* Convex hull management */
42
LCMSHANDLE cdecl cmsxHullInit(void);
43
void cdecl cmsxHullDone(LCMSHANDLE hHull);
44
BOOL cdecl cmsxHullAddPoint(LCMSHANDLE hHull, int x, int y, int z);
45
BOOL cdecl cmsxHullComputeHull(LCMSHANDLE hHull);
46
char cdecl cmsxHullCheckpoint(LCMSHANDLE hHull, int x, int y, int z);
47
BOOL cdecl cmsxHullDumpVRML(LCMSHANDLE hHull, const char* fname);
49
/* --------------------------------------------------------------------- */
53
/* This method is described in "Computational Geometry in C" Chapter 4. */
55
/* -------------------------------------------------------------------- */
56
/* This code is Copyright 1998 by Joseph O'Rourke. It may be freely */
57
/* redistributed in its entirety provided that this copyright notice is */
59
/* -------------------------------------------------------------------- */
61
#define SWAP(t,x,y) { t = x; x = y; y = t; }
64
/* if (p) { free ((char *) p); p = NULL; } */
67
#define ADD( head, p ) if ( head ) { \
69
p->Prev = head->Prev; \
75
head->Next = head->Prev = p; \
78
#define XDELETE( head, p ) if ( head ) { \
79
if ( head == head->Next ) \
81
else if ( p == head ) \
83
p->Next->Prev = p->Prev; \
84
p->Prev->Next = p->Next; \
88
/* Define Vertex indices. */
93
/* Define structures for vertices, edges and faces */
95
typedef struct _vertex_struct VERTEX,FAR *LPVERTEX;
96
typedef struct _edge_struct EDGE, FAR *LPEDGE;
97
typedef struct _face_struct FACE, FAR *LPFACE;
100
struct _edge_struct {
104
LPFACE NewFace; /* pointer to incident cone face. */
105
BOOL DoDelete; /* T iff Edge should be delete. */
110
struct _face_struct {
114
BOOL Visible; /* T iff face Visible from new point. */
119
struct _vertex_struct {
123
LPEDGE duplicate; /* pointer to incident cone Edge (or NULL) */
124
BOOL onhull; /* T iff point on hull. */
125
BOOL mark; /* T iff point already processed. */
135
#define PROCESSED true
136
#define SAFE 1000000 /* Range of safe coord values. */
138
#define DIM 3 /* Dimension of points */
139
typedef int VEC3I[DIM]; /* Type integer point */
141
#define PMAX 10000 /* Max # of pts */
145
/* Global variable definitions */
150
VEC3I Vertices[PMAX]; /* All the points */
151
VEC3I Faces[PMAX]; /* Each triangle face is 3 indices */
152
VEC3I Box[PMAX][2]; /* Box around each face */
164
/* static HULL Global; */
167
/*---------------------------------------------------------------------
168
MakeNullVertex: Makes a Vertex, nulls out fields.
169
---------------------------------------------------------------------*/
172
LPVERTEX MakeNullVertex(LPHULL hull)
176
v = (LPVERTEX) malloc(sizeof(VERTEX));
181
v->mark = !PROCESSED;
182
ADD( hull->vertices, v );
189
/*---------------------------------------------------------------------
190
MakeNullEdge creates a new cell and initializes all pointers to NULL
191
and sets all flags to off. It returns a pointer to the empty cell.
192
---------------------------------------------------------------------*/
194
LPEDGE MakeNullEdge(LPHULL hull)
198
e = (LPEDGE) malloc(sizeof(EDGE));
201
e->AdjFace[0] = e->AdjFace[1] = e->NewFace = NULL;
202
e->EndPts[0] = e->EndPts[1] = NULL;
203
e->DoDelete = !REMOVED;
204
ADD( hull->edges, e );
208
/*--------------------------------------------------------------------
209
MakeNullFace creates a new face structure and initializes all of its
210
flags to NULL and sets all the flags to off. It returns a pointer
212
---------------------------------------------------------------------*/
214
LPFACE MakeNullFace(LPHULL hull)
219
f = (LPFACE) malloc(sizeof(FACE));
222
for ( i=0; i < 3; ++i ) {
226
f->Visible = !VISIBLE;
227
ADD( hull->faces, f );
233
/*---------------------------------------------------------------------
234
MakeFace creates a new face structure from three vertices (in ccw
235
order). It returns a pointer to the face.
236
---------------------------------------------------------------------*/
238
LPFACE MakeFace(LPHULL hull, LPVERTEX v0, LPVERTEX v1, LPVERTEX v2, LPFACE fold)
243
/* Create edges of the initial triangle. */
245
e0 = MakeNullEdge(hull);
246
e1 = MakeNullEdge(hull);
247
e2 = MakeNullEdge(hull);
249
else { /* Copy from fold, in reverse order. */
254
e0->EndPts[0] = v0; e0->EndPts[1] = v1;
255
e1->EndPts[0] = v1; e1->EndPts[1] = v2;
256
e2->EndPts[0] = v2; e2->EndPts[1] = v0;
258
/* Create face for triangle. */
259
f = MakeNullFace(hull);
260
f->Edge[0] = e0; f->Edge[1] = e1; f->Edge[2] = e2;
261
f->Vertex[0] = v0; f->Vertex[1] = v1; f->Vertex[2] = v2;
263
/* Link edges to face. */
264
e0->AdjFace[0] = e1->AdjFace[0] = e2->AdjFace[0] = f;
269
/*---------------------------------------------------------------------
270
Collinear checks to see if the three points given are collinear,
271
by checking to see if each element of the cross product is zero.
272
---------------------------------------------------------------------*/
274
BOOL Collinear( LPVERTEX a, LPVERTEX b, LPVERTEX c )
277
( c->v[Z] - a->v[Z] ) * ( b->v[Y] - a->v[Y] ) -
278
( b->v[Z] - a->v[Z] ) * ( c->v[Y] - a->v[Y] ) == 0
279
&& ( b->v[Z] - a->v[Z] ) * ( c->v[X] - a->v[X] ) -
280
( b->v[X] - a->v[X] ) * ( c->v[Z] - a->v[Z] ) == 0
281
&& ( b->v[X] - a->v[X] ) * ( c->v[Y] - a->v[Y] ) -
282
( b->v[Y] - a->v[Y] ) * ( c->v[X] - a->v[X] ) == 0 ;
285
/*---------------------------------------------------------------------
286
VolumeSign returns the sign of the volume of the tetrahedron determined by f
287
and p. VolumeSign is +1 iff p is on the negative side of f,
288
where the positive side is determined by the rh-rule. So the volume
289
is positive if the ccw normal to f points outside the tetrahedron.
290
The final fewer-multiplications form is due to Bob Williamson.
291
---------------------------------------------------------------------*/
292
int VolumeSign( LPFACE f, LPVERTEX p )
295
double ax, ay, az, bx, by, bz, cx, cy, cz;
297
ax = f->Vertex[0]->v[X] - p->v[X];
298
ay = f->Vertex[0]->v[Y] - p->v[Y];
299
az = f->Vertex[0]->v[Z] - p->v[Z];
300
bx = f->Vertex[1]->v[X] - p->v[X];
301
by = f->Vertex[1]->v[Y] - p->v[Y];
302
bz = f->Vertex[1]->v[Z] - p->v[Z];
303
cx = f->Vertex[2]->v[X] - p->v[X];
304
cy = f->Vertex[2]->v[Y] - p->v[Y];
305
cz = f->Vertex[2]->v[Z] - p->v[Z];
307
vol = ax * (by*cz - bz*cy)
308
+ ay * (bz*cx - bx*cz)
309
+ az * (bx*cy - by*cx);
312
/* The volume should be an integer. */
313
if ( vol > 0.5 ) return 1;
314
else if ( vol < -0.5 ) return -1;
320
/*---------------------------------------------------------------------
321
CleanEdges runs through the Edge list and cleans up the structure.
322
If there is a NewFace then it will put that face in place of the
323
Visible face and NULL out NewFace. It also deletes so marked edges.
324
---------------------------------------------------------------------*/
326
void CleanEdges(LPHULL hull)
328
LPEDGE e; /* Primary index into Edge list. */
329
LPEDGE t; /* Temporary Edge pointer. */
331
/* Integrate the NewFace's into the data structure. */
332
/* Check every Edge. */
338
if ( e->AdjFace[0]->Visible )
339
e->AdjFace[0] = e->NewFace;
341
e->AdjFace[1] = e->NewFace;
348
} while ( e != hull ->edges );
350
/* Delete any edges marked for deletion. */
351
while ( hull ->edges && hull ->edges->DoDelete ) {
355
XDELETE( hull ->edges, e );
358
e = hull ->edges->Next;
365
XDELETE( hull ->edges, t );
369
} while ( e != hull ->edges );
372
/*---------------------------------------------------------------------
373
CleanFaces runs through the face list and deletes any face marked Visible.
374
---------------------------------------------------------------------*/
376
void CleanFaces(LPHULL hull)
378
LPFACE f; /* Primary pointer into face list. */
379
LPFACE t; /* Temporary pointer, for deleting. */
382
while ( hull ->faces && hull ->faces->Visible ) {
385
XDELETE( hull ->faces, f );
388
f = hull ->faces->Next;
395
XDELETE( hull ->faces, t );
399
} while ( f != hull ->faces );
404
/*---------------------------------------------------------------------
405
CleanVertices runs through the Vertex list and deletes the
406
vertices that are marked as processed but are not incident to any
408
---------------------------------------------------------------------*/
410
void CleanVertices(LPHULL hull)
415
/* Mark all vertices incident to some undeleted Edge as on the hull. */
419
e->EndPts[0]->onhull = e->EndPts[1]->onhull = ONHULL;
422
} while (e != hull ->edges);
425
/* Delete all vertices that have been processed but
426
are not on the hull. */
428
while ( hull ->vertices && hull->vertices->mark && !hull ->vertices->onhull ) {
431
XDELETE(hull ->vertices, v );
435
v = hull ->vertices->Next;
437
if (v->mark && !v->onhull ) {
440
XDELETE(hull ->vertices, t )
445
} while ( v != hull ->vertices );
456
} while (v != hull->vertices );
463
/*---------------------------------------------------------------------
464
MakeCcw puts the vertices in the face structure in counterclock wise
465
order. We want to store the vertices in the same
466
order as in the Visible face. The third Vertex is always p.
468
Although no specific ordering of the edges of a face are used
469
by the code, the following condition is maintained for each face f:
470
one of the two endpoints of f->Edge[i] matches f->Vertex[i].
471
But note that this does not imply that f->Edge[i] is between
472
f->Vertex[i] and f->Vertex[(i+1)%3]. (Thanks to Bob Williamson.)
473
---------------------------------------------------------------------*/
476
void MakeCcw(LPFACE f, LPEDGE e, LPVERTEX p)
478
LPFACE fv; /* The Visible face adjacent to e */
479
int i; /* Index of e->endpoint[0] in fv. */
480
LPEDGE s; /* Temporary, for swapping */
482
if (e->AdjFace[0]->Visible)
488
/* Set Vertex[0] & [1] of f to have the same orientation
489
as do the corresponding vertices of fv. */
491
for ( i=0; fv->Vertex[i] != e->EndPts[0]; ++i )
494
/* Orient f the same as fv. */
496
if ( fv->Vertex[ (i+1) % 3 ] != e->EndPts[1] ) {
498
f->Vertex[0] = e->EndPts[1];
499
f->Vertex[1] = e->EndPts[0];
502
f->Vertex[0] = e->EndPts[0];
503
f->Vertex[1] = e->EndPts[1];
504
SWAP( s, f->Edge[1], f->Edge[2] );
507
/* This swap is tricky. e is Edge[0]. Edge[1] is based on endpt[0],
508
Edge[2] on endpt[1]. So if e is oriented "forwards," we
509
need to move Edge[1] to follow [0], because it precedes. */
514
/*---------------------------------------------------------------------
515
MakeConeFace makes a new face and two new edges between the
516
Edge and the point that are passed to it. It returns a pointer to
518
---------------------------------------------------------------------*/
521
LPFACE MakeConeFace(LPHULL hull, LPEDGE e, LPVERTEX p)
527
/* Make two new edges (if don't already exist). */
529
for ( i=0; i < 2; ++i )
530
/* If the Edge exists, copy it into new_edge. */
531
if ( !( new_edge[i] = e->EndPts[i]->duplicate) ) {
533
/* Otherwise (duplicate is NULL), MakeNullEdge. */
534
new_edge[i] = MakeNullEdge(hull);
535
new_edge[i]->EndPts[0] = e->EndPts[i];
536
new_edge[i]->EndPts[1] = p;
537
e->EndPts[i]->duplicate = new_edge[i];
540
/* Make the new face. */
541
new_face = MakeNullFace(hull);
542
new_face->Edge[0] = e;
543
new_face->Edge[1] = new_edge[0];
544
new_face->Edge[2] = new_edge[1];
545
MakeCcw( new_face, e, p );
547
/* Set the adjacent face pointers. */
548
for ( i=0; i < 2; ++i )
549
for ( j=0; j < 2; ++j )
550
/* Only one NULL link should be set to new_face. */
551
if ( !new_edge[i]->AdjFace[j] ) {
552
new_edge[i]->AdjFace[j] = new_face;
560
/*---------------------------------------------------------------------
561
AddOne is passed a Vertex. It first determines all faces Visible from
562
that point. If none are Visible then the point is marked as not
563
onhull. Next is a loop over edges. If both faces adjacent to an Edge
564
are Visible, then the Edge is marked for deletion. If just one of the
565
adjacent faces is Visible then a new face is constructed.
566
---------------------------------------------------------------------*/
568
BOOL AddOne(LPHULL hull, LPVERTEX p)
576
/* Mark faces Visible from p. */
581
vol = VolumeSign(f, p);
584
f->Visible = VISIBLE;
590
} while ( f != hull ->faces );
592
/* If no faces are Visible from p, then p is inside the hull. */
600
/* Mark edges in interior of Visible region for deletion.
601
Erect a NewFace based on each border Edge. */
609
if ( e->AdjFace[0]->Visible && e->AdjFace[1]->Visible )
610
/* e interior: mark for deletion. */
611
e->DoDelete = REMOVED;
614
if ( e->AdjFace[0]->Visible || e->AdjFace[1]->Visible )
615
/* e border: make a new face. */
616
e->NewFace = MakeConeFace(hull, e, p );
620
} while ( e != hull ->edges );
626
/*---------------------------------------------------------------------
627
DoubleTriangle builds the initial double triangle. It first finds 3
628
noncollinear points and makes two faces out of them, in opposite order.
629
It then finds a fourth point that is not coplanar with that face. The
630
vertices are stored in the face structure in counterclockwise order so
631
that the volume between the face and the point is negative. Lastly, the
632
3 newfaces to the fourth point are constructed and the data structures
634
---------------------------------------------------------------------*/
637
BOOL DoubleTriangle(LPHULL hull)
639
LPVERTEX v0, v1, v2, v3;
640
LPFACE f0, f1 = NULL;
643
/* Find 3 noncollinear points. */
644
v0 = hull ->vertices;
645
while ( Collinear( v0, v0->Next, v0->Next->Next ) )
646
if ( ( v0 = v0->Next ) == hull->vertices )
647
return false; /* All points are Collinear! */
652
/* Mark the vertices as processed. */
653
v0->mark = PROCESSED;
654
v1->mark = PROCESSED;
655
v2->mark = PROCESSED;
657
/* Create the two "twin" faces. */
658
f0 = MakeFace(hull, v0, v1, v2, f1 );
659
f1 = MakeFace(hull, v2, v1, v0, f0 );
661
/* Link adjacent face fields. */
662
f0->Edge[0]->AdjFace[1] = f1;
663
f0->Edge[1]->AdjFace[1] = f1;
664
f0->Edge[2]->AdjFace[1] = f1;
665
f1->Edge[0]->AdjFace[1] = f0;
666
f1->Edge[1]->AdjFace[1] = f0;
667
f1->Edge[2]->AdjFace[1] = f0;
669
/* Find a fourth, noncoplanar point to form tetrahedron. */
671
vol = VolumeSign( f0, v3 );
675
if ( ( v3 = v3->Next ) == v0 )
676
return false; /* All points are coplanar! */
678
vol = VolumeSign( f0, v3 );
681
/* Insure that v3 will be the first added. */
682
hull ->vertices = v3;
688
/*---------------------------------------------------------------------
689
ConstructHull adds the vertices to the hull one at a time. The hull
690
vertices are those in the list marked as onhull.
691
---------------------------------------------------------------------*/
693
void ConstructHull(LPHULL hull)
696
BOOL changed; /* T if addition changes hull; not used. */
708
changed = AddOne(hull, v );
717
} while (v != hull->vertices );
723
/*-------------------------------------------------------------------*/
727
void AddVec( VEC3I q, VEC3I ray )
731
for( i = 0; i < DIM; i++ )
732
ray[i] = q[i] + ray[i];
735
/*---------------------------------------------------------------------
737
---------------------------------------------------------------------*/
739
void SubVec( VEC3I a, VEC3I b, VEC3I c )
743
for( i = 0; i < DIM; i++ )
748
/*---------------------------------------------------------------------
749
Returns the dot product of the two input vectors.
750
---------------------------------------------------------------------*/
752
double Dot( VEC3I a, LPVEC3 b )
757
for( i = 0; i < DIM; i++ )
758
sum += a[i] * b->n[i];
763
/*---------------------------------------------------------------------
764
Compute the cross product of (b-a)x(c-a) and place into N.
765
---------------------------------------------------------------------*/
767
void NormalVec( VEC3I a, VEC3I b, VEC3I c, LPVEC3 N )
769
N->n[X] = ( c[Z] - a[Z] ) * ( b[Y] - a[Y] ) -
770
( b[Z] - a[Z] ) * ( c[Y] - a[Y] );
771
N->n[Y] = ( b[Z] - a[Z] ) * ( c[X] - a[X] ) -
772
( b[X] - a[X] ) * ( c[Z] - a[Z] );
773
N->n[Z] = ( b[X] - a[X] ) * ( c[Y] - a[Y] ) -
774
( b[Y] - a[Y] ) * ( c[X] - a[X] );
781
int InBox( VEC3I q, VEC3I bmin, VEC3I bmax )
784
if( ( bmin[X] <= q[X] ) && ( q[X] <= bmax[X] ) &&
785
( bmin[Y] <= q[Y] ) && ( q[Y] <= bmax[Y] ) &&
786
( bmin[Z] <= q[Z] ) && ( q[Z] <= bmax[Z] ) )
795
This function returns a char:
796
'0': the segment [ab] does not intersect (completely misses) the
797
bounding box surrounding the n-th triangle T. It lies
798
strictly to one side of one of the six supporting planes.
799
'?': status unknown: the segment may or may not intersect T.
803
char BoxTest(LPHULL hull, int n, VEC3I a, VEC3I b)
805
int i; /* Coordinate index */
808
for ( i=0; i < DIM; i++ ) {
810
w = hull ->Box[ n ][0][i]; /* min: lower left */
812
if ( (a[i] < w) && (b[i] < w) ) return '0';
814
w = hull ->Box[ n ][1][i]; /* max: upper right */
816
if ( (a[i] > w) && (b[i] > w) ) return '0';
824
/* Return a random ray endpoint */
827
void RandomRay( VEC3I ray, int radius )
829
double x, y, z, w, t;
831
/* Generate a random point on a sphere of radius 1. */
832
/* the sphere is sliced at z, and a random point at angle t
833
generated on the circle of intersection. */
835
z = 2.0 * (double) rand() / RAND_MAX - 1.0;
836
t = 2.0 * M_PI * (double) rand() / RAND_MAX;
841
ray[X] = (int) ( radius * x );
842
ray[Y] = (int) ( radius * y );
843
ray[Z] = (int) ( radius * z );
849
int ComputeBox(LPHULL hull, int F, VEC3I bmin, VEC3I bmax )
854
for( i = 0; i < F; i++ )
855
for( j = 0; j < DIM; j++ ) {
857
if( hull ->Vertices[i][j] < bmin[j] )
858
bmin[j] = hull ->Vertices[i][j];
860
if( hull ->Vertices[i][j] > bmax[j] )
861
bmax[j] = hull ->Vertices[i][j];
864
radius = sqrt( pow( (double)(bmax[X] - bmin[X]), 2.0 ) +
865
pow( (double)(bmax[Y] - bmin[Y]), 2.0 ) +
866
pow( (double)(bmax[Z] - bmin[Z]), 2.0 ) );
868
return (int)( radius +1 ) + 1;
872
/*---------------------------------------------------------------------
873
Computes N & D and returns index m of largest component.
874
---------------------------------------------------------------------*/
876
int PlaneCoeff(LPHULL hull, VEC3I T, LPVEC3 N, double *D )
879
double t; /* Temp storage */
880
double biggest = 0.0; /* Largest component of normal vector. */
881
int m = 0; /* Index of largest component. */
883
NormalVec(hull ->Vertices[T[0]], hull ->Vertices[T[1]], hull ->Vertices[T[2]], N );
884
*D = Dot( hull ->Vertices[T[0]], N );
886
/* Find the largest component of N. */
887
for ( i = 0; i < DIM; i++ ) {
897
/*---------------------------------------------------------------------
898
'p': The segment lies wholly within the plane.
899
'q': The q endpoint is on the plane (but not 'p').
900
'r': The r endpoint is on the plane (but not 'p').
901
'0': The segment lies strictly to one side or the other of the plane.
902
'1': The segement intersects the plane, and 'p' does not hold.
903
---------------------------------------------------------------------*/
905
char SegPlaneInt(LPHULL hull, VEC3I T, VEC3I q, VEC3I r, LPVEC3 p, int *m)
909
double num, denom, t;
912
*m = PlaneCoeff(hull, T, &N, &D );
913
num = D - Dot( q, &N );
915
denom = Dot( rq, &N );
917
if ( denom == 0.0 ) { /* Segment is parallel to plane. */
918
if ( num == 0.0 ) /* q is on plane. */
926
for( i = 0; i < DIM; i++ )
927
p->n[i] = q[i] + t * ( r[i] - q[i] );
929
if ( (0.0 < t) && (t < 1.0) )
931
else if ( num == 0.0 ) /* t == 0 */
933
else if ( num == denom ) /* t == 1 */
941
int AreaSign( VEC3I a, VEC3I b, VEC3I c )
945
area2 = ( b[0] - a[0] ) * (double)( c[1] - a[1] ) -
946
( c[0] - a[0] ) * (double)( b[1] - a[1] );
948
/* The area should be an integer. */
949
if ( area2 > 0.5 ) return 1;
950
else if ( area2 < -0.5 ) return -1;
956
char InTri2D( VEC3I Tp[3], VEC3I pp )
958
int area0, area1, area2;
960
/* compute three AreaSign() values for pp w.r.t. each Edge of the face in 2D */
961
area0 = AreaSign( pp, Tp[0], Tp[1] );
962
area1 = AreaSign( pp, Tp[1], Tp[2] );
963
area2 = AreaSign( pp, Tp[2], Tp[0] );
965
if ( (( area0 == 0 ) && ( area1 > 0 ) && ( area2 > 0 )) ||
966
(( area1 == 0 ) && ( area0 > 0 ) && ( area2 > 0 )) ||
967
(( area2 == 0 ) && ( area0 > 0 ) && ( area1 > 0 )) )
970
if ( (( area0 == 0 ) && ( area1 < 0 ) && ( area2 < 0 )) ||
971
(( area1 == 0 ) && ( area0 < 0 ) && ( area2 < 0 )) ||
972
(( area2 == 0 ) && ( area0 < 0 ) && ( area1 < 0 )))
975
if ( (( area0 > 0 ) && ( area1 > 0 ) && ( area2 > 0 )) ||
976
(( area0 < 0 ) && ( area1 < 0 ) && ( area2 < 0 )))
979
if ( ( area0 == 0 ) && ( area1 == 0 ) && ( area2 == 0 ) )
980
return '?'; /* Error in InTriD */
982
if ( (( area0 == 0 ) && ( area1 == 0 )) ||
983
(( area0 == 0 ) && ( area2 == 0 )) ||
984
(( area1 == 0 ) && ( area2 == 0 )) )
991
/* Assumption: p lies in the plane containing T.
993
'V': the query point p coincides with a Vertex of triangle T.
994
'E': the query point p is in the relative interior of an Edge of triangle T.
995
'F': the query point p is in the relative interior of a Face of triangle T.
996
'0': the query point p does not intersect (misses) triangle T.
1000
char InTri3D(LPHULL hull, VEC3I T, int m, VEC3I p )
1002
int i; /* Index for X,Y,Z */
1003
int j; /* Index for X,Y */
1004
int k; /* Index for triangle Vertex */
1005
VEC3I pp; /* projected p */
1006
VEC3I Tp[3]; /* projected T: three new vertices */
1008
/* Project out coordinate m in both p and the triangular face */
1010
for ( i = 0; i < DIM; i++ ) {
1011
if ( i != m ) { /* skip largest coordinate */
1013
for ( k = 0; k < 3; k++ )
1014
Tp[k][j] = hull->Vertices[T[k]][i];
1018
return( InTri2D( Tp, pp ) );
1024
int VolumeSign2( VEC3I a, VEC3I b, VEC3I c, VEC3I d )
1027
double ax, ay, az, bx, by, bz, cx, cy, cz, dx, dy, dz;
1028
double bxdx, bydy, bzdz, cxdx, cydy, czdz;
1049
vol = (az-dz) * (bxdx*cydy - bydy*cxdx)
1050
+ (ay-dy) * (bzdz*cxdx - bxdx*czdz)
1051
+ (ax-dx) * (bydy*czdz - bzdz*cydy);
1054
/* The volume should be an integer. */
1055
if ( vol > 0.5 ) return 1;
1056
else if ( vol < -0.5 ) return -1;
1063
/*---------------------------------------------------------------------
1064
The signed volumes of three tetrahedra are computed, determined
1065
by the segment qr, and each Edge of the triangle.
1067
'v': the open segment includes a Vertex of T.
1068
'e': the open segment includes a point in the relative interior of an Edge
1070
'f': the open segment includes a point in the relative interior of a face
1072
'0': the open segment does not intersect triangle T.
1073
---------------------------------------------------------------------*/
1076
char SegTriCross(LPHULL hull, VEC3I T, VEC3I q, VEC3I r )
1078
int vol0, vol1, vol2;
1080
vol0 = VolumeSign2( q, hull->Vertices[ T[0] ], hull->Vertices[ T[1] ], r );
1081
vol1 = VolumeSign2( q, hull->Vertices[ T[1] ], hull->Vertices[ T[2] ], r );
1082
vol2 = VolumeSign2( q, hull->Vertices[ T[2] ], hull->Vertices[ T[0] ], r );
1085
/* Same sign: segment intersects interior of triangle. */
1086
if ( ( ( vol0 > 0 ) && ( vol1 > 0 ) && ( vol2 > 0 ) ) ||
1087
( ( vol0 < 0 ) && ( vol1 < 0 ) && ( vol2 < 0 ) ) )
1090
/* Opposite sign: no intersection between segment and triangle */
1091
if ( ( ( vol0 > 0 ) || ( vol1 > 0 ) || ( vol2 > 0 ) ) &&
1092
( ( vol0 < 0 ) || ( vol1 < 0 ) || ( vol2 < 0 ) ) )
1095
else if ( ( vol0 == 0 ) && ( vol1 == 0 ) && ( vol2 == 0 ) )
1096
return '?'; /* Error 1 in SegTriCross */
1098
/* Two zeros: segment intersects Vertex. */
1099
else if ( ( ( vol0 == 0 ) && ( vol1 == 0 ) ) ||
1100
( ( vol0 == 0 ) && ( vol2 == 0 ) ) ||
1101
( ( vol1 == 0 ) && ( vol2 == 0 ) ) )
1104
/* One zero: segment intersects Edge. */
1105
else if ( ( vol0 == 0 ) || ( vol1 == 0 ) || ( vol2 == 0 ) )
1109
return '?'; /* Error 2 in SegTriCross */
1115
char SegTriInt(LPHULL hull, VEC3I T, VEC3I q, VEC3I r, LPVEC3 p )
1120
code = SegPlaneInt(hull, T, q, r, p, &m );
1122
if ( code == '0') return '0';
1123
else if ( code == 'q') return InTri3D(hull, T, m, q );
1124
else if ( code == 'r') return InTri3D(hull, T, m, r );
1125
else if ( code == 'p') return 'p';
1126
else if ( code == '1' ) return SegTriCross(hull, T, q, r );
1128
return code; /* Error */
1135
This function returns a char:
1136
'i': the query point a is strictly interior to polyhedron P.
1137
'o': the query point a is strictly exterior to( or outside of) polyhedron P.
1139
char InPolyhedron(LPHULL hull, VEC3I q)
1141
int F = hull->nfaces;
1142
VEC3I Ray; /* Ray endpoint. */
1143
VEC3 p; /* Intersection point; not used. */
1144
int f, k = 0, crossings = 0;
1148
/* If query point is outside bounding box, finished. */
1149
if ( !InBox( q, hull->bmin, hull->bmax ) )
1157
RandomRay(Ray, hull->radius );
1162
for ( f = 0; f < F; f++ ) { /* Begin check each face */
1164
if ( BoxTest(hull, f, q, Ray ) == '0' ) {
1168
else code = SegTriInt(hull, hull->Faces[f], q, Ray, &p );
1171
/* If ray is degenerate, then goto outer while to generate another. */
1172
if ( code == 'p' || code == 'v' || code == 'e' ) {
1177
/* If ray hits face at interior point, increment crossings. */
1178
else if ( code == 'f' ) {
1183
/* If query endpoint q sits on a V/E/F, return inside. */
1184
else if ( code == 'V' || code == 'E' || code == 'F' )
1185
return code; /* 'i'; MM2 */
1187
/* If ray misses triangle, do nothing. */
1188
else if ( code == '0' )
1192
return '?'; /* Error */
1195
/* No degeneracies encountered: ray is generic, so finished. */
1198
} /* End while loop */
1201
/* q strictly interior to polyhedron iff an odd number of crossings. */
1202
if( ( crossings % 2 ) == 1 )
1209
/*/ ---------------------------------------------------------------------------------- */
1215
void StoreResults(LPHULL hull)
1226
v = hull ->vertices;
1231
hull ->Vertices[V][X] = v -> v[X];
1232
hull ->Vertices[V][Y] = v -> v[Y];
1233
hull ->Vertices[V][Z] = v -> v[Z];
1238
} while ( v != hull ->vertices );
1247
hull ->Faces[F][0] = f->Vertex[0]->vnum;
1248
hull ->Faces[F][1] = f->Vertex[1]->vnum;
1249
hull ->Faces[F][2] = f->Vertex[2]->vnum;
1251
for ( j=0; j < 3; j++ ) {
1253
hull ->Box[F][0][j] = hull ->Vertices[ hull ->Faces[F][0] ][j];
1254
hull ->Box[F][1][j] = hull ->Vertices[ hull ->Faces[F][0] ][j];
1257
/* Check k=1,2 vertices of face. */
1258
for ( k=1; k < 3; k++ )
1259
for ( j=0; j < 3; j++ ) {
1261
w = hull ->Vertices[ hull ->Faces[F][k] ][j];
1262
if ( w < hull ->Box[F][0][j] ) hull ->Box[F][0][j] = w;
1263
if ( w > hull ->Box[F][1][j] ) hull ->Box[F][1][j] = w;
1269
} while ( f != hull ->faces );
1275
/* Initialize the bounding box */
1276
for ( i = 0; i < DIM; i++ )
1277
hull ->bmin[i] = hull ->bmax[i] = hull ->Vertices[0][i];
1279
hull ->radius = ComputeBox(hull, V, hull ->bmin, hull ->bmax );
1285
LCMSHANDLE cmsxHullInit(void)
1287
LPHULL hull = (LPHULL) malloc(sizeof(HULL));
1289
ZeroMemory(hull, sizeof(HULL));
1291
hull->vnumCounter = 0;
1292
hull->vertices = NULL;
1298
return (LCMSHANDLE) (LPSTR) hull;
1302
void cmsxHullDone(LCMSHANDLE hHull)
1304
LPHULL hull = (LPHULL) (LPSTR) hHull;
1307
free((LPVOID) hull);
1311
BOOL cmsxHullAddPoint(LCMSHANDLE hHull, int x, int y, int z)
1314
LPHULL hull = (LPHULL) (LPSTR) hHull;
1317
v = MakeNullVertex(hull);
1321
v->vnum = hull->vnumCounter++;
1326
BOOL cmsxHullComputeHull(LCMSHANDLE hHull)
1329
LPHULL hull = (LPHULL) (LPSTR) hHull;
1331
if (!DoubleTriangle(hull)) return false;
1333
ConstructHull(hull);
1340
char cmsxHullCheckpoint(LCMSHANDLE hHull, int x, int y, int z)
1343
LPHULL hull = (LPHULL) (LPSTR) hHull;
1345
q[X] = x; q[Y] = y; q[Z] = z;
1347
return InPolyhedron(hull, q ) ;
1351
BOOL cmsxHullDumpVRML(LCMSHANDLE hHull, const char* fname)
1355
LPHULL hull = (LPHULL) (LPSTR) hHull;
1357
fp = fopen (fname, "wt");
1361
fprintf (fp, "#VRML V2.0 utf8\n");
1363
/* set the viewing orientation and distance */
1364
fprintf (fp, "DEF CamTest Group {\n");
1365
fprintf (fp, "\tchildren [\n");
1366
fprintf (fp, "\t\tDEF Cameras Group {\n");
1367
fprintf (fp, "\t\t\tchildren [\n");
1368
fprintf (fp, "\t\t\t\tDEF DefaultView Viewpoint {\n");
1369
fprintf (fp, "\t\t\t\t\tposition 0 0 340\n");
1370
fprintf (fp, "\t\t\t\t\torientation 0 0 1 0\n");
1371
fprintf (fp, "\t\t\t\t\tdescription \"default view\"\n");
1372
fprintf (fp, "\t\t\t\t}\n");
1373
fprintf (fp, "\t\t\t]\n");
1374
fprintf (fp, "\t\t},\n");
1375
fprintf (fp, "\t]\n");
1376
fprintf (fp, "}\n");
1378
/* Output the background stuff */
1379
fprintf (fp, "Background {\n");
1380
fprintf (fp, "\tskyColor [\n");
1381
fprintf (fp, "\t\t.5 .5 .5\n");
1382
fprintf (fp, "\t]\n");
1383
fprintf (fp, "}\n");
1385
/* Output the shape stuff */
1386
fprintf (fp, "Transform {\n");
1387
fprintf (fp, "\tscale 8 8 8\n");
1388
fprintf (fp, "\tchildren [\n");
1390
/* Draw the axes as a shape: */
1391
fprintf (fp, "\t\tShape {\n");
1392
fprintf (fp, "\t\t\tappearance Appearance {\n");
1393
fprintf (fp, "\t\t\t\tmaterial Material {\n");
1394
fprintf (fp, "\t\t\t\t\tdiffuseColor 0 0.8 0\n");
1395
fprintf (fp, "\t\t\t\t\temissiveColor 1.0 1.0 1.0\n");
1396
fprintf (fp, "\t\t\t\t\tshininess 0.8\n");
1397
fprintf (fp, "\t\t\t\t}\n");
1398
fprintf (fp, "\t\t\t}\n");
1399
fprintf (fp, "\t\t\tgeometry IndexedLineSet {\n");
1400
fprintf (fp, "\t\t\t\tcoord Coordinate {\n");
1401
fprintf (fp, "\t\t\t\t\tpoint [\n");
1402
fprintf (fp, "\t\t\t\t\t0.0 0.0 0.0,\n");
1403
fprintf (fp, "\t\t\t\t\t%f 0.0 0.0,\n", 255.0);
1404
fprintf (fp, "\t\t\t\t\t0.0 %f 0.0,\n", 255.0);
1405
fprintf (fp, "\t\t\t\t\t0.0 0.0 %f]\n", 255.0);
1406
fprintf (fp, "\t\t\t\t}\n");
1407
fprintf (fp, "\t\t\t\tcoordIndex [\n");
1408
fprintf (fp, "\t\t\t\t\t0, 1, -1\n");
1409
fprintf (fp, "\t\t\t\t\t0, 2, -1\n");
1410
fprintf (fp, "\t\t\t\t\t0, 3, -1]\n");
1411
fprintf (fp, "\t\t\t}\n");
1412
fprintf (fp, "\t\t}\n");
1415
/* Draw the triangles as a shape: */
1416
fprintf (fp, "\t\tShape {\n");
1417
fprintf (fp, "\t\t\tappearance Appearance {\n");
1418
fprintf (fp, "\t\t\t\tmaterial Material {\n");
1419
fprintf (fp, "\t\t\t\t\tdiffuseColor 0 0.8 0\n");
1420
fprintf (fp, "\t\t\t\t\temissiveColor 0 0 0\n");
1421
fprintf (fp, "\t\t\t\t\tshininess 0.8\n");
1422
fprintf (fp, "\t\t\t\t}\n");
1423
fprintf (fp, "\t\t\t}\n");
1424
fprintf (fp, "\t\t\tgeometry IndexedFaceSet {\n");
1425
fprintf (fp, "\t\t\t\tsolid false\n");
1427
/* fill in the points here */
1428
fprintf (fp, "\t\t\t\tcoord Coordinate {\n");
1429
fprintf (fp, "\t\t\t\t\tpoint [\n");
1431
for (i = 0; i < hull->nvertex; ++i)
1433
fprintf (fp, "\t\t\t\t\t%g %g %g%c\n",
1434
(double) hull->Vertices[i][X], (double) hull->Vertices[i][Y], (double) hull->Vertices[i][Z],
1435
i == hull->nvertex-1? ']': ',');
1437
fprintf (fp, "\t\t\t\t}\n");
1439
/* fill in the Vertex indices (followed by -1) */
1442
fprintf (fp, "\t\t\t\tcoordIndex [\n");
1443
for (i = 0; i < hull->nfaces; ++i)
1445
fprintf (fp, "\t\t\t\t\t%d, %d, %d, -1\n",
1446
hull->Faces[i][0], hull->Faces[i][1], hull->Faces[i][2]);
1449
fprintf (fp, "]\n");
1452
/* fill in the face colors */
1453
fprintf (fp, "\t\t\t\tcolor Color {\n");
1454
fprintf (fp, "\t\t\t\t\tcolor [\n");
1455
for (i = 0; i < hull->nfaces; ++i)
1460
vx = hull->Faces[i][0]; vy = hull->Faces[i][1]; vz = hull->Faces[i][2];
1461
r = (double) (hull->Vertices[vx][X] + hull->Vertices[vy][X] + hull->Vertices[vz][X]) / (3* 255);
1462
g = (double) (hull->Vertices[vx][Y] + hull->Vertices[vy][Y] + hull->Vertices[vz][Y]) / (3* 255);
1463
b = (double) (hull->Vertices[vx][Z] + hull->Vertices[vy][Z] + hull->Vertices[vz][Z]) / (3* 255);
1465
fprintf (fp, "\t\t\t\t\t%g %g %g%c\n", r, g, b,
1466
i == hull->nfaces-1? ']': ',');
1468
fprintf (fp, "\t\t\t}\n");
1470
fprintf (fp, "\t\t\tcolorPerVertex false\n");
1472
fprintf (fp, "\t\t\t}\n");
1473
fprintf (fp, "\t\t}\n");
1474
fprintf (fp, "\t]\n");
1475
fprintf (fp, "}\n");