[[SCALAの記事一覧]]

&topicpath;

*目次 [#sa3690a0]
#contents

*参考URL [#e5a5b372]
http://d.hatena.ne.jp/uchida75cm/20101208/1291800041

*コード [#ie8c02a5]
 
 package net.knserve.scala.polygon {
  import java.awt.{ List => _, _ }
  import java.awt.event._
 
  object Main {
    def main( args: Array[ String ] ): Unit = {
    //メイン処理
     def main( args: Array[ String ] ): Unit = {
      val p0 = Point3( -100,  100, -100, 1 )
      val p1 = Point3(  100,  100, -100, 1 )
      val p2 = Point3(  100, -100, -100, 1 )
      val p3 = Point3( -100, -100, -100, 1 )
      val p4 = Point3( -100,  100,  100, 1 )
      val p5 = Point3(  100,  100,  100, 1 )
      val p6 = Point3(  100, -100,  100, 1 )
      val p7 = Point3( -100, -100,  100, 1 )
      val cubic = Cubic(
        Face( p0, p1, p2, p3 ),
        Face( p4, p5, p6, p7 ),
        Face( p0, p4, p5, p1 ),
        Face( p1, p5, p6, p2 ),
        Face( p2, p6, p7, p3 ),
        Face( p3, p7, p4, p0 )
      )
      val drw = new Draw( cubic )
      drw.setBackground( Color.black )
      drw.setSize( 400, 400 )
      drw.setVisible( true )
      val thr = new Thread( drw )
      thr.start
    }
  }
 
  //座標格納用クラス
  case class Point3( x: Double, y: Double, z: Double, s: Double ) {
 
    type Matrix[T] = List[ List[T] ]
    type Rotation[T] = List[ T ]
 
    def determinantZ( r: Rotation[ Double ] ): Matrix[ Double ] = List(
      List( cos(r(2)), sin(r(2)), 0, 0 ),
      List( -sin(r(2)), cos(r(2)), 0, 0 ),
      List( 0, 0, 1, 0 ),
      List( 0, 0, 0, 1 )
    ) 
 
    def determinantY( r: Rotation[ Double ] ): Matrix[ Double ] = List(
      List( cos(r(1)), 0, -sin(r(1)), 0 ),
      List( 0, 1, 0, 0 ),
      List( sin(r(1)), 0, cos(r(1)), 0 ),
      List( 0, 0, 0, 1 )
    )
 
    def determinantX( r: Rotation[ Double ] ): Matrix[ Double ] = List(
      List( 1, 0, 0, 0 ),
      List( 0, cos(r(0)), sin(r(0)), 0 ),
      List( 0, -sin(r(0)), cos(r(0)), 0 ),
      List( 0, 0, 0, 1 )
    )
 
  //ラジアンでsinを求める 
    def sin( d: Double ) = math.sin( math.toRadians( d ))

    //ラジアンでcosを求める
    def cos( d: Double ) = math.cos( math.toRadians( d ))
 
    //アフィン変換
    def affine( m: Matrix[Double] ): Point3 = {
      def fusion( a: List[Double], b: List[Double], f: (Double, Double) => Double ) =
        a.zip( b ).map( org => f( org._1, org._2 ) )
      Point3( fusion( toList, List.transpose( m )(0), _*_ ).foldLeft(0.0)(_+_),
              fusion( toList, List.transpose( m )(1), _*_ ).foldLeft(0.0)(_+_),
              fusion( toList, List.transpose( m )(2), _*_ ).foldLeft(0.0)(_+_),
              fusion( toList, List.transpose( m )(3), _*_ ).foldLeft(0.0)(_+_)
            )
    }
 
    //回転
    def rotate( r: Rotation[ Double ] ) =
      affine( determinantX( r ) ).
        affine( determinantY( r ) ).
          affine( determinantZ( r ) ) 
 
    //リスト化
    def toList = List( x, y, z, s )
  }
  
  //表面(点の配列から構成)
  case class Face( points: Point3* ) {
    def toList: List[ Point3 ] = points.toList
  }
  
 //立体(表面から構成)
  case class Cubic( faces: Face* ) {
    def toList: List[ Face ] = faces.toList
  }
 
  //描画用定数
  object World {
    val axis3Depth = 400
    val screenDepth = 320
  }
 
  //描画
  object Draw {
    val axis2X = 200
    val axis2Y = 200
    val convert2d: ( Double, Double, Double ) => Int =
      ( x1, L1, L2 ) => (( x1 * L2 ) / L1).toInt
  //3次元を2次元に変換
    def P3toP2( p: Point3 ): Tuple2[Int, Int] = (
      convert2d( p.x, World.axis3Depth+p.z, World.screenDepth ),
      convert2d( p.y, World.axis3Depth+p.z, World.screenDepth )
    )
 
    
    //ポリゴン生成
    def polygonFactory( fc: List[Point3] ): Polygon = {
      val plist = fc.map( p => P3toP2( p ) )
      new Polygon(
        plist.map( p => p._1 + axis2X ).toArray,
        plist.map( p => p._2 + axis2Y ).toArray,
        plist.length
      )
    }
  }
 
  //マウス認識
  class Draw( cubic: Cubic ) extends Frame with Runnable with MouseMotionListener {
    
    addMouseMotionListener( this )
    addWindowListener( new WindowAdapter {
        override def windowClosing( e: WindowEvent ): Unit = {
          System.exit( 0 )
        }
    })
 
    val c: Cubic = cubic
    var r: List[Double] = List( 0.0, 0.0, 0.0 )
 
    override def paint( g: Graphics ): Unit = {
      g.setColor( Color.white )
      val rotated = c.toList.map( fc => fc.toList.map( p => p.rotate( r ) ) )
      rotated.foreach( fc => g.drawPolygon( Draw.polygonFactory( fc ) ) )
    }
 
    def mouseMoved( e: MouseEvent ): Unit = {
      r = List( e.getY-Draw.axis2Y, -( e.getX-Draw.axis2X ), 0.0 )
    }
 
    def mouseDragged( e: MouseEvent ): Unit = {
    }
 
    def run(): Unit = {
        try {
            while( true ) {
                repaint
                Thread.sleep( 30 )
            }
        } catch {
            case e: InterruptedException =>
                println( e.getMessage )
            }
        }
  }
 }

*実行方法 [#h09cbbc4]
上記のコードを2回ペーストする。
なぜ2回かというと、1回目ではPoint3が未定義と認識されて途中でエラーがでているからだ。

 Main.main(Array())

でマウスでグリグリできる立方体が表示されるよ。


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS