home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
ddjmag
/
ddj8711.arc
/
MAKE_GRI.C
< prev
next >
Wrap
C/C++ Source or Header
|
1987-10-08
|
8KB
|
335 lines
/*----------------------------------------------------------------
make_grid
converts graph data into a grid that can be interpreted
by hidlinpix
William May
303A Ridgefield Circle
Clinton, MA 01510
Feb 16, 1986 created
----------------------------------------------------------------*/
#define DEBUG
#ifdef DEBUG
#define P(x) x
#else
#define P(x)
#endif
#include <stdio.h>
#include "stack.h"
#include "make_hidlin.h"
#include "contour.h"
#include "global.h"
extern int stack_error;
extern int grid[HMAX][VMAX];
static STACK *stack;
/*------------------------------------------------------------------------
move vertically
assigning elevations to each grid point
------------------------------------------------------------------------*/
make_grid()
{
register int h;
stack = init_stack(2000); /* should be plenty! */
for (h = 1; h < (HMAX-1); h++) {
traverse_vert(h);
}
del_stack(&stack);
}
/*------------------------------------------------------------------------
Traverse a vertical grid line, determining elevations along the way
This is mostly simple: i.e. keep track of the elevation of the
contour line crossed last.
The main complications are tangents (in which case we want to ignore
the contour line) and inflection points (in which case we don't
ignore the contour line).
------------------------------------------------------------------------*/
traverse_vert(h)
register int h;
{
register int ver, hor;
register int vmax = (VMAX - 1) * INTERVAL;
hor = h * INTERVAL;
push(0, stack); /* push 0 (elev of border) onto the stack */
P(show_line(hor,1,hor,vmax));
for (ver = 1; ver < vmax; ver++) {
/* traverse a vertical grid line */
/* on a grid intersection set array to value on the stack */
if (!(ver % INTERVAL)) {
P(show_point(hor-3,ver));
P(show_point(hor+3,ver));
set_elevation(h, (ver / INTERVAL));
}
/* are we crossing a contour? are we tangent to it? */
if (getpixel(hor, ver, &bmap)) {
if (is_crossing(hor, ver) || start_inflection(hor, ver))
ver += check_hit(hor,ver);
}
}
}
/*------------------------------------------------------------------------
set grid[h][v] to the value of top of stack
------------------------------------------------------------------------*/
static set_elevation(h, v)
register int h, v; /* note these are grid coordinates !! */
{
grid[h][v] = top_of_stack(stack);
}
/*-----------------------------------------------------------------------
a pixel was hit, get the curve index from tree
get curve elevation from curve array
if curve elevation = elevation on stack
pop stack
else
push new elevation
end
return the number of pixels to skip-1 (i.e.
return 0 if wskip 1, etc.)
------------------------------------------------------------------------*/
static short check_hit(h, v)
register int h, v; /* note these are pixel coordinates !! */
{
short cnt = 1; /* number of pixels */
short ver;
union temp {
long key;
Point p;
} temp;
LEAF *lp;
long dcmp();
int elev;
/* traverse all pixels, if more than one */
for (ver = v+1; getpixel(h, ver++, &bmap); cnt++)
;
temp.p.h = h;
temp.p.v = v;
lp = find(root, temp.key, dcmp);
elev = curves[lp->curve].elevation;
if (elev == top_of_stack(stack))
pop(stack);
else
push(elev, stack);
return (cnt-1);
}
/*-----------------------------------------------------------------------
is_crossing: tests a point on a contour to figure out if
we are crossing the contour or tangent to the contour. If we are
tangent to it we don't want to bump the elevation yet.
The test is performed by examining the six pixels to the side:
1 4
2 h,v 5
3 6
Crossings are:
two or more hits in range 1-6
1+ in 1-3 and 1+ in 4-6
return false for a tangent, true for a crossing.
------------------------------------------------------------------------*/
static int is_crossing(h, v)
int h, v;
{
register int h_test, v_test, i;
h_test = h - 1; /* test the 1-3 */
v_test = v - 1;
for (i = 0; !getpixel(h_test, v_test, &bmap) && i < 3; i++, v_test++)
;
if (i == 3)
return false; /* a tangent was hit */
h_test = h + 1; /* test the 4-6 */
v_test = v - 1;
for (i = 0; !getpixel(h_test, v_test, &bmap) && i < 3; i++, v_test++)
;
if (i == 3)
return false; /* a tangent was hit */
return true; /* looks good! */
}
/*-----------------------------------------------------------------------
start_inflection: tests to see if this point is the start of an
inflection in the contour. An inflection will not look like a crossing,
but should be counted as one.
An inflection looks like
1
h,v
2
3
4
5
for example. Only the first point on the inflection is counted.
------------------------------------------------------------------------*/
static int start_inflection(h, v)
int h, v;
{
register int h_test, v_test, dir = 0, i;
if (getpixel(h, v-1, &bmap))
return false; /* only count the start of an inflection */
h_test = h - 1; /* test the 1-3 */
v_test = v - 1;
for (i = 0; !getpixel(h_test, v_test, &bmap) && i < 3; i++, v_test++)
;
if (i < 3)
dir = 1;
h_test = h + 1; /* test the 4-6 */
v_test = v - 1;
for (i = 0; !getpixel(h_test, v_test, &bmap) && i < 3; i++, v_test++)
;
if (i < 3)
dir = -1;
if (dir == 0)
return false; /* no inflection here */
/*
final test: track pixels downward
if the turn at the end is in the opposite direction
as the original turn (indicated by dir)
then it is an inflection
*/
v_test = v;
while (getpixel(h, v_test+1, &bmap))
v_test++;
if (v_test != v) {
v = v_test;
/* let's test the pixels again! */
h_test = h - 1; /* test the 1-3 */
v_test = v - 1;
for (i = 0; !getpixel(h_test, v_test, &bmap) && i < 3; i++, v_test++)
;
if (i < 3)
if (dir != 1)
return true; /* no change in direction, inflection */
else
return false; /* reversed direction, was a tangent */
h_test = h + 1; /* test the 4-6 */
v_test = v - 1;
for (i = 0; !getpixel(h_test, v_test, &bmap) && i < 3; i++, v_test++)
;
if (i < 3)
if (dir != -1)
return true; /* no change in direction, inflection */
else
return false;
}
else
return false;
}
#ifdef DEBUG
/*
Here is some code to display the progress of the algorithm
Fixed point math is used to speed up calculations.
Fixed point math is tricky in a typed language like C or
Pascal, and a cinch in assembly.
*/
#include <QuickDraw.h>
static Fixed int_to_fix(i)
int i;
{
asm {
move.w i,d0 ; get the number
ext.l d0 ; clear top of d0
swap d0 ; make it a fixed point number, all done
}
}
static int fix_to_int(i)
Fixed i;
{
asm {
move.l i,d0 ; get the number
add.l #0xA000,d0 ; add .5 to number, for rounding
swap d0 ; make the int, ignore upper word of d0
}
}
static Fixed ratio = 0x00004000;
static show_point(h,v)
register int h, v;
{
/*
draw each point in right window
scaled like the MacPaint draw function
*/
GrafPtr oldPort;
Rect r;
GetPort(&oldPort);
SetPort(right_wind);
r.top = fix_to_int(FixMul(int_to_fix(v), ratio));
r.left = fix_to_int(FixMul(int_to_fix(h), ratio));
r.right = r.left + 1;
r.bottom = r.top + 1;
FrameRect(&r);
SetPort(oldPort);
}
static show_line(h1,v1,h2,v2)
register int h1, v1, h2, v2;
{
/*
draw each line in right window
scaled like the MacPaint draw function
*/
GrafPtr oldPort;
GetPort(&oldPort);
SetPort(right_wind);
MoveTo(fix_to_int(FixMul(int_to_fix(h1), ratio)),
fix_to_int(FixMul(int_to_fix(v1), ratio)));
LineTo(fix_to_int(FixMul(int_to_fix(h2), ratio)),
fix_to_int(FixMul(int_to_fix(v2), ratio)));
SetPort(oldPort);
}
#endif