Oberon/V2/Curves
Appearance
< Oberon
MODULE Curves; (*NW 8.11.90 / 1.2.91*)
IMPORT Display, Files, Printer, Oberon, Graphics, GraphicFrames;
TYPE Curve* = POINTER TO CurveDesc;
CurveDesc* = RECORD (Graphics.ObjectDesc)
kind*, lw*: INTEGER
END ;
(*kind: 0 = up-line, 1 = down-line, 2 = circle, 3 = ellipse*)
VAR method*: Graphics.Method;
PROCEDURE dot(f: GraphicFrames.Frame; col: INTEGER; x, y: LONGINT);
BEGIN
IF (f.X <= x) & (x < f.X1) & (f.Y <= y) & (y < f.Y1) THEN Display.Dot(col, x, y, 0) END
END dot;
PROCEDURE mark(f: GraphicFrames.Frame; col, x, y: INTEGER);
BEGIN
IF (f.X <= x) & (x+4 < f.X1) & (f.Y <= y) & (y+4 < f.Y1) THEN
Display.ReplConst(col, x, y, 4, 4, 0)
END
END mark;
PROCEDURE line(f: GraphicFrames.Frame; col: INTEGER; x, y, w, h, d: LONGINT);
VAR x1, y1, u: LONGINT;
BEGIN
IF h < w THEN
x1 := x+w; u := (h-w) DIV 2;
IF d = -1 THEN INC(y, h) END ;
WHILE x < x1 DO
dot(f, col, x, y); INC(x);
IF u < 0 THEN INC(u, h) ELSE INC(u, h-w); INC(y, d) END
END
ELSE y1 := y+h; u := (w-h) DIV 2;
IF d = -1 THEN INC(x, w) END ;
WHILE y < y1 DO
dot(f, col, x, y); INC(y);
IF u < 0 THEN INC(u, w) ELSE INC(u, w-h); INC(x, d) END
END
END
END line;
PROCEDURE circle(f: GraphicFrames.Frame; col: INTEGER; x0, y0, r: LONGINT);
VAR x, y, u: LONGINT;
BEGIN u := 1 - r; x := r; y := 0;
WHILE y <= x DO
dot(f, col, x0+x, y0+y); dot(f, col, x0+y, y0+x); dot(f, col, x0-y, y0+x);
dot(f, col, x0-x, y0+y);
dot(f, col, x0-x, y0-y); dot(f, col, x0-y, y0-x); dot(f, col, x0+y, y0-x); dot(f, col, x0+x, y0-y);
IF u < 0 THEN INC(u, 2*y+3) ELSE INC(u, 2*(y-x)+5); DEC(x) END ;
INC(y)
END
END circle;
PROCEDURE ellipse(f: GraphicFrames.Frame; col: INTEGER; x0, y0, a, b: LONGINT);
VAR x, y, y1, aa, bb, d, g, h: LONGINT;
BEGIN aa := a*a; bb := b*b;
h := (aa DIV 4) - b*aa + bb; g := (9*aa DIV 4) - 3*b*aa + bb; x := 0; y := b;
WHILE g < 0 DO
dot(f, col, x0+x, y0+y); dot(f, col, x0-x, y0+y); dot(f, col, x0-x, y0-y); dot(f, col, x0+x, y0-y);
IF h < 0 THEN d := (2*x+3)*bb; INC(g, d)
ELSE d := (2*x+3)*bb - 2*(y-1)*aa; INC(g, d + 2*aa); DEC(y)
END ;
INC(h, d); INC(x)
END ;
y1 := y; h := (bb DIV 4) - a*bb + aa; x := a; y := 0;
WHILE y <= y1 DO
dot(f, col, x0+x, y0+y); dot(f, col, x0-x, y0+y); dot(f, col, x0-x, y0-y); dot(f, col, x0+x, y0-y);
IF h < 0 THEN INC(h, (2*y+3)*aa) ELSE INC(h, (2*y+3)*aa - 2*(x-1)*bb); DEC(x) END ;
INC(y)
END
END ellipse;
PROCEDURE New*;
VAR c: Curve;
BEGIN NEW(c); c.do := method; Graphics.new := c
END New;
PROCEDURE* Copy(src, dst: Graphics.Object);
BEGIN dst(Curve)^ := src(Curve)^
END Copy;
PROCEDURE* Draw(obj: Graphics.Object; VAR M: Graphics.Msg);
VAR x, y, w, h, col: INTEGER; f: GraphicFrames.Frame;
BEGIN
WITH M: GraphicFrames.DrawMsg DO
x := obj.x + M.x; y := obj.y + M.y; w := obj.w; h := obj.h; f := M.f;
IF M.col = Display.black THEN col := obj.col ELSE col := M.col END ;
IF (x < f.X1) & (f.X <= x+w) & (y < f.Y1) & (f.Y <= y+h) THEN
IF obj(Curve).kind = 0 THEN (*up-line*)
IF M.mode = 0 THEN
IF obj.selected THEN mark(f, Display.white, x, y) END ;
line(f, col, x, y, w, h, 1)
ELSIF M.mode = 1 THEN mark(f, Display.white, x, y)
ELSIF M.mode = 2 THEN mark(f, Display.black, x, y)
ELSE mark(f, Display.black, x, y); line(f, Display.black, x, y, w, h, 1)
END
ELSIF obj(Curve).kind = 1 THEN (*down-line*)
IF M.mode = 0 THEN
IF obj.selected THEN mark(f, Display.white, x, y+h) END ;
line(f, col, x, y, w, h, -1)
ELSIF M.mode = 1 THEN mark(f, Display.white, x, y+h)
ELSIF M.mode = 2 THEN mark(f, Display.black, x, y+h)
ELSE mark(f, Display.black, x, y+h); line(f, Display.black, x, y, w, h, -1)
END
ELSIF obj(Curve).kind = 2 THEN (*circle*)
w := w DIV 2;
IF M.mode = 0 THEN
IF obj.selected THEN mark(f, Display.white, x+w, y-4) END ;
circle(f, col, x+w, y+w, w)
ELSIF M.mode = 1 THEN mark(f, Display.white, x+w, y-4)
ELSIF M.mode = 2 THEN mark(f, Display.black, x+w, y-4)
ELSE mark(f, Display.black, x+w, y-4); circle(f, Display.black, x+w, y+w, w)
END
ELSIF obj(Curve).kind = 3 THEN (*ellipse*)
w := w DIV 2; h := h DIV 2;
IF M.mode = 0 THEN
IF obj.selected THEN mark(f, Display.white, x+w, y-4) END ;
ellipse(f, col, x+w, y+h, w, h)
ELSIF M.mode = 1 THEN mark(f, Display.white, x+w, y-4)
ELSIF M.mode = 2 THEN mark(f, Display.black, x+w, y-4)
ELSE mark(f, Display.black, x+w, y-4); ellipse(f, Display.black, x+w, y+h, w, h)
END
END
END
END
END Draw;
PROCEDURE* Selectable(obj: Graphics.Object; x, y: INTEGER): BOOLEAN;
VAR xm, y0, w, h: INTEGER;
BEGIN
IF obj(Curve).kind <= 1 THEN (*line*)
w := obj.w; h := obj.h;
IF obj(Curve).kind = 1 THEN y0 := obj.y + h; h := -h ELSE y0 := obj.y END ;
RETURN
(obj.x <= x) & (x < obj.x + w) & (ABS(LONG(y-y0)*w - LONG(x-obj.x)*h) < w*4)
ELSE (*circle or ellipse*)
xm := obj.w DIV 2 + obj.x;
RETURN (xm - 4 <= x) & (x <= xm + 4) & (obj.y - 4 <= y) & (y <= obj.y + 4)
END
END Selectable;
PROCEDURE* Handle(obj: Graphics.Object; VAR M: Graphics.Msg);
BEGIN
IF M IS Graphics.ColorMsg THEN obj.col := M(Graphics.ColorMsg).col END
END Handle;
PROCEDURE* Read(obj: Graphics.Object; VAR R: Files.Rider; VAR C: Graphics.Context);
VAR len: SHORTINT;
BEGIN Files.Read(R, len); Graphics.ReadInt(R, obj(Curve).kind);
Graphics.ReadInt(R, obj(Curve).lw)
END Read;
PROCEDURE* Write(obj: Graphics.Object; cno: SHORTINT;
VAR W: Files.Rider; VAR C: Graphics.Context);
BEGIN Graphics.WriteObj(W, cno, obj);
Files.Write(W, 4); Graphics.WriteInt(W, obj(Curve).kind);
Graphics.WriteInt(W, obj(Curve).lw)
END Write;
PROCEDURE* Print(obj: Graphics.Object; x, y: INTEGER);
VAR x0, y0: INTEGER;
BEGIN
IF obj(Curve).kind = 0 THEN
x0 := obj.x * 4 + x; y0 := obj.y * 4 + y;
Printer.Line(x0, y0, obj.w * 4 + x0, obj.h * 4 + y0)
ELSIF obj(Curve).kind = 1 THEN
x0 := obj.x * 4 + x; y0 := obj.y * 4 + y;
Printer.Line(x0, obj.h * 4 + y0, obj.w * 4 + x0, y0)
ELSIF obj(Curve).kind = 2 THEN
Printer.Circle((obj.x*2 + obj.w)*2 + x, (obj.y*2 + obj.h)*2 + y, obj.w*2)
ELSE
Printer.Ellipse((obj.x*2 + obj.w)*2 + x, (obj.y*2 + obj.h)*2 + y, obj.w*2, obj.h*2)
END
END Print;
PROCEDURE MakeLine*; (*command*)
VAR x0, x1, y0, y1: INTEGER;
c: Curve;
G: GraphicFrames.Frame;
BEGIN G := GraphicFrames.Focus();
IF (G # NIL) & (G.mark.next # NIL) THEN
GraphicFrames.Deselect(G);
x0 := G.mark.x; y0 := G.mark.y; x1 := G.mark.next.x; y1 := G.mark.next.y;
NEW(c); c.col := Oberon.CurCol;
c.w := ABS(x1-x0); c.h := ABS(y1-y0); c.lw := Graphics.width;
IF x0 <= x1 THEN c.x := x0;
IF y0 <= y1 THEN c.kind := 0; c.y := y0 ELSE c.kind := 1; c.y := y1 END
ELSE c.x := x1;
IF y1 < y0 THEN c.kind := 0; c.y := y1 ELSE c.kind := 1; c.y := y0 END
END ;
DEC(c.x, G.x); DEC(c.y, G.y); c.do := method;
Graphics.Add(G.graph, c);
GraphicFrames.Defocus(G); GraphicFrames.DrawObj(G, c)
END
END MakeLine;
PROCEDURE MakeCircle*; (*command*)
VAR x0, y0, r: INTEGER;
c: Curve;
G: GraphicFrames.Frame;
BEGIN G := GraphicFrames.Focus();
IF (G # NIL) & (G.mark.next # NIL) THEN
GraphicFrames.Deselect(G);
x0 := G.mark.x; y0 := G.mark.y; r := ABS(G.mark.next.x-x0);
IF r > 4 THEN
NEW(c); c.x := x0 - r - G.x; c.y := y0 - r - G.y; c.w := 2*r+1; c.h := c.w;
c.kind := 2; c.col := Oberon.CurCol;
c.lw := Graphics.width; c.do := method;
Graphics.Add(G.graph, c);
GraphicFrames.Defocus(G); GraphicFrames.DrawObj(G, c)
END
END
END MakeCircle;
PROCEDURE MakeEllipse*; (*command*)
VAR x0, y0, a, b: INTEGER;
c: Curve;
G: GraphicFrames.Frame;
BEGIN G := GraphicFrames.Focus();
IF (G # NIL) & (G.mark.next # NIL) & (G.mark.next.next # NIL) THEN
GraphicFrames.Deselect(G);
x0 := G.mark.x; y0 := G.mark.y;
a := ABS(G.mark.next.x-x0); b := ABS(G.mark.next.next.y - y0);
IF (a > 4) & (b > 4) THEN
NEW(c); c.x := x0 - a - G.x; c.y := y0 - b - G.y; c.w := 2*a+1; c.h := 2*b+1;
c.kind := 3; c.col := Oberon.CurCol;
c.lw := Graphics.width; c.do := method;
Graphics.Add(G.graph, c);
GraphicFrames.Defocus(G); GraphicFrames.DrawObj(G, c)
END
END
END MakeEllipse;
BEGIN NEW(method); method.module := "Curves"; method.allocator := "New";
method.new := New; method.copy := Copy; method.draw := Draw;
method.selectable := Selectable; method.handle := Handle;
method.read := Read; method.write := Write; method.print := Print
END Curves.