CDMEBESUtilitiesImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
McCreight, June 20, 1986 11:47:44 am PDT
DIRECTORY
Atom, Basics, CD, CDBasics, CDMEBES, CDVArrow, CDViewer, CStitching, D2Basic, IO, Rope, TerminalIO;
CDMEBESUtilitiesImpl: CEDAR PROGRAM
IMPORTS Atom, CDBasics, CDViewer, CDVArrow, CStitching, IO, Rope, TerminalIO
EXPORTS CDMEBES =
BEGIN OPEN CDMEBES;
SendCommand: PUBLIC PROC [ s: IO.STREAM, comm: REF ] =
BEGIN
sizeInWords: NAT;
WITH comm SELECT FROM
c: REF DrawRectangle => sizeInWords ← SIZE[DrawRectangle];
c: REF DrawTrapezoid => sizeInWords ← SIZE[DrawTrapezoid];
c: REF BasicCommand => sizeInWords ← SIZE[BasicCommand];
c: REF Mode12StartStripe => sizeInWords ← SIZE[Mode12StartStripe];
c: REF Mode12StartDrawing => sizeInWords ← SIZE[Mode12StartDrawing];
c: REF ExtAddrModeStartDrawing => sizeInWords ← SIZE[ExtAddrModeStartDrawing];
c: REF SegDirectoryEntry => sizeInWords ← SIZE[SegDirectoryEntry];
c: REF ExtAddrModeStartStripe => sizeInWords ← SIZE[ExtAddrModeStartStripe];
c: REF StartSegment => sizeInWords ← SIZE[StartSegment];
c: REF Date => sizeInWords ← SIZE[Date];
c: REF PatternFileName => sizeInWords ← SIZE[PatternFileName];
c: REF CARDINAL => sizeInWords ← SIZE[CARDINAL];
ENDCASE => ERROR;
TRUSTED {s.UnsafePutBlock[[base: LOOPHOLE[comm], startIndex: 0, count: Basics.bytesPerWord*sizeInWords]]};
END;
EBES IO Stream Types and Procedures
EBESStreamStateRef: TYPE = REF EBESStreamState;
EBESStreamState: TYPE = RECORD [
dest: IO.STREAM,
destIndexMod: [0..mebesBlockSize),
eor: BOOL,
buf: REF TEXT];
ebesStreamProcs: REF IO.StreamProcs = IO.CreateStreamProcs[
variety: output,
class: $EBESOutputStream,
putChar: PutEBESChar,
unsafePutBlock: PutEBESBlock,
flush: FlushEBES,
getIndex: GetIndexEBES,
setIndex: SetIndexEBES,
close: CloseEBES
];
EBESOpen: PUBLIC PROC [ dest: IO.STREAM, eor: BOOLTRUE ] RETURNS [ self: IO.STREAM ] =
BEGIN
state: EBESStreamStateRef = NEW[EBESStreamState ← [
dest: dest,
destIndexMod: dest.GetIndex[] MOD mebesBlockSize,
eor: eor,
buf: NEW[TEXT[mebesBlockSize]]
]];
state.buf.length ← 0;
self ← IO.CreateStream[
streamProcs: ebesStreamProcs,
streamData: state
];
END;
PutEBESChar: PROC [ self: IO.STREAM, char: CHAR ] =
TRUSTED BEGIN
state: EBESStreamStateRef = NARROW[self.streamData];
FlushEBESIfNecessary[state, 1];
state.buf[state.buf.length] ← char;
state.buf.length ← state.buf.length+1;
END;
PutEBESBlock: PROC [ self: IO.STREAM, block: IO.UnsafeBlock ] =
TRUSTED BEGIN
state: EBESStreamStateRef = NARROW[self.streamData];
FlushEBESIfNecessary[state, block.count];
FOR i: INT IN [0..block.count) DO
CharArrayPtr: TYPE = LONG POINTER TO PACKED ARRAY [0..0) OF CHAR;
state.buf[state.buf.length+i] ← LOOPHOLE[block.base, CharArrayPtr][block.startIndex+i];
ENDLOOP;
state.buf.length ← state.buf.length+block.count;
END;
FlushEBESIfNecessary: PROC [state: EBESStreamStateRef, newBytes: NAT] = INLINE
BEGIN
IF mebesBlockSize<state.destIndexMod+state.buf.length+newBytes+
(IF state.eor THEN 2*SIZE[BasicCommand] -- for end of record -- ELSE 0) THEN
DoFlushEBES[state];
END;
FlushEBES: PROC [ self: IO.STREAM ] = {DoFlushEBES[NARROW[self.streamData]]};
DoFlushEBES: PROC [ state: EBESStreamStateRef ] =
BEGIN
IF state.buf.length>0 OR state.destIndexMod>0 THEN
BEGIN
IF state.eor THEN
BEGIN
IF state.buf.length+2 <= mebesBlockSize-state.destIndexMod THEN
TRUSTED BEGIN -- append an end-of-record command to the buffer
endRec: PACKED ARRAY [0..2) OF CHAR = LOOPHOLE[endRecord];
state.buf[state.buf.length] ← endRec[0];
state.buf[state.buf.length+1] ← endRec[1];
state.buf.length ← state.buf.length+2;
END
ELSE ERROR; -- can't terminate buffer properly
END;
FOR i: INT IN [state.buf.length..mebesBlockSize-state.destIndexMod) DO
state.buf[i] ← 000C; -- pad out with 0's
ENDLOOP;
state.buf.length ← mebesBlockSize-state.destIndexMod;
state.dest.PutBlock[state.buf];
END;
state.buf.length ← 0;
state.destIndexMod ← 0;
END;
GetIndexEBES: PROC [ self: IO.STREAM ] RETURNS [ index: INT ] =
BEGIN
state: EBESStreamStateRef = NARROW[self.streamData];
index ← state.dest.GetIndex[]+state.buf.length;
END;
SetIndexEBES: PROC [ self: IO.STREAM, index: INT ] =
BEGIN
state: EBESStreamStateRef = NARROW[self.streamData];
IF state.buf.length>0 THEN state.dest.PutBlock[state.buf];
state.buf.length ← 0;
state.dest.SetIndex[index];
state.destIndexMod ← state.dest.GetIndex[] MOD mebesBlockSize;
END;
CloseEBES: PROC [ self: IO.STREAM, abort: BOOLFALSE ] =
BEGIN
state: EBESStreamStateRef = NARROW[self.streamData];
self.Flush[];
state.dest.Close[];
END;
Auxiliary Procedures
UserWantsToDebug: SIGNAL = CODE;
ComplainAt: PUBLIC PROC [ ms: MaskState, pos: MEBESPosition, explanation: ROPENIL, choice: LIST OF ROPENIL ] RETURNS [ chosen: NAT ] =
BEGIN
cdRect: CD.Rect = ScaleEBESToCD[ms, [x1: pos.x-25, y1: pos.y-25, x2: pos.x+25, y2: pos.y+25]];
CDVArrow.ShowArrow[ms.design, CDBasics.Center[cdRect]];
TerminalIO.WriteRope[IO.PutFR["\nMEBES generation problem: %g\n", IO.rope[explanation]]];
chosen ← 0;
DO ENABLE UNWIND => CDVArrow.ShowArrow[ms.design, ms.viewerArrow];
selected: NAT;
viewerList: CDViewer.ViewerList = CDViewer.ViewersOf[ms.design];
CDVArrow.ShowArrow[ms.design, CDBasics.Center[cdRect]];
IF viewerList # NIL THEN CDViewer.ShowAndScale[viewerList.first, cdRect];
SELECT (selected ← TerminalIO.RequestSelection[label: "Action..", choice: CONS["Abort", CONS["Debug", choice]]]) FROM
0 => {chosen ← 0; EXIT};
1 => ERROR ABORTED;
2 => {SIGNAL UserWantsToDebug; LOOP};
ENDCASE => {chosen ← selected-2; EXIT};
ENDLOOP;
CDVArrow.ShowArrow[ms.design, ms.viewerArrow];
END;
NewTesselation: PUBLIC PROC [ initValue: REFNIL ] RETURNS [ tess: Tesselation ] =
BEGIN
tess ← CStitching.NewTesselation[];
tess.ChangeRect[CDBasics.universe, initValue];
END;
DisposeTesselation: PUBLIC PROC [ tess: Tesselation ] RETURNS [ Tesselation ] =
BEGIN
CStitching.ResetTesselation[plane: tess];
RETURN[NIL];
END;
RopeNeeded: PUBLIC SIGNAL [ ref: REF REF ] = CODE;
ToRope: PUBLIC PROC [ ref: REF ] RETURNS [ rope: ROPE ] =
BEGIN
IF ref = NIL THEN rope ← NIL
ELSE WITH ref SELECT FROM
r: ROPE => rope ← r;
rt: REF TEXT => rope ← Rope.FromRefText[rt];
a: ATOM => rope ← Atom.GetPName[a];
ri: REF INT => rope ← IO.PutFR[format: "%d", v1: IO.int[ri^]];
ENDCASE =>
BEGIN
refRef: REF REF = NEW[REF ← ref];
SIGNAL RopeNeeded[refRef];
rope ← ToRope[refRef^ ! RopeNeeded => GOTO NoHelp];
EXITS
NoHelp => ERROR;
END;
END;
ScaleCDToEBES: PUBLIC PROC [ ms: MaskState, cdr: CD.Rect ] RETURNS [ mr: MEBESRect ] =
BEGIN
mr ← CDBasics.NormalizeRect[
[x1: RatMul[ms.scale, cdr.x1],
y1: RatMul[ms.scale, cdr.y1],
x2: RatMul[ms.scale, cdr.x2],
y2: RatMul[ms.scale, cdr.y2]]];
END;
ScaleEBESToCD: PUBLIC PROC [ ms: MaskState, mr: MEBESRect ] RETURNS [ cdr: CD.Rect ] =
BEGIN
cdr ← CDBasics.NormalizeRect[
[x1: RatDiv[ms.scale, mr.x1],
y1: RatDiv[ms.scale, mr.y1],
x2: RatDiv[ms.scale, mr.x2],
y2: RatDiv[ms.scale, mr.y2]]];
END;
Bloat: PUBLIC PROC [ r: D2Basic.Rect, deltaDiameter: D2Basic.Number ] RETURNS [ br: D2Basic.Rect ] =
BEGIN
b0: D2Basic.Number = deltaDiameter/2; -- split in "half" for radius
b1: D2Basic.Number = deltaDiameter-b0;
IF deltaDiameter<0 THEN ERROR;
Be careful not to exceed the limits of a D2Basic.Number, even temporarily
br ← [x1: MAX[FIRST[D2Basic.Number]+b0, r.x1]-b0,
y1: MAX[FIRST[D2Basic.Number]+b0, r.y1]-b0,
x2: MIN[LAST[D2Basic.Number]-b1, r.x2]+b1,
y2: MIN[LAST[D2Basic.Number]-b1, r.y2]+b1];
END;
ScaleRect: PUBLIC PROC [ r: D2Basic.Rect, factor: Rational ] RETURNS [ sr: D2Basic.Rect ] =
BEGIN
sr ← CDBasics.NormalizeRect[
[x1: RatMul[factor, r.x1],
y1: RatMul[factor, r.y1],
x2: RatMul[factor, r.x2],
y2: RatMul[factor, r.y2]]];
END;
ScalePoint: PUBLIC PROC [ p: D2Basic.Pos, factor: Rational ] RETURNS [ sp: D2Basic.Pos ] =
{sp ← [x: RatMul[factor, p.x], y: RatMul[factor, p.y]]};
Ceiling: PUBLIC PROC [ r: Rational ] RETURNS [ c: INT ] =
BEGIN
c ← r.num/r.denom;
c = SGN[r.num]*SGN[r.denom]*FLOOR[ABS[r.num]/ABS[r.denom]] if r.denom#0
IF ((r.num>0) = (r.denom>0)) AND r.num MOD r.denom # 0 THEN c ← c+1;
END;
ReduceRational: PUBLIC PROC [ r: Rational ] RETURNS [ Rational ] =
BEGIN
gcd: INT = IF r.num=0 THEN r.denom ELSE GCD[r.num, r.denom];
RETURN[[num: r.num/gcd, denom: r.denom/gcd]];
END;
RatMul: PROC [ mul: Rational, z: INT ] RETURNS [ INT ] =
INLINE {RETURN[(mul.num*z)/mul.denom]};
RatDiv: PROC [ div: Rational, z: INT ] RETURNS [ INT ] =
INLINE {RETURN[(div.denom*z)/div.num]};
GCD: PUBLIC PROC [ m, n: INT ] RETURNS [ INT ] =
BEGIN
r: INT;
SELECT m FROM
<0 => m ← -m;
ENDCASE => NULL;
SELECT n FROM
<0 => n ← -n;
>0 => NULL;
ENDCASE => RETURN[m];
r ← m MOD n;
WHILE r>0 DO m ← n; n ← r; r ← m MOD n; ENDLOOP;
RETURN[n];
END;
END. -- of CDMEBESUtilitiesImpl