ゆるゆるプログラミング

・円模様2

ここでは、できるだけ隙間がなくなるように円を並べて出来る模様の画像を作成する方法を紹介します。ここで紹介するプログラムで出力する画像の形式はPNGファイルです。

隙間の少ない円の整列模様円模様2

上の画像の例は、画像サイズ:256x256、円のピクセル半径:32、ピクセル線幅:4で作成したものです。

Pattern_Circle02.java ← クリックしてダウンロードページに移動
001:    import java.awt.image.BufferedImage;
002:    import java.awt.Graphics2D;
003:    import java.awt.Color;
004:    import java.awt.BasicStroke;
005:    import java.io.File;
006:    import javax.imageio.ImageIO;
007:    
008:    public class Pattern_Circle02 {
009:    	public static void main(String[] args) {
010:    		// 変数宣言
011:    		int w, h;			// 画像サイズ
012:    		int radius;			// 円の半径
013:    		int line_w;			// 線幅
014:    		String outname;			// 出力ファイル名
015:    		BufferedImage img = null;	// 画像格納クラス
016:    
017:    		// 入力した引数が5以上かを調べる
018:    		if ( 5 > args.length ) {
019:    			// 入力した引数が5未満の場合、使用方法を表示する
020:    			System.out.println( 
021:    				"Pattern_Circle02 [PNG名] [画像幅] [画像高] [円半径] [線幅]" );
022:    			return;
023:    		}
024:    
025:    		try {
026:    			// 引数を変換し、画像の幅と高さをwとhに代入
027:    			w =  Integer.valueOf( args[ 1 ] );
028:    			h =  Integer.valueOf( args[ 2 ] );
029:    
030:    			// 引数を変換し、円の半径radiusに代入
031:    			radius = Integer.valueOf( args[ 3 ] );
032:    			if ( 1 > radius ) {
033:    				System.out.println( "円の半径に1以上を指定!" );
034:    				return;
035:    			}
036:    
037:    			// 引数を変換し、線幅line_wに代入
038:    			line_w = Integer.valueOf( args[ 4 ] );
039:    			if ( 1 > line_w ) {
040:    				System.out.println( "線幅に1以上を指定!" );
041:    				return;
042:    			}
043:    		}
044:    		catch( NumberFormatException ne )
045:    		{
046:    			System.out.println( "引数が不正です" );
047:    			return;
048:    		}
049:    		// 出力PNG名をoutnameに代入(拡張子".png"省略なし)
050:    		outname = args[ 0 ];
051:    
052:    		// 新規画像を作成
053:    		img = new BufferedImage( w, h, BufferedImage.TYPE_INT_RGB );
054:    		Graphics2D g = (Graphics2D)img.getGraphics();
055:    		g.setColor( Color.white );	// 背景色を白に設定
056:    		g.fillRect( 0, 0, w, h );	// 背景で画像全体を塗る
057:    
058:    		// 模様を作成
059:    		int x, y;
060:    		int row;
061:    		int start_x;
062:    		int pitch_x, pitch_y;
063:    
064:    		// xとyの間隔を代入
065:    		pitch_x = radius * 2;
066:    		pitch_y = (int)( (double)radius * Math.sqrt( 3.0 ) );
067:    
068:    		// 線の色を黒に設定
069:    		g.setColor( Color.black );
070:    		// 線幅をline_wに設定
071:    		g.setStroke( new BasicStroke( line_w ) );
072:    
073:    		// 円模様の描画
074:    		row = 0;
075:    		for ( y = 0; y <= ( h + radius ); y = y + pitch_y ) {
076:    			++ row;
077:    			if ( 1 == ( row % 2 ) )
078:    				start_x = 0;
079:    			else
080:    				start_x = -radius;
081:    			//
082:    			for ( x = start_x; x <= ( w + radius ); x = x + pitch_x ) {
083:    				g.drawOval( x - radius, y - radius, radius * 2, radius * 2 );
084:    			}
085:    		}
086:    
087:    
088:    		try {
089:    			// imgをoutname(出力PNG)に保存
090:    			boolean result;
091:    			result = ImageIO.write( img, "PNG", new File( outname ) );
092:    		} catch ( Exception e ) {
093:    			// outname(出力PNG)の保存に失敗したときの処理
094:    			e.printStackTrace();
095:    			return;
096:    		}
097:    
098:    		// 正常に終了
099:    		System.out.println( "正常に終了しました" );
100:    	}
101:    }

Pattern_Circle02の実行例

java Pattern_Circle02 circle02.png 256 256 32 4

ここからは、このJavaソースコードを上から順番に解説していきます。

001:    import java.awt.image.BufferedImage;
002:    import java.awt.Graphics2D;
003:    import java.awt.Color;
004:    import java.awt.BasicStroke;
005:    import java.io.File;
006:    import javax.imageio.ImageIO;

Javaのクラスライブラリの中から「java.awt.image.BufferedImage」と「java.awt.Graphics2D」と「java.awt.Color」と「java.awt.BasicStroke」と「java.io.File」と「javax.imageio.ImageIO」というパッケージにあるクラスを、このプログラム内で使うために記述します。

008:    public class Pattern_Circle02 {

クラス名を、Pattern_Circle02としています。

009:    	public static void main(String[] args) {

このmainメソッドからプログラムを実行します。

010:    		// 変数宣言
011:    		int w, h;			// 画像サイズ
012:    		int radius;			// 円の半径
013:    		int line_w;			// 線幅
014:    		String outname;			// 出力ファイル名
015:    		BufferedImage img = null;	// 画像格納クラス

このプログラムで使う変数を宣言しています。

017:    		// 入力した引数が5以上かを調べる
018:    		if ( 5 > args.length ) {
019:    			// 入力した引数が5未満の場合、使用方法を表示する
020:    			System.out.println( 
021:    				"Pattern_Circle02 [PNG名] [画像幅] [画像高] [円半径] [線幅]" );
022:    			return;
023:    		}

5つ以上の引数が与えられたかをチェックし、5つ未満の場合に、使い方のメッセージを表示し、returnによってmainメソッドを抜けています。

025:    		try {
026:    			// 引数を変換し、画像の幅と高さをwとhに代入
027:    			w =  Integer.valueOf( args[ 1 ] );
028:    			h =  Integer.valueOf( args[ 2 ] );
029:    
030:    			// 引数を変換し、円の半径radiusに代入
031:    			radius = Integer.valueOf( args[ 3 ] );
032:    			if ( 1 > radius ) {
033:    				System.out.println( "円の半径に1以上を指定!" );
034:    				return;
035:    			}
036:    
037:    			// 引数を変換し、線幅line_wに代入
038:    			line_w = Integer.valueOf( args[ 4 ] );
039:    			if ( 1 > line_w ) {
040:    				System.out.println( "線幅に1以上を指定!" );
041:    				return;
042:    			}
043:    		}
044:    		catch( NumberFormatException ne )
045:    		{
046:    			System.out.println( "引数が不正です" );
047:    			return;
048:    		}
049:    		// 出力PNG名をoutnameに代入(拡張子".png"省略なし)
050:    		outname = args[ 0 ];

与えられた引数をそれぞれ、作成する画像の幅/高さ、円ピクセル半径、ピクセル線幅、出力PNG名を格納する変数に代入しています。画像の幅/高さ、円ピクセル半径、ピクセル線幅の引数はString型なので、Integerクラスを使ってint型に変換しています。

053:    		img = new BufferedImage( w, h, BufferedImage.TYPE_INT_RGB );

BufferedImageクラスコンストラクタで、新しいBufferedImageを構築しています。

BufferedImageコンストラクタ

BufferedImage( int width, int height, int imageType )
■新しい BufferedImage を構築します。
  パラメータ width     : 構築する画像の横ピクセル
        height    : 構築する画像の縦ピクセル
        imageType : 構築する画像のイメージ形式

054:    		Graphics2D g = (Graphics2D)img.getGraphics();
055:    		g.setColor( Color.white );	// 背景色を白に設定
056:    		g.fillRect( 0, 0, w, h );	// 背景で画像全体を塗る

img.getGraphics()でグラフックスコンテキストを取得し、背景を白で塗り潰しています。

ここで、グラフックスコンテキストを取得するとは、作成したBufferedImage imgに対してライン/円/多角形などのグラフィック描画を行うためのGraphics2Dクラスを取得することです。ここで取得したGraphics2Dクラスgにグラフィック描画を行うとimgに反映されます。

BufferedImageクラスで作成した画像に、グラフィックを描画するための準備と考えるのが良いと思います。

058:    		// 模様を作成
059:    		int x, y;
060:    		int row;
061:    		int start_x;
062:    		int pitch_x, pitch_y;

模様を作成するための変数を宣言しています。

064:    		// xとyの間隔を代入
065:    		pitch_x = radius * 2;
066:    		pitch_y = (int)( (double)radius * Math.sqrt( 3.0 ) );

int型変数pitch_xには半径radisuを2倍した値、つまり直径の値を代入しています。変数pitch_yには半径radisuにルート3(3の平方根)を掛けた値を代入しています。

これらは、隣り合った円の中心座標のx方向、y方向のそれぞれの距離を表しています。

中心座標の位置の関係は、以下の図を参考にしてください。

円の中心座標の間隔
068:    		// 線の色を黒に設定
069:    		g.setColor( Color.black );

描画する円の色を黒に設定しています。

Graphics.setColorメソッド

public abstract void setColor( Color c )
■このグラフィックスコンテキストの現在の色を、指定された色に設定します。

  パラメータ c : 色

  戻り値     なし

070:    		// 線幅をline_wに設定
071:    		g.setStroke( new BasicStroke( line_w ) );

描画する円の線幅をint型変数line_wで指定した値に設定しています。

Graphics.setStrokeメソッド

public abstract void setStroke( Stroke s )
■このグラフィックスコンテキストのストロークを設定します。

  パラメータ s : ストローク

  戻り値     なし

073:    		// 円模様の描画
074:    		row = 0;
075:    		for ( y = 0; y <= ( h + radius ); y = y + pitch_y ) {

for文でyのループを作成しています。変数yには、yの増加分pitch_yを足していきます。変数rowは、円描画の行数を表すものです。

076:    			++ row;
077:    			if ( 1 == ( row % 2 ) )
078:    				start_x = 0;
079:    			else
080:    				start_x = -radius;

行を表す変数rowをインクリメントしていきます。変数rowが偶数奇数かを判定して、円描画の開始x座標を決めています。

偶数の場合、開始x座標start_xに0を代入、奇数の場合、開始x座標start_xに-radiusを代入しています。

081:    			//
082:    			for ( x = start_x; x <= ( w + radius ); x = x + pitch_x ) {
083:    				g.drawOval( x - radius, y - radius, radius * 2, radius * 2 );
084:    			}

for文でxのループを作成しています。変数xには、xの増加分pitch_xを足していきます。開始の値は、start_xです。

forの2重ループで得られたxとyを使い、座標(x,y)を中心とした半径radisuの円を描画していきます。

以下に、drawOvalの仕様を記載します。参考にしてください。

Graphics.drawOvalメソッド

public abstract void drawOval( int x, int y, int width, int height )
■楕円の輪郭線を描きます。

  パラメータ x      : 描画する楕円の左上隅のx座標
        y      : 描画する楕円の左上隅のy座標
        width  : 描画する楕円の幅
        height : 描画する楕円の高さ

  戻り値     なし

楕円の輪郭描画

中心座標を基準に円を描画するために、以下の計算を行います。

中心座標を基準に円を表示

088:    		try {
089:    			// imgをoutname(出力PNG)に保存
090:    			boolean result;
091:    			result = ImageIO.write( img, "PNG", new File( outname ) );
092:    		} catch ( Exception e ) {
093:    			// outname(出力PNG)の保存に失敗したときの処理
094:    			e.printStackTrace();
095:    			return;
096:    		}

BufferedImageクラスのimgのメモリ内のデータを、出力PNG名の変数(outname)に格納されているファイル名で保存します。この場合は、PNGファイル名が不正であったり、保存先のHDDなどが存在していなかったり、空き容量が少ないなどが原因で処理が失敗する可能性があります。

098:    		// 正常に終了
099:    		System.out.println( "正常に終了しました" );

全ての処理が正常終了すると、ここまで処理が実行されます。

■関連コンテンツ

模様の描画 いろいろな模様の描画方法を紹介

■新着情報

2019.06.24 同じ数の組み合わせ 同じ数の組み合わせ数の取得方法を解説
2019.06.21 円周率πを求める その1 円周率πを計算で求める その1
2019.06.18 同心円模様 同心円模様の画像作成方法を紹介
2019.06.17 円模様2 隙間が少ない円の整列画像の作り方を紹介
2019.06.14 円模様1 円の縦横整列模様の画像作成方法を紹介

■広告

法人向けのETC専用カード

~約8,000名の受講生と80社以上の導入実績~ 企業向けプログラミング研修ならCodeCamp

日本最大級ショッピングサイト!お買い物なら楽天市場

 

 

 

 

 

 

 

 

 

Topへ