/common/lines.c
C | 1389 lines | 809 code | 123 blank | 457 comment | 161 complexity | 7289faf613bac99906ad05e56db34c72 MD5 | raw file
- /* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
- /***********************************************************
- Copyright 1989, 1998 The Open Group
- Permission to use, copy, modify, distribute, and sell this software and its
- documentation for any purpose is hereby granted without fee, provided that
- the above copyright notice appear in all copies and that both that
- copyright notice and this permission notice appear in supporting
- documentation.
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- Except as contained in this notice, the name of The Open Group shall not be
- used in advertising or otherwise to promote the sale, use or other dealings
- in this Software without prior written authorization from The Open Group.
- Copyright 1989 by Digital Equipment Corporation, Maynard, 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 name of Digital 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.
- ******************************************************************/
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #include <stdio.h>
- #include <spice/macros.h>
- #ifdef _XOPEN_SOURCE
- #include <math.h>
- #else
- #define _XOPEN_SOURCE /* to get prototype for hypot on some systems */
- #include <math.h>
- #undef _XOPEN_SOURCE
- #endif
- #include "lines.h"
- #include "mem.h"
- #define xalloc(i) spice_malloc(i)
- #define xrealloc(a,b) spice_realloc(a,b)
- #define xfree(i) free(i)
- typedef unsigned int CARD32;
- typedef int Boolean;
- typedef pixman_rectangle32_t xRectangle;
- typedef SpicePoint DDXPointRec;
- typedef DDXPointRec *DDXPointPtr;
- typedef struct lineGC *GCPtr;
- /* largest positive value that can fit into a component of a point.
- * Assumes that the point structure is {type x, y;} where type is
- * a signed type.
- */
- #define MAX_COORDINATE 2147483647
- #define MIN_COORDINATE -2147483647
- #define miZeroLine spice_canvas_zero_line
- #define miZeroDashLine spice_canvas_zero_dash_line
- #define miWideDash spice_canvas_wide_dash_line
- #define miWideLine spice_canvas_wide_line
- static inline int ICEIL (double x)
- {
- int _cTmp = (int)x;
- return ((x == _cTmp) || (x < 0.0)) ? _cTmp : _cTmp + 1;
- }
- typedef struct {
- int count; /* number of spans */
- DDXPointPtr points; /* pointer to list of start points */
- int *widths; /* pointer to list of widths */
- } Spans;
- typedef struct {
- int size; /* Total number of *Spans allocated */
- int count; /* Number of *Spans actually in group */
- Spans *group; /* List of Spans */
- int ymin, ymax; /* Min, max y values encountered */
- } SpanGroup;
- /* Initialize SpanGroup. MUST BE DONE before use. */
- static void miInitSpanGroup (SpanGroup * /*spanGroup */
- );
- /* Add a Spans to a SpanGroup. The spans MUST BE in y-sorted order */
- static void miAppendSpans (SpanGroup * /*spanGroup */ ,
- SpanGroup * /*otherGroup */ ,
- Spans * /*spans */
- );
- /* Paint a span group, insuring that each pixel is painted at most once */
- static void miFillUniqueSpanGroup (GCPtr /*pGC */ ,
- SpanGroup * /*spanGroup */ ,
- Boolean /* foreground */
- );
- /* Free up data in a span group. MUST BE DONE or you'll suffer memory leaks */
- static void miFreeSpanGroup (SpanGroup * /*spanGroup */
- );
- /* Rops which must use span groups */
- #define miSpansCarefulRop(rop) (((rop) & 0xc) == 0x8 || ((rop) & 0x3) == 0x2)
- #define miSpansEasyRop(rop) (!miSpansCarefulRop(rop))
- /*
- * Public definitions used for configuring basic pixelization aspects
- * of the sample implementation line-drawing routines provided in
- * {mfb,mi,cfb*} at run-time.
- */
- #define XDECREASING 4
- #define YDECREASING 2
- #define YMAJOR 1
- #define OCTANT1 (1 << (YDECREASING))
- #define OCTANT2 (1 << (YDECREASING|YMAJOR))
- #define OCTANT3 (1 << (XDECREASING|YDECREASING|YMAJOR))
- #define OCTANT4 (1 << (XDECREASING|YDECREASING))
- #define OCTANT5 (1 << (XDECREASING))
- #define OCTANT6 (1 << (XDECREASING|YMAJOR))
- #define OCTANT7 (1 << (YMAJOR))
- #define OCTANT8 (1 << (0))
- #define XMAJOROCTANTS (OCTANT1 | OCTANT4 | OCTANT5 | OCTANT8)
- #define DEFAULTZEROLINEBIAS (OCTANT2 | OCTANT3 | OCTANT4 | OCTANT5)
- /*
- * Devices can configure the rendering of routines in mi, mfb, and cfb*
- * by specifying a thin line bias to be applied to a particular screen
- * using the following function. The bias parameter is an OR'ing of
- * the appropriate OCTANT constants defined above to indicate which
- * octants to bias a line to prefer an axial step when the Bresenham
- * error term is exactly zero. The octants are mapped as follows:
- *
- * \ | /
- * \ 3 | 2 /
- * \ | /
- * 4 \ | / 1
- * \|/
- * -----------
- * /|\
- * 5 / | \ 8
- * / | \
- * / 6 | 7 \
- * / | \
- *
- * For more information, see "Ambiguities in Incremental Line Rastering,"
- * Jack E. Bresenham, IEEE CG&A, May 1987.
- */
- /*
- * Private definitions needed for drawing thin (zero width) lines
- * Used by the mi, mfb, and all cfb* components.
- */
- #define X_AXIS 0
- #define Y_AXIS 1
- #define OUT_LEFT 0x08
- #define OUT_RIGHT 0x04
- #define OUT_ABOVE 0x02
- #define OUT_BELOW 0x01
- #define OUTCODES(_result, _x, _y, _pbox) \
- if ( (_x) < (_pbox)->x1) (_result) |= OUT_LEFT; \
- else if ( (_x) >= (_pbox)->x2) (_result) |= OUT_RIGHT; \
- if ( (_y) < (_pbox)->y1) (_result) |= OUT_ABOVE; \
- else if ( (_y) >= (_pbox)->y2) (_result) |= OUT_BELOW;
- #define MIOUTCODES(outcode, x, y, xmin, ymin, xmax, ymax) \
- {\
- if (x < xmin) outcode |= OUT_LEFT;\
- if (x > xmax) outcode |= OUT_RIGHT;\
- if (y < ymin) outcode |= OUT_ABOVE;\
- if (y > ymax) outcode |= OUT_BELOW;\
- }
- #define SWAPINT(i, j) \
- { int _t = i; i = j; j = _t; }
- #define SWAPPT(i, j) \
- { DDXPointRec _t; _t = i; i = j; j = _t; }
- #define SWAPINT_PAIR(x1, y1, x2, y2)\
- { int t = x1; x1 = x2; x2 = t;\
- t = y1; y1 = y2; y2 = t;\
- }
- #define miGetZeroLineBias(_pScreen) (DEFAULTZEROLINEBIAS)
- #define CalcLineDeltas(_x1,_y1,_x2,_y2,_adx,_ady,_sx,_sy,_SX,_SY,_octant) \
- (_octant) = 0; \
- (_sx) = (_SX); \
- if (((_adx) = (_x2) - (_x1)) < 0) { \
- (_adx) = -(_adx); \
- (_sx = -(_sx)); \
- (_octant) |= XDECREASING; \
- } \
- (_sy) = (_SY); \
- if (((_ady) = (_y2) - (_y1)) < 0) { \
- (_ady) = -(_ady); \
- (_sy = -(_sy)); \
- (_octant) |= YDECREASING; \
- }
- #define SetYMajorOctant(_octant) ((_octant) |= YMAJOR)
- #define FIXUP_ERROR(_e, _octant, _bias) \
- (_e) -= (((_bias) >> (_octant)) & 1)
- #define IsXMajorOctant(_octant) (!((_octant) & YMAJOR))
- #define IsYMajorOctant(_octant) ((_octant) & YMAJOR)
- #define IsXDecreasingOctant(_octant) ((_octant) & XDECREASING)
- #define IsYDecreasingOctant(_octant) ((_octant) & YDECREASING)
- static int miZeroClipLine (int /*xmin */ ,
- int /*ymin */ ,
- int /*xmax */ ,
- int /*ymax */ ,
- int * /*new_x1 */ ,
- int * /*new_y1 */ ,
- int * /*new_x2 */ ,
- int * /*new_y2 */ ,
- unsigned int /*adx */ ,
- unsigned int /*ady */ ,
- int * /*pt1_clipped */ ,
- int * /*pt2_clipped */ ,
- int /*octant */ ,
- unsigned int /*bias */ ,
- int /*oc1 */ ,
- int /*oc2 */
- );
- /*
- * interface data to span-merging polygon filler
- */
- typedef struct _SpanData {
- SpanGroup fgGroup, bgGroup;
- } SpanDataRec, *SpanDataPtr;
- #define AppendSpanGroup(pGC, foreground, spanPtr, spanData) { \
- SpanGroup *group, *othergroup = NULL; \
- if (foreground) \
- { \
- group = &spanData->fgGroup; \
- if (pGC->lineStyle == LineDoubleDash) \
- othergroup = &spanData->bgGroup; \
- } \
- else \
- { \
- group = &spanData->bgGroup; \
- othergroup = &spanData->fgGroup; \
- } \
- miAppendSpans (group, othergroup, spanPtr); \
- }
- /*
- * Polygon edge description for integer wide-line routines
- */
- typedef struct _PolyEdge {
- int height; /* number of scanlines to process */
- int x; /* starting x coordinate */
- int stepx; /* fixed integral dx */
- int signdx; /* variable dx sign */
- int e; /* initial error term */
- int dy;
- int dx;
- } PolyEdgeRec, *PolyEdgePtr;
- #define SQSECANT 108.856472512142 /* 1/sin^2(11/2) - miter limit constant */
- /*
- * types for general polygon routines
- */
- typedef struct _PolyVertex {
- double x, y;
- } PolyVertexRec, *PolyVertexPtr;
- typedef struct _PolySlope {
- int dx, dy;
- double k; /* x0 * dy - y0 * dx */
- } PolySlopeRec, *PolySlopePtr;
- /*
- * Line face description for caps/joins
- */
- typedef struct _LineFace {
- double xa, ya;
- int dx, dy;
- int x, y;
- double k;
- } LineFaceRec, *LineFacePtr;
- /*
- * macros for polygon fillers
- */
- #define MIPOLYRELOADLEFT if (!left_height && left_count) { \
- left_height = left->height; \
- left_x = left->x; \
- left_stepx = left->stepx; \
- left_signdx = left->signdx; \
- left_e = left->e; \
- left_dy = left->dy; \
- left_dx = left->dx; \
- --left_count; \
- ++left; \
- }
- #define MIPOLYRELOADRIGHT if (!right_height && right_count) { \
- right_height = right->height; \
- right_x = right->x; \
- right_stepx = right->stepx; \
- right_signdx = right->signdx; \
- right_e = right->e; \
- right_dy = right->dy; \
- right_dx = right->dx; \
- --right_count; \
- ++right; \
- }
- #define MIPOLYSTEPLEFT left_x += left_stepx; \
- left_e += left_dx; \
- if (left_e > 0) \
- { \
- left_x += left_signdx; \
- left_e -= left_dy; \
- }
- #define MIPOLYSTEPRIGHT right_x += right_stepx; \
- right_e += right_dx; \
- if (right_e > 0) \
- { \
- right_x += right_signdx; \
- right_e -= right_dy; \
- }
- static void miRoundJoinClip (LineFacePtr /*pLeft */ ,
- LineFacePtr /*pRight */ ,
- PolyEdgePtr /*edge1 */ ,
- PolyEdgePtr /*edge2 */ ,
- int * /*y1 */ ,
- int * /*y2 */ ,
- Boolean * /*left1 */ ,
- Boolean * /*left2 */
- );
- static int miRoundCapClip (LineFacePtr /*face */ ,
- Boolean /*isInt */ ,
- PolyEdgePtr /*edge */ ,
- Boolean * /*leftEdge */
- );
- static int miPolyBuildEdge (double x0, double y0, double k, int dx, int dy,
- int xi, int yi, int left, PolyEdgePtr edge);
- static int miPolyBuildPoly (PolyVertexPtr vertices, PolySlopePtr slopes,
- int count, int xi, int yi, PolyEdgePtr left,
- PolyEdgePtr right, int *pnleft, int *pnright, int *h);
- static void
- miStepDash (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 > 0 && totallen <= dist)
- dist = dist % totallen;
- while (dist >= pDash[dashIndex]) {
- dist -= pDash[dashIndex];
- if (++dashIndex == numInDashList)
- dashIndex = 0;
- }
- *pDashIndex = dashIndex;
- *pDashOffset = dist;
- }
- /*
- These routines maintain lists of Spans, in order to implement the
- ``touch-each-pixel-once'' rules of wide lines and arcs.
- Written by Joel McCormack, Summer 1989.
- */
- static void
- miInitSpanGroup (SpanGroup * spanGroup)
- {
- spanGroup->size = 0;
- spanGroup->count = 0;
- spanGroup->group = NULL;
- spanGroup->ymin = MAX_COORDINATE;
- spanGroup->ymax = MIN_COORDINATE;
- } /* InitSpanGroup */
- #define YMIN(spans) (spans->points[0].y)
- #define YMAX(spans) (spans->points[spans->count-1].y)
- static void
- miSubtractSpans (SpanGroup * spanGroup, Spans * sub)
- {
- int i, subCount, spansCount;
- int ymin, ymax, xmin, xmax;
- Spans *spans;
- DDXPointPtr subPt, spansPt;
- int *subWid, *spansWid;
- int extra;
- ymin = YMIN (sub);
- ymax = YMAX (sub);
- spans = spanGroup->group;
- for (i = spanGroup->count; i; i--, spans++) {
- if (YMIN (spans) <= ymax && ymin <= YMAX (spans)) {
- subCount = sub->count;
- subPt = sub->points;
- subWid = sub->widths;
- spansCount = spans->count;
- spansPt = spans->points;
- spansWid = spans->widths;
- extra = 0;
- for (;;) {
- while (spansCount && spansPt->y < subPt->y) {
- spansPt++;
- spansWid++;
- spansCount--;
- }
- if (!spansCount)
- break;
- while (subCount && subPt->y < spansPt->y) {
- subPt++;
- subWid++;
- subCount--;
- }
- if (!subCount)
- break;
- if (subPt->y == spansPt->y) {
- xmin = subPt->x;
- xmax = xmin + *subWid;
- if (xmin >= spansPt->x + *spansWid || spansPt->x >= xmax) {
- ;
- } else if (xmin <= spansPt->x) {
- if (xmax >= spansPt->x + *spansWid) {
- memmove (spansPt, spansPt + 1, sizeof *spansPt * (spansCount - 1));
- memmove (spansWid, spansWid + 1, sizeof *spansWid * (spansCount - 1));
- spansPt--;
- spansWid--;
- spans->count--;
- extra++;
- } else {
- *spansWid = *spansWid - (xmax - spansPt->x);
- spansPt->x = xmax;
- }
- } else {
- if (xmax >= spansPt->x + *spansWid) {
- *spansWid = xmin - spansPt->x;
- } else {
- if (!extra) {
- DDXPointPtr newPt;
- int *newwid;
- #define EXTRA 8
- newPt = xrealloc (spans->points,
- (spans->count +
- EXTRA) * sizeof (DDXPointRec));
- if (!newPt)
- break;
- spansPt = newPt + (spansPt - spans->points);
- spans->points = newPt;
- newwid = xrealloc (spans->widths,
- (spans->count + EXTRA) * sizeof (int));
- if (!newwid)
- break;
- spansWid = newwid + (spansWid - spans->widths);
- spans->widths = newwid;
- extra = EXTRA;
- }
- memmove (spansPt + 1, spansPt, sizeof *spansPt * (spansCount));
- memmove (spansWid + 1, spansWid, sizeof *spansWid * (spansCount));
- spans->count++;
- extra--;
- *spansWid = xmin - spansPt->x;
- spansWid++;
- spansPt++;
- *spansWid = *spansWid - (xmax - spansPt->x);
- spansPt->x = xmax;
- }
- }
- }
- spansPt++;
- spansWid++;
- spansCount--;
- }
- }
- }
- }
- static void
- miAppendSpans (SpanGroup * spanGroup, SpanGroup * otherGroup, Spans * spans)
- {
- int ymin, ymax;
- int spansCount;
- spansCount = spans->count;
- if (spansCount > 0) {
- if (spanGroup->size == spanGroup->count) {
- spanGroup->size = (spanGroup->size + 8) * 2;
- spanGroup->group =
- xrealloc (spanGroup->group, sizeof (Spans) * spanGroup->size);
- }
- spanGroup->group[spanGroup->count] = *spans;
- (spanGroup->count)++;
- ymin = spans->points[0].y;
- if (ymin < spanGroup->ymin)
- spanGroup->ymin = ymin;
- ymax = spans->points[spansCount - 1].y;
- if (ymax > spanGroup->ymax)
- spanGroup->ymax = ymax;
- if (otherGroup && otherGroup->ymin < ymax && ymin < otherGroup->ymax) {
- miSubtractSpans (otherGroup, spans);
- }
- } else {
- xfree (spans->points);
- xfree (spans->widths);
- }
- } /* AppendSpans */
- static void
- miFreeSpanGroup (SpanGroup * spanGroup)
- {
- xfree (spanGroup->group);
- }
- static void
- QuickSortSpansX (DDXPointRec points[], int widths[], int numSpans)
- {
- int x;
- int i, j, m;
- DDXPointPtr r;
- /* Always called with numSpans > 1 */
- /* Sorts only by x, as all y should be the same */
- #define ExchangeSpans(a, b) \
- { \
- DDXPointRec tpt; \
- int tw; \
- \
- tpt = points[a]; points[a] = points[b]; points[b] = tpt; \
- tw = widths[a]; widths[a] = widths[b]; widths[b] = tw; \
- }
- do {
- if (numSpans < 9) {
- /* Do insertion sort */
- int xprev;
- xprev = points[0].x;
- i = 1;
- do { /* while i != numSpans */
- x = points[i].x;
- if (xprev > x) {
- /* points[i] is out of order. Move into proper location. */
- DDXPointRec tpt;
- int tw, k;
- for (j = 0; x >= points[j].x; j++) {
- }
- tpt = points[i];
- tw = widths[i];
- for (k = i; k != j; k--) {
- points[k] = points[k - 1];
- widths[k] = widths[k - 1];
- }
- points[j] = tpt;
- widths[j] = tw;
- x = points[i].x;
- } /* if out of order */
- xprev = x;
- i++;
- } while (i != numSpans);
- return;
- }
- /* Choose partition element, stick in location 0 */
- m = numSpans / 2;
- if (points[m].x > points[0].x)
- ExchangeSpans (m, 0);
- if (points[m].x > points[numSpans - 1].x)
- ExchangeSpans (m, numSpans - 1);
- if (points[m].x > points[0].x)
- ExchangeSpans (m, 0);
- x = points[0].x;
- /* Partition array */
- i = 0;
- j = numSpans;
- do {
- r = &(points[i]);
- do {
- r++;
- i++;
- } while (i != numSpans && r->x < x);
- r = &(points[j]);
- do {
- r--;
- j--;
- } while (x < r->x);
- if (i < j)
- ExchangeSpans (i, j);
- } while (i < j);
- /* Move partition element back to middle */
- ExchangeSpans (0, j);
- /* Recurse */
- if (numSpans - j - 1 > 1)
- QuickSortSpansX (&points[j + 1], &widths[j + 1], numSpans - j - 1);
- numSpans = j;
- } while (numSpans > 1);
- } /* QuickSortSpans */
- static int
- UniquifySpansX (Spans * spans, DDXPointRec * newPoints, int *newWidths)
- {
- int newx1, newx2, oldpt, i, y;
- DDXPointRec *oldPoints;
- int *oldWidths;
- int *startNewWidths;
- /* Always called with numSpans > 1 */
- /* Uniquify the spans, and stash them into newPoints and newWidths. Return the
- number of unique spans. */
- startNewWidths = newWidths;
- oldPoints = spans->points;
- oldWidths = spans->widths;
- y = oldPoints->y;
- newx1 = oldPoints->x;
- newx2 = newx1 + *oldWidths;
- for (i = spans->count - 1; i != 0; i--) {
- oldPoints++;
- oldWidths++;
- oldpt = oldPoints->x;
- if (oldpt > newx2) {
- /* Write current span, start a new one */
- newPoints->x = newx1;
- newPoints->y = y;
- *newWidths = newx2 - newx1;
- newPoints++;
- newWidths++;
- newx1 = oldpt;
- newx2 = oldpt + *oldWidths;
- } else {
- /* extend current span, if old extends beyond new */
- oldpt = oldpt + *oldWidths;
- if (oldpt > newx2)
- newx2 = oldpt;
- }
- } /* for */
- /* Write final span */
- newPoints->x = newx1;
- *newWidths = newx2 - newx1;
- newPoints->y = y;
- return (newWidths - startNewWidths) + 1;
- } /* UniquifySpansX */
- static void
- miDisposeSpanGroup (SpanGroup * spanGroup)
- {
- int i;
- Spans *spans;
- for (i = 0; i < spanGroup->count; i++) {
- spans = spanGroup->group + i;
- xfree (spans->points);
- xfree (spans->widths);
- }
- }
- static void
- miFillUniqueSpanGroup (GCPtr pGC, SpanGroup * spanGroup, Boolean foreground)
- {
- int i;
- Spans *spans;
- Spans *yspans;
- int *ysizes;
- int ymin, ylength;
- /* Outgoing spans for one big call to FillSpans */
- DDXPointPtr points;
- int *widths;
- int count;
- if (spanGroup->count == 0)
- return;
- if (spanGroup->count == 1) {
- /* Already should be sorted, unique */
- spans = spanGroup->group;
- (*pGC->ops->FillSpans)
- (pGC, spans->count, spans->points, spans->widths, TRUE, foreground);
- xfree (spans->points);
- xfree (spans->widths);
- } else {
- /* Yuck. Gross. Radix sort into y buckets, then sort x and uniquify */
- /* This seems to be the fastest thing to do. I've tried sorting on
- both x and y at the same time rather than creating into all those
- y buckets, but it was somewhat slower. */
- ymin = spanGroup->ymin;
- ylength = spanGroup->ymax - ymin + 1;
- /* Allocate Spans for y buckets */
- yspans = (Spans*)xalloc (ylength * sizeof (Spans));
- ysizes = (int *)xalloc (ylength * sizeof (int));
- if (!yspans || !ysizes) {
- xfree (yspans);
- xfree (ysizes);
- miDisposeSpanGroup (spanGroup);
- return;
- }
- for (i = 0; i != ylength; i++) {
- ysizes[i] = 0;
- yspans[i].count = 0;
- yspans[i].points = NULL;
- yspans[i].widths = NULL;
- }
- /* Go through every single span and put it into the correct bucket */
- count = 0;
- for (i = 0, spans = spanGroup->group; i != spanGroup->count; i++, spans++) {
- int index;
- int j;
- for (j = 0, points = spans->points, widths = spans->widths;
- j != spans->count; j++, points++, widths++) {
- index = points->y - ymin;
- if (index >= 0 && index < ylength) {
- Spans *newspans = &(yspans[index]);
- if (newspans->count == ysizes[index]) {
- DDXPointPtr newpoints;
- int *newwidths;
- ysizes[index] = (ysizes[index] + 8) * 2;
- newpoints = xrealloc (newspans->points,
- ysizes[index] * sizeof (DDXPointRec));
- newwidths = xrealloc (newspans->widths,
- ysizes[index] * sizeof (int));
- if (!newpoints || !newwidths) {
- for (i = 0; i < ylength; i++) {
- xfree (yspans[i].points);
- xfree (yspans[i].widths);
- }
- xfree (yspans);
- xfree (ysizes);
- xfree (newpoints);
- xfree (newwidths);
- miDisposeSpanGroup (spanGroup);
- return;
- }
- newspans->points = newpoints;
- newspans->widths = newwidths;
- }
- newspans->points[newspans->count] = *points;
- newspans->widths[newspans->count] = *widths;
- (newspans->count)++;
- } /* if y value of span in range */
- } /* for j through spans */
- count += spans->count;
- xfree (spans->points);
- spans->points = NULL;
- xfree (spans->widths);
- spans->widths = NULL;
- } /* for i thorough Spans */
- /* Now sort by x and uniquify each bucket into the final array */
- points = (DDXPointRec*)xalloc (count * sizeof (DDXPointRec));
- widths = (int *)xalloc (count * sizeof (int));
- if (!points || !widths) {
- for (i = 0; i < ylength; i++) {
- xfree (yspans[i].points);
- xfree (yspans[i].widths);
- }
- xfree (yspans);
- xfree (ysizes);
- xfree (points);
- xfree (widths);
- return;
- }
- count = 0;
- for (i = 0; i != ylength; i++) {
- int ycount = yspans[i].count;
- if (ycount > 0) {
- if (ycount > 1) {
- QuickSortSpansX (yspans[i].points, yspans[i].widths, ycount);
- count += UniquifySpansX (&(yspans[i]), &(points[count]), &(widths[count]));
- } else {
- points[count] = yspans[i].points[0];
- widths[count] = yspans[i].widths[0];
- count++;
- }
- xfree (yspans[i].points);
- xfree (yspans[i].widths);
- }
- }
- (*pGC->ops->FillSpans) (pGC, count, points, widths, TRUE, foreground);
- xfree (points);
- xfree (widths);
- xfree (yspans);
- xfree (ysizes); /* use (DE)xalloc for these? */
- }
- spanGroup->count = 0;
- spanGroup->ymin = MAX_COORDINATE;
- spanGroup->ymax = MIN_COORDINATE;
- }
- /*
- The bresenham error equation used in the mi/mfb/cfb line routines is:
- e = error
- dx = difference in raw X coordinates
- dy = difference in raw Y coordinates
- M = # of steps in X direction
- N = # of steps in Y direction
- B = 0 to prefer diagonal steps in a given octant,
- 1 to prefer axial steps in a given octant
- For X major lines:
- e = 2Mdy - 2Ndx - dx - B
- -2dx <= e < 0
- For Y major lines:
- e = 2Ndx - 2Mdy - dy - B
- -2dy <= e < 0
- At the start of the line, we have taken 0 X steps and 0 Y steps,
- so M = 0 and N = 0:
- X major e = 2Mdy - 2Ndx - dx - B
- = -dx - B
- Y major e = 2Ndx - 2Mdy - dy - B
- = -dy - B
- At the end of the line, we have taken dx X steps and dy Y steps,
- so M = dx and N = dy:
- X major e = 2Mdy - 2Ndx - dx - B
- = 2dxdy - 2dydx - dx - B
- = -dx - B
- Y major e = 2Ndx - 2Mdy - dy - B
- = 2dydx - 2dxdy - dy - B
- = -dy - B
- Thus, the error term is the same at the start and end of the line.
- Let us consider clipping an X coordinate. There are 4 cases which
- represent the two independent cases of clipping the start vs. the
- end of the line and an X major vs. a Y major line. In any of these
- cases, we know the number of X steps (M) and we wish to find the
- number of Y steps (N). Thus, we will solve our error term equation.
- If we are clipping the start of the line, we will find the smallest
- N that satisfies our error term inequality. If we are clipping the
- end of the line, we will find the largest number of Y steps that
- satisfies the inequality. In that case, since we are representing
- the Y steps as (dy - N), we will actually want to solve for the
- smallest N in that equation.
- Case 1: X major, starting X coordinate moved by M steps
- -2dx <= 2Mdy - 2Ndx - dx - B < 0
- 2Ndx <= 2Mdy - dx - B + 2dx 2Ndx > 2Mdy - dx - B
- 2Ndx <= 2Mdy + dx - B N > (2Mdy - dx - B) / 2dx
- N <= (2Mdy + dx - B) / 2dx
- Since we are trying to find the smallest N that satisfies these
- equations, we should use the > inequality to find the smallest:
- N = floor((2Mdy - dx - B) / 2dx) + 1
- = floor((2Mdy - dx - B + 2dx) / 2dx)
- = floor((2Mdy + dx - B) / 2dx)
- Case 1b: X major, ending X coordinate moved to M steps
- Same derivations as Case 1, but we want the largest N that satisfies
- the equations, so we use the <= inequality:
- N = floor((2Mdy + dx - B) / 2dx)
- Case 2: X major, ending X coordinate moved by M steps
- -2dx <= 2(dx - M)dy - 2(dy - N)dx - dx - B < 0
- -2dx <= 2dxdy - 2Mdy - 2dxdy + 2Ndx - dx - B < 0
- -2dx <= 2Ndx - 2Mdy - dx - B < 0
- 2Ndx >= 2Mdy + dx + B - 2dx 2Ndx < 2Mdy + dx + B
- 2Ndx >= 2Mdy - dx + B N < (2Mdy + dx + B) / 2dx
- N >= (2Mdy - dx + B) / 2dx
- Since we are trying to find the highest number of Y steps that
- satisfies these equations, we need to find the smallest N, so
- we should use the >= inequality to find the smallest:
- N = ceiling((2Mdy - dx + B) / 2dx)
- = floor((2Mdy - dx + B + 2dx - 1) / 2dx)
- = floor((2Mdy + dx + B - 1) / 2dx)
- Case 2b: X major, starting X coordinate moved to M steps from end
- Same derivations as Case 2, but we want the smallest number of Y
- steps, so we want the highest N, so we use the < inequality:
- N = ceiling((2Mdy + dx + B) / 2dx) - 1
- = floor((2Mdy + dx + B + 2dx - 1) / 2dx) - 1
- = floor((2Mdy + dx + B + 2dx - 1 - 2dx) / 2dx)
- = floor((2Mdy + dx + B - 1) / 2dx)
- Case 3: Y major, starting X coordinate moved by M steps
- -2dy <= 2Ndx - 2Mdy - dy - B < 0
- 2Ndx >= 2Mdy + dy + B - 2dy 2Ndx < 2Mdy + dy + B
- 2Ndx >= 2Mdy - dy + B N < (2Mdy + dy + B) / 2dx
- N >= (2Mdy - dy + B) / 2dx
- Since we are trying to find the smallest N that satisfies these
- equations, we should use the >= inequality to find the smallest:
- N = ceiling((2Mdy - dy + B) / 2dx)
- = floor((2Mdy - dy + B + 2dx - 1) / 2dx)
- = floor((2Mdy - dy + B - 1) / 2dx) + 1
- Case 3b: Y major, ending X coordinate moved to M steps
- Same derivations as Case 3, but we want the largest N that satisfies
- the equations, so we use the < inequality:
- N = ceiling((2Mdy + dy + B) / 2dx) - 1
- = floor((2Mdy + dy + B + 2dx - 1) / 2dx) - 1
- = floor((2Mdy + dy + B + 2dx - 1 - 2dx) / 2dx)
- = floor((2Mdy + dy + B - 1) / 2dx)
- Case 4: Y major, ending X coordinate moved by M steps
- -2dy <= 2(dy - N)dx - 2(dx - M)dy - dy - B < 0
- -2dy <= 2dxdy - 2Ndx - 2dxdy + 2Mdy - dy - B < 0
- -2dy <= 2Mdy - 2Ndx - dy - B < 0
- 2Ndx <= 2Mdy - dy - B + 2dy 2Ndx > 2Mdy - dy - B
- 2Ndx <= 2Mdy + dy - B N > (2Mdy - dy - B) / 2dx
- N <= (2Mdy + dy - B) / 2dx
- Since we are trying to find the highest number of Y steps that
- satisfies these equations, we need to find the smallest N, so
- we should use the > inequality to find the smallest:
- N = floor((2Mdy - dy - B) / 2dx) + 1
- Case 4b: Y major, starting X coordinate moved to M steps from end
- Same analysis as Case 4, but we want the smallest number of Y steps
- which means the largest N, so we use the <= inequality:
- N = floor((2Mdy + dy - B) / 2dx)
- Now let's try the Y coordinates, we have the same 4 cases.
- Case 5: X major, starting Y coordinate moved by N steps
- -2dx <= 2Mdy - 2Ndx - dx - B < 0
- 2Mdy >= 2Ndx + dx + B - 2dx 2Mdy < 2Ndx + dx + B
- 2Mdy >= 2Ndx - dx + B M < (2Ndx + dx + B) / 2dy
- M >= (2Ndx - dx + B) / 2dy
- Since we are trying to find the smallest M, we use the >= inequality:
- M = ceiling((2Ndx - dx + B) / 2dy)
- = floor((2Ndx - dx + B + 2dy - 1) / 2dy)
- = floor((2Ndx - dx + B - 1) / 2dy) + 1
- Case 5b: X major, ending Y coordinate moved to N steps
- Same derivations as Case 5, but we want the largest M that satisfies
- the equations, so we use the < inequality:
- M = ceiling((2Ndx + dx + B) / 2dy) - 1
- = floor((2Ndx + dx + B + 2dy - 1) / 2dy) - 1
- = floor((2Ndx + dx + B + 2dy - 1 - 2dy) / 2dy)
- = floor((2Ndx + dx + B - 1) / 2dy)
- Case 6: X major, ending Y coordinate moved by N steps
- -2dx <= 2(dx - M)dy - 2(dy - N)dx - dx - B < 0
- -2dx <= 2dxdy - 2Mdy - 2dxdy + 2Ndx - dx - B < 0
- -2dx <= 2Ndx - 2Mdy - dx - B < 0
- 2Mdy <= 2Ndx - dx - B + 2dx 2Mdy > 2Ndx - dx - B
- 2Mdy <= 2Ndx + dx - B M > (2Ndx - dx - B) / 2dy
- M <= (2Ndx + dx - B) / 2dy
- Largest # of X steps means smallest M, so use the > inequality:
- M = floor((2Ndx - dx - B) / 2dy) + 1
- Case 6b: X major, starting Y coordinate moved to N steps from end
- Same derivations as Case 6, but we want the smallest # of X steps
- which means the largest M, so use the <= inequality:
- M = floor((2Ndx + dx - B) / 2dy)
- Case 7: Y major, starting Y coordinate moved by N steps
- -2dy <= 2Ndx - 2Mdy - dy - B < 0
- 2Mdy <= 2Ndx - dy - B + 2dy 2Mdy > 2Ndx - dy - B
- 2Mdy <= 2Ndx + dy - B M > (2Ndx - dy - B) / 2dy
- M <= (2Ndx + dy - B) / 2dy
- To find the smallest M, use the > inequality:
- M = floor((2Ndx - dy - B) / 2dy) + 1
- = floor((2Ndx - dy - B + 2dy) / 2dy)
- = floor((2Ndx + dy - B) / 2dy)
- Case 7b: Y major, ending Y coordinate moved to N steps
- Same derivations as Case 7, but we want the largest M that satisfies
- the equations, so use the <= inequality:
- M = floor((2Ndx + dy - B) / 2dy)
- Case 8: Y major, ending Y coordinate moved by N steps
- -2dy <= 2(dy - N)dx - 2(dx - M)dy - dy - B < 0
- -2dy <= 2dxdy - 2Ndx - 2dxdy + 2Mdy - dy - B < 0
- -2dy <= 2Mdy - 2Ndx - dy - B < 0
- 2Mdy >= 2Ndx + dy + B - 2dy 2Mdy < 2Ndx + dy + B
- 2Mdy >= 2Ndx - dy + B M < (2Ndx + dy + B) / 2dy
- M >= (2Ndx - dy + B) / 2dy
- To find the highest X steps, find the smallest M, use the >= inequality:
- M = ceiling((2Ndx - dy + B) / 2dy)
- = floor((2Ndx - dy + B + 2dy - 1) / 2dy)
- = floor((2Ndx + dy + B - 1) / 2dy)
- Case 8b: Y major, starting Y coordinate moved to N steps from the end
- Same derivations as Case 8, but we want to find the smallest # of X
- steps which means the largest M, so we use the < inequality:
- M = ceiling((2Ndx + dy + B) / 2dy) - 1
- = floor((2Ndx + dy + B + 2dy - 1) / 2dy) - 1
- = floor((2Ndx + dy + B + 2dy - 1 - 2dy) / 2dy)
- = floor((2Ndx + dy + B - 1) / 2dy)
- So, our equations are:
- 1: X major move x1 to x1+M floor((2Mdy + dx - B) / 2dx)
- 1b: X major move x2 to x1+M floor((2Mdy + dx - B) / 2dx)
- 2: X major move x2 to x2-M floor((2Mdy + dx + B - 1) / 2dx)
- 2b: X major move x1 to x2-M floor((2Mdy + dx + B - 1) / 2dx)
- 3: Y major move x1 to x1+M floor((2Mdy - dy + B - 1) / 2dx) + 1
- 3b: Y major move x2 to x1+M floor((2Mdy + dy + B - 1) / 2dx)
- 4: Y major move x2 to x2-M floor((2Mdy - dy - B) / 2dx) + 1
- 4b: Y major move x1 to x2-M floor((2Mdy + dy - B) / 2dx)
- 5: X major move y1 to y1+N floor((2Ndx - dx + B - 1) / 2dy) + 1
- 5b: X major move y2 to y1+N floor((2Ndx + dx + B - 1) / 2dy)
- 6: X major move y2 to y2-N floor((2Ndx - dx - B) / 2dy) + 1
- 6b: X major move y1 to y2-N floor((2Ndx + dx - B) / 2dy)
- 7: Y major move y1 to y1+N floor((2Ndx + dy - B) / 2dy)
- 7b: Y major move y2 to y1+N floor((2Ndx + dy - B) / 2dy)
- 8: Y major move y2 to y2-N floor((2Ndx + dy + B - 1) / 2dy)
- 8b: Y major move y1 to y2-N floor((2Ndx + dy + B - 1) / 2dy)
- We have the following constraints on all of the above terms:
- 0 < M,N <= 2^15 2^15 can be imposed by miZeroClipLine
- 0 <= dx/dy <= 2^16 - 1
- 0 <= B <= 1
- The floor in all of the above equations can be accomplished with a
- simple C divide operation provided that both numerator and denominator
- are positive.
- Since dx,dy >= 0 and since moving an X coordinate implies that dx != 0
- and moving a Y coordinate implies dy != 0, we know that the denominators
- are all > 0.
- For all lines, (-B) and (B-1) are both either 0 or -1, depending on the
- bias. Thus, we have to show that the 2MNdxy +/- dxy terms are all >= 1
- or > 0 to prove that the numerators are positive (or zero).
- For X Major lines we know that dx > 0 and since 2Mdy is >= 0 due to the
- constraints, the first four equations all have numerators >= 0.
- For the second four equations, M > 0, so 2Mdy >= 2dy so (2Mdy - dy) >= dy
- So (2Mdy - dy) > 0, since they are Y major lines. Also, (2Mdy + dy) >= 3dy
- or (2Mdy + dy) > 0. So all of their numerators are >= 0.
- For the third set of four equations, N > 0, so 2Ndx >= 2dx so (2Ndx - dx)
- >= dx > 0. Similarly (2Ndx + dx) >= 3dx > 0. So all numerators >= 0.
- For the fourth set of equations, dy > 0 and 2Ndx >= 0, so all numerators
- are > 0.
- To consider overflow, consider the case of 2 * M,N * dx,dy + dx,dy. This
- is bounded <= 2 * 2^15 * (2^16 - 1) + (2^16 - 1)
- <= 2^16 * (2^16 - 1) + (2^16 - 1)
- <= 2^32 - 2^16 + 2^16 - 1
- <= 2^32 - 1
- Since the (-B) and (B-1) terms are all 0 or -1, the maximum value of
- the numerator is therefore (2^32 - 1), which does not overflow an unsigned
- 32 bit variable.
- */
- /* Bit codes for the terms of the 16 clipping equations defined below. */
- #define T_2NDX (1 << 0)
- #define T_2MDY (0) /* implicit term */
- #define T_DXNOTY (1 << 1)
- #define T_DYNOTX (0) /* implicit term */
- #define T_SUBDXORY (1 << 2)
- #define T_ADDDX (T_DXNOTY) /* composite term */
- #define T_SUBDX (T_DXNOTY | T_SUBDXORY) /* composite term */
- #define T_ADDDY (T_DYNOTX) /* composite term */
- #define T_SUBDY (T_DYNOTX | T_SUBDXORY) /* composite term */
- #define T_BIASSUBONE (1 << 3)
- #define T_SUBBIAS (0) /* implicit term */
- #define T_DIV2DX (1 << 4)
- #define T_DIV2DY (0) /* implicit term */
- #define T_ADDONE (1 << 5)
- /* Bit masks defining the 16 equations used in miZeroClipLine. */
- #define EQN1 (T_2MDY | T_ADDDX | T_SUBBIAS | T_DIV2DX)
- #define EQN1B (T_2MDY | T_ADDDX | T_SUBBIAS | T_DIV2DX)
- #define EQN2 (T_2MDY | T_ADDDX | T_BIASSUBONE | T_DIV2DX)
- #define EQN2B (T_2MDY | T_ADDDX | T_BIASSUBONE | T_DIV2DX)
- #define EQN3 (T_2MDY | T_SUBDY | T_BIASSUBONE | T_DIV2DX | T_ADDONE)
- #define EQN3B (T_2MDY | T_ADDDY | T_BIASSUBONE | T_DIV2DX)
- #define EQN4 (T_2MDY | T_SUBDY | T_SUBBIAS | T_DIV2DX | T_ADDONE)
- #define EQN4B (T_2MDY | T_ADDDY | T_SUBBIAS | T_DIV2DX)
- #define EQN5 (T_2NDX | T_SUBDX | T_BIASSUBONE | T_DIV2DY | T_ADDONE)
- #define EQN5B (T_2NDX | T_ADDDX | T_BIASSUBONE | T_DIV2DY)
- #define EQN6 (T_2NDX | T_SUBDX | T_SUBBIAS | T_DIV2DY | T_ADDONE)
- #define EQN6B (T_2NDX | T_ADDDX | T_SUBBIAS | T_DIV2DY)
- #define EQN7 (T_2NDX | T_ADDDY | T_SUBBIAS | T_DIV2DY)
- #define EQN7B (T_2NDX | T_ADDDY | T_SUBBIAS | T_DIV2DY)
- #define EQN8 (T_2NDX | T_ADDDY | T_BIASSUBONE | T_DIV2DY)
- #define EQN8B (T_2NDX | T_ADDDY | T_BIASSUBONE | T_DIV2DY)
- /* miZeroClipLine
- *
- * returns: 1 for partially clipped line
- * -1 for completely clipped line
- *
- */
- static int
- miZeroClipLine (int xmin, int ymin, int xmax, int ymax,
- int *new_x1, int *new_y1, int *new_x2, int *new_y2,
- unsigned int adx, unsigned int ady,
- int *pt1_clipped, int *pt2_clipped, int octant, unsigned int bias, int oc1, int oc2)
- {
- int swapped = 0;
- int clipDone = 0;
- CARD32 utmp = 0;
- int clip1, clip2;
- int x1, y1, x2, y2;
- int x1_orig, y1_orig, x2_orig, y2_orig;
- int xmajor;
- int negslope = 0, anchorval = 0;
- unsigned int eqn = 0;
- x1 = x1_orig = *new_x1;
- y1 = y1_orig = *new_y1;
- x2 = x2_orig = *new_x2;
- y2 = y2_orig = *new_y2;
- clip1 = 0;
- clip2 = 0;
- xmajor = IsXMajorOctant (octant);
- bias = ((bias >> octant) & 1);
- while (1) {
- if ((oc1 & oc2) != 0) { /* trivial reject */
- clipDone = -1;
- clip1 = oc1;
- clip2 = oc2;
- break;
- } else if ((oc1 | oc2) == 0) { /* trivial accept */
- clipDone = 1;
- if (swapped) {
- SWAPINT_PAIR (x1, y1, x2, y2);
- SWAPINT (clip1, clip2);
- }
- break;
- } else { /* have to clip */
- /* only clip one point at a time */
- if (oc1 == 0) {
- SWAPINT_PAIR (x1, y1, x2, y2);
- SWAPINT_PAIR (x1_orig, y1_orig, x2_orig, y2_orig);
- SWAPINT (oc1, oc2);
- SWAPINT (clip1, clip2);
- swapped = !swapped;
- }
- clip1 |= oc1;
- if (oc1 & OUT_LEFT) {
- negslope = IsYDecreasingOctant (octant);
- utmp = xmin - x1_orig;
- if (utmp <= 32767) { /* clip based on near endpt */
- if (xmajor)
- eqn = (swapped) ? EQN2 : EQN1;
- else
- eqn = (swapped) ? EQN4 : EQN3;
- anchorval = y1_orig;
- } else { /* clip based on far endpt */
- utmp = x2_orig - xmin;
- if (xmajor)
- eqn = (swapped) ? EQN1B : EQN2B;
- else
- eqn = (swapped) ? EQN3B : EQN4B;
- anchorval = y2_orig;
- negslope = !negslope;
- }
- x1 = xmin;
- } else if (oc1 & OUT_ABOVE) {
- negslope = IsXDecreasingOctant (octant);
- utmp = ymin - y1_orig;
- if (utmp <= 32767) { /* clip based on near endpt */
- if (xmajor)
- eqn = (swapped) ? EQN6 : EQN5;
- else
- eqn = (swapped) ? EQN8 : EQN7;
- anchorval = x1_orig;
- } else { /* clip based on far endpt */
- utmp = y2_orig - ymin;
- if (xmajor)
- eqn = (swapped) ? EQN5B : EQN6B;
- else
- eqn = (swapped) ? EQN7B : EQN8B;
- anchorval = x2_orig;
- negslope = !negslope;
- }
- y1 = ymin;
- } else if (oc1 & OUT_RIGHT) {
- negslope = IsYDecreasingOctant (octant);
- utmp = x1_orig - xmax;
- if (utmp <= 32767) { /* clip based on near endpt */
- if (xmajor)
- eqn = (swapped) ? EQN2 : EQN1;
- else
- eqn = (swapped) ? EQN4 : EQN3;
- anchorval = y1_orig;
- } else { /* clip based on far endpt */
- /*
- * Technically since the equations can handle
- * utmp == 32768, this overflow code isn't
- * needed since X11 protocol can't generate
- * a line which goes more than 32768 pixels
- * to the right of a clip rectangle.
- */
- utmp = xmax - x2_orig;
- if (xmajor)
- eqn = (swapped) ? EQN1B : EQN2B;
- else
- eqn = (swapped) ? EQN3B : EQN4B;
- anchorval = y2_orig;
- negslope = !negslope;
- }
- x1 = xmax;
- } else if (oc1 & OUT_BELOW) {
- negslope = IsXDecreasingOctant (octant);
- utmp = y1_orig - ymax;
- if (utmp <= 32767) { /* clip based on near endpt */
- if (xmajor)
- eqn = (swapped) ? EQN6 : EQN5;
- else
- eqn = (swapped) ? EQN8 : EQN7;
- anchorval = x1_orig;
- } else { /* clip based on far endpt */
- /*
- * Technically since the equations can handle
- * utmp == 32768, this overflow code isn't
- * needed since X11 protocol can't generate
- * a line which goes more than 32768 pixels
- * below the bottom of a clip rectangle.
- */
- utmp = ymax - y2_orig;
- if (xmajor)
- eqn = (swapped) ? EQN5B : EQN6B;
- else
- eqn = (swapped) ? EQN7B : EQN8B;
- anchorval = x2_orig;
- negslope = !negslope;
- }
- y1 = ymax;
- }
- if (swapped)
- negslope = !negslope;
- utmp <<= 1; /* utmp = 2N or 2M */
- if (eqn & T_2NDX)
- utmp = (utmp * adx);
- else /* (eqn & T_2MDY) */
- utmp = (utmp * ady);
- if (eqn & T_DXNOTY)
- if (eqn & T_SUBDXORY)
- utmp -= adx;
- else
- utmp += adx;
- else /* (eqn & T_DYNOTX) */ if (eqn & T_SUBDXORY)
- utmp -= ady;
- else
- utmp += ady;
-