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]; } } _______________________________________________ Bug-gnustep mailing list [EMAIL PROTECTED] http://mail.gnu.org/mailman/listinfo/bug-gnustep