bug-gnustep
[Top][All Lists]
Advanced

[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];
        }
     }




reply via email to

[Prev in Thread] Current Thread [Next in Thread]