home *** CD-ROM | disk | FTP | other *** search
- /*
- Copyright 1992 Mark Spychalla
-
- Permission to use, copy, modify, distribute, and sell this software and
- its documentation for any purpose is hereby granted without fee,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation, and that the name of Mark Spychalla not be used
- in advertising or publicity pertaining to distribution of the software
- without specific, written prior permission. Mark Spychalla makes no
- representations about the suitability of this software for any purpose.
- It is provided "as is" without express or implied warranty.
-
- Mark Spychalla disclaims all warranties with regard to this software,
- including all implied warranties of merchantability and fitness, in no
- event shall Mark Spychalla be liable for any special, indirect or
- consequential damages or any damages whatsoever resulting from loss of use,
- data or profits, whether in an action of contract, negligence or other
- tortious action, arising out of or in connection with the use or performance
- of this software.
- */
-
- #include <stdio.h>
- #include <math.h>
- #include <string.h>
-
- #define NUMCOLORS 11
- #define MAXLINE 8192
- #define EPSILON 0.01
- #define TRUE 1
- #define FALSE 0
-
- #define EOK 0
- #define SYSTEM -1
-
- #define RED 2
- #define GREEN 1
- #define BLUE 0
-
- typedef struct POLY Poly;
-
- typedef struct POINT{
- double x, y, z;
- int index;
- int used;
- } Point;
-
- typedef struct SEG{
- Point *p, *q;
- int index;
- Poly *poly;
- int lookupColor;
- } Seg;
-
- struct POLY{
- Point **points;
- Seg **segs;
- int red;
- int green;
- int blue;
- int numPoints;
- int numSegs;
- int index;
- int used;
- int lookupColor;
- };
-
- typedef struct HASHENTRY{
- Seg *seg;
- int used;
- } hashEntry;
-
- struct box {
- int r0; /* min value, exclusive */
- int r1; /* max value, inclusive */
- int g0;
- int g1;
- int b0;
- int b1;
- int vol;
- };
-
- /* Histogram is in elements 1..HISTSIZE along each axis,
- * element 0 is for base or marginal value
- * NB: these must start out 0!
- */
-
- float m2[33][33][33];
- long int wt[33][33][33], mr[33][33][33], mg[33][33][33], mb[33][33][33];
- unsigned char *Ir, *Ig, *Ib;
- int size; /*image size*/
- int K; /*color look-up table size*/
- unsigned int *Qadd;
-
-
- Point *dotCompareA, *dotCompareB;
- hashEntry *hashTable;
- int hashTableSize;
-
-
-
- /**********************************************************************
- Code for quantizer from Graphics Gems II starts here.
- **********************************************************************/
-
-
-
- /**********************************************************************
- C Implementation of Wu's Color Quantizer (v. 2)
- (see Graphics Gems vol. II, pp. 126-133)
-
- Author: Xiaolin Wu
- Dept. of Computer Science
- Univ. of Western Ontario
- London, Ontario N6A 5B7
- wu@csd.uwo.ca
-
- Algorithm: Greedy orthogonal bipartition of RGB space for variance
- minimization aided by inclusion-exclusion tricks.
- For speed no nearest neighbor search is done. Slightly
- better performance can be expected by more sophisticated
- but more expensive versions.
-
- The author thanks Tom Lane at Tom_Lane@G.GP.CS.CMU.EDU for much of
- additional documentation and a cure to a previous bug.
-
- Free to distribute, comments and suggestions are appreciated.
- **********************************************************************/
-
-
- static void
- Hist3d(vwt, vmr, vmg, vmb, M2)
- /* build 3-D color histogram of counts, r/g/b, c^2 */
- long int *vwt, *vmr, *vmg, *vmb;
- float *M2;
- {
- register int ind, r, g, b;
- int inr, ing, inb, table[256];
- register long int i;
-
- for(i=0; i<256; ++i) table[i]=i*i;
- Qadd = (unsigned int *)malloc(sizeof(int)*size);
- if (Qadd==NULL) {fprintf(stderr, "Not enough space\n"); exit(1);}
- for(i=0; i<size; ++i){
- r = Ir[i]; g = Ig[i]; b = Ib[i];
- inr=(r>>3)+1;
- ing=(g>>3)+1;
- inb=(b>>3)+1;
- Qadd[i]=ind=(inr<<10)+(inr<<6)+inr+(ing<<5)+ing+inb;
- /*[inr][ing][inb]*/
- ++vwt[ind];
- vmr[ind] += r;
- vmg[ind] += g;
- vmb[ind] += b;
- M2[ind] += (float)(table[r]+table[g]+table[b]);
- }
- }
-
- /* At conclusion of the histogram step, we can interpret
- * wt[r][g][b] = sum over voxel of P(c)
- * mr[r][g][b] = sum over voxel of r*P(c) , similarly for mg, mb
- * m2[r][g][b] = sum over voxel of c^2*P(c)
- * Actually each of these should be divided by 'size' to give the usual
- * interpretation of P() as ranging from 0 to 1, but we needn't do that here.
- */
-
- /* We now convert histogram into moments so that we can rapidly calculate
- * the sums of the above quantities over any desired box.
- */
-
-
- static void
- M3d(vwt, vmr, vmg, vmb, M2) /* compute cumulative moments. */
- long int *vwt, *vmr, *vmg, *vmb;
- float *M2;
- {
- register unsigned int ind1, ind2;
- register unsigned char i, r, g, b;
- long int line, line_r, line_g, line_b,
- area[33], area_r[33], area_g[33], area_b[33];
- float line2, area2[33];
-
- for(r=1; r<=32; ++r){
- for(i=0; i<=32; ++i)
- area2[i]=area[i]=area_r[i]=area_g[i]=area_b[i]=0;
- for(g=1; g<=32; ++g){
- line2 = line = line_r = line_g = line_b = 0;
- for(b=1; b<=32; ++b){
- ind1 = (r<<10) + (r<<6) + r + (g<<5) + g + b; /* [r][g][b] */
- line += vwt[ind1];
- line_r += vmr[ind1];
- line_g += vmg[ind1];
- line_b += vmb[ind1];
- line2 += M2[ind1];
- area[b] += line;
- area_r[b] += line_r;
- area_g[b] += line_g;
- area_b[b] += line_b;
- area2[b] += line2;
- ind2 = ind1 - 1089; /* [r-1][g][b] */
- vwt[ind1] = vwt[ind2] + area[b];
- vmr[ind1] = vmr[ind2] + area_r[b];
- vmg[ind1] = vmg[ind2] + area_g[b];
- vmb[ind1] = vmb[ind2] + area_b[b];
- M2[ind1] = M2[ind2] + area2[b];
- }
- }
- }
- }
-
-
- static long int Vol(cube, mmt)
- /* Compute sum over a box of any given statistic */
- struct box *cube;
- long int mmt[33][33][33];
- {
- return( mmt[cube->r1][cube->g1][cube->b1]
- -mmt[cube->r1][cube->g1][cube->b0]
- -mmt[cube->r1][cube->g0][cube->b1]
- +mmt[cube->r1][cube->g0][cube->b0]
- -mmt[cube->r0][cube->g1][cube->b1]
- +mmt[cube->r0][cube->g1][cube->b0]
- +mmt[cube->r0][cube->g0][cube->b1]
- -mmt[cube->r0][cube->g0][cube->b0] );
- }
-
- /* The next two routines allow a slightly more efficient calculation
- * of Vol() for a proposed subbox of a given box. The sum of Top()
- * and Bottom() is the Vol() of a subbox split in the given direction
- * and with the specified new upper bound.
- */
-
- static long int Bottom(cube, dir, mmt)
- /* Compute part of Vol(cube, mmt) that doesn't depend on r1, g1, or b1 */
- /* (depending on dir) */
- struct box *cube;
- unsigned char dir;
- long int mmt[33][33][33];
- {
- switch(dir){
- case RED:
- return( -mmt[cube->r0][cube->g1][cube->b1]
- +mmt[cube->r0][cube->g1][cube->b0]
- +mmt[cube->r0][cube->g0][cube->b1]
- -mmt[cube->r0][cube->g0][cube->b0] );
- break;
- case GREEN:
- return( -mmt[cube->r1][cube->g0][cube->b1]
- +mmt[cube->r1][cube->g0][cube->b0]
- +mmt[cube->r0][cube->g0][cube->b1]
- -mmt[cube->r0][cube->g0][cube->b0] );
- break;
- case BLUE:
- return( -mmt[cube->r1][cube->g1][cube->b0]
- +mmt[cube->r1][cube->g0][cube->b0]
- +mmt[cube->r0][cube->g1][cube->b0]
- -mmt[cube->r0][cube->g0][cube->b0] );
- break;
- }
- return 0;
- }
-
-
- static long int Top(cube, dir, pos, mmt)
- /* Compute remainder of Vol(cube, mmt), substituting pos for */
- /* r1, g1, or b1 (depending on dir) */
- struct box *cube;
- unsigned char dir;
- int pos;
- long int mmt[33][33][33];
- {
- switch(dir){
- case RED:
- return( mmt[pos][cube->g1][cube->b1]
- -mmt[pos][cube->g1][cube->b0]
- -mmt[pos][cube->g0][cube->b1]
- +mmt[pos][cube->g0][cube->b0] );
- break;
- case GREEN:
- return( mmt[cube->r1][pos][cube->b1]
- -mmt[cube->r1][pos][cube->b0]
- -mmt[cube->r0][pos][cube->b1]
- +mmt[cube->r0][pos][cube->b0] );
- break;
- case BLUE:
- return( mmt[cube->r1][cube->g1][pos]
- -mmt[cube->r1][cube->g0][pos]
- -mmt[cube->r0][cube->g1][pos]
- +mmt[cube->r0][cube->g0][pos] );
- break;
- }
- return 0;
- }
-
-
- static float Var(cube)
- /* Compute the weighted variance of a box */
- /* NB: as with the raw statistics, this is really the variance * size */
- struct box *cube;
- {
- float dr, dg, db, xx;
-
- dr = Vol(cube, mr);
- dg = Vol(cube, mg);
- db = Vol(cube, mb);
- xx = m2[cube->r1][cube->g1][cube->b1]
- -m2[cube->r1][cube->g1][cube->b0]
- -m2[cube->r1][cube->g0][cube->b1]
- +m2[cube->r1][cube->g0][cube->b0]
- -m2[cube->r0][cube->g1][cube->b1]
- +m2[cube->r0][cube->g1][cube->b0]
- +m2[cube->r0][cube->g0][cube->b1]
- -m2[cube->r0][cube->g0][cube->b0];
-
- return( xx - (dr*dr+dg*dg+db*db)/(float)Vol(cube,wt) );
- }
-
- /* We want to minimize the sum of the variances of two subboxes.
- * The sum(c^2) terms can be ignored since their sum over both subboxes
- * is the same (the sum for the whole box) no matter where we split.
- * The remaining terms have a minus sign in the variance formula,
- * so we drop the minus sign and MAXIMIZE the sum of the two terms.
- */
-
-
- static float Maximize(cube, dir, first, last, cut,
- whole_r, whole_g, whole_b, whole_w)
- struct box *cube;
- unsigned char dir;
- int first, last, *cut;
- long int whole_r, whole_g, whole_b, whole_w;
- {
- register long int half_r, half_g, half_b, half_w;
- long int base_r, base_g, base_b, base_w;
- register int i;
- register float temp, max;
-
- base_r = Bottom(cube, dir, mr);
- base_g = Bottom(cube, dir, mg);
- base_b = Bottom(cube, dir, mb);
- base_w = Bottom(cube, dir, wt);
- max = 0.0;
- *cut = -1;
- for(i=first; i<last; ++i){
- half_r = base_r + Top(cube, dir, i, mr);
- half_g = base_g + Top(cube, dir, i, mg);
- half_b = base_b + Top(cube, dir, i, mb);
- half_w = base_w + Top(cube, dir, i, wt);
- /* now half_x is sum over lower half of box, if split at i */
- if (half_w == 0) { /* subbox could be empty of pixels! */
- continue; /* never split into an empty box */
- } else
- temp = ((float)half_r*half_r + (float)half_g*half_g +
- (float)half_b*half_b)/half_w;
-
- half_r = whole_r - half_r;
- half_g = whole_g - half_g;
- half_b = whole_b - half_b;
- half_w = whole_w - half_w;
- if (half_w == 0) { /* subbox could be empty of pixels! */
- continue; /* never split into an empty box */
- } else
- temp += ((float)half_r*half_r + (float)half_g*half_g +
- (float)half_b*half_b)/half_w;
-
- if (temp > max) {max=temp; *cut=i;}
- }
- return(max);
- }
-
- static int
- Cut(set1, set2)
- struct box *set1, *set2;
- {
- unsigned char dir;
- int cutr, cutg, cutb;
- float maxr, maxg, maxb;
- long int whole_r, whole_g, whole_b, whole_w;
-
- whole_r = Vol(set1, mr);
- whole_g = Vol(set1, mg);
- whole_b = Vol(set1, mb);
- whole_w = Vol(set1, wt);
-
- maxr = Maximize(set1, RED, set1->r0+1, set1->r1, &cutr,
- whole_r, whole_g, whole_b, whole_w);
- maxg = Maximize(set1, GREEN, set1->g0+1, set1->g1, &cutg,
- whole_r, whole_g, whole_b, whole_w);
- maxb = Maximize(set1, BLUE, set1->b0+1, set1->b1, &cutb,
- whole_r, whole_g, whole_b, whole_w);
-
- if( (maxr>=maxg)&&(maxr>=maxb) ) {
- dir = RED;
- if (cutr < 0) return 0; /* can't split the box */
- }
- else
- if( (maxg>=maxr)&&(maxg>=maxb) )
- dir = GREEN;
- else
- dir = BLUE;
-
- set2->r1 = set1->r1;
- set2->g1 = set1->g1;
- set2->b1 = set1->b1;
-
- switch (dir){
- case RED:
- set2->r0 = set1->r1 = cutr;
- set2->g0 = set1->g0;
- set2->b0 = set1->b0;
- break;
- case GREEN:
- set2->g0 = set1->g1 = cutg;
- set2->r0 = set1->r0;
- set2->b0 = set1->b0;
- break;
- case BLUE:
- set2->b0 = set1->b1 = cutb;
- set2->r0 = set1->r0;
- set2->g0 = set1->g0;
- break;
- }
- set1->vol=(set1->r1-set1->r0)*(set1->g1-set1->g0)*(set1->b1-set1->b0);
- set2->vol=(set2->r1-set2->r0)*(set2->g1-set2->g0)*(set2->b1-set2->b0);
- return 1;
- }
-
-
- static void Mark(cube, label, tag)
- struct box *cube;
- int label;
- unsigned char *tag;
- {
- register int r, g, b;
-
- for(r=cube->r0+1; r<=cube->r1; ++r)
- for(g=cube->g0+1; g<=cube->g1; ++g)
- for(b=cube->b0+1; b<=cube->b1; ++b)
- tag[(r<<10) + (r<<6) + r + (g<<5) + g + b] = label;
- }
-
- static void quantize(red, green, blue, numColors, quantColors, lookup)
- unsigned char *red, *green, *blue;
- int numColors, *quantColors;
- unsigned *lookup;
- {
- struct box *cube;
- unsigned char *tag;
- unsigned char *lut_r, *lut_g, *lut_b;
- int next;
- register long int i, weight;
- register int k;
- float *vv, temp;
-
- if((cube = (struct box *)malloc(*quantColors * sizeof(struct box)))
- == NULL){
- fprintf(stderr, "Unable to allocate memory for cube\n");
- exit(1);
- }
-
- if((lut_r = (unsigned char *)malloc(*quantColors *
- sizeof(unsigned char))) == NULL){
- fprintf(stderr, "Unable to allocate memory for lut_r\n");
- exit(1);
- }
-
- if((lut_g = (unsigned char *)malloc(*quantColors *
- sizeof(unsigned char))) == NULL){
- fprintf(stderr, "Unable to allocate memory for lut_g\n");
- exit(1);
- }
-
- if((lut_b = (unsigned char *)malloc(*quantColors *
- sizeof(unsigned char))) == NULL){
- fprintf(stderr, "Unable to allocate memory for lut_b\n");
- exit(1);
- }
-
- if((vv = (float *)malloc(*quantColors *
- sizeof(float))) == NULL){
- fprintf(stderr, "Unable to allocate memory for lut_b\n");
- exit(1);
- }
-
- /* input R,G,B components into Ir, Ig, Ib;
- set size to width*height */
-
- Ir = red;
- Ig = green;
- Ib = blue;
- size = numColors;
- K = *quantColors;
-
- if((Ig = (unsigned char *)malloc(numColors * sizeof(unsigned char)))
- == NULL){
- fprintf(stderr, "Unable to allocate memory for Ig\n");
- exit(1);
- }
-
- if((Ib = (unsigned char *)malloc(numColors * sizeof(unsigned char)))
- == NULL){
- fprintf(stderr, "Unable to allocate memory for Ig\n");
- exit(1);
- }
-
- if((Ir = (unsigned char *)malloc(numColors * sizeof(unsigned char)))
- == NULL){
- fprintf(stderr, "Unable to allocate memory for Ig\n");
- exit(1);
- }
-
- memcpy(Ir, red, numColors * sizeof(unsigned char));
- memcpy(Ig, green, numColors * sizeof(unsigned char));
- memcpy(Ib, blue, numColors * sizeof(unsigned char));
-
- /*
- printf("no. of colors:\n");
- scanf("%d", &K);
- */
-
- Hist3d(wt, mr, mg, mb, m2); fprintf(stderr, "Histogram done\n");
-
- free(Ig); free(Ib); free(Ir);
-
- M3d(wt, mr, mg, mb, m2); fprintf(stderr, "Moments done\n");
-
- cube[0].r0 = cube[0].g0 = cube[0].b0 = 0;
- cube[0].r1 = cube[0].g1 = cube[0].b1 = 32;
- next = 0;
- for(i=1; i<K; ++i){
- if (Cut(&cube[next], &cube[i])) {
- /* volume test ensures we won't try to cut one-cell box */
- vv[next] = (cube[next].vol>1) ? Var(&cube[next]) : 0.0;
- vv[i] = (cube[i].vol>1) ? Var(&cube[i]) : 0.0;
- } else {
- vv[next] = 0.0; /* don't try to split this box again */
- i--; /* didn't create box i */
- }
- next = 0; temp = vv[0];
- for(k=1; k<=i; ++k)
- if (vv[k] > temp) {
- temp = vv[k]; next = k;
- }
- if (temp <= 0.0) {
- K = i+1;
- fprintf(stderr, "Only got %d boxes\n", K);
- break;
- }
- }
- fprintf(stderr, "Partition done\n");
-
- /* the space for array m2 can be freed now */
-
- tag = (unsigned char *)malloc(33*33*33);
- if (tag==NULL) {fprintf(stderr, "Not enough space\n"); exit(1);}
- for(k=0; k<K; ++k){
- Mark(&cube[k], k, tag);
- weight = Vol(&cube[k], wt);
- if (weight) {
- lut_r[k] = Vol(&cube[k], mr) / weight;
- lut_g[k] = Vol(&cube[k], mg) / weight;
- lut_b[k] = Vol(&cube[k], mb) / weight;
- }
- else{
- fprintf(stderr, "bogus box %d\n", k);
- lut_r[k] = lut_g[k] = lut_b[k] = 0;
- }
- }
-
- for(i=0; i<size; ++i) Qadd[i] = tag[Qadd[i]];
-
- /* output lut_r, lut_g, lut_b as color look-up table contents,
- Qadd as the quantized image (array of table addresses). */
-
- free(tag);
- memcpy(red, lut_r, *quantColors);
- memcpy(green, lut_g, *quantColors);
- memcpy(blue, lut_b, *quantColors);
- memcpy(lookup, Qadd, numColors * sizeof(int));
- *quantColors = K;
- free(cube);
- free(lut_r);
- free(lut_g);
- free(lut_b);
- free(vv);
- }
-
-
-
-
- /******************************************************************************
- My own hull.c code starts here.
- ******************************************************************************/
-
-
-
-
- static int fequal(x,y)
- double x, y;
- /******************************************************************************/
- /* Are x and y scaled equal within epsilon? */
- /******************************************************************************/
- {
- return (((fabs((x) - (y))) / (fabs(x) + 1.0)) < EPSILON);
- }
-
-
-
- static int pointEqual(p,q)
- Point *p, *q;
- /******************************************************************************/
- /* Are p and q equal? */
- /******************************************************************************/
- {
- return(fequal(p->x,q->x) && fequal(p->y,q->y) && fequal(p->z,q->z));
- }
-
-
-
- static void hash(p,q,segs,numSegs,seg,maxSegs,poly)
- Point *p, *q;
- Seg *segs;
- int *numSegs;
- Seg **seg;
- int maxSegs;
- Poly *poly;
- /******************************************************************************/
- /* Compute hash function for segment */
- /******************************************************************************/
- {
- int value, index;
-
- value = ((int)(p->x * q->x) + (int)(p->y * q->y) +
- (int)(p->z * q->z));
-
- if(value < 0){
- value = (-value) % hashTableSize;
- }else{
- value = value % hashTableSize;
- }
-
- index = value;
-
- while((hashTable[index].used == TRUE) && (
- !((p->x == hashTable[index].seg->p->x) &&
- (p->y == hashTable[index].seg->p->y) &&
- (p->z == hashTable[index].seg->p->z) &&
- (q->x == hashTable[index].seg->q->x) &&
- (q->y == hashTable[index].seg->q->y) &&
- (q->z == hashTable[index].seg->q->z)) )&&(
- !((q->x == hashTable[index].seg->p->x) &&
- (q->y == hashTable[index].seg->p->y) &&
- (q->z == hashTable[index].seg->p->z) &&
- (p->x == hashTable[index].seg->q->x) &&
- (p->y == hashTable[index].seg->q->y) &&
- (p->z == hashTable[index].seg->q->z)))) {
- index = (index + 1) % hashTableSize;
- }
-
- if(hashTable[index].used == TRUE){
- *seg = hashTable[index].seg;
- }else{
-
- if(*numSegs == maxSegs){
- fprintf(stderr, "Too many Segments\n");
- exit(1);
- }
-
- hashTable[index].seg = &(segs[*numSegs]);
- segs[*numSegs].p = p;
- segs[*numSegs].q = q;
- segs[*numSegs].poly = poly;
- p->used = TRUE;
- q->used = TRUE;
- segs[*numSegs].index = *numSegs;
- (*numSegs)++;
-
- hashTable[index].used = TRUE;
- *seg = hashTable[index].seg;
- }
- }
-
-
-
- static int comparePoints(p,q)
- Point *p, *q;
- /******************************************************************************/
- /* Compare p and q. */
- /******************************************************************************/
- {
- /* Sorted by X, Y, then Z */
-
- /* Lower X comes before higher X */
-
- if(p->x < q->x)
- return -1;
-
- if(p->x > q->x)
- return 1;
-
- /* Lower Y comes before higher Y */
-
- if(p->y < q->y)
- return -1;
-
- if(p->y > q->y)
- return 1;
-
- /* Lower Z comes before higher Z */
-
- if(p->z < q->z)
- return -1;
-
- if(p->z > q->z)
- return 1;
-
- return 0;
- }
-
-
-
- static int pComparePoints(p,q)
- Point **p, **q;
- /******************************************************************************/
- /* Compare p and q. */
- /******************************************************************************/
- {
- return comparePoints(*p,*q);
- }
-
-
-
- static int comparePolys(p,q)
- Poly *p, *q;
- /******************************************************************************/
- /* Compare p and q. */
- /******************************************************************************/
- {
- int index;
-
- if(p->numPoints < q->numPoints){
- return -1;
- }
-
- if(p->numPoints > q->numPoints){
- return 1;
- }
-
- index = 0;
-
- while(index < p->numPoints){
-
- if(p->points[index] < q->points[index])
- return -1;
-
- if(p->points[index] > q->points[index])
- return 1;
-
- index++;
- }
-
- return 0;
- }
-
-
-
- static int colorComparePolys(p,q)
- Poly *p, *q;
- /******************************************************************************/
- /* Compare p and q by color. */
- /******************************************************************************/
- {
- if(p->lookupColor < q->lookupColor){
- return -1;
- }
-
- if(p->lookupColor > q->lookupColor){
- return 1;
- }
-
- return 0;
- }
-
-
-
- static int colorCompareSegs(p,q)
- Seg *p, *q;
- /******************************************************************************/
- /* Compare p and q by color. */
- /******************************************************************************/
- {
- if(p->lookupColor < q->lookupColor){
- return -1;
- }
-
- if(p->lookupColor > q->lookupColor){
- return 1;
- }
-
- return 0;
- }
-
-
-
- static double dot(a, b, c)
- Point *a, *b, *c;
- /******************************************************************************/
- /* Compute ab (dot) ac. */
- /******************************************************************************/
- {
- double X1, Y1, Z1, X2, Y2, Z2, len1, len2;
-
- if((comparePoints(a, b) == 0) || (comparePoints(a, c) == 0)){
- return 2.0;
- }
-
- X1 = b->x - a->x; Y1 = b->y - a->y; Z1 = b->z - a->z;
- X2 = c->x - a->x; Y2 = c->y - a->y; Z2 = c->z - a->z;
-
- len1 = sqrt(X1 * X1 + Y1 * Y1 + Z1 * Z1);
- len2 = sqrt(X2 * X2 + Y2 * Y2 + Z2 * Z2);
-
- X1 /= len1; Y1 /= len1; Z1 /= len1;
- X2 /= len2; Y2 /= len2; Z2 /= len2;
-
- return(X1 * X2 + Y1 * Y2 + Z1 * Z2);
- }
-
-
-
- static int dotComparePoints(p,q)
- Point **p, **q;
- /******************************************************************************/
- /* Compare p and q. */
- /******************************************************************************/
- {
- double dotP, dotQ;
-
- dotP = dot(dotCompareA, dotCompareB, *p);
- dotQ = dot(dotCompareA, dotCompareB, *q);
-
- if(dotP < dotQ)
- return -1;
-
- if(dotP > dotQ)
- return 1;
-
- return 0;
- }
-
-
-
- static int readPoints(filename, points, numPoints, polys, numPolys, maxPoints,
- maxPolys)
- char *filename;
- Point **points;
- int *numPoints;
- Poly **polys;
- int *numPolys;
- int *maxPoints;
- int *maxPolys;
- /******************************************************************************/
- /* Read in a list of polygons from a file into the points, lines, and poly */
- /* arrays. */
- /******************************************************************************/
- {
- float X, Y, Z;
- double x, y, z;
- int count = 0, lineNo = 0, needColor = TRUE;
- int index, index2;
- char line[MAXLINE];
- FILE *fd;
-
- *numPoints = 0;
- *numPolys = 0;
-
- /* Try to open the file */
-
- if(strcmp(filename, "-") == 0){
- fd = stdin;
- }else{
- if((fd = fopen(filename, "r")) == NULL){
- fprintf(stderr, "Unable to open file %s\n", filename);
- exit(1);
- }
- }
-
- while(fgets(line, MAXLINE, fd) != NULL){
-
- /* Warn about long lines */
-
- if(strlen(line) > (MAXLINE - 5)){
- fprintf(stderr, "Line too long on line %d, line may be trucated.\n",
- lineNo);
- exit(1);
- }
-
- /* ignore comments */
-
- lineNo++;
-
- count = sscanf(line, "%f %f %f\n", &X, &Y, &Z);
-
- x = (double)X; y = (double)Y; z = (double)Z;
-
- if((strcmp(line, "\n") == 0) || (count == 0)){
-
- if((*polys)[*numPolys].numPoints != 0){
- (*numPolys)++;
- if(*numPolys == *maxPolys){
- if((*polys = (Poly *)realloc(*polys, ((*numPolys) + 100) *
- sizeof(Poly))) == NULL){
- fprintf(stderr,
- "Unable to allocate memory for polygons on line %d\n",
- lineNo);
- exit(1);
- }
- bzero(&((*polys)[*maxPolys]), 100 * sizeof(Poly));
- (*maxPolys) += 100;
- }
- needColor = TRUE;
- }
- }else{
-
- if(count != 3){
- fprintf(stderr, "Mismatch on line %d, %d items matched\n",
- lineNo, count);
- exit(1);
- }
-
- if(needColor == FALSE){
-
- if(*numPoints == *maxPoints){
- if((*points = (Point *)realloc(*points, (*maxPoints + 100)
- * sizeof(Point))) == NULL){
- fprintf(stderr,
- "Unable to allocate memory for points on line %d\n", lineNo);
- exit(1);
- }
- bzero(&((*points)[*maxPoints]), 100 * sizeof(Point));
- (*maxPoints) += 100;
- }
-
- if((*polys)[*numPolys].numPoints == 0){
- if(((*polys)[*numPolys].points = (Point **)malloc(
- sizeof(Point *))) == NULL){
- fprintf(stderr,
- "Unable to allocate memory for polygon points on line %d\n",
- lineNo);
- exit(1);
- }
- }else{
- if((((*polys)[*numPolys].points = (Point **)realloc(
- (*polys)[*numPolys].points, ((*polys)[*numPolys].numPoints
- + 1) * sizeof(Point *)))) == NULL){
- fprintf(stderr,
- "Unable to allocate memory for polygon points on line %d\n",
- lineNo);
- exit(1);
- }
- }
-
- /* BEWARE: Evil cast just below!!! */
-
- (*polys)[*numPolys].points[(*polys)[*numPolys].numPoints] =
- (Point *)(&((*points)[*numPoints]) - (*points));
-
- ((*polys)[*numPolys].numPoints)++;
-
- (*points)[*numPoints].x = x;
- (*points)[*numPoints].y = y;
- (*points)[*numPoints].z = z;
-
- (*numPoints)++;
-
- }else{
-
- if((x < 0.0) || (x > 255.0) ||
- (y < 0.0) || (y > 255.0) ||
- (z < 0.0) || (z > 255.0)){
- fprintf(stderr,
- "Color out of range ( %f %f %f ) on line %d\n",
- x, y, z, lineNo);
- exit(1);
- }
-
- (*polys)[*numPolys].red = (int)x;
- (*polys)[*numPolys].green = (int)y;
- (*polys)[*numPolys].blue = (int)z;
- needColor = FALSE;
- }
- }
- }
-
- if(feof(fd) == FALSE)
- return SYSTEM;
-
- if((*polys)[*numPolys].numPoints != 0){
- (*numPolys)++;
- }
-
- fclose(fd);
-
- /* Undo the Evilness of the Evil cast above */
-
- for(index = 0; index < *numPolys; index++){
- for(index2 = 0; index2 < (*polys)[index].numPoints; index2++){
- (*polys)[index].points[index2] =
- &((*points)[(int)(*polys)[index].points[index2]]);
- }
- }
-
- return(EOK);
- }
-
-
-
- static void eliminateDuplicatePoints(points, numPoints, polys, numPolys,
- maxPoints)
- Point **points;
- int *numPoints;
- Poly *polys;
- int numPolys;
- int *maxPoints;
- /******************************************************************************/
- /* Eliminate duplicate points. */
- /******************************************************************************/
- {
- Point *pointsCopy;
- Point *outPoints;
- int index, numOutPoints, index2, oldIndex;
-
- /* Sort the point list by coordinates */
-
- for(index = 0; index < *numPoints; index++){
- (*points)[index].index = index;
- }
-
- if((pointsCopy = (Point *)malloc(*maxPoints * sizeof(Point))) == NULL){
- fprintf(stderr, "Unable to allocate memory for points\n");
- exit(1);
- }
-
- if((outPoints = (Point *)malloc(*maxPoints * sizeof(Point))) == NULL){
- fprintf(stderr, "Unable to allocate memory for points\n");
- exit(1);
- }
-
- memcpy(pointsCopy, *points, *numPoints * sizeof(Point));
- qsort(pointsCopy, *numPoints, sizeof(Point), comparePoints);
-
- /* Eliminate duplicate points */
-
- index = 0;
- numOutPoints = 0;
-
- oldIndex = pointsCopy[index].index;
- outPoints[numOutPoints] = pointsCopy[index];
- pointsCopy[index].index = numOutPoints;
- (*points)[oldIndex].index = pointsCopy[index].index;
- numOutPoints++;
-
- for(index = 1; index < *numPoints; index++){
- oldIndex = pointsCopy[index].index;
- if(pointEqual(&(pointsCopy[index]), &(pointsCopy[index - 1]))){
- pointsCopy[index].index = pointsCopy[index - 1].index;
- }else{
- outPoints[numOutPoints] = pointsCopy[index];
- pointsCopy[index].index = numOutPoints;
- numOutPoints++;
- }
- (*points)[oldIndex].index = pointsCopy[index].index;
- }
-
- if((outPoints = (Point *)realloc(outPoints, numOutPoints * sizeof(Point)))
- == NULL){
- fprintf(stderr, "Unable to allocate memory for points\n");
- exit(1);
- }
-
- for(index = 0; index < numPolys; index++){
-
- if(polys[index].numPoints < 3){
- fprintf(stderr, "Too few points (%d) in polygon %d\n",
- polys[index].numPoints, index);
- exit(1);
- }
-
- for(index2 = 0; index2 < polys[index].numPoints; index2++){
- polys[index].points[index2] =
- &(outPoints[polys[index].points[index2]->index]);
- }
- }
-
- free(pointsCopy);
- free(*points);
-
- *numPoints = numOutPoints;
- *points = outPoints;
- }
-
-
-
- static int formPolygonsSegments(points, numPoints, polys, numPolys, segs,
- numSegs, numPointsUsed, numPolysUsed, maxSegs, dupPolys, invalidPolys)
- Point *points;
- int *numPoints;
- Poly *polys;
- int *numPolys;
- Seg *segs;
- int *numSegs;
- int *numPointsUsed;
- int *numPolysUsed;
- int maxSegs;
- int *dupPolys;
- int *invalidPolys;
- /******************************************************************************/
- /* Generate the list of line segments for the polygons. */
- /******************************************************************************/
- {
- int index, index2, index3;
- Point **polyPoints;
- Seg *seg;
-
- *dupPolys = 0;
- *invalidPolys = 0;
- *numSegs = 0;
-
- for(index = 0; index < *numPoints; index++){
- points[index].index = index;
- points[index].used = FALSE;
- }
-
- for(index = 0; index < *numPolys; index++){
-
- /* sort the poly's points by coordinates for finding duplicate polys */
-
- qsort(polys[index].points, polys[index].numPoints, sizeof(Point *),
- pComparePoints);
-
- polys[index].used = TRUE;
- }
-
- /* Sort the polygons */
-
- qsort(polys, *numPolys, sizeof(Poly), comparePolys);
-
- /* Tag duplicate polygons */
-
- if(*numPolys > 0){
- *numPolysUsed = 1;
- }
-
- for(index = 1; index < *numPolys; index++){
-
- if((comparePolys((&(polys[index - 1])), (&(polys[index])))) == 0){
- polys[index].used = FALSE;
- (*dupPolys)++;
- }else{
- (*numPolysUsed)++;
- }
- }
-
- /* Assemble valid polygons */
-
- for(index = 0; index < *numPolys; index++){
-
- if(polys[index].used == TRUE){
- polyPoints = polys[index].points;
- polys[index].numSegs = 0;
-
- /* Sort copy of the poly's points by angle to get another point on the */
- /* convex hull */
-
- dotCompareA = polyPoints[0];
- dotCompareB = polyPoints[1];
-
- qsort(polyPoints, polys[index].numPoints, sizeof(Point *),
- dotComparePoints);
-
- /* Sort copy of the poly's points by angle with respect to the segment on the */
- /* convex hull */
-
- dotCompareB = dotCompareA;
- dotCompareA = polyPoints[0];
-
- qsort(polyPoints, polys[index].numPoints, sizeof(Point *),
- dotComparePoints);
-
- /* Set line segments */
-
- dotCompareA = polyPoints[0];
- dotCompareB = polyPoints[polys[index].numPoints - 1];
-
- index2 = 1;
-
- while(index2 < (polys[index].numPoints - 1)){
-
- if(dotComparePoints(&(polyPoints[index2]),
- &(polyPoints[index2 + 1])) >= 0){
-
- /* if point would make polygon non-convex delete it */
-
- polys[index].numPoints--;
- for(index3 = index2; index3 < polys[index].numPoints; index3++){
- polyPoints[index3] = polyPoints[index3 + 1];
- }
- }else{
-
- /* keep the point and add the line segment */
-
- if(polys[index].numSegs == 0){
- if((polys[index].segs = (Seg **)malloc(
- sizeof(Seg *))) == NULL){
- fprintf(stderr,
- "Unable to allocate memory for polygon segments\n");
- exit(1);
- }
- }else{
- if((polys[index].segs = (Seg **)realloc(polys[index].segs,
- (polys[index].numSegs + 1) * sizeof(Seg *))) == NULL){
- fprintf(stderr,
- "Unable to allocate memory for polygon segments\n");
- exit(1);
- }
- }
-
- hash(dotCompareA,polyPoints[index2],segs,numSegs,&seg,
- maxSegs, &(polys[index]));
-
- polys[index].segs[polys[index].numSegs] = seg;
- (polys[index].numSegs)++;
-
- dotCompareB = dotCompareA;
- dotCompareA = polyPoints[index2];
-
- index2++;
- }
- }
-
- /* Close off the polygon */
-
- if(polys[index].numSegs == 0){
- polys[index].used = FALSE;
- (*numPolysUsed)--;
- (*invalidPolys)++;
- }else{
-
- if((polys[index].segs = (Seg **)realloc(polys[index].segs,
- (polys[index].numSegs + 1) * sizeof(Seg *))) == NULL){
- fprintf(stderr,
- "Unable to allocate memory for polygon segments\n");
- exit(1);
- }
-
- hash(polyPoints[polys[index].numPoints - 2],
- polyPoints[polys[index].numPoints - 1], segs, numSegs, &seg,
- maxSegs, &(polys[index]));
-
- polys[index].segs[polys[index].numSegs] = seg;
- (polys[index].numSegs)++;
-
- if((polys[index].segs = (Seg **)realloc(polys[index].segs,
- (polys[index].numSegs + 1) * sizeof(Seg *))) == NULL){
- fprintf(stderr,
- "Unable to allocate memory for polygon segments\n");
- exit(1);
- }
-
- hash(polyPoints[polys[index].numPoints - 1],
- polyPoints[0], segs, numSegs, &seg,
- maxSegs, &(polys[index]));
-
- polys[index].segs[polys[index].numSegs] = seg;
- (polys[index].numSegs)++;
- }
- }
- }
-
- index2 = 0;
-
- for(index = 0; index < *numPoints; index++){
- if(points[index].used == TRUE){
- points[index].index = index2++;
- }else{
- points[index].index = -1;
- }
- }
-
- *numPointsUsed = index2;
-
- return EOK;
- }
-
-
-
- void main(argc, argv)
- int argc;
- char **argv;
- {
- FILE *fd;
- Point *points;
- Poly *polys;
- Seg *segs, *segCopy;
- int numPoints, numPolys, numSegs, numPointsUsed, numPolysUsed;
- int maxPoints, maxPolys, maxSegs, numColors;
- int index, index2, dupPolys, invalidPolys;
- unsigned char *red, *green, *blue;
- unsigned int *lookup;
- char line[MAXLINE];
-
- if(argc == 4){
- numColors = atol(argv[3]);
- (void)sprintf(line, "%d", numColors);
-
- if((strcmp(line, argv[3])) || (numColors < 1)){
- fprintf(stderr, "\n\nIllegal number of colors specified\n");
- fprintf(stderr, "\nUsage: %s <infile> <outfile> [colors]\n", argv[0]);
- fprintf(stderr, "Use - for standard input or output\n");
- fprintf(stderr, "<infile> File to read polygons from\n");
- fprintf(stderr, "<outfile> File to write object to\n");
- fprintf(stderr, "[colors] Number of colors to quantize to\n");
- fprintf(stderr, " Default = %d\n", NUMCOLORS);
- fprintf(stderr, "\n");
- exit(1);
- }
- }else{
- numColors = NUMCOLORS;
- }
-
- if((argc != 3) && (argc != 4)){
- fprintf(stderr, "\nUsage: %s <infile> <outfile> [colors]\n", argv[0]);
- fprintf(stderr, "Use - for standard input or output\n");
- fprintf(stderr, "<infile> File to read polygons from\n");
- fprintf(stderr, "<outfile> File to write object to\n");
- fprintf(stderr, "[colors] Number of colors to quantize to\n");
- fprintf(stderr, " Default = %d\n", NUMCOLORS);
- fprintf(stderr, "\n");
- exit(1);
- }
-
- maxPoints = 100;
- maxPolys = 100;
-
- if((points = (Point *)calloc(1, maxPoints * sizeof(Point))) == NULL){
- fprintf(stderr, "Unable to allocate memory for points\n");
- exit(1);
- }
-
- if((polys = (Poly *)calloc(1, maxPolys * sizeof(Poly))) == NULL){
- fprintf(stderr, "Unable to allocate memory for polygons\n");
- exit(1);
- }
-
- readPoints(argv[1], &points, &numPoints, &polys, &numPolys, &maxPoints,
- &maxPolys);
-
- if(numPolys <= 0){
- fprintf(stderr, "No polygons found from which to generate object.\n");
- exit(1);
- }
-
- eliminateDuplicatePoints(&points, &numPoints, polys, numPolys, &maxPoints);
-
- maxSegs = (maxPoints * 3) / 2;
-
- if((segs = (Seg *)calloc(1, maxSegs * sizeof(Seg))) == NULL){
- fprintf(stderr, "Unable to allocate memory for segments\n");
- exit(1);
- }
-
- hashTableSize = maxSegs + 1000;
-
- if((hashTable = (hashEntry *)calloc(1, hashTableSize * sizeof(hashEntry)))
- == NULL){
- fprintf(stderr, "Unable to allocate memory for hashTable\n");
- exit(1);
- }
-
- formPolygonsSegments(points, &numPoints, polys, &numPolys, segs, &numSegs,
- &numPointsUsed, &numPolysUsed, maxSegs, &dupPolys, &invalidPolys);
-
- if(strcmp(argv[2], "-") == 0){
- fd = stdout;
- }else{
- if((fd = fopen(argv[2], "w")) == NULL){
- fprintf(stderr, "Unable to open file %s\n", argv[2]);
- exit(1);
- }
- }
-
- if((red = (unsigned char *)calloc(1, numPolys * sizeof(unsigned char)))
- == NULL){
- fprintf(stderr, "Unable to allocate memory for red\n");
- exit(1);
- }
-
- if((green = (unsigned char *)calloc(1, numPolys * sizeof(unsigned char)))
- == NULL){
- fprintf(stderr, "Unable to allocate memory for green\n");
- exit(1);
- }
-
- if((blue = (unsigned char *)calloc(1, numPolys * sizeof(unsigned char)))
- == NULL){
- fprintf(stderr, "Unable to allocate memory for blue\n");
- exit(1);
- }
-
- if((lookup = (unsigned int*)calloc(1, numPolys *
- sizeof(unsigned int))) == NULL){
- fprintf(stderr, "Unable to allocate memory for lookup\n");
- exit(1);
- }
-
- for(index = 0; index < numPolys; index++){
- red[index] = polys[index].red;
- green[index] = polys[index].green;
- blue[index] = polys[index].blue;
- }
-
- quantize(red, green, blue, numPolys, &numColors, lookup);
-
- fprintf(fd, "# x3d 2.0 object file generated by %s using %s\n\n",
- argv[0], argv[1]);
- fprintf(fd, "# number of colors used in object\n\n");
- fprintf(fd, "%d\n\n", numColors);
- fprintf(fd, "# colors used in object (color number red green blue)\n\n");
-
- for(index = 0; index < numColors; index++){
- fprintf(fd, "%d %d %d %d\n", index, red[index],
- green[index], blue[index]);
- }
-
- free(red);
- free(green);
- free(blue);
-
- fprintf(fd, "\n");
- fprintf(fd, "# number of points used in object\n\n");
- fprintf(fd, "%d\n\n", numPointsUsed);
- fprintf(fd, "# points used in object (point number x y z)\n\n");
-
- for(index = 0; index < numPoints; index++){
- if(points[index].used == TRUE){
- fprintf(fd, "%d %f %f %f\n", points[index].index,
- (float)points[index].x, (float)points[index].y, (float)points[index].z);
- }
- }
-
- /* Sort segments and polygons by color in hope of reducing foreground */
- /* color changes in x3d */
-
- for(index = 0; index < numSegs; index++){
- segs[index].lookupColor = lookup[segs[index].poly - polys];
- }
-
- if((segCopy = (Seg *)calloc(1, numSegs * sizeof(Seg))) == NULL){
- fprintf(stderr, "Unable to allocate memory for segCopy\n");
- exit(1);
- }
-
- memcpy(segCopy, segs, numSegs * sizeof(Seg));
-
- qsort(segCopy, numSegs, sizeof(Seg), colorCompareSegs);
-
- for(index = 0; index < numSegs; index++){
- segs[segCopy[index].index].index = index;
- segCopy[index].index = index;
- }
-
- for(index = 0; index < numPolys; index++){
- polys[index].lookupColor = lookup[index];
- }
-
- qsort(polys, numPolys, sizeof(Poly), colorComparePolys);
-
- fprintf(fd, "\n");
- fprintf(fd, "# number segments used in object\n\n");
- fprintf(fd, "%d\n\n", numSegs);
- fprintf(fd, "# segments used in object (segment number color p q)\n\n");
-
- for(index = 0; index < numSegs; index++){
- fprintf(fd, "%d %d %d %d\n", segCopy[index].index,
- segCopy[index].lookupColor, segCopy[index].p->index,
- segCopy[index].q->index);
- }
-
- fprintf(fd, "\n");
- fprintf(fd, "# number of polygons used in object\n\n");
- fprintf(fd, "%d\n\n", numPolysUsed);
- fprintf(fd, "# polygons used in object (polygon number color\n");
- fprintf(fd, "# number of segments in polygon s0 s1 s2 ... sn)\n\n");
-
- index2 = 0;
-
- for(index = 0; index < numPolys; index++){
- if(polys[index].used == TRUE){
- fprintf(fd, "%d %d %d ", index, polys[index].lookupColor,
- polys[index].numSegs);
- index2++;
- for(index2 = 0; index2 < polys[index].numSegs; index2++){
- fprintf(fd, " %d", polys[index].segs[index2]->index);
- }
- fprintf(fd, "\n");
- }
- }
-
- fprintf(stderr, "\nConversion successful:\n\n");
- fprintf(stderr, "%8d colors used in object.\n", numColors);
- fprintf(stderr, "%8d points used in object\n", numPointsUsed);
- fprintf(stderr, "%8d segments used in object\n", numSegs);
- fprintf(stderr, "%8d polygons used in object\n", numPolysUsed);
- fprintf(stderr, "%8d duplicate polygons removed.\n", dupPolys);
- fprintf(stderr, "%8d invalid polygons removed.\n", invalidPolys);
- fprintf(stderr, "\n");
- }
-