<> <> <> <> <> <> <> <> <> DIRECTORY CD, CDBasics, CDCommandOps, CDDefaultProcs, CDMenus, CDOps, CDOrient, CDPlot, CDPolygons, CDSequencer, CDVArrow, CGArea, CGClipper, CGReducer, Commander, CStitching, GraphicsBasic, IO, PDFileFormat, PDFileWriter, PeachPrint, Process, Real, Rope, TerminalIO, ViewerClasses, ViewerSpecs; CDPlotPDImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDCommandOps, CDDefaultProcs, CDMenus, CDOps, CDOrient, CDPlot, CDPolygons, CDSequencer, CDVArrow, CGArea, CGClipper, CGReducer, Commander, CStitching, IO, PDFileWriter, PeachPrint, Process, Real, TerminalIO = BEGIN <<--handling colors>> stipples: REF CDPlot.LayerTonerSipples _ NIL; whiteLoadRef: PDFileWriter.LoadReference = LAST[PDFileWriter.LoadReference]; -- blank tile ID <<--device description>> printerType: CDPlot.PrinterType _ nil; toners: PDFileWriter.TonerSet _ ALL[FALSE]; sRes: CARDINAL _ 200; -- resolution (slow directition), pixels / inch fRes: CARDINAL _ 200; -- resolution (fast direction), pixels / inch scanLineWidth: CARDINAL _ 8000; --for wide-bed Versatec, length in the "fast" direction; leftOverMode: BOOL _ FALSE; bandSSize: CARDINAL _ 64; -- number chosen because of buffer-size of versatec overLap: CARDINAL _ 300; -- number of pixels by which to overlap strips maxPixPerLambda: NAT _ 20; -- maximum # of pixels to make lambda paged: BOOL _ FALSE; slowLimited: BOOL _ FALSE; --only interesting if ~paged pageSlowSize: CARDINAL _ 0; F: BOOL = FALSE; PrinterToners: TYPE = ARRAY CDPlot.PrinterType OF PDFileWriter.TonerSet; printerToners: PrinterToners _ [ -- black cyan mag yellow nil: [F, F, F, F, F,F,F,F,F,F,F,F,F,F,F,F], raven300: [TRUE, F, F, F, F,F,F,F,F,F,F,F,F,F,F,F], raven384: [TRUE, F, F, F, F,F,F,F,F,F,F,F,F,F,F,F], o3: [F, F, F, F, F,F,F,F,F,F,F,F,F,F,F,F], plateMaker: [TRUE, F, F, F, F,F,F,F,F,F,F,F,F,F,F,F], o5: [F, F, F, F, F,F,F,F,F,F,F,F,F,F,F,F], puffin: [F, TRUE, TRUE, TRUE, F,F,F,F,F,F,F,F,F,F,F,F], colorVersatec: [TRUE, TRUE, TRUE, TRUE, F,F,F,F,F,F,F,F,F,F,F,F], versatec: [TRUE, F, F, F, F,F,F,F,F,F,F,F,F,F,F,F], color400: [TRUE, TRUE, TRUE, TRUE, F,F,F,F,F,F,F,F,F,F,F,F], c150: [TRUE, TRUE, TRUE, TRUE, F,F,F,F,F,F,F,F,F,F,F,F], d4020: [F, F, F, F, F,F,F,F,F,F,F,F,F,F,F,F], -- ??? bw400: [TRUE, F, F, F, F,F,F,F,F,F,F,F,F,F,F,F], o13: [F, F, F, F, F,F,F,F,F,F,F,F,F,F,F,F], o14: [F, F, F, F, F,F,F,F,F,F,F,F,F,F,F,F], o15: [F, F, F, F, F,F,F,F,F,F,F,F,F,F,F,F] ]; ColorVersatec: PROC [] = { sRes _ 200; -- resolution (slow directition), pixels / inch fRes _ 200; -- resolution (fast direction), pixels / inch scanLineWidth _ 8000; --for the wide-bed Versatec, length in the "fast" direction; bandSSize _ 64; -- number chosen because of buffer-size of versatec overLap _ 300; -- number of pixels by which to overlap strips maxPixPerLambda _ 20; -- maximum # of pixels to make lambda paged _ FALSE; slowLimited _ FALSE; leftOverMode _ FALSE; TerminalIO.WriteRope["color versatec"] }; InkJetC150: PROC [] = { sRes _ 120; -- resolution (slow directition), pixels / inch fRes _ 120; -- resolution (fast direction), pixels / inch scanLineWidth _ 1020; bandSSize _ 48; -- overLap _ 30; -- number of pixels by which to overlap strips maxPixPerLambda _ 20; -- maximum # of pixels to make lambda paged _ FALSE; slowLimited _ TRUE; pageSlowSize _ 1020; leftOverMode _ FALSE; TerminalIO.WriteRope["ink jet"] }; Color400: PROC [] = { sRes _ 400; -- resolution (slow directition), pixels / inch fRes _ 400; -- resolution (fast direction), pixels / inch scanLineWidth _ 4096; bandSSize _ 50; -- overLap _ 30; -- number of pixels by which to overlap strips maxPixPerLambda _ 60; -- maximum # of pixels to make lambda paged _ TRUE; pageSlowSize _ 5500; leftOverMode _ FALSE; TerminalIO.WriteRope["Color400"] }; Puffin: PROC [] = { sRes _ 384; -- resolution (slow directition), pixels / inch fRes _ 384; -- resolution (fast direction), pixels / inch scanLineWidth _ fRes * 17 / 2; bandSSize _ 16; -- overLap _ 30; -- number of pixels by which to overlap strips maxPixPerLambda _ 20; -- maximum # of pixels to make lambda paged _ TRUE; pageSlowSize _ sRes*11; leftOverMode _ TRUE; TerminalIO.WriteRope["Puffin"] }; PlateMaker: PROC [] = { sRes _ 1200; -- resolution (slow directition), pixels / inch fRes _ 1200; -- resolution (fast direction), pixels / inch scanLineWidth _ fRes * 17 / 2; bandSSize _ 16; -- overLap _ 30; -- number of pixels by which to overlap strips maxPixPerLambda _ 20; -- maximum # of pixels to make lambda paged _ TRUE; pageSlowSize _ sRes*11; leftOverMode _ TRUE; TerminalIO.WriteRope["Raven or platemaker"] }; <<--state of the plot>> abortPlot: REF BOOL _ NEW[BOOL _ FALSE]; plottingInProgress: BOOL _ FALSE; pdy: CARDINAL _ 0; -- top of band in pixel coords stripClip: CD.Rect; -- clip for a page; not reduced to real design clip plotScale: REAL; imageSSize: CARDINAL; imageFSize: CARDINAL; ps: PlotStateRef; PlotStateRef: TYPE = REF PlotState; PlotState: TYPE = RECORD [ tes: ARRAY CD.Layer OF CStitching.Tesselation _ ALL[NIL], scale: REAL _ 1.0, -- pixels per CD.Number bandClip: CD.Rect _ [0, 0, 0, 0], -- design space rect, touches all geometry in band totalPlotClip: CD.Rect _ [0, 0, 0, 0], -- design space rect, touches all geometry in plot pdState: PDFileWriter.PDState, stipples: REF CDPlot.LayerTonerSipples, -- tidy sequence colorLoads: REF CDPlot.LayerTonerLoadRef, -- stipples expanded into LoadRefs anouncedLayer: INT _ -1 ]; ClipArea: PROC [comm: CDSequencer.Command] RETURNS [plotClip: CD.Rect] = { SELECT TerminalIO.RequestSelection["Plot", LIST["complete design", "rectangle"]] FROM 2 => { plotClip _ CDBasics.ToRect[comm.pos, comm.sPos]; TerminalIO.WriteRope["plot rectangle\n"] }; ENDCASE => { plotClip _ CDCommandOps.BoundingBox[comm.design]; TerminalIO.WriteRope["plot all\n"] }; IF plotClip.x1>=plotClip.x2 OR plotClip.y1>=plotClip.y2 THEN { TerminalIO.WriteRope["**cannot plot empty area\n"]; ERROR ABORTED } }; ProtectedAutoPlot: PROC [comm: CDSequencer.Command] = { design: CD.Design = comm.design; plotClip: CD.Rect; plotSize: CD.Position; strips: INT _ 1; pdc: REF CDPlot.PDControlRec; IF comm=NIL OR comm.data=NIL THEN RETURN; pdc _ NARROW[comm.data]; strips _ pdc.stripes; plotClip _ pdc.clip; printerType _ pdc.ipType; plottingInProgress _ TRUE; TerminalIO.WriteRope["Starting Color plot for "]; SELECT printerType FROM colorVersatec => ColorVersatec[]; c150 => InkJetC150[]; puffin => Puffin[]; plateMaker => PlateMaker[]; color400 => Color400[]; ENDCASE => ERROR; toners _ printerToners[printerType]; stipples _ CDPlot.GetStipples[design, printerType]; TerminalIO.WriteLn[]; plotSize _ CDBasics.SizeOfRect[plotClip]; IF plotSize.x<=0 OR plotSize.y<=0 THEN {TerminalIO.WriteRope["**cannot plot empty area\n"]; RETURN}; TRUSTED {Process.SetPriority[Process.priorityBackground]}; PlotDesignBasic[design, plotClip, plotSize, strips]}; ProtectedPlotDesign: PROC [comm: CDSequencer.Command] = { design: CD.Design = comm.design; plotClip: CD.Rect; plotSize: CD.Position; strips: INT; plottingInProgress _ TRUE; TerminalIO.WriteRope["Starting Color plot for "]; SELECT comm.key FROM $VersatecColorPlot => {printerType _ colorVersatec; ColorVersatec[]}; $C150ColorPlot => {printerType _ c150; InkJetC150[]}; $PuffinColorPlot => {printerType _ puffin; Puffin[]}; $PlatemakerColorPlot => {printerType _ plateMaker; PlateMaker[]}; $Color400Plot => {printerType _ color400; Color400[]}; ENDCASE => ERROR; toners _ printerToners[printerType]; stipples _ CDPlot.GetStipples[design, printerType]; PrepareContextFilter[]; TerminalIO.WriteLn[]; plotClip _ ClipArea[comm]; plotSize _ CDBasics.SizeOfRect[plotClip]; TRUSTED {Process.SetPriority[Process.priorityBackground]}; strips _ 1; IF ~paged AND ~slowLimited THEN { IF TerminalIO.Confirm[label: "plot multiple vertical strips", choice: "yes"] THEN strips _ TerminalIO.RequestInt["How many vertical strips? [1..10] "]}; strips _ MAX[1, MIN[10, strips]]; PlotDesignBasic[design, plotClip, plotSize, strips]}; PlotDesignBasic: PROC[ design: CD.Design, plotClip: CD.Rect, plotSize: CD.Position, strips: INT] = { ENABLE { -- for ERRORs UNWIND => { CDVArrow.RemoveArrow[design]; TerminalIO.WriteRope[" ** plot aborted ** "]} }; dr: CD.DrawRef = CD.CreateDrawRef[[ design: design, stopFlag: abortPlot, drawRect: NoteRectangle, drawContext: DrawContext, contextFilter: contextFilter ]]; scale: REAL _ MIN[ REAL[maxPixPerLambda] / design.technology.lambda, REAL[(scanLineWidth-overLap)*strips+overLap] / plotSize.x ]; <<--Center the x range of the selected area of the design on the plotter bed, with at most maxPixPerLambda pixels per lambda. If multiple strips are called for, overlap adjacent ones by "overLap" pixels.>> <<-- total number of pixels across plot = REAL[scanLineWidth]+REAL[scanLineWidth-overLap]*(strips-1))>> pageStep: CD.Position; pageWidth: CD.Position; imageFSize _ scanLineWidth; imageSSize _ Real.FixC[plotSize.y*scale]+1; IF paged THEN { imageSSize _ MIN[imageSSize, pageSlowSize]; scale _ MIN[scale, REAL[pageSlowSize]/(plotSize.y+1)] }; ps _ NEW[PlotState _ [ scale: scale, totalPlotClip: plotClip, stipples: stipples, colorLoads: NEW[CDPlot.LayerTonerLoadRef _ ALL[NIL]] ]]; pageStep _ [plotSize.x/strips, plotSize.y]; pageWidth _ [Real.Round[scanLineWidth/scale], plotSize.y]; plotScale _ scale; dr.devicePrivate _ ps; FOR strip: INT IN [0..strips) DO localFileName: Rope.ROPE = PeachPrint.FileName[long, primary, strip+1, ".pd"]; TerminalIO.WriteRopes["Recording strip on file ", localFileName, "\n"]; stripClip _ [ --but not yet intersected with complete design clip x1: plotClip.x1+strip*pageStep.x, y1: plotClip.y1, x2: plotClip.x1+strip*pageStep.x+pageWidth.x, y2: plotClip.y2 ]; ps.pdState _ PDFileWriter.Create[ fileName: localFileName, deviceCode: LOOPHOLE[printerType], sResolution: sRes, fResolution: fRes, imageSSize: imageSSize, imageFSize: imageFSize, bandSSize: bandSSize, leftOverMode: leftOverMode ]; ps.colorLoads^ _ ALL[NIL]; PDFileWriter.StartImage[pdState: ps.pdState, toners: toners]; <<-- For each band in the strip>> FOR bandYtop: INT _ 0, bandYtop+bandSSize WHILE bandYtop {abortPlot^ _ TRUE; CONTINUE}]; IF abortPlot^ THEN GOTO AbortPlot; <<-- Determine coordinate transformations>> pdy _ bandYtop; dc _ CDBasics.NormalizeRect[[ x1: stripClip.x1-1, y1: stripClip.y2-Real.Fix[(bandYtop+bandSSize)/scale]-1, x2: stripClip.x1+Real.Fix[scanLineWidth/scale]+1, y2: stripClip.y2-Real.Fix[bandYtop/scale]+1 ]] ; dr.interestClip _ ps.bandClip _ CDBasics.Intersection[plotClip, dc]; <<--Display current band under consideration to pacify user>> CDVArrow.ShowArrow[design: design, pos: [ x: (dr.interestClip.x1+dr.interestClip.x2)/2, y: (dr.interestClip.y1+dr.interestClip.y2)/2] ]; <<-- clear previous tessalations >> ps.anouncedLayer _ -1; FOR l: CD.Layer IN CD.Layer DO IF ps.tes[l]#NIL THEN CStitching.ChangeRect[plane: ps.tes[l], rect: CDBasics.universe, new: NIL]; ENDLOOP; CDOps.DrawDesign[design, dr]; -- build tesselations of the relevant design rectangle AnalyzeTesselations[ps]; --will actually draw TerminalIO.WriteRope["."]; ENDLOOP; -- for each band in the strip PDFileWriter.EndPage[ps.pdState]; PDFileWriter.Close[ps.pdState]; TerminalIO.WriteRope["*\n"]; ENDLOOP; -- for each strip TerminalIO.WriteRope[" finished plot(s)\n"]; TerminalIO.WriteF[" Example usage:\n PeachPrint Sleepy %g ", IO.rope[ PeachPrint.FileName[long, primary, 1, ".pd"]]]; CDVArrow.RemoveArrow[design: design]; plottingInProgress _ FALSE; EXITS AbortPlot => { CDVArrow.RemoveArrow[design]; TerminalIO.WriteRope[" ** plot aborted ** "] }; }; -- PlotDesign NoteRectangle: PROC [r: CD.Rect, l: CD.Layer, pr: CD.DrawRef] = { ps: PlotStateRef = NARROW[pr.devicePrivate]; IF CDBasics.NonEmpty[r] THEN { IF ps.tes[l]=NIL THEN ps.tes[l] _ CStitching.NewTesselation[]; ps.tes[l].ChangeRect[rect: r, new: $covered]} }; SetColor: PROC [ps: PlotStateRef, lev: CD.Layer] = { MakeLoadref: PROC [pattern: REF ANY] RETURNS [loadRef: PDFileWriter.LoadReference] = TRUSTED { texture: CDPlot.Stipple16; texturePtr: LONG POINTER TO CDPlot.Stipple16 _ @texture; longPtr: LONG POINTER _ LOOPHOLE[texturePtr]; IF pattern=NIL THEN texture _ ALL[0]; -- error WITH pattern SELECT FROM s16: REF CDPlot.Stipple16 => texture _ s16^; s8: REF CDPlot.Stipple8 => FOR i: [0..8) IN [0..8) DO texture[i] _ texture[i+8] _ (256+1)*s8[i]; ENDLOOP; s4: REF CDPlot.Stipple4 => FOR i: [0..4) IN [0..4) DO texture[i] _ texture[i+4] _ texture[i+8] _ texture[i+12] _ s4[i]*1111H; ENDLOOP; ENDCASE => texture _ [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0FFFFH]; -- error loadRef _ PDFileWriter.LoadContiguousColorTile[pdState: ps.pdState, phase: 0, sMin: 0, fMin: 0, sSize: 16, fSize: 16, bitsPtr: longPtr] }; MakeLoad: PROC [ps: PlotStateRef, lev: CD.Layer] = { IF ps.colorLoads^[lev]=NIL THEN { -- makes the load if it does not already exist ps.colorLoads^[lev] _ NEW[CDPlot.TonerLoadRef]; FOR toner: CDPlot.Toner IN CDPlot.Toner DO tex: REF _ IF ps.stipples.size<=lev THEN NIL ELSE ps.stipples[lev][toner]; ps.colorLoads^[lev][toner] _ IF tex=NIL THEN whiteLoadRef ELSE MakeLoadref[tex] ENDLOOP } }; <<--SetColor>> IF ps.anouncedLayer=lev THEN RETURN; IF ps.colorLoads^[lev]=NIL THEN MakeLoad[ps, lev]; FOR toner: CDPlot.Toner IN CDPlot.Toner DO IF ps.colorLoads^[lev][toner] = whiteLoadRef THEN PDFileWriter.SetColorOff[ps.pdState, toner] ELSE PDFileWriter.SetColorTile[ps.pdState, toner, ps.colorLoads^[lev][toner], transparent]; ENDLOOP; ps.anouncedLayer _ lev}; contextFilter: REF CD.ContextFilter = NEW[CD.ContextFilter_ALL[TRUE]]; PrepareContextFilter: PROC [] = { contextFilter^ _ ALL[FALSE]; FOR l: CD.Layer IN [0..stipples.size) DO FOR toner: CDPlot.Toner IN CDPlot.Toner DO IF stipples[l][toner]#NIL THEN {contextFilter[l] _ TRUE; EXIT}; ENDLOOP; ENDLOOP }; PlotPolygon: PROC [ob: CD.Object, pos: CD.Position, orient: CD.Orientation] = BEGIN OutputTrapezoid: PROC [xbotL: REAL, xbotR: REAL, ybot: REAL, xtopL: REAL, xtopR: REAL, ytop: REAL] = <<--lower left x, lower right x, lower y, upper left x, upper right x, upper y>> BEGIN <<--global variables ps, stripClip, plotScale, imageFSize, imageSSize, pdy>> <<--x-Fast>> <<--y-Slow>> PDFileWriter.MaskTrapezoid[ pdState: ps.pdState, sMin: Real.RoundC[ybot], sSize: Real.RoundC[ytop-ybot], fMin: Real.RoundC[xbotL], fSize: Real.RoundC[xbotR-xbotL], fMinLast: Real.RoundC[xtopL], fSizeLast: Real.RoundC[xtopR-xtopL] ]; END; --OutputTrapezoid <<--PlotPolygon>> pp: CDPolygons.PolygonPtr = NARROW[ob.specificRef]; polygon: CGReducer.Ref = CGReducer.New[size: 8]; tiling: CGArea.Ref = CGArea.New[size: 4]; clipRef: CGClipper.Ref = CGClipper.New[size: 4]; clip: GraphicsBasic.Box _ [ xmin: 0, ymin: pdy, xmax: MIN[(ps.bandClip.x2-stripClip.x1)*plotScale, imageFSize], ymax: MIN[pdy+bandSSize, imageSSize] ]; CGClipper.SetBox[self: clipRef, box: clip]; CGClipper.Load[self: clipRef, reducer: polygon]; FOR p: LIST OF CD.Position _ pp.points, p.rest WHILE p#NIL DO at: CD.Position = CDOrient.MapPoint[ pointInCell: p.first, cellSize: ob.size, cellInstOrient: orient, cellInstPos: pos ]; CGReducer.Vertex[self: polygon, v: [ x: (at.x-stripClip.x1)*plotScale, y: (stripClip.y2-at.y)*plotScale ]] ENDLOOP; CGReducer.Close[polygon]; CGReducer.Generate[self: polygon, area: tiling]; UNTIL CGArea.Empty[tiling] DO t: GraphicsBasic.Trap = CGArea.Remove[tiling]; OutputTrapezoid[t.xbotL, t.xbotR, t.ybot, t.xtopL, t.xtopR, t.ytop]; ENDLOOP; END; --PlotPolygon DrawContext: PROC [pr: CD.DrawRef, proc: CD.DrawContextLayerProc, ob: CD.Object, pos: CD.Position, orient: CD.Orientation, layer: CD.Layer] = BEGIN IF CDPolygons.IsPolygon[ob] THEN { SetColor[ps, layer]; PlotPolygon[ob, pos, orient]; } ELSE CDDefaultProcs.DrawContext[pr, proc, ob, pos, orient, layer] END; AnalyzeTesselations: PROC [ps: PlotStateRef] = BEGIN FOR lev: CD.Layer IN CD.Layer DO IF ps.tes[lev]#NIL THEN { SetColor[ps, lev]; CStitching.EnumerateArea[plane: ps.tes[lev], rect: ps.bandClip, eachTile: ProcessTile, data: ps]; }; ENDLOOP; END; ProcessTile: PROC [tile: CStitching.Tile, data: REF ANY] = BEGIN IF tile.value = $covered THEN { rightBound, xStart, xStop, yStart, yStop: INT; cxStart, cxStop, cyStop, cyStart: CARDINAL; sSize, fSize: CARDINAL; ps: PlotStateRef = NARROW[data]; r: CD.Rect = tile.Area; <<-- calculate device coords of rectangle>> xStart _ Real.Round[(r.x1-stripClip.x1)*plotScale]; yStop _ Real.Round[(stripClip.y2-r.y1)*plotScale]; xStop _ Real.Round[(r.x2-stripClip.x1)*plotScale]; yStart _ Real.Round[(stripClip.y2-r.y2)*plotScale]; <<-- clip device rectangle>> rightBound _ Real.Round[(ps.bandClip.x2-stripClip.x1)*plotScale]; IF xStart>rightBound OR xStop<0 THEN RETURN; IF yStopMIN[imageSSize, pdy+bandSSize] THEN RETURN; <<-- print device rectangle>> cxStart _ MAX[xStart, 0]; cxStop _ MIN[xStop, rightBound, imageFSize]; cyStart _ MAX[yStart, pdy]; cyStop _ MIN[yStop, pdy+bandSSize, imageSSize]; fSize _ cxStop - cxStart; sSize _ cyStop - cyStart; IF sSize>0 AND fSize>0 THEN PDFileWriter.MaskRectangle[pdState: ps.pdState, sMin: cyStart, fMin: cxStart, sSize: sSize, fSize: fSize]; }; END; WaitPlotFinishedCommand: Commander.CommandProc = BEGIN prio: Process.Priority = Process.GetPriority[]; IF ~plottingInProgress THEN { IO.PutRope[cmd.out, " waiting for plot to start"]; WHILE ~plottingInProgress DO Process.Pause[Process.SecondsToTicks[1]]; ENDLOOP; IO.PutRope[cmd.out, ". plot started...\n"] }; Process.SetPriority[Process.priorityBackground]; WHILE plottingInProgress DO Process.Pause[Process.SecondsToTicks[2]]; ENDLOOP; Process.SetPriority[prio]; IO.PutRope[cmd.out, " finished\n"] END; PDAutoPlotComm: PROC [comm: CDSequencer.Command] = { TerminalIO.WriteRope["Color plot - non interactive\n"]; [] _ CDCommandOps.CallWithResource[ProtectedAutoPlot, comm, $ColorPlot, abortPlot]}; PDColorPlotComm: PROC [comm: CDSequencer.Command] = { TerminalIO.WriteRope["Color plot\n"]; [] _ CDCommandOps.CallWithResource[ProtectedPlotDesign, comm, $ColorPlot, abortPlot]}; Init: PROC [] = BEGIN OPEN CDS: CDSequencer; CDS.ImplementCommand[key: $PDAutoPlot, proc: PDAutoPlotComm, queue: dontQueue]; CDS.ImplementCommand[key: $VersatecColorPlot, proc: PDColorPlotComm, queue: doQueue]; CDS.ImplementCommand[key: $C150ColorPlot, proc: PDColorPlotComm, queue: doQueue]; CDS.ImplementCommand[key: $Color400Plot, proc: PDColorPlotComm, queue: doQueue]; CDS.ImplementCommand[key: $PuffinColorPlot, proc: PDColorPlotComm, queue: doQueue]; CDS.ImplementCommand[key: $PlatemakerColorPlot, proc: PDColorPlotComm, queue: doQueue]; CDMenus.CreateEntry[$HardCopyMenu, "PD Color Versatec", $VersatecColorPlot]; CDMenus.CreateEntry[$HardCopyMenu, "PD C150", $C150ColorPlot]; CDMenus.CreateEntry[$HardCopyMenu, "PD Color400", $Color400Plot]; CDMenus.CreateEntry[$HardCopyMenu, "PD Puffin, (1 page)", $PuffinColorPlot]; CDMenus.CreateEntry[$HardCopyMenu, "PD Platemaker", $PlatemakerColorPlot]; Commander.Register[ key: "///Commands/CDWaitPlotFinished", proc: WaitPlotFinishedCommand, doc: "waits until ChipNDale pd plotting is finished"]; TerminalIO.WriteRope["ChipNDale color plot program loaded.\n"]; END; Init[]; END.