CDColorVersatecImpl.mesa
Copyright © 1983, 1984 by Xerox Corporation. All rights reserved.
written by E. McCreight, August 1, 1983 2:00 PM
Last Edited by: McCreight, November 23, 1983 4:58 pm
Last Edited by: Jacobi, October 27, 1983 12:36 pm
Last Edited by: Jacobi, November 5, 1984 3:11:09 pm PST
Last Edited by: Kimr, October 29, 1984 9:49:48 am PST
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;
??? PDFileWriter seems to require that some value be given; at the current time, there wasn't one for versatec so I chose the only unassigned value
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: BOOLFALSE;
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],
rectangles in design space touching all geometry in the plot, or this band
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]<sysdir>plot.pd";
plotFileOnPlotter: Rope.ROPE ← "<sysdir>plot.pd";
plotFileOnLocalMachine: Rope.ROPE ← "plot0.pd";
spoolToPlotter: BOOLTRUE;
abortPlot: REF BOOL = NEW[BOOLFALSE];
ProtectedPlotDesign: PROC [comm: CDSequencer.Command] =
BEGIN
design: CD.Design = comm.design;
plotClip: CD.DesignRect = CDBasics.ToRect[comm.pos, comm.sPos];
s: IO.STREAMNIL;
n: INT ← TerminalIO.RequestInt["How many vertical strips? [1..10] "];
strips: INTMAX[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: REALMIN[maxPixPerLambda/CD.lambda, (REAL[scanLineWidth]+REAL[scanLineWidth-overLap]*(strips-1))/(plotClip.x2-plotClip.x1)];
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))
-- 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 BOOLNIL;
imageSSize ← (plotClip.y2-plotClip.y1)* scale;
-- length of plot <in slow direction> 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 BOOLALL[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<imageSSize DO
x1, y1, x2, y2: REAL;
dc: CD.DesignRect;
IF abortPlot^ THEN GOTO AbortPlot;
-- Determine coordinate transformations
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;
t: CornerStitching.TilePtr;
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];
TerminalIO.WriteRope["+"];
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
Put lines at boundaries with regions of other color
FOR t ← tile.NEastNeighbour, t.WSouthNeighbour WHILE tile.SouthEdge<t.NorthEdge DO
going south along east edge of tile
IF t.Value#tileValue THEN
BEGIN
ps.context[black].SetCP[x: tile.EastEdge, y: MAX[tile.SouthEdge, t.SouthEdge]];
ps.context[black].DrawTo[x: tile.EastEdge, y: MIN[tile.NorthEdge, t.NorthEdge]];
END;
ENDLOOP;
FOR t ← tile.ENorthNeighbour, t.SWestNeighbour WHILE tile.WestEdge<t.EastEdge DO
going west along north edge of tile
IF t.Value#tileValue THEN
BEGIN
ps.context[black].SetCP[x: MAX[tile.WestEdge, t.WestEdge], y: tile.NorthEdge];
ps.context[black].DrawTo[x: MIN[tile.EastEdge, t.EastEdge], y: tile.NorthEdge];
END;
ENDLOOP;
END;
SignalValueRef: TYPE = REF SignalValue;
SignalValue: TYPE = RECORD [s: Rope.ROPE];
LookForSignalName: PROC [ design: CD.Design, aptr: CD.ApplicationPtr, x: REF ] RETURNS [done: BOOLFALSE, removeMe: BOOLFALSE, include: CD.ApplicationList←NIL,
repaintMe: BOOLFALSE, repaintInclude: BOOLFALSE] -- CDCallSpecific.CallProc -- =
BEGIN
This area needs considerable improvement. The ultimate goal is to find a place to put the signal name where it will not be confused with any other geometry (than the named piece, or continuations on the same layer) or signal name.
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;
ps: PlotStateRef = NARROW[x];
r: CD.DesignRect = CDBasics.Intersection[ps.totalPlotClip, CDApplications.ApplicationRect[aptr]];
signal: REF = CDProperties.GetProp[from: aptr, prop: $SignalName];
IF signal # NIL AND CDBasics.NonEmpty[r] THEN
BEGIN
signalValue: SignalValueRef = NEW[SignalValue ← [s: GetSignalName[signal]]];
others: LIST OF REF CornerStitching.Region = NARROW[ps.text.EnumerateArea[rect: r]];
ps.text.ChangeRect[rect: r, newValue: signalValue];
FOR other: LIST OF REF CornerStitching.Region ← others, other.rest WHILE other#NIL DO
ps.text.ChangeRect[rect: other.first.rect, newValue: other.first.value];
ENDLOOP;
END
ELSE done ← FALSE;
END;
PaintASignalName: PROC [tile: CornerStitching.TilePtr, data: REF ANY] RETURNS [REF ANY] -- CornerStitching.PerTileProc -- =
BEGIN
ps: PlotStateRef = NARROW[data];
textContext: Graphics.Context = ps.vPatch[black].CopyContext[];
signalValue: SignalValueRef = NARROW[tile.Value[]];
dx, dy, xmin, xmax, ymin, ymax: REAL;
r: CD.DesignRect = CDBasics.Intersection[tile.Area, ps.totalPlotClip];
ctr: CD.DesignPosition = CDBasics.Center[r];
[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];
textContext.Translate[tx: dx-(xmax+xmin)/2, ty: dy-(ymax+ymin)/2]; -- centers the text in r
IF ((xmax-xmin)>(ymax-ymin)) # ((r.x2-r.x1)>(r.y2-r.y1)) THEN
textContext.Rotate[270];
textContext.SetColor[Graphics.white];
textContext.DrawBox[[xmin: -2, ymin: -2, xmax: xmax-xmin+2, ymax: ymax-ymin+2]];
leave a two-scan-line white patch all around
textContext.SetColor[Graphics.black];
textContext.SetCP[x: 0, y: 0];
textContext.DrawRope[rope: signalValue.s, font: signalFont];
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];
signalFont ← VFonts.GraphicsFont[VFonts.EstablishFont[family: "Helvetica", size: 18, bold: TRUE]];
CDMenus.CreateEntry[$RectProgramMenu, "Color Plot", $VersatecColorPlot];
TerminalIO.WriteRope["ChipNDale COLOR Versatec plotter loaded\n"];
};
Init[];
END. -- of CDColorVersatecImpl