ImagerDefaultImpl.mesa
Michael Plass, April 12, 1984 3:08:20 pm PST
Doug Wyatt, July 23, 1984 12:39:51 pm PDT
 
DIRECTORY
Imager,
ImagerBasic,
ImagerDefault,
ImagerOps USING [DRound],
ImagerTransform,
Real;
 
ImagerDefaultImpl: CEDAR PROGRAM
IMPORTS Imager, ImagerOps, ImagerTransform, Real
EXPORTS ImagerDefault
~ BEGIN OPEN Imager;
InitialStateRep: ImagerBasic.StateRep ~ [
cpx: 0.0,
cpy: 0.0,
correctMX: 0.0,
correctMY: 0.0,
correctMaskCount: 0,
correctMaskX: 0.0,
correctMaskY: 0.0,
correctSumX: 0.0,
correctSumY: 0.0,
correctSpaceX: 0.0,
correctSpaceY: 0.0,
correctcpx: 0.0,
correctcpy: 0.0,
correctTargetX: 0.0,
correctTargetY: 0.0,
T: ImagerTransform.Create[1,0,0,0,1,0],
priorityImportant: 0,
mediumXSize: 0,
mediumYSize: 0,
fieldXMin: 0,
fieldYMin: 0,
fieldXMax: 0,
fieldYMax: 0,
showVec: NIL,
color: NIL,
noImage: 0,
strokeWidth: 0.0,
strokeEnd: 0,
underlineStart: 0.0,
amplifySpace: 1.0,
correctPass: 0,
correctShrink: 0.5,
correctTX: 0.0,
correctTY: 0.0,
clipper: NIL,
propertyList: NIL
];
 
InitState: PUBLIC PROC [context: Context] ~ {
state: State ← NEW[ImagerBasic.StateRep ← InitialStateRep];
state.color ← Imager.black;
context.state ← state;
};
 
DoSave: 
PUBLIC 
PROC[context: Context, body: 
PROC] ~ {
state: State ~ context.state;
saved: StateRep ~ state^;
Restore: 
PROC ~ {
state.T ← saved.T;
state.priorityImportant ← saved.priorityImportant;
state.mediumXSize ← saved.mediumXSize;
state.mediumYSize ← saved.mediumYSize;
state.fieldXMin ← saved.fieldXMin;
state.fieldYMin ← saved.fieldYMin;
state.fieldXMax ← saved.fieldXMax;
state.fieldYMax ← saved.fieldYMax;
state.showVec ← saved.showVec;
state.color ← saved.color;
state.noImage ← saved.noImage;
state.strokeWidth ← saved.strokeWidth;
state.strokeEnd ← saved.strokeEnd;
state.underlineStart ← saved.underlineStart;
state.amplifySpace ← saved.amplifySpace;
state.correctPass ← saved.correctPass;
state.correctShrink ← saved.correctShrink;
state.correctTX ← saved.correctTX;
state.correctTY ← saved.correctTY;
state.clipper ← saved.clipper;
};
 
body[! UNWIND => Restore[]];
Restore[];
};
 
DoSaveAll: 
PUBLIC 
PROC[context: Context, body: 
PROC] ~ {
state: State ~ context.state;
saved: StateRep ~ state^;
Restore: PROC ~ { state^ ← saved };
body[! UNWIND => Restore[]];
Restore[];
};
 
SetPriorityImportant: 
PUBLIC 
PROC[context: Context, priorityImportant: 
BOOL] ~ {
context.state.priorityImportant ← IF priorityImportant THEN 1 ELSE 0;
};
 
SetFont: 
PUBLIC 
PROC[context: Context, font: 
FONT] ~ {
context.state.showVec ← font;
};
 
SetColor: 
PUBLIC 
PROC[context: Context, color: Color] ~ {
context.state.color ← color;
};
 
SetNoImage: 
PUBLIC 
PROC[context: Context, noImage: 
BOOL] ~ {
context.state.noImage ← IF noImage THEN 1 ELSE 0;
};
 
SetStrokeWidth: 
PUBLIC 
PROC[context: Context, strokeWidth: 
REAL] ~ {
context.state.strokeWidth ← strokeWidth;
};
 
SetStrokeEnd: 
PUBLIC 
PROC[context: Context, strokeEnd: StrokeEnd] ~ {
context.state.strokeEnd ← (
SELECT strokeEnd 
FROM
square => 0, butt => 1, round => 2, ENDCASE => ERROR);
};
 
SetAmplifySpace: 
PUBLIC 
PROC[context: Context, amplifySpace: 
REAL] ~ {
context.state.amplifySpace ← amplifySpace;
};
 
SetCorrectShrink: 
PUBLIC 
PROC[context: Context, correctShrink: 
REAL] ~ {
context.state.correctShrink ← correctShrink;
};
 
SetSampledColor: 
PUBLIC 
PROC[context: Context,
pa: PixelArray, pixelT: Transformation, colorOperator: ATOM] ~ {
state: State ~ context.state;
color: SampledColor ~ 
NEW[ColorRep.sampled ← [sampled[
transparent: FALSE,
pa: pa,
m: pixelT.Concat[state.T],
colorOperator: colorOperator
]]];
state.color ← color;
};
 
SetSampledBlack: 
PUBLIC 
PROC[context: Context,
pa: PixelArray, pixelT: Transformation, transparent: BOOL] ~ {
state: State ~ context.state;
color: SampledColor ~ 
NEW[ColorRep.sampled ← [sampled[
transparent: transparent,
pa: pa,
m: pixelT.Concat[state.T],
colorOperator: $SampledBlack
]]];
state.color ← color;
};
 
ConcatT: 
PUBLIC PROC[context: Context, m: Transformation] ~ {
state: State ~ context.state;
state.T ← ImagerTransform.Concat[m, state.T];
};
 
ScaleT: 
PUBLIC PROC[context: Context, s: 
REAL] ~ {
state: State ~ context.state;
state.T ← ImagerTransform.PreScale[s, state.T];
};
 
Scale2T: 
PUBLIC PROC[context: Context, sx, sy: 
REAL] ~ {
state: State ~ context.state;
state.T ← ImagerTransform.PreScale2[sx, sy, state.T];
};
 
RotateT: 
PUBLIC PROC[context: Context, a: 
REAL] ~ {
state: State ~ context.state;
state.T ← ImagerTransform.PreRotate[a, state.T];
};
 
TranslateT: 
PUBLIC PROC[context: Context, x, y: 
REAL] ~ {
state: State ~ context.state;
state.T ← ImagerTransform.PreTranslate[x, y, state.T];
};
 
Move: 
PUBLIC PROC[context: Context] ~ {
state: State ~ context.state;
new: Pair ~ [state.cpx, state.cpy];
t: Transformation ~ state.T;
state.T ← ImagerTransform.Create[t.a, t.b, new.x, t.d, t.e, new.y];
};
 
Trans: 
PUBLIC PROC[context: Context] ~ {
state: State ~ context.state;
new: Pair ~ ImagerOps.DRound[[state.cpx, state.cpy]];
t: Transformation ~ state.T;
state.T ← ImagerTransform.Create[t.a, t.b, new.x, t.d, t.e, new.y];
};
 
SetXY: 
PUBLIC 
PROC[context: Context, x, y: 
REAL] ~ {
state: State ~ context.state;
[[state.cpx, state.cpy]] ← ImagerTransform.Transform[[x, y], state.T];
};
 
SetXYI: 
PUBLIC 
PROC[context: Context, x, y: 
INTEGER] ~ {
context.SetXY[x, y];
};
 
SetXYRel: 
PUBLIC PROC[context: Context, x, y: 
REAL] ~ {
state: State ~ context.state;
delta: Pair ~ ImagerTransform.TransformVec[[x, y], state.T];
state.cpx ← state.cpx + delta.x;
state.cpy ← state.cpy + delta.y;
};
 
SetXYRelI: 
PUBLIC PROC[context: Context, x, y: 
INTEGER] ~ {
context.SetXYRel[x, y];
};
 
GetCP: PUBLIC PROC [context: Context] RETURNS [cp: Pair] ~ {
WITH context.state SELECT FROM
state: State => {
cp ← ImagerTransform.InverseTransform[[state.cpx, state.cpy], state.T];
};
 
ENDCASE => ERROR Imager.Error[$Bug];
 
};
 
GetCPRounded: PUBLIC PROC [context: Context] RETURNS [cp: Pair] ~ {
WITH context.state SELECT FROM
state: State => {
cp ← ImagerTransform.InverseTransform[[Real.RoundLI[state.cpx], Real.RoundLI[state.cpy]], state.T];
};
 
ENDCASE => ERROR Imager.Error[$Bug];
 
};
 
MaskVector: 
PUBLIC 
PROC[context: Context, x1, y1, x2, y2: 
REAL] ~ {
vector: PathProc ~ { move[[x1, y1]]; line[[x2, y2]] };
context.MaskStrokePath[vector];
};
 
MaskVectorI: 
PUBLIC 
PROC[context: Context, x1, y1, x2, y2: 
INTEGER] ~ {
context.MaskVector[x1, y1, x2, y2];
};
 
StartUnderline: 
PUBLIC 
PROC[context: Context] ~ {
state: State ~ context.state;
cp: Pair ~ ImagerTransform.InverseTransform[[state.cpx, state.cpy], state.T];
state.underlineStart ← cp.x;
};
 
MaskUnderline: 
PUBLIC PROC[context: Context, dy, h: 
REAL] ~ {
body: 
PROC ~ {
state: State ~ context.state;
cp: Pair ~ ImagerTransform.InverseTransform[[state.cpx, state.cpy], state.T];
context.SetXY[state.underlineStart, cp.y-dy-h];
context.Trans[];
context.MaskRectangle[0, 0, cp.x-state.underlineStart, h];
};
context.DoSaveAll[body];
};
 
MaskUnderlineI: 
PUBLIC PROC[context: Context, dy, h: 
INTEGER] ~ {
context.MaskUnderline[dy, h];
};
 
ClipOutline: PUBLIC PROC[context: Context, pathProc: PathProc, pathData: REF] ~ {
WITH context.state SELECT FROM
state: State => {
trans: ImagerTransform.TransformationRec ~ state.T.Contents;
XForm: PROC [p: Pair] RETURNS [Pair] ~ {
RETURN [[trans.a*p.x+trans.b*p.y+trans.c, trans.d*p.x+trans.e*p.y+trans.f]]
};
 
tList: LIST OF Trajectory ← NIL;
Move: PROC [p: Pair] ~ {tList ← CONS[Imager.MoveTo[XForm[p]], tList]};
Line: PROC [p: Pair] ~ {tList.first ← tList.first.LineTo[XForm[p]]};
Curve: PROC [p1, p2, p3: Pair] ~ {
tList.first ← tList.first.CurveTo[XForm[p1], XForm[p2], XForm[p3]]
};
 
Conic: PROC [p1, p2: Pair, r: REAL] ~ {
tList.first ← tList.first.ConicTo[XForm[p1], XForm[p2], r]
};
 
pathMap[pathData, Move, Line, Curve, Conic];
state.clipper ← CONS[[exclude: FALSE, easyRectangle: FALSE, pathMap: MapTrajectoryList, pathData: tList], state.clipper];
};
 
ENDCASE => ERROR Imager.Error[$InvalidState];
 
};
 
MapTrajectory: PathMapType = {
t: Trajectory = NARROW[data];
move[t.lp];
FOR x: Trajectory ← t, x.prev UNTIL x.prev=NIL DO
p0: Pair = x.prev.lp;
WITH x SELECT FROM
x: REF TrajectoryRep[line] => line[p0];
x: REF TrajectoryRep[curve] => curve[x.p2, x.p1, p0];
x: REF TrajectoryRep[conic] => conic[x.p1, p0, x.r];
x: REF TrajectoryRep[move] => ERROR;
ENDCASE => ERROR;
 
ENDLOOP;
 
};
 
MapTrajectoryList: PathMapType = {
FOR x: LIST OF Trajectory ← NARROW[data], x.rest UNTIL x = NIL DO
MapTrajectory[x.first, move, line, curve, conic]
ENDLOOP;
 
};
 
ExcludeOutline: PUBLIC PROC[context: Context, pathMap: PathMapType, pathData: REF] ~ {
WITH context.state SELECT FROM
state: State => {
ClipOutline[context, pathMap, pathData];
state.clipper.first.exclude ← TRUE;
};
 
ENDCASE => ERROR Imager.Error[$InvalidState];
 
};
 
ClipRectangle: 
PUBLIC PROC[context: Context, x, y, w, h: 
REAL] ~ {
state: State ~ context.state;
rectangle: PathProc ~ {
move[[x, y]]; line[[x+w, y]]; line[[x+w, y+h]]; line[[x, y+h]];
};
ClipOutlinePath[context, rectangle];
WITH state.clipper 
SELECT 
FROM
clipper: ImagerBasic.ClientClipper => {
t: Transformation ~ state.T;
clipper.first.easyRectangle ← (t.a = 0 AND t.e = 0) OR (t.b = 0 AND t.d = 0);
};
ENDCASE => ERROR Imager.Error[$Bug];
 
};
 
ClipRectangleI: 
PUBLIC PROC[context: Context, x, y, w, h: 
INTEGER] ~ {
context.ClipRectangle[x, y, w, h];
};
 
ExcludeRectangle: 
PUBLIC PROC[context: Context, x, y, w, h: 
REAL] ~ {
ClipRectangle[context, x, y, w, h];
WITH context.state.clipper 
SELECT 
FROM
clipper: ImagerBasic.ClientClipper => clipper.first.exclude ← TRUE;
ENDCASE => ERROR Imager.Error[$Bug];
 
};
 
ExcludeRectangleI: 
PUBLIC PROC[context: Context, x, y, w, h: 
INTEGER] ~ {
context.ExcludeRectangle[x, y, w, h];
};
 
CorrectMask: 
PUBLIC PROC[context: Context] ~ {
state: State ~ context.state;
SELECT state.correctPass 
FROM
1 => state.correctMaskCount ← state.correctMaskCount + 1;
2 => 
IF state.correctMaskCount > 0 
THEN {
spx: REAL ~ state.correctMaskX/state.correctMaskCount;
spy: REAL ~ state.correctMaskY/state.correctMaskCount;
state.correctMaskX ← state.correctMaskX - spx;
state.correctMaskY ← state.correctMaskY - spy;
state.correctMaskCount ← state.correctMaskCount - 1;
state.cpx ← state.cpx + spx;
state.cpy ← state.cpy + spy;
};
ENDCASE => NULL;
 
};
 
CorrectSpace: 
PUBLIC 
PROC[context: Context, x, y: 
REAL] ~ {
state: State ~ context.state;
CorrectSpaceView[context, ImagerTransform.TransformVec[[x, y], state.T]];
};
 
CorrectSpaceView: 
PUBLIC PROC[context: Context, v: Pair] ~ {
state: State ~ context.state;
SELECT state.correctPass 
FROM
1 => {
state.correctSumX ← state.correctSumX + v.x;
state.correctSumY ← state.correctSumY + v.y;
};
2 => {
Div: 
PROC [num, denom: 
REAL] 
RETURNS [
REAL] ~ {
IF denom = 0.0 
THEN {
IF num = 0.0 THEN RETURN [0.0]
ELSE ERROR Imager.Error[$ZeroDivideInCorrectSpace]
}
 
ELSE RETURN [num/denom]
};
 
spx: REAL ~ Div[v.x*state.correctSpaceX, state.correctSumX];
spy: REAL ~ Div[v.y*state.correctSpaceY, state.correctSumY];
state.correctSumX ← state.correctSumX - v.x;
state.correctSumY ← state.correctSumY - v.y;
state.correctSpaceX ← state.correctSpaceX - spx;
state.correctSpaceY ← state.correctSpaceY - spy;
state.cpx ← state.cpx + spx;
state.cpy ← state.cpy + spy;
};
ENDCASE => NULL;
 
};
 
SetCorrectMeasure: 
PUBLIC 
PROC[context: Context, x, y: 
REAL] ~ {
state: State ~ context.state;
[[state.correctMX, state.correctMY]] ← ImagerTransform.TransformVec[[x, y], state.T];
};
 
SetCorrectTolerance: 
PUBLIC 
PROC[context: Context, x, y: 
REAL] ~ {
state: State ~ context.state;
[[state.correctTX, state.correctTY]] ← ImagerTransform.TransformVec[[x, y], state.T];
};
 
Space: 
PUBLIC PROC[context: Context, x: 
REAL] ~ {
Equivalent to {SetXYRel[context, [x, 0]]; CorrectSpace[context, [x, 0]]}
state: State ~ context.state;
v: Pair ~ ImagerTransform.TransformVec[[x, 0], state.T];
state.cpx ← state.cpx + v.x;
state.cpy ← state.cpy + v.y;
SELECT state.correctPass 
FROM
1 => {
state.correctSumX ← state.correctSumX + v.x;
state.correctSumY ← state.correctSumY + v.y;
};
2 => 
IF state.correctMaskCount > 0 
THEN {
Div: 
PROC [num, denom: 
REAL] 
RETURNS [
REAL] ~ {
IF denom = 0.0 
THEN {
IF num = 0.0 THEN RETURN [0.0]
ELSE ERROR Imager.Error[$ZeroDivideInCorrectSpace]
}
 
ELSE RETURN [num/denom]
};
 
spx: REAL ~ Div[v.x*state.correctSpaceX, state.correctSumX];
spy: REAL ~ Div[v.y*state.correctSpaceY, state.correctSumY];
state.correctSumX ← state.correctSumX - v.x;
state.correctSumY ← state.correctSumY - v.y;
state.correctSpaceX ← state.correctSpaceX - spx;
state.correctSpaceY ← state.correctSpaceY - spy;
state.cpx ← state.cpx + spx;
state.cpy ← state.cpy + spy;
};
ENDCASE => NULL;
 
};
 
SpaceI: 
PUBLIC 
PROC [context: Context, x: 
INTEGER] ~ {
context.Space[x];
};
 
Correct: 
PUBLIC 
PROC[context: Context, body: 
PROC] ~ {
state: State ~ context.state;
Length: 
PROC [x, y: 
REAL] 
RETURNS [
REAL] ~ {
The interpress document asks that this be the length in meters, but since it is only used for comparisons, view coordinates should work as well.  If the view coordinates had non-uniform scaling, this would have to be accounted for here.
RETURN [Real.SqRt[x*x + y*y]];
};
 
state.correctcpx ← state.cpx;
state.correctcpy ← state.cpy;
state.noImage ← 1;
state.correctMaskCount ← 0;
state.correctSumX ← state.correctSpaceY ← 0;
state.correctPass ← 1;
Imager.DoSave[context, body];
state.correctTargetX ← state.correctcpx + state.correctMX;
state.correctTargetY ← state.correctcpy + state.correctMY;
state.correctMaskX ← state.correctMaskY ← 0;
state.correctMaskCount ← state.correctMaskCount - 1;
state.correctSpaceX ← state.correctTargetX - state.cpx;
state.correctSpaceY ← state.correctTargetY - state.cpy;
CHECKED {
IF (
Length[state.correctSpaceX, state.correctSpaceY] > state.correctShrink*Length[state.correctSumX, state.correctSumY]
AND
Length[state.correctcpx - state.correctTargetX, state.correctcpy - state.correctTargetY] <
Length[state.correctcpx - state.cpx, state.correctcpy - state.cpy]
 
)
 
THEN {
state.correctMaskX ← state.correctSpaceX + state.correctShrink*state.correctSumX;
state.correctMaskY ← state.correctSpaceY + state.correctShrink*state.correctSumY;
state.correctSpaceX ← state.correctSpaceX - state.correctMaskX;
state.correctSpaceY ← state.correctSpaceY - state.correctMaskY;
};
 
IF state.correctSumX = 0 
AND state.correctSpaceX # 0 
THEN {
state.correctMaskX ← state.correctSpaceX;
state.correctSpaceX ← 0;
};
 
IF state.correctSumY = 0 
AND state.correctSpaceY # 0 
THEN {
state.correctMaskY ← state.correctSpaceY;
state.correctSpaceY ← 0;
};
 
};
 
state.cpx ← state.correctcpx;
state.cpy ← state.correctcpy;
state.noImage ← 0;
state.correctPass ← 2;
Imager.DoSave[context, body];
state.correctPass ← 0;
IF Length[state.correctTargetX - state.cpx, state.correctTargetY - state.cpy] > Length[state.correctTX, state.correctTY] THEN ERROR Imager.Error[$UnableToProperlyAdjustMaskPositions];
state.cpx ← state.correctTargetX;
state.cpy ← state.correctTargetY;
};
 
Reset: PUBLIC PROC [context: Context] ~ {
WITH context.state SELECT FROM
state: State => {
propertyList: REF ← state.propertyList;
state^ ← InitialStateRep;
state.color ← Imager.black;
state.propertyList ← propertyList;
};
 
ENDCASE => ERROR Imager.Error[$Bug];
 
};
 
DrawBitmap: PUBLIC PROC [context: Context, base: LONG POINTER, raster: CARDINAL, area: IntRectangle] ~ {
ERROR Imager.Error[$NotYetImplemented];
};
 
MaskBits: PUBLIC PROC [context: Context, base: LONG POINTER, raster: CARDINAL, tile: IntRectangle, area: IntRectangle] ~ {
ERROR Imager.Error[$NotYetImplemented];
};
 
GetSurfaceBounds: PUBLIC PROC [context: Context] RETURNS [IntRectangle] ~ {
WITH context.state SELECT FROM
state: State => {
ERROR Imager.Error[$NotYetImplemented];
};
 
ENDCASE => ERROR Imager.Error[$Bug];
 
};
 
END.