DIRECTORY Commander, CornerStitching, IO, Process, SafeStorage; CornerStitchingImpl: CEDAR MONITOR IMPORTS Commander, IO, Process, SafeStorage EXPORTS CornerStitching = BEGIN Tesselation: TYPE = CornerStitching.Tesselation; Tile: TYPE = CornerStitching.Tile; Number: TYPE = CornerStitching.Number; Pos: TYPE = CornerStitching.Pos; CsRect: TYPE = CornerStitching.CsRect; PerTileProc: TYPE = CornerStitching.PerTileProc; PerTileChangeProc: TYPE = CornerStitching.PerTileChangeProc; Region: TYPE = CornerStitching.Region; UseOfAlreadyDeletedTile: ERROR = CODE; NEdge: PROC [t: REF Tile] RETURNS [Number] = INLINE {RETURN [t.en.pos.y]}; EEdge: PROC [t: REF Tile] RETURNS [Number] = INLINE {RETURN [NE[t].pos.x]}; SEdge: PROC [t: REF Tile] RETURNS [Number] = INLINE {RETURN [t.pos.y]}; WEdge: PROC [t: REF Tile] RETURNS [Number] = INLINE {RETURN [t.pos.x]}; neLimit: Pos = [x: Number.LAST, y: Number.LAST]; nwLimit: Pos = [x: Number.FIRST, y: Number.LAST]; swLimit: Pos = [x: Number.FIRST, y: Number.FIRST]; seLimit: Pos = [x: Number.LAST, y: Number.FIRST]; allSpace: CsRect = [x1: Number.FIRST+1, y1: Number.FIRST, x2: Number.LAST-1, y2: Number.LAST-1]; maxSpace: CsRect = [x1: allSpace.x1+1, y1: allSpace.y1+1, x2: allSpace.x2-1, y2: allSpace.y2-1]; empty: CsRect = [x1: Number.LAST, y1: Number.LAST, x2: Number.FIRST, y2: Number.FIRST]; PrivateRec: TYPE = RECORD[notused: REF]; guard: REF = NEW[PrivateRec_[$CSGuard]]; deleted: REF = NEW[PrivateRec_[$CSDeleted]]; northLimit: REF Tile = NEW[Tile _ [pos: nwLimit, value: guard]]; northBuffer: REF Tile = NEW[Tile _ [pos: [allSpace.x1, allSpace.y2], value: guard]]; southLimit: REF Tile = NEW[Tile _ [pos: swLimit, value: guard]]; eastLimit: REF Tile = NEW[Tile _ [pos: seLimit, value: guard]]; westLimit: REF Tile = NEW[Tile _ [pos: swLimit, value: guard]]; Disguise: TYPE = RECORD [hiddenValue: REF]; disposedTiles: REF Tile _ NIL; disguiseCache: REF Disguise _ NIL; InitTesselationBorderTiles: PROC = BEGIN northLimit.ne _ RtoP[eastLimit]; eastLimit.en _ northLimit; southLimit.en _ eastLimit; southLimit.ne _ RtoP[eastLimit]; eastLimit.ws _ RtoP[southLimit]; eastLimit.sw _ southLimit; westLimit.ne _ RtoP[northLimit]; westLimit.en _ northLimit; northLimit.sw _ westLimit; northLimit.ws _ RtoP[westLimit]; southLimit.sw _ westLimit; westLimit.ws _ RtoP[southLimit]; northBuffer.en _ northLimit; northBuffer.ne _ RtoP[eastLimit]; northBuffer.sw _ westLimit; northBuffer.ws _ NIL; END; DumpCache: PUBLIC ENTRY PROC = BEGIN ENABLE UNWIND => NULL; IF disposedTiles#NIL THEN { lag: REF Tile _ disposedTiles; FOR tc: REF Tile _ disposedTiles.en, tc.en WHILE tc#NIL DO lag.en _ NIL; lag _ tc ENDLOOP; disposedTiles _ NIL }; IF disguiseCache#NIL THEN { lag: REF Disguise _ disguiseCache; FOR dc: REF Disguise _ NARROW[disguiseCache.hiddenValue], NARROW[dc.hiddenValue] WHILE dc # NIL DO lag.hiddenValue _ NIL; lag _ dc ENDLOOP; disguiseCache _ NIL }; END; NewTile: ENTRY PROC RETURNS [tile: REF Tile] = BEGIN ENABLE UNWIND => NULL; tile _ InternalNewTile[]; END; InternalNewTile: INTERNAL PROC RETURNS [tile: REF Tile] = INLINE BEGIN IF disposedTiles#NIL THEN { tile _ disposedTiles; disposedTiles _ disposedTiles.en; } ELSE tile _ NEW[Tile]; END; DisposeTile: ENTRY PROC [tile: REF Tile] = BEGIN ENABLE UNWIND => NULL; tile.sw _ NIL; -- Prevent potential circular chains in the disposed cache. tile.ne _ tile.ws _ NIL; tile.value _ deleted; tile.en _ disposedTiles; disposedTiles _ tile; END; NewDisguise: ENTRY PROC [hiddenValue: REF_NIL] RETURNS [disguise: REF Disguise] = BEGIN ENABLE UNWIND => NULL; IF disguiseCache#NIL THEN { disguise _ disguiseCache; disguiseCache _ NARROW[disguiseCache.hiddenValue]; } ELSE disguise _ NEW[Disguise]; disguise.hiddenValue _ hiddenValue; END; DisposeDisguise: ENTRY PROC [disguise: REF Disguise] = BEGIN ENABLE UNWIND => NULL; disguise.hiddenValue _ disguiseCache; disguiseCache _ disguise; END; Setup: INTERNAL PROC [plane: REF Tesselation] = BEGIN eastSpace: REF Tile = InternalNewTile[]; centreSpace: REF Tile = InternalNewTile[]; eastSpace^ _ [ en: northBuffer, ne: RtoP[eastLimit], sw: centreSpace, ws: RtoP[southLimit], pos: [allSpace.x2, allSpace.y1], value: guard ]; centreSpace^ _ [ en: northBuffer, ne: RtoP[eastSpace], sw: westLimit, ws: RtoP[southLimit], pos: [allSpace.x1, allSpace.y1], value: NIL ]; plane^ _ [southEast: eastSpace, current: centreSpace, data: NIL, stopFlag: plane.stopFlag, tilesInTesselationCount: 1]; IF plane.stopFlag=NIL THEN plane.stopFlag _ NEW[BOOL_FALSE]; END; NewTesselation: PUBLIC ENTRY PROC [data: REF_NIL, stopFlag: REF BOOL_NIL] RETURNS [plane: REF Tesselation] = BEGIN plane _ NEW[CornerStitching.Tesselation_[NIL, NIL, 1, stopFlag, data]]; Setup[plane]; SafeStorage.EnableFinalization[plane]; END; FreeTesselation: PUBLIC PROC [plane: REF Tesselation, freeCache: BOOL] = BEGIN CacheTileList: PROC [header: REF Tile] = { WHILE header#NIL DO t: REF Tile _ header; header _ header.en; DisposeTile[t]; ENDLOOP; }; CacheIt: PerTileProc = { tile.value _ deleted; tile.en _ header; header _ tile; }; MySetup: ENTRY PROC [plane: REF Tesselation] = { Setup[plane]; }; header: REF Tile _ NIL; IF plane#NIL THEN { EnumerateArea[plane, maxSpace, CacheIt, NIL, deleted]; CacheTileList[header]; MySetup[plane]; }; IF freeCache THEN DumpCache[]; END; EWCompatible: PROC [a, b: REF Tile] RETURNS [BOOL] = INLINE { RETURN [a.value=b.value AND a.pos.x=b.pos.x AND NE[a].pos.x=NE[b].pos.x] }; ChangeRect: PUBLIC PROC [plane: REF Tesselation, rect: CsRect, newValue: REF ANY _ NIL] = BEGIN SplitEWRunning: PROC [rider: REF Tile, splitY, endX: Number] = BEGIN WHILE WEdge[rider]splitY DO rider _ WS[rider] ENDLOOP; --won't go left nor right! (Ib) IF SEdge[rider]=rect.x2 OR rect.y1>=rect.y2 THEN RETURN; tile _ FindTile[plane.current, rect.x1, rect.y2]; plane.current _ tile; SplitEWRunning[tile, rect.y2, rect.x2]; --north border SplitEWRunning[FindTile[plane.current, rect.x1, rect.y1], rect.y1, rect.x2]; --south border tile _ FindTile[plane.current, rect.x1, rect.y2-1]; DO IF tile.value#newValue AND WEdge[tile]rect.x2 THEN { right: REF Tile _ EWSplit[plane, tile, rect.x2].east; IF EWCompatible[right, right.en] THEN right _ NSMerge[plane, right, right.en]; IF EWCompatible[right, WS[right]] THEN right _ NSMerge[plane, WS[right], right]; }; tile _ MyChangeTile[plane, tile, newValue]; --returns northernmost tile if changed }; IF EEdge[tile]>=rect.x2 THEN EXIT; tile _ NE[tile]; WHILE SEdge[tile]>=rect.y2 DO tile _ WS[tile] ENDLOOP; -- EMM ENDLOOP; IF WEdge[tile]>rect.x1 THEN ERROR; IF SEdge[tile]<=rect.y1 THEN EXIT; tile _ Below[tile, rect.x1]; ENDLOOP END; FuncChangeRect: PUBLIC PROC [plane: REF Tesselation, rect: CsRect, perTile: PerTileChangeProc, data: REF _ NIL] = BEGIN DisguiseTile: PerTileProc = BEGIN tile.value _ NewDisguise[tile.value]; END; ApplyFuncToTile: PerTileProc = BEGIN disguise: REF Disguise = NARROW[tile.value]; clippedBB: CsRect = [ MAX[WEdge[tile], rect.x1], MAX[SEdge[tile], rect.y1], MIN[EEdge[tile], rect.x2], MIN[NEdge[tile], rect.y2] ]; -- Clip tile against Enumeration's bounding box [] _ MyChangeTile[plane, tile, disguise.hiddenValue]; perTile[plane: plane, rect: clippedBB, oldValue: disguise.hiddenValue, data: data]; DisposeDisguise[disguise]; END; EnumerateArea[plane, rect, DisguiseTile, NIL, deleted]; EnumerateArea[plane, rect, ApplyFuncToTile, data, deleted]; END; ChangeTile: PUBLIC PROC [plane: REF Tesselation, tile: REF Tile, newValue: REF _ NIL] = TRUSTED BEGIN IF tile.value#newValue THEN [] _ MyChangeTile[plane, tile, newValue] END; MyChangeTile: PROC [plane: REF Tesselation, tile: REF Tile, new: REF] RETURNS [REF Tile] = BEGIN n: Number = NEdge[tile]; e: Number = EEdge[tile]; s: Number = SEdge[tile]; w: Number = WEdge[tile]; tWest, tEast, tNorth: REF Tile; IF tile.value=new THEN RETURN [tile]; tile.value _ new; tEast _ NE[tile]; IF tEast.value=new AND NEdge[tEast]>n THEN [] _ NSSplit[plane, tEast, n]; tWest _ tile.en; --east now but west soon WHILE WEdge[tWest]>=w DO tWest _ tWest.sw ENDLOOP; IF tWest.value=new AND SEdge[tWest]s THEN [] _ NSSplit[plane, tEast, s]; tWest _ tile.sw; WHILE NEdge[tWest]s DO tile _ tEast.sw; IF (tEast.value=new OR WS[tEast].value=new) AND SEdge[tile]n THEN EXIT ENDLOOP; IF EWCompatible[tile, tNorth] THEN [] _ NSMerge[plane, tile, tNorth]; RETURN [tile] END; AreaEmpty: PUBLIC PROC [plane: REF Tesselation, rect: CsRect, skipValue: REF ANY _ NIL] RETURNS [BOOL] = BEGIN rect.x1 _ MAX[maxSpace.x1, rect.x1]; rect.x2 _ MIN[maxSpace.x2, rect.x2]; rect.y1 _ MAX[maxSpace.y1, rect.y1]; rect.y2 _ MIN[maxSpace.y2, rect.y2]; IF rect.x1>rect.x2 OR rect.y1>rect.y2 THEN RETURN [TRUE]; plane.current _ FindTile[plane.current, rect.x1, rect.y1]; FOR tile: REF Tile _ plane.current, Above[tile, rect.x1] WHILE SEdge[tile]rect.x2 OR rect.y1>rect.y2 THEN RETURN [empty]; plane.current _ FindTile[plane.current, rect.x1, rect.y1]; FOR tile _ plane.current, Above[tile, rect.x1] DO IF SEdge[tile]>=rect.y2 THEN RETURN; -- plane is empty IF tile.value#skipValue OR EEdge[tile]rect.x1 THEN { bBox.x2 _ MAX[bBox.x2, WEdge[tile]]; bBox.y2 _ NEdge[tile] }; tile _ Above[tile, rect.x2-1]; ENDLOOP; END; EnumerateArea: PUBLIC PROC [plane: REF Tesselation, rect: CsRect, perTile: PerTileProc, data: REF _ NIL, skipValue: REF] = BEGIN IsChild: PROC [me: REF Tile, you: REF Tile] RETURNS [BOOL] = INLINE { RETURN [you.sw=me AND you.pos.y>rect.y1]; }; IsBrother: PROC [me: REF Tile, you: REF Tile] RETURNS [BOOL] = INLINE { RETURN [me.sw=you.sw AND you.pos.y>rect.y1]; }; tile: REF Tile; visit: REF Tile; doneSouthEastTile: BOOL _ FALSE; rect.x1 _ MAX[maxSpace.x1, rect.x1]; rect.x2 _ MIN[maxSpace.x2, rect.x2]; rect.y1 _ MAX[maxSpace.y1, rect.y1]; rect.y2 _ MIN[maxSpace.y2, rect.y2]; IF rect.x1>=rect.x2 OR rect.y1>=rect.y2 THEN RETURN; tile _ FindTile[plane.current, rect.x1, rect.y2]; IF SEdge[tile]=rect.y2 AND SEdge[tile]>rect.y1 THEN tile _ Below[tile, rect.x1]; plane.current _ tile; WHILE ~doneSouthEastTile DO seeking: {youth, experience, nothing} _ youth; --of tile DO IF seeking=youth THEN { child: REF Tile _ NE[tile]; WHILE SEdge[child]>=rect.y2 DO child _ WS[child] ENDLOOP; IF IsChild[tile, child] AND WEdge[child]rect.y1 THEN tile _ Below[tile, rect.x1] ELSE { IF EEdge[tile]>=rect.x2 THEN doneSouthEastTile _ TRUE ELSE { tile _ NE[tile]; WHILE SEdge[tile]>rect.y1 DO tile _ WS[tile] ENDLOOP; } } } ELSE { IF IsBrother[tile, WS[tile]] THEN { tile _ WS[tile]; --brother seeking _ youth } ELSE tile _ tile.sw; --father! }; IF visit.value#skipValue THEN perTile[visit, data]; --must not fool tile IF seeking=nothing THEN EXIT ENDLOOP ENDLOOP; END; ListArea: PUBLIC PROC [plane: REF Tesselation, rect: CsRect, skipValue: REF _ NIL] RETURNS [rl: LIST OF REF Region_NIL] = BEGIN PerTile: PerTileProc = { rl _ CONS[NEW[ Region _ [ [ MAX[WEdge[tile], rect.x1], MAX[SEdge[tile], rect.y1], MIN[EEdge[tile], rect.x2], MIN[NEdge[tile], rect.y2] ], tile.value ]], rl]; }; EnumerateArea[plane, rect, PerTile, NIL, skipValue]; END; Below: PROC [tile: REF Tile, x: Number] RETURNS [t: REF Tile] = INLINE BEGIN t _ WS[tile]; WHILE NE[t].pos.x<=x DO t _ NE[t] ENDLOOP; END; Above: PROC [tile: REF Tile, x: Number] RETURNS [t: REF Tile] = INLINE BEGIN t _ tile.en; WHILE t.pos.x>x DO t _ t.sw ENDLOOP; END; TileAt: PUBLIC PROC [plane: REF Tesselation, pos: Pos] RETURNS [tile: REF Tile] = BEGIN pos.x _ MIN[maxSpace.x2, pos.x]; pos.y _ MIN[maxSpace.y2, pos.y]; tile _ FindTile[current: plane.current, x: pos.x, y: pos.y]; IF tile.value=guard THEN ERROR; plane.current _ tile; END; FindTile: PROC [current: REF Tile, x, y: Number] RETURNS [REF Tile] = TRUSTED BEGIN IF current.value=deleted THEN ERROR UseOfAlreadyDeletedTile; DO --south-- WHILE y=current.en.pos.y DO current _ current.en ENDLOOP; IF x=current.ne.pos.x THEN --east-- WHILE x>=current.ne.pos.x DO current _ LOOPHOLE[current.ne] ENDLOOP ELSE EXIT ENDLOOP; RETURN [current] END; EWSplit: PROC [plane: REF Tesselation, tile: REF Tile, x: Number] RETURNS [east: REF Tile] = BEGIN t: REF Tile; east _ NewTile[]; IF WEdge[tile]>=x OR EEdge[tile]<= x THEN ERROR; east^ _ tile^; plane.tilesInTesselationCount _ plane.tilesInTesselationCount + 1; tile.ne _ RtoP[east]; east.sw _ tile; east.pos.x _ x; t _ east.en; WHILE t.pos.x>=x DO t.ws _ RtoP[east]; t _ t.sw ENDLOOP; tile.en _ t; t _ NE[east]; WHILE t.sw=tile DO t.sw _ east; t _ WS[t] ENDLOOP; t _ Below[tile, x]; east.ws _ RtoP[t]; WHILE t.en=tile DO t.en _ east; t _ NE[t] ENDLOOP; RETURN [east] END; NSSplit: PROC [plane: REF Tesselation, tile: REF Tile, y: Number] RETURNS [north: REF Tile] = BEGIN t: REF Tile; north _ NewTile[]; IF SEdge[tile]>=y OR NEdge[tile]<=y THEN ERROR; north^ _ tile^; plane.tilesInTesselationCount _ plane.tilesInTesselationCount + 1; tile.en _ north; north.ws _ RtoP[tile]; north.pos.y _ y; t _ NE[north]; WHILE t.pos.y>=y DO t.sw _ north; t _ WS[t] ENDLOOP; tile.ne _ RtoP[t]; t _ north.en; WHILE t.ws=RtoP[tile] DO t.ws _ RtoP[north]; t _ t.sw ENDLOOP; t _ tile.sw; WHILE t.en.pos.y<=y DO t _ t.en ENDLOOP; north.sw _ t; WHILE NE[t]=tile DO t.ne _ RtoP[north]; t _ t.en ENDLOOP; RETURN [north] END; EWMerge: PROC [plane: REF Tesselation, tileW, tileE: REF Tile] RETURNS [REF Tile] = BEGIN IF tileE.sw#tileW OR NE[tileW]#tileE OR tileW.pos.y#tileE.pos.y OR tileW.en.pos.y#tileE.en.pos.y OR tileW.value#tileE.value THEN ERROR; tileW.en _ tileE.en; tileW.ne _ tileE.ne; FOR t: REF Tile _ tileW.en, t.sw WHILE WS[t]=tileE DO t.ws _ RtoP[tileW] ENDLOOP; FOR t: REF Tile _ NE[tileW], WS[t] WHILE t.sw=tileE DO t.sw _ tileW ENDLOOP; FOR t: REF Tile _ WS[tileE], NE[t] WHILE t.en=tileE DO t.en _ tileW ENDLOOP; IF plane.current=tileE THEN plane.current _ tileW; DisposeTile[tileE]; plane.tilesInTesselationCount _ plane.tilesInTesselationCount - 1; RETURN [tileW]; END; NSMerge: PROC [plane: REF Tesselation, tileS, tileN: REF Tile] RETURNS [REF Tile] = BEGIN IF WS[tileN]#tileS OR tileS.en#tileN OR tileS.pos.x#tileN.pos.x OR NE[tileS].pos.x#NE[tileN].pos.x OR tileS.value#tileN.value THEN ERROR; tileS.ne _ tileN.ne; tileS.en _ tileN.en; FOR t: REF Tile _ NE[tileS], WS[t] WHILE t.sw=tileN DO t.sw _ tileS ENDLOOP; FOR t: REF Tile _ tileS.en, t.sw WHILE WS[t]=tileN DO t.ws _ RtoP[tileS] ENDLOOP; FOR t: REF Tile _ tileN.sw, t.en WHILE NE[t]=tileN DO t.ne _ RtoP[tileS] ENDLOOP; IF plane.current=tileN THEN plane.current _ tileS; DisposeTile[tileN]; plane.tilesInTesselationCount _ plane.tilesInTesselationCount - 1; RETURN [tileS]; END; WS: PROC [t: REF Tile] RETURNS [REF Tile] = INLINE { TRUSTED { RETURN [LOOPHOLE[t.ws]] } }; NE: PROC [t: REF Tile] RETURNS [REF Tile] = INLINE { TRUSTED { RETURN [LOOPHOLE[t.ne]] } }; RtoP: PROC [r: REF Tile] RETURNS [LONG POINTER TO Tile] ~ INLINE { TRUSTED { RETURN [LOOPHOLE[r]] } }; Load: Commander.CommandProc = { cmd.out.PutRope["CornerStiching loaded\n"]; }; FinalizeTesselation: ENTRY PROC [plane: REF CornerStitching.Tesselation] = BEGIN ENABLE UNWIND => NULL; InternalDispose: PerTileProc = BEGIN tile.value _ deleted; tile.en _ header; header _ tile; END; header: REF Tile _ NIL; IF plane.current#NIL THEN EnumerateArea[plane, maxSpace, InternalDispose, NIL, deleted]; plane.current _ plane.southEast _ NIL; plane.data _ NIL; WHILE header#NIL DO t: REF Tile _ header; header _ header.en; t.sw _ t.en _ NIL; t.ne _ t.ws _ NIL; ENDLOOP; END; FinalizerProcess: PROC[fooFQ: SafeStorage.FinalizationQueue] = BEGIN DO foo: REF CornerStitching.Tesselation = NARROW[SafeStorage.FQNext[fooFQ]]; FinalizeTesselation[foo]; ENDLOOP END; fooFQ: SafeStorage.FinalizationQueue = SafeStorage.NewFQ[]; SafeStorage.EstablishFinalization[CODE[CornerStitching.Tesselation], 0, fooFQ]; TRUSTED {Process.Detach[FORK FinalizerProcess[fooFQ]]}; InitTesselationBorderTiles[]; Commander.Register[key: "CornerStiching", proc: Load, doc: "loads the CornerStiching"]; END. CornerStitchingImpl.mesa Copyright c 1983, 1986 by Xerox Corporation. All rights reserved. Written by Shand, September 12, 1983 11:40 pm PDT Last Edited by: McCreight, November 28, 1983 5:53 pm Last Edited by: Jacobi, February 23, 1984 3:59 pm Last Edited by: Shand, August 6, 1984 4:16:51 am PDT Last Edited by: Jacobi, January 24, 1986 6:01:21 pm PST Last Edited by: Beretta, February 13, 1985 11:46:26 am PST -- Co-ordinates at "infinity" -- House-keeping tile values to flag deleted tiles and tiles at "infinity" -- Border Tiles (shared by all tesselations) -- The stitching is not quite kosher at Guard corners. -- Think of the guard tile as having bevelled ends -- which fit together like a picture-frame and are stitched accordingly. -- North-East -- South-East -- North-West -- South-West -- northBuffer --caller must check that it is not a current tile --and cache the tile, this is faster than going through the garbage collector --This is to help the Garbage Collector (by NILing all REFs). -- Depends on fact that Enumeration proceeds NE to SW, -- so en ref may be clobbered by caching process. --test whether tiles have same west border, same east border and same value --split tiles, starting with rider, going eastwards --rider must intersect splitY horizontal line --splitY will belong to the north tiles --endX is first point not to be split --knows value to be inserted and might not split the last tile if already right value. ugh --Invariants --Ia (tiles to the left of rider are handled) --Ib (while SEdge[rider]>splitY rider _ WS[rider] wouldnt change rider's left x coordinate) --at beginning Ia and Ib true because of parameters --go east --Ia and Ib --go south until split line is hit --Ia and Ib and (rider touches or intersects split line) --split --this second test prevents splitting tiles outside area of interest which might have to be remerged later (but ChangeRect wont do it, laying outside) --I rider touches or intersects split line --I rider touches or intersects split line -- tile containing nw corner (right north of area of interest) -- change values. --I all northern tiles are already handled -- split out left part of tile if necessary. -- make sure we keep outside tile in order NS-wise. -- right border --I tile has value --I tile.s <=rect.y2 --I tile touches east border and all northern tiles are already handled --set tile back up and left; remember, the northern tiles are merged already -- restore tile value -- call user perTile function --FuncChangeRect -- returns the northernmost tile intersecting the changed region. -- (there is exactly one such tile! maximal-EW-property) -- restore maximal East-West strip property -- split up tiles that horizontally abut any of the tile's four corners, -- but extend beyond the corner in a North-South direction --northeast corner --northwest corner -- the tile with EEdge >= w but WEdge < w. -- In fact SEdge[tWest] < n holds only if EEdge = w --southwest corner --southeast corner -- analogous to split of northwest corner. -- convert the West and East adjacent tiles to maximal East-West strips -- run South to North along the West edge -- splitting North-South, merging East-West -- tile is the northernmost strip in the changed area. -- now any maximal-EW-property violations of tile are confined to its Eastern border. -- however, some merges at the northern and southern borders may be pending. -- run North to South along the East edge splitting North-South any tile to -- the East which abuts more than one new tile in the changed area. --I SEdge[tEast]<=s -- run South to North along the East edge -- splitting North-South, merging East-West; eventually merging North-South.. -- Relies on the Maximal East-West strip property. -- relies on the Maximal East-West strip property. --find south west corner -- else the east edge of tile must abut a non-skipValue tile (Maximal East-West) --find north east corner by going up starting at the south east corner -- Uses the tiles own links to maintain an implicit stack of tiles. -- Enumeration proceeds in a manner which ensures that a tiles ne and en -- pointers will never be needed once that tile has appeared in the enumeration; -- this fact is exploited in FreeTesselation. -- Defn: b is a's child iff b.sw = a. -- correct for one off error when rect.y2 lies at tile boundary (YUK) --a tile is visited only after all its children --if child is a child of tile then it is southernmost one --NOT seeking youth! -- Is tile a border tile? -- Find next border tile, i.e. next tree root -- assumes x is within tile (i.e. WEdge[tile] <= x & EEdge[tile] > x) -- assumes x is within tile (i.e. WEdge[tile] <= x & EEdge[tile] > x) --a-symmetric -- the East tile will be the new one. -- x is west point in new east tile. -- east starts out a replica of tile -- Fix the tiles relative to each other. -- Fix North boundary -- Fix East boundary -- Fix South boundary -- the North tile will be the new one. -- y is south point of new north tile -- north starts out a replica of tile -- Fix the tiles relative to each other. -- Fix East boundary -- Fix North boundary -- Fix West boundary -- The East tile will be deallocated. -- The caller must assure that tileW.value=tileE.value and that the tiles really -- do have a common border of equal length. --checks -- Fix the tiles relative to each other. -- Fix North boundary -- Fix East boundary -- Fix South boundary -- the north tile will be deallocated. -- the caller must assure that tileS.value=tileN.value and that the tiles really -- do have a common border of equal length. --checks -- Fix the tiles relative to each other. -- Fix East boundary -- Fix North boundary -- Fix West boundary -- Depends on fact that Enumeration proceeds NE to SW, -- so en ref may be clobbered by caching process. Edited on February 8, 1985 4:40:46 pm PST, by Jacobi Formatting FindTile completely rewritten Edited on September 30, 1985 1:43:22 pm PDT, by Jacobi Correct comments when which procedure is valid included in definition EnumerateArea and ListArea made two procedures whith simpler parameters Edited on December 12, 1985 6:28:29 pm PST, by Jacobi maxSpace introduced, Edited on January 14, 1986 7:07:36 pm PST, by Jacobi finalization introduced Edited on January 17, 1986 4:06:17 pm PST, by Jacobi comments, invariants, shorter, bug correction in ChangeTile, Below, WS, NE introduced Κ_˜code™Kšœ Οmœ7™BKšœ1™1K™4K™1K™4K™7K™:K˜—šΟk ˜ Kšœžœžœ ˜5—K˜šΠblœžœž˜"Kšžœ žœžœ ˜,Kšžœ˜—Kšž˜K˜Kšœ žœ˜0Kšœžœ˜"Kšœžœ˜&Kšœžœ˜ Kšœžœ˜&Kšœ žœ˜0Kšœžœ%˜Kšœ˜Kšœ(‘˜6KšœL‘˜\Kšœ™Kšœ3˜3šž˜K™*Kšœ,™,šžœžœžœ˜5Kšœžœ˜Kšœ*˜*Kšœ˜K™3Kšžœžœ&˜IKšžœžœžœžœ˜KK˜—šžœ‘A˜Dšžœžœ˜Kšœ™šžœžœ˜Kšœžœ+˜5Kšžœžœ)˜NKšžœžœ žœžœ˜PK˜—Kšœ,‘&˜RK˜K™—Kšžœžœžœ˜"Kšœžœ˜Kš žœžœžœžœ‘˜=Kšœ™Kšžœ˜—KšœG™GKšžœžœžœ˜"Kšžœžœžœ˜"KšœM™MKšœ˜Kšž˜—Kšžœ˜—K˜K˜š  œžœžœ žœ>žœžœ˜qKšž˜K–H -- [tile: CornerStitching.TilePtr, data: REF ANY] RETURNS [REF ANY] -- ˜š’ œ˜Kšž˜Kšœ%˜%Kšžœ˜—K–H -- [tile: CornerStitching.TilePtr, data: REF ANY] RETURNS [REF ANY] -- ˜š’œ˜Kšž˜Kšœ žœ žœ ˜,šœ˜Kšžœ˜Kšžœ˜Kšžœ˜Kšžœ˜Kšœ‘/˜2—K™Kšœ5˜5K™KšœS˜SKšœ˜Kšžœ˜—K™Kšœ™Kšœ)žœ ˜7Kšœ;˜;Kšžœ˜—K˜š  œžœžœ žœžœžœžœ˜WKšžœž˜ Kšžœžœ)˜DKšžœ˜—K˜š  œžœ žœžœ žœžœžœ˜ZK™CK™8Kšž˜K˜K˜K˜K˜Kšœžœ˜Kšžœžœžœ˜%Kšœ˜Kšœ+™+K™Kš’I™IKšœ:™:K™Kšœžœ˜Kšžœžœžœ˜IK™Kšœ‘˜)Kšžœžœžœ˜2Kšœ,™,Kšœ3™3Kšžœžœžœ˜IK™Kšœ˜Kšžœžœžœ˜IK™Kšœžœ˜Kšžœžœ žœžœ˜3K™*Kšžœžœžœ˜IK™Kš’G™GKšœ*™*Kšœ,™,K˜šžœž˜Kšžœžœžœ˜?šžœ˜Kšœ*˜*Kšžœžœžœ ˜>K˜K˜—Kšžœ˜—Kšœ6™6Kšžœžœ$˜;KšœW™WKšœL™LK™KšœL™LKšœC™CKšœžœ˜šžœž˜K˜š žœžœžœžœž˜MKšœ(˜(—Kšœžœ˜Kšžœ˜—Kšœ™K™Kšœ*™*KšœM™MKšœ‘˜$Kšžœžœžœ˜5šž˜Kšœ‘˜%Kšœ‘ ˜2šžœžœžœ˜Kšžœžœžœ˜EKšœžœ˜%K˜—Kšžœžœžœžœ˜KKšžœžœž˜Kšžœ˜—K˜Kšžœžœ"˜EKšžœ˜ Kšžœ˜—K˜š  œžœžœ žœ'žœžœžœžœžœ˜hKšœ2™2Kšž˜Kšœ žœ˜$Kšœ žœ˜$Kšœ žœ˜$Kšœ žœ˜$Kš žœžœžœžœžœ˜9Kšœ:˜:šžœžœ,žœž˜UKš žœžœžœžœžœ˜BKšžœ˜—Kšžœžœ˜ Kšžœ˜—K˜š  œžœžœ žœ'žœžœžœžœ˜|Kšœ2™2Kšž˜Kšœžœ˜Kšœ žœ˜$Kšœ žœ˜$Kšœ žœ˜$Kšœ žœ˜$Kšžœžœžœžœ ˜:Kšœ™Kšœ:˜:šžœ,ž˜1Kšžœžœžœ‘˜7Kšžœžœžœž˜8Kšžœ˜—Kšœ žœ˜$šžœž˜Kšžœžœžœ˜7KšœP™PKšžœžœžœ˜JKšœ˜Kšžœ˜—KšœF™FKšœ3˜3šžœž˜šžœžœ˜Kšœ˜Kšœ˜K˜—šžœžœžœ˜"Kšœ žœ˜$Kšœ˜K˜—Kšœ˜Kšžœ˜—Kšžœ˜—K˜š  œžœžœ žœ8žœžœ žœ˜zKšœE™EKšœI™IKšœQ™QKšœ-™-Kšœ%™%Kšž˜K˜š œžœžœ žœžœžœžœ˜EKšžœ žœ˜)K˜—K˜š  œžœžœ žœžœžœžœ˜GKšžœžœ˜,K˜—K˜Kšœžœ˜Kšœžœ˜Kšœžœžœ˜ Kšœ žœ˜$Kšœ žœ˜$Kšœ žœ˜$Kšœ žœ˜$Kšžœžœžœžœ˜4Kšœ1˜1K™EKšžœžœžœ˜PKšœ˜K™/šžœž˜Kšœ0‘ ˜9šž˜šžœžœ˜Kšœžœžœ˜Kšžœžœ žœžœ˜9Kšœ9™9šžœžœžœ˜7Kšœ ˜ Kšž˜K˜—Kšžœ‘ ˜:K˜—Kšœ™Kšœ ˜ K™šžœžœžœ˜6K™-K˜Kšžœžœ˜7šžœ˜Kšžœžœž˜5šžœ˜Kšœžœ˜Kšžœžœžœžœ˜5K˜—K˜—K˜—šžœ˜šžœžœžœ˜#Kšœžœ‘ ˜K˜K˜—Kšžœ‘ ˜K˜—Kšžœžœ‘˜HKšžœžœž˜Kšž˜—Kšžœ˜—Kšžœ˜—K˜š œžœžœ žœ'žœžœžœžœžœžœžœ˜yKšž˜š’œ˜šœžœžœ ˜šœ˜Kšžœ˜Kšžœ˜Kšžœ˜Kšžœ˜Kšœ˜—Kšœ ˜ Kšœ˜—Kšœ˜—Kšœ$žœ ˜4Kšžœ˜K˜—š  œžœžœžœžœ ž˜FKšœE™EKšž˜Kšœžœ˜ Kš žœžœ žœžœžœ˜*Kšžœ˜—K˜š  œžœžœžœžœ ž˜FKšœE™EKšž˜K˜ Kšžœ žœ žœ˜$Kšžœ˜—K˜š  œžœžœ žœžœžœ˜QKšž˜Kšœžœ˜ Kšœžœ˜ Kšœ<˜K™Kšœ ˜ Kšžœžœ žœ˜(Kšœ ˜ Kšžœžœ žœžœ˜9Kšžœ˜Kšžœ˜—K˜š  œžœ žœžœžœžœ˜SK™%KšœP™PK™+Kšž˜Kšœ™Kšžœžœžœžœžœžœžœžœ˜‡K™(Kšœ˜Kšœ˜K™Kš žœžœžœžœ žœžœ˜QK™Kšžœžœžœ žœžœ žœ žœ˜LK™Kšžœžœžœ žœžœ žœ žœ˜LKšžœžœ˜2Kšœ˜KšœB˜BKšžœ ˜Kšžœ˜—K˜š  œžœ žœžœžœžœ ˜TK™&KšœP™PK™+Kšž˜Kšœ™Kšžœžœžœžœžœžœžœžœžœžœ˜‰K™(Kšœ˜K˜K™Kšžœžœžœ žœžœ žœ žœ˜LK™Kš žœžœžœžœ žœžœ˜QK™Kš žœžœžœžœ žœžœ˜QKšžœžœ˜2K˜KšœB˜BKšžœ ˜Kšžœ˜—K˜š Πbkœžœžœžœžœ žœ˜4Kšžœžœžœ ˜#K˜K˜—š £œžœžœžœžœ žœ˜4Kšžœžœžœ ˜#K˜K˜—š œžœžœžœžœžœžœ žœ˜BKšžœžœžœ˜ K˜—K˜š’œ˜Kšœ+˜+Kšœ˜K˜—š  œžœžœ žœžœ˜JKšž˜Kšžœžœžœ˜K˜š’œ˜Kšœ7™7Kšœ1™1Kšž˜Kšœ˜Kšœ˜Kšœ˜Kšžœ˜—K˜Kšœžœž˜Kšžœžœžœ1žœ ˜XKšœ"žœ˜&Kšœ žœ˜šžœžœž˜Kšœžœ˜Kšœ˜Kšœžœžœ˜%Kšžœ˜ —Kšžœ˜—K˜š œžœ(˜>Kšž˜šž˜Kšœžœžœ˜IKšœ˜Kšž˜—Kšžœ˜—K˜Kšœ;˜;Kšœ"žœ)˜OKšžœžœ˜7K˜Kšœ˜KšœW˜WKšžœ˜K˜™4K™ Kšœ™—K™šœ6™6K™EK™G—K™šœ5™5K™—K™šœ4™4K™—K™šœ4™4K™K™K™—K˜—…—IΈ‚'