Syntax10.Scn.Fnt MODULE Kepler8; (* Semesterarbeit Wintersemester 91/92 von Samuel Urech Erweiterung des Graphikeditors Kepler um Objektklassen f r das Zeichnen von technischen Graphen. Programmiersprache: Oberon-2 auf Ceres-1 Autor: Samuel Urech, Tannenrauchstrasse 35/107, 8038 Z Tel. 01 481 92 92 Stud.Nr. 87-906-434 Datum: 13.12.91 Stand: 12.2.92 J. Templ, 18.06.92, NewEllipIntersect renamed to NewEllipseIntersect J. Templ, 01.07.93 expressions simplified IMPORT Display, Math, Files, KeplerPorts, KeplerGraphs, KeplerFrames, In; CONST EPS = 0.001; fg = Display.white; TYPE RectIntersect* = POINTER TO RectIntersectDesc; RectIntersectDesc* = RECORD ( KeplerGraphs.PlanetDesc ) END; (* RectIntersect *) CircleIntersect* = POINTER TO CircleIntersectDesc; CircleIntersectDesc* = RECORD ( KeplerGraphs.PlanetDesc ) END; (* CircleIntersect *) EllipIntersect* = POINTER TO EllipIntersectDesc; EllipIntersectDesc* = RECORD ( KeplerGraphs.PlanetDesc ) END; (* EllipIntersect *) AttrRect* = POINTER TO AttrRectDesc; AttrRectDesc* = RECORD ( KeplerGraphs.ConsDesc ) texture* : INTEGER; (* Textur des Inneren des Rechtecks *) lineWidth* : INTEGER; (* Liniendicke *) shadow* : INTEGER; (* Textur des Schattens; <= 0: kein Schatten *) shadowWidth* : INTEGER; (* Breite des Schattens; <= 0: kein Schatten *) corner* : INTEGER; (* Radius der Ecken; <= 1: keine Abrundungen *) END; (* AttrRect *) FilledCircle* = POINTER TO FilledCircleDesc; FilledCircleDesc* = RECORD ( KeplerGraphs.ConsDesc ) texture* : INTEGER; (* Textur des Inneren des Kreises *) END; (* FilledCircle *) (* ---------------------------------------- Hilfsprozeduren ---------------------------------------- *) PROCEDURE MinMax( a, b : INTEGER; VAR min, max: INTEGER ); BEGIN IF a < b THEN min := a; max := b ELSE min := b; max := a END END MinMax; (* ----------------------------------------- RectIntersect ----------------------------------------- *) PROCEDURE ( self : RectIntersect ) Calc*; VAR mx, my, x1, y1, x2, y2 : INTEGER; slope : REAL; BEGIN (* Calc *) mx := ( self.c.p[ 0 ].x + self.c.p[ 1 ].x ) DIV 2; my := ( self.c.p[ 0 ].y + self.c.p[ 1 ].y ) DIV 2; IF ( mx = self.c.p[ 2 ].x ) & ( my = self.c.p[ 2 ].y ) THEN self.x := mx; self.y := self.c.p[ 1 ].y; ELSE IF self.c.p[ 2 ].x - mx # 0 THEN slope := ( self.c.p[ 2 ].y - my ) / ( self.c.p[ 2 ].x - mx ); IF ( self.c.p[ 1 ].x # mx ) & ( ABS( slope ) > ABS( ( self.c.p[ 1 ].y - my ) / ( self.c.p[ 1 ].x - mx ) ) ) THEN (* Gerade schneidet auf waagrechter Linie *) IF ( ( self.c.p[ 2 ].y < my ) & ( self.c.p[ 0 ].y < my ) ) OR ( ( self.c.p[ 2 ].y > my ) & ( self.c.p[ 0 ].y > my ) ) THEN self.y := self.c.p[ 0 ].y; self.x := mx + SHORT( ENTIER( ( self.c.p[ 0 ].y - my ) / slope ) ); ELSE self.y := self.c.p[ 1 ].y; self.x := mx + SHORT( ENTIER( ( self.c.p[ 1 ].y - my ) / slope ) ); END; (* IF *) ELSE (* Gerade schneidet auf senkrechter Linie *) IF self.c.p[ 2 ].y - my # 0 THEN IF ( ( self.c.p[ 2 ].x < mx ) & ( self.c.p[ 0 ].x < mx ) ) OR ( ( self.c.p[ 2 ].x > mx ) & ( self.c.p[ 0 ].x > mx ) ) THEN self.x := self.c.p[ 0 ].x; self.y := my + SHORT( ENTIER( ( self.c.p[ 0 ].x - mx ) * slope ) ); ELSE self.x := self.c.p[ 1 ].x; self.y := my + SHORT( ENTIER( ( self.c.p[ 1 ].x - mx ) * slope ) ); END; (* IF *) ELSE (* Gerade ist parallel zur Horizontalen *) self.y := my; IF ( ( self.c.p[ 2 ].x < mx ) & ( self.c.p[ 0 ].x < mx ) ) OR ( ( self.c.p[ 2 ].x > mx ) & ( self.c.p[ 0 ].x > mx ) ) THEN self.x := self.c.p[ 0 ].x; ELSE self.x := self.c.p[ 1 ].x; END; (* IF *) END; (* IF *) END; (* IF *) ELSE (* Gerade ist parallel zur Vertikalen *) self.x := mx; IF ( ( self.c.p[ 2 ].y < my ) & ( self.c.p[ 0 ].y < my ) ) OR ( ( self.c.p[ 2 ].y > my ) & ( self.c.p[ 0 ].y > my ) ) THEN self.y := self.c.p[ 0 ].y; ELSE self.y := self.c.p[ 1 ].y; END; (* IF *) END; (* IF *) END; (* IF *) END Calc; PROCEDURE NewRectIntersect*; (* Liest drei Fokuspunkte ein und bestimmt einen Planeten am Schnittpunkt zwischen dem Rechteck, das durch die ersten beiden Punkte bestimmt wird und der Gerade durch den Mittelpunkt des Rechtecks und den dritten Punkt. *) VAR new : RectIntersect; BEGIN (* NewRectIntersect *) IF KeplerFrames.nofpts >= 3 THEN NEW( new ); NEW( new.c ); new.c.nofpts := 3; KeplerFrames.ConsumePoint( new.c.p[ 0 ] ); KeplerFrames.ConsumePoint( new.c.p[ 1 ] ); KeplerFrames.ConsumePoint( new.c.p[ 2 ] ); new.Calc; KeplerFrames.Focus.Append( new ); KeplerFrames.Focus.FlipSelection( new ); END; (* IF *) END NewRectIntersect; (* -------------------------------------------- CircleIntersect -------------------------------------- *) PROCEDURE ( self : CircleIntersect ) Calc*; VAR factor : REAL; x0, y0, x1, y1, x2, y2 : LONGINT; BEGIN (* Calc *) x0 := self.c.p[ 0 ].x; y0 := self.c.p[ 0 ].y; x1 := self.c.p[ 1 ].x; y1 := self.c.p[ 1 ].y; x2 := self.c.p[ 2 ].x; y2 := self.c.p[ 2 ].y; IF ( x0 = x2 ) & ( y0 = y2 ) THEN self.x := SHORT( x1 ); self.y := SHORT( y1 ); ELSE factor := Math.sqrt( ( ( ( x1 - x0 ) * ( x1 - x0 ) ) + ( ( y1 - y0 ) * ( y1 - y0 ) ) ) / ( ( ( x2 - x0 ) * ( x2 - x0 ) ) + ( ( y2 - y0 ) * ( y2 - y0 ) ) ) ); self.x := SHORT( x0 ) + SHORT( ENTIER( factor * ( x2 - x0 ) ) ); self.y := SHORT( y0 ) + SHORT( ENTIER( factor * ( y2 - y0 ) ) ); END; (* IF *) END Calc; PROCEDURE NewCircleIntersect*; (* Liest drei Fokuspunkte ein und bestimmt einen Planeten am Schnittpunkt zwischen dem Kreis, dessen Mittelpunkt durch den ersten Punkt und dessen Radius durch den zweiten Punkt gegeben ist sowie der Gerade zwischen dem Mittelpunkt des Kreises und dem dritten Punkt. *) VAR new : CircleIntersect; BEGIN (* NewCircleIntersect *) IF KeplerFrames.nofpts >= 3 THEN NEW( new ); NEW( new.c ); new.c.nofpts := 3; KeplerFrames.ConsumePoint( new.c.p[ 0 ] ); KeplerFrames.ConsumePoint( new.c.p[ 1 ] ); KeplerFrames.ConsumePoint( new.c.p[ 2 ] ); new.Calc; KeplerFrames.Focus.Append( new ); KeplerFrames.Focus.FlipSelection( new ); END; (* IF *) END NewCircleIntersect; (* -------------------------------------------- EllipIntersect -------------------------------------- *) PROCEDURE ( self : EllipIntersect ) Calc*; VAR a2, b2 : LONGINT; slope2, temp : REAL; xsign, ysign, t : INTEGER; BEGIN (* Calc *) IF self.c.p[ 3 ].x > self.c.p[ 0 ].x THEN xsign := 1; ELSE xsign := -1; END; (* IF *) IF self.c.p[ 3 ].y > self.c.p[ 0 ].y THEN ysign := 1; ELSE ysign := -1; END; (* IF *) IF self.c.p[ 3 ].x # self.c.p[ 0 ].x THEN IF self.c.p[ 3 ].y # self.c.p[ 0 ].y THEN a2 := self.c.p[ 1 ].x - self.c.p[ 0 ].x; a2 := a2 * a2; b2 := self.c.p[ 2 ].y - self.c.p[ 0 ].y; b2 := b2 * b2; t := self.c.p[ 3 ].y - self.c.p[ 0 ].y; slope2 := ( t ) / ( self.c.p[ 3 ].x - self.c.p[ 0 ].x ); slope2 := slope2 * slope2; temp := a2 / ( b2 + a2*slope2 ) * b2; self.x := xsign * SHORT( ENTIER( Math.sqrt( temp ) ) ) + self.c.p[ 0 ].x; self.y := ysign * SHORT( ENTIER( Math.sqrt( slope2 * temp ) ) ) + self.c.p[ 0 ].y; ELSE (* Gerade ist horizontal *) t := self.c.p[ 1 ].x - self.c.p[ 0 ].x; self.x := self.c.p[ 0 ].x + xsign * ( t ); self.y := self.c.p[ 0 ].y; END; (* IF *) ELSE (* Gerade ist vertikal *) self.x := self.c.p[ 0 ].x; t := self.c.p[ 2 ].y - self.c.p[ 0 ].y; self.y := self.c.p[ 0 ].y + ysign * ( t ); END; (* IF *) END Calc; PROCEDURE NewEllipseIntersect*; (* Liest vier Fokuspunkte ein und bestimmt einen Planeten am Schnittpunkt zwischen der Ellipse, die durch die ersten drei Punkte gegeben ist, sowie der Gerade zwischen dem Mittelpunkt der Ellipse und dem vierten Punkt. *) VAR new : EllipIntersect; BEGIN (* NewEllipIntersect *) IF KeplerFrames.nofpts >= 4 THEN NEW( new ); NEW( new.c ); new.c.nofpts := 4; KeplerFrames.ConsumePoint( new.c.p[ 0 ] ); KeplerFrames.ConsumePoint( new.c.p[ 1 ] ); KeplerFrames.ConsumePoint( new.c.p[ 2 ] ); KeplerFrames.ConsumePoint( new.c.p[ 3 ] ); new.Calc; KeplerFrames.Focus.Append( new ); KeplerFrames.Focus.FlipSelection( new ); END; (* IF *) END NewEllipseIntersect; (* -------------------------------------------- AttrRect -------------------------------------- *) PROCEDURE ( self : AttrRect ) Read*( VAR r : Files.Rider ); BEGIN (* Read *) Files.ReadInt( r, self.texture ); Files.ReadInt( r, self.lineWidth ); Files.ReadInt( r, self.shadow ); Files.ReadInt( r, self.shadowWidth ); Files.ReadInt( r, self.corner ); self.Read^( r ); END Read; PROCEDURE ( self : AttrRect ) Write*( VAR r : Files.Rider ); BEGIN (* Write *) Files.WriteInt( r, self.texture ); Files.WriteInt( r, self.lineWidth ); Files.WriteInt( r, self.shadow ); Files.WriteInt( r, self.shadowWidth ); Files.WriteInt( r, self.corner ); self.Write^( r ); END Write; PROCEDURE ( self : AttrRect ) Draw*( f : KeplerPorts.Port ); VAR x1, y1, x2, y2 : INTEGER; BEGIN MinMax( self.p[ 0 ].x, self.p[ 1 ].x, x1, x2 ); MinMax( self.p[ 0 ].y, self.p[ 1 ].y, y1, y2 ); IF self.corner > 1 THEN (* rounded edges *) IF ( self.shadow > 0 ) & ( self.shadowWidth > 0 ) THEN (* draw shadow *) f.FillCircle( x2 + self.shadowWidth - self.corner, y2 - self.shadowWidth - self.corner, self.corner, fg, self.shadow, Display.replace ); f.FillCircle( x1 + self.shadowWidth + self.corner, y1 - self.shadowWidth + self.corner, self.corner, fg, self.shadow, Display.replace ); f.FillCircle( x2 + self.shadowWidth - self.corner, y1 - self.shadowWidth + self.corner, self.corner, fg, self.shadow, Display.replace ); IF self.shadowWidth > self.corner THEN f.FillRect( x2, y2 - self.shadowWidth - self.corner, self.shadowWidth - self.corner, self.corner + f.scale, fg, self.shadow, Display.replace ); f.FillRect( x1 + self.shadowWidth, y1 - self.shadowWidth + self.corner, self.corner, self.shadowWidth - self.corner, fg, self.shadow, Display.replace ); f.FillRect( x2 - self.corner + f.scale, y1 - f.scale, self.corner, self.corner, fg, self.shadow, Display.replace ); END; f.FillRect( x2 + f.scale, y1 - self.shadowWidth + self.corner, self.shadowWidth, y2 - y1 - 2 * self.corner, fg, self.shadow, Display.replace ); f.FillRect( x1 + self.shadowWidth + self.corner, y1 - self.shadowWidth - f.scale, x2 - x1 - 2 * self.corner, self.shadowWidth, fg, self.shadow, Display.replace ); END; f.FillCircle( x1 + self.corner, y1 + self.corner, self.corner, fg, 5, Display.replace ); f.FillCircle( x2 - self.corner, y1 + self.corner, self.corner, fg, 5, Display.replace ); f.FillCircle( x2 - self.corner, y2 - self.corner, self.corner, fg, 5, Display.replace ); f.FillCircle( x1 + self.corner, y2 - self.corner, self.corner, fg, 5, Display.replace ); IF self.corner > self.lineWidth THEN f.FillCircle( x1 + self.corner, y1 + self.corner, self.corner - self.lineWidth, fg, self.texture, Display.replace ); f.FillCircle( x2 - self.corner, y1 + self.corner, self.corner - self.lineWidth, fg, self.texture, Display.replace ); f.FillCircle( x2 - self.corner, y2 - self.corner, self.corner - self.lineWidth, fg, self.texture, Display.replace ); f.FillCircle( x1 + self.corner, y2 - self.corner, self.corner - self.lineWidth, fg, self.texture, Display.replace ) END; f.FillRect( x1 + self.lineWidth - f.scale, y1 + self.corner, x2 - x1 - 2 * self.lineWidth + 2 * f.scale, y2 - y1 - 2 * self.corner, fg, self.texture, Display.replace ); f.FillRect( x1 + self.corner, y1 + self.lineWidth - f.scale, x2 - x1 - 2 * self.corner, y2 - y1 - 2 * self.lineWidth + 2 * f.scale, fg, self.texture, Display.replace ); f.FillRect( x1 + self.corner, y1 - f.scale, x2 - x1 - 2 * self.corner, self.lineWidth + f.scale - 1, fg, 5, Display.replace ); f.FillRect( x1 + self.corner, y2 - self.lineWidth + f.scale, x2 - x1 - 2 * self.corner, self.lineWidth + f.scale - 1, fg, 5, Display.replace ); f.FillRect( x1 - f.scale, y1 + self.corner, self.lineWidth + f.scale - 1, y2 - y1 - 2 * self.corner, fg, 5, Display.replace ); f.FillRect( x2 - self.lineWidth + f.scale, y1 + self.corner, self.lineWidth + f.scale - 1, y2 - y1 - 2 * self.corner, fg, 5, Display.replace ); ELSE (* sharp edges *) f.FillRect( x2, y1 - self.shadowWidth, self.shadowWidth, y2 - y1, fg, self.shadow, Display.replace ); f.FillRect( x1 + self.shadowWidth, y1 - self.shadowWidth, x2 -x1, self.shadowWidth, fg, self.shadow, Display.replace ); f.FillRect( x1 + self.lineWidth, y1 + self.lineWidth, x2 - x1 - 2 * self.lineWidth, y2 - y1 - 2 * self.lineWidth, fg, self.texture, Display.replace ); f.FillRect( x1, y1, x2 - x1, self.lineWidth, fg, 5, Display.replace ); f.FillRect( x1, y2 - self.lineWidth, x2 - x1, self.lineWidth, fg, 5, Display.replace ); f.FillRect( x1, y1, self.lineWidth, y2 - y1, fg, 5, Display.replace ); f.FillRect( x2 - self.lineWidth, y1, self.lineWidth, y2 - y1, fg, 5, Display.replace ) END END Draw; PROCEDURE NewAttrRect*; VAR new : AttrRect; texture, lineWidth, shadow, shadowWidth, corner : INTEGER; BEGIN (* NewAttrRect *) IF KeplerFrames.nofpts >= 2 THEN NEW( new ); new.nofpts := 2; In.Open; In.Int( texture ); IF texture < 0 THEN new.texture := 0; ELSE new.texture := texture END; In.Int( lineWidth ); IF lineWidth < 0 THEN new.lineWidth := 0; ELSE new.lineWidth := lineWidth END; In.Int( shadow ); IF shadow < 0 THEN new.shadow := 0; ELSE new.shadow := shadow END; In.Int( shadowWidth ); IF shadowWidth < 0 THEN new.shadowWidth := 0; ELSE new.shadowWidth := shadowWidth END; In.Int( corner ); IF corner <= 1 THEN new.corner := 0; ELSE new.corner := corner END; IF In.Done THEN KeplerFrames.ConsumePoint( new.p[ 0 ] ); KeplerFrames.ConsumePoint( new.p[ 1 ] ); KeplerFrames.Focus.Append( new ); END; (* IF *) END; (* IF *) END NewAttrRect; (* -------------------------------------------- FilledCircle -------------------------------------- *) PROCEDURE ( self : FilledCircle ) Read*( VAR r : Files.Rider ); BEGIN (* Read *) Files.ReadInt( r, self.texture ); self.Read^( r ); END Read; PROCEDURE ( self : FilledCircle ) Write*( VAR r : Files.Rider ); BEGIN (* Write *) Files.WriteInt( r, self.texture ); self.Write^( r ); END Write; PROCEDURE ( self : FilledCircle ) Draw*( f : KeplerPorts.Port ); VAR rx, ry : LONGINT; r : INTEGER; BEGIN (* Draw *) rx := self.p[ 1 ].x - self.p[ 0 ].x; ry := self.p[ 1 ].y - self.p[ 0 ].y; r := SHORT( ENTIER( Math.sqrt( rx * rx + ry * ry ) ) ); f.FillCircle( self.p[ 0 ].x, self.p[ 0 ].y, r, fg, self.texture, Display.replace ); END Draw; PROCEDURE NewFilledCircle*; VAR new: FilledCircle; texture: INTEGER; BEGIN IF KeplerFrames.nofpts >= 2 THEN NEW( new ); new.nofpts := 2; In.Open; In.Int( texture ); IF texture < 0 THEN new.texture := 0; ELSE new.texture := texture; END; IF In.Done THEN KeplerFrames.ConsumePoint( new.p[ 0 ] ); KeplerFrames.ConsumePoint( new.p[ 1 ] ); KeplerFrames.Focus.Append( new ); END END END NewFilledCircle; END Kepler8.