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:
BOOL ←
TRUE ]
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:
BOOL ←
FALSE ] =
BEGIN
state: EBESStreamStateRef = NARROW[self.streamData];
self.Flush[];
state.dest.Close[];
END;
UserWantsToDebug: SIGNAL = CODE;
ComplainAt:
PUBLIC
PROC [ ms: MaskState, pos: TadPosition, explanation:
ROPE ←
NIL, choice:
LIST
OF
ROPE ←
NIL ]
RETURNS [ chosen:
NAT ] =
BEGIN
radius: Tad = 20*ms.nmPerLambda*ms.tadsPerNm;
cdRect: CD.Rect = ScaleTadToCD[ms, [x1: pos.x-radius, y1: pos.y-radius, x2: pos.x+radius, y2: pos.y+radius]];
CDVArrow.ShowArrow[ms.design, CDBasics.Center[cdRect]];
TerminalIO.PutRope[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[header: "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:
REF ←
NIL ]
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];
END;
END;
ScaleCDToTad:
PUBLIC
PROC [ ms: MaskState, cdr:
CD.Rect ]
RETURNS [ tr: TadRect ] =
BEGIN
tr ← CDBasics.ReInterpreteRect[
[x1: RatIntMul[ms.scale, cdr.x1],
y1: RatIntMul[ms.scale, cdr.y1],
x2: RatIntMul[ms.scale, cdr.x2],
y2: RatIntMul[ms.scale, cdr.y2]]];
END;
ScaleTadToCD:
PUBLIC
PROC [ ms: MaskState, tr: TadRect ]
RETURNS [ cdr:
CD.Rect ] =
BEGIN
cdr ← CDBasics.ReInterpreteRect[
[x1: RatIntDiv[ms.scale, tr.x1],
y1: RatIntDiv[ms.scale, tr.y1],
x2: RatIntDiv[ms.scale, tr.x2],
y2: RatIntDiv[ms.scale, tr.y2]]];
END;
Bloat:
PUBLIC
PROC [ r: TadRect, deltaDiameter: Tad ]
RETURNS [ br: TadRect ] =
BEGIN
b: Tad = deltaDiameter/2; -- split in "half" for radius
IF deltaDiameter<0 THEN ERROR;
IF (deltaDiameter
MOD 2) # 0
THEN
ERROR TadTooLarge;
Be careful not to exceed the limits of a D2Basic.Number, even temporarily
br ← [x1: MAX[FIRST[D2Basic.Number]+b, r.x1]-b,
y1: MAX[FIRST[D2Basic.Number]+b, r.y1]-b,
x2: MIN[LAST[D2Basic.Number]-b, r.x2]+b,
y2: MIN[LAST[D2Basic.Number]-b, r.y2]+b];
END;
TadTooLarge: PUBLIC ERROR = CODE;
ScaleRect:
PUBLIC
PROC [ r: D2Basic.Rect, factor: Rational ]
RETURNS [ sr: D2Basic.Rect ] =
BEGIN
sr ← CDBasics.ReInterpreteRect[
[x1: RatIntMul[factor, r.x1],
y1: RatIntMul[factor, r.y1],
x2: RatIntMul[factor, r.x2],
y2: RatIntMul[factor, r.y2]]];
END;
ScalePoint:
PUBLIC
PROC [ p: D2Basic.Vector, factor: Rational ]
RETURNS [ sp: D2Basic.Vector ] =
{sp ← [x: RatIntMul[factor, p.x], y: RatIntMul[factor, p.y]]};
Basic Rational Arithmetic
RatAdd:
PUBLIC
PROC [ r1, r2: Rational ]
RETURNS [ Rational ] =
{RETURN[ReduceRational[[num: r2.denom*r1.num+r1.denom*r2.num, denom: r1.denom*r2.denom]]]};
RatNeg:
PUBLIC PROC [ r: Rational ]
RETURNS [ Rational ] =
{RETURN[[num: -r.num, denom: r.denom]]};
RatMul:
PUBLIC PROC [ r1, r2: Rational ]
RETURNS [ Rational ] =
{RETURN[ReduceRational[[num: r1.num*r2.num, denom: r1.denom*r2.denom]]]};
RatInv:
PUBLIC PROC [ r: Rational ]
RETURNS [ Rational ] =
{RETURN[ReduceRational[[num: r.denom, denom: r.num]]]};
RatIntMul:
PROC [ mul: Rational, z:
INT ]
RETURNS [
INT ] =
INLINE {RETURN[(mul.num*z)/mul.denom]};
RatIntDiv:
PUBLIC PROC [ div: Rational, z:
INT ]
RETURNS [
INT ] =
INLINE {RETURN[(div.denom*z)/div.num]};
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;
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;
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;