home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
listings
/
v_10_11
/
1011058a
< prev
next >
Wrap
Text File
|
1992-06-18
|
10KB
|
329 lines
/* CORDIC.C : Demonstrates the integer-based CORDIC
* system for calculating sines and cosines. The
* vertices of a regular hexagon are calculated using
* CORDIC trig and the hexagon itself is rotated.
* Make in Borland C++'s internal environment.
* (c) 1991 Michael Bertrand.
*/
#include <stdio.h> /* printf */
#include <math.h> /* sqrt, atan */
#include <conio.h> /* getch */
#include <stdlib.h> /* */
#include <graphics.h> /* BGI */
typedef struct
{
int x;
int y;
} POINT;
typedef unsigned int WORD;
void CalcHexPtsCORDIC(POINT center, POINT vertex);
void DrawHexagon(POINT center, POINT vertex);
void DrawCross(POINT pt, int colr);
void SinCosSetup(void);
void SinCos(WORD theta, int *sin, int *cos);
#define ESC 0x1B
/* Quadrants for angles. */
#define QUAD1 1
#define QUAD2 2
#define QUAD3 3
#define QUAD4 4
/* NBITS is number of bits for CORDIC units. */
#define NBITS 14
/* NUM_PTS is number of vertices in polygon. */
#define NUM_PTS 6
int ArcTan[NBITS]; /* angles for rotation */
int xInit; /* initial x projection */
WORD CordicBase; /* base for CORDIC units */
WORD HalfBase; /* CordicBase / 2 */
WORD Quad2Boundary; /* 2 * CordicBase */
WORD Quad3Boundary; /* 3 * CordicBase */
POINT HexPts[NUM_PTS+1]; /* calculated poly points */
void main(void)
{
int driver; /* for initgraph() */
int mode; /* for initgraph() */
WORD theta; /* CORDIC angle */
int sine; /* sine of CORDIC angle */
int cosine; /* cosine of CORDIC angle */
POINT center; /* center of hexagon */
POINT vertex; /* hexagon's original base vertex */
POINT vertex1; /* hexagon's changing base vertex */
POINT del; /* vertex - center (radial spoke) */
int radius; /* radius of circumscribing circle */
driver = VGA; /* for initgraph() */
mode = VGAHI; /* mode 0x12 : 640x480 16 color */
if (registerbgidriver(EGAVGA_driver) < 0)
{
printf("couldn't find VGA driver"); return;
}
initgraph(&driver, &mode, NULL);
printf("Press ENTER to rotate, ESC to quit.");
center.x = 320; center.y = 240;
vertex.x = 470; vertex.y = 240;
radius = vertex.x - center.x;
/* Calculate the radial spoke : vertex - center. */
del.x = vertex.x - center.x;
del.y = vertex.y - center.y;
setwritemode(XOR_PUT);
/* Draw circumscribing circle. */
setcolor(RED);
circle(center.x, center.y, radius);
/* Draw small cross at center. */
DrawCross(center, YELLOW);
setcolor(WHITE);
/* Setup CORDIC system, initialize theta = 0. */
SinCosSetup();
theta = 0;
/* Draw initial hexagon. */
DrawHexagon(center, vertex1 = vertex);
/* Rotate hexagon. vertex is fixed; vertex1 rotates
* clockwise around vertex in increments of 650
* CORDIC units (3.57 deg). CORDIC sines/cosines are
* used to find vertex1. DrawHexagon() also uses
* CORDIC sines/cosines to calculate the remaining
* vertices for each hexagon so they can be drawn.
*/
while (getch() != ESC)
{
/* Erase last hexagon. */
DrawHexagon(center, vertex1);
/* Inc theta by 650 CORDIC units (3.57 deg). */
theta += 650;
SinCos(theta, &sine, &cosine);
/* Calc new vertex by rotating around center. */
vertex1.x = (int)
(((long) del.x * cosine - (long) del.y * sine +
HalfBase) >> NBITS) + center.x;
vertex1.y = (int)
(((long) del.x * sine + (long) del.y * cosine +
HalfBase) >> NBITS) + center.y;
/* Draw new hexagon. */
DrawHexagon(center, vertex1);
}
closegraph();
}
void CalcHexPtsCORDIC(POINT center, POINT vertex)
/*
USE: Calc array of hex vertices using CORDIC calcs.
IN: center = center of hexagon.
vertex = one of the hexagon vertices
NOTE: Loads global array HexPoints[] with other 5
vertices of regular hexagon. Uses CORDIC routines
for trig and long integer calculations.
*/
{
int sine; /* sine of central angle */
int cosine; /* cosine of central angle */
int corner; /* index for vertices of polygon */
POINT del; /* vertex - center (radial spoke) */
/* 60 deg = 10923 CORDIC units. */
SinCos(10923, &sine, &cosine);
/* Set initial and final point to incoming vertex. */
HexPts[0].x = HexPts[NUM_PTS].x = vertex.x;
HexPts[0].y = HexPts[NUM_PTS].y = vertex.y;
/* Go clockwise around circle to calc hex points. */
for (corner = 1; corner < NUM_PTS; corner++)
{
/* Calculate the radial spoke : vertex - center. */
del.x = vertex.x - center.x;
del.y = vertex.y - center.y;
/* calc new vertex by rotating around center. */
vertex.x = (int)
(((long) del.x * cosine - (long) del.y * sine +
HalfBase) >> NBITS) + center.x;
vertex.y = (int)
(((long) del.x * sine + (long) del.y * cosine +
HalfBase) >> NBITS) + center.y;
/* Store new vertex in array. */
HexPts[corner].x = vertex.x;
HexPts[corner].y = vertex.y;
}
}
void DrawHexagon(POINT center, POINT vertex)
/*
USE: Draw Hexagon given center and one vertex.
IN: center = center of hexagon.
vertex = one of the hexagon vertices
NOTE: Call CalcHexPtsCORDIC() to load global array
HexPts[] with hexagon vertices.
*/
{
CalcHexPtsCORDIC(center, vertex);
drawpoly(NUM_PTS+1, (int far *)HexPts);
}
void DrawCross(POINT pt, int colr)
/*
USE: Draw cross on screen at pt with given color.
*/
{
int oldColor;
setwritemode(COPY_PUT);
oldColor = getcolor();
setcolor(colr);
moveto(pt.x - 2, pt.y); lineto(pt.x + 2, pt.y);
moveto(pt.x, pt.y - 2); lineto(pt.x, pt.y + 2);
setcolor(oldColor);
setwritemode(XOR_PUT);
}
void SinCosSetup(void)
/*
USE : Load globals used by SinCos().
OUT : Loads globals used in SinCos() :
CordicBase = base for CORDIC units
HalfBase = Cordicbase / 2
Quad2Boundary = 2 * CordicBase
Quad3Boundary = 3 * CordicBase
ArcTan[] = the arctans of 1/(2^i)
xInit = initial value for x projection
NOTE: Must be called once only to initialize before
calling SinCos(). xInit is sufficiently less than
CordicBase to exactly compensate for the expansion
in each rotation.
*/
{
int i; /* to index ArcTan[] */
double f; /* to calc initial x projection */
long powr; /* powers of 2 up to 2^(2*(NBITS-1)) */
CordicBase = 1 << NBITS;
HalfBase = CordicBase >> 1;
Quad2Boundary = CordicBase << 1;
Quad3Boundary = CordicBase + Quad2Boundary;
/* ArcTan's are diminishingly small angles. */
powr = 1;
for (i = 0; i < NBITS; i++)
{
ArcTan[i] = (int)
(atan(1.0/powr)/(M_PI/2)*CordicBase + 0.5);
powr <<= 1;
}
/* xInit is initial value of x projection to comp-
* ensate for expansions. f = 1/sqrt(2/1 * 5/4 * ...
* Normalize as an NBITS binary fraction (multiply by
* CordicBase) and store in xInit. Get f = 0.607253
* and xInit = 9949 = 0x26DD for NBITS = 14.
*/
f = 1.0;
powr = 1;
for (i = 0; i < NBITS; i++)
{
f = (f * (powr + 1)) / powr;
powr <<= 2;
}
f = 1.0/sqrt(f);
xInit = (int) (CordicBase * f + 0.5);
}
void SinCos(WORD theta, int *sin, int *cos)
/*
USE : Calc sin and cos with integer CORDIC routine.
IN : theta = incoming angle (in CORDIC angle units)
OUT : sin = ptr to sin (in CORDIC fixed point units)
cos = ptr to cos (in CORDIC fixed point units)
NOTE: The incoming angle theta is in CORDIC angle
units, which subdivide the circle into 64K parts,
with 0 deg = 0, 90 deg = 16384 (CordicBase), 180 deg
= 32768, 270 deg = 49152, etc. The calculated sine
and cosine are in CORDIC fixed point units : an int
considered as a fraction of 16384 (CordicBase).
*/
{
int quadrant; /* quadrant of incoming angle */
int z; /* incoming angle moved to 1st quad */
int i; /* to index rotations : one per bit */
int x, y; /* projections onto axes */
int x1, y1; /* projections of rotated vector */
/* Determine quadrant of incoming angle, translate to
* 1st quadrant. Note use of previously calculated
* values CordicBase, etc. for speed.
*/
if (theta < CordicBase)
{
quadrant = QUAD1;
z = (int) theta;
}
else if (theta < Quad2Boundary)
{
quadrant = QUAD2;
z = (int) (Quad2Boundary - theta);
}
else if (theta < Quad3Boundary)
{
quadrant = QUAD3;
z = (int) (theta - Quad2Boundary);
}
else
{
quadrant = QUAD4;
z = - ((int) theta);
}
/* Initialize projections. */
x = xInit;
y = 0;
/* Negate z, so same rotations taking angle z to 0
* will take (x, y) = (xInit, 0) to (*cos, *sin).
*/
z = -z;
/* Rotate NBITS times. */
for (i = 0; i < NBITS; i++)
{
if (z < 0)
{
/* Counter-clockwise rotation. */
z += ArcTan[i];
y1 = y + (x >> i);
x1 = x - (y >> i);
}
else
{
/* Clockwise rotation. */
z -= ArcTan[i];
y1 = y - (x >> i);
x1 = x + (y >> i);
}
/* Put new projections into (x,y) for next go. */
x = x1;
y = y1;
} /* for i */
/* Attach signs depending on quadrant. */
*cos = (quadrant==QUAD1 || quadrant==QUAD4) ? x : -x;
*sin = (quadrant==QUAD1 || quadrant==QUAD2) ? y : -y;
}