CDPlotIPImpl.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Last Edited by: Jacobi, July 12, 1985 8:50:32 am PST
Last Edited by: Jacobi, October 16, 1985 11:18:36 am PDT
Last Edited by: Curry, March 27, 1986 6:57:17 pm PST
DIRECTORY
CD, CDBasics, CDCommandOps, CDIO, CDMenus, CDOps, CDPlot, CDProperties, CDSequencer, CDTexts, FS, Imager, ImagerInterpress, IO, PeachPrint, Process, Real, RefTab, Rope, SymTab, TerminalIO;
CDPlotIPImpl: CEDAR PROGRAM
IMPORTS CD, CDBasics, CDCommandOps, CDIO, CDMenus, CDOps, CDProperties, CDSequencer, CDTexts, FS, Imager, ImagerInterpress, IO, PeachPrint, Process, Real, RefTab, Rope, SymTab, TerminalIO =
BEGIN
Constants
defaultBorder:  REAL   = Imager.metersPerInch;
versatecColor42X: REAL   = 0.97; -- 42" Color plotter model ECP 42 / serial #110
Globals
abortFlag:   REF BOOL    = NEW[BOOLFALSE];
contextColors:  REF CD.ContextColors = NEW[CD.ContextColors←ALL[Imager.black]];
contextNormal:  BOOL      ← FALSE;
fontTab:    SymTab.Ref;
wDir:     Rope.ROPE;
RectToRectangle: PROC [r: CD.Rect] RETURNS [Imager.Rectangle] =
{RETURN [[x: r.x1, y: r.y1, w: r.x2-r.x1, h: r.y2-r.y1]]};
ResetContextFilter: PROC [ignoreProperties: BOOLTRUE] = {
contextNormal ← ignoreProperties;
FOR layer: CD.Layer IN CD.Layer DO
contextColors[layer] ← IF ignoreProperties THEN Imager.black ELSE NIL;
CDProperties.PutLayerProp[layer, $CDxInterpressPlot, NIL];
ENDLOOP;
contextColors[CD.backgroundLayer] ← NIL};
SetUpContextFilter: PROC [] = {
contextNormal ← FALSE;
FOR layer: CD.Layer IN CD.Layer DO
contextColors[layer] ← IF CDProperties.GetLayerProp[layer, $CDxInterpressPlot]=$do
THEN Imager.black ELSE NIL;
ENDLOOP;
contextColors[CD.backgroundLayer] ← NIL };
HardCopyCommand: PROC [comm: CDSequencer.Command] = {
IF comm.data = NIL
THEN TerminalIO.WriteRope["HardCopy\n"]
ELSE TerminalIO.WriteRope["Non interactive hardcopy\n"];
abortFlag^ ← FALSE;
[] ← CDCommandOps.CallWithResource[
proc:   ProtectedHardCopy,
comm:   comm,
resource:  $CDSimplePlotImpl,
abortFlag: abortFlag ]};
DrawOutLine: PUBLIC PROC [r: CD.Rect, l: CD.Layer, pr: CD.DrawRef] =
BEGIN
ActionWithContext: PROC [] =
BEGIN
Imager.SetColor[pr.deviceContext, pr.contextColors[l]];
Imager.MaskVector[pr.deviceContext, [r.x1, r.y1], [r.x2, r.y1]];
Imager.MaskVector[pr.deviceContext, [r.x2, r.y1], [r.x2, r.y2]];
Imager.MaskVector[pr.deviceContext, [r.x2, r.y2], [r.x1, r.y2]];
Imager.MaskVector[pr.deviceContext, [r.x1, r.y2], [r.x1, r.y1]];
END;
IF pr.deviceContext#NIL THEN {
IF pr.contextColors[l]#NIL THEN Imager.DoSave[pr.deviceContext, ActionWithContext]
}
END;
ProtectedHardCopy: PROC [comm: CDSequencer.Command] = { -- not re-entrant: uses globals
InteractiveSetUp: PROC [seqCom: CDSequencer.Command]
RETURNS [rec: REF CDPlot.IPControlRec] = {
rec ← NEW[CDPlot.IPControlRec ← [ ]];
rec.scale ← Imager.metersPerPoint/seqCom.design.technology.lambda; -- init as fixed
DialogFontSubstitute [rec];
DialogClipRect   [rec, seqCom];
DialogMedium   [rec];
SELECT rec.type FROM
stripe  => DialogStripedScaling  [rec];
fixed  => DialogFixedScaling  [rec];
ENDCASE => DialogVariableScaling [rec];
TerminalIO.WriteF[" printing %01g rows and %01g columns\n",
IO.int[rec.pageNumX], IO.int[rec.pageNumY]] };
DialogFontSubstitute: PROC[rec: REF CDPlot.IPControlRec] = {
SELECT TerminalIO.RequestSelection["substitute fonts ?", LIST
["no substitution", "standard substitution file", "user substitution file"]] FROM
2 => {
rec.altFonts  ← TRUE;
rec.altFontsFile ← NIL;
TerminalIO.WriteRope["use standard font substitution file\n"]};
3 => {
rec.altFonts  ← TRUE;
rec.altFontsFile ← TerminalIO.RequestRope
["fullpath name for font substitution file > "]};
ENDCASE => {
rec.altFonts  ← FALSE;
rec.altFontsFile ← NIL;
TerminalIO.WriteRope["don't substitute fonts\n"]} };
DialogClipRect: PROC [rec: REF CDPlot.IPControlRec, seqCom: CDSequencer.Command] = {
n: INT ← TerminalIO.RequestSelection[label: "plot area",
choice: LIST["complete design", "area of selection", "drawn rectangle"] ];
SELECT n FROM
3 => {
TerminalIO.WriteRope["plot rectangular area drawn\n"];
rec.clip ← CDBasics.ToRect[seqCom.pos, seqCom.sPos] };
2 => {
TerminalIO.WriteRope["plot area of selection\n"];
rec.clip ← CDCommandOps.BoundingBox[design: seqCom.design, onlySelected: TRUE] };
ENDCASE => {
TerminalIO.WriteRope["plot complete design\n"];
rec.clip ← CDCommandOps.BoundingBox[design: seqCom.design, onlySelected: FALSE] };
IF ~CDBasics.NonEmpty[rec.clip] THEN {
TerminalIO.WriteRope["rec.clip rectangle is empty\n"];
ERROR ABORTED} };
DialogMedium: PROC[rec: REF CDPlot.IPControlRec] = {
SELECT TerminalIO.RequestSelection["Plot", LIST
["standard page and scale", "fill standard page", "fill versatec stripe", "fill c400 page", "other"]] FROM
1   => {rec.type ← fixed; TerminalIO.WriteRope["standard page and scale\n"] };
3   => {rec.type ← stripe; TerminalIO.WriteRope["fill versatec stripe\n"] };
4   => {rec.pageX ← CDPlot.c400PageX; rec.pageY ← CDPlot.c400PageY;
TerminalIO.WriteRope["fill c400 page\n"] };
5   => {
TerminalIO.WriteRope["special:\n"];
rec.special ← TRUE;
SELECT TerminalIO.RequestSelection["Plot", LIST
["fill standard pages", "fill versatec stripes", "standard scale standard pages", "fill c400 pages", "standard scale c400 pages"]] FROM
1 => {rec.type ← variable; TerminalIO.WriteRope["fill standard pages\n"] };
2 => {rec.type ← stripe;  TerminalIO.WriteRope["fill versatec stripes\n"] };
3 => {rec.type ← fixed; TerminalIO.WriteRope["standard scale standard pages\n"] };
4 => {
rec.pageX  ← CDPlot.c400PageX;
rec.pageY  ← CDPlot.c400PageY;
TerminalIO.WriteRope["standard scale standard pages\n"] };
5 => {
rec.pageX  ← CDPlot.c400PageX;
rec.pageY  ← CDPlot.c400PageY;
rec.type ← fixed;
TerminalIO.WriteRope["standard scale standard pages\n"] };
ENDCASE => ERROR ABORTED };
ENDCASE => {rec.type ← variable; TerminalIO.WriteRope["fill standard page\n"]} };
DialogStripedScaling: PROC[rec: REF CDPlot.IPControlRec] = {
IF rec.special AND TerminalIO.Confirm["multiple stripes ?"]
THEN {
rec.pageNumX ← TerminalIO.RequestInt["How many stripes? >"];
IF rec.pageNumX NOT IN [1..20]
THEN {TerminalIO.WriteRope[" to bad\n"]; ERROR ABORTED} }
ELSE rec.pageNumX ← 1;
rec.borders ← no;
help ← IO.PutFR["%g versatec; PeachPrint Sleepy %g\n",
IO.rope[help], IO.rope[PeachPrint.FileName[long, secondary, 1, ".pd"]]] };
DialogFixedScaling: PROC[rec: REF CDPlot.IPControlRec] = {
DialogBorder[rec, IPRoomForBorders[rec]];
help ← IO.PutFR["%g raven384; TSetter Stinger %g\n",
IO.rope[help], IO.rope[PeachPrint.FileName[long, secondary, 1, ".pd"]]] };
DialogVariableScaling: PROC[rec: REF CDPlot.IPControlRec] = {
dontAdj: BOOLFALSE;
rec.specialMults rec.special AND TerminalIO.Confirm["multiple pages ?"];
IF rec.specialMults THEN {
rec.pageNumX ← TerminalIO.RequestInt["Number of pages in x direction? >"];
IF rec.pageNumX NOT IN [1..20]
THEN {TerminalIO.WriteRope[" to bad\n"]; ERROR ABORTED} };
DialogBorder[rec, NOT rec.specialMults];
help ← IO.PutFR["%g raven384; TSetter Stinger %g\n",
IO.rope[help], IO.rope[PeachPrint.FileName[long, secondary, 1, ".pd"]]] };
DialogBorder: PROC [rec: REF CDPlot.IPControlRec, anyWay: BOOLFALSE] = {
rec.borders ← IF (anyWay AND ~rec.special)
THEN no ELSE SELECT TerminalIO.RequestSelection[label: "border", choice: LIST
["yes", "fill space", "never"]] FROM
2   => no,
3   => mosaic,
ENDCASE => yes };
PreAmble: PROC [ref: ImagerInterpress.Ref, contextColors: REF CD.ContextColors] = {
declared: RefTab.Ref ← RefTab.Create[];
FOR layer: CD.Layer IN CD.Layer DO
IF contextColors[layer]#NIL THEN
IF RefTab.Insert[declared, contextColors[layer], contextColors[layer]] THEN
ImagerInterpress.DeclareColor[ref, contextColors[layer]]
ENDLOOP;
declared ← NIL};
PlotPage: PROC [context: Imager.Context] = {-- the real stuff
dr: CD.DrawRef;
r: CD.Rect ← CDBasics.RectAt[start, ipc.sizePerPage];
r ← CDBasics.Intersection [r, ipc.clip];
IF ~ CDBasics.NonEmpty [r] THEN RETURN;
Process.CheckForAbort[! ABORTED => {abortFlag^ ← TRUE; CONTINUE}];
IF abortFlag^ THEN RETURN;
Imager.TranslateT  [context, ipc.transPos];
Imager.ScaleT   [context, ipc.scale];
Imager.TranslateT  [context, [-r.x1, -r.y1]];
Imager.ClipRectangle [context, RectToRectangle[r]];
dr ← CD.CreateDrawRef[[
design:   comm.design,
stopFlag:   abortFlag,
drawOutLine: DrawOutLine,
contextColors: contextColors,
borders:   TRUE,
interestClip:  r,
deviceContext: context
]];
IF ipc.altFonts THEN {
dr.specialFonts ← TRUE;
CDProperties.PutProp[dr.properties, $FontExchange, fontReplace] };
CDOps.DrawDesign[comm.design, dr]};
fileName: Rope.ROPE ← PeachPrint.FileName[long, primary,1, ".ip"];
help:  Rope.ROPE;
start:  CD.Position;
ref:  ImagerInterpress.Ref;
ipc:  REF CDPlot.IPControlRec ← NARROW[comm.data];
help ← IO.PutFR[" Example usage:\n InterpressToPD %g ← %g ",
IO.rope[PeachPrint.FileName[long, secondary, 1, ".pd"]],
IO.rope[fileName]];
IF ~contextNormal THEN
{TerminalIO.WriteRope["** SPECIAL COLORS\n"]; SetUpContextFilter[] };
IF ipc=NIL
THEN ipc ← InteractiveSetUp[comm]
ELSE ipc.scale ← Imager.metersPerPoint/comm.design.technology.lambda; -- init fixed scale
IPBorders[ipc];
SELECT ipc.type FROM
stripe  => IPSetUpStripedScaling [ipc];
fixed  => IPSetUpFixedScaling  [ipc];
ENDCASE => IPSetUpVariableScaling [ipc];
IF ipc.borders#mosaic THEN IPAdjustTransPos[ipc];
fontTab ← IF ipc.altFonts THEN InitFontTab[ipc.altFontsFile] ELSE NIL;
ref  ← ImagerInterpress.Create[fileName];
PreAmble[ref, contextColors];
FOR nX: INT IN [0..ipc.pageNumX) DO
FOR nY: INT IN [0..ipc.pageNumY) DO
IF abortFlag^ THEN EXIT;
start.x ← ipc.clip.x1+nX*ipc.sizePerPage.x;
start.y ← ipc.clip.y1+nY*ipc.sizePerPage.y;
ImagerInterpress.DoPage[ref, PlotPage];
ENDLOOP;
ENDLOOP;
ImagerInterpress.Close[ref];
TerminalIO.WriteF1[" ""%01g"" created\n", IO.rope[fileName]];
IF ~Rope.IsEmpty[help] THEN TerminalIO.WriteRope[help];
IF ~abortFlag^ THEN TerminalIO.WriteRope[" done\n"] };
-- Scaling procedures
IPRoomForBorders: PROC[ipc: REF CDPlot.IPControlRec] RETURNS[BOOL] = {
RETURN[
( (ipc.clip.x2-ipc.clip.x1) *ipc.scale < (ipc.pageX - 0.05) ) AND
( (ipc.clip.y2-ipc.clip.y1) *ipc.scale < (ipc.pageY - 0.05) )] };
IPBorders: PROC[ipc: REF CDPlot.IPControlRec] =
{IF ipc.borders=yes THEN ipc.transPos.y ← ipc.transPos.x ← defaultBorder};
IPSetUpStripedScaling: PROC[ipc: REF CDPlot.IPControlRec] = {
ipc.pageX    ← versatecColor42X;
ipc.pageNumY  ← 1;
ipc.transPos.x   ← 0;
ipc.transPos.y  ← defaultBorder;
ipc.sizePerPage.x  ← (ipc.clip.x2-ipc.clip.x1)/ipc.pageNumX;
ipc.sizePerPage.y ← ipc.clip.y2-ipc.clip.y1;
ipc.scale    ← ipc.pageX/ipc.sizePerPage.x;
ipc.pageY    ← ipc.scale*ipc.sizePerPage.y+2*ipc.transPos.y };
IPSetUpFixedScaling: PROC[ipc: REF CDPlot.IPControlRec] = {
ipc.scale    ← ipc.scale;
ipc.sizePerPage.x  ← Real.Round[(ipc.pageX-2*ipc.transPos.x)/ipc.scale];
ipc.sizePerPage.y ← Real.Round[(ipc.pageY-2*ipc.transPos.y)/ipc.scale];
ipc.pageNumX  ← (ipc.clip.x2-ipc.clip.x1+ipc.sizePerPage.x-1)/ipc.sizePerPage.x;
ipc.pageNumY  ← (ipc.clip.y2-ipc.clip.y1+ipc.sizePerPage.y-1)/ipc.sizePerPage.y };
IPSetUpVariableScaling: PROC[ipc: REF CDPlot.IPControlRec] = {
insidePageX: REAL ← ipc.pageX-2*ipc.transPos.x; --what fits in a page without border
insidePageY: REAL ← ipc.pageY-2*ipc.transPos.y; --what fits in a page without border
IF ipc.specialMults
THEN { --multiple pages
ipc.sizePerPage.x ← (ipc.clip.x2-ipc.clip.x1)/ipc.pageNumX+1;
ipc.sizePerPage.y ← Real.Fix[insidePageY*((ipc.sizePerPage.x-1.0)/insidePageX)];
ipc.scale   ← insidePageX/ipc.sizePerPage.x;
ipc.pageNumY ← ( (ipc.clip.y2-ipc.clip.y1)+(ipc.sizePerPage.y-1) )/ipc.sizePerPage.y }
ELSE { --single page
ipc.pageNumX ← 1;
ipc.pageNumY ← 1;
ipc.sizePerPage ← CDBasics.SizeOfRect[ipc.clip];
ipc.scale   ← MIN[insidePageX/ipc.sizePerPage.x, insidePageY/ipc.sizePerPage.y]}};
IPAdjustTransPos: PROC [ipc: REF CDPlot.IPControlRec] = {
IF ipc.type=stripe OR ipc.pageNumX=1 THEN {
ipc.transPos.x ← MIN[(ipc.pageX - (ipc.clip.x2-ipc.clip.x1)*ipc.scale)/2, defaultBorder] };
IF ipc.pageNumY=1 THEN {
pictureHeight: REAL ← (ipc.clip.y2-ipc.clip.y1)*ipc.scale;
ipc.transPos.y ← MAX[ipc.pageY-defaultBorder-pictureHeight, (ipc.pageY-pictureHeight)/2]} };
-- Font replacement stuff
fontReplace: REF PROC [CDTexts.CDFont] RETURNS [CDTexts.CDFont]
NEW[PROC [CDTexts.CDFont] RETURNS [CDTexts.CDFont] ← FontReplace];
FontReplace: PROC [cdFont: CDTexts.CDFont] RETURNS [CDTexts.CDFont] = {
newFont: CDTexts.CDFont ← NIL;
fontKey: Rope.ROPE ← FontKeyRope[cdFont.supposedName, cdFont.scaleI];
WITH SymTab.Fetch[fontTab, fontKey].val SELECT FROM
f: CDTexts.CDFont => RETURN [f];
f: REF CDTexts.FontRec => RETURN [f];
ENDCASE => NULL;
WITH SymTab.Fetch[fontTab, cdFont.supposedName].val SELECT FROM
l: LIST OF REF ANY => {
IF l.first#NIL AND l.rest#NIL AND l.rest.rest=NIL THEN {
scale: INT ← 0;
name: Rope.ROPE ← CDCommandOps.ToRope[l.first];
WITH l.rest.first SELECT FROM
ri: REF INT => scale ← ri^*cdFont.scaleI
ENDCASE => NULL;
IF scale>0 AND ~Rope.IsEmpty[name] THEN {
newFont ← CDTexts.MakeFont[name, scale];
IF newFont#NIL THEN {
x: REF CDTexts.FontRec;
TRUSTED {x ← LOOPHOLE[newFont]};
[] ← SymTab.Store[fontTab, fontKey, x] } } } };
f: CDTexts.CDFont => newFont ← f;
f: REF CDTexts.FontRec => newFont ← f;
ENDCASE => NULL;
IF newFont=NIL THEN newFont�ont;
RETURN [newFont] };
FontKeyRope: PROC[name: Rope.ROPE, scale: INT] RETURNS[key: Rope.ROPE] =
{RETURN[ IO.PutFR["%g-%g", IO.rope[name], IO.int[scale] ]]};
InitFontTab: PROC [fileName: Rope.ROPENIL] RETURNS [fontTab: SymTab.Ref] = {
OneLine: PROC [line: Rope.ROPE] = {
stream: IO.STREAMIO.RIS[line];
scale: INT;
subst, by: Rope.ROPE;
subst ← IO.GetRopeLiteral[stream];
by ← IO.GetRopeLiteral[stream];
scale ← IO.GetInt[stream];
[] ← fontTab.Store[subst, LIST[by, NEW[INT←scale]]] };
file: IO.STREAMNIL;
fontTab ← SymTab.Create[];
IF Rope.IsEmpty[fileName] THEN fileName ← "CDSubstituteFonts";
fileName ← CDIO.MakeName[base: fileName, ext: "SubstituteFonts", wDir: wDir];
file ← FS.StreamOpen[fileName ! FS.Error => {
TerminalIO.WriteRopes["no font substitution: ", error.explanation, "\n"];
GOTO thatsIt }];
DO
line: Rope.ROPE;
line ← IO.GetLineRope[file ! IO.EndOfStream => GOTO thatsIt];
IF ~Rope.IsEmpty[line] THEN
OneLine[line !
IO.EndOfStream => GOTO thatsIt;
IO.Error => {
TerminalIO.WriteRopes["**error reading font substitution: ", line, "\n"];
CONTINUE } ];
ENDLOOP;
EXITS thatsIt => NULL };
-- Init
Init: PROC = {
OPEN CDS: CDSequencer;
wDir ← FileNames.CurrentWorkingDirectory[];
wDir ← CDIO.GetWorkingDirectory[NIL];
ResetContextFilter[ignoreProperties: TRUE];
CDS.ImplementCommand[key: $IPAutoPlot,  proc: HardCopyCommand, queue: dontQueue];
CDS.ImplementCommand[key: $InterpressPlot, proc: HardCopyCommand, queue: doQueue];
CDMenus.CreateEntry[menu: $HardCopyMenu, entry: "B&W interpress", key: $InterpressPlot];
TerminalIO.WriteRope["BW Interpress plot loaded.\n"] };
Init[];
END.