home *** CD-ROM | disk | FTP | other *** search
- /* THETAFEAT: function determines features and feature descriptions
- * from theta plot
- * usage: nThetaFeats = thetafeat (data, edge, theta,
- * nTheta, wwPar)
- * - Note that the <zCross> array contains a flag which
- * is UP, DOWN, ZERO for the *first sample* as read
- * sequentially in the respective regions.
- * - Note that if there is a cycle, the <data> array is
- * augmented by the wrap-around in function CYCLEAUGMENT.
- * However this array is NOT sent back to the calling program.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #include "pcc2.h" /* wing-walk include file */
-
- #define ROOT2 1.41421356237 /* square root of 2 */
- #if defined(WIN32)
- #define PI 3.1415927
- #endif
-
- #define UP 3 /* codes for zero ranges, above, and below */
- #define ZERO 2
- #define DOWN 1
- #define NOCROSSING 0
-
- extern long maxCorner; /* maximum arc length of corner curvature */
- /* needed for zzWidth calc in FEATDETERM */
-
- extern int linkcorner (int, struct point);
- extern int linkcurve (struct dpoint, struct point, struct point,
- struct dpoint, double, short);
-
- long thetazz (struct theta *, long, short *, struct wwPar, long *, long *);
- long boundzz (struct theta *, long, short **, long *, struct point **,
- struct edge *, long *, long *);
- long featdeterm (short *, long, long, struct theta *, long,
- struct point *, struct edge, struct wwPar,
- long *, long *, short);
- long featcorner (struct point *, long, long, long, long,
- struct edge, struct point *);
- long featcurve (struct point *, long, long, long, long, struct edge,
- double, double, struct dpoint *, struct point *,
- struct point *, struct dpoint *, double *, short *);
- long eventranspts (struct dpoint *, struct dpoint *,
- struct point, struct point, struct dpoint, double *);
- short cycleaugment (long, short **, long *, struct point **,
- struct edge *, long, long);
- long bounddeterm2 (short *, struct theta *, long, long,
- long, struct point *, struct edge, long *, long *);
- long bounddeterm (short *, struct theta *, long, long, long,
- struct point *, long *, long *);
- long featbound (struct point, struct point, struct point,
- double *, struct dpoint *, struct dpoint *, short *);
- long curvecorner (struct point, struct point, struct point,
- double, struct dpoint, struct dpoint *, short *);
- long feat2bound (struct point, struct point, double, struct dpoint,
- double *, struct dpoint *, short *);
- double radsearch (double, double, double);
- short curvedirn (struct point, struct point, struct dpoint, struct dpoint);
- long linesintrsct (struct point, struct dpoint, struct point,
- struct point, struct dpoint *);
-
- long
- thetafeat (data, edge, theta, nTheta, wwPar, curveFlag)
- struct point *data; /* sequence of coordinates of lines */
- struct edge edge; /* lower and upper <data> indices */
- struct theta *theta; /* theta plot */
- long nTheta; /* no. values in theta plot */
- struct wwPar wwPar; /* wing-walk parameters */
- short curveFlag; /* =0 for curve fit by 2 lines; =1 for curve */
- {
- short *zCross; /* array of flags at locations of zero
- * * crossings on theta plot */
- long zStart, /* starting zero crossing of peak */
- zEnd, /* ending zero crossing of peak */
- nThetaFeats, /* no. of features found on theta plot */
- i;
- long nZCross, /* no. of values in zero-crossing plot */
- zLow, /* line indices marking extent of feature to */
- zHigh; /* halfway (+1) within line below feat
- * * and halfway (-1) within line after feat;
- * * unless at either end where it goes to end - 1 */
- long zInitial, /* initial/final valid <zCross> indices */
- zFinal; /* inside of border values on theta plot */
-
- /* find significant peak widths on theta plot */
- nZCross = nTheta;
- if ((zCross = (short *) calloc (nZCross, sizeof (*zCross))) == NULL) {
- printf ("CALLOC: not enough memory -- sorry");
- return (-1);
- }
-
- thetazz (theta, nZCross, zCross, wwPar, &zInitial, &zFinal);
-
- if ((boundzz (theta, wwPar.l, &zCross, &nZCross,
- &data, &edge, &zInitial, &zFinal))
- == 0)
- return (0);
-
- /* perform feature determination from peaks on theta plot */
- for (zStart = 1; (zStart < nZCross)
- && (zCross[zStart] == ZERO || zCross[zStart] == NOCROSSING);
- zStart++);
- for (i = zStart + 1, nThetaFeats = 0; i < nZCross; i++) {
- if (zCross[i] != NOCROSSING) {
- zEnd = i - 1;
- if (zStart == zInitial || i == zFinal)
- bounddeterm2 (zCross, theta, zStart, zEnd, nZCross, data,
- edge, &zLow, &zHigh);
- else
- featdeterm (zCross, zStart, zEnd, theta, nZCross, data,
- edge, wwPar, &zLow, &zHigh, curveFlag);
- nThetaFeats++;
- /* <= 1 added (formerly == 0) 6 Oct 88 */
- zLow = (zLow <= 1) ? 1 : zLow + (zStart - zLow) / 2;
- zHigh = (zHigh == nZCross - 1)
- ? zHigh - 1 : zEnd + (zHigh - zEnd) / 2;
- for (zStart = i; (zStart < nZCross)
- && (zCross[zStart] == ZERO || zCross[zStart] == NOCROSSING);
- zStart++);
- i = zStart + 1;
- }
- }
-
- free (zCross);
- return (nThetaFeats);
- }
-
-
- /* THETAZZ: function finds significantly wide peak widths on theta plot
- * usage: thetazz (theta, nTheta, zCross, wwPar,
- * &zInitial, &zFinal)
- * Note that although the peaks are represented by the
- * locations of the first and last non-zero region theta values
- * (iLow and i), the peak width is measured between zero
- * crossings, thus <iLow - 1> and <i + 1> below.
- */
-
- long
- thetazz (theta, nTheta, zCross, wwPar, zInitial, zFinal)
- struct theta *theta; /* theta plot */
- long nTheta; /* no. values in theta plot */
- short *zCross; /* array of zero crossings of theta plot */
- struct wwPar wwPar; /* wing-walk parameters */
- long *zInitial, /* initial/final valid <zCross> indices */
- *zFinal; /* inside of border values on theta plot */
- {
- double zeroRange, /* threshold for zero (strt line) region */
- minZZ, /* minimum zero crossing length for peak */
- lengthZZ, /* zero-crossing length */
- atan2 ();
- short range, rangeB4; /* zero, up, or down regions */
- int zStart, /* first zero crossing on theta plot */
- iLow, /* lower index of zero crossing pair */
- i;
- struct narrowest { /* narrowest zero crossing pair */
- double length; /* peak arc length */
- long iLow, iHigh; /* indices of start/end of peak on plot */
- } narrowest;
-
- zeroRange = atan2 (2.0, wwPar.l - wwPar.m - 2.0 * ROOT2 + 2.0);
-
- /* find first and last valid theta points, and set <zCross> to NOCROSSING
- * in these border regions */
- for (*zInitial = 0; *zInitial < nTheta; (*zInitial)++) {
- if (theta[*zInitial].theta != BORDERTHETA)
- break;
- zCross[*zInitial] = NOCROSSING;
- }
- for (*zFinal = nTheta - 1; *zFinal >= 0; --(*zFinal)) {
- if (theta[*zFinal].theta != BORDERTHETA)
- break;
- zCross[*zFinal] = NOCROSSING;
- }
-
- /* find zero crossings on theta plot */
- if (theta[*zInitial].theta > zeroRange)
- rangeB4 = UP;
- else if (theta[*zInitial].theta < -zeroRange)
- rangeB4 = DOWN;
- else
- rangeB4 = ZERO;
- zCross[*zInitial] = rangeB4;
- for (i = *zInitial + 1; i <= *zFinal; i++) {
- if (theta[i].theta > zeroRange)
- range = UP;
- else if (theta[i].theta < -zeroRange)
- range = DOWN;
- else
- range = ZERO;
- zCross[i] = (range != rangeB4) ? range : NOCROSSING;
- rangeB4 = range;
- }
-
- /* if any zero crossings are skipped (UP to DOWN, or vice versa without
- * a ZERO in between) then put ZERO in between, or if the crossings are
- * 1 or 2 samples apart then set lower crossing to NOCROSSING */
- zStart = *zInitial;
- for (i = *zInitial + 1; i <= *zFinal; i++) {
- if (zCross[i] != NOCROSSING) {
- if ((zCross[zStart] == UP && zCross[i] == DOWN)
- || (zCross[zStart] == DOWN && zCross[i] == UP)) {
- zCross[i - 1] = (zCross[i - 1] == NOCROSSING)
- ? ZERO : NOCROSSING;
- }
- zStart = i;
- }
- }
-
- /* eliminate zero crossings for peak widths which are too narrow */
- minZZ = (double) (wwPar.l - 1) + EPSILON1;
- while (1) {
- narrowest.length = theta[nTheta - 1].length;
- rangeB4 = zCross[*zInitial];
- for (zStart = *zInitial + 1;
- (zCross[zStart] == NOCROSSING) && zStart < *zFinal; zStart++);
- if (zStart == *zFinal)
- return (0);
- for (iLow = zStart, i = zStart + 1; i <= *zFinal; i++) {
- if (zCross[i] != NOCROSSING) { /* see note above */
- lengthZZ = theta[i + 1].length - theta[iLow - 1].length;
- if (lengthZZ < narrowest.length && rangeB4 == zCross[i]) {
- narrowest.length = theta[i + 1].length
- - theta[iLow - 1].length;
- narrowest.iLow = iLow;
- narrowest.iHigh = i - 1;
- }
- rangeB4 = zCross[iLow];
- iLow = i;
- }
- }
- if (narrowest.length < minZZ)
- zCross[narrowest.iLow] = zCross[narrowest.iHigh + 1]
- = NOCROSSING;
- else
- break;
- }
-
- return (0);
- }
-
-
- /* BOUNDZZ: function adjusts zero crossings at bounds of line
- * or at seam of cycle
- * usage: featFlag = boundzz (theta, wwParL
- * &zCross, &nZCross, &data, &edge,
- * &zInitial, &zFinal)
- * Function returns 0 if cycle has no zero-crossings; 1
- * otherwise.
- */
-
- long
- boundzz (theta, wwParL, zCross, nZCross, data, edge,
- zInitial, zFinal)
- struct theta *theta; /* theta plot */
- long wwParL; /* ww length parameter */
- short **zCross; /* array of flags at zero-crossing locns */
- long *nZCross; /* no. values in zero-crossing plot */
- struct point **data; /* sequence of coordinates of lines */
- struct edge *edge; /* lower and upper <data> indices */
- long *zInitial, *zFinal; /* initial and final valid zCross indices */
- {
- double minZZ, /* minimum zero-crossing length for peak */
- lengthZZ; /* zero-crossing length */
- long firstCross, /* first, second, and last zero crossing */
- secondCross, lastCross, featFlag, /* =0 if no features in cycle; 1 otherwise */
- i;
-
- minZZ = (double) (wwParL - 1) + EPSILON1;
-
- for (firstCross = *zInitial + 1; firstCross <= *zFinal; firstCross++)
- if ((*zCross)[firstCross] != NOCROSSING)
- break;
- for (lastCross = *zFinal; lastCross >= *zInitial; --lastCross)
- if ((*zCross)[lastCross] != NOCROSSING)
- break;
-
- /* if it is not a cycle, clean up zero-crossings at bounds */
- /* if (cycleFlag == 0) { ??? */
- if (1) {
- featFlag = 1;
-
- /* eliminate peaks at beginning and end if too narrow */
- lengthZZ = theta[firstCross + 1].length;
- if (lengthZZ < minZZ) {
- (*zCross)[*zInitial] = NOCROSSING;
- *zInitial = firstCross;
- }
- lengthZZ = theta[*nZCross - 1].length - theta[lastCross - 1].length;
- if (lengthZZ < minZZ)
- (*zCross)[lastCross] = NOCROSSING;
-
- /* move the initial zero crossing to the first element and put a
- * ZERO crossing at the final element if it ended with
- * an UP/DOWN; this is for boundary feature determination */
- (*zCross)[1] = (*zCross)[*zInitial];
- (*zCross)[*zInitial] = NOCROSSING;
- *zInitial = 1;
- for (i = lastCross; ((*zCross)[i] == NOCROSSING && i >= *zInitial);
- --i);
- *zFinal = *nZCross - 1;
- if ((*zCross)[i] != ZERO)
- (*zCross)[*zFinal] = ZERO;
- }
- /* if it is a cycle, clean up zero-crossings at bounds (= seam) */
- else {
- if ((*zCross)[*zInitial] != NOCROSSING)
- firstCross = *zInitial;
-
- /* if the first and last zero-crossings are the same, remove first */
- if (firstCross <= *zFinal
- && (*zCross)[firstCross] == (*zCross)[lastCross]) {
- (*zCross)[firstCross] = NOCROSSING;
- for (firstCross = firstCross + 1; firstCross <= *zFinal;
- firstCross++)
- if ((*zCross)[firstCross] != NOCROSSING)
- break;
- }
- /* if first and last zero crossing don't have zero between, insert it */
- else if (firstCross <= *zFinal && (*zCross)[firstCross] != ZERO
- && (*zCross)[lastCross] != ZERO) {
- (*zCross)[firstCross + 1] = (*zCross)[firstCross];
- (*zCross)[firstCross] = ZERO;
- }
- /* if a peak at the seam is too narrow, eliminate it */
- for (secondCross = firstCross + 1; secondCross <= *zFinal;
- secondCross++)
- if ((*zCross)[secondCross] != NOCROSSING)
- break;
- if (secondCross < lastCross
- && (*zCross)[secondCross] == (*zCross)[lastCross]) {
- lengthZZ = theta[*zFinal].length - theta[lastCross - 1].length
- + theta[firstCross + 1].length
- - theta[*zInitial].length;
- if (lengthZZ < minZZ) {
- (*zCross)[firstCross] = NOCROSSING;
- (*zCross)[secondCross] = NOCROSSING;
- for (firstCross = secondCross + 1; firstCross <= *zFinal;
- firstCross++)
- if ((*zCross)[firstCross] != NOCROSSING)
- break;
- for (secondCross = firstCross + 1; secondCross <= *zFinal;
- secondCross++)
- if ((*zCross)[secondCross] != NOCROSSING)
- break;
- }
- }
- }
- return (featFlag);
- }
-
-
-
- /* FEATDETERM: function determines the feature type and parameters
- * from the theta plot and other information
- * usage: featdeterm (zCross, zStart, zEnd, theta, nTheta,
- * data, edge, wwPar, &zLow, &zHigh, curveFlag)
- */
-
- long
- featdeterm (zCross, zStart, zEnd, theta, nTheta, data, edge, wwPar,
- zLow, zHigh, curveFlag)
- short *zCross; /* array of flags at crossings on theta */
- long zStart, /* start and end zero crossing indices */
- zEnd; /* (these are *within* peak) */
- struct theta *theta; /* theta plot */
- long nTheta; /* no. values in theta plot */
- struct point *data; /* data array */
- struct edge edge; /* lower and upper <data> indices */
- struct wwPar wwPar; /* wing-walk parameters */
- long *zLow, /* line indices of end of peak before, */
- *zHigh; /* and start of peak after, feature peak */
- short curveFlag; /* =0 for curve fit by 2 lines; =1 for curve */
- {
- long lD2, /* WMW-length divided by 2 */
- i;
-
- long zLowB, /* line indices of peak before and after */
- zHighB; /* including buffer of half ww length */
-
- double widthZZ, /* peak width between zero crossings */
- threshZZ; /* zero crossing width threshold between
- * * curve and corner */
- struct dpoint intrsct; /* intersection of tangents to curve */
- struct point corner, /* corner coordinates */
- trans1, /* transition coords into and out of curve */
- trans2;
- struct dpoint center; /* center of curvature */
- double radiusC; /* radius of curvature */
- short curveSweep; /* indicates sweep of curve */
- struct dpoint midArcPt; /* middle coord on arc */
- short curveDirn;
-
- widthZZ = theta[zEnd + 1].length - theta[zStart - 1].length;
- threshZZ = (double) (wwPar.l + maxCorner - 1) + EPSILON2;
-
- /* find zero crossings before and after peak */
- for (i = zStart - 1; i >= 0; --i) {
- if (zCross[i] == ZERO)
- break;
- else if (zCross[i] == UP || zCross[i] == DOWN)
- printf ("FEATDETERM error: UP/DOWN crossing instead of ZERO\n");
- }
- *zLow = i;
- for (i = zEnd + 2; i < nTheta; i++) {
- if (zCross[i] == UP || zCross[i] == DOWN)
- break;
- else if (zCross[i] == ZERO)
- printf ("FEATDETERM error: ZERO crossing instead of UP/DOWN\n");
- }
- *zHigh = i - 1;
-
- lD2 = wwPar.l / 2; /* corrected from (L - M) / 2 6Jan88 */
- zLowB = ((*zLow - lD2) < 0) ? 0 : (*zLow - lD2);
- zStart = zStart - 1 + lD2;
- zEnd = zEnd + 1 - lD2;
- zHighB = ((*zHigh + lD2) >= nTheta) ? nTheta - 1 : (*zHigh + lD2);
- if (zEnd < zStart)
- zStart = zEnd = (zStart + zEnd) / 2;
-
- if (widthZZ <= threshZZ || zEnd <= zStart) { /* 1Nov88, 2nd cond. added */
- featcorner (data, zLowB, zStart, zEnd, zHighB, edge, &corner);
- linkcorner (WWCORNER, corner);
- }
- else {
- if ((featcurve (data, zLowB, zStart, zEnd, zHighB, edge, widthZZ,
- threshZZ, &intrsct, &trans1, &trans2, ¢er, &radiusC,
- &curveSweep)) == 0) {
-
- /* the mid arc point are not reliable after <eventranspts> function
- * if the sweep is <=180; therefore if this is so, use intersection pt;
- * if the sweep is >180 then <eventranspts> shortens the longer length
- * and using mid arc point is okay (13 Sept 88) */
- if (curveSweep == CURVELT180)
- midArcPt = intrsct;
- else if (curveSweep == CURVEEQ180) {
- midArcPt.x = (trans1.x + trans2.x) / 2;
- midArcPt.y = (trans1.y + trans2.y) / 2;
- }
- else {
- midArcPt.x = data[(zEnd + zStart) / 2].x;
- midArcPt.y = data[(zEnd + zStart) / 2].y;
- }
- curveDirn = curvedirn (trans1, trans2, midArcPt, center);
- if (curveFlag == 0) {
- center.x = midArcPt.x;
- center.y = midArcPt.y;
- }
- linkcurve (intrsct, trans1, trans2, center, radiusC, curveDirn);
- }
- else { /* asymmetric curve = shorter curve converted to corner */
- corner.x = (long) (center.x + 0.5);
- corner.y = (long) (center.y + 0.5);
- linkcorner (WWCORNER, corner);
- }
- }
- return (0);
- }
-
-
-
- /* FEATCORNER: function calculates corner parameters
- * usage: featcorner (data, zLow, zStart, zEnd, zHigh,
- * edge, &coord)
- * Note that in this function the <zLow, zStart,...>
- * variables have already been adjusted +- (L-1)/2
- * and that they are indices of the <zCross> or <theta>
- * array, not of the data array.
- */
-
-
- long
- featcorner (data, zLow, zStart, zEnd, zHigh, edge, coord)
- struct point *data; /* data array of coordinates */
- long zLow, /* indices of line coords before peak */
- zStart, zEnd, /* indices of line coords after peak */
- zHigh;
- struct edge edge; /* lower and upper <data> indices */
- struct point *coord; /* output location of corner */
- {
- double d, e; /* temporary variables */
- double deltaX1, deltaX2; /* x difference along fore and aft lines */
- double coordX, coordY; /* floating point corner coordinates */
- short parallel; /* flag = 1 if lines parallel; else 0 */
-
- zLow += edge.iLow;
- zStart += edge.iLow;
- zEnd += edge.iLow;
- zHigh += edge.iLow;
-
- deltaX1 = (double) (data[zStart].x - data[zLow].x);
- deltaX2 = (double) (data[zHigh].x - data[zEnd].x);
- parallel = 0;
- if (deltaX1 == 0.0 && deltaX2 == 0.0)
- parallel = 1;
- else if (deltaX1 == 0.0) {
- e = (double) (data[zHigh].y - data[zEnd].y) / deltaX2;
- coord->x = data[zStart].x;
- coord->y = (long) (e * (coord->x - (double) data[zEnd].x) + (double) data[zEnd].y);
- }
- else if (deltaX2 == 0.0) {
- d = (double) (data[zStart].y - data[zLow].y) / deltaX1;
- coord->x = data[zHigh].x;
- coord->y = (long) (d * (coord->x - (double) data[zLow].x) + (double) data[zLow].y);
- }
- else {
- d = (double) (data[zStart].y - data[zLow].y) / deltaX1;
- e = (double) (data[zHigh].y - data[zEnd].y) / deltaX2;
- if (d == e)
- parallel = 1;
- else {
- coordX = (d * data[zLow].x - e * data[zEnd].x + data[zEnd].y
- - data[zLow].y) / (d - e);
- coordY = d * (coordX - data[zLow].x) + data[zLow].y;
- coord->x = (int) (coordX + 0.5);
- coord->y = (int) (coordY + 0.5);
- }
- }
- if (parallel == 1) {
- coord->x = (data[zStart].x + data[zEnd].x) / 2;
- coord->y = (data[zStart].y + data[zEnd].y) / 2;
- }
- return (0);
- }
-
-
-
- /* FEATCURVE: function calculates curve parameters
- * usage: cornerOrCurve =
- * featcurve (data, zLow, zStart, zEnd, zHigh, edge,
- * widthZZ, threshZZ,
- * &intrsct, &trans1, &trans2,
- * ¢er, &radiusC, &curveSweep)
- * - Function returns a flag which is 0 if the feature is a curve
- * but -1 if the curve has been converted to a corner (see next).
- * - Note that if the curve is asymmetric, the further adjacent
- * line is extended to the same distance from the corner as
- * the other line. If the new zero crossing width after this
- * is less than the corner/curve threshold, then the feature
- * is a corner.
- * - Note that in this function the <zLow, zStart,...>
- * variables have already been adjusted +- (L-1)/2
- * and that they are indices of the <zCross> or <theta>
- * array, not of the data array.
- * - Note that the case where the transition slopes are equal
- * or they do not intersect are not taken care of here.
- */
-
- #include <math.h>
-
- /*#define PI 3.14159265358979 */
-
- long
- featcurve (data, zLow, zStart, zEnd, zHigh, edge, widthZZ, threshZZ,
- intrsct, trans1, trans2, center, radiusC, curveSweep)
- struct point *data; /* data array of coordinates */
- long zLow, /* indices of line coords before peak */
- zStart, zEnd, /* indices of line coords after peak */
- zHigh;
- struct edge edge; /* lower and upper <data> indices */
- double widthZZ, /* peak width between zero crossings */
- threshZZ; /* corner/curve thresh zero crossing width */
- struct dpoint *intrsct; /* intersection of lines tangent to curve */
- struct point *trans1, /* transition coords into and out of curve */
- *trans2;
- struct dpoint *center; /* center of curvature */
- double *radiusC; /* radius of curvature */
- short *curveSweep; /* indicates sweep of curve */
- {
- double deltaX1, deltaX2, /* x, y diff.s along fore and aft lines */
- deltaY1, deltaY2, d, e, /* used in equation for center */
- distTI, distEI; /* distances: trans and end to intersectn */
- struct dpoint transD1, /* (double) of transition point locations */
- transD2;
-
- /* add offset to curve locations to correspond to <data> array */
- zLow += edge.iLow;
- zStart += edge.iLow;
- zEnd += edge.iLow;
- zHigh += edge.iLow;
-
- /* find corner of intersection of tangent lines to curve */
- *curveSweep = CURVELT180;
- deltaX1 = (double) (data[zStart].x - data[zLow].x);
- deltaX2 = (double) (data[zHigh].x - data[zEnd].x);
- deltaY1 = (double) (data[zStart].y - data[zLow].y);
- deltaY2 = (double) (data[zHigh].y - data[zEnd].y);
- if (deltaX1 == 0.0 && deltaX2 == 0.0)
- *curveSweep = CURVEEQ180;
- else if (deltaX1 == 0.0) {
- e = deltaY2 / deltaX2;
- intrsct->x = (double) data[zStart].x;
- intrsct->y = e * (intrsct->x - data[zEnd].x) + data[zEnd].y;
- }
- else if (deltaX2 == 0.0) {
- d = deltaY1 / deltaX1;
- intrsct->x = (double) data[zHigh].x;
- intrsct->y = d * (intrsct->x - data[zLow].x) + data[zLow].y;
- }
- else {
- d = deltaY1 / deltaX1;
- e = deltaY2 / deltaX2;
- if (d == e)
- *curveSweep = CURVEEQ180;
- else {
- intrsct->x = (d * data[zLow].x - e * data[zEnd].x + data[zEnd].y
- - data[zLow].y) / (d - e);
- intrsct->y = d * (intrsct->x - data[zLow].x) + data[zLow].y;
- }
- }
-
- /* find curve sweep, for curves which sweep greater than or less than 180 */
- if (*curveSweep != CURVEEQ180) {
- distTI = (intrsct->x - (double) data[zStart].x)
- * (intrsct->x - (double) data[zStart].x)
- + (intrsct->y - (double) data[zStart].y)
- * (intrsct->y - (double) data[zStart].y);
- distEI = (intrsct->x - (double) data[zLow].x)
- * (intrsct->x - (double) data[zLow].x)
- + (intrsct->y - (double) data[zLow].y)
- * (intrsct->y - (double) data[zLow].y);
- *curveSweep = (distEI > distTI) ? CURVELT180 : CURVEGT180;
- }
-
- /* adjust transition points so they are symmetric around middle of curve */
- transD1.x = (double) data[zStart].x;
- transD1.y = (double) data[zStart].y;
- transD2.x = (double) data[zEnd].x;
- transD2.y = (double) data[zEnd].y;
- eventranspts (&transD1, &transD2, data[zLow], data[zHigh], *intrsct,
- &widthZZ);
-
- trans1->x = (transD1.x >= 0.0) ? (int) (transD1.x + 0.5) :
- (int) (transD1.x - 0.5);
- trans1->y = (transD1.y >= 0.0) ? (int) (transD1.y + 0.5) :
- (int) (transD1.y - 0.5);
- trans2->x = (transD2.x >= 0.0) ? (int) (transD2.x + 0.5) :
- (int) (transD2.x - 0.5);
- trans2->y = (transD2.y >= 0.0) ? (int) (transD2.y + 0.5) :
- (int) (transD2.y - 0.5);
-
- /* if the new zero-crossing width is less than the corner/curve threshold,
- * then return a corner */
- if (widthZZ <= threshZZ) {
- center->x = intrsct->x;
- center->y = intrsct->y;
- return (-1);
- }
-
- /* center of curvature */
- if (deltaX1 == deltaX2);
- /* printf ("FEATCURVE: ERROR:problems -curve >= 180 degrees in sweep\n"); */
- else if (deltaX1 == 0.0) {
- e = (double) (data[zHigh].y - data[zEnd].y) / deltaX2;
- center->y = transD1.y;
- center->x = transD2.x - e * (center->y - transD2.y);
- }
- else if (deltaX2 == 0.0) {
- d = (double) (data[zStart].y - data[zLow].y) / deltaX1;
- center->y = transD2.y;
- center->x = transD1.x - d * (center->y - transD1.y);
- }
- else {
- d = (double) (data[zStart].y - data[zLow].y) / deltaX1;
- e = (double) (data[zHigh].y - data[zEnd].y) / deltaX2;
- if (d == e);
- /* printf ("FEATCURVE: transition line slopes equal\n"); */
- else if (d == 0) {
- center->x = transD1.x;
- center->y = transD2.y - (center->x - transD2.x) / e;
- }
- else {
- center->x = (d * e * transD2.y + d * transD2.x
- - d * e * transD1.y - e * transD1.x) / (d - e);
- center->y = (transD1.x - center->x) / d + transD1.y;
- }
- }
-
- /* radius of curvature */
- *radiusC = sqrt ((center->x - transD1.x) * (center->x - transD1.x)
- + (center->y - transD1.y) * (center->y - transD1.y));
-
- return (0);
- }
-
- /* EVENTRANSPTS: function evens the transition points so they are
- * symmetric around the middle of curve
- * usage: eventranspts (&trans1, &trans2,
- * lineLow, lineHigh, intrsct,
- * &widthZZ)
- * Note that the points are evened here so that
- * the shorter is elongated so that its end is
- * perpendicular to the longer. Other valid adjustments
- * would be to shorten the longer to the shorter,
- * or to adjust them both to the middle length.
- */
-
- #define NOTEQUALSLOPES 0 /* 2 lines of different slopes */
- #define EQUALSLOPES 1 /* 2 lines of same slopes (not 0, infin.) */
- #define INFINITESLOPES 2 /* 2 lines of same infinite slopes */
- #define ZEROSLOPES 3 /* 2 lines of same 0 slopes */
-
- long
- eventranspts (trans1, trans2, lineLow, lineHigh, intrsct, widthZZ)
- struct dpoint *trans1, *trans2; /* transition points to be evened */
- struct point lineLow, lineHigh; /* low/high points of transition lines */
- struct dpoint intrsct; /* intersection point of transition lines */
- double *widthZZ; /* zero crossing width */
- {
- double deltaX1, deltaY1, /* x,y increments of lines */
- deltaX2, deltaY2, mPerpen, bPerpen; /* slope, intercept for perpendicular line */
- short equalSlopes; /* flag showing relative slopes for lines */
- long furtherPt; /* extended point for parallel lines */
- struct point pt; /* other pt on perpendicular line */
- struct dpoint intrsct1, intrsct2; /* intersects with perpendicular */
- double dist1, dist2, fraction;
- struct point lineLow0;
-
- deltaX1 = trans1->x - (double) lineLow.x;
- deltaX2 = (double) lineHigh.x - trans2->x;
- deltaY1 = trans1->y - (double) lineLow.y;
- deltaY2 = (double) lineHigh.y - trans2->y;
-
- if (deltaX1 == 0.0 && deltaX2 == 0.0)
- equalSlopes = INFINITESLOPES;
- else if (deltaY1 == 0.0 && deltaY2 == 0.0)
- equalSlopes = ZEROSLOPES;
- else if (deltaY1 / deltaX1 == deltaY2 / deltaX2)
- equalSlopes = EQUALSLOPES;
- else
- equalSlopes = NOTEQUALSLOPES;
-
- switch (equalSlopes) {
- /* adjust transition point for lines of different slopes */
- /* this adjusts the further transition pt to be the same distance
- * to the intersect for arcs of BOTH CURVELT180 and CURVEGT180 */
- case NOTEQUALSLOPES:
- dist1 = (trans1->x - intrsct.x) * (trans1->x - intrsct.x)
- + (trans1->y - intrsct.y) * (trans1->y - intrsct.y);
- dist2 = (trans2->x - intrsct.x) * (trans2->x - intrsct.x)
- + (trans2->y - intrsct.y) * (trans2->y - intrsct.y);
- if (dist1 > dist2) {
- dist1 = sqrt (dist1);
- dist2 = sqrt (dist2);
- fraction = (dist1 - dist2) / dist1;
- trans1->x = trans1->x + fraction * (intrsct.x - trans1->x);
- trans1->y = trans1->y + fraction * (intrsct.y - trans1->y);
- *widthZZ -= dist1 - dist2;
- }
- else if (dist2 > dist1) {
- dist1 = sqrt (dist1);
- dist2 = sqrt (dist2);
- fraction = (dist2 - dist1) / dist2;
- trans2->x = trans2->x + fraction * (intrsct.x - trans2->x);
- trans2->y = trans2->y + fraction * (intrsct.y - trans2->y);
- *widthZZ -= dist2 - dist1;
- }
- break;
- /* adjust transition point for both lines of vertical slope */
- case INFINITESLOPES:
- if (trans1->y >= lineLow.y)
- furtherPt = (trans1->y >= trans2->y) ? (long) trans1->y : (long) trans2->y;
- else
- furtherPt = (trans1->y <= trans2->y) ? (long) trans1->y : (long) trans2->y;
- trans1->y = trans2->y = (double) furtherPt;
- break;
- /* adjust transition point for both lines of zero slope */
- case ZEROSLOPES:
- if (trans1->x >= lineLow.x)
- furtherPt = (trans1->x >= trans2->x) ? (long) trans1->x : (long) trans2->x;
- else
- furtherPt = (trans1->x <= trans2->x) ? (long) trans1->x : (long) trans2->x;
- trans1->x = trans2->x = (double) furtherPt;
- break;
- /* adjust transition point for both lines parallel */
- case EQUALSLOPES:
- mPerpen = -deltaX1 / deltaY1;
- bPerpen = trans1->y - mPerpen * trans1->x;
- pt.x = (long) trans1->x + 10000; /* 10000 is arbitrary, but need big
- * * number so int roundoff small */
- pt.y = (long) (mPerpen * pt.x + bPerpen);
- lineLow0.x = (long) trans2->x;
- lineLow0.y = (long) trans2->y;
- linesintrsct (pt, *trans1, lineLow0, lineHigh, &intrsct1);
-
- bPerpen = trans2->y - mPerpen * trans2->x;
- pt.x = (long) trans2->x + 10000; /* 10000 is arbitrary, but need big
- * * number so int roundoff small */
- pt.y = (long) (mPerpen * pt.x + bPerpen);
- lineHigh.x = (long) trans1->x;
- lineHigh.y = (long) trans1->y;
- linesintrsct (pt, *trans2, lineLow, lineHigh, &intrsct2);
- dist1 = (trans1->x - lineLow.x) * (trans1->x - lineLow.x)
- + (trans1->y - lineLow.y) * (trans1->y - lineLow.y);
- dist2 = (intrsct1.x - lineLow.x) * (intrsct1.x - lineLow.x)
- + (intrsct1.y - lineLow.y) * (intrsct1.y - lineLow.y);
- if (dist2 > dist1) {
- trans2->x = intrsct1.x;
- trans2->y = intrsct1.y;
- }
- else {
- trans1->x = intrsct2.x;
- trans1->y = intrsct2.y;
- }
- break;
- }
- return (0);
- }
-
-
- /* CYCLEAUGMENT: function rewrites the zero-crossing array (and corresponding
- * data array) so that the array begins at the first zero
- * crossing for the entire array, then the array is wrapped
- * around the beginning until the first UP/DOWN crossing
- * so that features can be determined in the FEATDETERM
- * function
- * usage: nFeatsFlag = cycleaugment (wwPar.l,
- * &zCross, &nZCross, &data, &edge,
- * zInitial, zFinal)
- * - The flag <nFeatsFlag> is 0 if no crossings are found,
- * and 1 if there is at least one feature.
- * - Note that the <zCross> plot has already been overlapped
- * by <zInitial> at the front and <zFinal> at the end.
- * Therefore the additional wrap-around here is done from
- * within this overlap.
- */
-
- short
- cycleaugment (wwParL, zCross, nZCross, data, edge, zInitial, zFinal)
- long wwParL; /* ww length parameter */
- short **zCross; /* array of flags at zero-crossing locns */
- long *nZCross; /* no. values in zero-crossing plot */
- struct point **data; /* sequence of coordinates of lines */
- struct edge *edge; /* lower and upper <data> indices */
- long zInitial, zFinal; /* initial and final valid zCross indices */
- {
- long nNew; /* no. new points */
- int firstZero, firstUpDown, /* indices of first ZERO and first UP/DOWN */
- /* crossings on the zero-crossing plot */
- i, j;
- short *zCrossNew; /* new zero-crossing plot */
- struct point *dataNew; /* new data array containing
- * * wrap-around cycle */
-
- /* look for first ZERO crossing to start from */
- for (firstZero = zInitial; firstZero <= zFinal; firstZero++)
- if ((*zCross)[firstZero] == ZERO)
- break;
-
- if (firstZero >= zFinal)
- return (0); /* no ZEROs => circle */
-
- /* look for first UP/DOWN crossing after initial point to end with */
- for (firstUpDown = firstZero + 1; firstUpDown <= zFinal; firstUpDown++)
- if ((*zCross)[firstUpDown] == UP
- || (*zCross)[firstUpDown] == DOWN)
- break;
- if (firstUpDown > zFinal) {
- for (firstUpDown = zInitial; firstUpDown < firstZero; firstUpDown++)
- if ((*zCross)[firstUpDown] == UP
- || (*zCross)[firstUpDown] == DOWN)
- break;
- if (firstUpDown >= firstZero)
- return (0); /* 1 crossing => circle */
- }
-
- /* allocate space and write zero-crossing plot augmented with wrap-around */
- nNew = (zFinal - firstZero + 1) + (firstUpDown - zInitial + 1);
- if (firstUpDown < firstZero)
- nNew += zFinal - zInitial + 1;
-
- if ((zCrossNew = (short *) calloc (nNew, sizeof (*zCrossNew))) == NULL) {
- printf ("CYCLEAUGMENT: CALLOC: not enough memory -- sorry");
- return (-2);
- }
- if ((dataNew = (struct point *) calloc (nNew, sizeof (*dataNew))) == NULL) {
- printf ("CYCLEAUGMENT: CALLOC not enough memory");
- return (-3);
- }
-
- for (i = firstZero, j = 0; i <= zFinal; i++) {
- zCrossNew[j] = (*zCross)[i];
- dataNew[j++] = (*data)[i];
- }
- for (i = zInitial; i < firstZero; i++) {
- zCrossNew[j] = (*zCross)[i];
- dataNew[j++] = (*data)[i];
- }
- if (firstUpDown > firstZero)
- for (i = firstZero; i <= firstUpDown; i++) {
- zCrossNew[j] = (*zCross)[i];
- dataNew[j++] = (*data)[i];
- }
- else {
- for (i = firstZero; i <= zFinal; i++) {
- zCrossNew[j] = (*zCross)[i];
- dataNew[j++] = (*data)[i];
- }
- for (i = zInitial; i <= firstUpDown; i++) {
- zCrossNew[j] = (*zCross)[i];
- dataNew[j++] = (*data)[i];
- }
- }
- if (j != nNew)
- printf ("CYCLEAUGMENT: oh nuts: j = %3d, nNew = %3d\n",
- j, nNew);
- free (*zCross);
- (*zCross) = zCrossNew;
- (*data) = dataNew;
- (*edge).iHigh = nNew - 1;
- *nZCross = nNew;
-
- return (1);
- }
-
-
-
- /* BOUNDDETERM2: function determines boundary feature
- * former function, BOUNDDETERM, fit a curve as the boundary
- * feature; here, we fit two corners
- * usage: bounddeterm2 (zCross, theta, zStart, zEnd, nTheta,
- * edge, data, &zLow, &zHigh)
- */
-
- #define NOBOUNDCURVE -1 /* flag indicates small curvature */
-
- long
- bounddeterm2 (zCross, theta, zStart, zEnd, nTheta, data, edge, zLow, zHigh)
- short *zCross; /* array of flags at crossings on theta */
- struct theta *theta; /* theta plot */
- long zStart, /* start and end zero crossing indices */
- zEnd; /* (these are *within* peak) */
- long nTheta; /* no. values in theta plot */
- struct point *data; /* data array */
- struct edge edge; /* lower and upper <data> indices */
- long *zLow, /* line indices of end of peak before, */
- *zHigh; /* and start of peak after, feature peak */
- {
- struct point linePt, /* pt on line, not transition pt */
- transPt, /* transition pt between curve/line */
- endPt; /* final pt on curve */
- struct dpoint midArcPt; /* middle coord on arc */
- struct point corner, /* transition coords into and out of curve */
- trans1, trans2;
- int i;
-
- /* for feature at beginning of line (or beginning and end), determine coords */
-
- *zLow += edge.iLow;
- zStart += edge.iLow;
- zEnd += edge.iLow;
- *zHigh += edge.iLow;
-
- if (zStart == 1) {
- *zLow = zStart;
- endPt = data[zStart];
- transPt = data[zEnd];
- /* find zero crossing after peak */
- for (i = zEnd + 2 - edge.iLow; i < nTheta; i++) {
- if (zCross[i] == UP || zCross[i] == DOWN)
- break;
- else if (zCross[i] == ZERO)
- printf
- ("BOUNDDETERM error: ZERO crossing instead of UP/DOWN\n");
- }
- *zHigh = i - 1;
- linePt = data[*zHigh];
- trans1 = endPt;
- trans2 = transPt;
- corner.x = trans1.x;
- corner.y = trans1.y;
- linkcorner (WWCORNER, corner);
-
- midArcPt.x = data[(zEnd + zStart) / 2].x;
- midArcPt.y = data[(zEnd + zStart) / 2].y;
- corner.x = (long) (midArcPt.x + 0.5);
- corner.y = (long) (midArcPt.y + 0.5);
- corner.x = trans2.x;
- corner.y = trans2.y;
- linkcorner (WWCORNER, corner);
- }
-
- /* for a feature at end of line, determine coordinates */
- else {
- *zHigh = zEnd;
- for (i = zStart - 1 - edge.iLow; i >= 0; --i) {
- if (zCross[i] == ZERO)
- break;
- else if (zCross[i] == UP || zCross[i] == DOWN)
- printf
- ("BOUNDDETERM error: UP/DOWN crossing instead of ZERO\n");
- }
- *zLow = i;
- linePt = data[*zLow];
- transPt = data[zStart];
- endPt = data[zEnd + 1];
- trans1 = transPt;
- trans2 = endPt;
-
- }
-
- /* determine feature parameters, and store them */
-
- return (0);
- }
-
-
-
-
- /* BOUNDDETERM: function determines boundary feature
- * usage: bounddeterm (zCross, theta, zStart, zEnd, nTheta,
- * data, &zLow, &zHigh)
- */
-
- #define NOBOUNDCURVE -1 /* flag indicates small curvature */
-
- long
- bounddeterm (zCross, theta, zStart, zEnd, nTheta, data, zLow, zHigh)
- short *zCross; /* array of flags at crossings on theta */
- struct theta *theta; /* theta plot */
- long zStart, /* start and end zero crossing indices */
- zEnd; /* (these are *within* peak) */
- long nTheta; /* no. values in theta plot */
- struct point *data; /* data array */
- long *zLow, /* line indices of end of peak before, */
- *zHigh; /* and start of peak after, feature peak */
- {
- struct point linePt, /* pt on line, not transition pt */
- transPt, /* transition pt between curve/line */
- endPt; /* final pt on curve */
- struct dpoint intrsct; /* intersection of tangents to curve */
- double arcLength; /* length of arc of curve */
- short curveSweep; /* indicates sweep of curve */
- struct dpoint midArcPt; /* middle coord on arc */
- struct point trans1, /* transition coords into and out of curve */
- trans2;
- struct dpoint center; /* center of curvature */
- double radiusC; /* radius of curvature */
- short curveDirn;
- int i;
-
- /* for curve at beginning of line (or beginning and end), determine coords */
- if (zStart == 1) {
- *zLow = zStart;
- endPt = data[zStart]; /* 8Jan88 -- extra pt; 7Feb97 reverted back */
- transPt = data[zEnd];
- /* find zero crossing after peak */
- for (i = zEnd + 2; i < nTheta; i++) {
- if (zCross[i] == UP || zCross[i] == DOWN)
- break;
- else if (zCross[i] == ZERO)
- printf
- ("BOUNDDETERM error: ZERO crossing instead of UP/DOWN\n");
- }
- *zHigh = i - 1;
- linePt = data[*zHigh];
- trans1 = endPt;
- trans2 = transPt;
- }
-
- /* for a curve at end of line, determine coordinates */
- else {
- *zHigh = zEnd;
- for (i = zStart - 1; i >= 0; --i) {
- if (zCross[i] == ZERO)
- break;
- else if (zCross[i] == UP || zCross[i] == DOWN)
- printf
- ("BOUNDDETERM error: UP/DOWN crossing instead of ZERO\n");
- }
- *zLow = i;
- linePt = data[*zLow];
- transPt = data[zStart];
- endPt = data[zEnd + 1]; /* 8Jan88 -- extra pt = better accuracy */
- trans1 = transPt;
- trans2 = endPt;
- }
-
- /* determine curve parameters, and store them */
- midArcPt.x = data[(zEnd + zStart) / 2].x;
- midArcPt.y = data[(zEnd + zStart) / 2].y;
- /* if isolated arc with no boundary lines */
- if (zStart == 1 && zEnd == nTheta - 2) {
- arcLength = theta[zEnd + 1].length - theta[zStart - 1].length;
- if (feat2bound (transPt, endPt, arcLength, midArcPt, &radiusC, ¢er,
- &curveSweep) == NOBOUNDCURVE)
- return (0);
- }
- /* if boundary curve with 1 boundary line */
- else {
- if (featbound (linePt, transPt, endPt, &radiusC, ¢er,
- &intrsct, &curveSweep) == NOBOUNDCURVE)
- return (0);
- }
- if (((trans1.x == midArcPt.x) && (trans1.y == midArcPt.y))
- || ((trans2.x == midArcPt.x) && (trans2.y == midArcPt.y)));
- else
- curveDirn = curvedirn (trans1, trans2, midArcPt, center);
- linkcurve (intrsct, trans1, trans2, center, radiusC, curveDirn);
-
- return (0);
- }
-
-
- /* FEATBOUND: function calculates curve parameters for boundary feature
- * usage: flag = featbound (linePt, transPt, endPt,
- * &radius, ¢erPt, &jctPt, &curveSweep)
- * Function returns -1 if there is no curve, rather a straight
- * line.
- *
- */
-
- #include <images.h> /* for image format */
-
- long
- featbound (linePt, transPt, endPt, radius, centerPt, jctPt, curveSweep)
- struct point linePt, /* pt on line, not transition pt */
- transPt, /* transition pt between curve/line */
- endPt; /* final pt on curve */
-
- double *radius; /* output curve radius */
- struct dpoint *centerPt; /* output curve center */
- struct dpoint *jctPt; /* junction of curve tangents */
- short *curveSweep; /* indicates sweep of curve arc */
- {
- double denom, /* denominator */
- A, B, /* constants */
- sqrt ();
-
- /* calculate curve parameters */
- denom = (double) (linePt.y - transPt.y);
- if (denom != 0.0) {
- A = (double) (transPt.x - linePt.x) / denom;
- B = (double) (transPt.x * linePt.x - transPt.x * transPt.x
- + transPt.y * linePt.y - transPt.y * transPt.y) / denom;
- denom = 2.0 * (endPt.x + A * endPt.y - A * transPt.y - transPt.x);
- if (denom == 0.0)
- return (NOBOUNDCURVE);
- centerPt->x = (endPt.x * endPt.x + endPt.y * endPt.y
- - 2.0 * B * endPt.y - transPt.x * transPt.x
- - transPt.y * transPt.y + 2.0 * B * transPt.y)
- / denom;
- centerPt->y = A * centerPt->x + B;
- }
- else {
- centerPt->x = transPt.x;
- denom = 2.0 * (endPt.y - transPt.y);
- if (denom == 0.0)
- return (NOBOUNDCURVE);
- centerPt->y = (endPt.x * endPt.x - 2.0 * endPt.x * centerPt->x
- + endPt.y * endPt.y - transPt.y * transPt.y
- + 2.0 * transPt.x * centerPt->x
- - transPt.x * transPt.x) / denom;
- }
-
- *radius = sqrt ((transPt.x - centerPt->x) * (transPt.x - centerPt->x)
- + (transPt.y - centerPt->y) * (transPt.y - centerPt->y));
-
-
- /* calculate intersection of tangents to curve */
- curvecorner (linePt, transPt, endPt, *radius, *centerPt,
- jctPt, curveSweep);
-
- return (0);
- }
-
-
- /* CURVECORNER: intersection point of lines tangent to the transition
- * point and at the end point of an end curve feature
- * curvecorner (linePt, transPt, endPt, radius,
- * centerPt, &jctPt, &curveSweep)
- */
-
- #define PID2 1.570796327
-
- long
- curvecorner (linePt, transPt, endPt, radius, centerPt, jctPt, curveSweep)
- struct point linePt, /* pt on line, not transition pt */
- transPt, /* transition pt between curve/line */
- endPt; /* final pt on curve */
- double radius; /* output curve radius */
- struct dpoint centerPt; /* center of curve */
- struct dpoint *jctPt; /* jct pt of tangents to curve */
- short *curveSweep; /* indicates sweep of curve arc */
- {
- double denomE, denomT, /* end, trans slope denominators */
- mTrans, mEnd, /* end, transition line slopes */
- bTrans, bEnd, /* end, transition line slopes */
- distTJSqr, /* sqr dist. jct to transition pt */
- distLJSqr; /* sqr dist. jct to line pt */
-
- denomE = endPt.y - centerPt.y;
- denomT = transPt.x - linePt.x;
-
- /* parallel tangents */
- if (denomE == 0.0 && denomT == 0.0) {
- *curveSweep = CURVEEQ180;
- jctPt->x = (double) linePt.x;
- jctPt->y = (double) linePt.y;
- return (0);
- }
-
- /* not parallel tangents */
- else if (denomE == 0.0) {
- jctPt->x = endPt.x;
- mTrans = (transPt.y - linePt.y) / denomT;
- bTrans = -mTrans * linePt.x + linePt.y;
- jctPt->y = mTrans * jctPt->x + bTrans;
- }
- else if (denomT == 0.0) {
- jctPt->x = transPt.x;
- mEnd = -(endPt.x - centerPt.x) / denomE;
- bEnd = endPt.y - mEnd * endPt.x;
- jctPt->y = mEnd * jctPt->x + bEnd;
- }
- else {
- mEnd = -(endPt.x - centerPt.x) / denomE;
- bEnd = -mEnd * endPt.x + endPt.y;
- mTrans = (transPt.y - linePt.y) / denomT;
- bTrans = -mTrans * linePt.x + linePt.y;
- if (mEnd == mTrans) {
- *curveSweep = CURVEEQ180;
- jctPt->x = (double) linePt.x;
- jctPt->y = (double) linePt.y;
- return (0);
- }
- jctPt->x = (bEnd - bTrans) / (mTrans - mEnd);
- jctPt->y = mEnd * jctPt->x + bEnd;
- }
-
- /* check if tangents diverge or not */
- distTJSqr = (jctPt->x - transPt.x) * (jctPt->x - transPt.x)
- + (jctPt->y - transPt.y) * (jctPt->y - transPt.y);
- distLJSqr = (jctPt->x - linePt.x) * (jctPt->x - linePt.x)
- + (jctPt->y - linePt.y) * (jctPt->y - linePt.y);
- *curveSweep = (distLJSqr > distTJSqr) ? CURVELT180 : CURVEGT180;
-
- return (0);
- }
-
- /* FEAT2BOUND: function calculates curve parameters for an isolated arc
- * (i.e. a curve which is boundary on 2 sides)
- * usage: flag = feat2bound (strtPt, endPt, arcLength,
- * midArcPt, &radius, ¢erPt,
- * &curveSweep)
- * Function returns a -1 if there is no curve.
- *
- * When there are no bounding lines on the arc, we calculate
- * the curve from the arc length. (Since arc length is not
- * terribly reliable, we only use this method when lacking
- * bounding lines for other curve features.)
- *
- * Note: If the arc length is too large with respect to the
- * distance between the points, the radius is set equal
- * to half the circumference of the circle with the
- * transition-to-curve point diameter.
- */
-
- #define MAXRAD 100.0 /* this should be put in ww.h, made a fct
- * * of something and generally cleaned up ?? */
-
- long
- feat2bound (strtPt, endPt, arcLength, midArcPt, radius, centerPt, curveSweep)
- struct point strtPt, /* start pt of curve */
- endPt; /* final pt on curve */
- double arcLength; /* curve arc length */
- struct dpoint midArcPt; /* middle point on arc */
- double *radius; /* output curve radius */
- struct dpoint *centerPt; /* output curve center */
- short *curveSweep; /* indicates sweep of curve arc */
- {
- double dist, /* Euclid. dist start to end curve */
- beta, /* angle center to line and curve */
- perpend, /* dist center to <dist> line */
- xMidPt, yMidPt, /* midpt: line end to curve end */
- A, B, C, D, /* constants */
- xCenter1, yCenter1, /* potential center points */
- xCenter2, yCenter2, distSqr1, /* sqr dist from line to potential */
- distSqr2, /* center pts */
- temp;
-
- /* initial calculations */
- xMidPt = (strtPt.x + endPt.x) * 0.5;
- yMidPt = (strtPt.y + endPt.y) * 0.5;
- dist = sqrt ((double) ((endPt.x - strtPt.x) * (endPt.x - strtPt.x)
- + (endPt.y - strtPt.y) * (endPt.y - strtPt.y)));
-
- /* calculate radius of curvature by iterative half interval search */
- *radius = radsearch (arcLength, dist, MAXRAD);
- if (*radius == NOBOUNDCURVE)
- return (0);
-
- /* calculate angle of curve sweep */
- beta = arcLength / *radius;
- if (beta < PI)
- *curveSweep = CURVELT180;
- else if (beta > PI)
- *curveSweep = CURVEGT180;
- else
- *curveSweep = CURVEEQ180;
-
- /* calculate center of curvature */
- if (strtPt.x == endPt.x) {
- yCenter1 = yCenter2 = yMidPt;
- A = (*radius * *radius
- - (strtPt.y - yCenter1) * (strtPt.y - yCenter1));
- if (A < 0.0)
- A = 0.0;
- xCenter1 = strtPt.x + A;
- xCenter2 = strtPt.x - A;
- }
- else if (strtPt.y == endPt.y) {
- xCenter1 = xCenter2 = xMidPt;
- A = (*radius * *radius
- - (strtPt.x - xCenter1) * (strtPt.x - xCenter1));
- if (A < 0.0)
- A = 0.0;
- yCenter1 = strtPt.y + A;
- yCenter2 = strtPt.y - A;
- }
- else {
- perpend = *radius * cos (beta * 0.5);
- A = (endPt.y - strtPt.y) * (endPt.y - strtPt.y);
- B = A + strtPt.x * strtPt.x + endPt.x * endPt.x
- - 2.0 * strtPt.x * endPt.x;
- C = -2.0 * A * xMidPt - 2.0 * strtPt.x * strtPt.x * xMidPt
- + 4.0 * strtPt.x * endPt.x * xMidPt
- - 2.0 * endPt.x * endPt.x * xMidPt;
- D = A * xMidPt * xMidPt + strtPt.x * strtPt.x * xMidPt * xMidPt
- + endPt.x * endPt.x * xMidPt * xMidPt
- - 2.0 * strtPt.x * endPt.x * xMidPt * xMidPt
- - A * perpend * perpend;
-
- temp = C * C - 4.0 * B * D;
- if (temp < 0.0)
- temp = 0.0;
- xCenter1 = (-C + sqrt (temp)) / (2.0 * B);
- yCenter1 = ((strtPt.x - endPt.x) * (xCenter1 - xMidPt))
- / (endPt.y - strtPt.y) + yMidPt;
- temp = C * C - 4.0 * B * D;
- if (temp < 0.0)
- temp = 0.0;
- xCenter2 = (-C - sqrt (temp)) / (2.0 * B);
- yCenter2 = ((strtPt.x - endPt.x) * (xCenter2 - xMidPt))
- / (endPt.y - strtPt.y) + yMidPt;
- }
-
- distSqr1 = (xCenter1 - midArcPt.x) * (xCenter1 - midArcPt.x)
- + (yCenter1 - midArcPt.y) * (yCenter1 - midArcPt.y);
- distSqr2 = (xCenter2 - midArcPt.x) * (xCenter2 - midArcPt.x)
- + (yCenter2 - midArcPt.y) * (yCenter2 - midArcPt.y);
-
- if (distSqr1 > distSqr2) {
- centerPt->x = xCenter1;
- centerPt->y = yCenter1;
- }
- else {
- centerPt->x = xCenter2;
- centerPt->y = yCenter2;
- }
-
- return (0);
- }
-
-
- /* RADSEARCH: function calculates radius function by iterative
- * half interval search
- * usage: radius = radsearch (arcLength, dist, maxRad)
- * double radius, radsearch ();
- * Note: I don't know if the comparison of the <error> with
- * MAXERROR is the best test (should really be testing
- * the error in radius, but this has problems also). I
- * think this is okay, because of the search for
- * zero-crossing, preceding, which results in the
- * half-interval search having far fewer iterations.
- * In any event, by making the MAXERROR small, the
- * error in <radius> is decreased, and it seems to
- * converge pretty quickly (3-5 iterations).
- */
-
- #define NINTERVALX 10 /* no. intervals to search 0-cross */
- #define MAXERROR 0.001 /* error as fraction of radius */
-
- double
- radsearch (arcLength, dist, maxRad)
- double arcLength, /* curve arc length */
- dist, /* dist beginning to end of curve */
- maxRad; /* maximum allowable radius */
- {
- double minX, maxX, /* x range */
- error, /* fct value - should tend to 0 */
- deltaX, /* interval in x */
- x, /* function variable */
- higherX, /* region contains x zero crossing */
- lowerX, sin ();
-
- long nIter; /* iteration number */
-
- minX = arcLength * 0.5 / maxRad;
- maxX = PI;
-
- /* if arclength is too large, return largest possible radius */
- if (arcLength >= (PI * dist))
- return (PI * dist);
- /* if curvature is too small, return flag indicating this */
- error = sin (minX) - dist * 0.5 / maxRad;
- if (error <= 0.0)
- return (NOBOUNDCURVE);
-
- /* find zero crossing region */
- deltaX = (maxX - minX) / NINTERVALX;
- for (x = minX + deltaX; x <= maxX; x += deltaX) {
- error = sin (x) - (dist / arcLength) * x;
- if (error <= 0) {
- higherX = x;
- lowerX = higherX - deltaX;
- break;
- }
- }
-
- /* perform iterative half interval search on region with zero crossing */
- x = (lowerX + higherX) * 0.5;
- deltaX = (higherX - x) * 0.5;
- error = sin (x) - (dist / arcLength) * x;
- nIter = 0;
- while (ABS (error) > MAXERROR) { /* see note above */
- nIter++;
- if (error > 0) {
- x += deltaX;
- deltaX *= 0.5;
- }
- else if (error < 0) {
- x -= deltaX;
- deltaX *= 0.5;
- }
- error = sin (x) - (dist / arcLength) * x;
- }
-
- return ((arcLength * 0.5) / x);
- }
-
-
-
- /* CURVEDIRN: function finds direction of curve and returns a 1 if the
- * arc points are already ordered in counterclockwise (ccw)
- * order or a -1 if they are ordered clockwise (cw)
- * usage: dirn = curvedirn (arc1, arc2, midArc, center)
- *
- */
-
- /*#define PI 3.14159265358979 */
- #define PIT2 6.283185307
- #define PID2 1.570796327
- #define PI3D2 4.71238898
-
- short
- curvedirn (arc1, arc2, midArc, center)
- struct point arc1, arc2; /* boundary points of arc */
- struct dpoint midArc; /* point on arc about midway from start */
- struct dpoint center; /* center of curve */
- {
- double angle1, angle2, /* angle about center of arc1, arc2 */
- angleM, /* angle about center of mid arc point */
- theta12, /* angle from arc1 to arc2 ccw wrt center */
- theta1M; /* angle from arc1 to mid arc */
-
- /* calculate the ccw angles from arc1 to midArc and arc2 around center */
- angle1 = atan2 ((double) arc1.y - center.y, (double) arc1.x - center.x);
- if (angle1 < 0.0)
- angle1 += PIT2;
- angleM = atan2 ((double) midArc.y - center.y, (double) midArc.x - center.x);
- if (angleM < 0.0)
- angleM += PIT2;
- angle2 = atan2 ((double) arc2.y - center.y, (double) arc2.x - center.x);
- if (angle2 < 0.0)
- angle2 += PIT2;
-
- theta1M = angleM - angle1;
- if (theta1M < 0.0)
- theta1M += PIT2;
- theta12 = angle2 - angle1;
- if (theta12 < 0.0)
- theta12 += PIT2;
-
- if (theta12 > theta1M)
- return (1);
- else
- return (-1);
- }
-
-
-
- /* LINESINTRSCT: function calculates intersection point between
- * two lines
- * usage: flag = linesintrsct (line1Strt, line1End,
- * line2Strt, line2End, &intrsct)
- * Returns 0 if intersection, -1 if no intersection
- * and infinite slopes, -1 if no intersection and equal
- * (but not infinite) slopes.
- */
-
- #define NOTEQUALSLOPES 0 /* so there is an intersection pt */
- #define INFINITESLOPES2 -1 /* vertical slopes = no intersectn */
- #define EQUALSLOPES2 -2 /* equal slopes = no intersection */
-
- long
- linesintrsct (line1Strt, line1End, line2Strt, line2End, intrsct)
- struct point line1Strt;
- struct dpoint line1End; /* start/end coords of lines */
- struct point line2Strt, line2End;
- struct dpoint *intrsct; /* intersection point */
- {
- double deltaX1, deltaX2, /* x increments of lines */
- m1, m2, /* slopes of lines */
- b1, b2; /* y-intersects of lines */
-
- /* calculate intersection of lines */
- deltaX1 = (double) (line1Strt.x - line1End.x);
- deltaX2 = (double) (line2Strt.x - line2End.x);
- if (deltaX1 == 0.0 && deltaX2 == 0.0)
- return (INFINITESLOPES2);
- else if (deltaX1 == 0.0) {
- intrsct->x = (double) line1Strt.x;
- m2 = (double) (line2Strt.y - line2End.y) / deltaX2;
- b2 = -m2 * line2End.x + line2End.y;
- intrsct->y = m2 * intrsct->x + b2;
- }
- else if (deltaX2 == 0.0) {
- intrsct->x = (double) line2Strt.x;
- m1 = (line1Strt.y - line1End.y) / deltaX1;
- b1 = -m1 * line1End.x + line1End.y;
- intrsct->y = m1 * intrsct->x + b1;
- }
- else {
- m1 = (double) (line1Strt.y - line1End.y) / deltaX1;
- b1 = -m1 * line1Strt.x + line1Strt.y;
- m2 = (line2Strt.y - line2End.y) / deltaX2;
- b2 = -m2 * line2End.x + line2End.y;
- if (m1 == m2)
- return (EQUALSLOPES2);
- intrsct->x = (b1 - b2) / (m2 - m1);
- intrsct->y = m1 * intrsct->x + b1;
- }
- return (NOTEQUALSLOPES);
- }
-