ホモサピエンス
戻る
::::::::::::::
Animal.java
::::::::::::::
/**
$Id: homo.html,v 1.1 2009/06/22 16:12:12 kishi Exp kishi $
*/
public interface Animal {
public void move();
}
::::::::::::::
Ape.java
::::::::::::::
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
$Id: homo.html,v 1.1 2009/06/22 16:12:12 kishi Exp kishi $
@author KISHI Yasuhiro
*/
public class Ape implements Animal {
/** 頭の中心座標 */
private Point head;
/** 頭の半径 */
private double headSize = 10.0;
/** 首根っこ */
private Point scrag;
/** 首の長さ */
private double lengthOfNeck = 10.0;
/** 尻 */
private Point hip;
public Ape( double x, double y ) {
head = new Point( x, y );
scrag = new Point( head.getX(), head.getY() + lengthOfNeck );
hip = new Point( scrag.getX() + 2.5, scrag.getY() + 20.0 );
}
public void move() {}
public void paint( Graphics g ) {
g.setColor( Color.green );
// 頭を描画
g.fillOval( ( int ) ( head.getX() - 0.5 * headSize ), ( int ) ( head.getY() - 0.5 * headSize ), ( int ) headSize, ( int ) headSize );
// 首を描く
g.drawLine( ( int ) head.getX(), ( int ) head.getY(), ( int ) scrag.getX(), ( int ) scrag.getY() );
// 背骨を描く
g.drawLine( ( int ) scrag.getX(), ( int ) scrag.getY(), ( int ) hip.getX(), ( int ) hip.getY() );
}
}
::::::::::::::
Branch.java
::::::::::::::
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* $Id: homo.html,v 1.1 2009/06/22 16:12:12 kishi Exp kishi $
* @author KISHI Yasuhiro
* 描画はBranchManagerに任せる
*/
public class Branch implements Runnable {
/** 寿命 */
private int lifeDuration = 200;
/** 現在の年齢 */
private int currentAge = 0;
/** 1年で伸びる長さ */
private double pitch;
/** 角度 */
private double angle;
private Point from;
private Point to;
private BranchManager manager;
private Map map;
/** 描画色 */
private Color color = Color.red;
public Branch( BranchManager manager, double angle, Point from, double pitch ) {
this.manager = manager;
this.angle = angle;
this.from = from;
this.to = new Point( from.getX(), from.getY() );
this.pitch = pitch;
// BranchManagerにこのインスタンスを登録
manager.addBranch( this );
// 子供の枝を生成するタイミングを設定する
MilestoneProvider milestoneProvider = new MilestoneProvider( lifeDuration );
map = milestoneProvider.getMilestones();
// 自身のスレッド開始
( new Thread( this ) ).start();
}
/** 描画色を決める */
public void setColor( Color color ) {
this.color = color;
}
public void run() {
while ( isGrowable() ) {
// 増分を求める
double deltaX = pitch * Math.cos( HomoSapiensUtil.degreeToRadian( angle ) );
double deltaY = pitch * Math.sin( HomoSapiensUtil.degreeToRadian( angle ) );
// 増分を与える
to.add( deltaX, deltaY );
// System.out.printf( "%8.3f - %8.3f\n", to.getX(), to.getY() );
currentAge++;
// 子供の枝を生成する
beget();
try {
Thread.sleep( 100 );
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
private void beget() {
if ( !manager.isAcceptable() ) {
//-----------------------------------------------------
// 枝の数の上限を超えたら、新たな枝を生成しない
//-----------------------------------------------------
return ;
}
//-------------------------------------------------------------
// 子供の枝を生成させる年齢に達したかどうかをチェックする
//-------------------------------------------------------------
Integer key = new Integer( currentAge );
if ( map.containsKey( key ) ) {
Double value = ( Double ) map.get( key );
System.out.printf( "%3d %6.2f\n", key.intValue(), value.doubleValue() );
// 新たな枝の開始位置
Point newFrom = new Point( to.getX(), to.getY() );
Branch newBranch = new Branch( manager, angle + value, newFrom, pitch * 0.8 );
newBranch.setColor( color );
}
}
/** 成長可能かどうか */
private boolean isGrowable() {
return currentAge < lifeDuration;
}
public void paint( Graphics g ) {
g.setColor( color );
g.drawLine( ( int ) from.getX(), ( int ) from.getY(), ( int ) to.getX(), ( int ) to.getY() );
}
static public void main( String[] args ) {
BranchManager manager = new BranchManager( 500 );
Point from = new Point( 0.0, 0.0 );
Branch branch = new Branch( manager, 90.0, from, 1.0 );
}
}
::::::::::::::
BranchManager.java
::::::::::::::
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* $Id: homo.html,v 1.1 2009/06/22 16:12:12 kishi Exp kishi $
* @author KISHI Yasuhiro
* 複数のブランチを管理するクラス
*/
public class BranchManager {
/** 許容最大数 */
private int permissibleCount;
private java.util.List list = new LinkedList();
public BranchManager( int permissibleCount ) {
this.permissibleCount = permissibleCount;
;
}
public void addBranch( Branch branch ) {
list.add( branch );
}
public int getSize() {
return list.size();
}
public synchronized boolean isAcceptable() {
return permissibleCount > list.size();
}
public synchronized void paintAll( Graphics g ) {
Iterator iterator = list.iterator();
while ( iterator.hasNext() ) {
Branch branch = ( Branch ) iterator.next();
branch.paint( g );
}
}
}
::::::::::::::
Centipede.java
::::::::::::::
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
$Id: homo.html,v 1.1 2009/06/22 16:12:12 kishi Exp kishi $
@author KISHI Yasuhiro
*/
public class Centipede implements Animal {
private int count;
private int angle = 0;
private java.util.List pointList = new LinkedList();
/** 節点間の距離 */
private double segmentLength = 128.0;
public Centipede( double sx, double sy, int count ) {
this.count = count;
double[] point = new double[ 2 ];
point[ 0 ] = sx;
point[ 1 ] = sy;
pointList.add( point );
for ( int i = 1;i < count;i++ ) {
double[] nextPoint = new double[ 2 ];
sy += segmentLength;
nextPoint[ 0 ] = sx;
nextPoint[ 1 ] = sy;
pointList.add( nextPoint );
}
System.out.println( pointList.size() );
}
public void move() {
angle++;
if ( angle == 360 ) {
angle = 0;
}
// 先頭の点を移動させる
double[] point = ( double[] ) pointList.get( 0 );
point[ 0 ] = 400 + 321 * Math.cos( Math.PI * angle / 60.0 );
point[ 1 ] = 200 + 250 * Math.sin( Math.PI * angle / 240.0 );
// 追従する点の座標を求める
double[] attractor = point;
for ( int i = 1;i < count;i++ ) {
double[] follower = ( double[] ) pointList.get( i );
//===================================================
// アトラクタが動いた後の距離を求める
//===================================================
double newDistance = HomoSapiensUtil.getDistance( attractor, follower );
//System.out.printf("-- %8.2f\n", newDistance);
//===================================================
// フォロワの次の位置を取得し、更新する
//===================================================
double xDiff = attractor[ 0 ] - follower[ 0 ];
double yDiff = attractor[ 1 ] - follower[ 1 ];
follower[ 0 ] += xDiff * ( segmentLength / newDistance );
follower[ 1 ] += yDiff * ( segmentLength / newDistance );
attractor = follower;
}
}
public void paint( Graphics g ) {
g.setColor( Color.white );
for ( int i = 1;i < count;i++ ) {
double[] from = ( double[] ) pointList.get( i - 1 );
double[] to = ( double[] ) pointList.get( i );
g.drawLine( ( int ) from[ 0 ], ( int ) from[ 1 ], ( int ) to[ 0 ], ( int ) to[ 1 ] );
}
}
public void dumpAll() {
Iterator iterator = pointList.iterator();
while ( iterator.hasNext() ) {
double[] point = ( double[] ) iterator.next();
System.out.printf( "(%8.2f - %8.2f) ", point[ 0 ], point[ 1 ] );
}
System.out.println();
}
// 単体試験用
public static void main( String[] args ) {
Centipede centipede = new Centipede( 10.0, 0.0, 4 );
centipede.dumpAll();
for ( int i = 0;i < 50;i++ ) {
centipede.move();
centipede.dumpAll();
}
}
}
::::::::::::::
DrawingPanel.java
::::::::::::::
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
$Id: homo.html,v 1.1 2009/06/22 16:12:12 kishi Exp kishi $
@author KISHI Yasuhiro
*/
public class DrawingPanel extends JPanel implements Runnable {
private Ape ape;
private Centipede centipede;
private Plant plant;
private PlantPainter plantPainter;
private BranchManager branchManager;
private BranchManager branchManager2;
private BranchManager branchManager3;
private Branch branch;
private Branch branch2;
private Branch branch3;
private final double[] CENTER_POINT = {400.0, 300.0};
private double rotationAngle = 0.0;
public DrawingPanel() {
System.out.println( isDoubleBuffered() );
setDoubleBuffered( true );
System.out.println( isDoubleBuffered() );
//--------------------------------
// お猿さん
//--------------------------------
ape = new Ape( 30, 50 );
//--------------------------------
// ムカデ
//--------------------------------
centipede = new Centipede( 400.0, 300.0, 500 );
//--------------------------------
// 植物
//--------------------------------
Point start = new Point( 200.0, 5.0 );
plant = new Plant( start, 90.0, 3, 5, 60.0 );
//--------------------------------
// 枝
//--------------------------------
branchManager = new BranchManager( 1000 );
branch = new Branch( branchManager, -90.0, new Point( 400, 600 ), 1.0 );
branch.setColor( Color.blue );
branchManager2 = new BranchManager( 2000 );
branch2 = new Branch( branchManager2, -90.0, new Point( 200, 600 ), 0.5 );
branch2.setColor( Color.red );
branchManager3 = new BranchManager( 500 );
branch3 = new Branch( branchManager, -90.0, new Point( 600, 600 ), 0.75 );
branch3.setColor( Color.yellow );
// スレッド開始
Thread thread = new Thread( this );
thread.start();
}
public void run() {
while ( true ) {
// System.out.println( ( new java.util.Date() ).toString() );
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
repaint();
}
}
);
try {
Thread.sleep( 100 );
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
public void paintComponent( Graphics g ) {
int width = getWidth();
int height = getHeight();
//--------------------------------------------------
// 画面クリア
//--------------------------------------------------
g.setColor( Color.black );
//--------------------------------------------------
// このコンポーネントのサイズを取得する
//--------------------------------------------------
g.fillRect( 0 , 0 , width , height );
// お猿さん
ape.move( );
ape.paint( g );
// ムカデ(ムカデに見えない)
centipede.move( );
centipede.paint( g );
// 植物を描画してくれるクラスに線分のリストを引き渡す
rotationAngle += 5.0;
java.util.List rotatedSegmentList = SegmentRotator.getList( plant.getSegmentList(), CENTER_POINT, rotationAngle );
plantPainter = new PlantPainter( rotatedSegmentList );
plantPainter.paint( g );
// 枝
branchManager.paintAll( g );
branchManager2.paintAll( g );
branchManager3.paintAll( g );
}
}
::::::::::::::
HomoSapiens.java
::::::::::::::
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* <pre>
* 人の動きをシミュレーションするApplet
* </pre>
* $Id: homo.html,v 1.1 2009/06/22 16:12:12 kishi Exp kishi $
* @author KISHI Yasuhiro
*/
public class HomoSapiens extends JApplet {
public void init() {
Container contentPane = getContentPane();
contentPane.setLayout( new FlowLayout() );
DrawingPanel dp = new DrawingPanel();
dp.setPreferredSize( new Dimension( getWidth() , getHeight() ) );
contentPane.add( dp );
}
}
::::::::::::::
HomoSapiensUtil.java
::::::::::::::
/**
$Id: homo.html,v 1.1 2009/06/22 16:12:12 kishi Exp kishi $
*/
public class HomoSapiensUtil {
/** 2点間の距離を求める */
static public double getDistance( double[] from , double[] to ) {
return Math.sqrt(
( from[ 0 ] - to[ 0 ] ) * ( from[ 0 ] - to[ 0 ] )
+ ( from[ 1 ] - to[ 1 ] ) * ( from[ 1 ] - to[ 1 ] )
);
}
/** 2点間の距離を求める */
static public double getDistance( Point from , Point to ) {
return Math.sqrt(
( from.getX() - to.getX() ) * ( from.getX() - to.getX() )
+ ( from.getY() - to.getY() ) * ( from.getY() - to.getY() )
);
}
/** 線分の傾きを角度で返す
* @param from 開始点
* @param to 終了点
* @return 角度
*/
static double getAngle( double[] from , double[] to ) {
double xDiff = to[ 0 ] - from[ 0 ];
double yDiff = to[ 1 ] - from[ 1 ];
// 傾きを得る
double gradient = yDiff / xDiff;
// DEGREE(度)で返す
return Math.atan( gradient ) * 180.0 / Math.PI;
}
/** 角度をラジアンに変換して返す */
static double degreeToRadian( double angle ) {
return angle * Math.PI / 180.0;
}
/** 指定した点を中心にある角度だけ回転させる */
static double[] rotate( double[] originalPoint, double[] centerPoint, double rotationAngle ) {
double[] newPoint = new double[ 2 ];
double radius = getDistance( centerPoint, originalPoint );
// System.out.println( "radius=" + radius );
double currentAngle = getAngle( centerPoint, originalPoint );
// System.out.println( "currentAngle=" + currentAngle );
double nextAngle = currentAngle + rotationAngle;
// System.out.println( "nextAngle=" + nextAngle );
newPoint[ 0 ] = centerPoint[ 0 ] + radius * Math.cos( nextAngle / 180.0 * Math.PI );
newPoint[ 1 ] = centerPoint[ 1 ] + radius * Math.sin( nextAngle / 180.0 * Math.PI );
return newPoint;
}
}
::::::::::::::
MilestoneProvider.java
::::::::::::::
import java.util.*;
/**
* $Id: homo.html,v 1.1 2009/06/22 16:12:12 kishi Exp kishi $
* @author KISHI Yasuhiro
*/
public class MilestoneProvider {
private Map milestones;
public MilestoneProvider( int lifeDuration ) {
/** 人生のうちに3回岐路がある? */
milestones = new TreeMap();
int first = lifeDuration / 2;
milestones.put( new Integer( first ), new Double( getFluctuation() ) );
int second = lifeDuration * 3 / 4;
milestones.put( new Integer( second ), new Double( getFluctuation() ) );
int third = lifeDuration * 7 / 8 ;
milestones.put( new Integer( third ), new Double( getFluctuation() ) );
}
/** 揺らぎを取得する */
private double getFluctuation() {
Random random = new Random();
// -45.0から+45.0の範囲内に収まるようにする
return random.nextDouble() * 90.0 - 45.0;
}
public Map getMilestones() {
// メソッドの戻り値の型は極力インタフェースあるは抽象クラスを使う!
return milestones;
}
// 単体試験
static public void main( String[] args ) {
if ( args.length != 1 ) {
System.out.println( "Usage: java MilestoneProvider [lifeDuration]" );
System.exit( 1 );
}
MilestoneProvider mp = new MilestoneProvider( new Integer( args[ 0 ] ).intValue() );
Map map = mp.getMilestones();
Iterator iterator = map.keySet().iterator();
while ( iterator.hasNext() ) {
Integer key = ( Integer ) iterator.next();
Double value = ( Double ) map.get( key );
System.out.printf( "%3d %6.2f\n", key.intValue(), value.doubleValue() );
}
}
}
::::::::::::::
Plant.java
::::::::::::::
import java.util.*;
/**
* <pre>
* $Id: homo.html,v 1.1 2009/06/22 16:12:12 kishi Exp kishi $
* @author KISHI Yasuiro
* 植物を表現するクラス(MODEL)
* </pre>
*/
public class Plant {
private int childrenCount;
private int depth;
private double segmentLength;
/** 最初に与える点 */
private Point startPoint;
/** 生成した線分をリストに格納したもの */
private List segmentList = new LinkedList();
public Plant( Point startPoint, double firstAngle, int childrenCount, int depth, double segmentLength ) {
this.startPoint = startPoint;
this.childrenCount = childrenCount;
this.depth = depth;
this.segmentLength = segmentLength;
// 初期の角度を与える
generate( startPoint, firstAngle, 0 );
}
private void generate( Point startPoint, double angle, int layer ) {
if ( layer < depth ) {
// 子ノードに与える角度を求める
double[] nextAngles = getNextAngles( angle, layer );
// 子ノードを生成する
for ( int i = 0;i < childrenCount;i++ ) {
double x = startPoint.getX() + segmentLength * Math.cos( nextAngles[ i ] * Math.PI / 180.0 );
double y = startPoint.getY() + segmentLength * Math.sin( nextAngles[ i ] * Math.PI / 180.0 );
Point nextStartPoint = new Point( x, y );
// 線分を生成
Segment segment = new Segment( startPoint, nextStartPoint );
// segment.dump();
// 線分をリストに追加
segmentList.add( segment );
// 再帰処理
generate( nextStartPoint, nextAngles[ i ], layer + 1 );
}
}
}
private double[] getNextAngles( double angle, int layer ) {
double[] nextAngles = new double[ childrenCount ];
double range = 30.0;
double diff = range / ( childrenCount - 1 );
double firstAngle = angle - range / 2.0;
/*
indent( layer );
System.out.printf( "もともとの角度=%6.3f\n" , angle );
*/
for ( int i = 0;i < childrenCount;i++ ) {
nextAngles[ i ] = firstAngle + i * diff;
/*
indent( layer );
System.out.printf( "--得られた角度=%6.3f\n" , nextAngles[ i ] );
*/
}
return nextAngles;
}
public List getSegmentList() {
return segmentList;
}
/** インデントする */
private void indent( int layer ) {
for ( int i = 0;i < layer;i++ ) {
System.out.print( " " );
}
}
// 単体試験
static public void main( String[] args ) {
if ( args.length != 2 ) {
System.out.println( "Usage: java Plant [childrenCount] [nodeDepth]" );
System.exit( 1 );
}
Point start = new Point( 0.0, 0.0 );
double firstAngle = 0.0;
// インスタンス化およびツリーの生成
Plant plant = new Plant( start, firstAngle, new Integer( args[ 0 ] ).intValue(), new Integer( args[ 1 ] ).intValue(), 10.0 );
}
}
::::::::::::::
PlantPainter.java
::::::::::::::
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* $Id: homo.html,v 1.1 2009/06/22 16:12:12 kishi Exp kishi $
* @author KISHI Yasuhiro
* 植物を描画するクラス
*/
public class PlantPainter {
private java.util.List segmentList;
public PlantPainter( java.util.List segmentList ) {
this.segmentList = segmentList;
}
public void paint( Graphics g ) {
g.setColor( new Color( 0xcc, 0xcc, 0xff ) );
Iterator iterator = segmentList.iterator();
while ( iterator.hasNext() ) {
Segment segment = ( Segment ) iterator.next();
Point from = segment.getFrom();
Point to = segment.getTo();
g.drawLine( ( int ) from.getX(), ( int ) from.getY(), ( int ) to.getX(), ( int ) to.getY() );
}
}
}
::::::::::::::
Point.java
::::::::::::::
/**
$Id: homo.html,v 1.1 2009/06/22 16:12:12 kishi Exp kishi $
*/
public class Point {
private double x, y;
public Point( double x, double y ) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public void set
( double x, double y ) {
this.x = x;
this.y = y;
}
/** x,yの座標値を配列で返す */
public double[] get
() {
double[] value = new double[ 2 ];
value[ 0 ] = x;
value[ 1 ] = y;
return value;
}
public void add
( double deltaX, double deltaY ) {
x += deltaX;
y += deltaY;
}
}
::::::::::::::
Segment.java
::::::::::::::
/**
* <pre>
* $Id: homo.html,v 1.1 2009/06/22 16:12:12 kishi Exp kishi $
* @author KISHI Yasuiro
* 線分を表現するクラス
* </pre>
*/
public class Segment {
private Point from, to;
public Segment( Point from , Point to ) {
this.from = from;
this.to = to;
}
public Point getFrom() {
return from;
}
public Point getTo() {
return to;
}
public void dump() {
System.out.printf( "( %6.3f, %6.3f ) - ( %6.3f, %6.3f )\n",
from.getX(), from.getY(),
to.getX(), to.getY() );
}
}
::::::::::::::
SegmentRotator.java
::::::::::::::
import java.util.*;
/**
$Id: homo.html,v 1.1 2009/06/22 16:12:12 kishi Exp kishi $
@author KISHI Yasuhiro
*/
public class SegmentRotator {
static public List getList( List segmentList, double[] centerPoint, double angle ) {
List list = new LinkedList();
Iterator iterator = segmentList.iterator();
while ( iterator.hasNext() ) {
Segment segment = ( Segment ) iterator.next();
Point from = segment.getFrom();
Point to = segment.getTo();
double[] newFrom = HomoSapiensUtil.rotate( from.get(), centerPoint, angle );
double[] newTo = HomoSapiensUtil.rotate( to.get(), centerPoint, angle );
Segment newSegment = new Segment(
new Point( newFrom[ 0 ], newFrom[ 1 ] )
, new Point( newTo[ 0 ], newTo[ 1 ] ) );
list.add( newSegment );
}
return list;
}
}
戻る