1 /************************************************************
3 Copyright 1989, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
25 Author: Bob Scheifler, MIT X Consortium
27 ********************************************************/
30 * "Algorithm for drawing ellipses or hyperbolae with a digital plotter"
31 * by M. L. V. Pitteway
32 * The Computer Journal, November 1967, Volume 10, Number 3, pp. 282-289
35 #ifdef HAVE_DIX_CONFIG_H
36 #include <dix-config.h>
41 #include <X11/Xprotostr.h>
42 #include "regionstr.h"
44 #include "pixmapstr.h"
48 #define FULLCIRCLE (360 * 64)
49 #define OCTANT (45 * 64)
50 #define QUADRANT (90 * 64)
51 #define HALFCIRCLE (180 * 64)
52 #define QUADRANT3 (270 * 64)
55 #define M_PI 3.14159265358979323846
58 #define Dsin(d) ((d) == 0 ? 0.0 : ((d) == QUADRANT ? 1.0 : \
59 ((d) == HALFCIRCLE ? 0.0 : \
60 ((d) == QUADRANT3 ? -1.0 : sin((double)d*(M_PI/11520.0))))))
62 #define Dcos(d) ((d) == 0 ? 1.0 : ((d) == QUADRANT ? 0.0 : \
63 ((d) == HALFCIRCLE ? -1.0 : \
64 ((d) == QUADRANT3 ? 0.0 : cos((double)d*(M_PI/11520.0))))))
81 static miZeroArcPtRec oob
= { 65536, 65536, 0 };
84 * (x - l)^2 / (W/2)^2 + (y + H/2)^2 / (H/2)^2 = 1
86 * where l is either 0 or .5
98 miZeroArcSetup(xArc
* arc
, miZeroArcRec
* info
, Bool ok360
)
102 int startseg
, endseg
;
103 int startAngle
, endAngle
;
105 miZeroArcPtRec start
, end
;
108 if (arc
->width
== arc
->height
) {
114 info
->a
= (arc
->width
<< 2) - 12;
115 info
->d
= 17 - (arc
->width
<< 1);
122 else if (!arc
->width
|| !arc
->height
) {
127 info
->a
= -(int) arc
->height
;
132 /* initial conditions */
133 info
->alpha
= (arc
->width
* arc
->width
) << 2;
134 info
->beta
= (arc
->height
* arc
->height
) << 2;
135 info
->k1
= info
->beta
<< 1;
136 info
->k3
= info
->k1
+ (info
->alpha
<< 1);
137 info
->b
= l
? 0 : -info
->beta
;
138 info
->a
= info
->alpha
* arc
->height
;
139 info
->d
= info
->b
- (info
->a
>> 1) - (info
->alpha
>> 2);
141 info
->d
-= info
->beta
>> 2;
143 /* take first step, d < 0 always */
147 /* octant change, b < 0 always */
148 info
->k1
= -info
->k1
;
149 info
->k3
= -info
->k3
;
151 info
->d
= info
->b
- info
->a
- info
->d
;
152 info
->a
= info
->a
- (info
->b
<< 1);
156 info
->w
= (arc
->width
+ 1) >> 1;
157 info
->h
= arc
->height
>> 1;
158 info
->xorg
= arc
->x
+ (arc
->width
>> 1);
160 info
->xorgo
= info
->xorg
+ l
;
161 info
->yorgo
= info
->yorg
+ arc
->height
;
166 info
->initialMask
= 0;
167 info
->startAngle
= 0;
180 angle1
= arc
->angle1
;
181 angle2
= arc
->angle2
;
182 if ((angle1
== 0) && (angle2
>= FULLCIRCLE
)) {
187 if (angle2
> FULLCIRCLE
)
189 else if (angle2
< -FULLCIRCLE
)
190 angle2
= -FULLCIRCLE
;
192 startAngle
= angle1
+ angle2
;
197 endAngle
= angle1
+ angle2
;
200 startAngle
= FULLCIRCLE
- (-startAngle
) % FULLCIRCLE
;
201 if (startAngle
>= FULLCIRCLE
)
202 startAngle
= startAngle
% FULLCIRCLE
;
204 endAngle
= FULLCIRCLE
- (-endAngle
) % FULLCIRCLE
;
205 if (endAngle
>= FULLCIRCLE
)
206 endAngle
= endAngle
% FULLCIRCLE
;
208 info
->startAngle
= startAngle
;
209 info
->endAngle
= endAngle
;
210 if (ok360
&& (startAngle
== endAngle
) && arc
->angle2
&&
211 arc
->width
&& arc
->height
) {
212 info
->initialMask
= 0xf;
217 startseg
= startAngle
/ OCTANT
;
218 if (!arc
->height
|| (((startseg
+ 1) & 2) && arc
->width
)) {
219 start
.x
= Dcos(startAngle
) * ((arc
->width
+ 1) / 2.0);
225 start
.y
= Dsin(startAngle
) * (arc
->height
/ 2.0);
228 start
.y
= info
->h
- start
.y
;
231 endseg
= endAngle
/ OCTANT
;
232 if (!arc
->height
|| (((endseg
+ 1) & 2) && arc
->width
)) {
233 end
.x
= Dcos(endAngle
) * ((arc
->width
+ 1) / 2.0);
239 end
.y
= Dsin(endAngle
) * (arc
->height
/ 2.0);
242 end
.y
= info
->h
- end
.y
;
245 info
->firstx
= start
.x
;
246 info
->firsty
= start
.y
;
247 info
->initialMask
= 0;
248 overlap
= arc
->angle2
&& (endAngle
<= startAngle
);
249 for (i
= 0; i
< 4; i
++) {
251 ((i
* QUADRANT
<= endAngle
) || ((i
+ 1) * QUADRANT
> startAngle
)) :
252 ((i
* QUADRANT
<= endAngle
) && ((i
+ 1) * QUADRANT
> startAngle
)))
253 info
->initialMask
|= (1 << i
);
255 start
.mask
= info
->initialMask
;
256 end
.mask
= info
->initialMask
;
259 overlap
= overlap
&& (endseg
== startseg
);
260 if (start
.x
!= end
.x
|| start
.y
!= end
.y
|| !overlap
) {
263 info
->initialMask
&= ~(1 << startseg
);
264 if (start
.x
> end
.x
|| start
.y
> end
.y
)
265 end
.mask
&= ~(1 << startseg
);
268 start
.mask
&= ~(1 << startseg
);
269 if (((start
.x
< end
.x
|| start
.y
< end
.y
) ||
270 (start
.x
== end
.x
&& start
.y
== end
.y
&& (endseg
& 1))) &&
272 end
.mask
&= ~(1 << startseg
);
275 end
.mask
&= ~(1 << endseg
);
276 if (((start
.x
> end
.x
|| start
.y
> end
.y
) ||
277 (start
.x
== end
.x
&& start
.y
== end
.y
&& !(startseg
& 1))) &&
279 start
.mask
&= ~(1 << endseg
);
283 info
->initialMask
&= ~(1 << endseg
);
284 if (start
.x
< end
.x
|| start
.y
< end
.y
)
285 start
.mask
&= ~(1 << endseg
);
288 /* take care of case when start and stop are both near 45 */
289 /* handle here rather than adding extra code to pixelization loops */
291 ((start
.y
< 0 && end
.y
>= 0) || (start
.y
>= 0 && end
.y
< 0))) {
292 i
= (startAngle
+ OCTANT
) % OCTANT
;
293 if (i
< EPSILON45
|| i
> OCTANT
- EPSILON45
) {
294 i
= (endAngle
+ OCTANT
) % OCTANT
;
295 if (i
< EPSILON45
|| i
> OCTANT
- EPSILON45
) {
297 i
= Dsin(startAngle
) * (arc
->height
/ 2.0);
300 if (info
->h
- i
== end
.y
)
301 start
.mask
= end
.mask
;
304 i
= Dsin(endAngle
) * (arc
->height
/ 2.0);
307 if (info
->h
- i
== start
.y
)
308 end
.mask
= start
.mask
;
323 if (info
->altend
.x
< info
->end
.x
|| info
->altend
.y
< info
->end
.y
) {
327 info
->altend
= info
->end
;
330 info
->altstart
= oob
;
333 info
->altstart
= end
;
334 if (info
->altstart
.x
< info
->start
.x
||
335 info
->altstart
.y
< info
->start
.y
) {
338 tmp
= info
->altstart
;
339 info
->altstart
= info
->start
;
344 if (!info
->start
.x
|| !info
->start
.y
) {
345 info
->initialMask
= info
->start
.mask
;
346 info
->start
= info
->altstart
;
348 if (!arc
->width
&& (arc
->height
== 1)) {
350 info
->initialMask
|= info
->end
.mask
;
351 info
->initialMask
|= info
->initialMask
<< 1;
358 #define Pixelate(xval,yval) \
365 #define DoPix(idx,xval,yval) if (mask & (1 << idx)) Pixelate(xval, yval);
368 miZeroArcPts(xArc
* arc
, DDXPointPtr pts
)
371 int x
, y
, a
, b
, d
, mask
;
375 do360
= miZeroArcSetup(arc
, &info
, TRUE
);
377 mask
= info
.initialMask
;
378 if (!(arc
->width
& 1)) {
379 DoPix(1, info
.xorgo
, info
.yorg
);
380 DoPix(3, info
.xorgo
, info
.yorgo
);
382 if (!info
.end
.x
|| !info
.end
.y
) {
383 mask
= info
.end
.mask
;
384 info
.end
= info
.altend
;
386 if (do360
&& (arc
->width
== arc
->height
) && !(arc
->width
& 1)) {
387 int yorgh
= info
.yorg
+ info
.h
;
388 int xorghp
= info
.xorg
+ info
.h
;
389 int xorghn
= info
.xorg
- info
.h
;
392 Pixelate(info
.xorg
+ x
, info
.yorg
+ y
);
393 Pixelate(info
.xorg
- x
, info
.yorg
+ y
);
394 Pixelate(info
.xorg
- x
, info
.yorgo
- y
);
395 Pixelate(info
.xorg
+ x
, info
.yorgo
- y
);
398 Pixelate(xorghp
- y
, yorgh
- x
);
399 Pixelate(xorghn
+ y
, yorgh
- x
);
400 Pixelate(xorghn
+ y
, yorgh
+ x
);
401 Pixelate(xorghp
- y
, yorgh
+ x
);
405 if (x
> 1 && pts
[-1].x
== pts
[-5].x
&& pts
[-1].y
== pts
[-5].y
)
411 while (y
< info
.h
|| x
< info
.w
) {
414 Pixelate(info
.xorg
+ x
, info
.yorg
+ y
);
415 Pixelate(info
.xorgo
- x
, info
.yorg
+ y
);
416 Pixelate(info
.xorgo
- x
, info
.yorgo
- y
);
417 Pixelate(info
.xorg
+ x
, info
.yorgo
- y
);
424 while (y
< info
.h
|| x
< info
.w
) {
427 if ((x
== info
.start
.x
) || (y
== info
.start
.y
)) {
428 mask
= info
.start
.mask
;
429 info
.start
= info
.altstart
;
431 DoPix(0, info
.xorg
+ x
, info
.yorg
+ y
);
432 DoPix(1, info
.xorgo
- x
, info
.yorg
+ y
);
433 DoPix(2, info
.xorgo
- x
, info
.yorgo
- y
);
434 DoPix(3, info
.xorg
+ x
, info
.yorgo
- y
);
435 if ((x
== info
.end
.x
) || (y
== info
.end
.y
)) {
436 mask
= info
.end
.mask
;
437 info
.end
= info
.altend
;
444 if ((x
== info
.start
.x
) || (y
== info
.start
.y
))
445 mask
= info
.start
.mask
;
446 DoPix(0, info
.xorg
+ x
, info
.yorg
+ y
);
447 DoPix(2, info
.xorgo
- x
, info
.yorgo
- y
);
448 if (arc
->height
& 1) {
449 DoPix(1, info
.xorgo
- x
, info
.yorg
+ y
);
450 DoPix(3, info
.xorg
+ x
, info
.yorgo
- y
);
456 #define DoPix(idx,xval,yval) \
457 if (mask & (1 << idx)) \
459 arcPts[idx]->x = xval; \
460 arcPts[idx]->y = yval; \
465 miZeroArcDashPts(GCPtr pGC
,
469 int maxPts
, DDXPointPtr
* evenPts
, DDXPointPtr
* oddPts
)
472 int x
, y
, a
, b
, d
, mask
;
475 DDXPointPtr arcPts
[4];
476 DDXPointPtr startPts
[5], endPts
[5];
478 DDXPointPtr startPt
, pt
, lastPt
, pts
;
479 int i
, j
, delta
, ptsdelta
, seg
, startseg
;
481 for (i
= 0; i
< 4; i
++)
482 arcPts
[i
] = points
+ (i
* maxPts
);
483 (void) miZeroArcSetup(arc
, &info
, FALSE
);
485 mask
= info
.initialMask
;
486 startseg
= info
.startAngle
/ QUADRANT
;
487 startPt
= arcPts
[startseg
];
488 if (!(arc
->width
& 1)) {
489 DoPix(1, info
.xorgo
, info
.yorg
);
490 DoPix(3, info
.xorgo
, info
.yorgo
);
492 if (!info
.end
.x
|| !info
.end
.y
) {
493 mask
= info
.end
.mask
;
494 info
.end
= info
.altend
;
496 while (y
< info
.h
|| x
< info
.w
) {
499 if ((x
== info
.firstx
) || (y
== info
.firsty
))
500 startPt
= arcPts
[startseg
];
501 if ((x
== info
.start
.x
) || (y
== info
.start
.y
)) {
502 mask
= info
.start
.mask
;
503 info
.start
= info
.altstart
;
505 DoPix(0, info
.xorg
+ x
, info
.yorg
+ y
);
506 DoPix(1, info
.xorgo
- x
, info
.yorg
+ y
);
507 DoPix(2, info
.xorgo
- x
, info
.yorgo
- y
);
508 DoPix(3, info
.xorg
+ x
, info
.yorgo
- y
);
509 if ((x
== info
.end
.x
) || (y
== info
.end
.y
)) {
510 mask
= info
.end
.mask
;
511 info
.end
= info
.altend
;
517 if ((x
== info
.firstx
) || (y
== info
.firsty
))
518 startPt
= arcPts
[startseg
];
519 if ((x
== info
.start
.x
) || (y
== info
.start
.y
))
520 mask
= info
.start
.mask
;
521 DoPix(0, info
.xorg
+ x
, info
.yorg
+ y
);
522 DoPix(2, info
.xorgo
- x
, info
.yorgo
- y
);
523 if (arc
->height
& 1) {
524 DoPix(1, info
.xorgo
- x
, info
.yorg
+ y
);
525 DoPix(3, info
.xorg
+ x
, info
.yorgo
- y
);
527 for (i
= 0; i
< 4; i
++) {
528 seg
= (startseg
+ i
) & 3;
529 pt
= points
+ (seg
* maxPts
);
532 endPts
[i
] = arcPts
[seg
];
536 startPts
[i
] = arcPts
[seg
] - 1;
541 startPts
[4] = startPts
[0];
543 startPts
[0] = startPt
;
545 if (startPts
[4] != endPts
[4])
550 if (startPts
[0] > startPts
[4])
552 if (startPts
[4] < endPts
[4])
556 if (arc
->angle2
< 0) {
557 DDXPointPtr tmps
, tmpe
;
561 tmps
= startPts
[0] - tmpd
;
562 tmpe
= endPts
[0] - tmpd
;
563 startPts
[0] = endPts
[4] - deltas
[4];
564 endPts
[0] = startPts
[4] - deltas
[4];
565 deltas
[0] = -deltas
[4];
570 tmps
= startPts
[1] - tmpd
;
571 tmpe
= endPts
[1] - tmpd
;
572 startPts
[1] = endPts
[3] - deltas
[3];
573 endPts
[1] = startPts
[3] - deltas
[3];
574 deltas
[1] = -deltas
[3];
578 tmps
= startPts
[2] - deltas
[2];
579 startPts
[2] = endPts
[2] - deltas
[2];
581 deltas
[2] = -deltas
[2];
583 for (i
= 0; i
< 5 && startPts
[i
] == endPts
[i
]; i
++);
587 for (j
= 4; startPts
[j
] == endPts
[j
]; j
--);
588 lastPt
= endPts
[j
] - deltas
[j
];
589 if (dinfo
->haveLast
&&
590 (pt
->x
== dinfo
->endPt
.x
) && (pt
->y
== dinfo
->endPt
.y
)) {
591 startPts
[i
] += deltas
[i
];
594 dinfo
->dashIndex
= dinfo
->dashIndexInit
;
595 dinfo
->dashOffset
= dinfo
->dashOffsetInit
;
597 if (!dinfo
->skipStart
&& (info
.startAngle
!= info
.endAngle
)) {
598 dinfo
->startPt
= *pt
;
599 dinfo
->haveStart
= TRUE
;
601 else if (!dinfo
->skipLast
&& dinfo
->haveStart
&&
602 (lastPt
->x
== dinfo
->startPt
.x
) &&
603 (lastPt
->y
== dinfo
->startPt
.y
) && (lastPt
!= startPts
[i
]))
605 if (info
.startAngle
!= info
.endAngle
) {
606 dinfo
->haveLast
= TRUE
;
607 dinfo
->endPt
= *lastPt
;
609 dashRemaining
= pGC
->dash
[dinfo
->dashIndex
] - dinfo
->dashOffset
;
610 for (i
= 0; i
< 5; i
++) {
614 while (pt
!= lastPt
) {
615 if (dinfo
->dashIndex
& 1) {
623 while ((pt
!= lastPt
) && --dashRemaining
>= 0) {
628 if (dinfo
->dashIndex
& 1)
632 if (dashRemaining
<= 0) {
633 if (++(dinfo
->dashIndex
) == pGC
->numInDashList
)
634 dinfo
->dashIndex
= 0;
635 dashRemaining
= pGC
->dash
[dinfo
->dashIndex
];
639 dinfo
->dashOffset
= pGC
->dash
[dinfo
->dashIndex
] - dashRemaining
;
643 miZeroPolyArc(DrawablePtr pDraw
, GCPtr pGC
, int narcs
, xArc
* parcs
)
649 DDXPointPtr points
, pts
, oddPts
= NULL
;
654 XID fgPixel
= pGC
->fgPixel
;
657 for (arc
= parcs
, i
= narcs
; --i
>= 0; arc
++) {
658 if (!miCanZeroArc(arc
))
659 miPolyArc(pDraw
, pGC
, 1, arc
);
661 if (arc
->width
> arc
->height
)
662 n
= arc
->width
+ (arc
->height
>> 1);
664 n
= arc
->height
+ (arc
->width
>> 1);
671 numPts
= maxPts
<< 2;
672 dospans
= (pGC
->fillStyle
!= FillSolid
);
674 widths
= malloc(sizeof(int) * numPts
);
679 if (pGC
->lineStyle
!= LineSolid
) {
681 dinfo
.haveStart
= FALSE
;
682 dinfo
.skipStart
= FALSE
;
683 dinfo
.haveLast
= FALSE
;
684 dinfo
.dashIndexInit
= 0;
685 dinfo
.dashOffsetInit
= 0;
686 miStepDash((int) pGC
->dashOffset
, &dinfo
.dashIndexInit
,
687 (unsigned char *) pGC
->dash
, (int) pGC
->numInDashList
,
688 &dinfo
.dashOffsetInit
);
690 points
= malloc(sizeof(DDXPointRec
) * numPts
);
697 for (arc
= parcs
, i
= narcs
; --i
>= 0; arc
++) {
698 if (miCanZeroArc(arc
)) {
699 if (pGC
->lineStyle
== LineSolid
)
700 pts
= miZeroArcPts(arc
, points
);
703 oddPts
= &points
[(numPts
>> 1) - 1];
705 miZeroArcDashPts(pGC
, arc
, &dinfo
,
706 oddPts
+ 1, maxPts
, &pts
, &oddPts
);
707 dinfo
.skipStart
= TRUE
;
711 (*pGC
->ops
->PolyPoint
) (pDraw
, pGC
, CoordModeOrigin
, n
, points
);
717 if (pGC
->miTranslate
) {
718 for (pt
= points
; pt
!= pts
; pt
++) {
723 (*pGC
->ops
->FillSpans
) (pDraw
, pGC
, n
, points
, widths
, FALSE
);
725 if (pGC
->lineStyle
!= LineDoubleDash
)
727 if ((pGC
->fillStyle
== FillSolid
) ||
728 (pGC
->fillStyle
== FillStippled
)) {
731 gcval
.val
= pGC
->bgPixel
;
732 ChangeGC(NullClient
, pGC
, GCForeground
, &gcval
);
733 ValidateGC(pDraw
, pGC
);
735 pts
= &points
[numPts
>> 1];
739 (*pGC
->ops
->PolyPoint
) (pDraw
, pGC
, CoordModeOrigin
, n
, oddPts
);
745 if (pGC
->miTranslate
) {
746 for (pt
= oddPts
; pt
!= pts
; pt
++) {
751 (*pGC
->ops
->FillSpans
) (pDraw
, pGC
, n
, oddPts
, widths
, FALSE
);
753 if ((pGC
->fillStyle
== FillSolid
) ||
754 (pGC
->fillStyle
== FillStippled
)) {
758 ChangeGC(NullClient
, pGC
, GCForeground
, &gcval
);
759 ValidateGC(pDraw
, pGC
);