-- ChipOrientImpl.mesa -- A package to transform Chipmonk rectangles and -- orientations. -- last edited by E. McCreight, December 15, 1982 6:10 PM -- written by E. McCreight, February 22, 1982 10:11 AM DIRECTORY ChipOrient, InlineDefs, ppdefs; ChipOrientImpl: PROGRAM IMPORTS ChipOrient, InlineDefs, ppdefs EXPORTS ChipOrient = BEGIN OPEN ppdefs, ChipOrient; -- Orientation Transformations -- x increases to the right, y increases downward. -- An orientationIndex idx is composed of two parts: -- a clockwise rotation of (idx/2)*45 degrees, -- followed by a reflection in x if (idx MOD 2)#0. -- Odd multiples of 45 degrees are not yet supported. MapRect: PUBLIC PROC [itemInCell: Rect, cellSize: Point, cellInstOrient: orientationIndex, cellInstPos: Point ← [0,0]] RETURNS [itemInWorld: Rect] = -- 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 OPEN InlineDefs; x1, y1, x2, y2, sizeX, sizeY, t: locNum; IF cellInstOrient=0 THEN RETURN[[x1: cellInstPos.x+itemInCell.x1, x2: cellInstPos.x+itemInCell.x2, y1: cellInstPos.y+itemInCell.y1, y2: cellInstPos.y+itemInCell.y2]]; -- most common case [x: sizeX, y: sizeY] ← cellSize; [x1: x1, x2: x2, y1: y1, y2: y2] ← itemInCell; SELECT BITAND[cellInstOrient, 14B] FROM 0 => NULL; 4 => -- 90 degrees clockwise BEGIN t ← y1; y1 ← x1; x1 ← sizeY-y2; y2 ← x2; x2 ← sizeY-t; sizeX ← sizeY; END; 10B => -- 180 degrees clockwise BEGIN t ← sizeX-x1; x1 ← sizeX-x2; x2 ← t; t ← sizeY-y1; y1 ← sizeY-y2; y2 ← t; END; 14B => -- 270 degrees clockwise BEGIN t ← x1; x1 ← y1; y1 ← sizeX-x2; x2 ← y2; y2 ← sizeX-t; sizeX ← sizeY; END; ENDCASE; IF BITAND[cellInstOrient, 1]#0 THEN -- mirror in x {t ← sizeX-x1; x1 ← sizeX-x2; x2 ← t}; itemInWorld ← [x1: cellInstPos.x+x1, -- translate by cellInstPos y1: cellInstPos.y+y1, x2: cellInstPos.x+x2, y2: cellInstPos.y+y2]; END; DeMapRect: PUBLIC PROC [itemInWorld: Rect, cellSize: Point, cellInstOrient: orientationIndex, cellInstPos: Point ← [0,0]] RETURNS [itemInCell: Rect] = BEGIN OPEN InlineDefs; -- 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: orientationIndex = 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: Size[size: cellSize, orient: inverseOrient]]; END; ComposeOrient: PUBLIC PROC [ itemOrientInCell, cellOrientInWorld: orientationIndex] RETURNS [itemOrientInWorld: orientationIndex] = BEGIN OPEN InlineDefs; -- 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] ← BITAND[itemOrientInCell, 1]; rot2: [0..14] ← BITAND[cellOrientInWorld, 14]; IF refl1#0 AND rot2#0 THEN rot2 ← 16-rot2; itemOrientInWorld ← BITAND[BITAND[itemOrientInCell, 14]+ rot2+BITXOR[refl1, BITAND[cellOrientInWorld, 1]], 15]; END; InverseOrient: PUBLIC PROC [orient: orientationIndex] RETURNS [inverse: orientationIndex] = BEGIN OPEN InlineDefs; -- 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] ← BITAND[orient, 1]; rot: [0..14] ← BITAND[orient, 14]; IF refl=0 AND rot#0 THEN rot ← 16-rot; inverse ← rot+refl; END; DecomposeOrient: PUBLIC PROC [ itemOrientInWorld, cellOrientInWorld: orientationIndex] RETURNS [itemOrientInCell: orientationIndex] = BEGIN -- For all orientationIndexes o1 and o2, -- DecomposeOrient[cellOrientInWorld: o1, itemOrientInWorld: -- ComposeOrient[cellOrientInWorld: o1, itemOrientInCell: o2]] = o2. RETURN[ComposeOrient[itemOrientInCell: itemOrientInWorld, cellOrientInWorld: InverseOrient[cellOrientInWorld]]]; END; RefPt: PUBLIC PROC [r: Rect] RETURNS [Point] = {RETURN[[x: ((r.x1+r.x2)/(2*Lambda))*Lambda, y: ((r.y1+r.y2)/(2*Lambda))*Lambda]]}; NormalizeList: PUBLIC PROC [lp: listPtr, origin: Point ← [0,0]] RETURNS [size, offset: Point] = BEGIN r: Rect ← BoundingRect[lp]; offset ← [x: origin.x-r.x1, y: origin.y-r.y1]; size ← [x: r.x2-r.x1, y: r.y2-r.y1]; FOR lpp: listPtr ← lp, lpp.nxt WHILE lpp#NIL DO lpp.lx ← lpp.lx+offset.x; lpp.ly ← lpp.ly+offset.y; ENDLOOP; END; BoundingRect: PUBLIC PROC [lp: listPtr] RETURNS [r: Rect] = BEGIN x1, y1, x2, y2: locNum; [mix: x1, miy: y1, max: x2, may: y2] ← minmax[lp]; r ← [x1: x1, y1: y1, x2: x2, y2: y2]; END; DecomposeRect: PUBLIC PROC [r, test: Rect, rInsideTest, rOutsideTest: PROC[Rect]] = BEGIN IF r.x1<test.x1 THEN BEGIN rOutsideTest[[x1: r.x1, y1: r.y1, x2: MIN[r.x2, test.x1], y2: r.y2]]; IF r.x2<test.x1 THEN RETURN; END; IF r.y1<test.y1 THEN BEGIN rOutsideTest[[x1: MAX[test.x1, r.x1], y1: r.y1, x2: r.x2, y2: MIN[r.y2, test.y1]]]; IF r.y2<test.y1 THEN RETURN; END; IF test.y2<r.y2 THEN BEGIN rOutsideTest[[x1: MAX[test.x1, r.x1], y1: MAX[test.y2, r.y1], x2: r.x2, y2: r.y2]]; IF test.y2<r.y1 THEN RETURN; END; IF test.x2<r.x2 THEN BEGIN rOutsideTest[[x1: MAX[test.x2, r.x1], y1: MAX[test.y1, r.y1], x2: r.x2, y2: MIN[r.y2, test.y2]]]; IF test.x2<r.x1 THEN RETURN; END; rInsideTest[[x1: MAX[test.x1, r.x1], y1: MAX[test.y1, r.y1], x2: MIN[test.x2, r.x2], y2: MIN[test.y2, r.y2]]]; END; -- Certification tests, can be commented out for speed of startup -- FOR o1: orientationIndex IN orientationIndex DO -- IF ComposeOrient[o1, InverseOrient[o1]] # 0 THEN ERROR; -- FOR o2: orientationIndex IN orientationIndex DO -- IF DecomposeOrient[cellOrientInWorld: o1, itemOrientInWorld: -- ComposeOrient[cellOrientInWorld: o1, itemOrientInCell: o2]] # o2 THEN ERROR; -- ENDLOOP; -- ENDLOOP; END. -- of ChipOrientImpl