|
|
1.1 root 1: /***********************************************************
2: Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
3: and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
4:
5: All Rights Reserved
6:
7: Permission to use, copy, modify, and distribute this software and its
8: documentation for any purpose and without fee is hereby granted,
9: provided that the above copyright notice appear in all copies and that
10: both that copyright notice and this permission notice appear in
11: supporting documentation, and that the names of Digital or MIT not be
12: used in advertising or publicity pertaining to distribution of the
13: software without specific, written prior permission.
14:
15: DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
17: DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
18: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
20: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21: SOFTWARE.
22:
23: ******************************************************************/
24: /* $Header: miarc.c,v 1.46 87/08/31 16:39:34 toddb Exp $ */
25: /* Author: Todd Newman */
26: #include "X.h"
27: #include "Xprotostr.h"
28: #include "misc.h"
29: #include "gcstruct.h"
30: #include "scrnintstr.h"
31: #include "pixmapstr.h"
32: #include "windowstr.h"
33: #include "mifpoly.h"
34:
35: extern double sqrt(), cos(), sin(), atan();
36: /* these are from our <math.h>, but I'm told some systems don't have
37: * math.h and that they're not in all versions of math.h. Psi! */
38: #define M_PI 3.14159265358979323846
39: #define M_PI_2 1.57079632679489661923
40:
41:
42: #define SAMESIGN(a, b) ((((a) >= 0) && ((b) >= 0)) ||\
43: (((a) <= 0) && ((b) <= 0)))
44:
45: /* This contains the information needed to draw one arc of a polyarc.
46: * An array of them can be allocated if the polyarc has more than 1 part */
47: typedef struct
48: {
49: int cpt;
50: DDXPointPtr pPts;
51: } POLYARCINFO;
52:
53: #define GCValsFunction 0
54: #define GCValsForeground 1
55: #define GCValsBackground 2
56: #define GCValsLineWidth 3
57: #define GCValsCapStyle 4
58: #define GCValsJoinStyle 5
59: #define GCValsArcMode 6
60: static int gcvals[]= {GXcopy, 1, 0, 0, 0, 0, 0};
61:
62: /* MIPOLYARC -- Public entry for the polyarc call.
63: * Strategy: Similar in many ways to that for wide lines.
64: * In general, we will each arc segment as a polyline. (We can make the arc
65: * arbitrarily smooth by increasing the number of segments and shortening
66: * the length of each segment.)
67: * If there's only 1 arc, or if the arc is draw with zero width lines, we
68: * don't have to worry about the rasterop or join styles.
69: * Otherwise, we set up pDrawTo and pGCTo according to the rasterop, then
70: * draw using pGCTo and pDrawTo. If the raster-op was "tricky," that is,
71: * if it involves the destination, then we use PushPixels to move the bits
72: * from the scratch drawable to pDraw. (See the wide line code for a
73: * fuller explanation of this.)
74: */
75: void
76: miPolyArc(pDraw, pGC, narcs, parcs)
77: DrawablePtr pDraw;
78: GCPtr pGC;
79: int narcs;
80: xArc *parcs;
81: {
82: register int i, j;
83: register DDXPointPtr ppt; /* Points for the current arc */
84: register DDXPointPtr pAllPts; /* Points for all arcs so far */
85: register int cpt, /* count of points in current arc */
86: cptAll; /* count of points in all arcs */
87: DDXPointPtr pPts; /* Points for the current arc */
88: int xMin, xMax, yMin, yMax, yOrg, xOrg, dx, dy,
89: ifirst, ilast, count, gcmode, arcmode, width;
90: Bool fAllOne, fTricky;
91: PixmapPtr pDrawTo;
92: GCPtr pGCTo;
93: POLYARCINFO *polyarcs;
94: DDXPointRec LastPt;
95:
96:
97: width = pGC->lineWidth;
98: if(width == 0 || narcs == 1)
99: {
100: /* don't have to worry about overlap or joinstyles */
101: for(i = 0; i < narcs; i++)
102: {
103: pPts = (DDXPointPtr)NULL;
104: if( cpt = miGetArcPts(&parcs[i], 0, &pPts))
105: {
106: (*pGC->Polylines)(pDraw, pGC, CoordModeOrigin, cpt, pPts);
107: Xfree(pPts);
108: }
109: }
110: }
111: else
112: {
113: count = 0;
114: ifirst = 0;
115: fAllOne = FALSE;
116: pPts = (DDXPointPtr) NULL;
117: pAllPts = (DDXPointPtr) NULL;
118: polyarcs = (POLYARCINFO *)ALLOCATE_LOCAL(narcs * sizeof(POLYARCINFO));
119: if(!polyarcs)
120: return;
121:
122: xMin = yMin = MAXSHORT;
123: xMax = yMax = MINSHORT;
124:
125: /* Get all points for all the arcs. */
126: for(i = 0; i < narcs; i++)
127: {
128: pPts = (DDXPointPtr) NULL;
129: if((cpt = miGetArcPts(&parcs[i], 0, &pPts)) == 0)
130: {
131: /* One of the arcs was empty. Give up */
132: while(--i >= 0)
133: {
134: Xfree(polyarcs[i].pPts);
135: }
136: DEALLOCATE_LOCAL(polyarcs);
137: return;
138: }
139: polyarcs[i].cpt = cpt;
140: polyarcs[i].pPts = pPts;
141: ppt = pPts;
142: for(j = 0; j < cpt; j++)
143: {
144: xMin = min(xMin, ppt->x);
145: yMin = min(yMin, ppt->y);
146: xMax = max(xMax, ppt->x);
147: yMax = max(yMax, ppt->y);
148: ppt++;
149: }
150: }
151: /* Set up pDrawTo and pGCTo based on the rasterop */
152: switch(pGC->alu)
153: {
154: case GXclear: /* 0 */
155: case GXcopy: /* src */
156: case GXcopyInverted: /* NOT src */
157: case GXset: /* 1 */
158: fTricky = FALSE;
159: pDrawTo = (PixmapPtr) pDraw;
160: pGCTo = pGC;
161: if(pGCTo->arcMode != ArcChord)
162: {
163: arcmode = pGCTo->arcMode;
164: DoChangeGC(pGCTo, GCArcMode, &gcvals[GCValsArcMode], 0);
165: ValidateGC(pDrawTo, pGCTo);
166: }
167: else
168: arcmode = ArcChord;
169:
170: break;
171: case GXand: /* src AND dst */
172: case GXandReverse: /* src AND NOT dst */
173: case GXandInverted: /* NOT src AND dst */
174: case GXnoop: /* dst */
175: case GXxor: /* src XOR dst */
176: case GXor: /* src OR dst */
177: case GXnor: /* NOT src AND NOT dst */
178: case GXequiv: /* NOT src XOR dst */
179: case GXinvert: /* NOT dst */
180: case GXorReverse: /* src OR NOT dst */
181: case GXorInverted: /* NOT src OR dst */
182: case GXnand: /* NOT src OR NOT dst */
183: fTricky = TRUE;
184:
185: pGCTo = GetScratchGC(1, pDraw->pScreen);
186: gcvals[GCValsLineWidth] = pGC->lineWidth;
187: gcvals[GCValsCapStyle] = pGC->capStyle;
188: gcvals[GCValsJoinStyle] = pGC->joinStyle;
189:
190: /* Also what about arcmode?? */
191: gcmode = GCFunction | GCForeground | GCBackground | GCLineWidth |
192: GCCapStyle | GCJoinStyle;
193: DoChangeGC(pGCTo, gcmode, gcvals, 0);
194:
195: xOrg = xMin - (width + 1)/2;
196: yOrg = yMin - (width + 1)/2;
197: dx = xMax - xMin + width + 1;
198: dy = yMax - yMin + width + 1;
199: for(i = 0; i < narcs; i++)
200: {
201: cpt = polyarcs[i].cpt;
202: ppt = polyarcs[i].pPts;
203: for(j = 0; j < cpt; j++)
204: {
205: ppt->x -= xOrg;
206: ppt->y -= yOrg;
207: ppt++;
208: }
209: }
210:
211: /* allocate a 1 bit deep pixmap of the appropriate size, and
212: * validate it */
213: pDrawTo = (PixmapPtr)(*pDraw->pScreen->CreatePixmap)
214: (pDraw->pScreen, dx, dy, 1, XYBitmap);
215: ValidateGC(pDrawTo, pGCTo);
216: miClearDrawable(pDrawTo, pGCTo);
217: }
218:
219: ilast = narcs - 1;
220:
221: /* If the last arc joins with the first, find all the final arcs
222: * that join together and join them with the initial ones.
223: */
224: if(PtEqual(polyarcs[0].pPts[0],
225: polyarcs[ilast].pPts[polyarcs[ilast].cpt - 1]) )
226: {
227: count = 1;
228: while(PtEqual (polyarcs[ilast].pPts[0],
229: polyarcs[ilast - 1].pPts[polyarcs[ilast - 1].cpt - 1]) )
230: {
231: if(ilast <= 1)
232: {
233: fAllOne = TRUE;
234: break;
235: }
236: else
237: {
238: ilast--;
239: count++;
240: }
241: }
242: if(!fAllOne)
243: {
244: while(PtEqual(polyarcs[ifirst].pPts[polyarcs[ifirst].cpt -1],
245: polyarcs[ifirst + 1].pPts[0]))
246: ifirst++;
247: cptAll = polyarcs[ilast].cpt;
248: pAllPts = polyarcs[ilast].pPts;
249: polyarcs[ilast++].pPts = (DDXPointPtr) NULL;
250: for(; ilast < narcs; ilast++)
251: {
252: cpt = polyarcs[ilast].cpt;
253: pAllPts = (DDXPointPtr) Xrealloc(pAllPts,
254: (cptAll+cpt-1) * sizeof(DDXPointRec));
255: bcopy((char *) &polyarcs[ilast].pPts[1],
256: (char *) &pAllPts[cptAll],
257: (cpt - 1) * sizeof(DDXPointRec));
258: cptAll += cpt - 1;
259: }
260: for( i = 0; i <= ifirst; i++)
261: {
262: cpt = polyarcs[i].cpt;
263: pAllPts = (DDXPointPtr) Xrealloc(pAllPts,
264: (cptAll+cpt-1) * sizeof(DDXPointRec));
265: bcopy((char *) &polyarcs[i].pPts[1],
266: (char *) &pAllPts[cptAll],
267: (cpt - 1) * sizeof(DDXPointRec));
268: cptAll += cpt - 1;
269: }
270: (*pGCTo->Polylines)(pDrawTo, pGCTo, CoordModeOrigin,
271: cptAll, pAllPts);
272: /* Don't need to free pAllPts, because we're sure to
273: * Xrealloc it again */
274: if(fTricky)
275: {
276: (*pGC->PushPixels)(pGC, pDrawTo, pDraw, dx, dy,
277: xOrg, yOrg);
278: miClearDrawable(pDrawTo, pGCTo);
279: }
280: }
281: ifirst++;
282: }
283: narcs -= count;
284:
285: /* Now draw all the (remaining) arcs */
286: cptAll = 0;
287: for(i = ifirst; i < narcs; i++)
288: {
289: cpt = polyarcs[i].cpt;
290: pPts = polyarcs[i].pPts;
291:
292: if((i > ifirst) && PtEqual(pPts[0], LastPt))
293: {
294: pAllPts = (DDXPointPtr)
295: Xrealloc(pAllPts,
296: (cptAll-1 + cpt) * sizeof(DDXPointRec));
297: bcopy((char *)&pPts[1],
298: (char *)&pAllPts[cptAll],
299: (cpt - 1) * sizeof(DDXPointRec));
300: cptAll += cpt - 1;
301: }
302: else
303: {
304: /* Flush what we have so far and start collecting again */
305: if(cptAll > 0)
306: {
307: (*pGC->Polylines)(pDrawTo, pGCTo, CoordModeOrigin,
308: cptAll, pAllPts);
309: Xfree(pAllPts);
310: if(fTricky)
311: {
312: (*pGC->PushPixels)(pGC, pDrawTo, pDraw, dx, dy,
313: xOrg, yOrg);
314: miClearDrawable(pDrawTo, pGCTo);
315: }
316: }
317: cptAll = cpt;
318: pAllPts = pPts;
319: }
320: LastPt = pPts[cpt-1];
321: } /* end for each remaining arc */
322:
323:
324: if(cptAll > 0)
325: {
326: (*pGC->Polylines)(pDrawTo,pGCTo, CoordModeOrigin, cptAll, pAllPts);
327: Xfree(pAllPts);
328: }
329: if(fTricky)
330: (*pGC->PushPixels)(pGC, pDrawTo, pDraw, dx, dy, xOrg, yOrg);
331: for(i = 0; i < narcs; i++)
332: {
333: Xfree(polyarcs[i].pPts);
334: }
335: DEALLOCATE_LOCAL(polyarcs);
336: if(fTricky)
337: {
338: (*pGCTo->pScreen->DestroyPixmap)(pDrawTo);
339: FreeScratchGC(pGCTo);
340: }
341: else
342: if(arcmode != ArcChord)
343: {
344: DoChangeGC(pGCTo, GCArcMode, &arcmode, 0);
345: ValidateGC(pDrawTo, pGCTo);
346: }
347: }
348: }
349:
350: /* 360 degrees * 64 sub-degree positions */
351: #define FULLCIRCLE 64 * 360
352:
353: /* MIPOLYFILLARC -- The public entry for the PolyFillArc request.
354: * Since we don't have to worry about overlapping segments, we can just
355: * fill each arc as it comes. As above, we convert the arc into a set of
356: * line segments and then fill the resulting polygon.
357: */
358: void
359: miPolyFillArc(pDraw, pGC, narcs, parcs)
360: DrawablePtr pDraw;
361: GCPtr pGC;
362: int narcs;
363: xArc *parcs;
364: {
365: int i, cpt;
366: DDXPointPtr pPts;
367:
368: for(i = 0; i < narcs; i++)
369: {
370: /* We do this test every time because a full circle PieSlice isn't
371: * really a slice, but a full pie, and the Chord code (below) should
372: * handle it better */
373: if(pGC->arcMode == ArcPieSlice && parcs[i].angle2 < FULLCIRCLE)
374: {
375: cpt = 1;
376: pPts = (DDXPointPtr)Xalloc(sizeof(DDXPointRec));
377: if(cpt = miGetArcPts(&parcs[i], cpt, &pPts))
378: {
379: pPts[0].x = parcs[i].x + parcs[i].width/2;
380: pPts[0].y = parcs[i].y + parcs[i].height/2;
381: (*pGC->FillPolygon)(pDraw, pGC, Convex,
382: CoordModeOrigin, cpt + 1, pPts);
383: Xfree((char *) pPts);
384: }
385: }
386: else /* Chord */
387: {
388: pPts = (DDXPointPtr)NULL;
389: if(cpt = miGetArcPts(&parcs[i], 0, &pPts))
390: {
391: (*pGC->FillPolygon)(pDraw, pGC, Convex,
392: CoordModeOrigin, cpt, pPts);
393: Xfree((char *) pPts);
394: }
395: }
396: }
397: }
398:
399: /* MIGETARCPTS -- Converts an arc into a set of line segments -- a helper
400: * routine for arc and line (round cap) code.
401: * Returns the number of points in the arc. Note that it takes a pointer
402: * to a pointer to where it should put the points and an index (cpt).
403: * This procedure allocates the space necessary to fit the arc points.
404: * Sometimes it's convenient for those points to be at the end of an existing
405: * array. (For example, if we want to leave a spare point to make sectors
406: * instead of segments.) So we pass in the Xalloc()ed chunk that contains the
407: * array and an index saying where we should start stashing the points.
408: * If there isn't an array already, we just pass in a null pointer and
409: * count on Xrealloc() to handle the null pointer correctly.
410: */
411: int
412: miGetArcPts(parc, cpt, ppPts)
413: xArc *parc; /* points to an arc */
414: int cpt; /* number of points already in arc list */
415: DDXPointPtr *ppPts; /* pointer to pointer to arc-list -- modified */
416: {
417: double st, /* Start Theta, start angle */
418: et, /* End Theta, offset from start theta */
419: dt, /* Delta Theta, angle to sweep ellipse */
420: cdt, /* Cos Delta Theta, actually 2 cos(dt) */
421: x0, y0, /* the recurrence formula needs two points to start */
422: x1, y1,
423: x2, y2, /* this will be the new point generated */
424: xc, yc; /* the center point */
425: int count, i;
426: DDXPointPtr poly;
427:
428: /* The spec says that positive angles indicate counterclockwise motion.
429: * Given our coordinate system (with 0,0 in the upper left corner),
430: * the screen appears flipped in Y. The easiest fix is to negate the
431: * angles given */
432:
433: /* Throw out multiples of 360 degrees. */
434: i = -parc->angle1;
435: if(i < 0)
436: {
437: while (i < -FULLCIRCLE)
438: i += FULLCIRCLE;
439: }
440: else
441: {
442: while(i > FULLCIRCLE)
443: i -= FULLCIRCLE;
444: }
445: st = (double ) i;
446: st *= ((double)M_PI) / (64 * 180); /* convert to degrees, then to rads */
447:
448: i = -parc->angle2;
449: /* If it's more than one full rotation, make it exactly 1 rotation */
450: if(i > FULLCIRCLE || i < -FULLCIRCLE)
451: {
452: i = FULLCIRCLE;
453: }
454: et = (double) i;
455: et *= ((double)M_PI) / (64 * 180); /* convert to degrees, then to rads */
456:
457: /* Try to get a delta theta that is within 1/2 pixel. Then adjust it
458: * so that it divides evenly into the total.
459: * I'm just using cdt 'cause I'm lazy.
460: */
461: cdt = max(parc->width, parc->height)/2;
462: if(cdt <= 0)
463: return 0;
464: dt = ( (double)2.0 / sqrt(cdt));
465: count = et/dt;
466: count = abs(count) + 1;
467: dt = et/count;
468: count++;
469:
470: cdt = 2 * cos(dt);
471:
472: poly = (DDXPointPtr) Xrealloc(*ppPts, (count + cpt) * sizeof(DDXPointRec));
473: *ppPts = poly;
474:
475: xc = parc->width/2.0; /* store half width and half height */
476: yc = parc->height/2.0;
477:
478:
479: x0 = xc * cos(st);
480: y0 = yc * sin(st);
481: x1 = xc * cos(st + dt);
482: y1 = yc * sin(st + dt);
483: xc += parc->x; /* by adding initial point, these become */
484: yc += parc->y; /* the center point */
485: poly[cpt].x = ROUNDTOINT(xc + x0);
486: poly[cpt].y = ROUNDTOINT(yc + y0);
487: poly[cpt + 1].x = ROUNDTOINT(xc + x1);
488: poly[cpt + 1].y = ROUNDTOINT(yc + y1);
489:
490: for(i = 2; i < count; i++)
491: {
492: x2 = cdt * x1 - x0;
493: y2 = cdt * y1 - y0;
494: poly[cpt + i].x = ROUNDTOINT(xc + x2);
495: poly[cpt + i].y = ROUNDTOINT(yc + y2);
496:
497: x0 = x1; y0 = y1;
498: x1 = x2; y1 = y2;
499: }
500: /* adjust the last point */
501: poly[cpt +i -1].x = ROUNDTOINT(cos(st + et) * parc->width/2.0 + xc);
502: poly[cpt +i -1].y = ROUNDTOINT(sin(st + et) * parc->height/2.0 + yc);
503:
504: return(count);
505: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.