~
BEGIN
Pair: TYPE ~ G2dBasic.Pair;
PairSequence: TYPE ~ G2dBasic.PairSequence;
Triple: TYPE ~ G2dBasic.Triple;
TripleSequence: TYPE ~ G2dBasic.TripleSequence;
Matrix:
TYPE ~ G2dMatrix.Matrix;
Data: TYPE ~ REF DataRep;
DataRep:
TYPE ~
RECORD [
s, sx, sy, r, tx, ty: Controls.Control ¬ NIL,
vmin, vmax: Pair ¬ [0.0, 0.0],
outerData: Controls.OuterData ¬ NIL,
outer, graphics: Controls.Viewer ¬ NIL,
buf: ImagerSample.SampleMap ¬ NIL,
nPts: NAT ¬ 5,
pts, nrms: PairSequence ¬ NIL,
lines: TripleSequence ¬ NIL
];
TransformCmd: Commander.CommandProc ~ {
d: Data ¬ NEW[DataRep];
d.tx ¬ Controls.NewControl[name: "TX", proc: T, clientData: d, min: -10., max: 10.0, init: 0];
d.ty ¬ Controls.NewControl[name: "TY", proc: T, clientData: d, min: -10., max: 10.0, init: 0];
d.sx ¬ Controls.NewControl[name: "SX", proc: T, clientData: d, min: -10., max: 10.0, init: 1];
d.s ¬ Controls.NewControl[name: "S", proc: S, clientData: d, min: -10., max: 10.0, init: 1];
d.sy ¬ Controls.NewControl[name: "SY", proc: T, clientData: d, min: -10., max: 10.0, init: 1];
d.r ¬ Controls.NewControl[name: "R", proc: T, clientData: d, max: 360.0, init: 0.0];
d.outerData ¬ Controls.OuterViewer[
name: "2d Transform",
buttons:
LIST[
Controls.ClickButton["IP Out", IPOut, d],
Controls.ClickButton["NPts", NPts, d],
Controls.ClickButton["Reset", Reset, d]],
controls: LIST[d.tx, d.ty, d.sx, d.s, d.sy, d.r],
typescriptHeight: 18,
graphicsHeight: 300,
drawProc: Draw,
clientData: d
];
d.outer ¬ d.outerData.parent;
d.graphics ¬ d.outerData.graphics;
Init[d];
};
Init:
PROC [d: Data] ~ {
IF d.pts =
NIL
OR d.pts.maxLength < d.nPts
THEN {
d.pts ¬ NEW[G2dBasic.PairSequenceRep[d.nPts]];
d.nrms ¬ NEW[G2dBasic.PairSequenceRep[d.nPts]];
d.lines ¬ NEW[G2dBasic.TripleSequenceRep[d.nPts]];
};
FOR i:
NAT
IN [0..d.nPts)
DO
a: REAL ¬ (2.0*3.141592)*REAL[i]/REAL[d.nPts];
c: Pair ¬ d.nrms[i] ¬ d.pts[i] ¬ [RealFns.Cos[a], RealFns.Sin[a]];
d.lines[i] ¬ [c.x, c.y, -c.x*c.x-c.y*c.y];
ENDLOOP;
};
T: Controls.ControlProc ~ {Repaint[
NARROW[control.clientData, Data], $Slider]};
S: Controls.ControlProc ~ {
d: Data ¬ NARROW[control.clientData];
Controls.SetSliderDialValue[d.sx, control.value];
Controls.SetSliderDialValue[d.sy, control.value];
Repaint[d, $Slider];
};
Rotate:
PROC [m: Matrix, degrees:
REAL]
RETURNS [Matrix] ~ {
cosDeg: REAL ¬ RealFns.CosDeg[degrees];
sinDeg: REAL ¬ RealFns.SinDeg[degrees];
RETURN[G2dMatrix.Mul[m, [[cosDeg, sinDeg, 0.0], [-sinDeg, cosDeg, 0.0], [0.0, 0.0, 1.0]]]];
};
Reset: Controls.ClickProc ~ {
d: Data ¬ NARROW[clientData];
Controls.Reset[d.sx, d.sy, d.s, d.r, d.tx, d.ty];
Repaint[d, $Init];
};
Repaint:
PROC [d: Data, r:
REF
ANY] ~ {ViewerOps.PaintViewer[d.graphics, client,
FALSE, r]};
Draw: Controls.DrawProc ~ {
Buffer:
PROC [op: {save, restore}] ~ {
Save: PROC [pm: Imager.PixelMap] ~ {d.buf ¬ ImagerSample.Copy[pm[0]]};
Restore: PROC [pm: Imager.PixelMap] ~ {ImagerSample.Transfer[pm[0], d.buf]};
r: Imager.Rectangle ¬ ImagerBackdoor.GetBounds[context];
ImagerBackdoor.AccessBufferRectangle[context, IF op = save THEN Save ELSE Restore, r];
};
InvViewPt: PROC [p: Pair] RETURNS [q: Pair] ~ {q ¬ [(p.x-200.0)/50.0, (p.y-200.0)/50.0]};
ViewPt: PROC [p: Pair] RETURNS [q: Pair] ~ {q ¬ [200.0+50.0*p.x, 150.0+50.0*p.y]};
Segment: PROC [p1, p2: Pair] ~ {Draw2d.Line[context, ViewPt[p1], ViewPt[p2], type]};
Arrow:PROC[p,v:Pair]~{Draw2d.Arrow[context,ViewPt[p],ViewPt[G2dVector.Add[p,v]],type]};
DrawLine:
PROC [l: Triple] ~ {
IF
ABS[l.y] < 0.0001
THEN
IF
ABS[l.x] < 0.0001
THEN RETURN
ELSE Segment[[-l.z/l.x, 2*d.vmin.y], [-l.z/l.x, d.vmax.y]]
ELSE Segment[[d.vmin.x,(-l.z-l.x*(d.vmin.x))/l.y], [d.vmax.x,(-l.z-l.x*d.vmax.x)/l.y]];
};
PreMultiplyNormal:
PROC [n: Pair, i: Matrix]
RETURNS [Pair] ~ {
RETURN[[i.row1.x*n.x+i.row1.y*n.y, i.row2.x*n.x+i.row2.y*n.y]];
};
PreMultiplyLine:
PROC [l: Triple, i: Matrix]
RETURNS [Triple] ~ {
RETURN[[
i.row1.x*l.x+i.row1.y*l.y+i.row1.z*l.z,
i.row2.x*l.x+i.row2.y*l.y+i.row2.z*l.z,
i.row3.x*l.x+i.row3.y*l.y+i.row3.z*l.z]];
};
XformPt:
PROC [p: Pair, i: Matrix]
RETURNS [Pair] ~ {
xHP: Triple ¬ G2dMatrix.Transform[[p.x, p.y, 1.0], i];
RETURN[[xHP.x/xHP.z, xHP.y/xHP.z]];
};
Action:
PROC ~ {
DrawTransformed:
PROC ~ {
x: Matrix ¬ G2dMatrix.Translate[
Rotate[
G2dMatrix.Scale[
G2dMatrix.Identity[],
[d.sx.value, d.sy.value]],
d.r.value],
[d.tx.value, d.ty.value]];
adjoint: Matrix ¬ G2dMatrix.Adjoint[x];
xP0: Pair ¬ XformPt[d.pts[d.nPts-1], x];
FOR i:
NAT
IN [0..d.nPts)
DO
xP1: Pair ¬ XformPt[d.pts[i], x];
n: Pair ¬ d.nrms[i];
xHN: Triple ¬ G2dMatrix.Transform[[n.x, n.y, 0.0], x];
type ← dashed; DrawLine[PreMultiplyLine[d.lines[i], adjoint]]; type ← solid;
type ¬ dashed; Arrow[xP1, [xHN.x, xHN.y]]; type ¬ solid;
Arrow[xP1, PreMultiplyNormal[d.nrms[i], adjoint]];
Segment[xP0, xP1];
xP0 ¬ xP1;
ENDLOOP;
};
DrawOriginal:
PROC ~ {
FOR i:
NAT
IN [0..d.nPts)
DO
p1: Pair ¬ d.pts[i];
Arrow[p1, d.nrms[i]];
Segment[p1, d.pts[(i+1) MOD d.nPts]];
ENDLOOP;
};
SELECT whatChanged
FROM
$IPOut => DrawTransformed[];
$Slider => {Buffer[restore]; DrawTransformed[]};
ENDCASE => {
d.vmin ¬ InvViewPt[[viewer.wx, viewer.wy]];
d.vmax ¬ InvViewPt[[viewer.wx+viewer.ww, viewer.wy+viewer.wh]];
DrawOriginal[];
Buffer[save];
IF whatChanged = $Init THEN DrawTransformed[];
};
};
d: Data ¬ NARROW[clientData];
type: Draw2d.DrawType ¬ solid;
Draw2d.DoWithBuffer[context, Action];
};
NPts: Controls.ClickProc ~ {
d: Data ¬ NARROW[clientData];
d.nPts ¬ Controls.GetNat[d.outerData.typescript, "# points: ", d.nPts];
Init[d];
Repaint[d, $Init];
};
IPOut: Controls.ClickProc ~ {
d: Data ¬ NARROW[clientData];
fileName: Rope.ROPE ¬ Controls.TypescriptReadFileName[d.outerData.typescript];
IF fileName # NIL THEN Draw2d.IPOut[fileName, Draw, d];
};
G2dTool.Register["Transform", TransformCmd, "2d transformations test"];