DIRECTORY Args USING [Arg, ArgsGet, Error, NArgs], Atom USING [MakeAtom], BasicTime USING [GMT, Now, OutOfRange, Period, ToNSTime, Update], CD USING [commentLayer, ContextColors, CreateDrawRef, Design, DrawProc, DrawContextProc, DrawRectProc, DrawRef, Instance, InstanceList, Layer, Number, Object, Position, Rect, undefLayer], CDBasics USING [BaseOfRect, ImagerTransform, Intersection, NonEmpty, SizeOfRect], CDDirectory USING [EachEntryAction, Enumerate], CDCurves USING [CurveSpecific], CDOps USING [DrawDesign, InstList], CDProperties USING [GetListProp], CDTexts USING [TextSpecific], CDValue USING [Fetch], Commander USING [CommandProc, Register], CStitching USING [all, Area, ChangeEnumerateArea, ChangeRect, DumpCache, EnumerateArea, EnumerateNeighborhood, NewTesselation, RectProc, Region, ResetTesselation, Tesselation, Tile, TileProc], D2Orient USING [Orientation], FS USING [ComponentPositions, Error, ExpandName, FileInfo, Position], Imager USING [ClipRectangle, ColorOperator, ConcatT, Context, ConstantColor, DoSave, Font, MaskBitmap, MaskDashedStrokeTrajectory, MaskFillTrajectory, MaskRectangle, MaskStrokeTrajectory, MaskVector, MaskVectorI, PutProp, Rectangle, ScaleT, SetColor, SetFont, SetPriorityImportant, SetStrokeEnd, SetStrokeJoint, SetStrokeWidth, SetXY, ShowRope, StrokeEnd, StrokeJoint, TranslateT, VEC], ImagerColor USING [ColorOperator, ConstantColor, NewColorOperatorRGB, RGB], ImagerColorFns USING [NewColorOperatorCMYK], ImagerColorPrivate USING [RGBFromColor], ImagerFont USING [Find, FontBoundingBox, Modify, RopeBoundingBox, RopeEscapement, Scale, Substitution, Typeface, TypefaceRep], ImagerInterpress USING [Close, Create, DeclareColorOperator, DeclareFont, DoPage, Ref], ImagerPath USING [LineToX, LineToY, MoveTo, Trajectory], ImagerSample USING [Box, Clear, Fill, NewSampleMap, RasterSampleMap, Trim], ImagerTransformation USING [Cat, Create, Invert, Rotate, Scale2, Transformation, Translate], ImagerTypeface USING [TypefaceRep], IO USING [bool, card, int, PutFR, PutFR1, real, rope, time], MessageWindow USING [Append, Blink, Clear], Nectarine, NectarineAids USING [ComposeRegisterMarks], NectarineColors USING [Bitset, blackBlack, Blend, BlendTileColours, BlendRec, ResetColourStatistics, Color, NumberOfColours, ColourTile, colSubDef, DeclareColours, IthColour, LayerColour, ListColourStatistics, orableBackground, ReadMap, ResetLayerColourTable, SetLayerColourTable, traceColourInferences, unColour], NectarinePd USING [field, PdPrintProcess], NodeStyle USING [FontFace], NodeStyleFont USING [FontFromStyleParams], PrincOpsUtils USING [], Process USING [CheckForAbort, Detach, priorityBackground, SetPriority], Real USING [Fix, Float, Round], RefTab USING [Create, Delete, EachPairAction, Fetch, GetSize, Insert, Pairs, Ref], Rope USING [Cat, Concat, Equal, Fetch, IsEmpty, Length, Replace, ROPE, SkipTo, Substr], SafeStorage USING [ReclaimCollectibleObjects], TerminalIO USING [PutF, PutRope], UserCredentials USING [Get], UserProfile USING [Boolean, CallWhenProfileChanges, ProfileChangedProc, Token], XNSPrint USING [Context, Error, GetDefaults, PrintFromFile]; NectarineImpl: CEDAR PROGRAM IMPORTS Args, Atom, BasicTime, CD, CDBasics, CDDirectory, CDOps, CDProperties, CDValue, Commander, CStitching, FS, Imager, ImagerColor, ImagerColorFns, ImagerColorPrivate, ImagerFont, ImagerInterpress, ImagerPath, ImagerSample, ImagerTransformation, IO, MessageWindow, NectarineAids, NectarineColors, NectarinePd, NodeStyleFont, Process, Real, RefTab, Rope, SafeStorage, TerminalIO, UserProfile, UserCredentials, XNSPrint EXPORTS ImagerFont, Nectarine ~ BEGIN OPEN NectarineColors, NectarinePd, Real; break: SIGNAL ~ CODE; -- for debugging invalidPrinter: PUBLIC SIGNAL ~ CODE; communicationsFailure: PUBLIC SIGNAL ~ CODE; tooComplex: PUBLIC SIGNAL ~ CODE; layout, showTesselation, ignoreAnnotation, imageRegions: BOOL _ FALSE; letChipndaleCallTheImager, centerSignalNames: BOOL _ TRUE; signalNameFont: Font _ NIL; outline: REAL _ -1.0; risk: INT _ 2; -- decrease if Nectarine runs out of VM. More risk mean much more speed. Geometric interpretation: consider a horizontal straight line through the design; you state that you have a rectangle only each risk l. At zero risk, Nectarine uses only 14 MB of memory in the worst case. Font: TYPE ~ Imager.Font; Typeface: TYPE ~ REF TypefaceRep; TypefaceRep: PUBLIC TYPE ~ ImagerTypeface.TypefaceRep; Transformation: TYPE ~ ImagerTransformation.Transformation; Hyperplane: TYPE ~ RECORD [used: BOOL _ FALSE, hyp: ImagerSample.RasterSampleMap]; ColorRegion: TYPE ~ REF ColorRegionRep; ColorRegionRep: TYPE ~ RECORD [SEQUENCE size: NAT OF Hyperplane]; ROPE: TYPE ~ Rope.ROPE; Box: TYPE ~ ImagerSample.Box; State: TYPE ~ REF StateRec; StateRec: TYPE ~ RECORD [ previousColour: Color _ NIL, previousStrokeWidth: REAL _ -1.0, previousFont: Font _ NIL, previousTextOrientation: D2Orient.Orientation _ original, cardTile: CARD _ 0, -- |{tile}| startTime: BasicTime.GMT, context: Imager.Context, ipName: ROPE, design: CD.Design, interpress: ImagerInterpress.Ref, tess: Tess, abort: REF BOOL, clip: BOOL _ FALSE, -- Wysiwyg or selectedOnly cdClip: CD.Rect, -- Wysiwyg or selectedOnly selectedOnly: BOOL, singleLayer: BOOL _ FALSE, -- only the layer of interset will be printed layerOfInterest: CD.Layer _ CD.undefLayer, isFirstPage, isLastPage: BOOL _ TRUE, substituteColor: BOOL _ colSubDef, band: REF CD.Rect _ NIL, bitmapScale: REAL _ 0.0, -- Versatec hack only colorRegion: ColorRegion _ NIL]; statistics: BOOL _ FALSE; debug: BOOL _ FALSE; remindFontConventions: BOOL _ TRUE; minInteger: INT ~ INTEGER.FIRST; maxInteger: INT ~ INTEGER.LAST; regionShrink: INT _ 4; mmXin: REAL ~ 25.4; versatecWidth: REAL ~ 8000; -- 40 inches at 200 bits per inch versatecLength: REAL ~ 32600; -- 163 inches at 200 bits per inch versatecWidthInMM: REAL ~ 40 * mmXin; versatecLengthInMM: REAL ~ 163 * mmXin; versatecResolution: REAL ~ 0.001 / 200 * mmXin; Region: TYPE ~ LIST OF REF CStitching.Region; Tess: TYPE ~ CStitching.Tesselation; Tile: TYPE ~ CStitching.Tile; TileAndContext: TYPE ~ REF TcRec; TcRec: TYPE ~ RECORD [tile: Tile, context: Imager.Context]; empty: REF ~ NIL; nothing: REF INT ~ NEW [INT]; StartDecomposition: PROC [state: State] RETURNS [dec: Tess] ~ {RETURN [CStitching.NewTesselation[stopFlag: state.abort]]}; FlushDecomposition: PROC [dec: Tess] ~ BEGIN CStitching.ResetTesselation [dec] END; -- FlushDecomposition FastMaskVector: PROC [context: Imager.Context, x1, y1, x2, y2: INT] ~ BEGIN IF ((x1 >= minInteger) AND (y1 >= minInteger) AND (x2 <= maxInteger) AND (y2 <= maxInteger)) THEN context.MaskVectorI [x1, y1, x2, y2] ELSE context.MaskVector [[Float[x1], Float[y1]], [Float[x2], Float[y2]]] END; -- FastMaskVector SouthRim: CStitching.TileProc ~ BEGIN tc: TileAndContext ~ NARROW [data]; IF (tile.value # tc.tile.value) THEN BEGIN tr: CD.Rect ~ tc.tile.Area; nr: CD.Rect ~ tile.Area; x1: INT ~ MAX [tr.x1, nr.x1]; x2: INT ~ MIN [tr.x2, nr.x2]; b: Blend ~ NARROW [tile.value]; IF (x1 < x2) AND ((b = NIL) OR (b.blend # blackBlack)) THEN FastMaskVector [tc.context, x1, tr.y1, x2, tr.y1] END END; -- SouthRim EastRim: CStitching.TileProc ~ BEGIN tc: TileAndContext ~ NARROW [data]; IF (tile.value # tc.tile.value) THEN BEGIN tr: CD.Rect ~ tc.tile.Area; nr: CD.Rect ~ tile.Area; y1: INT ~ MAX [tr.y1, nr.y1]; y2: INT ~ MIN [tr.y2, nr.y2]; b: Blend ~ NARROW [tile.value]; IF (y1 < y2) AND ((b = NIL) OR (b.blend # blackBlack)) THEN FastMaskVector [tc.context, tr.x2, y1, tr.x2, y2] END END; -- EastRim NorthRim: CStitching.TileProc ~ BEGIN tc: TileAndContext ~ NARROW [data]; IF (tile.value # tc.tile.value) THEN BEGIN tr: CD.Rect ~ tc.tile.Area; nr: CD.Rect ~ tile.Area; x1: INT ~ MAX [tr.x1, nr.x1]; x2: INT ~ MIN [tr.x2, nr.x2]; b: Blend ~ NARROW [tile.value]; IF (x1 < x2) AND ((b = NIL) OR (b.blend # blackBlack)) THEN FastMaskVector [tc.context, x1, tr.y2, x2, tr.y2] END END; -- NorthRim WestRim: CStitching.TileProc ~ BEGIN tc: TileAndContext ~ NARROW [data]; IF (tile.value # tc.tile.value) THEN BEGIN tr: CD.Rect ~ tc.tile.Area; nr: CD.Rect ~ tile.Area; y1: INT ~ MAX [tr.y1, nr.y1]; y2: INT ~ MIN [tr.y2, nr.y2]; b: Blend ~ NARROW [tile.value]; IF (y1 < y2) AND ((b = NIL) OR (b.blend # blackBlack)) THEN FastMaskVector [tc.context, tr.x1, y1, tr.x1, y2] END END; -- WestRim PrintTile: CStitching.TileProc ~ BEGIN state: State ~ NARROW [data]; colour: Blend ~ NARROW [tile.value]; r: CD.Rect ~ CStitching.Area [tile]; -- not the area but the rectangle ! ChangeColour [state, colour.blend]; state.context.MaskRectangle [ImagerRect [r]]; IF state.abort^ THEN ERROR ABORTED; IF (outline >= 0.0) AND (colour.blend # blackBlack) THEN BEGIN ChangeColour [state, blackBlack]; ChangeStrokeWidth [state, outline]; IF showTesselation THEN BEGIN FastMaskVector [state.context, r.x1, r.y1, r.x2, r.y1]; -- South FastMaskVector [state.context, r.x2, r.y1, r.x2, r.y2]; -- East FastMaskVector [state.context, r.x2, r.y2, r.x1, r.y2]; -- North FastMaskVector [state.context, r.x1, r.y2, r.x1, r.y1] -- West END ELSE BEGIN tc: TileAndContext ~ NEW [TcRec _ [tile, state.context]]; state.tess.EnumerateNeighborhood [tile, SouthRim, WestRim, NorthRim, EastRim, tc, nothing] END END; IF statistics THEN BEGIN l: CD.Number ~ state.design.technology.lambda; colour.area _ colour.area + ((r.x2 - r.x1) / l) * ((r.y2 - r.y1) / l); state.cardTile _ SUCC [state.cardTile] END END; -- PrintTile NewPrintTile: CStitching.TileProc ~ BEGIN state: State ~ NARROW [data]; b: Blend ~ NARROW [tile.value]; r: CD.Rect ~ CStitching.Area [tile]; -- not the area but the rectangle ! ir: Imager.Rectangle ~ ImagerRect [r]; median: INT; ChangeColour [state, b.blend]; IF (ir.w > ir.h) THEN BEGIN ChangeStrokeWidth [state, ir.h]; median _ (r.y1 + r.y2) / 2; FastMaskVector [state.context, r.x1, median, r.x2, median] END ELSE BEGIN ChangeStrokeWidth [state, ir.w]; median _ (r.x1 + r.x2) / 2; FastMaskVector [state.context, median, r.y1, median, r.y2] END; IF state.abort^ THEN ERROR ABORTED; IF (outline >= 0.0) AND (b.blend # blackBlack) THEN BEGIN ChangeColour [state, blackBlack]; ChangeStrokeWidth [state, outline]; IF showTesselation THEN BEGIN FastMaskVector [state.context, r.x1, r.y1, r.x2, r.y1]; -- South FastMaskVector [state.context, r.x2, r.y1, r.x2, r.y2]; -- East FastMaskVector [state.context, r.x2, r.y2, r.x1, r.y2]; -- North FastMaskVector [state.context, r.x1, r.y2, r.x1, r.y1] -- West END ELSE BEGIN tc: TileAndContext ~ NEW [TcRec _ [tile, state.context]]; state.context.SetStrokeEnd [square]; state.tess.EnumerateNeighborhood [tile, SouthRim, WestRim, NorthRim, EastRim, tc, nothing]; state.context.SetStrokeEnd [butt] END END; IF statistics THEN BEGIN l: CD.Number ~ state.design.technology.lambda; b.area _ b.area + ((r.x2 - r.x1) / l) * ((r.y2 - r.y1) / l); state.cardTile _ SUCC [state.cardTile] END END; -- NewPrintTile AddTile: CStitching.TileProc ~ BEGIN state: State ~ NARROW [data]; colour: Blend ~ NARROW [tile.value]; band: CD.Rect ~ QuickTransf [IF (state.band = NIL) THEN state.cdClip ELSE CDBasics.Intersection [state.cdClip, state.band^], state]; r: Box ~ BoxFromRect [QuickTransf [tile.Area, state], band]; i: INT _ colour.index.ABS - 1; IF (i < 0) OR (i > 30) THEN i _ 0; -- Cheap hack for seldom layer combinations (e.g. pads) state.colorRegion[i].used _ TRUE; state.colorRegion[i].hyp.Fill [r] END; -- AddTile PrintStippledTile: CStitching.TileProc ~ BEGIN state: State ~ NARROW [data]; b: Blend ~ NARROW [tile.value]; r: CD.Rect ~ CStitching.Area [tile]; -- not the area but the rectangle ! FOR i: CD.Layer IN CD.Layer DO IF b.flavours[i] THEN BEGIN ChangeColour [state, LayerColour [i]]; state.context.MaskRectangle [ImagerRect [r]] END ENDLOOP; IF state.abort^ THEN ERROR ABORTED; IF (outline >= 0.0) AND (b.blend # blackBlack) THEN BEGIN ChangeColour [state, blackBlack]; ChangeStrokeWidth [state, outline]; IF showTesselation THEN BEGIN FastMaskVector [state.context, r.x1, r.y1, r.x2, r.y1]; -- South FastMaskVector [state.context, r.x2, r.y1, r.x2, r.y2]; -- East FastMaskVector [state.context, r.x2, r.y2, r.x1, r.y2]; -- North FastMaskVector [state.context, r.x1, r.y2, r.x1, r.y1] -- West END ELSE BEGIN tc: TileAndContext ~ NEW [TcRec _ [tile, state.context]]; state.tess.EnumerateNeighborhood [tile, SouthRim, WestRim, NorthRim, EastRim, tc, nothing] END END; IF statistics THEN BEGIN l: CD.Number ~ state.design.technology.lambda; b.area _ b.area + ((r.x2 - r.x1) / l) * ((r.y2 - r.y1) / l); state.cardTile _ SUCC [state.cardTile] END END; -- PrintStippledTile PrintBand: PROC [state: State] ~ BEGIN gdr: CD.DrawRef ~ CD.CreateDrawRef [[]]; smp: Imager.VEC; -- sample map position deviceBand: CD.Rect; box: Box; EnumerateGeometry: PROC ~ BEGIN state.context.SetStrokeEnd [IF layout THEN square ELSE butt]; state.context.SetStrokeJoint [miter]; -- I hope that's faster for rectangles IF (state.colorRegion # NIL) THEN BEGIN state.tess.EnumerateArea [rect: CStitching.all, eachTile: AddTile, data: state, skip: empty] END ELSE BEGIN IF state.substituteColor THEN BEGIN IF layout THEN state.tess.EnumerateArea [rect: CStitching.all, eachTile: PrintTile, data: state, skip: empty] ELSE state.tess.EnumerateArea [rect: CStitching.all, eachTile: NewPrintTile, data: state, skip: empty] END ELSE state.tess.EnumerateArea [rect: CStitching.all, eachTile: PrintStippledTile, data: state, skip: empty] END END; -- EnumerateGeometry Process.CheckForAbort []; IF state.abort^ THEN ERROR ABORTED; gdr.interestClip _ IF (state.band = NIL) THEN state.cdClip ELSE CDBasics.Intersection [state.cdClip, state.band^]; state.tess _ StartDecomposition [state]; gdr.drawRect _ NewRect; gdr.drawContext _ DoNotDrawContext; gdr.devicePrivate _ state; IF state.abort^ THEN ERROR ABORTED; IF state.selectedOnly THEN DrawSelection [state.design, gdr] ELSE CDOps.DrawDesign [state.design, gdr]; -- pass 2 TerminalIO.PutRope ["."]; IF state.abort^ THEN ERROR ABORTED; IF state.substituteColor THEN BlendTileColours []; TerminalIO.PutRope ["."]; -- pass 3 state.previousColour _ NIL; state.previousStrokeWidth _ -1.0; state.previousFont _ NIL; state.previousTextOrientation _ original; IF (state.colorRegion # NIL) THEN BEGIN deviceBand _ QuickTransf [gdr.interestClip, state]; box _ BoxFromRect [deviceBand, deviceBand]; smp _ [x: 0, y: deviceBand.y2]; FOR p: INT IN [0 .. state.colorRegion.size) DO state.colorRegion[p].used _ FALSE; IF state.abort^ THEN ERROR ABORTED; state.colorRegion[p].hyp _ ImagerSample.NewSampleMap [box]; state.colorRegion[p].hyp.Clear ENDLOOP; gdr.drawRect _ NewRect; SafeStorage.ReclaimCollectibleObjects END; state.context.DoSave [EnumerateGeometry]; -- pass 4 FlushDecomposition [state.tess]; SafeStorage.ReclaimCollectibleObjects; IF (state.colorRegion # NIL) THEN BEGIN FOR p: INT IN [0 .. state.colorRegion.size) DO IF state.colorRegion[p].used THEN BEGIN state.context.SetColor [IthColour [p+1]]; IF debug THEN [] _ state.colorRegion[p].hyp.Trim [box]; state.context.MaskBitmap [bitmap: state.colorRegion[p].hyp, position: smp]; state.colorRegion[p].used _ FALSE; state.colorRegion[p].hyp _ NIL; SafeStorage.ReclaimCollectibleObjects; IF state.abort^ THEN ERROR ABORTED END; ENDLOOP; END; TerminalIO.PutRope [". "] END; -- PrintBand NewRect: CD.DrawRectProc ~ BEGIN state: State ~ NARROW [pr.devicePrivate, State]; rect: CD.Rect; IF (state.singleLayer AND (l # state.layerOfInterest)) THEN RETURN; rect _ IF (state.band = NIL) THEN r ELSE CDBasics.Intersection [r, state.band^]; IF (CDBasics.NonEmpty [rect]) THEN BEGIN dec: Tess ~ state.tess; InsertRect: CStitching.RectProc = BEGIN WITH oldValue SELECT FROM b: Blend => IF NOT b.flavours[l] THEN dec.ChangeRect [rect: rect, new: ColourTile [b, l]]; ENDCASE => BEGIN b: Blend _ NEW [BlendRec]; dec.ChangeRect [rect: rect, new: ColourTile [b, l]] END END; -- InsertRect dec.ChangeEnumerateArea [rect: rect, eachRect: InsertRect, skip: nothing]; IF state.abort^ THEN ERROR ABORTED END END; -- NewRect mirrorY: Transformation ~ ImagerTransformation.Scale2 [[-1, 1]]; rot180: Transformation ~ ImagerTransformation.Rotate [180]; SpecialHack: PROC [obj: CD.Object, or: D2Orient.Orientation] RETURNS [t: Transformation] ~ BEGIN adjustX: Transformation ~ ImagerTransformation.Translate [[-(obj.bbox.x2 - obj.bbox.x1), 0]]; adjustXY: Transformation ~ ImagerTransformation.Translate [[-(obj.bbox.x2 - obj.bbox.x1), -(obj.bbox.y2 - obj.bbox.y1)]]; adjustXhalfY: Transformation ~ ImagerTransformation.Translate [[-(obj.bbox.x2 - obj.bbox.x1), -(obj.bbox.y2 - obj.bbox.y1) / 2]]; IF (obj.class.objectType # $FlipText) THEN ERROR; -- tocca ferro t _ SELECT or FROM mirrorX, rotate90X => adjustX.Cat [mirrorY], -- TxSxSy rotate180X, rotate270X => adjustXY.Cat [rot180, adjustX, mirrorY], -- TxySxyRTxSxSy rotate180, rotate90 => adjustXhalfY.Cat [rot180], -- Txy/2SxyR ENDCASE => ImagerTransformation.Create [1, 0, 0, 0, 1, 0] -- plain vanilla Identity END; -- SpecialHack DrawText: CD.DrawProc ~ BEGIN state: State ~ NARROW [pr.devicePrivate]; context: Imager.Context ~ state.context; text: CDTexts.TextSpecific ~ NARROW [ob.specific]; offset: Imager.VEC _ text.cdFont.xy; transf, invTransf: Transformation; IF (state.singleLayer AND (ob.layer # state.layerOfInterest)) THEN RETURN; IF state.abort^ THEN ERROR ABORTED; ChangeColour [state, LayerColour [ob.layer]]; ChangeFont [state, text.cdFont.font]; -- order of statements important ! transf _ CDBasics.ImagerTransform [trans]; IF (ob.class.objectType = $FlipText) THEN BEGIN transf _ ImagerTransformation.Cat [SpecialHack [ob, trans.orient], transf]; SELECT trans.orient FROM mirrorX, rotate90, rotate180, rotate90X => BEGIN offset.x _ offset.x + (ImagerFont.RopeBoundingBox [font: text.cdFont.font, rope: text.text].rightExtent) - (ImagerFont.RopeBoundingBox [font: state.previousFont, rope: text.text].rightExtent); offset.y _ 0; -- that's what's in ChipNDale release 25 IF (trans.orient = rotate90) OR (trans.orient = rotate180) THEN offset.y _ offset.y - ImagerFont.FontBoundingBox [state.previousFont].descent / 2.0 END ENDCASE => offset _ [0, 0]; -- that's what's in ChipNDale release 25 END ELSE offset.y _ 0; -- different from CD but a closer approximation invTransf _ ImagerTransformation.Invert [transf]; context.ConcatT [transf]; context.SetXY [offset]; context.ShowRope [text.text]; context.ConcatT [invTransf] END; -- DrawText DrawPath: CD.DrawProc ~ BEGIN state: State ~ NARROW [pr.devicePrivate]; context: Imager.Context ~ state.context; curve: CDCurves.CurveSpecific ~ NARROW [ob.specific]; transf: Transformation ~ CDBasics.ImagerTransform [trans]; invTransf: Transformation ~ ImagerTransformation.Invert [transf]; IF (state.singleLayer AND (ob.layer # state.layerOfInterest)) THEN RETURN; IF state.abort^ THEN ERROR ABORTED; context.ConcatT [transf]; -- context.SetXY [offset]; ChangeColour [state, LayerColour [ob.layer]]; ChangeStrokeWidth [state, Float [curve.w]]; context.MaskStrokeTrajectory [curve.path]; context.ConcatT [invTransf] END; -- DrawPath DrawArea: CD.DrawProc ~ BEGIN state: State ~ NARROW [pr.devicePrivate]; context: Imager.Context ~ state.context; curve: CDCurves.CurveSpecific ~ NARROW [ob.specific]; transf: Transformation ~ CDBasics.ImagerTransform [trans]; invTransf: Transformation ~ ImagerTransformation.Invert [transf]; IF (state.singleLayer AND (ob.layer # state.layerOfInterest)) THEN RETURN; IF state.abort^ THEN ERROR ABORTED; context.ConcatT [transf]; -- context.SetXY [offset]; ChangeColour [state, LayerColour [ob.layer]]; ChangeStrokeWidth [state, Float [curve.w]]; context.MaskFillTrajectory [curve.path, TRUE]; context.ConcatT [invTransf] END; -- DrawArea DrawObjectBorder: CD.DrawRectProc ~ BEGIN state: State ~ NARROW [pr.devicePrivate, State]; pen: REAL ~ Float [state.design.technology.lambda]; halfPen: REAL ~ pen / 2.0; object: Imager.Rectangle ~ ImagerRect [r]; border: ImagerPath.Trajectory; IF state.abort^ THEN ERROR ABORTED; ChangeColour [state, blackBlack]; ChangeStrokeWidth [state, pen]; border _ ImagerPath.MoveTo [[object.x - halfPen, object.y - halfPen]]; border _ border.LineToX [object.x + object.w + halfPen]; -- South border _ border.LineToY [object.y + object.h + halfPen]; -- East border _ border.LineToX [object.x - halfPen]; -- North border _ border.LineToY [object.y - halfPen]; -- West state.context.MaskStrokeTrajectory [trajectory: border] END; -- DrawObjectBorder DrawDashedObjectBorder: CD.DrawRectProc ~ BEGIN state: State ~ NARROW [pr.devicePrivate, State]; pen: REAL ~ Float [state.design.technology.lambda / 2]; halfPen: REAL ~ pen / 2.0; object: Imager.Rectangle ~ ImagerRect [r]; border: ImagerPath.Trajectory; patternElements: NAT ~ 8; DotDotDotDash: PROC [i: NAT] RETURNS [REAL] ~ BEGIN pattern: ARRAY [0 .. patternElements) OF REAL ~ [0, 5*pen, 0, 5*pen, 0, 10*pen, 30*pen, 10*pen]; RETURN [pattern[i]] END; -- DotDotDotDash IF state.abort^ THEN ERROR ABORTED; ChangeColour [state, blackBlack]; ChangeStrokeWidth [state, pen]; border _ ImagerPath.MoveTo [[object.x - halfPen, object.y - halfPen]]; border _ border.LineToX [object.x + object.w + halfPen]; -- South border _ border.LineToY [object.y + object.h + halfPen]; -- East border _ border.LineToX [object.x - halfPen]; -- North border _ border.LineToY [object.y - halfPen]; -- West Imager.MaskDashedStrokeTrajectory [context: state.context, trajectory: border, offset: 0, length: 2*(object.w+object.h), patternLen: patternElements, pattern: DotDotDotDash] END; -- DrawDashedObjectBorder DrawObject: CD.DrawProc ~ BEGIN Process.CheckForAbort []; SELECT ob.class.objectType FROM $Text, $RigidText, $FlipText => DrawText [pr, ob, trans, readOnlyInstProps]; $Spline0, $Line0 => DrawPath [pr, ob, trans, readOnlyInstProps]; $FilledCurve0, $Polygon0 => DrawArea [pr, ob, trans, readOnlyInstProps]; ENDCASE => ob.class.drawMe [pr, ob, trans, readOnlyInstProps] END; -- DrawObject DrawObjectWithSignalNames: CD.DrawProc ~ BEGIN Process.CheckForAbort []; IF (readOnlyInstProps # NIL) THEN BEGIN name: ROPE ~ NARROW [CDProperties.GetListProp [readOnlyInstProps, $SignalName]]; IF NOT name.IsEmpty THEN BEGIN state: State ~ NARROW [pr.devicePrivate]; transf: Transformation ~ CDBasics.ImagerTransform [trans]; invTransf: Transformation ~ ImagerTransformation.Invert [transf]; offset: Imager.VEC _ [0, 0]; IF state.abort^ THEN ERROR ABORTED; ChangeColour [state, LayerColour [CD.commentLayer]]; ChangeFont [state, signalNameFont]; -- order of statements important ! IF (ob.class.objectType = $Rect) AND centerSignalNames THEN BEGIN esc: Imager.VEC ~ ImagerFont.RopeEscapement [signalNameFont, name]; offset.x _ ob.bbox.x1 + ((ob.bbox.x2 - ob.bbox.x1) - esc.x) / 2.0; offset.y _ ob.bbox.y1 + ((ob.bbox.y2 - ob.bbox.y1) - esc.y) / 2.0 END; state.context.ConcatT [transf]; state.context.SetXY [offset]; state.context.ShowRope [name]; state.context.ConcatT [invTransf] END END; SELECT ob.class.objectType FROM $Text, $RigidText, $FlipText => DrawText [pr, ob, trans, readOnlyInstProps]; $Spline0, $Line0 => DrawPath [pr, ob, trans, readOnlyInstProps]; $FilledCurve0, $Polygon0 => DrawArea [pr, ob, trans, readOnlyInstProps]; ENDCASE => ob.class.drawMe [pr, ob, trans, readOnlyInstProps] END; -- DrawObjectWithSignalNames multipageHack: State; rgbLinear: Imager.ColorOperator ~ ImagerColor.NewColorOperatorRGB [255]; cmyk: Imager.ColorOperator ~ ImagerColorFns.NewColorOperatorCMYK [255]; DoInterpress: PUBLIC PROC [design: CD.Design, chipNDaleWindow: CD.Rect, clip, onlySel, singleLayer, register: BOOL _ FALSE, layer: CD.Layer _ CD.undefLayer, lambda: REAL _ 0.0, firstPage, lastPage: BOOL _ TRUE, abortFlag: REF BOOL] RETURNS [masterName: Rope.ROPE, usedField: Imager.Rectangle] ~ BEGIN state: State; OpenIPMaster: PROC [] RETURNS [ImagerInterpress.Ref] ~ BEGIN ENABLE {FS.Error => GOTO failure}; subDir: ROPE ~ "[]<>Temp>Nectarine>"; -- follows the religion pos: FS.ComponentPositions; ext: ROPE _ ".dummy"; ext _ IO.PutFR ["-NS%g%g", IO.card [BasicTime.ToNSTime [BasicTime.Now[]]], IO.rope [ext]]; IF NOT design.name.IsEmpty[] THEN masterName _ design.name.Cat [ext] ELSE BEGIN cdName: ROPE ~ NARROW [CDValue.Fetch [design, $CDxLastFile]]; IF cdName.IsEmpty[] THEN masterName _ Rope.Cat ["UnnamedMaster", ext] ELSE BEGIN shortFName: ROPE; [fullFName: masterName, cp: pos] _ FS.ExpandName [cdName, subDir]; shortFName _ masterName.Substr [start: pos.base.start, len: pos.base.length]; masterName _ shortFName.Cat [ext] END END; [fullFName: masterName, cp: pos] _ FS.ExpandName [masterName, subDir]; masterName _ masterName.Replace [pos.ext.start, pos.ext.length, "Interpress"]; RETURN [ImagerInterpress.Create [masterName]]; EXITS failure => BEGIN masterName _ IO.PutFR ["[]<>Temp>Nectarine>UnnamedMaster-NS%g.%g", IO.card [BasicTime.ToNSTime [BasicTime.Now[]]], IO.rope ["Interpress"]]; RETURN [ImagerInterpress.Create [masterName]] END END; -- OpenIPMaster DrawToIP: PROC [context: Imager.Context] ~ BEGIN tdr: CD.DrawRef ~ CD.CreateDrawRef [[]]; window: Imager.Rectangle; -- in the CG sense ratioW, ratioH, y0: REAL; iterations, bandSize: INT; -- number and size of bands chronos: BOOL; lap, end: BasicTime.GMT; EnumerateTextInDesign: PROC ~ BEGIN IF state.selectedOnly THEN DrawSelection [state.design, tdr] ELSE CDOps.DrawDesign [state.design, tdr] END; -- EnumerateTextInDesign state.context _ context; window _ ImagerRect [chipNDaleWindow]; IF imageRegions THEN BEGIN width, heigth: REAL; state.bitmapScale _ versatecWidth / window.w; width _ versatecWidthInMM; heigth _ window.h*state.bitmapScale/200*mmXin; IF (heigth > versatecWidthInMM) THEN BEGIN state.bitmapScale _ versatecLength / window.h; width _ window.w*state.bitmapScale/200*mmXin; heigth _ versatecLengthInMM END; usedField _ [x: 0.0, y: 0.0, w: width, h: heigth]; state.colorRegion _ NEW [ColorRegionRep[NumberOfColours[]]] END ELSE BEGIN ratioW _ field.w / window.w; ratioH _ field.h / window.h; usedField.x _ field.x; usedField.y _ field.y; -- in mm IF ratioH < ratioW THEN {usedField.w _ window.w * ratioH; usedField.h _ field.h} ELSE {usedField.w _ field.w; usedField.h _ window.h * ratioW}; y0 _ 0.0; IF register THEN BEGIN pos: FS.ComponentPositions; fName: ROPE; [fullFName: fName, cp: pos] _ FS.ExpandName [masterName, NIL]; context.PutProp [$separationLabel, fName.Substr [pos.base.start, pos.base.length]]; NectarineAids.ComposeRegisterMarks ["Nectarine", UseProcessColors[], context] END; context.TranslateT [[usedField.x, y0 + field.y]]; IF (lambda = 0.0) THEN context.ScaleT [MIN [ratioW, ratioH]] ELSE context.ScaleT [lambda / Float [design.technology.lambda]]; context.TranslateT [[-window.x, -window.y]]; IF clip THEN context.ClipRectangle [window] -- global to context !!! END; IF NOT SetLayerColourTable[] THEN TerminalIO.PutRope ["\nSome layers are not in the Color Registry.\n"]; context.SetPriorityImportant [NOT (ignoreAnnotation OR (NOT state.substituteColor) OR DoLineArt[] OR imageRegions)]; IF (NOT state.substituteColor) AND (NOT DoLineArt[]) THEN BEGIN ChangeColour [state, orableBackground]; state.context.MaskRectangle [window] END; IF state.substituteColor AND (NOT DoLineArt []) THEN BEGIN IF imageRegions THEN BEGIN bandSizeR: REAL ~ MIN [320.0, window.h * state.bitmapScale]; bandSize _ Fix [bandSizeR / state.bitmapScale]; -- translate into ChipNDale units iterations _ Fix [window.h] / bandSize -- "zero relative" ! END ELSE BEGIN bandSize _ Fix [(1000000.0 * (risk+1)) / window.w]; IF bandSize < 4 * design.technology.lambda THEN SIGNAL tooComplex; iterations _ Fix [window.h] / bandSize; -- "zero relative" ! END; IF (iterations > 5) THEN TerminalIO.PutF [" There will be %g sets of 3 dots ", IO.int [iterations]] ELSE {IF debug THEN TerminalIO.PutF [v1: IO.int [iterations]]}; IF ((iterations = 0) AND (NOT state.clip)) THEN PrintBand [state] -- shortcut ELSE BEGIN halftime: INT ~ iterations / 2; currentBand: REF CD.Rect ~ NEW [CD.Rect _ chipNDaleWindow]; state.band _ currentBand; chronos _ iterations > 5; FOR b: INT DECREASING IN [0 .. iterations] DO currentBand.y1 _ chipNDaleWindow.y1 + b * bandSize; currentBand.y2 _ MIN [chipNDaleWindow.y2, currentBand.y1 + bandSize + 1]; IF chronos THEN BEGIN fudge: INT ~ 8; IF (b = iterations - 3) THEN lap _ BasicTime.Now []; IF (b = iterations - 4) AND state.isLastPage THEN BEGIN duration: INT ~ BasicTime.Period [lap, BasicTime.Now[]]; end _ BasicTime.Update [lap, fudge * duration * (b + 2) ! BasicTime.OutOfRange => GOTO endless]; TerminalIO.PutF ["\nInterpress page will be ready ca. %g (this is only an educated guess)\n", IO.time [end]]; chronos _ FALSE END END; PrintBand [state]; IF (b = halftime) AND (iterations > 10) AND state.isLastPage THEN BEGIN fudge: INT ~ 3; -- more than 2 because of memory fragmentation duration: INT ~ BasicTime.Period [state.startTime, BasicTime.Now[]]; end _ BasicTime.Update [state.startTime, fudge * duration ! BasicTime.OutOfRange => GOTO endless]; TerminalIO.PutF ["\nRevised duration inference: Interpress master will be ready ca. %g\n", IO.time [end]] END ENDLOOP; state.band _ NIL END; IF (state.tess # NIL) THEN {CStitching.DumpCache []; state.tess _ NIL}; state.colorRegion _ NIL; SafeStorage.ReclaimCollectibleObjects END -- IF state.substituteColor ELSE BEGIN gdr: CD.DrawRef ~ CD.CreateDrawRef [[]]; gdr.interestClip _ state.cdClip; gdr.devicePrivate _ state; gdr.drawRect _ IF DoLineArt [] THEN LineRect ELSE OrRect; gdr.drawContext _ DoNotDrawContext; CDOps.DrawDesign [state.design, gdr] END; IF ignoreAnnotation OR (DoLineArt []) THEN RETURN; IF imageRegions THEN RETURN; -- because it does not work yet context.SetStrokeEnd [round]; context.SetStrokeJoint [round]; IF clip THEN tdr.interestClip _ chipNDaleWindow; tdr.drawRect _ DoNotDrawRect; IF letChipndaleCallTheImager THEN BEGIN tdr.deviceContext _ context; tdr.fontSubstitution _ TRUE; tdr.contextColors _ NEW [CD.ContextColors]; FOR c: CD.Layer IN CD.Layer DO tdr.contextColors[c] _ LayerColour [c] ENDLOOP END ELSE BEGIN tdr.drawContext _ DoNotDrawContext; tdr.drawChild _ IF (signalNameFont = NIL) THEN DrawObject ELSE DrawObjectWithSignalNames END; tdr.drawOutLine _ DrawObjectBorder; tdr.borders _ TRUE; tdr.selections _ FALSE; tdr.devicePrivate _ state; state.previousColour _ NIL; -- needed by Interpress state.previousStrokeWidth _ -1.0; -- needed by Interpress context.DoSave [EnumerateTextInDesign]; TerminalIO.PutRope [". "]; -- pass 5 EXITS endless => BEGIN ImportantMessage [" Nectarine would not terminate before 2036"]; SIGNAL tooComplex END END; -- DrawToIP Action: PROC [] ~ BEGIN DeclareFonts: RefTab.EachPairAction ~ {state.interpress.DeclareFont [NARROW [val,Font]]; RETURN [FALSE]}; ListFonts: RefTab.EachPairAction ~ BEGIN t: Typeface ~ NARROW [val, Font].typeface; TerminalIO.PutF ["%g\n", IO.rope [t.name]]; RETURN [FALSE] END; -- ListFonts IF state.isFirstPage THEN BEGIN state.interpress _ OpenIPMaster []; state.ipName _ masterName; TerminalIO.PutRope [Rope.Cat ["Producing Interpress master ", masterName, "\n"]]; IF DoLineArt [] THEN BEGIN TerminalIO.PutRope ["Line art (overrides halftoning and cross-hatching). "]; IF UseProcessColors [] THEN TerminalIO.PutRope ["Requires process colors to print.\n"] ELSE TerminalIO.PutRope ["Requires custom colors to print.\n"] END ELSE TerminalIO.PutRope ["Halftoned art. Requires process colors to print.\n"]; IF NOT state.substituteColor THEN TerminalIO.PutRope ["No color substitution.\n"]; IF (SubColours [] OR DoLineArt []) THEN state.interpress.DeclareColorOperator [IF UserProfile.Boolean [key: "Nectarine.ContinuousTone", default: FALSE] THEN rgbLinear ELSE cmyk] ELSE NULL; IF (NumberOfColours[] + fontMap.GetSize[] < 50) THEN DeclareColours [state.interpress]; UpdateFontMap [state]; IF (NOT ignoreAnnotation) AND (fontMap.GetSize[] < 50) THEN [] _ fontMap.Pairs [DeclareFonts]; IF (signalNameFont # NIL) THEN state.interpress.DeclareFont [signalNameFont]; TerminalIO.PutRope [". "]; -- pass 1 IF debug THEN BEGIN TerminalIO.PutRope ["\nThe following fonts are in the preamble:\n"]; [] _ fontMap.Pairs [ListFonts] END END; TRUSTED {Process.SetPriority [Process.priorityBackground]}; state.interpress.DoPage [action: DrawToIP, scale: IF imageRegions THEN versatecResolution ELSE 0.001]; IF state.isLastPage THEN BEGIN state.interpress.Close []; multipageHack _ NIL; TerminalIO.PutRope [TimeToRope [state.startTime, BasicTime.Now[]]]; TerminalIO.PutRope ["\n"]; IF (statistics OR debug) THEN ListColourStatistics [state.cardTile]; TerminalIO.PutRope [Rope.Cat ["Interpress master ", state.ipName, " is ready.\n"]] END END; -- Action IF firstPage THEN BEGIN IF (multipageHack # NIL) THEN BEGIN TerminalIO.PutRope [Rope.Cat ["Interpress master ", multipageHack.ipName, " was orphaned and is being salvaged.\n"]]; multipageHack.interpress.Close []; multipageHack _ NIL END; multipageHack _ state _ NEW [StateRec]; state.design _ design; IF singleLayer THEN {state.singleLayer _ TRUE; state.layerOfInterest _ layer}; state.substituteColor _ SubColours []; IF statistics THEN {ResetColourStatistics; state.cardTile _ 0}; state.abort _ IF abortFlag # NIL THEN abortFlag ELSE NEW [BOOL _ FALSE]; state.startTime _ BasicTime.Now [] END ELSE BEGIN state _ multipageHack; masterName _ state.ipName; state.previousColour _ NIL; state.previousStrokeWidth _ -1.0; state.previousFont _ NIL; state.previousTextOrientation _ original END; state.isLastPage _ lastPage; state.isFirstPage _ firstPage; state.clip _ clip; state.cdClip _ chipNDaleWindow; state.selectedOnly _ onlySel; Action [] END; -- DoInterpress DrawSelection: PROC [design: CD.Design, d: CD.DrawRef] ~ BEGIN FOR all: CD.InstanceList _ CDOps.InstList [design], all.rest WHILE all # NIL DO IF all.first.selected THEN d.drawChild [d, all.first.ob, all.first.trans, all.first.properties] ENDLOOP END; -- DrawSelection EnumerateObjects: PROC [design: CD.Design, d: CD.DrawRef] ~ BEGIN DoObject: CDDirectory.EachEntryAction ~ BEGIN d.drawChild [d, ob, [[0,0], original], NIL] END; -- DoObject [] _ CDDirectory.Enumerate [design, DoObject] END; -- EnumerateObjects ChangeColour: PROC [state: State, colour: Color] ~ INLINE BEGIN context: Imager.Context ~ state.context; IF (colour # state.previousColour) THEN BEGIN context.SetColor [colour]; state.previousColour _ colour END END; -- ChangeColour ChangeStrokeWidth: PROC [state: State, w: REAL] ~ INLINE BEGIN context: Imager.Context ~ state.context; IF (w < 0) OR (w # state.previousStrokeWidth) THEN BEGIN context.SetStrokeWidth [w]; state.previousStrokeWidth _ w END END; -- ChangeStrokeWidth ChangeFont: PROC [state: State, skFont: Font] ~ INLINE BEGIN context: Imager.Context ~ state.context; IF (skFont # state.previousFont) THEN BEGIN prFont: Font _ NARROW [fontMap.Fetch[skFont].val]; IF (prFont = NIL) THEN BEGIN prFont _ Mapping [skFont]; [] _ fontMap.Insert [skFont, prFont] END; context.SetFont [prFont]; state.previousFont _ skFont END END; -- ChangeFont fontMap: RefTab.Ref ~ RefTab.Create []; -- global fontPrefix: ATOM ~ Atom.MakeAtom ["xerox/pressfonts/"]; visitedCells: RefTab.Ref; DrawFilter: CD.DrawProc ~ BEGIN SELECT ob.class.objectType FROM $Text, $RigidText, $FlipText => FindFont [pr, ob, trans, readOnlyInstProps]; $Cell => IF visitedCells.Insert [ob, $hack] THEN ob.class.drawMe [pr, ob, trans, readOnlyInstProps]; ENDCASE => NULL END; -- DrawFilter FindFont: CD.DrawProc ~ BEGIN text: CDTexts.TextSpecific ~ NARROW [ob.specific]; font: Font ~ text.cdFont.font; IF NOT fontMap.Fetch[font].found THEN [] _ fontMap.Insert [font, Mapping [font]] END; -- FindFont UpdateFontMap: PROC [state: State] ~ BEGIN tdr: CD.DrawRef ~ CD.CreateDrawRef [[]]; Evict: RefTab.EachPairAction ~ {[] _ visitedCells.Delete [key]; RETURN [FALSE]}; remindFontConventions _ TRUE; tdr.drawChild _ DrawFilter; tdr.drawRect _ DoNotDrawRect; tdr.drawContext _ DoNotDrawContext; tdr.devicePrivate _ state; visitedCells _ RefTab.Create [557]; IF state.selectedOnly THEN DrawSelection [state.design, tdr] ELSE EnumerateObjects [state.design, tdr]; [] _ visitedCells.Pairs [Evict]; visitedCells _ NIL END; -- UpdateFontMap Mapping: PROC [sk: Font] RETURNS [mr: Font] ~ BEGIN fontVendor, fontClass, fullName, shortName, family, attributes: ROPE; slashPos1, slashPos2, sizePos, facePos: INTEGER; isXerox: BOOL; face: NodeStyle.FontFace _ Regular; typeface: Typeface _ sk.typeface; size: REAL; fullName _ typeface.name; slashPos1 _ fullName.SkipTo [0, "/"]; fontVendor _ fullName.Substr [0, slashPos1]; isXerox _ fontVendor.Equal ["Xerox", FALSE]; slashPos1 _ slashPos1.SUCC; slashPos2 _ fullName.SkipTo [slashPos1, "/"]; fontClass _ fullName.Substr [slashPos1, slashPos2-slashPos1]; shortName _ fullName.Substr [slashPos2+1]; SELECT TRUE FROM isXerox AND fontClass.Equal ["PressFonts", FALSE] => BEGIN IF remindFontConventions THEN BEGIN TerminalIO.PutRope ["Nectarine takes care of all the font substitutions. You can use the strike fonts for the layout.\n"]; remindFontConventions _ FALSE END; mr _ sk END; isXerox AND fontClass.Equal ["TiogaFonts", FALSE] => BEGIN sizePos _ shortName.SkipTo [0, "0123456789"]; attributes _ shortName.Substr [sizePos, shortName.Length[]-sizePos]; facePos _ attributes.SkipTo [0, "bBiI"]; size _ (ORD [attributes.Fetch[0]] - ORD ['0]); FOR i: INT IN [1 .. facePos) DO size _ size * 10.0 + (ORD [attributes.Fetch[i]] - ORD ['0]) ENDLOOP; IF (facePos # attributes.Length[]) THEN BEGIN it: BOOL ~ (attributes.SkipTo [0, "iI"] # attributes.Length[]); b: BOOL ~ (attributes.SkipTo [0, "bB"] # attributes.Length[]); SELECT TRUE FROM it AND b => face _ BoldItalic; it AND NOT b => face _ Italic; NOT it AND b => face _ Bold; ENDCASE => ERROR END; family _ shortName.Substr [0, sizePos]; mr _ NodeStyleFont.FontFromStyleParams [prefix: fontPrefix, family: Atom.MakeAtom[family], face: face, size: size, alphabets: CapsAndLower]; mr _ ImagerFont.Modify [mr, sk.charToClient] END; ENDCASE => BEGIN IF isXerox THEN TerminalIO.PutRope [fullName.Cat [": font class", fontClass, " unknown, not substituted.\n"]] ELSE TerminalIO.PutRope [fullName.Cat [": vendor", fontVendor, " unknown, not substituted.\n"]]; mr _ sk END END; -- Mapping ImagerRect: PROC [r: CD.Rect] RETURNS [Imager.Rectangle] ~ BEGIN base: CD.Position ~ CDBasics.BaseOfRect [r]; size: CD.Position ~ CDBasics.SizeOfRect [r]; RETURN [[Float[base.x], Float[base.y], Float[size.x], Float[size.y]]] END; -- ImagerRect ImagerVec: PROC [p: CD.Position] RETURNS [Imager.VEC] ~ BEGIN RETURN [[Float[p.x], Float[p.y]]] END; -- ImagerVec BoxFromRect: PROC [r, viewport: CD.Rect] RETURNS [Box] ~ BEGIN RETURN [[min: [f: r.x1-viewport.x1, s: viewport.y2-r.y2], max: [f: r.x2-viewport.x1, s: viewport.y2-r.y1]]] END; -- BoxFromRect QuickTransf: PROC [r: CD.Rect, state: State] RETURNS [CD.Rect] ~ BEGIN PointX: PROC [p: INT] RETURNS [INT] ~ INLINE BEGIN RETURN [Round [Float [p-state.cdClip.x1] * state.bitmapScale]] END; -- PointX PointY: PROC [p: INT] RETURNS [INT] ~ INLINE BEGIN RETURN [Round [Float [p-state.cdClip.y1] * state.bitmapScale]] END; -- PointY RETURN [[PointX [r.x1], PointY [r.y1], PointX [r.x2], PointY [r.y2]]] END; -- QuickTransf RGBFromColour: PROC [c: Color] RETURNS [rgb: ImagerColor.RGB] ~ INLINE BEGIN WITH c SELECT FROM constant: Imager.ConstantColor => rgb _ ImagerColorPrivate.RGBFromColor [constant]; ENDCASE => rgb _ unColour; RETURN [rgb] END; -- RGBFromColour SubColours: PROC RETURNS [BOOL] ~ INLINE BEGIN RETURN [UserProfile.Boolean [key: "Nectarine.SubstituteColors", default: colSubDef]] END; -- SubColours DoLineArt: PROC RETURNS [BOOL] ~ INLINE BEGIN RETURN [UserProfile.Boolean [key: "Nectarine.LineArt", default: FALSE]] END; -- DoLineArt UseProcessColors: PROC RETURNS [BOOL] ~ INLINE BEGIN RETURN [UserProfile.Boolean [key: "Nectarine.ProcessColors", default: TRUE]] END; -- UseProcessColors ImportantMessage: PROC [msg: ROPE] ~ BEGIN TerminalIO.PutRope [msg]; TerminalIO.PutRope ["\n"]; MessageWindow.Clear []; MessageWindow.Append [msg]; MessageWindow.Blink [] END; -- ImportantMessage DoNotDrawContext: CD.DrawContextProc ~ {}; DoNotDrawObject: CD.DrawProc ~ {}; DoNotDrawRect: CD.DrawRectProc ~ {}; OrRect: CD.DrawRectProc ~ BEGIN state: State ~ NARROW [pr.devicePrivate, State]; IF (state.singleLayer AND (l # state.layerOfInterest)) THEN RETURN; IF (CDBasics.NonEmpty [r]) THEN BEGIN IF state.abort^ THEN ERROR ABORTED; ChangeColour [state, LayerColour [l]]; state.context.MaskRectangle [ImagerRect [r]] END END; -- OrRect LineRect: CD.DrawRectProc ~ BEGIN state: State ~ NARROW [pr.devicePrivate, State]; IF (state.singleLayer AND (l # state.layerOfInterest)) THEN RETURN; IF (CDBasics.NonEmpty [r]) AND (LayerColour [l] # NIL) THEN BEGIN IF state.abort^ THEN ERROR ABORTED; ChangeColour [state, LayerColour [l]]; state.context.MaskRectangle [ImagerRect [r]] END END; -- LineRect Print: PUBLIC PROC [masterName: Rope.ROPE, printerKey: ATOM, copies: INT _ 1, doNotScale: BOOL _ FALSE, mergeRegister: BOOL _ TRUE, sizeHint: REF Imager.Rectangle _ NIL, abortFlag: REF BOOL] RETURNS [peachName: ROPE] ~ BEGIN errorCause: ROPE; pos: FS.ComponentPositions; {ENABLE BEGIN XNSPrint.Error => {errorCause _ explanation; GOTO xnsFailure}; END; IF masterName.IsEmpty THEN BEGIN TerminalIO.PutRope ["Produce an Interpress master first.\n"]; RETURN [NIL] END; IF (abortFlag = NIL) THEN abortFlag _ NEW [BOOL _ FALSE]; IF abortFlag^ THEN ERROR ABORTED; Process.CheckForAbort; pos _ FS.ExpandName[masterName].cp; SELECT printerKey FROM $NVersatec, $NColorVersatec, $NBw400, $NColor400, $NPeachExpand, $NRaven384 => BEGIN peachName _ masterName.Replace [pos.ext.start, pos.ext.length, "PD"]; TRUSTED BEGIN Process.Detach [FORK PdPrintProcess [masterName, peachName, printerKey, copies, doNotScale, FALSE, sizeHint, abortFlag]] END; TerminalIO.PutRope ["Printing process forked off.\n"] END; $NRaven300, $C2700 => BEGIN serverName: ROPE; fullName: ROPE; -- with version number c: XNSPrint.Context ~ XNSPrint.GetDefaults []; fullName _ FS.FileInfo [name: masterName, remoteCheck: FALSE].fullFName; pos _ FS.ExpandName [fullName].cp; c.printObjectName _ fullName.Substr[start: pos.base.start, len: pos.base.length].Cat["!",fullName.Substr[start: pos.ver.start, len: pos.ver.length]]; -- Sorry ! SELECT printerKey FROM $NRaven300 => serverName _ UserProfile.Token ["Nectarine.Raven300", "Quoth"]; $C2700 => serverName _ UserProfile.Token ["Nectarine.C2700", "TimsToy"]; ENDCASE => SIGNAL invalidPrinter; c.printerName _ serverName; c.printObjectCreateDate _ FS.FileInfo [name: fullName, remoteCheck: FALSE].created; c.copyCount _ copies; c.senderName _ UserCredentials.Get[].name; c.message _ Rope.Cat ["Nectarine for ", c.senderName]; IF abortFlag^ THEN ERROR ABORTED; Process.CheckForAbort; [] _ XNSPrint.PrintFromFile [fullName, c]; TerminalIO.PutF ["%g submitted to %g.\n", IO.rope [c.printObjectName], IO.rope [serverName]]; peachName _ masterName END; $NPlateMaker => BEGIN peachName _ masterName.Substr [pos.base.start, pos.base.length]; TRUSTED BEGIN Process.Detach [FORK PdPrintProcess [masterName, peachName, printerKey, copies, doNotScale, mergeRegister, sizeHint, abortFlag]] END; TerminalIO.PutRope ["Printing process forked off.\n"]; IF abortFlag^ THEN ERROR ABORTED; Process.CheckForAbort; END; ENDCASE => SIGNAL invalidPrinter; EXITS xnsFailure => BEGIN ImportantMessage [errorCause.Cat [" File saved on ", peachName, " for manual retry."]] END } END; -- Print previousColorSubEntry: BOOL _ SubColours []; previousLineArtEntry: BOOL _ DoLineArt []; previousInkEntry: BOOL _ UseProcessColors []; GetStatisticsToggle: UserProfile.ProfileChangedProc ~ BEGIN colorSub: BOOL ~ SubColours []; lineArt: BOOL ~ DoLineArt []; processColors: BOOL ~ UseProcessColors []; statistics _ UserProfile.Boolean [key: "Nectarine.Statistics"]; IF (colorSub # previousColorSubEntry) THEN BEGIN previousColorSubEntry _ colorSub; IF (reason = edit) OR (reason = newUser) THEN BEGIN TerminalIO.PutRope ["\nOption for color substitution changed.\n"]; IF colorSub THEN BEGIN ReadMap ["[DATools]Nectarine>Discriminable.ColorMap"]; [] _ ResetLayerColourTable []; BlendTileColours END ELSE [] _ ResetLayerColourTable [] END END; IF (lineArt # previousLineArtEntry) THEN BEGIN previousLineArtEntry _ lineArt; IF (reason = edit) OR (reason = newUser) THEN BEGIN TerminalIO.PutRope ["\nOption for line art changed.\n"]; IF NOT lineArt THEN BEGIN ReadMap ["[DATools]Nectarine>Discriminable.ColorMap"]; [] _ ResetLayerColourTable []; BlendTileColours END ELSE [] _ ResetLayerColourTable [] END END; IF (processColors # previousInkEntry) THEN BEGIN previousInkEntry _ processColors; IF (reason = edit) OR (reason = newUser) THEN BEGIN TerminalIO.PutRope ["\nOption for line art ink changed.\n"]; [] _ ResetLayerColourTable [] END END END; -- GetStatisticsToggle TimeToRope: PROC [from, to: BasicTime.GMT] RETURNS [time: ROPE] ~ BEGIN TwoPosInt: PROC [i: INT] RETURNS [ROPE] ~ BEGIN RETURN [SELECT i FROM = 0 => "00", < 10 => Rope.Cat ["0", IO.PutFR1 [value: IO.int [i]]], ENDCASE => IO.PutFR1 [value: IO.int [i]]] END; s: INT _ BasicTime.Period [from, to]; m: INT _ s / 60; h: INT _ m / 60; d: INT ~ h / 24; s _ s MOD 60; m _ m MOD 60; h _ h MOD 24; IF (d > 0) THEN time _ Rope.Cat ["d:h:m:s ", TwoPosInt[d], ":"] ELSE time _ "h:m:s "; time _ time.Cat [TwoPosInt[h], ":"]; RETURN [time.Cat [TwoPosInt[m], ":", TwoPosInt[s]]] END; -- TimeToRope doc: ROPE ~ "tunes the parameters of Nectarine.\n\t-a do not align rectangles to pixels (schematics)\n\t-b outline regions\n\t\t-1: no outline\n\t\t 0: one pixel outline\n\t\t 1: unit width outline\n\t-c do not use (reveal tess.)\n\t-d <1/density> controls the size of bands (risk)\n\t-e do not trace color inferences\n\t-f do not use ChipNDale to image annotation\n\t-g ignore annotation (image only rectangles)\n\t-h do rectangles\nIf a boolean switch is absent, it is set to TRUE.\n[Additional commands: NCount, NRedo, NQuery, NWriteColors, NReadColors, NOldColors, PrintDesignOnVersatec, NectarineField, NSetMaxField, NectarineSignal]."; fieldDoc: ROPE ~ "explicitly set the field size to perform image ganging. Specify the field in mm\n\t-x lower left corner x\n\t-y lower left corner y\n\t-w width\n\t-h height\nDefaults: x: medium.x + 10.0, y: medium.y + 10.0, w: medium.w - 20.0, h: medium.h - 20.0; where medium = [x: 0.0, y: 0.0, w: 215.9, h: 279.4]\n[Additional commands: NCount, NRedo, NQuery, NWriteColors, NReadColors, NOldColors, PrintDesignOnVersatec, Nectarine, NSetMaxField, NectarineSignal]."; signalDoc: ROPE ~ "controls the rendering of signal names. If no parameter is specified, they will rendered with a 5 CMOS-lambda font. If a positive value is specified with the -a switch, this values is used as the font size, otherwise the rendering of signal names is disabled. If switch -b is not specified or positive, the names are centered, otherwise they start at the origin. Side-effect: Nectarine's -f switch is set.\n[Additional commands: NCount, NRedo, NQuery, NWriteColors, NReadColors, NOldColors, PrintDesignOnVersatec, NectarineField, NSetMaxField, Nectarine]."; argError: ROPE; SetSwitches: Commander.CommandProc ~ BEGIN align, outlineType, tess, density, inferenceTrace, ann, skipAnn, hyp: Args.Arg; prevTraceValue: BOOL ~ traceColourInferences; IF (Args.NArgs [cmd] # 0) THEN BEGIN [align, outlineType, tess, density, inferenceTrace, ann, skipAnn, hyp] _ Args.ArgsGet [cmd, "-a%b-b%i-c%b-d%i-e%b-f%b-g%b-h%b" ! Args.Error => {argError _ reason; GOTO failure}]; layout _ (align.ok AND align.bool); IF outlineType.ok THEN outline _ SELECT outlineType.int FROM < 0 => -1.0, > 0 => 1.0, ENDCASE => 0.0; showTesselation _ (tess.ok AND tess.bool); IF density.ok THEN risk _ density.int; traceColourInferences _ (inferenceTrace.ok AND inferenceTrace.bool); letChipndaleCallTheImager _ NOT (ann.ok AND ann.bool); ignoreAnnotation _ (skipAnn.ok AND skipAnn.bool); IF debug THEN imageRegions _ (hyp.ok AND hyp.bool) END; msg _ IO.PutFR ["Nectarine parametrisation: layout = %g, outline = %g, risk = %g, annotation via cd = %g, ignore annotation = %g\nYou typed: Nectarine", IO.bool [layout], IO.real [outline], IO.int [risk], IO.bool [letChipndaleCallTheImager], IO.bool [ignoreAnnotation]]; IF layout THEN msg _ msg.Concat [" -a"]; msg _ IO.PutFR ["%g -b %g -d %g", IO.rope [msg], IO.int [Round [outline]], IO.int [risk]]; IF traceColourInferences THEN msg _ msg.Concat [" -e"]; IF NOT letChipndaleCallTheImager THEN msg _ msg.Concat [" -f"]; IF ignoreAnnotation THEN msg _ msg.Concat [" -g"]; IF imageRegions THEN msg _ msg.Concat [" -h"]; IF (traceColourInferences # prevTraceValue) THEN BEGIN [] _ ResetLayerColourTable []; IF SubColours [] THEN BlendTileColours [] END; EXITS failure => RETURN [$Failure, argError.Cat ["\n", doc]] END; -- SetSwitches SignalNames: Commander.CommandProc ~ BEGIN size, alignement: Args.Arg; [size, alignement] _ Args.ArgsGet [cmd, "-a%i-b%i" ! Args.Error => {argError _ reason; GOTO failure}]; IF (Args.NArgs [cmd] = 0) OR (NOT size.ok) THEN size.int _ 5; -- in l IF (size.int <= 0) THEN size.int _ 0; IF size.int > 0 THEN BEGIN regularFace: Font ~ ImagerFont.Find ["Xerox/PressFonts/Modern-MRR", substituteQuietly]; signalNameFont _ regularFace.Scale [8 * size.int]; msg _ IO.PutFR ["Signal names will be imaged and their size will be %g CMOS-lambdas.", IO.int [size.int]]; letChipndaleCallTheImager _ FALSE END ELSE {signalNameFont _ NIL; msg _ "Signal names will not be imaged"}; IF alignement.ok THEN centerSignalNames _ (alignement.int > 0); msg _ IO.PutFR ["%g Centered signal names = %g.", IO.rope [msg], IO.bool [centerSignalNames]]; EXITS failure => RETURN [$Failure, argError.Cat ["\n", signalDoc]] END; -- SignalNames UserProfile.CallWhenProfileChanges [GetStatisticsToggle]; Commander.Register [key: "Nectarine", proc: SetSwitches, doc: doc]; Commander.Register [key: "NectarineSignals", proc: SignalNames, doc: signalDoc] END. †ÒNectarineImpl.mesa Copyright Ó 1986, 1987, 1988 by Xerox Corporation. All rights reserved. Giordano Bruno Beretta, April 11, 1986 7:57:41 pm PST gbb October 14, 1988 11:46:38 am PDT Implements an alternate way to produce Interpress masters from ChipNDale drawings. The difference is in the user interface. It is similar to the one in programs by Imaging Folks, and it is simpler to use for casual users. Fuzzless and sweeter than peaches (S. Williams) Interpress USING [classAppearanceError, classAppearanceWarning, classComment, classMasterError, classMasterWarning, Close, DoPage, LogProc, Master, Open], SimpleMailer USING [SendMessage, SendMessageInfo], Implementation note on clipping: If bands have to be created because of the size of the design, true clipping to bands must be done when traversing the design. The penalty on the corner stitched data structure may be swallowed, since it is an overnight job anyway. However, leaving clipping to the Imager, you will have all those rectangles in the Interpress master with their multiciplity. A large disk can hold only about 90% of a thing like the Cross-RAM, and every single file on your disk will have been flushed off when you come in in the morning. If you insist on leaving the clipping to the imager, then you must be very careful deciding where to place it. The reason is that clipping in the Imager is relative, and therefore the window must be specified inside Do-Save-Simple-Body, in order not to disturb the global clipping window. The places would be EnumerateGeometry and EnumerateTextInDesign. Geometry Does what FreeTesselation supposedly did once upon a time. Probably for speed reasons the Imager uses 16 bit integers. PROC [tile: REF Tile, data: REF] PROC [tile: REF Tile, data: REF] PROC [tile: REF Tile, data: REF] PROC [tile: REF Tile, data: REF] PrintAlignedTile: CStitching.TileProc ~ BEGIN PROC [tile: REF Tile, data: REF] This version is much slower than PrintTile. It uses 4 additional operations and 12 additional bytes. This buys that all rectangles get aligned to pixels. This makes that all wires in schematics are printed with the same width. state: State ~ NARROW [data]; b: Blend ~ NARROW [tile.value]; r: CD.Rect ~ CStitching.Area [tile]; -- not the area but the rectangle ! ir: Imager.Rectangle ~ ImagerRect [r]; MaskAlignedRectangle: PROC ~ BEGIN state.context.SetXY [[ir.x, ir.y]]; state.context.Trans []; state.context.MaskRectangle [[0, 0, ir.w, ir.h]] END; -- MaskAlignedRectangle ChangeColour [state, b.blend]; state.context.DoSave [MaskAlignedRectangle]; IF state.abort^ THEN ERROR ABORTED; IF (outline >= 0.0) AND (b.blend # blackBlack) THEN BEGIN tc: TileAndContext ~ NEW [TcRec _ [tile, state.context]]; ChangeColour [state, blackBlack]; ChangeStrokeWidth [state, outline]; state.tess.EnumerateNeighborhood [tile, SouthRim, WestRim, NorthRim, EastRim, tc, nothing] END; IF statistics THEN BEGIN l: CD.Number ~ state.design.technology.lambda; b.area _ b.area + ((r.x2 - r.x1) / l) * ((r.y2 - r.y1) / l); state.cardTile _ SUCC [state.cardTile] END END; -- PrintAlignedTile PROC [tile: REF Tile, data: REF] PROC [tile: REF Tile, data: REF] This is an experiment for Cedar 7.0. Michael Plass has changed the implementation of MaskVector so that it gives the result of PrintAlignedTile at the cost of PrintTile. AddTile: CStitching.TileProc ~ BEGIN PROC [tile: REF Tile, data: REF] state: State ~ NARROW [data]; colour: Blend ~ NARROW [tile.value]; band: CD.Rect ~ IF (state.band = NIL) THEN state.cdClip ELSE CDBasics.Intersection [state.cdClip, state.band^]; r: Box ~ BoxFromRect [tile.Area, band]; state.colorRegion[colour.index.ABS - 1].used _ TRUE; state.colorRegion[colour.index.ABS - 1].hyp.Fill [r] END; -- AddTile PROC [tile: REF Tile, data: REF] PROC [tile: REF Tile, data: REF] Prints a band. If there is only one band and no clipping is necessary, setting clip to false will make it faster. [r: Rect, l: Layer, pr: DrawRef] Note that merging works correctly because of the use of the colour table. [plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF] NewScaledRect: CD.DrawRectProc ~ BEGIN [r: Rect, l: Layer, pr: DrawRef] state: State ~ NARROW [pr.devicePrivate, State]; rect: CD.Rect _ [r.x1/regionShrink, r.y1/regionShrink, r.x2/regionShrink, r.y2/regionShrink]; rect _ IF (state.band = NIL) THEN rect ELSE CDBasics.Intersection [rect, state.band^]; IF (CDBasics.NonEmpty [rect]) THEN BEGIN Note that merging works correctly because of the use of the colour table. dec: Tess ~ state.tess; InsertRect: CStitching.RectProc = BEGIN [plane: REF Tesselation, rect: Rect, oldValue: REF, data: REF] WITH oldValue SELECT FROM b: Blend => IF NOT b.flavours[l] THEN dec.ChangeRect [rect: rect, new: ColourTile [b, l]]; ENDCASE => BEGIN b: Blend _ NEW [BlendRec]; dec.ChangeRect [rect: rect, new: ColourTile [b, l]] END END; -- InsertRect dec.ChangeEnumerateArea [rect: rect, eachRect: InsertRect, skip: nothing]; END END; -- NewScaledRect Annotation This is a special temporary hack that hacks out the transformation required to print the same thing as ChipNDale displays in the class $FlipText. Do not try to understand it from a geometrical point of view, it is brain-dammaged. adjustY: Transformation ~ ImagerTransformation.Translate [[0, +(obj.bbox.x2 - obj.bbox.x1)]]; The transformation sequences in comment are what has been reconstructed using the Interpreter as what ChipNDale does. rotate180, rotate90 => adjustXY.Cat [rot180], -- TxySxyR rotate180, rotate90 => adjustXY.Cat [adjustY, rot180], -- TxyTySxyR [pr: CD.DrawRef, ob: CD.Object, trans: CD.Transformation_[], readOnlyInstProps: CD.PropList_NIL] Obviously it is bogus to use the bounding box of the bits instead of the font metrics. However, ChipNDale uses the bits, and therefore the rope will be off and the user will manually shift it in place. Since the user corrects manually this error, Nectarine has to intentionally introduce this error to make things look the same on the screen and on paper. In particular, if text is changed from rigid to flipped, or vice versa, it will be off by the difference between the font metrics and the bit approximation. However, also what the user seen on the screen is off, because ChipNDale uses the bit approximation. Since he will ``fix'' it manually, Nectarine must introduce the same error. Correct offset: offset.x _ offset.x + (ImagerFont.RopeEscapement [font: text.cdFont.font, rope: text.text].x) - (ImagerFont.RopeEscapement [font: state.previousFont, rope: text.text].x); A wild guess that is closer to the above. [pr: CD.DrawRef, ob: CD.Object, trans: CD.Transformation_[], readOnlyInstProps: CD.PropList_NIL] [pr: CD.DrawRef, ob: CD.Object, trans: CD.Transformation_[], readOnlyInstProps: CD.PropList_NIL] [r: Rect, l: Layer, pr: DrawRef] The border is drawn outside the cell, since this is the way they are used by Rick Barth, currently the only creator of documents using boxes. Convert the object border into an Imager trajectory. Draw it ! Note that the stroke ends and joints are round. [r: Rect, l: Layer, pr: DrawRef] The border is drawn outside the cell, since this is the way they are used by Rick Barth, currently the only creator of documents using boxes. Convert the object border into an Imager trajectory. Draw it ! Note that the stroke ends and joints are round. DrawObjectBorder: CD.DrawRectProc ~ BEGIN [r: Rect, l: Layer, pr: DrawRef] The border is drawn outside the cell, since this is the way they are used by Rick Barth, currently the only creator of documents using boxes. state: State ~ NARROW [pr.devicePrivate, State]; pen: REAL ~ Float [state.design.technology.lambda / 2]; object, border: Imager.Rectangle; Process.CheckForAbort []; IF state.abort^ THEN ERROR ABORTED; ChangeColour [state, blackBlack]; object _ ImagerRect [r]; South: object.x _ object.x - pen; object.y _ object.y - pen; object.w _ object.w + 2 * pen; object.h _ object.h + 2 * pen; border _ [x: object.x, y: object.y, w: object.w , h: pen]; state.context.MaskRectangle [border]; West: border _ [x: object.x, y: object.y, w: pen, h: object.h]; state.context.MaskRectangle [border]; East: border _ [x: object.x + object.w - pen, y: object.y, w: pen, h: object.h]; state.context.MaskRectangle [border]; North: border _ [x: object.x, y: object.y + object.h - pen, w: object.w, h: pen]; state.context.MaskRectangle [border] END; -- DrawObjectBorder [pr: CD.DrawRef, ob: CD.Object, trans: CD.Transformation_[], readOnlyInstProps: CD.PropList_NIL] The procedure for rectangles is called through the recursion step. [pr: CD.DrawRef, ob: CD.Object, trans: CD.Transformation_[], readOnlyInstProps: CD.PropList_NIL] The procedure for rectangles is called through the recursion step. Interpress Produces an Interpress master of the design. The master is scaled such that it fits a whole page. chipNDaleWindow is either the bounding box of the design or a window in it. In the latter case, clip must be set to TRUE, and objects completetly outside the window will be ommitted from the Interpress master (because of things like mitering, actual clipping can be performed only when a bitmap is created). The usedField is specified in millimetres. It is useful for subsequent processing of the Interpress master as long as this field cannot be specified in the preamble of Interpress masters themselves. If onlySel is true, only the selected object are included in the Interpress master. If singleLayer is true, only objects in the layer layer are included in the Interpress master. If lambda = 0 then scale such that the window fills the field, else scale such that 1  will be lambda mm in the Interpress master. If not last page, the Interpress master is not closed, hence the next call of this procedure will add a page to the same master instead of creating a new document. May return signal tooComplex if it is believed that there might be too many rectangles in a horizontal cross section. The used criterion is the width of the design; if you do not agree, use the Interpreter to increase the risk. Creates the interpress master. Version number alone are not sufficient to allow for different files with the same name. In fact, independently of the version numbers, some tools have the property to get notified if a new version of a file is created, replacing the file they are working on in favour of the new version. Called back by the Interpress machinery. state.context.SetPriorityImportant [TRUE]; -- see EnumerateGeometry Preview considers the top of the page to be most important, because we write text from top to bottom. Also designers want have images to be flush to the top of the field, so they can use the bottom of the medium for hand-annotations. Unfortunately, this causes a severe problem when producing a PD file. In fact there is said to be a hack fixing a hard bug in the Peach software. This hack is said to be a white rectangle at the lower left corner of the medium. On the Versatec this means that with every image in landscape format you would get metres of white paper. This is why images are positioned in the lower left corner of the field. y0 _ IF ratioH < ratioW THEN 0.0 ELSE field.h - shrunkWindow.h * ratioW; IF (ratioH < ratioW) THEN usedField.x _ (field.w - usedField.w) / 2.0; This hack is necessary because colours will be OR-ed. Rectangles: Magic numbers: 1000 bytes per line, cylinder holds 64 lines. There are 27 bitmaps. You also need space for finding the intersections. Magic numbers: Assume 14 MB of memory may be used. Each tile requires 16 words of storage (14 words for the tile and 2 words Cedar overhead), hence 106 tiles can be stored. In the current worst case, a die is 10 mm wide. If a gate can be 2 mm long, in the worst case there is a rectangle each mm. In the average there are as many space tiles as there are colored tiles. The intersection of the current band with the clipping window is performed by PrintBand. The field state.cdClip is assigned earlier. Produce bands from high to low y-coordinate values in order to avoid paging in succeeding software. The first bands are not typical, because they are not dense. Text: The stroke joint must be round, because a ChipNDale staightline segment [a, b] is made out of a spline [a, b, a'], where d (a, a') < e. The end must also be round because polygons are drawn as polylines with common endpoints. Now you think that's all and zip. Wrong, you darn sucker. Of course Chipndale does not use the Color Registry, but uses an own hack of it. So here we go to consult the Color Hyper Registry (I should have trade marked this) to build a a fourth color registry and give it to Chipndale. Does it at background priority. Produce preamble. It is not possible to declare all colours in the preamble, because the size of the Interpress frame is 50 entries (this is defined in the Standard). This is a terrible hack, since the colours in the table are those from the previuos run. Unfortunately the Imager does not permit to define the preamble when all the data has been processed. Create a table of the fonts and them in the preamble. Produce the page. All coordinates will be in millimetres. Close. Main of DoInterpress Same as CDOps.DrawDesign, but visits only the selected objects. Same as CDOps.DrawDesign, but visits objects only once. PROC [name: ROPE, ob: CD.Object] RETURNS [quit: BOOL_FALSE] At this point we know that only one colour representation is used. Must be fast as a bullet. ChangeColour: PROC [state: State, colour: Color] ~ INLINE BEGIN At this point we know that only one colour representation is used. Must be fast as a bullet. context: Imager.Context ~ state.context; a: ImagerColor.RGB ~ RGBFromColour [colour]; b: ImagerColor.RGB ~ RGBFromColour [state.previousColour]; IF (a.R # b.R) OR (a.G # b.G) OR (a.B # b.B) OR (state.previousColour = NIL) THEN BEGIN context.SetColor [colour]; state.previousColour _ colour END END; -- ChangeColour w < 0 means that it has not yet been set in this body. Must be fast as a bullet. Must be fast as a bullet This is nasty code. The trade off was between sort of a hack, 20 minutes of CPU on full chips, and this fix here. I wanted to find all fonts appearing in the design in order to declare them in the preamble. The most stupid thing somebody could do, would be to use a ChipNDale drawProc to visit all text objects [this can take 20 minutes of CPU]. In fact you only need to visit once every object. In ChipNDale you do this by enumerating the directory. Unfortunately ChipNDale has one object which is never in the directory, namely the root cell. In order to avoid the unesthetic special code for the root, the fonts used in the root object are not cached. In the normal case, no fonts are missed, because if there are non-cell objects in the root then usually they have some buddy inside an official cell. So all this was to justify why the print font can be L and has to be handled here at this stange place. All in all I don't care, so if you want to do something different just go ahead (the quickest would be to bypass the ChipNDale directory enumeration procedure and to do your own; this is easy if you use my table called visitedCells). Conversions Data is global [pr: CD.DrawRef, ob: CD.Object, trans: CD.Transformation_[], readOnlyInstProps: CD.PropList_NIL] There is no facility offered by ChipNDale to visit only a cell without recursing to its subcells, so here is a homebrew hack. [pr: CD.DrawRef, ob: CD.Object, trans: CD.Transformation_[], readOnlyInstProps: CD.PropList_NIL] The map is global, because fonts rarely change across designs. DrawDesign is an overkill, which easily takes 20 minutes on the CrossRAM. There is no facility offered by ChipNDale to visit only a cell without recursing to its subcells, so here is a homebrew hack. Translates from strike to spline fonts. Find the size and face from the old style name: Compute the size (assume: there always is a size): Determine the face: Box: TYPE ~ RECORD [min, max: Vec _ zeroVec]; b: Box denotes all v: Vec that satisfy v.s IN[b.min.s..b.max.s) AND v.f IN[b.min.f..b.max.f) RETURN [[min: [f: r.x1, s: viewport.y2-r.y2], max: [f: r.x2, s: viewport.y2-r.y1]]] CdPos: PROC [v: Imager.VEC] RETURNS [CD.Position] ~ BEGIN RETURN [[InlineRound[v.x], InlineRound[v.y]]] END; -- CdPos Assume that LayerColour had previously been called. Writes a message in the ChipNDale terminal viewer and in the Message Window at the top of the LF screen and makes it blink. [r: Rect, l: Layer, pr: DrawRef] [r: Rect, l: Layer, pr: DrawRef] Printing Produces (if necessary) a PD file from an Interpress master and ships it to the printer. Valid printer keys are $NVersatec, $NColorVersatec, $NPeachExpand, $NBw400, $NColor400, $NPlateMaker, $NRaven300, $C2700, $NRaven384. May return signals invalidPrinter. If the image is in portrait format and the printer uses roll paper, the rectangle usedField from DoInterpress can be specified as a sizeHint to increase the scale so a to use the full roll width. If doNotScale then Print does not fit the field to the medium. Process.CheckForAbort has to be called because of the Redo command. Note: the Interpress decomposer shifts to the right by 7.9375 mm and up by 12.7 mm. sent: BOOL; info: SimpleMailer.SendMessageInfo; user: ROPE ~ UserCredentials.Get[].name; erieSeparations: ROPE _ UserProfile.Token ["Nectarine.PlatemakerSeparations"]; Following statement is wrong: need to call MergeRegisterMarks first. gName: ROPE ~ FS.Copy [from: masterName, to: Rope.Cat ["[Cyan]Platemaker>", user, ">", masterName.Substr [pos.base.start, pos.base.length], ".Interpress"]]; IF erieSeparations.IsEmpty THEN break; [sent, info] _ SimpleMailer.SendMessage [from: "Nectarine", to: LIST ["Scamporrino.PA"], cc: LIST [user], subject: "Platemaker Print Request", body: Rope.Cat ["Dear Bridget,\n\nHow are you today ?\nPlease print for me the file ", gName, ".\n\nThe Interpress master is in A size with a margin of 1 cm on each side.\n\nThis master is for your convenience to preview the picture on a monitor. In a while, you will also find there the required separations ready to be printed. I will send you a message with the names as soon as I will have produced them.\n\nThank you,\n", user]]; IF NOT sent THEN ImportantMessage [Rope.Cat ["Ask Bridget Scamporrino to print ", gName, " for you."]]; SELECT info FROM ok => TerminalIO.PutRope ["Your job will be printed as fast as possible.\n"]; invalidRecipient => TerminalIO.PutRope ["The person in charge of Platemaker has changed. Please consult a wizard.\n"]; noValidRecipients => TerminalIO.PutRope ["Nectarine can no longer handle printing on Platemaker. Please consult a wizard.\n"]; badPwd => TerminalIO.PutF ["Your password is invalid. May be you just changed it and did not roll-back. Ask Bridget Scamporrino to print %g for you.\n", IO.rope [gName]]; badSender => TerminalIO.PutF ["You need a Grapevine account to print on Platemaker with no hands. Ask Bridget Scamporrino to print %g for you.\n", IO.rope [gName]]; badReturnTo => TerminalIO.PutRope ["Implementation problem.\n"]; allDown => TerminalIO.PutF ["The mail system is down. Ask Bridget Scamporrino to print %g for you.\n", IO.rope [gName]]; ENDCASE => ERROR Statistics Although the INT returned BasicTime.Period is the same as GMT and might hence be loopholed to use IO.time from Conversions, the latter uses BasicTime.Unpack which allows only values that give a valid date. Initialization PROC [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] Sets the switches which control the tuning of Nectarine. PROC [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] gbb September 4, 1986 1:49:44 pm PDT Made a change to avoid anti-aliasing. All rectangles are now printed with the lower left corner starting on a pixel. changes to: DIRECTORY, PrintAlignedTile, MaskAlignedRectangle (local of PrintAlignedTile), PrintTile, PrintBand, EnumerateGeometry (local of PrintBand) gbb September 4, 1986 5:51:47 pm PDT Changed the border of cells from a sequence of rectangles to a trajectory. changes to: DIRECTORY, IMPORTS, DrawObjectBorder, DotDotDotSpace (local of DrawObjectBorder), DrawObject gbb September 5, 1986 11:09:19 am PDT Added the parameter sizeHint to the print procedure. changes to: PeachProcess, Print gbb September 19, 1986 7:14:38 pm PDT Black toner for color Versatec had gone lost somewhen. changes to: PeachProcess gbb September 22, 1986 3:26:33 pm PDT Added capability to produce tone separations for PlateMaker. changes to: DIRECTORY, PeachProcess, Print gbb September 23, 1986 6:04:17 pm PDT Addded filled trajectories. changes to: DIRECTORY, DrawArea, DrawObjectBorder, DrawObject gbb September 24, 1986 3:47:17 pm PDT Fixed scaling for devices with cut paper. Changed colour model used to print black. Added 1 to the height of bands. changes to: DIRECTORY, DrawToIP (local of DoInterpress), black, unColour, BlendColours, PeachProcess. gbb September 25, 1986 8:00:34 pm PDT Bypassed an arcane bug in the compiler. changes to: PeachProcess: see implementation note. gbb October 2, 1986 1:01:19 pm PDT Introduced a mild temporary hack to fix a server locking problem until the new print server software becomes available in about three to four weeks. Finished adjusting and testing all the little details to print on Platemaker at 1200 lines per inch resolution. Instructions are written in the Terminal viewer. When submitting the separations, please advise the operator that the separations make use of the full device size. changes to: Action (local of DoInterpress), PeachProcess gbb October 7, 1986 3:36:11 pm PDT Tweeking the rendition of colours on the Versatec. changes to: PeachProcess gbb October 9, 1986 1:47:12 pm PDT Handle gracefully the limit of 50 entries in the Interpress frame. changes to: DIRECTORY, Action (local of DoInterpress) gbb December 5, 1986 1:48:47 pm PST Added Raven 384 printer changes to: PeachProcess, Print. gbb December 18, 1986 4:52:55 pm PST In ChipNdale 23 cut (cut-2) was always black (blue), but in rel. 24 was displayed black (blue) and printed blue (green). changes to: SetLayerColourTable: cut is forced to black and cut-2 to blue. gbb December 18, 1986 7:52:00 pm PST In mid-december 1986, the Interpress to PD software has changed, and the speed-up trick of turning off the Interpress imaging model for the tesselated geometry does no longer work. The new regime is: the imager priority is always set to important, but setting NectarineImpl.layout _ TRUE in the interpreter, the priority is turned off. In addition rectangles are no longer aligned to pixels, avoiding the white strikes. changes to: OPEN, EnumerateGeometry (local of PrintBand), EnumerateTextInDesign (local of DrawToIP, local of DoInterpress), DrawToIP (local of DoInterpress), BlendRec, BlendColours, SetLayerColourTable gbb December 24, 1986 10:33:00 am PST Since gates are very important, they are given double weight. changes to: doubleYellowRGB: doubled, BlendColours: double weight for gates. gbb February 2, 1987 6:02:40 pm PST Added the capability to print at a given scale, i.e., to define  in millimetres changes to: DoInterpress added parameter lambda, DrawToIP (local of DoInterpress): fixed scaling, Print: added parameter doNotScale. gbb February 6, 1987 1:20:30 pm PST Added XNS printing service. changes to: DIRECTORY, IMPORTS, submittedPrintRequests: interim, XNSwatch:interim, PdPrintProcess, Print. gbb February 7, 1987 6:56:46 pm PST Added queueing for XNS printing service. changes to: DIRECTORY, XNSinfo, PrintRequest, PrintRequestRec, pendingRequests, AnalyzeSubmitted (local of ReportXNSprintingStatus), Resubmit (local of ReportXNSprintingStatus), ReportXNSprintingStatus, PdPrintProcess gbb February 9, 1987 1:59:04 pm PST Added a watcher because this stuff does not work in the Cedar 6.1 version of XNS printing. changes to: DIRECTORY, PrintRequestRec, niceGuyQueueSize, XNSfinalisation, XNSwatcher, ReportXNSprintingStatus, Resubmit (local of ReportXNSprintingStatus), PdPrintProcess, UserProfile, TRUSTED gbb February 10, 1987 2:56:47 pm PST Added the ability to print only a single layer. changes to: OPEN, StateRec, NewRect, DrawText, DrawPath, DrawArea, DrawObjectBorder, DrawDashedObjectBorder, DoInterpress, DrawToIP (local of DoInterpress), Action (local of DoInterpress), DrawSelection, niceGuyQueueSize gbb March 16, 1987 3:22:03 pm PST Added capability to print multi-page documents for the Dragon documentation. changes to: StateRec, DoInterpress, DrawToIP (local of DoInterpress), Action (local of DoInterpress), PdPrintProcess gbb March 25, 1987 3:26:43 pm PST Changed scaling for Platemaker to be fixed to 1.0 instead of using Platemaker's device size. changes to: PdPrintProcess gbb March 31, 1987 4:12:04 pm PST Took out pending queue, because did never get notification from printer, hence locking up the transfer. Now everything is just shipped off to the printer. changes to: PrintRequestRec, submittedRequests, XNSfinalisation, AnalyzeSubmitted (local of ReportXNSprintingStatus), ReportXNSprintingStatus, PdPrintProcess, UserProfile gbb April 14, 1987 4:16:31 pm PDT Implemented new user profile option to substitute named colors. Imager error is caught and bogus colors are replaced by black. changes to: DIRECTORY, DrawToIP (local of DoInterpress), SetLayerColourTable gbb April 17, 1987 3:25:52 pm PDT Radically changed printing on Platemaker. changes to: DIRECTORY, IMPORTS, Print gbb May 19, 1987 1:22:59 pm PDT Optimized main data space storage requirements for the case of Interpress printers. changes to: PdPrintProcess, Print gbb May 19, 1987 5:42:42 pm PDT Added a command that allows to parametrize Nectarine via straight commands instead of using the Interpreter. changes to: DIRECTORY, IMPORTS, OPEN, StateRec, OpenIPMaster (local of DoInterpress), DoObject (local of EnumerateObjects), Mapping, ImportantMessage, ResetColourStatistics, doc, SetSwitches, UserProfile, Commander. gbb May 26, 1987 4:27:06 pm PDT Added capability to draw borders of regions (rims). changes to: DIRECTORY, Tile, TileAndContext, TcRec, FlushDecomposition, SouthRim, EastRim, NorthRim, WestRim, PrintAlignedTile, PrintTile, PrintBand, EnumerateGeometry (local of PrintBand) gbb June 5, 1987 1:08:47 pm PDT Added color corection for PD devices. changes to: FillSample (local of PdPrintProcess), PdPrintProcess gbb June 5, 1987 5:49:44 pm PDT Added some redundant consistency checks because of a spurious problem in printing very large multi-page Interpress masters. Michael Plass has changed the implementation of MaskVector so that it gives the result of PrintAlignedTile at the cost of PrintTile. changes to: DIRECTORY, OPEN, FastMaskVector, SouthRim, EastRim, NorthRim, WestRim, NewPrintTile, PrintBand, EnumerateGeometry (local of PrintBand), multipageHack, DoInterpress, Action (local of DoInterpress), Set (local of FillSample, local of PdPrintProcess), PdPrintProcess gbb June 8, 1987 4:37:40 pm PDT Added grey balance. changes to: PdPrintProcess gbb June 12, 1987 4:14:04 pm PDT Changed the layer $yellow to print as n-well and $blue as metal-1, because that's what you see on the screen. Up to Cedar 6.1, Imager.black was printed on the black separation. Starting from 7.0, it is printed on all layers except black because of the 3-dimensionality of the thermal transfer printing process. Since this in not wanted for schematics, black is now taken from the CMYK color model instead of RGB linear. changes to: DIRECTORY, DoInterpress, Action (local of DoInterpress), blackBlack, SetLayerColourTable, DrawText gbb June 16, 1987 3:02:24 pm PDT A new procedure PrintStippledTile has been introduced, that paints every tile once for every layer intersecting in it. If no colour substitution is performed, this allows to produce exactly the same output as with the checkplot software, except that outlines can be drawn around regions if the user wishes so. changes to: StateRec, OPEN, SouthRim, EastRim, NorthRim, WestRim, PrintStippledTile, PrintBand, EnumerateGeometry (local of PrintBand), OpenIPMaster (local of DoInterpress), DoInterpress gbb June 16, 1987 4:35:04 pm PDT Optimized outiles for named colours. Maureen Stone will be notified by mail every time an Interpress master with named colours is used. changes to: SouthRim, EastRim, NorthRim, WestRim, Action (local of DoInterpress), DoInterpress, Print gbb June 17, 1987 11:21:25 am PDT Implemented a concertated change with the Imager that speeds-up the raster-scan conversion of a factor 3. changes to: PrintTile, PrintStippledTile gbb June 17, 1987 5:38:22 pm PDT CDColors changed to CDColorsExtras with different semantics. changes to: DIRECTORY, IMPORTS, SetLayerColourTable gbb June 18, 1987 10:01:52 am PDT 1000 details for ChipNDale's special colors. changes to: DIRECTORY, PrintBand, DrawObjectBorder, DrawDashedObjectBorder, DrawToIP (local of DoInterpress), cyan, red, SetLayerColourTable, previousColorSubEntry, GetStatisticsToggle gbb June 22, 1987 1:12:14 pm PDT Following an expert advice, colours are taken from the Imager instead from ChipNDale. changes to: DIRECTORY, SetLayerColourTable gbb June 23, 1987 3:26:58 pm PDT The inheritance scheme for the colour registries turned out to be unsafe. Hence, it has been substituted by a rule based inference engine. changes to: OPEN, undefColour, SetLayerColourTable, MakeConstant (local of SetLayerColourTable), ColourName (local of SetLayerColourTable), InferenceStatus (local of SetLayerColourTable), Decide (local of SetLayerColourTable), One (local of SetLayerColourTable), Two (local of SetLayerColourTable), Three (local of SetLayerColourTable), Four (local of SetLayerColourTable), Five (local of SetLayerColourTable), Six (local of SetLayerColourTable), Seven (local of SetLayerColourTable), Nine (local of SetLayerColourTable), Ten (local of SetLayerColourTable), doc, SetSwitches gbb June 24, 1987 10:36:28 am PDT Put colour registry inference engine in a separate module because a limit in the code generation part of the compiler was blown. changes to: DIRECTORY, IMPORTS, OPEN, colourTable, ColourTile, BlendColours, GetStatisticsToggle, SetSwitches gbb June 30, 1987 5:33:12 pm PDT Introduced a fourth color registry so that ChipNDale can be used to draw the annotation. This was necessary for some undiscovered spurious side-effect lurking somewhere deep in its guts. Since ChipNDale does not use the Color Registry, we have to put him up one. changes to: DIRECTORY, OPEN, DrawToIP (local of DoInterpress) gbb September 16, 1987 11:06:27 am PDT Changed the font name parser to be independent of an eventual working directory in which ChipNDale might have been forked as a process. changes to: Mapping. gbb October 28, 1987 3:20:46 pm PST Added creation and automatic submission of separations for printing on Platemeker. changes to: PdPrintProcess, Print gbb November 10, 1987 11:19:23 am PST Standardization of Cromalin pigments to SOP-Cyan, SOP-Magenta, and SOP-Yellow. changes to: PdPrintProcess. gbb November 16, 1987 1:35:44 pm PST Another attempt to simulate what happened from 24 to 25 with the font offset. changes to: DrawText, DIRECTORY gbb November 25, 1987 5:11:22 pm PST Merged colour blending into NectarineHyperRegistryImpl and renamed it into NectarineColourImpl. changes to: DIRECTORY, IMPORTS, EXPORTS, OPEN, Action (local of DoInterpress), DoInterpress, ProgressLog, previousColorSubEntry, GetStatisticsToggle gbb December 3, 1987 11:01:23 am PST Changed the default for grey balancing to TRUE. Made printing abortable from the ChipNDale viewer. changes to: PdPrintProcess, Print. gbb December 5, 1987 3:50:23 pm PST Added alignement marks to the separations for Platemaker. changes to: DIRECTORY, IMPORTS, MergeAlignementMarks, DoIt (local of MergeAlignementMarks), PdPrintProcess, Print. gbb December 9, 1987 5:01:01 pm PST New switch to image only rectangles changes to: doc. gbb December 14, 1987 2:16:55 pm PST Peach printing is now forked off. changes to: PdPrintProcess. gbb December 15, 1987 4:32:40 pm PST The Interpress masters for Platemaker are now being merged with the alignment marks. This means, that it is no longer possible to translate or scale during the InterpressToPD conversion; the user has to live with the 1 cm margin. changes to: PdPrintProcess: eliminated tx, ty, and scale in the Platemaker case. gbb December 22, 1987 11:23:18 am PST Tweaked screening for Versatec. changes to: DrawToIP (local of DoInterpress), Action (local of DoInterpress), PdPrintProcess. gbb December 31, 1987 3:57:54 pm PST New user profile option Nectarine.ContinuousTone: BOOL _ FALSE. Set to TRUE when separations are created by an electronic color scanner or by photographic halftoning. changes to: Action (local of DoInterpress). gbb January 4, 1988 4:11:58 pm PST Added a command to explicitly set the field size to perform image ganging. changes to: OPEN, doc, fieldDoc, SetSwitches, SetField, Commander, Commander gbb January 5, 1988 5:59:25 pm PST Introduced line art. changes to: DrawToIP (local of DoInterpress), Action (local of DoInterpress), DoLineArt, ImportantMessage, LineRect, previousColorSubEntry, previousLineArtEntry, GetStatisticsToggle gbb January 9, 1988 4:00:17 pm PST Re-implemented high resolution high speed halftoning. changes to: PdPrintProcess gbb January 12, 1988 11:32:22 am PST Trying to reduce local disk sace requirements by 75% in the case of platemaker output. changes to: DIRECTORY, IMPORTS, ForcedDelete, MergeRegisterMarks, PdPrintProcess gbb January 29, 1988 7:51:09 pm PST Dusted off an old algorithm for finding multiple connected regions. changes to: DIRECTORY, OPEN, StateRec, AddTile, PrintStippledTile, EnumerateGeometry (local of PrintBand), PrintBand, NewScaledRect, DrawToIP (local of DoInterpress), ChangeFont, BoxFromRect, doc, SetSwitches, Commander gbb February 10, 1988 4:26:09 pm PST Tuned the algortihm with respect to the Cedar Imager changes to: OPEN, AddTile, DrawToIP (local of DoInterpress) gbb August 12, 1988 11:32:43 am PDT Added the capability to render signal names (for debugging routers, requested by Bryan Preas) changes to: DIRECTORY, IMPORTS, OPEN, DrawObject, DrawObjectWithSignalNames, DrawToIP (local of DoInterpress), Action (local of DoInterpress), fieldDoc, signalDoc, SignalNames, Commander, Commander gbb September 19, 1988 10:07:15 am PDT Added Versatec C2700 changes to: Print gbb October 13, 1988 2:50:17 pm PDT When ratioH < ratioW the image is centered. changes to: DrawToIP (local of DoInterpress) Ê@˜codešœ™KšœH™HKšœ5™5K™$—K™™ßIquote™/—code2šÏk ˜ Kšœœ˜(Kšœœ ˜Kšœ œœ-˜AKšœœ³˜»Kšœ œC˜QKšœ œ˜/Kšœ œ˜Kšœœ˜#Kšœ œ˜!Kšœœ˜Kšœœ ˜Kšœ œ˜(Kšœ œ°˜ÀKšœ œ˜Kšœœ=˜EKšœœñœ˜‚Kšœ œ5œ˜KKšœœ˜,Kšœœ˜(Kšœ œn˜~KšœœA˜WKšœ œ(˜8Kšœ œ9˜KKšœœB˜\Kšœœ˜#Kšœ œŠ™šKšœœ4˜˜OKšœ œ.˜<—MšÐln œœ˜MšœœNœ‰œ©˜¥Mšœ˜%šœ$˜(IunitšÏbœŽ™­Kšœ·Ïeœ œ™ãNšœœœÏc˜'Kšœœœœ˜%Kšœœœœ˜,Kšœ œœœ˜!Nšœ9œœ˜FKšœ.œœ˜:Kšœœ˜Kšœ œ˜Kšœœ¡ËÐce¡Ðcg¡G˜§Nšœœ˜Kšœ œœ ˜!Kšœ œœ˜6Kšœœ'˜;Kš œ œœœœ%˜RKšœ œœ˜'Kš œœœœœœ ˜AKšœœœ˜Kšœœ˜Nšœœœ ˜KšAœ œœœœœFœ¡ œœ#œ œ>œœœœ¡œ œ¡œœœœ¡-œœ œ&œœœœœœœ¡œœ˜ôNšœ œœ˜Kšœœœ˜Nšœœœ˜#Nšœ œœœ˜ Kšœ œœœ˜Kšœœ˜Kšœœ˜Kšœœ ¡!˜=Kšœœ ¡"˜@Kšœœ#œ˜MKšœœ˜0—head™Mš œœœœœ˜-Kšœœ˜$Kšœœ˜Kšœœœ˜!Kšœœœ'˜;Kšœœœ˜Kš œ œœœœ˜šÏnœœœ˜=Kšœœ5˜<—š¤œœ˜,Kšœ  œ!™:Kšœ!˜!Kšœ¡˜—š¤œœ+œ˜KK™KšœE˜Ešœœ˜Kšœ8¡˜@Kšœ8¡˜?Kšœ8¡˜@Kšœ7¡˜>Kš˜—šœ˜ Kšœœ!˜9KšœZ˜ZKš˜—Kšœ˜—šœ œ˜Kšœœ)˜.KšœF˜FKšœœ˜&Kš˜—Kšœ¡ ˜—š¤ œ˜)Kšœœ œ™ Kšœ œ¢ œ™©Kšœœ˜Kšœ œ˜Kšœœ ¡#˜HKšœ&˜&Kšœœ˜ Nšœ˜šœœ˜Kšœ<˜Kš˜—šœ˜ Kšœœ!˜9Kšœ$˜$Kšœ[˜[Kšœ!˜!Kš˜—Kšœ˜—šœ œ˜Kšœœ)˜.Kšœ<˜Kš˜—šœ˜ Kšœœ!˜9KšœZ˜ZKš˜—Kšœ˜—šœ œ˜Kšœœ)˜.Kšœ<˜˜>Kšœœœ˜#Kšœœ"˜šœ œ˜Kšœ œœœ5˜Zšœ˜Kšœ œ ˜Kšœ3˜3Kš˜——Kšœ¡ ˜—NšœJ˜JKšœœœ˜"Kš˜—Kšœ¡˜—š¤ œœ™&Kšœ ™ Kšœœ™0KšœœU™]Kš œœœœœ+™Všœœ™(KšœI™IKšœ™š¤ œ™'Kšœœ$œœ™>šœ œ™Kšœ œœœ5™Zšœ™Kšœ œ ™Kšœ3™3Kš™——Kšœ¡ ™—NšœJ™JKš™—Kšœ¡ ™——™ Mšœ@˜@Kšœ;˜;š ¤ œœœ#œ˜`Kšœå™åKšœ]˜]Kšœ]™]Kšœy˜yKšœ˜Kšœ$œœ¡˜@šœœ˜K™uKšœ-¡Ðcd¡¦œ¦˜6Kš œC¡¦¡¦¡¦¡¦¡¦˜SKšœ1¡¦¡¦¡™8Kšœ:¡¦¡¦¡¦¡™CKšœ5¡¦¡¦¡œ˜?Kšœ3¡˜S—Kšœ¡˜—š¤œœ ˜Kš œœœœ'œ œ™`Kšœœ˜)Kšœ(˜(Kšœœ˜2Kšœœ˜$Kšœ"˜"Nšœœ%œœ˜JKšœœœœ˜#Kšœ-˜-Kšœ&¡"˜HKšœ*˜*šœ"œ˜/KšœK˜Kšœ˜šœ+˜0K™ãK™ÍKšœÀ˜ÀK™Kšœª™ªKšœ¡(˜6šœœ˜?K™)KšœS˜S—Kš˜—Kšœ¡(˜D—Kš˜—Kšœ¡/˜BKšœ1˜1Kšœ1˜1Kšœ9˜9Kšœ¡˜—š¤œœ ˜Kš œœœœ'œ œ™`Kšœœ˜)Kšœ(˜(Kšœ œ˜5Kšœ:˜:KšœA˜ANšœœ%œœ˜JKšœœœœ˜#Nšœ¡˜4Kšœ-˜-Kšœ+˜+KšœF˜FKšœ¡ ˜—š¤œœ ˜Kš œœœœ'œ œ™`Kšœœ˜)Kšœ(˜(Kšœ œ˜5Kšœ:˜:KšœA˜ANšœœ%œœ˜JKšœœœœ˜#Nšœ¡˜4Kšœ-˜-Kšœ+˜+Kšœ(œ˜JKšœ¡ ˜—š¤œœ˜)Kšœ ™ K™Kšœœ˜0Kšœœ*˜3Kšœ œ ˜Kšœ*˜*Kšœ˜Nšœœœœ˜#KšœA˜AKšœ4™4KšœF˜FKšœ9¡˜AKšœ9¡˜@Kšœ/¡˜7Kšœ/¡˜6K™ K™/Kšœ7˜7Kšœ¡˜—š¤œœ˜/Kšœ ™ K™Kšœœ˜0Kšœœ.˜7Kšœ œ ˜Kšœ*˜*Kšœ˜Kšœœ˜š ¤ œœœœœ˜3Kšœ œœœ3˜`Kšœ ˜Kšœ¡˜—Nšœœœœ˜#KšœA˜AKšœ4™4KšœF˜FKšœ9¡˜AKšœ9¡˜@Kšœ/¡˜7Kšœ/¡˜6K™ K™/Kšœ­˜­Kšœ¡˜—š¤œœ™)Kšœ ™ K™Kšœœ™0Kšœœ.™7Kšœ!™!Kš œœœœœ™=Kšœ!™!Kšœ™Kšœ™Kšœ5™5Kšœ=™=Kšœ:™:Kšœ%™%Kšœ™Kšœ9™9Kšœ%™%Kšœ™KšœJ™JKšœ%™%Kšœ™KšœJ™JKšœ$™$Kšœ¡™—š¤ œœ ˜Kš œœœœ'œ œ™`Kšœ˜šœ˜KšœL˜LKšœ@˜@KšœI˜IK™BKšœ7˜>—Kšœ¡ ˜—š¤œœ ˜.Kš œœœœ'œ œ™`Kšœ˜šœœœ˜'Kšœœœ=˜Pšœœœ˜Kšœœ˜)Kšœ:˜:KšœA˜AKšœœ ˜Kšœœœœ˜#Kšœ"œ˜4Kšœ$¡"˜Fšœœœ˜AKšœ œ4˜CKšœB˜BKšœA˜AKšœ˜—Kšœ=˜=Kšœ@˜@Kš˜—Kšœ˜—šœ˜KšœL˜LKšœ@˜@KšœI˜IK™BKšœ7˜>—Kšœ¡˜!——™ Mšœ˜KšœH˜HKšœG˜Gš!¤ œœœ œœ-œœ œ œœœœ œœœœ!˜¬Kšœd œR œœ»™˜Kšœ  œº™ÇKšœ œI™SKšœ  œ$ œ'™^Kšœ` œ™ƒK™£Kšœ  œÃ œ™äKšœ ˜ š¤ œœœ˜šœ©œÛ™†Kšœœœœ#™H—Kšœ ˜ šœ œ˜Kšœœœ˜(Kšœœœ˜>KšœS˜SKšœM˜MKšœ˜—Kšœœ-™FKšœ1˜1Kšœœœ˜Kšœ œ7˜DKšœTœ ˜cKšœ[œ ˜iKš˜—Kšœ˜—Kšœ ˜Kšœ˜—Kšœœœ(œ˜GKšœœ'˜>Kšœ¡˜—šœ˜ Kšœœ œ˜(Kšœ;˜;Kšœœœ œ˜9Kšœ#˜#Kšœ$˜$Kšœ˜—NšœœœÐbkœ˜2Kšœœ©œ¡˜˜>KšœQ˜Qšœœ˜KšœL˜LKšœœ;˜VKšœ:˜>Kš˜—KšœK˜OKšœœœ1˜RN™šœœ˜'Kš œ'œ@œœ œ˜‰—Kšœœ˜ K™”šœ.œ#˜WKšœ¾™¾—K™5Kšœ˜šœœœ˜;Kšœ"˜"—Kšœœœ/˜MKšœ¡¥˜$šœœ˜KšœD˜DKšœ˜Kš˜—Kšœ˜—N™:Kšœ4˜;K•StartOfExpansionI[self: ImagerInterpress.Ref, action: PROC [...], scale: REAL _ 1.0]šœ2œ œœ˜fN™šœœ˜Kšœ+œ˜/KšœC˜CKšœ˜Kšœ œœ'˜DKšœR˜RKš˜—Kšœ¡ ˜—Ošœ¡ ™šœ œ˜šœœœ˜#Kšœu˜uKšœ3˜6Kšœ˜—Kšœœ#˜>Kšœ œœ!˜NKšœ&˜&Kšœ œ-˜?Kšœœ œœ œœœœ˜HKšœ"˜"Kš˜—šœ˜ Kšœ1˜1Kšœœ#˜=Kšœœ*˜BKšœ˜—Nšœ;˜;KšœÐbxœ˜2Kšœ˜Nšœ ˜ Kšœ¡˜—š ¤ œœ œ œ ˜>Kšœ?™?š œœ2œœ˜OJšœœE˜_Jš˜—Kšœ¡ ˜—š ¤œœ œ œ ˜AKšœ7™7š¤œ ˜-Kš œœœ œœœ™;Kšœ'œ˜+Kšœ¡ ˜—Kšœœ˜-Kšœ¡˜—š¤ œœ!œ˜?K™]Kšœ(˜(šœ!œ˜-Kšœ8˜8Kš˜—Kšœ¡˜—š¤ œœ!œ™?K™]Kšœ(™(Kšœœ™,Kšœœ(™:š œ œ œ œœœ™WKšœ8™8Kš™—Kšœ¡™—š ¤œœœœ˜>MšœQ™QKšœ(˜(šœ œ!œ˜8Kšœ9˜9Kš˜—Kšœ¡˜—š¤ œœ œ˜Kšœœ œ˜(Kš¤œ<œœ˜QNšœœ˜Kšœ9˜9Kšœ>˜>Kšœ#˜#Kšœœ"˜<šœ&˜*K™ÈKšœ0˜3—Kšœ¡ ˜—š¤œœ œ˜3K™'Kšœ@œ˜EKšœ(œ˜0Kšœ œ˜Kšœ#˜#Kšœ!˜!Kšœœ˜ Nšœ˜Kšœ%˜%KšœRœ˜YKšœœ/˜IKšœ=˜=Kšœ*˜*šœœ˜šœœ œ˜:šœœ˜#Kšœ{˜{Kšœ˜Kšœ˜—K˜Kšœ˜—šœœ œ˜:K™/Kšœ-˜-KšœD˜DKšœ(˜(K™2Kšœœœ˜.šœœœ˜Kšœœœ˜;Kšœ˜—K™šœ œ˜-Kšœœ7˜?Kšœœ7˜>šœœ˜Kšœœ˜Kšœœœ˜Kšœœ˜Kšœ˜—Kšœ˜—Kšœ'˜'KšœŒ˜ŒKšœ,˜,Kšœ˜—šœ˜šœ˜Kšœ]˜]—Kšœ\˜`K˜Kš˜——Kšœ¡˜—š ¤ œœœœ˜@Kšœœ$˜,Kšœœ$˜,Kšœ?˜EKšœ¡ ˜—š ¤ œœœ œ œ˜=Kšœ˜!Kšœ¡ ˜—š ¤ œœœœ ˜>Kšœœœ™-Kšœ+œœœ™\KšœM™SKšœe˜kKšœ¡˜—š ¤ œœœœœ ˜Fš ¤œœœœœœ˜2Kšœ8˜>Kšœ¡ ˜—š ¤œœœœœœ˜2Kšœ8˜>Kšœ¡ ˜—Kšœ?˜EKšœ¡˜—š ¤œœ œœœ ™9Kšœ'™-Kšœ¡™ —š ¤ œœ œœœ˜LKšœ   œ™3šœ ˜KšœS˜SKšœ˜—Kšœ˜ Kšœ¡˜—š ¤ œœœœœ˜.KšœN˜TKšœ¡ ˜—š ¤ œœœœœ˜-Kšœ:œ˜GKšœ¡ ˜—š ¤œœœœœ˜4Kšœ@œ˜LKšœ¡˜—š¤œœœ˜*Kšœ^œ™{Kšœ4˜4KšœJ˜JKšœ¡˜—Mš¤œœ˜*Mš¤œœ˜"Mš¤ œœ˜$š¤œœ˜Kšœ ™ Kšœœ˜0Kšœœœ©œ˜Cšœœ˜%Kšœœœœ˜#Kšœ&˜&Kšœ,˜,Kš˜—Kšœ¡ ˜—š¤œœ˜!Kšœ ™ Kšœœ˜0Kšœœœ©œ˜Cš œœœœ˜AKšœœœœ˜#KšœS˜SKš˜—Kšœ¡ ˜——™š!¤œœœœœ œœœœœ œœ œœœ œ˜àMš œœU œ Pœ œ™ƒMšœR  œ  œ œ7™ÃMšœ  œ œ'™?Kšœ œ˜Kšœœ˜šœœ˜ Kšœ-œ ˜>Kšœ˜—šœœ˜ Kšœ>©Ÿœœ˜JKšœ˜—Kš œœœ œœœ˜9šœ œœœ˜8KšœC™C—Kšœœ˜#šœ ˜šœO˜TKšœE˜Ešœ˜ KšœœHœ˜xKšœ˜—Kšœ5˜5Kšœ˜—šœ˜Kšœ œ˜Kšœ œ¡˜&Kšœ.˜.Nšœ œ*œ ˜HKšœœ˜"Kšœ–¡ ˜ šœ ˜KšœM˜MKšœH˜HKšœœ˜!—Kšœ˜K–n[name: ROPE, wantedCreatedTime: GMT _ OPAQUE#17777777777B, remoteCheck: BOOL _ TRUE, wDir: ROPE _ NIL]šœœ(œ ˜SKšœ˜Kšœ*˜*Kšœ6˜6Kšœ œœœ˜8Kšœ*˜*Kšœ*œœ˜]Kšœ˜Kšœ˜—šœ˜KšŸœN™SKšœœ%™/Kšœœ™(Kšœœ9™NšœD™DKšœœœ˜™¨—Nšœœ™&Kšœ@˜@šœ˜ Kšœœl˜€Kšœ˜—Kšœ6˜6Kšœ œœœ˜8Kšœ@œœà™ÁKšœœœW™gšœ™KšœM™MKšœv™vKšœ~™~Kšœ™œ™ªKšœ“œ™¤Kšœ@™@Kšœgœ™xKšœ™—Kšœ˜—Kšœœ˜!—š˜šœ˜KšœV˜VKš˜——Kšœ˜Kšœ¡˜ ——™ Mšœœ˜,Kšœœ˜*Kšœœ˜-š¤œ#˜;Mšœ œ˜Mšœ œ˜Mšœœ˜*Mšœ?˜?šœ$œ˜0Kšœ!˜!šœœœ˜3KšœB˜Bšœ œ˜KšœB˜BKšœ/˜/Kš˜—Kšœ˜"Kš˜—Kšœ˜—šœ"œ˜.Kšœ˜šœœœ˜3Kšœ8˜8šœœ œ˜KšœB˜BKšœ/˜/Kš˜—Kšœ˜"Kš˜—Kšœ˜—šœ$œ˜0Kšœ!˜!šœœœ˜3Kšœ<˜