Scalaで図形言語
Scalaで図形言語に挑戦してみた。まだ、Scalaってコードではないけど…。
まずはベクトルClass
// Vector2d Class // newを省くためにcase classにする。 case class Vector2d(xVal: Double, yVal: Double) { val x: Double = xVal val y: Double = yVal override def toString = "("+x+","+y+")" def this(v:Double) = this(v,v) //s*(x,y)みたいなScaler積表現のため def + (that: Vector2d): Vector2d = new Vector2d(x+that.x, y+that.y) def - (that: Vector2d): Vector2d = new Vector2d(x-that.x, y-that.y) def scala (s: Double): Vector2d = new Vector2d(s*x, s*y) def * (that: Vector2d): Vector2d = new Vector2d(x*that.x, y*that.y) //s*(x,y)みたいなScaler積表現のため def * (s: Double): Vector2d = new Vector2d(s*x, s*y) //s*(x,y)みたいなScaler積表現のため }
次に、肝になるPainterの関連
import scala.swing._ import java.awt.Graphics2D class Frame(o:Vector2d, e1:Vector2d, e2:Vector2d) { val origin:Vector2d = o val edge1 :Vector2d = e1 val edge2 :Vector2d = e2 override def toString = "("+o+","+e1+","+e2+")" } case class Segment(s:Vector2d, e:Vector2d) { val start:Vector2d = s val end :Vector2d = e override def toString = "("+start+","+end+")" } // objectでPainter操作の集合を定義 object painterComponent { type Painter = (Frame) => (Graphics2D) => Unit //s*(x,y)みたいなScaler積表現のため implicit def doubleToVector2d(x: Double) = new Vector2d(x) def mapVectorToFrameCoord(f:Frame)(v:Vector2d):Vector2d = { f.origin + v.x * f.edge1 + v.y * f.edge2 } def segmentsToPainter(segments:List[Segment]):Painter = (f:Frame) => (g:Graphics2D) => { for(segment <- segments) { val start = mapVectorToFrameCoord(f)(segment.start) val end = mapVectorToFrameCoord(f)(segment.end) g.drawLine(start.x.toInt, start.y.toInt, end.x.toInt, end.y.toInt) } } def transformPainter(painter:Painter, origin:Vector2d, corner1:Vector2d, corner2:Vector2d):Painter = (baseFrame:Frame) => { val mapToBaseFrame = mapVectorToFrameCoord (baseFrame) _ val newOrigin = mapToBaseFrame (origin) val newEdge1 = mapToBaseFrame (corner1) - newOrigin val newEdge2 = mapToBaseFrame (corner2) - newOrigin val newFrame = new Frame(newOrigin, newEdge1, newEdge2) painter (newFrame) } def flipVert(painter:Painter):Painter = transformPainter(painter, Vector2d(0.0, 1.0), Vector2d(1.0, 1.0), Vector2d(0.0, 0.0)) def flipHoriz(painter:Painter):Painter = transformPainter(painter, Vector2d(1.0, 0.0), Vector2d(0.0, 0.0), Vector2d(1.0, 1.0)) def shrinkToUpperRight(painter:Painter):Painter = transformPainter(painter, Vector2d(0.5, 0.5), Vector2d(1.0, 0.5), Vector2d(0.5, 1.0)) def rotate90(painter:Painter):Painter = transformPainter(painter, Vector2d(1.0, 0.0), Vector2d(1.0, 1.0), Vector2d(0.0, 0.0)) def rotate180(painter:Painter):Painter = rotate90(rotate90(painter)) def rotate270(painter:Painter):Painter = rotate180(rotate90(painter)) def beside(leftp:Painter, rightp:Painter):Painter = (f:Frame) => (g:Graphics2D) => { val splitPoint = Vector2d(0.5,0.0) val shrinkedLeftp = transformPainter(leftp, Vector2d(0.0, 0.0), splitPoint, Vector2d (0.0, 1.0)) val shrinkedRightp = transformPainter(rightp, splitPoint, Vector2d (1.0, 0.0), Vector2d(0.5, 1.0)) shrinkedLeftp(f)(g) shrinkedRightp(f)(g) } def below(bottomp:Painter, topp:Painter):Painter = (f:Frame) => { rotate90 (beside(rotate270(bottomp), rotate270(topp))) (f) } def identiy(painter:Painter):Painter = painter def squareOfFour(tl:Painter => Painter, tr:Painter => Painter, bl:Painter => Painter, br:Painter => Painter) (painter:Painter):Painter = { val top:Painter = beside(tl(painter), tr(painter)) val bottom:Painter = beside(bl(painter), br(painter)) below (bottom, top) } def rightSplit(painter:Painter, n:Int):Painter = if(n > 0) { val smaller = rightSplit(painter, n-1) beside(painter, below(smaller, smaller)) } else { painter } def upSplit(painter:Painter, n:Int):Painter = if(n > 0) { val smaller = upSplit(painter, n-1) below(painter, beside(smaller, smaller)) } else { painter } def cornerSplit(painter:Painter, n:Int):Painter = if(n > 0){ val up = upSplit(painter, n-1) val right = rightSplit(painter, n-1) val topLeft = beside(up, up) val bottomRight = below(right, right) val corner = cornerSplit(painter, n-1) beside (below(painter,topLeft), below(bottomRight, corner)) } else { painter } def splitLimit(painter:Painter, n:Int):Painter = { val combine = squareOfFour(flipHoriz, identity, rotate180, flipVert) _ combine(cornerSplit(painter, n)) } } // Swingの部品。Painterをとって実際に実行 class canvasComponent(width:Int, height:Int, p:painterComponent.Painter) extends Component { peer.setPreferredSize(new Dimension(width, height)) override protected def paintComponent(g: Graphics2D){ //frameを設定するためにComponentの大きさを取る val currentSize:Dimension = peer.getSize() val origin = new Vector2d(0, currentSize.height) val edge1 = new Vector2d(currentSize.width, 0) val edge2 = new Vector2d(0, -currentSize.height) val componetFrame:Frame = new Frame(origin, edge1, edge2) //白で塗りつぶし g.setPaint(java.awt.Color.WHITE) g.fillRect(0, 0, currentSize.width, currentSize.height) //線の色は黒 g.setColor(java.awt.Color.BLACK) p(componetFrame)(g) } }
で、splitLimit 4を行うmainのオブジェクト
import scala.swing._ object wave extends SimpleSwingApplication { //名前空間を省略するためのalias type Painter = painterComponent.Painter def segmentsToPainter(segments:List[Segment]):Painter = painterComponent.segmentsToPainter(segments) def flipVert(painter:Painter):Painter = painterComponent.flipVert(painter) def flipHoriz(painter:Painter):Painter = painterComponent.flipHoriz(painter) def shrinkToUpperRight(painter:Painter):Painter = painterComponent.shrinkToUpperRight(painter) def beside(leftp:Painter, rightp:Painter):Painter = painterComponent.beside(leftp, rightp) def below(bottomp:Painter, topp:Painter):Painter = painterComponent.below(bottomp, topp) def rightSplit(painter:Painter, n:Int):Painter = painterComponent.rightSplit(painter, n) def upSplit(painter:Painter, n:Int):Painter = painterComponent.upSplit(painter, n) def cornerSplit(painter:Painter, n:Int):Painter = painterComponent.cornerSplit(painter, n) def splitLimit(painter:Painter, n:Int):Painter = painterComponent.splitLimit(painter, n) val waveSegment = List(Segment(Vector2d(0.0, 0.65), Vector2d(0.15, 0.4)), Segment(Vector2d(0.15, 0.4), Vector2d(0.3, 0.6)), Segment(Vector2d(0.3, 0.6), Vector2d(0.35, 0.55)), Segment(Vector2d(0.35, 0.55), Vector2d(0.25, 0.0)), Segment(Vector2d( 0.4, 0.0), Vector2d( 0.5, 0.3)), Segment(Vector2d( 0.5, 0.3), Vector2d( 0.6, 0.0)), Segment(Vector2d( 0.75,0.0), Vector2d( 0.6, 0.5)), Segment(Vector2d( 0.6, 0.5), Vector2d( 1.0, 0.15)), Segment(Vector2d( 1.0, 0.35), Vector2d( 0.75,0.65)), Segment(Vector2d( 0.75,0.65), Vector2d( 0.6, 0.65)), Segment(Vector2d( 0.6, 0.65), Vector2d( 0.65,0.85)), Segment(Vector2d( 0.65,0.85), Vector2d( 0.6, 1.0)), Segment(Vector2d( 0.4, 1.0), Vector2d( 0.35,0.85)), Segment(Vector2d( 0.35,0.85), Vector2d( 0.4, 0.65)), Segment(Vector2d( 0.4, 0.65), Vector2d( 0.3, 0.65)), Segment(Vector2d( 0.3, 0.65), Vector2d( 0.15,0.6)), Segment(Vector2d( 0.15,0.6), Vector2d( 0.0, 0.85))) val wave = segmentsToPainter(waveSegment) def top = new MainFrame { title = "wave" contents = new BorderPanel { add(new canvasComponent(400, 400, splitLimit(wave,4)), BorderPanel.Position.Center) } } }
参考にしたページ
Scala Componentメモ(Hishidama's Scala Swing Component Memo)