<> <> <> <> <> <> <> <> DIRECTORY D2Basic USING [Number, Vector, Rect]; CStitching: CEDAR DEFINITIONS = BEGIN <<-- Types.>> Number: TYPE = D2Basic.Number; Pos: TYPE = D2Basic.Vector; Rect: TYPE = D2Basic.Rect; <<-- WARNING: Conventions are different from ChipNDale:>> <<-- In CornerStitching, lower left border is inclusive; upper right border is exclusive.>> all: Rect = [Number.FIRST, Number.FIRST, Number.LAST, Number.LAST]; Tile: TYPE = REF --READONLY-- TileRec; TileRec: TYPE = RECORD [ --all fields readonly eN, sW: Tile _ NIL, nE, wS: LONG POINTER TO TileRec _ NIL, pos: Pos, value: REF _ NIL -- NIL for space tiles ]; <<-- Tiles are recollected whenever they are not part of a tesselation! dont keep on to tiles. >> <<-- Corner stitching with ref's is too circular for the current Cedar safestorage, >> <<-- therefore two stitches are made pointers (idea of Mark Brown). >> <<-- eN... eastern-most neighbour to the North; capitalization enlightens asymetry)>> <<-- pos: lower left corner>> <<>> Tesselation: TYPE = REF TesselationRec; TesselationRec: TYPE = RECORD [ --do never use NEW state: State,--readonly, not all implementations use this field immute: PRIVATE BOOL _ FALSE, current, southEast: PRIVATE Tile _, --readonly tileCount: PRIVATE INT _ 1, --readonly stopFlag: REF BOOL, data: REF ]; <<-- Use only NewTesselation to create Tesselations (Finalization!)>> <<-- data: reserved for clients>> <<-- stopFlag: reserved for clients>> <<>> State: TYPE = RECORD [ --readonly r: Rect_all, yf: Number_LAST[Number], --fathers limitting y ys: Number_LAST[Number] --lowest sons lowest y ]; <<>> <<-- All procedures sharing a Tesselation must be synchrounized by caller; >> <<-- CStitching itself does not monitor clients (even if using the same Tesselation). >> <<-- Synchrounization errors can propagate to unrelated Tesselation!>> <<>> <<>> <<-- Worlds.>> NewTesselation: PROC [data: REF _ NIL, stopFlag: REF BOOL _ NIL] RETURNS [Tesselation]; <<-- Creates a new Tesselation>> ResetTesselation: PROC [plane: Tesselation, stopFlag: REF BOOL _ NIL]; <<-- Returns the tile memory; Tesselation is ready for fresh usage>> TrustedDisposeTesselation: PROC [plane: Tesselation]; <<-- Returns the tile memory and the Tesselation>> <<-- Caller absolutely guarantees there exists no pointer to plane anymore.>> DumpCache: PROC; <<-- Returns cached memory used globaly for Tiles of all Tesselations>> <<>> <<>> <<-- Modifying.>> ChangeRect: PROC [plane: Tesselation, rect: Rect, new: REF _ NIL]; <<-- Change the rect having new as tile value>> <<-- Beware: rect must lie completely in the changeable area (even for identity changes)>> ChangeTile: PROC [plane: Tesselation, tile: Tile, new: REF _ NIL]; <<-- Change a tile >> <<-- Beware: tile must lie completely in the changeable area (even for identity changes) >> RectProc: TYPE = PROC [plane: Tesselation, rect: Rect, oldValue: REF, data: REF]; ChangeEnumerateArea: PROC [plane: Tesselation, rect: Rect, eachRect: RectProc, data: REF _ NIL, skip: REF _]; <<-- For each rectangle in rect (with value # skip) call "eachRect"; (rect must be changeable)>> <<-- eachRect is must not change any point outside its rect area.>> <<-- Outside eachRect's rect the maximal size properties dont hold while the enumeration.>> <<>> <<-- Enumerations.>> FindTile: PROC [plane: Tesselation, pos: Pos] RETURNS [Tile]; <<-- Finds the tile which contains the point at pos>> TileProc: TYPE = PROC [tile: Tile, data: REF]; <<>> EnumerateArea: PROC [plane: Tesselation, rect: Rect, eachTile: TileProc, data: REF _ NIL, skip: REF _ NIL]; <<-- Enumerates all the tiles covering points of rect in plane. >> <<-- While the enumeration the plane must not be changed>> <<-- data: passed through to the eachTile procedure. >> <<-- skip: tiles with value skip will be ignored and not enumerated. >> <<-- To get every tile, set skip to some value not existing value (e.g. NEW[INT]). >> <<-- rect must must be changeable or the maximal size properties dont hold>> <<>> <<-- In EnumerateArea the order of enumeration is well defined. A tile appears in the enumeration immediately after the last of its children. Where tileA is defined to be a child of tileB iff its sW stitch points to tileB. Children are ordered such that the southernmost is the last. For tiles touching the western and southern borders these rules do not apply, these tiles are parent-less. Such tiles appear at some point after all the parent-less tiles touching touching a given parent-less tile's northern and western borders have been enumerated.>> Region: TYPE = RECORD [rect: Rect, value: REF]; -- value NIL for space tiles ListArea: PROC [plane: Tesselation, rect: Rect, skip: REF _ NIL] RETURNS [LIST OF REF Region]; <<-- Returns a list of regions describing the area rect in the tesselation plane.>> <<-- Regions with tile value skip are not returned.>> <<-- rect must must be changeable or the maximal size properties dont hold>> <<>> EnumerateNeighborhood: PROC [plane: Tesselation, tile: Tile, eachTile: TileProc, data: REF _ NIL, skip: REF _ NIL]; <<-- Enumerates all tiles touching the given tile. >> <<-- [The current implementation starts the enumeration in the SW corner and >> <<-- continues clockwise]>> <<-- The plane may not be modified during the enumeration. >> <<-- The data variable is passed through to eachTile. >> <<-- Tiles with value skip are skipped.>> <<>> <<>> <<-- Stepping from Tile to Tile.>> <<>> <<-- Coordinates increase from south to north, and west to east. All tile worlds are >> <<-- bordered by tiles at infinity so bounded searches wil never find NIL tiles. >> <<-- never need worry about tile = NIL. >> <<-- The tiles at infinity are not stitched to tiles in the Tesselation, rather they are >> <<-- stitched to each other in the manner of the bevelled edges of a picture frame. >> <<-- The meanings of the stepping routines are as follows ...>> <<-- EN  eastern most tile to the north>> <<-- NE  northern most tile to the east>> <<-- WS  western most tile to the south>> <<-- SW  southern most tile to the west>> EN: PROC [tile: Tile] RETURNS [Tile] = INLINE { RETURN [tile.eN] }; NE: PROC [tile: Tile] RETURNS [Tile] = INLINE { TRUSTED { RETURN [LOOPHOLE[tile.nE]] } }; WS: PROC [tile: Tile] RETURNS [Tile] = INLINE { TRUSTED { RETURN [LOOPHOLE[tile.wS]] } }; SW: PROC [tile: Tile] RETURNS [Tile] = INLINE { RETURN [tile.sW] }; <<>> <<-- Enquiries>> Area: PROC [t: Tile] RETURNS [Rect] = TRUSTED INLINE { <<--rect of tile; (upper and right border exclusive)>> RETURN [[x1: t.pos.x, y1: t.pos.y, x2: t.nE.pos.x, y2: t.eN.pos.y]] }; NEdge: PROC [t: Tile] RETURNS [Number] = INLINE {RETURN [t.eN.pos.y]}; EEdge: PROC [t: Tile] RETURNS [Number] = TRUSTED INLINE {RETURN [t.nE.pos.x]}; SEdge: PROC [t: Tile] RETURNS [Number] = INLINE {RETURN [t.pos.y]}; WEdge: PROC [t: Tile] RETURNS [Number] = INLINE {RETURN [t.pos.x]}; <<>> IsEmpty: PROC [plane: Tesselation, rect: Rect _ all, skip: REF _ NIL] RETURNS [BOOL]; <<-- Returns whether rect in plane has only tiles with value skip.>> <<-- rect must must be changeable >> BBox: PROC [plane: Tesselation, rect: Rect _ all, skip: REF _ NIL] RETURNS [bBox: Rect]; <<-- Returns a minimal bounding box for non-skip tiles in rect>> <<-- rect must must be changeable.>> <<>> END.