<> <<>> <> <> <> <> <> <> DIRECTORY Atom, CD, CDBasics, CDCommandOps, CDViewer, CDMenus, CDOps, CDProperties, CDSequencer, CornerStitching, Graphics, GraphicsOps, IO, PDFileFormat, PDFileWriter, Process, Real, Rope, TerminalIO, ViewerClasses, ViewerSpecs; CDColorVersatecImpl: CEDAR PROGRAM IMPORTS Atom, CD, CDBasics, CDCommandOps, CDMenus, CDViewer, CDOps, CDProperties, CDSequencer, CornerStitching, IO, PDFileWriter, Process, Real, TerminalIO = BEGIN Ink: TYPE = PDFileFormat.Toner; -- {black, cyan, magenta, yellow}; ColorRef: TYPE = REF ColorLoad_NIL; ColorLoad: TYPE = ARRAY Ink OF PDFileWriter.LoadReference; <<-- a color associated with a level is a collection of textures associated with inks>> whiteLoadRef: PDFileWriter.LoadReference _ LAST[PDFileWriter.LoadReference]; <<-- used to identify tiles without toner so that you can avoid recording them>> pdState: PDFileWriter.PDState; pdx, pdy : CARDINAL _ 0; -- origin of band in pixel coords cdx, cdy, -- origin of band in chipndale coords xoffset, yoffset : INT _ 0; -- offset in transforming between coord systems plotScale: REAL; <<-- scale factor between systems, is negative for y-axis due to reversed direction of increasing values (when compared with pixel coordinates)>> <<>> <<>> versatec: PDFileFormat.DeviceCode _ last; <> sRes, fRes: CARDINAL _ 200; -- resolution (slow directition, fast direction) in pixels per inch maxScanLineWidth: CARDINAL = 8000; <<--for the wide-bed Versatec, length in the "fast" direction>> maxPixPerLambda: REAL = 20; -- maximum # of pixels to make lambda overLap: CARDINAL = 300; -- number of pixels by which to overlap strips scanLineWidth: CARDINAL _ maxScanLineWidth; imageSSize: REAL _ 0; imageFSize: CARDINAL _ maxScanLineWidth; bandSSize: CARDINAL _ 64; <<-- number chosen because of buffer-size of versatec>> debugging: BOOL _ FALSE; numBands, numRectangles: INT _ 0; PlotStateRef: TYPE = REF PlotState; PlotState: TYPE = RECORD [ text: REF CornerStitching.Tesselation _ NIL, tes: ARRAY CD.Level OF REF CornerStitching.Tesselation _ ALL[NIL], -- enumerates all the rectangles in a given level scale: REAL _ 1.0, -- pixels per CD.DesignNumber totalPlotClip, bandClip: CD.DesignRect _ [0,0,0,0], <> colorLoads: REF ARRAY CD.Level OF ColorRef ]; StripFileName: PROC [index: INTEGER] RETURNS [name: Rope.ROPE] = BEGIN name _ IO.PutFR[ "///temp/plot%d.pd", IO.int[index+1]]; END; VersatecColorPlotComm: PROC [ comm: CDSequencer.Command ] = BEGIN TerminalIO.WriteRope["Colorplot\n"]; [] _ CDCommandOps.CallWithResource[ProtectedPlotDesign, comm, $ColorPlot, abortPlot]; END; signalFont: Graphics.FontRef _ NIL; plotter: Rope.ROPE _ "vice"; plotFileToSpool: Rope.ROPE _ "[vice]plot.pd"; plotFileOnPlotter: Rope.ROPE _ "plot.pd"; plotFileOnLocalMachine: Rope.ROPE _ "plot0.pd"; spoolToPlotter: BOOL _ TRUE; abortPlot: REF BOOL = NEW[BOOL _ FALSE]; ProtectedPlotDesign: PROC [comm: CDSequencer.Command] = BEGIN design: CD.Design = comm.design; plotClip: CD.DesignRect = CDBasics.ToRect[comm.pos, comm.sPos]; s: IO.STREAM _ NIL; n: INT _ TerminalIO.RequestInt["How many vertical strips? [1..10] "]; strips: INT _ MAX[1, MIN[10, n]]; BEGIN ENABLE { -- for ERRORs UNWIND => { s _ AbortFile[s]; CDViewer.RemoveArrow[design]; TerminalIO.WriteRope[" ** plot aborted ** "] }; }; dr: CD.DrawRef = CD.NewNullDeviceDrawRef[design]; scale: REAL _ MIN[maxPixPerLambda/CD.lambda, (REAL[scanLineWidth]+REAL[scanLineWidth-overLap]*(strips-1))/(plotClip.x2-plotClip.x1)]; <
> <<-- total number of pixels across plot = REAL[scanLineWidth]+REAL[scanLineWidth-overLap]*(strips-1))>> <<-- total width of design = plotClip.x2-plotClip.x1>> <<>> ps: PlotStateRef = NEW[ PlotState _ [ text: CornerStitching.NewTesselation[], scale: scale, totalPlotClip: plotClip, colorLoads: NEW[ARRAY CD.Level OF ColorRef_ALL[NIL]] ] ]; usedLevels: REF PACKED ARRAY CD.Level OF BOOL _ NIL; imageSSize _ (plotClip.y2-plotClip.y1)* scale; <<-- length of plot in pixels>> <<>> plotScale _ scale; <<>> IF debugging THEN { TerminalIO.WriteRope[" Scale factor (pixels/design#)*100 --> "]; TerminalIO.WriteInt[Real.RoundLI[plotScale*100]]; TerminalIO.WriteLn[]; }; <<>> TerminalIO.WriteRope["Starting Color Versatec plot "]; TerminalIO.WriteLn[]; TRUSTED {Process.SetPriority[Process.priorityBackground]}; dr.minimalSize _ 0; dr.drawRect _ dr.saveRect _ NoteLevel; dr.worldClip _ CDBasics.universe; dr.stopFlag _ abortPlot; dr.devicePrivate _ usedLevels _ NEW[PACKED ARRAY CD.Level OF BOOL _ ALL[FALSE]]; CDOps.DrawDesign[design, dr]; -- mark used levels dr.drawRect _ dr.saveRect _ NoteRectangle; dr.devicePrivate _ ps; FOR strip: INT IN [0..strips) DO <<-- Determine clip rectangle for strip>> clip: CD.DesignRect = [ x1: plotClip.x1+strip*((plotClip.x2-plotClip.x1)/strips), y1: plotClip.y1, x2: plotClip.x1+(strip+1)*((plotClip.x2-plotClip.x1)/strips)+ Real.Fix[overLap/scale]+1, y2: plotClip.y2]; tonerSet: PDFileWriter.TonerSet _ ALL[TRUE]; localFileName: Rope.ROPE = StripFileName[strip]; TerminalIO.WriteRope["Recording strip on file "]; TerminalIO.WriteRope[localFileName]; TerminalIO.WriteLn[]; pdState _ PDFileWriter.Create[ fileName: localFileName, deviceCode: versatec, sResolution: sRes, fResolution: fRes, imageSSize: Real.RoundC[imageSSize + 1], imageFSize: imageFSize, bandSSize: bandSSize, leftOverMode: FALSE]; ps.colorLoads^ _ ALL[NIL]; <<>> numBands _ 0; numRectangles _ 0; <<>> PDFileWriter.StartImage[pdState: pdState, toners: tonerSet]; <<-- For each band in the strip>> FOR topLine: INT _ 0, topLine+bandSSize WHILE topLine> pdx _ 0; pdy _ topLine; cdx _ clip.x1; cdy _ clip.y2 - Real.Fix[topLine*(1./scale)]; xoffset _ pdx - Real.Fix[cdx*scale]; yoffset _ pdy - Real.Fix[cdy*(-1*scale)]; <<-- (negative scale to account for CD increasing y north, PD increasing y going south)>> x1 _ (-1 - xoffset )/scale; y1 _ ((pdy + bandSSize +1) - yoffset)/(-scale); x2 _ (scanLineWidth - xoffset)/scale; y2 _ (pdy - yoffset)/(-scale); <<>> dc _ CDBasics.NormalizeRect[[x1: Real.Fix[x1], y1: Real.Fix[y1], x2: Real.Fix[x2], y2: Real.Fix[y2]]] ; ps.bandClip _ dr.worldClip _ [x1: MAX[plotClip.x1, dc.x1-1], y1: MAX[plotClip.y1, dc.y1-1], x2: MIN[plotClip.x2, dc.x2+1], y2: MIN[plotClip.y2, dc.y2+1]]; <<-- rectangle in design space that ChipNDale can use to clip its recursive drawing>> <<>> IF debugging THEN { TerminalIO.WriteLn; TerminalIO.WriteRope[" pdy: "]; TerminalIO.WriteInt[pdy]; TerminalIO.WriteLn; TerminalIO.WriteRope[" CD band: "]; TerminalIO.WriteInt[ps.bandClip.x1]; TerminalIO.WriteInt[ps.bandClip.y1]; TerminalIO.WriteInt[ps.bandClip.x2]; TerminalIO.WriteInt[ps.bandClip.y2]; TerminalIO.WriteLn }; <<--Display current band under consideration to pacify user>> CDViewer.ShowArrow[design: design, pos: [x: (dr.worldClip.x1+dr.worldClip.x2)/2, y: (dr.worldClip.y1+dr.worldClip.y2)/2]]; <<>> FOR l: CD.Level IN CD.Level DO IF ps.tes[l]#NIL THEN <<-- clear previous tessalations >> CornerStitching.ChangeRect[plane: ps.tes[l], rect: CDBasics.universe, newValue: NIL]; ENDLOOP; CDOps.DrawDesign[design, dr]; -- build tesselations of the relevant design rectangle AnalyzeTesselations[ps]; <<-- assign each level a texture and draw all the rectangles in the region>> numBands _ numBands + 1; TerminalIO.WriteRope["."]; ENDLOOP; -- for each band in the strip PDFileWriter.EndPage[pdState]; PDFileWriter.Close[pdState]; TerminalIO.WriteRope["*\n"]; ENDLOOP; -- for each strip <<>> TerminalIO.WriteRope[" finished plot(s)\n"]; IF debugging THEN { TerminalIO.WriteRope["# bands -> "]; TerminalIO.WriteInt[numBands]; TerminalIO.WriteRope[" # rectangles -> "]; TerminalIO.WriteInt[numRectangles]; TerminalIO.WriteLn; }; CDViewer.RemoveArrow[design: design]; EXITS AbortPlot => { s _ AbortFile[s]; CDViewer.RemoveArrow[design]; TerminalIO.WriteRope[" ** plot aborted ** "]; }; END; -- enable END; -- PlotDesign NoteLevel: PROC [ r: CD.DesignRect, l: CD.Level, pr: CD.DrawRef ] = BEGIN ps: REF PACKED ARRAY CD.Level OF BOOL = NARROW[pr.devicePrivate]; ps[l] _ TRUE; END; NoteRectangle: PROC [ r: CD.DesignRect, l: CD.Level, pr: CD.DrawRef ] = BEGIN ps: PlotStateRef = NARROW[pr.devicePrivate]; IF CDBasics.NonEmpty[r] THEN { IF ps.tes[l]=NIL THEN ps.tes[l] _ CornerStitching.NewTesselation[]; ps.tes[l].ChangeRect[rect: r, newValue: $covered]; }; END; TonerKey: PROC [toner: PDFileFormat.Toner] RETURNS [ATOM] = INLINE { RETURN [ SELECT toner FROM black => $CDxVersatecBlack, cyan => $CDxVersatecCyan, magenta => $CDxVersatecMagenta, yellow => $CDxVersatecYellow, ENDCASE => $CDxVersatecBlack ] }; AnalyzeTesselations: PROC [ ps: PlotStateRef ] = BEGIN FOR lev: CD.Level IN CD.Level DO IF ps.tes[lev]#NIL THEN { IF ps.colorLoads^[lev]=NIL THEN { tex: REF; ps.colorLoads^[lev] _ NEW[ColorLoad]; FOR toner: Ink IN Ink DO tex _ CDProperties.GetPropFromLevel[from: lev, prop: TonerKey[toner]]; ps.colorLoads^[lev][toner] _ (IF tex = NIL THEN whiteLoadRef ELSE MakeLoadref[tex]); ENDLOOP; }; FOR toner: Ink IN Ink DO IF ps.colorLoads^[lev][toner] = whiteLoadRef THEN PDFileWriter.SetColorOff[pdState, toner] ELSE PDFileWriter.SetColorTile[pdState, toner, ps.colorLoads^[lev][toner], transparent]; ENDLOOP; [] _ ps.tes[lev].EnumerateArea[ rect: ps.bandClip, perTile: ProcessTile, data: ps, backgroundValue: $none ]; }; ENDLOOP; END; ProcessTile: PROCEDURE [tile: CornerStitching.TilePtr, data: REF ANY] -- CornerStitching.PerTileProc -- = BEGIN -- only called on covered tiles rightBound, x1, y1, x2, y2: INT; pdx1, pdx2, pdy1, pdy2 : CARDINAL; sSize, fSize : CARDINAL; <> ps: PlotStateRef = NARROW[data]; tileValue: REF = tile.Value; IF tileValue = $covered THEN BEGIN r: CD.DesignRect = tile.Area; <<-- Calculate absolute coords of rectangle here as offset from plot origin>> x1 _ Real.RoundLI[xoffset + r.x1*plotScale]; y1 _ Real.RoundLI[yoffset + r.y1*(-plotScale)]; x2 _ Real.RoundLI[xoffset + r.x2*plotScale]; y2 _ Real.RoundLI[yoffset + r.y2*(-plotScale)]; rightBound _ Real.RoundLI[xoffset + ps.bandClip.x2*plotScale]; <<-- if rectangle is in bandarea, clip and write; otherwise disregard rectangle>> IF NOT ((( x1 > rightBound) OR (x2 < 0)) OR (( y1 < pdy) OR (y2 > MIN[imageSSize, pdy+bandSSize]))) THEN { pdx1 _ MAX[x1, 0]; pdx2 _ MIN[x2, rightBound, imageFSize]; pdy1 _ MIN[y1, pdy+bandSSize]; pdy2 _ MAX[y2, pdy]; fSize _ pdx2 - pdx1; sSize _ pdy1 - pdy2; <<-- can't have rectangles landing on or over the imageSSize>> IF pdy1 >= imageSSize THEN sSize _ Real.Fix[imageSSize - pdy2] ; <<-- disregard rectangles without area>> IF ((sSize # 0) AND (fSize # 0)) THEN { PDFileWriter.MaskRectangle[pdState: pdState, sMin: pdy2, fMin: pdx1, sSize: sSize, fSize: fSize]; <> numRectangles _ numRectangles + 1; IF debugging THEN { TerminalIO.WriteRope[" position -> "]; TerminalIO.WriteInt[Real.RoundLI[y1]]; TerminalIO.WriteInt[Real.RoundLI[x1]]; TerminalIO.WriteRope[" size -> "]; TerminalIO.WriteInt[sSize]; TerminalIO.WriteInt[fSize]; TerminalIO.WriteLn; } } } END; <<>> <<-- code for outlining rectangles>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> END; SignalValueRef: TYPE = REF SignalValue; SignalValue: TYPE = RECORD [s: Rope.ROPE]; LookForSignalName: PROC [ design: CD.Design, aptr: CD.ApplicationPtr, x: REF ] RETURNS [done: BOOL_FALSE, removeMe: BOOL_FALSE, include: CD.ApplicationList_NIL, repaintMe: BOOL_FALSE, repaintInclude: BOOL_FALSE] -- CDCallSpecific.CallProc -- = BEGIN <> GetSignalName: PROC [signal: REF] RETURNS [s: Rope.ROPE] = BEGIN WITH signal SELECT FROM atom: ATOM => s _ Atom.GetPName[atom]; rope: Rope.ROPE => s _ rope; ENDCASE => s _ "?"; END; <<>> <> <> <> <> <> <> <> <> <> <> <> <> <> END; PaintASignalName: PROC [tile: CornerStitching.TilePtr, data: REF ANY] RETURNS [REF ANY] -- CornerStitching.PerTileProc -- = BEGIN ps: PlotStateRef = NARROW[data]; <> <> <> <> <> <<[dx: dx, dy: dy] _ Graphics.Map[sc: ps.context[black], dc: ps.vPatch, sx: ctr.x, sy: ctr.y];>> <<[xmin: xmin, ymin: ymin, xmax: xmax, ymax: ymax] _ Graphics.RopeBox[font: signalFont, rope: signalValue.s];>> <> <(ymax-ymin)) # ((r.x2-r.x1)>(r.y2-r.y1)) THEN>> <> <> <> <> <> <> <> RETURN[data]; END; Stipple16: TYPE = ARRAY[0..16) OF CARDINAL; Stipple8: TYPE = ARRAY[0..8) OF [0..256); Stipple4: TYPE = ARRAY[0..4) OF [0..16); ToTexture: PROC [pattern: REF ANY] RETURNS [texture: Stipple16] = <<--tries to convert pattern to a texture stipple>> BEGIN IF pattern=NIL THEN RETURN[Stipple16[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]; -- should not occur WITH pattern SELECT FROM s16: REF Stipple16 => texture _ s16^; s8: REF Stipple8 => FOR i: [0..8) IN [0..8) DO texture[i] _ texture[i+8] _ (256+1)*s8[i]; ENDLOOP; s4: REF 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 => RETURN[Stipple16[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0FFFFH]]; -- error texture RETURN [texture] END; MakeLoadref: PROC [pattern: REF ANY] RETURNS [PDFileWriter.LoadReference] = TRUSTED BEGIN loadRef: PDFileWriter.LoadReference; texture: Stipple16 _ ToTexture[pattern]; loadRef _ PDFileWriter.LoadContiguousColorTile[pdState: pdState, phase: 0, sMin: 0, fMin: 0, sSize: 16, fSize: 16, bitsPtr: @texture]; RETURN[loadRef]; END; AbortFile: PROC [s: IO.STREAM ] RETURNS [ IO.STREAM ] = {IF s#NIL THEN s.Close[abort: TRUE]; RETURN[NIL]}; <<>> Init: PROC ~ { CDSequencer.ImplementCommand[a~$VersatecColorPlot, p~VersatecColorPlotComm]; <> CDMenus.CreateEntry[$RectProgramMenu, "Color Plot", $VersatecColorPlot]; TerminalIO.WriteRope["ChipNDale COLOR Versatec plotter loaded\n"]; }; Init[]; END. -- of CDColorVersatecImpl