ContoursTestImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Bloomenthal, September 17, 1986 4:25:55 pm PDT
Types
PixelMap: TYPE ~ ImagerPixelMap.PixelMap;
Spot: TYPE ~ RECORD [x, y: INTEGER];
SpotSequence: TYPE ~ REF SpotSequenceRec;
SpotSequenceRec:
TYPE ~
RECORD [
length: NAT ← 0,
elememnt: SEQUENCE maxLength: NAT OF Spot
];
Commands
ProgramData: TYPE ~ REF ProgramDataRec;
ProgramDataRec:
TYPE ~
RECORD [
outer: Viewer ← NIL, -- the outer (parent, top level) viewer
contour: Control ← NIL, -- the contour control
color: CARDINAL ← 200,
cd: Context ← NIL,
out: STREAM ← NIL
];
ContoursFill: Commander.CommandProc ~ {
p: ProgramData ← NEW[ProgramDataRec];
p.contour ← Controls.NewControl[type: contour, w: 160, proc: Negate, data: p];
p.outer ← Controls.OuterViewer[
name: "Contours Fill", controls: LIST[p.contour], buttons: LIST[["Clear", Clear]], data: p];
p.cd ← ColorTrixBasics.InitCd[gray];
p.out ← cmd.out;
};
Clear: Controls.ClickProc ~ {
p: ProgramData ← NARROW[NARROW[clientData, Controls.OuterData].data];
Controls.Reset[p.contour];
};
Commander.Register["///Commands/ContoursFill", ContoursFill, "Fill a contour\n"];
..
NegateSegment: PROC [pm: PixelMap, s0, s1: Spot] ~ {
x: REAL ← s0.x;
xMax: INTEGER ← pm.fMin+pm.fSize;
dx: REAL ← IF s0.y # s1.y THEN (s1.x-s0.x)/(s1.y-s0.y) ELSE 1.0;
color: CARDINAL ← IF dx < 0 THEN 100 ELSE p.color;
FOR y: INTEGER IN [s0.y..s1.y) DO
xx: INTEGER ← Real.RoundI[x];
dest: PixelMap ← ImagerPixelMap.SetWindow[p.pm, [y, xx, 1, xMax-xx]];
ImagerPixelMap.Transfer[dest, p.pm, [null, complement]];
x ← x+dx;
ENDLOOP;
};
Fill: Controls.ControlProc ~ {
Presumes contour is clockwise and its coordinates are [-1..1].
p: ProgramData ← NARROW[control.data];
contour: Contour ← Contours.FromControl[p.contour];
SpotsStart: PROC [spots: SpotSequence] RETURNS [INTEGER] ~ {
start, ymin: INTEGER ← 10000;
FOR n: NAT IN [0..spots.length) DO
IF spots[n].y < ymin THEN {ymin ← spots[n].y; start ← n};
ENDLOOP;
RETURN[start];
};
FloodSegment: PROC [pm: PixelMap, s0, s1: Spot] ~ {
x: REAL ← s0.x;
xMax: INTEGER ← pm.fMin+pm.fSize;
dx: REAL ← IF s0.y # s1.y THEN (s1.x-s0.x)/(s1.y-s0.y) ELSE 1.0;
color: CARDINAL ← IF dx < 0 THEN 100 ELSE p.color;
FOR y: INTEGER IN [s0.y..s1.y] DO
xx: INTEGER ← Real.RoundI[x];
ImagerPixelMap.Fill[pm, [y, xx, 1, xMax-xx], color];
x ← x+dx;
ENDLOOP;
};
IF contour.closed THEN {
spots: SpotSequence ← PmSpotsFromContour[contour, p.pm];
n, start: INTEGER ← SpotsStart[spots];
s0, s1: Spot ← spots[start];
ImagerPixelMap.Fill[p.pm, [p.pm.sMin, p.pm.fMin, p.pm.sSize, p.pm.fSize], 60];
DO
s0 ← s1;
s1 ← spots[n ← (n+1) MOD spots.length];
FloodSegment[p.pm, s0, s1];
IF n = start THEN EXIT;
ENDLOOP;
};
};
PmSpotsFromContour: PROC [contour: Contour, pm: PixelMap, invert: BOOL ← TRUE]
RETURNS [SpotSequence] ~ {
spots: SpotSequence ← NEW[SpotSequenceRec[contour.pairs.length]];
scale: REAL ← (MIN[pm.sSize, pm.fSize]-1)/2.0;
xOffset: REAL ← pm.fMin+scale-1.0;
yOffset: REAL ← pm.sMin+scale-1.0;
xMin: INTEGER ← 10000;
spots.length ← spots.maxLength;
FOR n: NAT IN [0..spots.length) DO
spots[n] ← [
Real.RoundI[xOffset+scale*contour.pairs[n].x],
Real.RoundI[yOffset+scale*contour.pairs[n].y]];
ENDLOOP;
IF invert THEN FOR n: NAT IN [0..spots.length) DO
spots[n].y ← pm.sMin+pm.sSize-spots[n].y;
ENDLOOP;
RETURN[spots];
};
Negate: Controls.ControlProc ~ {
Presumes contour is clockwise and its coordinates are [-1..1].
p: ProgramData ← NARROW[control.data];
yLast: INTEGER ← -1;
xMax: INTEGER ← p.pm.fMin+p.pm.fSize;
contour: Contour ← Contours.FromControl[p.contour];
NegateSegment: PROC [pm: PixelMap, s0, s1: Spot] ~ {
NegateToEnd: PROC [x, y: INTEGER] ~ {
IF y # yLast THEN {
dest: PixelMap ← ImagerPixelMap.SetWindow[pm, [y, x, 1, xMax-x]];
ImagerPixelMap.Transfer[dest, pm, [null, complement]];
yLast ← y;
};
};
IF s0.y = s1.y
THEN NegateToEnd[s0.x, s0.y]
ELSE {
Dot: Draw2d.PixelProc ~ {NegateToEnd[x, y]};
Draw2d.DoWithLine[s0.x, s0.y, s1.x, s1.y, Dot];
};
};
IF contour.closed THEN {
spots: SpotSequence ← PmSpotsFromContour[contour, p.pm];
s0, s1: Spot ← spots[spots.length-1];
ColorTrixBasics.FillPm[p.pm, 100];
FOR n: NAT IN [0..spots.length) DO
s0 ← s1;
s1 ← spots[n];
ColorTrixBasics.PutLine[p.pm, s0.x, s0.y, s1.x, s1.y, 200];
NegateSegment[p.pm, s0, s1];
ENDLOOP;
};
};
Negate: Controls.ControlProc ~ {
Presumes contour is clockwise and its coordinates are [-1..1].
p: ProgramData ← NARROW[control.data];
yLast: INTEGER ← -1;
xMax: INTEGER ← p.pm.fMin+p.pm.fSize;
contour: Contour ← Contours.FromControl[p.contour];
NegateSegment: PROC [pm: PixelMap, s0, s1: Spot] ~ {
NegateToEnd: PROC [x, y: INTEGER] ~ {
IF y # yLast THEN {
dest: PixelMap ← ImagerPixelMap.SetWindow[pm, [y, x, 1, xMax-x]];
ImagerPixelMap.Transfer[dest, pm, [null, complement]];
yLast ← y;
};
};
IF s0.y = s1.y
THEN NegateToEnd[s0.x, s0.y]
ELSE {
Dot: Draw2d.PixelProc ~ {NegateToEnd[x, y]};
Draw2d.DoWithLine[s0.x, s0.y, s1.x, s1.y, Dot];
};
};
IF contour.closed THEN {
spots: SpotSequence ← PmSpotsFromContour[contour, p.pm];
s0, s1: Spot ← spots[spots.length-1];
ColorTrixBasics.FillPm[p.pm, 100];
FOR n: NAT IN [0..spots.length) DO
s0 ← s1;
s1 ← spots[n];
ColorTrixBasics.PutLine[p.pm, s0.x, s0.y, s1.x, s1.y, 200];
NegateSegment[p.pm, s0, s1];
ENDLOOP;
};
};