home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
gdead.berkeley.edu
/
gdead.berkeley.edu.tar
/
gdead.berkeley.edu
/
pub
/
cad-tools
/
pgsort.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-05
|
9KB
|
429 lines
/*
* Sort a mann formatted file in preparation for saving the GCA pattern
* generator some work.
* Mann format is:
* L <layer-name>;
* B <width> <height> <x> <y> <foo> <bar>;
* E
* where foo and bar are optional rotation values.
* Sort layer by layer.
* Within a layer, sort by width, then height, with the special
* consideration that the heights for a given width may be output
* in reverse order to prevent a sawtooth movement.
* For a given size of box, try to minimize positional movement.
* Subsorts are done at output time.
*/
#include <stdio.h>
#include <ctype.h>
#include <math.h>
FILE *Input, *I2;
FILE *Output;
char LayerName[32];
int LayerCount;
int LastXPos, LastYPos;
long LayerStartTell;
char *nil = "0";
char *malloc(), *NextNum();
#define RFUNK 32828392
double StatCnt, StatSum1, StatSum2, StatSqr1, StatSqr2;
double Var1, Var2;
int Which;
struct datum {
long d; /* file position */
int d_w;
int d_h;
int d_x;
int d_y;
int d_r1;
int d_r2;
};
main(argc, argv)
int argc;
char **argv;
{
if (argc != 3) {
fputs("pgsort: improper argument count\n", stderr);
exit(1);
}
Input = fopen(argv[1], "r"); /* seek file */
I2 = fopen(argv[1], "r"); /* toplevel read file */
if (! Input || ! I2) {
perror(argv[1]);
exit(1);
}
Output = fopen(argv[2], "w"); /* the result */
if (! Output) {
perror(argv[1]);
exit(1);
}
TopLevel(); /* do it */
exit(0);
}
TopLevel()
{
char nextLayer[128]; /* storage for next layer */
char buf[BUFSIZ];
int onceThrough = 0; /* iteration control */
int globalLine = 0;
int layerLine;
for (;;) { /* loop once per layer */
if (! onceThrough) {
if (! fgets(buf, BUFSIZ, I2) ) {
fputs("pgsort: premature EOF\n", stderr);
exit(1);
}
globalLine++;
}
fputs(buf, Output); /* dump line */
if (buf[0] == 'L') { /* start layer */
LayerStartTell = ftell(I2); /* start of boxes */
strcpy(LayerName, buf + 2); /* save name too */
LayerCount = 0;
for (;;) { /* loop once per box in layer */
if (! fgets(buf, BUFSIZ, I2) ) {
fputs("pgsort: premature EOF\n", stderr);
exit(1);
}
globalLine++;
LayerCount++;
if (buf[0] == 'L' || buf[0] == 'E') {
onceThrough = 1;
LayerCount--;
LastXPos = 0;
LastYPos = 0;
DoLayerInput();
break;
} else if (buf[0] != 'B') {
fprintf(stderr,
"pgsort: unknown command at line %d\n", globalLine);
fputs(buf, Output);
}
} /* end of layer loop */
} else if (buf[0] == 'E') { /* end of file */
break;
} else {
fprintf(stderr, "pgsort: unknown command at line %d\n", globalLine);
}
} /* end of file loop */
}
/*
* Given the name of the layer already output, and the start of the
* boxes in the given layer, and the number of lines (useful or no)
* in the current layer, sort and output the layer.
*/
DoLayerInput()
{
int count, lcount;
register char *cp;
register struct datum *dp, **dpp;
struct datum *dBase, **dpBase;
char buf[BUFSIZ];
dBase = (struct datum *) malloc((LayerCount + 1) * sizeof (struct datum));
dpBase = (struct datum**) malloc((LayerCount + 1) * sizeof (int *));
if (! dBase || ! dpBase) {
fputs("pgsort: out of memory\n", stderr);
exit(1);
}
fseek(Input, LayerStartTell, 0); /* goto point of interest */
count = 0;
lcount = 0;
dp = dBase;
dpp = dpBase;
StatReset();
while (lcount < LayerCount) {
if (! fgets(buf, BUFSIZ, Input) ) {
fputs("pgsort: unexpected EOF\n", stderr);
exit(1);
}
lcount++;
if (buf[0] == 'B') {
count++;
cp = NextNum(buf); /* stash the line */
dp->d_w = atoi(cp);
cp = NextNum(cp);
dp->d_h = atoi(cp);
cp = NextNum(cp);
dp->d_x = atoi(cp);
cp = NextNum(cp);
dp->d_y = atoi(cp);
cp = NextNum(cp);
if (cp != nil) {
dp->d_r1 = atoi(cp);
cp = NextNum(cp);
dp->d_r2 = atoi(cp);
} else {
dp->d_r1 = RFUNK;
}
Sigma(dp->d_w, dp->d_h);
*dpp++ = dp;
dp++;
}
} /* end of layer read loop */
if (count) {
Variance();
Which = (Var2 > Var1);
DumpLayerStats(dpBase, count, 0);
SortBySize(dpBase, count);
OutputSort(dpBase, count);
DumpLayerStats(dpBase, count, 1);
DumpOutput(dpBase, count);
}
free((char*)dBase);
free((char*)dpBase);
}
/*
* Comparison function for box sizes.
*/
SizeSort(a1, a2)
struct datum **a1, **a2;
{
register struct datum *d1, *d2;
d1 = *a1;
d2 = *a2;
if (Which) /* variance of h > variance of w */
if (d1->d_h != d2->d_h)
if (d1->d_h < d2->d_h)
return (-1);
else
return (1);
else if (d1->d_w != d2->d_w)
if (d1->d_w < d2->d_w)
return (-1);
else
return (1);
else
return (0);
else
if (d1->d_w != d2->d_w)
if (d1->d_w < d2->d_w)
return (-1);
else
return (1);
else if (d1->d_h != d2->d_h)
if (d1->d_h < d2->d_h)
return (-1);
else
return (1);
else
return (0);
}
/*
* Do the sort. Not too difficult.
*/
SortBySize(dpp, n)
struct datum **dpp;
int n;
{
qsort((char*)dpp, n, sizeof (struct datum *), SizeSort);
}
/*
* Reverse order of given chunk.
* d2 is just past end of area of interest.
*/
SortOutput(d1, d2)
register struct datum **d1, **d2;
{
struct datum *d;
while (d1 < --d2) {
d = *d1;
*d1++ = *d2;
*d2 = d;
}
}
/*
* Perform secondary optimizations.
*/
OutputSort(dpBase, n)
struct datum **dpBase;
int n;
{
register struct datum **d1, **d2;
int lastH = 0, x1, x2;
d2 = dpBase;
while (n) { /* loop once per width value */
d1 = d2;
do {
d2++, n--;
} while (n && (*d2)->d_w == (*d1)->d_w);/* stop @ end or change */
if (d2 > d1 + 1) {
if ( (x1 = (*d1)->d_h - lastH) < 0)
x1 = -x1;
if ( (x2 = (*d2[-1]).d_h - lastH) < 0)
x2 = -x2;
if (x1 > x2)
SortOutput(d1, d2);
}
lastH = (*d2[-1]).d_h;
SortPositions(d1, d2 - d1);
}
}
/*
* Do a sort of same sized boxes based on their positions.
*/
PosSort(a1, a2)
struct datum **a1, **a2;
{
register struct datum *d1, *d2;
d1 = *a1;
d2 = *a2;
if (Which) /* variance of y > variance of x */
if (d1->d_y != d2->d_y)
if (d1->d_y < d2->d_y)
return (-1);
else
return (1);
else if (d1->d_x != d2->d_x)
if (d1->d_x < d2->d_x)
return (-1);
else
return (1);
else
return (0);
else
if (d1->d_x != d2->d_x)
if (d1->d_x < d2->d_x)
return (-1);
else
return (1);
else if (d1->d_y != d2->d_y)
if (d1->d_y < d2->d_y)
return (-1);
else
return (1);
else
return (0);
}
/*
* Given a chunk in which all widths are the same,
* find all identical boxes and sort them by position.
*/
SortPositions(dpBase, n)
struct datum **dpBase;
int n;
{
register struct datum **d1, **d2;
d2 = dpBase;
while (n) {
d1 = d2;
StatReset();
do {
Sigma((*d2)->d_x, (*d2)->d_y);
d2++, n--;
} while (n && (*d2)->d_h == (*d1)->d_h);/* stop @ end or change */
if (d2 > d1 + 1) {
Variance();
Which = (Var2 > Var1);
qsort((char*)d1, d2 - d1, sizeof (struct datum *), PosSort);
}
LastXPos = (*d2[-1]).d_x;
LastYPos = (*d2[-1]).d_y;
}
}
DumpOutput(dpp, n)
struct datum **dpp;
int n;
{
register struct datum *dp;
while (n--) {
dp = *dpp;
fprintf(Output, "B %d %d %d %d", dp->d_w, dp->d_h, dp->d_x, dp->d_y);
if (dp->d_r1 != RFUNK)
fprintf(Output, " %d %d", dp->d_r1, dp->d_r2);
fputs(";\n", Output);
dpp++;
}
}
DumpLayerStats(dpp, n, final)
struct datum **dpp;
int n, final;
{
}
/*
* Skip any current number and find the next.
* Number is defined as a possibly negated integer.
*/
char *
NextNum(s)
register char *s;
{
if (! s || s == nil)
return (nil);
while (isdigit(*s) || *s == '-')
s++;
while (*s && ! isdigit(*s) && *s != '-')
s++;
if (*s)
return (s);
return (nil);
}
StatReset()
{
StatCnt = 0.;
StatSum1 = 0.;
StatSum2 = 0.;
StatSqr1 = 0.;
StatSqr2 = 0.;
}
Sigma(v1, v2)
int v1, v2;
{
double d1, d2;
d1 = v1;
d2 = v2;
StatSum1 += d1;
StatSum2 += d2;
StatSqr1 += d1 * d1;
StatSqr2 += d2 * d2;
StatCnt += 1.;
}
Variance()
{
double nsqr;
if (StatCnt) {
nsqr = StatCnt * StatCnt;
Var1 = (StatCnt * StatSqr1 - StatSum1 * StatSum1) / nsqr;
Var2 = (StatCnt * StatSqr2 - StatSum2 * StatSum2) / nsqr;
} else {
Var1 = 0.;
Var2 = 0.;
}
}