<> <> <> <> <> <> DIRECTORY CDOrient, Basics, CD; CDOrientImpl: CEDAR PROGRAM IMPORTS Basics, CDOrient EXPORTS CDOrient = BEGIN OPEN CDOrient; <<-- Orientation Transformations>> <<-- x increases to the right, y increases upward. >> <<-- An CD.Orientation idx is composed of two parts:>> <<-- a clockwise rotation of (idx/2)*90 degrees,>> <<-- followed by a reflection in x if (idx MOD 2)#0.>> MapRect: PUBLIC PROC [itemInCell: CD.Rect, cellSize: CD.Position, cellInstOrient: CD.Orientation, cellInstPos: CD.Position _ [0,0]] RETURNS [itemInWorld: CD.Rect_TRASH] = <<-- Given an item in a prototype cell, and the>> <<-- size of the prototype cell, both in "cell" co-ordinates, and>> <<-- the position and orientation index of an instance of that cell in "world">> <<-- co-ordinates, this procedure returns the world>> <<-- co-ordinates of the instance of the item.>> BEGIN SELECT cellInstOrient FROM original => RETURN[CD.Rect[ x1: cellInstPos.x+itemInCell.x1, x2: cellInstPos.x+itemInCell.x2, y1: cellInstPos.y+itemInCell.y1, y2: cellInstPos.y+itemInCell.y2 ]]; mirrorX => -- reflection in x RETURN[CD.Rect[ x1: cellInstPos.x+cellSize.x-itemInCell.x2, x2: cellInstPos.x+cellSize.x-itemInCell.x1, y1: cellInstPos.y+itemInCell.y1, y2: cellInstPos.y+itemInCell.y2 ]]; rotate90 => { -- 90 degrees clockwise RETURN[CD.Rect[ x1: cellInstPos.x+cellSize.y-itemInCell.y2, y1: cellInstPos.y+itemInCell.x1, x2: cellInstPos.x+cellSize.y-itemInCell.y1, y2: cellInstPos.y+itemInCell.x2]]; }; rotate90X => { -- 90 degrees clockwise followed by reflection in x RETURN[CD.Rect[ x1: cellInstPos.x+itemInCell.y1, y1: cellInstPos.y+itemInCell.x1, x2: cellInstPos.x+itemInCell.y2, y2: cellInstPos.y+itemInCell.x2]]; }; rotate180 => { -- 180 degrees clockwise RETURN[CD.Rect[ x1: cellInstPos.x+cellSize.x-itemInCell.x2, y1: cellInstPos.y+cellSize.y-itemInCell.y2, x2: cellInstPos.x+cellSize.x-itemInCell.x1, y2: cellInstPos.y+cellSize.y-itemInCell.y1]]; }; rotate180X => { -- 180 degrees clockwise followed by reflection in x RETURN[CD.Rect[ x1: cellInstPos.x+itemInCell.x1, y1: cellInstPos.y+cellSize.y-itemInCell.y2, x2: cellInstPos.x+itemInCell.x2, y2: cellInstPos.y+cellSize.y-itemInCell.y1]]; }; rotate270 => { -- 270 degrees clockwise RETURN[CD.Rect[ x1: cellInstPos.x+itemInCell.y1, y1: cellInstPos.y+cellSize.x-itemInCell.x2, x2: cellInstPos.x+itemInCell.y2, y2: cellInstPos.y+cellSize.x-itemInCell.x1]]; }; rotate270X => { -- 270 degrees clockwise followed by reflection in x RETURN[CD.Rect[ x1: cellInstPos.x+cellSize.y-itemInCell.y2, y1: cellInstPos.y+cellSize.x-itemInCell.x2, x2: cellInstPos.x+cellSize.y-itemInCell.y1, y2: cellInstPos.y+cellSize.x-itemInCell.x1]]; }; ENDCASE; END; DeMapRect: PUBLIC PROC [itemInWorld: CD.Rect, cellSize: CD.Position, cellInstOrient: CD.Orientation, cellInstPos: CD.Position _ [0,0]] RETURNS [itemInCell: CD.Rect] = BEGIN <<-- Given an item in world co-ordinates, and the>> <<-- size of a prototype cell, both in "cell" co-ordinates, and>> <<-- the position and orientation index of an instance of that cell in "world">> <<-- co-ordinates, this procedure returns the cell prototype>> <<-- co-ordinates of that item.>> inverseOrient: CD.Orientation = InverseOrient[cellInstOrient]; itemInCell _ MapRect[ itemInCell: [ x1: itemInWorld.x1-cellInstPos.x, y1: itemInWorld.y1-cellInstPos.y, x2: itemInWorld.x2-cellInstPos.x, y2: itemInWorld.y2-cellInstPos.y ], cellInstOrient: inverseOrient, cellSize: CDOrient.OrientedSize[size: cellSize, orient: inverseOrient] ]; END; MapPoint: PUBLIC PROC [pointInCell: CD.Position, cellSize: CD.Position, cellInstOrient: Orientation, cellInstPos: CD.Position _ [0,0]] RETURNS [pointInWorld: CD.Position] = <<--Given an point in a prototype cell, >> <<--the size of the prototype cell, both in "cell" co-ordinates, and>> <<--the position and orientation index of an instance of that cell in "world">> <<--co-ordinates, this procedure returns the world>> <<--co-ordinates of the point.>> <<--WARNING: a position of a rect can not be mapped with MapPoint>> BEGIN SELECT cellInstOrient FROM original => RETURN[CD.Position[ x: cellInstPos.x+pointInCell.x, y: cellInstPos.y+pointInCell.y ]]; mirrorX => -- reflection in x RETURN[CD.Position[ x: cellInstPos.x+cellSize.x-pointInCell.x, y: cellInstPos.y+pointInCell.y ]]; rotate90 => { -- 90 degrees clockwise RETURN[CD.Position[ x: cellInstPos.x+cellSize.y-pointInCell.y, y: cellInstPos.y+pointInCell.x]]; }; rotate90X => { -- 90 degrees clockwise followed by reflection in x RETURN[CD.Position[ x: cellInstPos.x+pointInCell.y, y: cellInstPos.y+pointInCell.x]]; }; rotate180 => { -- 180 degrees clockwise RETURN[CD.Position[ x: cellInstPos.x+cellSize.x-pointInCell.x, y: cellInstPos.y+cellSize.y-pointInCell.y]]; }; rotate180X => { -- 180 degrees clockwise followed by reflection in x RETURN[CD.Position[ x: cellInstPos.x+pointInCell.x, y: cellInstPos.y+cellSize.y-pointInCell.y]]; }; rotate270 => { -- 270 degrees clockwise RETURN[CD.Position[ x: cellInstPos.x+pointInCell.y, y: cellInstPos.y+cellSize.x-pointInCell.x]]; }; rotate270X => { -- 270 degrees clockwise followed by reflection in x RETURN[CD.Position[ x: cellInstPos.x+cellSize.y-pointInCell.y, y: cellInstPos.y+cellSize.x-pointInCell.x]]; }; ENDCASE; END; DeMapPoint: PUBLIC PROC [pointInWorld: CD.Position, cellSize: CD.Position, cellInstOrient: Orientation, cellInstPos: CD.Position _ [0,0]] RETURNS [pointInCell: CD.Position] = <<--Given a point in world co-ordinates>> <<--the size of the prototype cell, in "cell" co-ordinates, and>> <<--the position and orientation index of an instance of that cell in "world">> <<--co-ordinates, this procedure returns the cell>> <<--co-ordinates of the point.>> <<--WARNING: a position of a rect can not be mapped with DeMapPoint>> BEGIN inverseOrient: CD.Orientation = InverseOrient[cellInstOrient]; pointInCell _ MapPoint[ pointInCell: [ x: pointInWorld.x-cellInstPos.x, y: pointInWorld.y-cellInstPos.y ], cellInstOrient: inverseOrient, cellSize: CDOrient.OrientedSize[size: cellSize, orient: inverseOrient] ]; END; ComposeOrient: PUBLIC PROC [ itemOrientInCell, cellOrientInWorld: CD.Orientation] RETURNS [itemOrientInWorld: CD.Orientation] = BEGIN <<-- This procedure produces the composite orientation>> <<-- obtained by first doing itemOrientInCell and then>> <<-- doing cellOrientInWorld. It uses the observation>> <<-- that a reflection in x followed by a z-degree clockwise>> <<-- rotation is the same as a (360-z)-degree clockwise rotation>> <<-- followed by a reflection in x. Thus if itemOrientInCell>> <<-- contains a final reflection, then cellOrientInWorld's rotation>> <<-- operates in reverse.>> itemOrientInWorld _ composeTable[itemOrientInCell][cellOrientInWorld] END; InverseOrient: PUBLIC PROC [orient: CD.Orientation] RETURNS [inverse: CD.Orientation] = BEGIN <<-- For all orientationIndexes o1, ComposeOrient[o1, InverseOrient[o1]] = 0.>> <<-- A reflection in x followed by a z-degree clockwise>> <<-- rotation is the same as a (360-z)-degree clockwise rotation>> <<-- followed by a reflection in x. Thus if orient>> <<-- contains a final reflection, then the inverse rotation>> <<-- operates in the same direction as the forward one.>> refl: [0..1] ~ Basics.BITAND[orient, 1]; rot: [0..6] _ Basics.BITAND[orient, 6]; IF refl=0 AND rot#0 THEN rot _ 8-rot; inverse _ rot+refl; END; DecomposeOrient: PUBLIC PROC [ itemOrientInWorld, cellOrientInWorld: CD.Orientation] RETURNS [itemOrientInCell: CD.Orientation] = BEGIN <<-- For all orientationIndexes o1 and o2,>> <<-- DecomposeOrient[cellOrientInWorld: o1, itemOrientInWorld:>> <<-- ComposeOrient[cellOrientInWorld: o1, itemOrientInCell: o2]] = o2.>> RETURN[ composeTable[itemOrientInWorld][InverseOrient[cellOrientInWorld]] ] END; ReallyComposeOrient: PUBLIC PROC [ itemOrientInCell, cellOrientInWorld: CD.Orientation] RETURNS [itemOrientInWorld: CD.Orientation] = BEGIN <<-- This procedure produces the composite orientation>> <<-- obtained by first doing itemOrientInCell and then>> <<-- doing cellOrientInWorld. It uses the observation>> <<-- that a reflection in x followed by a z-degree clockwise>> <<-- rotation is the same as a (360-z)-degree clockwise rotation>> <<-- followed by a reflection in x. Thus if itemOrientInCell>> <<-- contains a final reflection, then cellOrientInWorld's rotation>> <<-- operates in reverse.>> refl1: [0..1] ~ Basics.BITAND[itemOrientInCell, 1]; rot2: [0..6] _ LOOPHOLE[Basics.BITAND[cellOrientInWorld, 6]]; IF refl1#0 AND rot2#0 THEN rot2 _ 8-rot2; itemOrientInWorld _ Basics.BITAND[LOOPHOLE[Basics.BITAND[itemOrientInCell, 6], CARDINAL]+ rot2+LOOPHOLE[Basics.BITXOR[refl1, Basics.BITAND[cellOrientInWorld, 1]], CARDINAL], 7]; END; <<-- Certification tests, can be commented out for speed of startup>> <> <> <> <> <> <> <> <<>> composeTable: ARRAY CD.Orientation OF ARRAY CD.Orientation OF CD.Orientation; FOR o1: CD.Orientation IN CD.Orientation DO FOR o2: CD.Orientation IN CD.Orientation DO composeTable[o1][o2] _ ReallyComposeOrient[o1, o2]; ENDLOOP; ENDLOOP; END.