<> <> <> <<>> 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; <> 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 mebesBlockSize0 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]; EXITS NoHelp => ERROR; 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; <> 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]]}; <> 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; <> IF ((r.num>0) = (r.denom>0)) AND r.num MOD r.denom # 0 THEN c _ c+1; END; END. -- of CDMEBESUtilitiesImpl <<>> <> <> <> <<>> <<>>