Selaa lähdekoodia

porting

git-svn-id: https://svn.inf.ethz.ch/svn/lecturers/a2/trunk@7287 8c9fc860-2736-0410-a75d-ab315db34111
eth.metacore 8 vuotta sitten
vanhempi
commit
39884c5f97
7 muutettua tiedostoa jossa 1284 lisäystä ja 1411 poistoa
  1. 693 97
      source/AGfx.Mod
  2. BIN
      source/AGfx.Tool
  3. 45 46
      source/AGfxBuffer.Mod
  4. 3 8
      source/AGfxFonts.Mod
  5. 42 51
      source/AGfxPaths.Mod
  6. 153 808
      source/AGfxRaster.Mod
  7. 348 401
      source/AGfxRegions.Mod

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 693 - 97
source/AGfx.Mod


BIN
source/AGfx.Tool


+ 45 - 46
source/AGfxBuffer.Mod

@@ -18,7 +18,7 @@ MODULE GfxBuffer; (** portable *)	(* eos  *)
 
 
 	TYPE
-		Context* = OBJECT(GfxRaster.Context)
+		Context* = OBJECT (GfxRaster.Context)
 		VAR
 			orgX*, orgY*: REAL;	(** origin of default coordinate system **)
 			scale*: REAL;	(** default scale factor **)
@@ -30,7 +30,7 @@ MODULE GfxBuffer; (** portable *)	(* eos  *)
 			(** initialize buffered context **)
 			PROCEDURE InitBuffer* (img: Images.Image);
 			BEGIN
-				InitRaster();
+				SELF.InitRaster();
 				SELF.compOp := 1; (* Copy Op is default *)
 				SELF.img := img;
 				SELF.SetCoordinates(0, 0, 1);
@@ -38,24 +38,51 @@ MODULE GfxBuffer; (** portable *)	(* eos  *)
 				SELF.Reset();
 			END InitBuffer;
 
-			(*--- Methods ---*)
+
+			PROCEDURE{FINAL} SetColPat* (col: Gfx.Color; pat: Gfx.Pattern);
+			BEGIN
+				SetColPat^(col, pat);
+				Images.SetRGBA(SELF.pix, col.r, col.g, col.b, col.a)
+			END SetColPat;
+
+			(** set default coordinate origin and scale factor **)
+			PROCEDURE{FINAL} SetCoordinates* (x, y, scale: REAL);
+			BEGIN
+				SELF.orgX := x; SELF.orgY := y; SELF.scale := scale
+			END SetCoordinates;
+
+			(** set background color **)
+			PROCEDURE{FINAL} SetBGColor* (col: Gfx.Color);
+			BEGIN
+				SELF.bgCol := col
+			END SetBGColor;
+
+			(** set composition operation as defined in Raster **)
+			PROCEDURE{FINAL} SetCompOp* (op:SHORTINT);
+			BEGIN
+				SELF.compOp := op
+			END SetCompOp;
+
+		(**--- Coordinate System ---**)
 
 			(** current transformation matrix **)
-			PROCEDURE ResetCTM*();
+			PROCEDURE{FINAL} ResetCTM* ();
 			BEGIN
 				GfxMatrix.Translate(GfxMatrix.Identity, SELF.orgX, SELF.orgY, SELF.ctm);
 				GfxMatrix.Scale(SELF.ctm, SELF.scale, SELF.scale, SELF.ctm)
 			END ResetCTM;
 
-			(** clipping **)
-			PROCEDURE ResetClip*();
+		(**--- Clipping ---**)
+
+			PROCEDURE{FINAL} ResetClip* ();
 			BEGIN
-				ResetClip^();
+				SELF.ResetClip^();
 				SELF.clipReg.SetToRect(0, 0, SHORT(SELF.img.width), SHORT(SELF.img.height))
 			END ResetClip;
 
-			(** images and patterns **)
-			PROCEDURE Image* (x, y: REAL; img: Images.Image; VAR filter: GfxImages.Filter);
+		(**--- Raster ---**)
+
+			PROCEDURE{FINAL} DrawImage* (x, y: REAL; img: Images.Image; VAR filter: GfxImages.Filter);
 				VAR m: GfxMatrix.Matrix; dx, dy, llx, lly, urx, ury: INTEGER; col: Images.Pixel;
 			BEGIN
 				GfxMatrix.Translate(SELF.ctm, x, y, m);
@@ -85,15 +112,9 @@ MODULE GfxBuffer; (** portable *)	(* eos  *)
 					END
 				END;
 				Images.SetModeColor(filter, ORD(col[Images.r]), ORD(col[Images.g]), ORD(col[Images.b]))
-			END Image;
+			END DrawImage;
 
-			PROCEDURE SetColPat* (col: Gfx.Color; pat: Gfx.Pattern);
-			BEGIN
-				SELF.col := col; SELF.pat := pat;
-				Images.SetRGBA(SELF.pix, col.r, col.g, col.b, col.a)
-			END SetColPat;
-
-			PROCEDURE FillDot* (x, y: LONGINT);
+			PROCEDURE{FINAL} dot*(x, y: LONGINT);	(** current dot procedure **)
 				VAR px, py: LONGINT; mode: Images.Mode;
 			BEGIN
 				IF (SELF.clipState = GfxRaster.In) OR
@@ -109,9 +130,9 @@ MODULE GfxBuffer; (** portable *)	(* eos  *)
 						Images.Copy(SELF.pat.img, SELF.img, px, py, px+1, py+1, SHORT(x), SHORT(y), mode)
 					END
 				END
-			END FillDot;
+			END dot;
 
-			PROCEDURE FillRect* (llx, lly, urx, ury: LONGINT);
+			PROCEDURE{FINAL} rect* (llx, lly, urx, ury: LONGINT);	(** current rect procedure **)
 				VAR data: RegData; mode: Images.Mode;
 			BEGIN
 				IF (SELF.clipState # GfxRaster.Out) & (llx < urx) & (lly < ury) THEN
@@ -131,27 +152,7 @@ MODULE GfxBuffer; (** portable *)	(* eos  *)
 						SELF.clipReg.Enumerate(SHORT(llx), SHORT(lly), SHORT(urx), SHORT(ury), Tile, data)
 					END
 				END
-			END FillRect;
-
-			(*--- Exported Interface ---*)
-
-			(** set default coordinate origin and scale factor **)
-			PROCEDURE SetCoordinates* (x, y, scale: REAL);
-			BEGIN
-				SELF.orgX := x; SELF.orgY := y; SELF.scale := scale
-			END SetCoordinates;
-
-			(** set background color **)
-			PROCEDURE SetBGColor* (col: Gfx.Color);
-			BEGIN
-				SELF.bgCol := col
-			END SetBGColor;
-
-			(** set composition operation as defined in Raster **)
-			PROCEDURE SetCompOp* (op:SHORTINT);
-			BEGIN
-				SELF.compOp := op
-			END SetCompOp;
+			END rect;
 
 		END Context;
 
@@ -161,7 +162,6 @@ MODULE GfxBuffer; (** portable *)	(* eos  *)
 			mode: Images.Mode;
 		END;
 
-
 	(*--- Rendering ---*)
 
 	PROCEDURE Color (llx, lly, urx, ury: INTEGER; VAR data: GfxRegions.EnumData);
@@ -181,30 +181,29 @@ MODULE GfxBuffer; (** portable *)	(* eos  *)
 		END
 	END Tile;
 
-	(*--- Exported Interface ---*)
 
 	(** set default coordinate origin and scale factor **)
 	PROCEDURE SetCoordinates* (bc: Context; x, y, scale: REAL);
 	BEGIN
-		bc.SetCoordinates (x, y, scale);
+		bc.SetCoordinates(x, y, scale);
 	END SetCoordinates;
 
 	(** set background color **)
 	PROCEDURE SetBGColor* (bc: Context; col: Gfx.Color);
 	BEGIN
-		bc.SetBGColor (col);
+		bc.SetBGColor(col);
 	END SetBGColor;
 
 	(** set composition operation as defined in Raster **)
 	PROCEDURE SetCompOp* (bc: Context; op:SHORTINT);
 	BEGIN
-		bc.SetCompOp (op);
+		bc.SetCompOp(op);
 	END SetCompOp;
 
 	(** initialize buffered context **)
 	PROCEDURE Init* (bc: Context; img: Images.Image);
 	BEGIN
-		bc.InitBuffer(img);
+		bc.InitBuffer( img );
 	END Init;
 
 END GfxBuffer.

+ 3 - 8
source/AGfxFonts.Mod

@@ -87,11 +87,6 @@ MODULE GfxFonts; (** non-portable *)	(* eos  *)
 			prev, next: Font;	(* previous and next font in font cache *)
 			char: ARRAY 256 OF Char;	(* cached characters *)
 			rfile: RasterFile;	(* link to raster file *)
-			
-			PROCEDURE Derive*(ptsize: INTEGER; VAR mat: GfxMatrix.Matrix): Font; END Derive;
-			PROCEDURE GetWidth*(ch: CHAR; VAR dx, dy: REAL); END GetWidth;
-			PROCEDURE GetMap*(ch: CHAR; VAR x, y, dx, dy: REAL; VAR map: Raster.Image); END GetMap;
-			PROCEDURE GetOutline*(ch: CHAR; x, y: REAL; path: GfxPaths.Path); END GetOutline;
 		END;
 
 		MethodDesc* = RECORD
@@ -988,7 +983,7 @@ MODULE GfxFonts; (** non-portable *)	(* eos  *)
 		tmpRegion.Clear();
 		pathdata.region := tmpRegion;
 		tmpPath.EnumFlattened(0.5, AddElem, pathdata);
-		IF tmpRegion.Empty( ) THEN
+		IF tmpRegion.Empty() THEN
 			x := 0; y := 0; map := NIL
 		ELSE
 			llx := tmpRegion.llx; lly := tmpRegion.lly; urx := tmpRegion.urx; ury := tmpRegion.ury;
@@ -1052,7 +1047,7 @@ MODULE GfxFonts; (** non-portable *)	(* eos  *)
 					path.AddEnter(x, y, dx, dy)
 				| GfxPaths.Line:
 					GfxMatrix.Apply(mat, s.x, s.y, x, y);
-					path.AddLine( x, y)
+					path.AddLine(x, y)
 				| GfxPaths.Arc:
 					GfxMatrix.Apply(mat, s.x, s.y, x, y); GfxMatrix.Apply(mat, s.x0, s.y0, x0, y0);
 					GfxMatrix.Apply(mat, s.x1, s.y1, x1, y1); GfxMatrix.Apply(mat, s.x2, s.y2, x2, y2);
@@ -1066,7 +1061,7 @@ MODULE GfxFonts; (** non-portable *)	(* eos  *)
 					path.AddExit(dx, dy);
 					DEC(len)
 				END;
-				s.Scan( )
+				s.Scan()
 			UNTIL len = 0
 		END
 	END OGetOutline;

+ 42 - 51
source/AGfxPaths.Mod

@@ -13,8 +13,8 @@ MODULE GfxPaths; (** portable *)	(* eos  *)
 		15.9.98 - minor cleanup: removed position, Save/Restore, GetBBox; simplified scanner interface
 		26.11.98 - added procedure Close
 		26.1.99 - added procedure Split
-		21.5.99 - fixed major bug in Reverse (no update of destination path fields)
-		12.7.99 - fixed another bug in Reverse (wrong direction when reverting Exit element)
+		21.5.99 - fixed major bug in ReverseTo (no update of destination path fields)
+		12.7.99 - fixed another bug in ReverseTo (wrong direction when reverting Exit element)
 		12.7.99 - approximate arc with line if radius is smaller than flatness
 		18.02.2000 - simpler initial step without sqrt in EnumArc
 		18.02.2000 - more robust bezier code (deals with folded curves and cusps)
@@ -53,6 +53,33 @@ MODULE GfxPaths; (** portable *)	(* eos  *)
 		END;
 
 		(** path abstraction **)
+		(**
+			A paths consists of any number of subpaths, where each subpath starts with a Enter element, followed by
+			any number of curve elements, and terminated by an Exit element.
+
+			Enter
+				(x, y) is the starting point for the following curve element
+				(dx, dy) is the tangent vector at the end of an adjacent subpath or (0, 0) if there is none
+
+			Line
+				(x, y) is the end point of the line and the starting point of any subsequent curve
+
+			Arc
+				(x, y) is the end point of the arc and the starting point of any subsequent curve (may coincide with the
+						current point, resulting in a circle or ellipse)
+				(x0, y0) is the center of the circle/ellipse this arc is part of
+				(x1, y1) is the end point of the first half axis vector
+				(x2, y2) is the end point of the first half axis vector (not necessarily perpendicular to the first HAV)
+
+			Bezier
+				(x, y) is the end point of the cubic bezier curve and the starting point of any subsequent curve
+				(x1, y1) is the first control point of the cubic bezier curve
+				(x1, y1) is the second control point of the cubic bezier curve
+
+			Exit
+				(dx, dy) is the tangent vector at the starting point of an adjacent subpath or (0, 0) if there is none
+		**)
+		
 		Path* = OBJECT
 		VAR
 			elems* := 0, coords* := 0: INTEGER;	(** number of elements/coordinate pairs in path **)
@@ -69,7 +96,7 @@ MODULE GfxPaths; (** portable *)	(* eos  *)
 				SELF.elems := 0; SELF.coords := 0;
 				SELF.firstEB.coords := 0
 			END Clear;
-			
+
 			(** append enter element **)
 			PROCEDURE AddEnter* (x, y, dx, dy: REAL);
 			BEGIN
@@ -77,7 +104,7 @@ MODULE GfxPaths; (** portable *)	(* eos  *)
 				AddCoord(SELF, dx, dy);
 				AddCoord(SELF, x, y)
 			END AddEnter;
-			
+
 			(** append line element **)
 			PROCEDURE AddLine* (x, y: REAL);
 			BEGIN
@@ -409,7 +436,7 @@ MODULE GfxPaths; (** portable *)	(* eos  *)
 					INC(pos); INC(epos)
 				END
 			END Apply;
-
+			
 			(** try to close disconnected enter/exit points by modifying their direction vectors **)
 			PROCEDURE Close* ();
 				CONST
@@ -477,7 +504,7 @@ MODULE GfxPaths; (** portable *)	(* eos  *)
 					INC(pos); INC(epos)
 				END
 			END Close;
-			
+
 			(** split subpath in two at given offset (resulting subpaths may be flattened in the process) **)
 			PROCEDURE Split* (offset: REAL; head, tail: Path);
 				VAR data: SplitData;
@@ -492,15 +519,15 @@ MODULE GfxPaths; (** portable *)	(* eos  *)
 					SELF.EnumFlattened(1, EnumSplit, data)
 				END
 			END Split;
-			
+
 			(** return projection of point onto path **)
-			PROCEDURE ProjectTo* (x, y: REAL; VAR u, v: REAL);
+			PROCEDURE ProjectToPath* (x, y: REAL; VAR u, v: REAL);
 				VAR data: ProjectData;
 			BEGIN
 				data.px := x; data.py := y; data.dist := MAX(REAL); data.rx := MAX(REAL); data.ry := MAX(REAL);
 				SELF.EnumFlattened(1, EnumProject, data);
 				u := data.rx; v := data.ry
-			END ProjectTo;
+			END ProjectToPath;
 
 			(**--- Path Queries ---**)
 
@@ -522,7 +549,6 @@ MODULE GfxPaths; (** portable *)	(* eos  *)
 				RETURN data.hit
 			END OnPath;
 
-			
 		END Path;
 
 		(** path scanner **)
@@ -530,7 +556,7 @@ MODULE GfxPaths; (** portable *)	(* eos  *)
 			Path scanners can be used to iterate over a path under client control. The scanner's elem field specifies what
 			the current element is, whereas the remaining fields contain the parameters for that element. A Stop element
 			indicates that the end of the path has been reached.
-		**)
+		**)		
 		Scanner* = RECORD
 			path*: Path;	(** visited path **)
 			pos*: INTEGER;	(** element position **)
@@ -542,7 +568,6 @@ MODULE GfxPaths; (** portable *)	(* eos  *)
 			curCB: CoordBlock;	(* current coordinate block *)
 			epos, cpos: INTEGER;	(* next element and coordinate position within current block *)
 			
-			
 			(** open scanner on path and load parameters of element at given position **)
 			PROCEDURE Open* (path: Path; pos: INTEGER);
 			BEGIN
@@ -578,7 +603,7 @@ MODULE GfxPaths; (** portable *)	(* eos  *)
 					END
 				END
 			END Open;
-			
+
 			(** advance to next element and load its parameters **)
 			PROCEDURE Scan* ();
 			BEGIN
@@ -601,15 +626,15 @@ MODULE GfxPaths; (** portable *)	(* eos  *)
 					END
 				END
 			END Scan;
-	
-			PROCEDURE get (VAR x, y: REAL);
+			
+			PROCEDURE- get (VAR x, y: REAL);
 			BEGIN
 				IF SELF.cpos = CoordBlockSize THEN
 					SELF.curCB := SELF.curCB.next; SELF.cpos := 0
 				END;
 				x := SELF.curCB.x[SELF.cpos]; y := SELF.curCB.y[SELF.cpos]; INC(SELF.cpos)
 			END get;			
-	
+
 		END (* Scanner *);
 
 		(** path enumeration **)
@@ -654,34 +679,6 @@ MODULE GfxPaths; (** portable *)	(* eos  *)
 		END;
 
 
-	(**
-		A paths consists of any number of subpaths, where each subpath starts with a Enter element, followed by
-		any number of curve elements, and terminated by an Exit element.
-
-		Enter
-			(x, y) is the starting point for the following curve element
-			(dx, dy) is the tangent vector at the end of an adjacent subpath or (0, 0) if there is none
-
-		Line
-			(x, y) is the end point of the line and the starting point of any subsequent curve
-
-		Arc
-			(x, y) is the end point of the arc and the starting point of any subsequent curve (may coincide with the
-					current point, resulting in a circle or ellipse)
-			(x0, y0) is the center of the circle/ellipse this arc is part of
-			(x1, y1) is the end point of the first half axis vector
-			(x2, y2) is the end point of the first half axis vector (not necessarily perpendicular to the first HAV)
-
-		Bezier
-			(x, y) is the end point of the cubic bezier curve and the starting point of any subsequent curve
-			(x1, y1) is the first control point of the cubic bezier curve
-			(x1, y1) is the second control point of the cubic bezier curve
-
-		Exit
-			(dx, dy) is the tangent vector at the starting point of an adjacent subpath or (0, 0) if there is none
-	**)
-
-
 	VAR
 		Coords: ARRAY Exit+1 OF SHORTINT;	(* number of coordinate pairs for each element type *)
 
@@ -1091,7 +1088,7 @@ MODULE GfxPaths; (** portable *)	(* eos  *)
 		END
 	END EnumSpline;
 
-
+	
 	(**--- Path Queries ---**)
 
 	PROCEDURE Code (VAR data: QueryData; x, y: REAL): SET;
@@ -1402,12 +1399,6 @@ MODULE GfxPaths; (** portable *)	(* eos  *)
 		END
 	END EnumProject;
 
-	(** return projection of point onto path **)
-	PROCEDURE ProjectToPath* (path: Path; x, y: REAL; VAR u, v: REAL);
-	BEGIN
-		path.ProjectTo(x, y, u, v);
-	END ProjectToPath;
-
 BEGIN
 	Coords[Enter] := 2; Coords[Line] := 1; Coords[Arc] := 4; Coords[Bezier] := 3; Coords[Exit] := 1
 END GfxPaths.

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 153 - 808
source/AGfxRaster.Mod


+ 348 - 401
source/AGfxRegions.Mod

@@ -59,7 +59,9 @@ MODULE GfxRegions; (** portable *)	(* eos  *)
 			typically the case with AddPoint. This is why regions have a valid flag, indicating whether encoded points are sorted
 			or not. Invalidating operations only have to set valid to FALSE, other operations will eventually validate the region
 			again, at the same time eliminating multiple points and overlapping spans.
-		*)			
+		*)
+		
+		
 		Region* = OBJECT
 		VAR
 			llx*, lly*, urx*, ury*: INTEGER;	(** bounding box **)
@@ -68,258 +70,8 @@ MODULE GfxRegions; (** portable *)	(* eos  *)
 			data: RegionData;	(* points defining region boundary *)
 			points: LONGINT;	(* number of data points actually used *)
 
-			(** initialize region **)
-			PROCEDURE Init* (mode: INTEGER);
-			BEGIN
-				SELF.mode := mode;
-				SELF.Clear()
-			END Init;
 			
-			(**--- Region Queries ---**)
-
-			(** return whether region is empty **)
-			PROCEDURE Empty* (): BOOLEAN;
-			BEGIN
-				RETURN (SELF.llx >= SELF.urx) OR (SELF.lly >= SELF.ury)
-			END Empty;
-
-			(** return whether (non_empty) region is rectangular **)
-			PROCEDURE IsRect* (): BOOLEAN;
-			BEGIN
-				SELF.Validate();
-				RETURN SELF.points = 0
-			END IsRect;
-
-			(** return whether point is inside (non_empty) region **)
-			PROCEDURE PointInside* (x, y: INTEGER): BOOLEAN;
-				VAR data: RegionData; n: LONGINT; u, v, dir: INTEGER;
-			BEGIN
-				IF ~PointInRect(x, y, SELF.llx, SELF.lly, SELF.urx, SELF.ury) THEN	(* point not even within region rectangle *)
-					RETURN FALSE
-				ELSIF SELF.IsRect() THEN	(* region is rectangular *)
-					RETURN TRUE
-				END;
-
-				(* find span containing point *)
-				data := SELF.data;
-				SELF.FindLower(y, n);
-				Decode(data[n], u, v, dir);
-				WHILE u < x DO
-					INC(n);
-					Decode(data[n], u, v, dir)
-				END;
-				RETURN (u = x) & (dir = Enter) OR (u > x) & (dir = Exit)
-			END PointInside;
-
-			(** return whether (non_empty) rectangle is completely inside (non_empty) region **)
-			PROCEDURE RectInside* (llx, lly, urx, ury: INTEGER): BOOLEAN;
-				VAR data: RegionData; n: LONGINT; u, v, dir, y: INTEGER;
-			BEGIN
-				IF ~RectInRect(llx, lly, urx, ury, SELF.llx, SELF.lly, SELF.urx, SELF.ury) THEN	(* not even within bounding rectangle *)
-					RETURN FALSE
-				ELSIF SELF.IsRect() THEN	(* region is rectangular *)
-					RETURN TRUE
-				END;
-
-				data := SELF.data;
-				SELF.FindLower(lly, n);
-				Decode(data[n], u, v, dir);
-				REPEAT
-					y := v;
-					WHILE (v = y) & (u <= llx) DO
-						INC(n);
-						Decode(data[n], u, v, dir)
-					END;
-					IF (v > y) OR (u < urx) OR (dir = Enter) THEN	(* rectangle not covered by span *)
-						RETURN FALSE
-					END;
-
-					(* skip to next line *)
-					WHILE v = y DO
-						INC(n);
-						Decode(data[n], u, v, dir)
-					END
-				UNTIL v >= ury;
-
-				RETURN TRUE	(* rectangle is fully covered by spans *)
-			END RectInside;
-
-			(** return whether (non_empty) rectangle overlaps (non_empty) region **)
-			PROCEDURE RectOverlaps* (llx, lly, urx, ury: INTEGER): BOOLEAN;
-				VAR data: RegionData; n: LONGINT; u, v, dir, y: INTEGER;
-			BEGIN
-				IF ~RectsIntersect(llx, lly, urx, ury, SELF.llx, SELF.lly, SELF.urx, SELF.ury) THEN
-					RETURN FALSE	(* rect does not even intersect region rectangle *)
-				ELSIF SELF.IsRect() THEN	(* region is rectangular *)
-					RETURN TRUE
-				END;
-
-				ClipRect(llx, lly, urx, ury, SELF.llx, SELF.lly, SELF.urx, SELF.ury);
-				data := SELF.data;
-				SELF.FindLower(lly, n);
-				Decode(data[n], u, v, dir);
-				REPEAT
-					y := v;
-					WHILE (v = y) & (u <= llx) DO
-						INC(n);
-						Decode(data[n], u, v, dir)
-					END;
-					IF (v = y) & ((u < urx) OR (dir = Exit)) THEN
-						RETURN TRUE
-					END;
-
-					(* skip to next line *)
-					WHILE v = y DO
-						INC(n);
-						Decode(data[n], u, v, dir)
-					END
-				UNTIL v >= ury;
-
-				RETURN FALSE	(* rectangle does not intersect any span *)
-			END RectOverlaps;
-
-			(** return whether region is completely within another region **)
-			PROCEDURE RegionInside* (outer: Region): BOOLEAN;
-				VAR idata, odata: RegionData; in, on, is, os: LONGINT; iu, iv, idir, ou, ov, odir, iy, oy: INTEGER;
-			BEGIN
-				IF ~RectInRect(SELF.llx, SELF.lly, SELF.urx, SELF.ury, outer.llx, outer.lly, outer.urx, outer.ury) THEN
-					RETURN FALSE	(* SELF rect not even within outer rect *)
-				ELSIF outer.IsRect() THEN
-					RETURN TRUE	(* outer region fully covers SELF region *)
-				ELSIF SELF.IsRect() THEN
-					RETURN outer.RectInside(SELF.llx, SELF.lly, SELF.urx, SELF.ury)
-				END;
-
-				idata := SELF.data; odata := outer.data;
-				in := FirstSlice;
-				outer.FindLower(SELF.lly, on);
-				Decode(idata[in], iu, iv, idir);
-				Decode(odata[on], ou, ov, odir);
-				is := in; os := on;
-				REPEAT
-					iy := iv; oy := ov;
-
-					(* skip empty slices *)
-					WHILE (iv = iy) & (iu = UBound) DO
-						INC(in);
-						Decode(idata[in], iu, iv, idir)
-					END;
-
-					(* compare slices *)
-					WHILE (iv = iy) OR (ov = oy) DO
-						IF (ov > oy) OR (iv = iy) & (idir = Exit) & (odir = Enter) THEN
-							RETURN FALSE
-						END;
-						IF (iv > iy) OR (ou <= iu) THEN
-							INC(on);
-							Decode(odata[on], ou, ov, odir)
-						ELSE
-							INC(in);
-							Decode(idata[in], iu, iv, idir)
-						END
-					END;
-
-					(* reset to begin of slice if not on same line *)
-					IF iv > ov THEN
-						in := is; os := on;
-						Decode(idata[in], iu, iv, idir)
-					ELSIF ov > iv THEN
-						on := os; is := in;
-						Decode(odata[on], ou, ov, odir)
-					ELSE
-						is := in; os := on
-					END
-				UNTIL iv = SELF.ury;
-
-				RETURN TRUE	(* all spans were covered by enclosing region *)
-			END RegionInside;
-
-			(** return whether two regions intersect each other **)
-			PROCEDURE RegionOverlaps* (arg: Region): BOOLEAN;
-				VAR rdata, adata: RegionData; bot, top, ru, rv, rdir, au, av, adir, ry, ay: INTEGER; rn, an, rs, as: LONGINT;
-			BEGIN
-				IF ~RectsIntersect(SELF.llx, SELF.lly, SELF.urx, SELF.ury, arg.llx, arg.lly, arg.urx, arg.ury) THEN
-					RETURN FALSE	(* rect does not even intersect arg's bounding box *)
-				ELSIF SELF.IsRect() THEN
-					RETURN arg.RectOverlaps(SELF.llx, SELF.lly, SELF.urx, SELF.ury)
-				ELSIF arg.IsRect() THEN
-					RETURN SELF.RectOverlaps(arg.llx, arg.lly, arg.urx, arg.ury)
-				END;
-
-				rdata := SELF.data; adata := arg.data;
-				bot := MAX(SELF.lly, arg.lly);
-				top := MIN(SELF.ury, arg.ury);
-				SELF.FindLower(bot, rn);
-				arg.FindLower(bot, an);
-				Decode(rdata[rn], ru, rv, rdir);
-				Decode(adata[an], au, av, adir);
-				rs := rn; as := an;
-				REPEAT
-					ry := rv; ay := av;
-
-					(* compare slices *)
-					WHILE (rv = ry) OR (av = ay) DO
-						IF (rv = ry) & (av = ay) & (rdir = Exit) & (adir = Exit) THEN
-							RETURN TRUE
-						END;
-						IF (av > ay) OR (rv = ry) & (ru <= au) THEN
-							INC(rn);
-							Decode(rdata[rn], ru, rv, rdir)
-						ELSE
-							INC(an);
-							Decode(adata[an], au, av, adir)
-						END
-					END;
-
-					(* reset to begin of line if not on same line *)
-					IF rv > av THEN
-						rn := rs; as := an;
-						Decode(rdata[rn], ru, rv, rdir)
-					ELSIF av > rv THEN
-						an := as; rs := rn;
-						Decode(adata[an], au, av, adir)
-					ELSE
-						rs := rn; as := an
-					END
-				UNTIL (rv = top) OR (av = top);
-
-				RETURN FALSE	(* no pair of spans intersected *)
-			END RegionOverlaps;
-
-			(** enumerate region within rectangle **)
-			PROCEDURE Enumerate* (llx, lly, urx, ury: INTEGER; enum: Enumerator; VAR edata: EnumData);
-			BEGIN
-				IF RectsIntersect(SELF.llx, SELF.lly, SELF.urx, SELF.ury, llx, lly, urx, ury) THEN
-					ClipRect(llx, lly, urx, ury, SELF.llx, SELF.lly, SELF.urx, SELF.ury);
-					IF ~RectEmpty(llx, lly, urx, ury) THEN
-						IF SELF.IsRect() THEN
-							enum(llx, lly, urx, ury, edata)
-						ELSE
-							SELF.Enum(llx, lly, urx, ury, enum, edata, Enter)
-						END
-					END
-				END
-			END Enumerate;
-
-			(** enumerate parts of rectangle not within region **)
-			PROCEDURE EnumerateInv* (llx, lly, urx, ury: INTEGER; enum: Enumerator; VAR edata: EnumData);
-			BEGIN
-				IF RectsIntersect(SELF.llx, SELF.lly, SELF.urx, SELF.ury, llx, lly, urx, ury) THEN
-					IF SELF.IsRect() & RectInRect(SELF.llx, SELF.lly, SELF.urx, SELF.ury, llx, lly, urx, ury) THEN
-						IF lly < SELF.lly THEN enum(llx, lly, urx, SELF.lly, edata) END;
-						IF llx < SELF.llx THEN enum(llx, SELF.lly, SELF.llx, SELF.ury, edata) END;
-						IF urx > SELF.urx THEN enum(SELF.urx, SELF.lly, urx, SELF.ury, edata) END;
-						IF ury > SELF.ury THEN enum(llx, SELF.ury, urx, ury, edata) END
-					ELSE
-						SELF.Enum(llx, lly, urx, ury, enum, edata, Exit)
-					END
-				ELSE
-					enum(llx, lly, urx, ury, edata)
-				END
-			END EnumerateInv;
-
-
-			(**--- Region Construction ---**)
+	(**--- Region Construction ---**)
 
 			(** make region empty **)
 			PROCEDURE Clear* ();
@@ -336,6 +88,14 @@ MODULE GfxRegions; (** portable *)	(* eos  *)
 				SELF.mode := mode
 			END SetMode;
 
+			(** initialize region **)
+			PROCEDURE Init* (mode: INTEGER);
+			BEGIN
+				SELF.mode := mode;
+				(* SELF.data := NIL; *)
+				SELF.Clear()
+			END Init;
+
 			(** make region rectangular **)
 			PROCEDURE SetToRect* (llx, lly, urx, ury: INTEGER);
 			BEGIN
@@ -466,12 +226,10 @@ MODULE GfxRegions; (** portable *)	(* eos  *)
 
 			(** add rectangle to region **)
 			PROCEDURE AddRect* (llx, lly, urx, ury: INTEGER);
-				VAR rectRegion: Region; (*TODO use rect *)
-			BEGIN
-				rectRegion := NEW Region( );
-				rectRegion.Init( Winding );
-				rectRegion.SetToRect(llx, lly, urx, ury);
-				SELF.Add(rectRegion)
+				VAR reg: Region;
+			BEGIN{EXCLUSIVE}
+				reg.SetToRect(llx, lly, urx, ury);
+				SELF.Add(reg)
 			END AddRect;
 
 			(** subtract second region from first **)
@@ -535,110 +293,107 @@ MODULE GfxRegions; (** portable *)	(* eos  *)
 
 			(** subtract rectangle from region **)
 			PROCEDURE SubtractRect* (llx, lly, urx, ury: INTEGER);
-				VAR rectRegion: Region;
-			BEGIN
-				rectRegion := NEW Region( );
-				rectRegion.Init( Winding );
-				rectRegion.SetToRect(llx, lly, urx, ury);
-				SELF.Subtract(rectRegion)
+				VAR reg: Region;
+			BEGIN{EXCLUSIVE}
+				reg.SetToRect(llx, lly, urx, ury);
+				SELF.Subtract(reg)
 			END SubtractRect;
 
-			(** intersect first region with second region **)
-			PROCEDURE Intersect* (arg: Region);
-				VAR rdata, adata: RegionData; points, rn, an, rslice, aslice: LONGINT; ru, rv, rdir, au, av, adir, ry, ay, y: INTEGER;
-			BEGIN
-				IF ~RectsIntersect(SELF.llx, SELF.lly, SELF.urx, SELF.ury, arg.llx, arg.lly, arg.urx, arg.ury) THEN
-					SELF.Clear()
-
-				ELSIF ~arg.RectInside(SELF.llx, SELF.lly, SELF.urx, SELF.ury) THEN
-					SELF.Validate(); arg.Validate();
-					SELF.MakeData(); arg.MakeData();
-					rdata := SELF.data; adata := arg.data;
-					points := SELF.points;
+		(** intersect first region with second region **)
+		PROCEDURE Intersect* (arg: Region);
+			VAR rdata, adata: RegionData; points, rn, an, rslice, aslice: LONGINT; ru, rv, rdir, au, av, adir, ry, ay, y: INTEGER;
+		BEGIN
+			IF ~RectsIntersect(SELF.llx, SELF.lly, SELF.urx, SELF.ury, arg.llx, arg.lly, arg.urx, arg.ury) THEN
+				SELF.Clear()
 
-					(* cut off slices above arg *)
-					IF SELF.ury > arg.ury THEN
-						SELF.FindUpper(arg.ury, points);
-						Encode(rdata[points], UBound, arg.ury, Enter); INC(points);
-						Encode(rdata[points], UBound, arg.ury, Exit); INC(points);
-						Encode(rdata[points], UBound, Top, Exit); INC(points);
-						SELF.points := points
-					END;
+			ELSIF ~arg.RectInside(SELF.llx, SELF.lly, SELF.urx, SELF.ury) THEN
+				SELF.Validate(); arg.Validate();
+				SELF.MakeData(); arg.MakeData();
+				rdata := SELF.data; adata := arg.data;
+				points := SELF.points;
+
+				(* cut off slices above arg *)
+				IF SELF.ury > arg.ury THEN
+					SELF.FindUpper(arg.ury, points);
+					Encode(rdata[points], UBound, arg.ury, Enter); INC(points);
+					Encode(rdata[points], UBound, arg.ury, Exit); INC(points);
+					Encode(rdata[points], UBound, Top, Exit); INC(points);
+					SELF.points := points
+				END;
 
-					(* delete slices below arg *)
-					IF SELF.lly < arg.lly THEN
-						SELF.FindLower(arg.lly, rn);
-						IF rn > FirstSlice THEN
-							points := FirstSlice;
-							WHILE rn < SELF.points DO
-								rdata[points] := rdata[rn];
-								INC(points); INC(rn)
-							END;
-							SELF.points := points
+				(* delete slices below arg *)
+				IF SELF.lly < arg.lly THEN
+					SELF.FindLower(arg.lly, rn);
+					IF rn > FirstSlice THEN
+						points := FirstSlice;
+						WHILE rn < SELF.points DO
+							rdata[points] := rdata[rn];
+							INC(points); INC(rn)
 						END;
-
-						rn := FirstSlice;
-						Decode(rdata[rn], ru, rv, rdir);
-						ry := rv;
-						REPEAT
-							Encode(rdata[rn], ru, arg.lly, rdir);
-							INC(rn);
-							Decode(rdata[rn], ru, rv, rdir)
-						UNTIL rv > ry;
-
-						rn := FirstSlice; an := FirstSlice
-					ELSE
-						rn := FirstSlice;
-						arg.FindLower(SELF.lly, an)
+						SELF.points := points
 					END;
 
+					rn := FirstSlice;
 					Decode(rdata[rn], ru, rv, rdir);
-					Decode(adata[an], au, av, adir);
-					rslice := rn; aslice := an;
+					ry := rv;
+					REPEAT
+						Encode(rdata[rn], ru, arg.lly, rdir);
+						INC(rn);
+						Decode(rdata[rn], ru, rv, rdir)
+					UNTIL rv > ry;
 
-					WHILE rv < SELF.ury DO
-						(* merge intersecting slices *)
-						ry := rv; ay := av; y := MAX(ry, ay);
-						SELF.Append(LBound, y, Exit);
-						REPEAT
-							IF (av > ay) OR (rv = ry) & (ru <= au) THEN
-								IF rv # y THEN	(* do not duplicate existing points *)
-									SELF.Append(ru, y, rdir)
-								END;
-								INC(rn);
-								Decode(rdata[rn], ru, rv, rdir)
-							ELSE
-								SELF.Append(au, y, adir);
-								INC(an);
-								Decode(adata[an], au, av, adir)
-							END
-						UNTIL (rv > ry) & (av > ay);
-						SELF.Append(UBound, y, Enter);
+					rn := FirstSlice; an := FirstSlice
+				ELSE
+					rn := FirstSlice;
+					arg.FindLower(SELF.lly, an)
+				END;
 
-						(* advance to next slice *)
-						IF rv < av THEN
-							an := aslice; rslice := rn;
-							Decode(adata[an], au, av, adir)
-						ELSIF av < rv THEN
-							rn := rslice; aslice := an;
+				Decode(rdata[rn], ru, rv, rdir);
+				Decode(adata[an], au, av, adir);
+				rslice := rn; aslice := an;
+
+				WHILE rv < SELF.ury DO
+					(* merge intersecting slices *)
+					ry := rv; ay := av; y := MAX(ry, ay);
+					SELF.Append(LBound, y, Exit);
+					REPEAT
+						IF (av > ay) OR (rv = ry) & (ru <= au) THEN
+							IF rv # y THEN	(* do not duplicate existing points *)
+								SELF.Append(ru, y, rdir)
+							END;
+							INC(rn);
 							Decode(rdata[rn], ru, rv, rdir)
 						ELSE
-							rslice := rn; aslice := an
+							SELF.Append(au, y, adir);
+							INC(an);
+							Decode(adata[an], au, av, adir)
 						END
-					END;
+					UNTIL (rv > ry) & (av > ay);
+					SELF.Append(UBound, y, Enter);
+
+					(* advance to next slice *)
+					IF rv < av THEN
+						an := aslice; rslice := rn;
+						Decode(adata[an], au, av, adir)
+					ELSIF av < rv THEN
+						rn := rslice; aslice := an;
+						Decode(rdata[rn], ru, rv, rdir)
+					ELSE
+						rslice := rn; aslice := an
+					END
+				END;
 
-					SELF.Merge(points);
-					SELF.CalcRect()
-				END
-			END Intersect;
+				SELF.Merge(points);
+				SELF.CalcRect()
+			END
+		END Intersect;
 
 			(** intersect region with rectangle **)
 			PROCEDURE IntersectRect* (llx, lly, urx, ury: INTEGER);
-				VAR rectRegion: Region; (**TODO use rect *)
-			BEGIN
-				rectRegion := NEW Region( ); rectRegion.Init( Winding );
-				rectRegion.SetToRect(llx, lly, urx, ury);
-				SELF.Intersect(rectRegion)
+				VAR reg: Region;
+			BEGIN{EXCLUSIVE}
+				reg.SetToRect(llx, lly, urx, ury);
+				SELF.Intersect(reg)
 			END IntersectRect;
 
 			(** invert region **)
@@ -710,11 +465,253 @@ MODULE GfxRegions; (** portable *)	(* eos  *)
 					SELF.Append(x, y + (-dy) DIV 2, dy);	(* dy = -1 => y, dy = 1 => y - 1 *)
 					SELF.valid := FALSE
 				END
-			END AddPoint;			
+			END AddPoint;
 			
-			(*--- Auxiliary Routines For Managing Regions ---*)			
+		(**--- Region Queries ---**)
+
+			(** return whether region is empty **)
+			PROCEDURE Empty* (): BOOLEAN;
+			BEGIN
+				RETURN (SELF.llx >= SELF.urx) OR (SELF.lly >= SELF.ury)
+			END Empty;
+
+			(** return whether (non_empty) region is rectangular **)
+			PROCEDURE IsRect* (): BOOLEAN;
+			BEGIN
+				SELF.Validate();
+				RETURN SELF.points = 0
+			END IsRect;
+
+			(** return whether point is inside (non_empty) region **)
+			PROCEDURE PointInside* (x, y: INTEGER): BOOLEAN;
+				VAR data: RegionData; n: LONGINT; u, v, dir: INTEGER;
+			BEGIN
+				IF ~PointInRect(x, y, SELF.llx, SELF.lly, SELF.urx, SELF.ury) THEN	(* point not even within region rectangle *)
+					RETURN FALSE
+				ELSIF SELF.IsRect() THEN	(* region is rectangular *)
+					RETURN TRUE
+				END;
+
+				(* find span containing point *)
+				data := SELF.data;
+				SELF.FindLower(y, n);
+				Decode(data[n], u, v, dir);
+				WHILE u < x DO
+					INC(n);
+					Decode(data[n], u, v, dir)
+				END;
+				RETURN (u = x) & (dir = Enter) OR (u > x) & (dir = Exit)
+			END PointInside;
+
+			(** return whether (non_empty) rectangle is completely inside (non_empty) region **)
+			PROCEDURE RectInside* (llx, lly, urx, ury: INTEGER): BOOLEAN;
+				VAR data: RegionData; n: LONGINT; u, v, dir, y: INTEGER;
+			BEGIN
+				IF ~RectInRect(llx, lly, urx, ury, SELF.llx, SELF.lly, SELF.urx, SELF.ury) THEN	(* not even within bounding rectangle *)
+					RETURN FALSE
+				ELSIF SELF.IsRect() THEN	(* region is rectangular *)
+					RETURN TRUE
+				END;
+
+				data := SELF.data;
+				SELF.FindLower(lly, n);
+				Decode(data[n], u, v, dir);
+				REPEAT
+					y := v;
+					WHILE (v = y) & (u <= llx) DO
+						INC(n);
+						Decode(data[n], u, v, dir)
+					END;
+					IF (v > y) OR (u < urx) OR (dir = Enter) THEN	(* rectangle not covered by span *)
+						RETURN FALSE
+					END;
+
+					(* skip to next line *)
+					WHILE v = y DO
+						INC(n);
+						Decode(data[n], u, v, dir)
+					END
+				UNTIL v >= ury;
+
+				RETURN TRUE	(* rectangle is fully covered by spans *)
+			END RectInside;
+
+			(** return whether (non_empty) rectangle overlaps (non_empty) region **)
+			PROCEDURE RectOverlaps* (llx, lly, urx, ury: INTEGER): BOOLEAN;
+				VAR data: RegionData; n: LONGINT; u, v, dir, y: INTEGER;
+			BEGIN
+				IF ~RectsIntersect(llx, lly, urx, ury, SELF.llx, SELF.lly, SELF.urx, SELF.ury) THEN
+					RETURN FALSE	(* rect does not even intersect region rectangle *)
+				ELSIF SELF.IsRect() THEN	(* region is rectangular *)
+					RETURN TRUE
+				END;
+
+				ClipRect(llx, lly, urx, ury, SELF.llx, SELF.lly, SELF.urx, SELF.ury);
+				data := SELF.data;
+				SELF.FindLower(lly, n);
+				Decode(data[n], u, v, dir);
+				REPEAT
+					y := v;
+					WHILE (v = y) & (u <= llx) DO
+						INC(n);
+						Decode(data[n], u, v, dir)
+					END;
+					IF (v = y) & ((u < urx) OR (dir = Exit)) THEN
+						RETURN TRUE
+					END;
+
+					(* skip to next line *)
+					WHILE v = y DO
+						INC(n);
+						Decode(data[n], u, v, dir)
+					END
+				UNTIL v >= ury;
+
+				RETURN FALSE	(* rectangle does not intersect any span *)
+			END RectOverlaps;
+
+			(** return whether region is completely within another region **)
+			PROCEDURE RegionInside* (outer: Region): BOOLEAN;
+				VAR idata, odata: RegionData; in, on, is, os: LONGINT; iu, iv, idir, ou, ov, odir, iy, oy: INTEGER;
+			BEGIN
+				IF ~RectInRect(SELF.llx, SELF.lly, SELF.urx, SELF.ury, outer.llx, outer.lly, outer.urx, outer.ury) THEN
+					RETURN FALSE	(* SELF rect not even within outer rect *)
+				ELSIF outer.IsRect() THEN
+					RETURN TRUE	(* outer region fully covers SELF region *)
+				ELSIF SELF.IsRect() THEN
+					RETURN outer.RectInside(SELF.llx, SELF.lly, SELF.urx, SELF.ury)
+				END;
+
+				idata := SELF.data; odata := outer.data;
+				in := FirstSlice;
+				outer.FindLower(SELF.lly, on);
+				Decode(idata[in], iu, iv, idir);
+				Decode(odata[on], ou, ov, odir);
+				is := in; os := on;
+				REPEAT
+					iy := iv; oy := ov;
+
+					(* skip empty slices *)
+					WHILE (iv = iy) & (iu = UBound) DO
+						INC(in);
+						Decode(idata[in], iu, iv, idir)
+					END;
+
+					(* compare slices *)
+					WHILE (iv = iy) OR (ov = oy) DO
+						IF (ov > oy) OR (iv = iy) & (idir = Exit) & (odir = Enter) THEN
+							RETURN FALSE
+						END;
+						IF (iv > iy) OR (ou <= iu) THEN
+							INC(on);
+							Decode(odata[on], ou, ov, odir)
+						ELSE
+							INC(in);
+							Decode(idata[in], iu, iv, idir)
+						END
+					END;
+
+					(* reset to begin of slice if not on same line *)
+					IF iv > ov THEN
+						in := is; os := on;
+						Decode(idata[in], iu, iv, idir)
+					ELSIF ov > iv THEN
+						on := os; is := in;
+						Decode(odata[on], ou, ov, odir)
+					ELSE
+						is := in; os := on
+					END
+				UNTIL iv = SELF.ury;
+
+				RETURN TRUE	(* all spans were covered by enclosing region *)
+			END RegionInside;
+
+			(** return whether two regions intersect each other **)
+			PROCEDURE RegionOverlaps* (arg: Region): BOOLEAN;
+				VAR rdata, adata: RegionData; bot, top, ru, rv, rdir, au, av, adir, ry, ay: INTEGER; rn, an, rs, as: LONGINT;
+			BEGIN
+				IF ~RectsIntersect(SELF.llx, SELF.lly, SELF.urx, SELF.ury, arg.llx, arg.lly, arg.urx, arg.ury) THEN
+					RETURN FALSE	(* rect does not even intersect arg's bounding box *)
+				ELSIF SELF.IsRect() THEN
+					RETURN arg.RectOverlaps(SELF.llx, SELF.lly, SELF.urx, SELF.ury)
+				ELSIF arg.IsRect() THEN
+					RETURN SELF.RectOverlaps(arg.llx, arg.lly, arg.urx, arg.ury)
+				END;
+
+				rdata := SELF.data; adata := arg.data;
+				bot := MAX(SELF.lly, arg.lly);
+				top := MIN(SELF.ury, arg.ury);
+				SELF.FindLower(bot, rn);
+				arg.FindLower(bot, an);
+				Decode(rdata[rn], ru, rv, rdir);
+				Decode(adata[an], au, av, adir);
+				rs := rn; as := an;
+				REPEAT
+					ry := rv; ay := av;
+
+					(* compare slices *)
+					WHILE (rv = ry) OR (av = ay) DO
+						IF (rv = ry) & (av = ay) & (rdir = Exit) & (adir = Exit) THEN
+							RETURN TRUE
+						END;
+						IF (av > ay) OR (rv = ry) & (ru <= au) THEN
+							INC(rn);
+							Decode(rdata[rn], ru, rv, rdir)
+						ELSE
+							INC(an);
+							Decode(adata[an], au, av, adir)
+						END
+					END;
+
+					(* reset to begin of line if not on same line *)
+					IF rv > av THEN
+						rn := rs; as := an;
+						Decode(rdata[rn], ru, rv, rdir)
+					ELSIF av > rv THEN
+						an := as; rs := rn;
+						Decode(adata[an], au, av, adir)
+					ELSE
+						rs := rn; as := an
+					END
+				UNTIL (rv = top) OR (av = top);
+
+				RETURN FALSE	(* no pair of spans intersected *)
+			END RegionOverlaps;
+
+			(** enumerate region within rectangle **)
+			PROCEDURE Enumerate* (llx, lly, urx, ury: INTEGER; enum: Enumerator; VAR edata: EnumData);
+			BEGIN
+				IF RectsIntersect(SELF.llx, SELF.lly, SELF.urx, SELF.ury, llx, lly, urx, ury) THEN
+					ClipRect(llx, lly, urx, ury, SELF.llx, SELF.lly, SELF.urx, SELF.ury);
+					IF ~RectEmpty(llx, lly, urx, ury) THEN
+						IF SELF.IsRect() THEN
+							enum(llx, lly, urx, ury, edata)
+						ELSE
+							SELF.Enum(llx, lly, urx, ury, enum, edata, Enter)
+						END
+					END
+				END
+			END Enumerate;
+
+			(** enumerate parts of rectangle not within region **)
+			PROCEDURE EnumerateInv* (llx, lly, urx, ury: INTEGER; enum: Enumerator; VAR edata: EnumData);
+			BEGIN
+				IF RectsIntersect(SELF.llx, SELF.lly, SELF.urx, SELF.ury, llx, lly, urx, ury) THEN
+					IF SELF.IsRect() & RectInRect(SELF.llx, SELF.lly, SELF.urx, SELF.ury, llx, lly, urx, ury) THEN
+						IF lly < SELF.lly THEN enum(llx, lly, urx, SELF.lly, edata) END;
+						IF llx < SELF.llx THEN enum(llx, SELF.lly, SELF.llx, SELF.ury, edata) END;
+						IF urx > SELF.urx THEN enum(SELF.urx, SELF.lly, urx, SELF.ury, edata) END;
+						IF ury > SELF.ury THEN enum(llx, SELF.ury, urx, ury, edata) END
+					ELSE
+						SELF.Enum(llx, lly, urx, ury, enum, edata, Exit)
+					END
+				ELSE
+					enum(llx, lly, urx, ury, edata)
+				END
+			END EnumerateInv;
+	
+		(*--- Auxiliary Routines For Managing Regions ---*)			
 
-			
 			(* append point to region data *)
 			PROCEDURE Append (u, v, dir: INTEGER);
 				VAR size: LONGINT; data: RegionData;
@@ -822,7 +819,9 @@ MODULE GfxRegions; (** portable *)	(* eos  *)
 			(* merge two runs of data points *)
 			PROCEDURE Merge (split: LONGINT);
 				VAR data: RegionData; n, N, m, M, p, tmp: LONGINT; nu, nv, ndir, mu, mv, mdir, sum, u, v, inc, nsum: INTEGER;
-			BEGIN
+					Data: RegionData;	(* temporary region data for merging *)
+					DataSize: LONGINT;	(* number of points allocated for Data *)				
+			BEGIN{EXCLUSIVE}
 				data := SELF.data;
 				n := 0; N := split;
 				Decode(data[n], nu, nv, ndir);
@@ -1085,11 +1084,6 @@ MODULE GfxRegions; (** portable *)	(* eos  *)
 		EnumData* = RECORD END;
 		Enumerator* = PROCEDURE (llx, lly, urx, ury: INTEGER; VAR edata: EnumData);
 
-
-	VAR
-		Data: RegionData;	(* temporary region data for merging *)
-		DataSize: LONGINT;	(* number of points allocated for Data *)
-
 	(**--- Rectangles ---**)
 
 	(** make rectangle large enough to include a point **)
@@ -1146,35 +1140,6 @@ MODULE GfxRegions; (** portable *)	(* eos  *)
 
 	(*--- Auxiliary Routines For Managing Regions ---*)
 
-	(*
-		Implementation notes:
-
-		Regions are managed by slicing them horizontally. For each scanline y, a set of spans on the scanline defines which
-		parts of the scanline are part of the region. The spans are defined through the x_coordinates of their end points.
-		Every point on a scanline has a direction attribute, which specifies whether the point starts a span (Enter) or ends
-		one (Exit), allowing spans to nest or overlap.
-
-		The x_ and y_coordinates of a point along with its direction are encoded into a LONGINT. The chosen encoding
-		weights the y_coordinate most, followed by the x_coordinate and the direction of an intersection. Visiting all
-		encoded points in ascending order therefore traverses all spans of the region from the bottom left corner to the
-		top right corner.
-
-		In order to save space, identical slices adjacent to each other are stored only once. The bottommost scanline of
-		an identical sequence of scanlines serves as a representant for the whole sequence; all others are eliminated.
-		This means that if no points exist for a certain y_coordinate, the spans of the corresponding scanline are identical
-		to those of the one below it. As a consequence, scanlines that are completely outside the region need an empty
-		filler span to distinguish them from eliminated scanlines. A filler span consists of two points located at UBound,
-		one entering the region and the other leaving it.
-
-		Most operations modifying regions append new points in ascending order to the sequence of existing points and
-		then merge the two sequences again. If points cannot be appended in order, the whole set of points has to be
-		sorted before any other operation can be executed. Doing this immediately after the sequence of points has been
-		invalidated can decrease performance significantly if a lot of invalidating operations are issued in sequence, as is
-		typically the case with AddPoint. This is why regions have a valid flag, indicating whether encoded points are sorted
-		or not. Invalidating operations only have to set valid to FALSE, other operations will eventually validate the region
-		again, at the same time eliminating multiple points and overlapping spans.
-	*)
-
 	(* encode point coordinates and curve direction into a LONGINT *)
 	PROCEDURE Encode (VAR item: LONGINT; u, v, dir: LONGINT);
 	BEGIN
@@ -1302,7 +1267,6 @@ MODULE GfxRegions; (** portable *)	(* eos  *)
 		reg.EnumerateInv(llx, lly, urx, ury, enum, edata);
 	END EnumerateInv;
 
-
 	(**--- Region Construction ---**)
 
 	(** make region empty **)
@@ -1383,23 +1347,6 @@ MODULE GfxRegions; (** portable *)	(* eos  *)
 		reg.Invert();
 	END Invert;
 
-	(**
-		In addition to creating rectangular regions and using Boolean operations to combine several regions, a region
-		can also be built by tracing its outline with AddPoint. In order to allow the correct handling of self_intersecting
-		contours, a direction parameter is needed which indicates whether the curve is going up (dy = 1) or down
-		(dy = -1) at the given point.
-
-		When performing Boolean operations upon regions or when building regions from self_intersecting contours,
-		it is possible that some areas in the resulting region get "covered" more than once. Since most query operations
-		reduce regions to non_overlapping areas, a rule which decides whether a point is inside a region or not is needed.
-		Imagine a ray originating at such a point and counting every intersection of the ray with the boundary curve of the
-		region as +1 if the curve crosses the ray from right to left and as -1 otherwise.
-			- for mode Winding (the default), a point is inside the region if the resulting sum is non_zero
-			- for mode EvenOdd, a point is inside the region if the resulting sum is odd
-
-		Behaviour of all region queries and region operations is undefined for contours which are not closed.
-	**)
-
 	(** add a scanline intersection to a region **)
 	PROCEDURE AddPoint* (reg: Region; x, y, dy: INTEGER);
 	BEGIN

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä