[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
XGGState, filled complex paths
From: |
Georg Fleischmann |
Subject: |
XGGState, filled complex paths |
Date: |
Wed, 1 Aug 2001 21:16:52 +0200 |
Hi,
I have written a method to display filled bezier paths of higher complexity
for XGGState.
The patch provides correct display of paths with separated path elements, eg.
a circle in a circle in a circle.
For stroked paths, clipping, and for simple paths the old _doPath is still
called. Only more complex paths use the new _doComplexPath method.
I have created a screenshot which shows some paths:
http://www.vhf.de/products/cenon/GNUstep1.jpg
Georg
2001-08-01 Georg Fleischmann
* xgps/Source/XGGState.m
[XGGState _paintPath:]: more complex path handling added
[XGGState _doComplexPath:]: new, fill complex bezier paths
diff -u xgps/Source/XGGState.m.old xgps/Source/XGGState.m
--- xgps/Source/XGGState.m.old Thu Jul 26 23:35:11 2001
+++ xgps/Source/XGGState.m Wed Aug 1 19:13:24 2001
@@ -912,26 +912,132 @@
}
}
+/* fill a complex path. All coordinates should already
+ have been transformed to device coordinates. */
+- (void) _doComplexPath: (XPoint*)pts : (int*)types : (int)count
+ ll: (XPoint)ll ur: (XPoint)ur draw: (ctxt_object_t)type
+{
+ int x, y, i, j, cnt, nseg = 0;
+ XSegment segments[count];
+ Window root_rtn;
+ unsigned int width, height, b_rtn, d_rtn;
+
+ COPY_GC_ON_CHANGE;
+ if (draw == 0)
+ DPS_ERROR(DPSinvalidid, @"No Drawable defined");
+
+ XGetGeometry(XDPY, draw, &root_rtn, &x, &y, &width, &height,
+ &b_rtn, &d_rtn);
+ if (ur.x < x || ll.x > x + (int)width)
+ return;
+
+ if (ll.y < y)
+ ll.y = y;
+ if (ur.y > y + height)
+ ur.y = y + height;
+
+ /* draw horicontal lines from the bottom to the top of the path */
+ for (y = ll.y; y <= ur.y; y++)
+ {
+ int x[count], w[count], y0, y1;
+ int yh = y * 2 + 1; // shift y of horicontal line
+ XPoint lastP, p1;
+
+ /* intersect horicontal line with path */
+ for (i = 0, cnt = 0; i < count-1; i++)
+ {
+ if (types[i] == 0) // move (new subpath)
+ lastP = pts[i];
+ if (types[i+1] == 0) // last line of subpath
+ {
+ if (lastP.y == pts[i].y)
+ continue;
+ p1 = lastP; // close subpath
+ }
+ else
+ p1 = pts[i+1];
+ y0 = pts[i].y * 2, y1 = p1.y * 2;
+ if ((y0 < yh && yh < y1) || (y1 < yh && yh < y0) )
+ {
+ int dy = yh - pts[i].y * 2;
+ int ldy = y1 - y0;
+ int ldx = (p1.x - pts[i].x) * 2;
+
+ x[cnt] = pts[i].x + (ldx * dy / ldy) / 2;
+ /* sum up winding directions */
+ if (type == path_fill)
+ w[cnt] = ((cnt) ? w[cnt-1] : 0) + (y0 < y1) ? -1 : 1;
+ cnt++;
+ }
+ }
+
+ /* sort intersections */
+ for (i = 0; i < cnt-1; i++)
+ {
+ for (j=i+1; j<cnt; j++)
+ {
+ if (x[j] < x[i])
+ {
+ x[i] ^= x[j]; x[j] ^= x[i]; x[i] ^= x[j];
+ }
+ }
+ }
+
+ /* draw lines between intersections */
+ for (i = 0; i < cnt-1; i++)
+ {
+ /* eofill -> start line on odd intersection count
+ * winding fill -> start line on odd winding count
+ */
+ if ((type == path_eofill && !(i%2)) || (type == path_fill && w[i]))
+ {
+ segments[nseg].x1 = x[i];
+ segments[nseg].x2 = x[i+1];
+ segments[nseg].y1 = segments[nseg].y2 = y;
+ nseg++;
+ }
+ }
+
+ XDrawSegments(XDPY, draw, xgcntxt, segments, nseg);
+ if (drawingAlpha)
+ {
+ xr_device_color_t old_color;
+ NSAssert(alpha_buffer, NSInternalInconsistencyException);
+
+ old_color = color;
+ [self DPSsetgray: color.field[AINDEX]];
+ XDrawSegments(XDPY, alpha_buffer, xgcntxt, segments, nseg);
+ [self setColor: old_color];
+ }
+ nseg = 0;
+ } // for y
+}
+
- (void) _paintPath: (ctxt_object_t) drawType
{
unsigned count;
- NSBezierPath *flatPath;
+ NSBezierPath *flatPath;
+ XPoint ll, ur;
if (!path)
return;
+ ll.x = ll.y = 0x7FFF;
+ ur.x = ur.y = 0;
flatPath = [path bezierPathByFlatteningPath];
count = [flatPath elementCount];
if (count)
{
XPoint pts[count];
+ int ts[count];
unsigned j, i = 0;
NSBezierPathElement type;
- NSPoint points[3];
- BOOL first = YES;
- NSPoint p, last_p;
- BOOL doit;
-
+ NSPoint points[3];
+ BOOL first = YES;
+ NSPoint p, last_p;
+ BOOL doit;
+ BOOL complex = NO;
+
for(j = 0; j < count; j++)
{
doit = NO;
@@ -939,16 +1045,23 @@
switch(type)
{
case NSMoveToBezierPathElement:
- if (i > 1)
- {
- [self _doPath: pts : i draw: drawType];
- }
- i = 0;
+ if (drawType != path_eofill && drawType != path_fill)
+ {
+ if (i > 1)
+ {
+ [self _doPath: pts : i draw: drawType];
+ }
+ i = 0;
+ }
+ else if (i > 1)
+ complex = YES;
last_p = p = points[0];
+ ts[i] = 0;
first = NO;
break;
case NSLineToBezierPathElement:
p = points[0];
+ ts[i] = 1;
if (first)
{
last_p = points[0];
@@ -958,6 +1071,7 @@
case NSCurveToBezierPathElement:
// This should not happen, as we flatten the path
p = points[2];
+ ts[i] = 1;
if (first)
{
last_p = points[2];
@@ -966,22 +1080,40 @@
break;
case NSClosePathBezierPathElement:
p = last_p;
+ ts[i] = 1;
doit = YES;
break;
default:
break;
}
- pts[i++] = XGWindowPointToX(self, p);
+ pts[i] = XGWindowPointToX(self, p);
+ if (pts[i].x < ll.x)
+ ll.x = pts[i].x;
+ if (pts[i].y > ur.x)
+ ur.x = pts[i].x;
+ if (pts[i].y < ll.y)
+ ll.y = pts[i].y;
+ if (pts[i].y > ur.y)
+ ur.y = pts[i].y;
+ i++;
if (doit && i > 1)
{
- [self _doPath: pts : i draw: drawType];
+ if (complex)
+ [self _doComplexPath: pts : ts : i
+ ll: ll ur: ur draw: drawType];
+ else
+ [self _doPath: pts : i draw: drawType];
i = 0;
}
} /* for */
- if (i > 1)
+ if (i > 1)
{
- [self _doPath: pts : i draw: drawType];
+ if (complex)
+ [self _doComplexPath: pts : ts : i
+ ll: ll ur: ur draw: drawType];
+ else
+ [self _doPath: pts : i draw: drawType];
}
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- XGGState, filled complex paths,
Georg Fleischmann <=