home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************
- Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
- and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
-
- All Rights Reserved
-
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee is hereby granted,
- 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 names of Digital or MIT not be
- used in advertising or publicity pertaining to distribution of the
- software without specific, written prior permission.
-
- DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
- ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
- DIGITAL 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.
-
- ******************************************************************/
- /* $XConsortium: midash.c,v 5.3 89/09/14 19:14:48 rws Exp $ */
- #include "miscstruct.h"
- #include "mistruct.h"
- #include "mifpoly.h"
-
- static miDashPtr CheckDashStorage();
-
- /* return a list of DashRec. there will be an extra
- entry at the end holding the last point of the polyline.
- this means that the code that actually draws dashes can
- get a pair of points for every dash. only the point in the last
- dash record is useful; the other fields are not used.
- nseg is the number of segments, not the number of points.
-
- example:
-
- dash1.start
- dash2.start
- dash3.start
- last-point
-
- defines a list of segments
- (dash1.pt, dash2.pt)
- (dash2.pt, dash3.pt)
- (dash3.pt, last-point)
- and nseg == 3.
-
- NOTE:
- EVEN_DASH == ~ODD_DASH
-
- NOTE ALSO:
- miDashLines may return 0 segments, going from pt[0] to pt[0] with one dash.
- */
-
- miDashPtr
- miDashLine(npt, ppt, nDash, pDash, offset, pnseg)
- int npt;
- DDXPointPtr ppt;
- unsigned int nDash;
- unsigned char *pDash;
- unsigned int offset;
- int *pnseg;
- {
- DDXPointRec pt1, pt2;
- int lenCur; /* npt used from this dash */
- int lenMax; /* npt in this dash */
- int iDash = 0; /* index of current dash */
- int which; /* EVEN_DASH or ODD_DASH */
- miDashPtr pseg; /* list of dash segments */
- miDashPtr psegBase; /* start of list */
- int nseg = 0; /* number of dashes so far */
- int nsegMax = 0; /* num segs we can fit in this list */
-
- int x, y, len;
- int adx, ady, signdx, signdy;
- int du, dv, e1, e2, e, base_e = 0;
-
- lenCur = offset;
- which = EVEN_DASH;
- while(lenCur >= pDash[iDash])
- {
- lenCur -= pDash[iDash];
- iDash++;
- if (iDash >= nDash)
- iDash = 0;
- which = ~which;
- }
- lenMax = pDash[iDash];
-
- psegBase = (miDashPtr)NULL;
- pt2 = ppt[0]; /* just in case there is only one point */
-
- while(--npt)
- {
- if (PtEqual(ppt[0], ppt[1]))
- {
- ppt++;
- continue; /* no duplicated points in polyline */
- }
- pt1 = *ppt++;
- pt2 = *ppt;
-
- adx = pt2.x - pt1.x;
- ady = pt2.y - pt1.y;
- signdx = sign(adx);
- signdy = sign(ady);
- adx = abs(adx);
- ady = abs(ady);
-
- if (adx > ady)
- {
- du = adx;
- dv = ady;
- len = adx;
- }
- else
- {
- du = ady;
- dv = adx;
- len = ady;
- }
-
- e1 = dv * 2;
- e2 = e1 - 2*du;
- e = e1 - du;
- x = pt1.x;
- y = pt1.y;
-
- nseg++;
- pseg = CheckDashStorage(&psegBase, nseg, &nsegMax);
- if (!pseg)
- return (miDashPtr)NULL;
- pseg->pt = pt1;
- pseg->e1 = e1;
- pseg->e2 = e2;
- base_e = pseg->e = e;
- pseg->which = which;
- pseg->newLine = 1;
-
- while (len--)
- {
- if (adx > ady)
- {
- /* X_AXIS */
- if (((signdx > 0) && (e < 0)) ||
- ((signdx <=0) && (e <=0))
- )
- {
- e += e1;
- }
- else
- {
- y += signdy;
- e += e2;
- }
- x += signdx;
- }
- else
- {
- /* Y_AXIS */
- if (((signdx > 0) && (e < 0)) ||
- ((signdx <=0) && (e <=0))
- )
- {
- e +=e1;
- }
- else
- {
- x += signdx;
- e += e2;
- }
- y += signdy;
- }
-
- lenCur++;
- if (lenCur >= lenMax && (len || npt <= 1))
- {
- nseg++;
- pseg = CheckDashStorage(&psegBase, nseg, &nsegMax);
- if (!pseg)
- return (miDashPtr)NULL;
- pseg->pt.x = x;
- pseg->pt.y = y;
- pseg->e1 = e1;
- pseg->e2 = e2;
- pseg->e = e;
- which = ~which;
- pseg->which = which;
- pseg->newLine = 0;
-
- /* move on to next dash */
- iDash++;
- if (iDash >= nDash)
- iDash = 0;
- lenMax = pDash[iDash];
- lenCur = 0;
- }
- } /* while len-- */
- } /* while --npt */
-
- if (lenCur == 0 && nseg != 0)
- {
- nseg--;
- which = ~which;
- }
- *pnseg = nseg;
- pseg = CheckDashStorage(&psegBase, nseg+1, &nsegMax);
- if (!pseg)
- return (miDashPtr)NULL;
- pseg->pt = pt2;
- pseg->e = base_e;
- pseg->which = which;
- pseg->newLine = 0;
- return psegBase;
- }
-
-
- #define NSEGDELTA 16
-
- /* returns a pointer to the pseg[nseg-1], growing the storage as
- necessary. this interface seems unnecessarily cumbersome.
-
- */
-
- static
- miDashPtr
- CheckDashStorage(ppseg, nseg, pnsegMax)
- miDashPtr *ppseg; /* base pointer */
- int nseg; /* number of segment we want to write to */
- int *pnsegMax; /* size (in segments) of list so far */
- {
- if (nseg > *pnsegMax)
- {
- miDashPtr newppseg;
-
- *pnsegMax += NSEGDELTA;
- newppseg = (miDashPtr)xrealloc(*ppseg,
- (*pnsegMax)*sizeof(miDashRec));
- if (!newppseg)
- {
- xfree(*ppseg);
- return (miDashPtr)NULL;
- }
- *ppseg = newppseg;
- }
- return(*ppseg+(nseg-1));
- }
-
- miStepDash (dist, pDashIndex, pDash, numInDashList, pDashOffset)
- int dist; /* distance to step */
- int *pDashIndex; /* current dash */
- unsigned char *pDash; /* dash list */
- int numInDashList; /* total length of dash list */
- int *pDashOffset; /* offset into current dash */
- {
- int dashIndex, dashOffset;
- int totallen;
- int i;
-
- dashIndex = *pDashIndex;
- dashOffset = *pDashOffset;
- if (dist < pDash[dashIndex] - dashOffset)
- {
- *pDashOffset = dashOffset + dist;
- return;
- }
- dist -= pDash[dashIndex] - dashOffset;
- if (++dashIndex == numInDashList)
- dashIndex = 0;
- totallen = 0;
- for (i = 0; i < numInDashList; i++)
- totallen += pDash[i];
- if (totallen <= dist)
- dist = dist % totallen;
- while (dist >= pDash[dashIndex])
- {
- dist -= pDash[dashIndex];
- if (++dashIndex == numInDashList)
- dashIndex = 0;
- }
- *pDashIndex = dashIndex;
- *pDashOffset = dist;
- }
-