2019.06.17

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

はじめに

ここでは、できるだけ隙間がなくなるようにを並べて出来る模様の画像を作成する方法を紹介します。

プログラムで出力する画像の形式PNGファイルです。

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

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

Javaソースコード

Pattern_Circle02.java

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
import java.awt.image.BufferedImage;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.BasicStroke;
import java.io.File;
import javax.imageio.ImageIO;

public class Pattern_Circle02 {
	public static void main(String[] args) {
		// 変数宣言
		int w, h;			// 画像サイズ
		int radius;			// 円の半径
		int line_w;			// 線幅
		String outname;			// 出力ファイル名
		BufferedImage img = null;	// 画像格納クラス

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

		try {
			// 引数を変換し、画像の幅と高さをwとhに代入
			w =  Integer.valueOf( args[ 1 ] );
			h =  Integer.valueOf( args[ 2 ] );

			// 引数を変換し、円の半径radiusに代入
			radius = Integer.valueOf( args[ 3 ] );
			if ( 1 > radius ) {
				System.out.println( "円の半径に1以上を指定!" );
				return;
			}

			// 引数を変換し、線幅line_wに代入
			line_w = Integer.valueOf( args[ 4 ] );
			if ( 1 > line_w ) {
				System.out.println( "線幅に1以上を指定!" );
				return;
			}
		}
		catch( NumberFormatException ne )
		{
			System.out.println( "引数が不正です" );
			return;
		}
		// 出力PNG名をoutnameに代入(拡張子".png"省略なし)
		outname = args[ 0 ];

		// 新規画像を作成
		img = new BufferedImage( w, h, BufferedImage.TYPE_INT_RGB );
		Graphics2D g = (Graphics2D)img.getGraphics();
		g.setColor( Color.white );	// 背景色を白に設定
		g.fillRect( 0, 0, w, h );	// 背景で画像全体を塗る

		// 模様を作成
		int x, y;
		int row;
		int start_x;
		int pitch_x, pitch_y;

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

		// 線の色を黒に設定
		g.setColor( Color.black );
		// 線幅をline_wに設定
		g.setStroke( new BasicStroke( line_w ) );

		// 円模様の描画
		row = 0;
		for ( y = 0; y <= ( h + radius ); y = y + pitch_y ) {
			++ row;
			if ( 1 == ( row % 2 ) )
				start_x = 0;
			else
				start_x = -radius;
//			
			for ( x = start_x; x <= ( w + radius ); x = x + pitch_x ) {
				g.drawOval( x - radius, y - radius, radius * 2, radius * 2 );
			}
		}


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

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

コンパイル ソースコードが「ANSI」の場合

C:\talavax\javasample>javac -encoding sjis Pattern_Circle02.java

コンパイル ソースコードが「UTF-8」の場合

C:\talavax\javasample>javac Pattern_Circle02.java

実行

C:\talavax\javasample>java Pattern_Circle02 circle02.png 256 256 32 4

Javaソースコードの解説

001
002
003
004
005
006
import java.awt.image.BufferedImage;
import java.awt.Graphics2D;
import java.awt.Color;
import java.awt.BasicStroke;
import java.io.File;
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
012
013
014
015
		// 変数宣言
		int w, h;			// 画像サイズ
		int radius;			// 円の半径
		int line_w;			// 線幅
		String outname;			// 出力ファイル名
		BufferedImage img = null;	// 画像格納クラス

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

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

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

025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
		try {
			// 引数を変換し、画像の幅と高さをwとhに代入
			w =  Integer.valueOf( args[ 1 ] );
			h =  Integer.valueOf( args[ 2 ] );

			// 引数を変換し、円の半径radiusに代入
			radius = Integer.valueOf( args[ 3 ] );
			if ( 1 > radius ) {
				System.out.println( "円の半径に1以上を指定!" );
				return;
			}

			// 引数を変換し、線幅line_wに代入
			line_w = Integer.valueOf( args[ 4 ] );
			if ( 1 > line_w ) {
				System.out.println( "線幅に1以上を指定!" );
				return;
			}
		}
		catch( NumberFormatException ne )
		{
			System.out.println( "引数が不正です" );
			return;
		}
		// 出力PNG名をoutnameに代入(拡張子".png"省略なし)
		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
055
056
		Graphics2D g = (Graphics2D)img.getGraphics();
		g.setColor( Color.white );	// 背景色を白に設定
		g.fillRect( 0, 0, w, h );	// 背景で画像全体を塗る

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

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

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

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

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

064
065
066
		// xとyの間隔を代入
		pitch_x = radius * 2;
		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
071
		// 線幅をline_wに設定
		g.setStroke( new BasicStroke( line_w ) );

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

Graphics.setStrokeメソッド

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

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

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

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

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

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

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

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

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

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

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

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

以上です。

関連コンテンツ

いろいろな模様(パターン)を描画する方法を紹介します。

2019.02.25

一般に使われている画像フォーマットには、いろいろな種類があります。画像フォーマットBMP、JPEG、PNG、GIF、TIFFの特徴を知ってますか?

2015.11.29

テキストで塗りつぶし円を表現する方法を紹介します。興味のある方は是非ご覧ください。

2020.06.03

処理を繰り返すために使用するfor文について解説しています。

2020.03.23

割り算で割り切れずに残った端数を剰余(余り)といいます。この剰余の計算をJavaのソースコードを使って解説しています。

2020.03.23

Javaのmainメソッドで受け取るパラメータについて解説しています。

2017.09.26

mainメソッドで受け取るパラメータの数の取得の仕方について解説しています。

2019.05.14

条件式を判断して処理を分岐する方法を詳しく説明しています。

2023.03.20

変数やクラスに格納されている値をコンソール出力する方法は?

2020.03.23

メソッドを抜けるときに使用するreturn文について説明しています。

2020.03.20

プログラムの最初に実行されるメソッドは?

2022.12.13

プログラミングで使う変数って何?

2020.03.23

Javaのプログラムを書いてみませんか?プログラムの書き方をくわしく説明しています。

2020.03.23

「Javaソースコード」から実行可能な「オブジェクトコード」に変換する方法をくわしく説明しています。

2020.03.23

Javaのプログラムを作ってみませんか?プログラミングに必要なものの用意から実行までを説明しています。

2020.03.23

Javaの学習に役立つソースコードを多数紹介しています。是非、ご覧ください。

2022.09.10

Swingパッケージを使ってグラフィック表示を行う方法を解説しています。

2020.03.23

画像フォーマット形式・色・大きさ・傾きなどの変更、特定の図形(文字・記号など)を見つけたり、取り出したりする画像処理について詳しく解説。

2015.11.29

繰り返し処理を使ったJavaのソースコードサンプルを紹介しています。

2020.03.23

配列を使うJavaソースコードを多数紹介しています。

2021.05.18

数学に関係するJavaのメソッドやソースコードなどを紹介しています。

2022.10.25

三角形、台形、円などいろいろな図形の面積を計算するプログラムを紹介しています。詳しくは、記事をご覧ください。

2021.05.18

StringクラスとStringBuilderクラスを利用したプログラミングの仕方を紹介しています。

2016.12.16

Javaを使った簡単な応用プログラム(生年月日から年齢を計算プログラムなど)を紹介しています。

2022.07.07

プログラミング、ITに関する用語をまとめています。

2022.10.17

日本で使われてきた伝統文様「和柄」について解説しています。

2022.07.27

画像って何?

2022.07.25

デジタル画像データを構成している要素について解説しています。

2015.12.22

円の直径と半径について図を使って詳しく解説しています。

2020.03.23

プログラミング言語とは?種類や特徴について説明しています。

2022.08.03

Javaプログラムの構成について解説しています。詳しくは、こちらをご覧ください。

2020.03.23

メソッドの定義方法を詳しく解説しています。Javaのサンプルソースコードを使った説明もあります。

2020.03.23

Integerクラスについて、ソースコードを使って詳しく説明しています。

2020.03.23

平方根の意味と、Math.sqrtメソッドの使い方をソースコードを使って詳しく解説しています。

2020.03.23

平面上の位置を表す座標系の1つXY座標系について詳しく解説。

2020.03.23

2つの座標(x1,y1)と(x2,y2)の直線距離を求める計算式は?

2020.03.23

for文で変数名iがよく使われる理由について説明しています。興味のある方は是非。

2022.08.29

繰り返し処理の作り方を解説しています。

2016.03.02

偶数・奇数を判定する方法を詳しく説明しています。興味のある方は、ご覧ください。

2015.11.17

整数型の変数に1を足すインクリメント、1つ引くデクリメントについて詳しく説明しています。

2020.03.23

for文などのループ中に、さらにループがある多重ループについて解説しています。

2021.02.09

コンピュータに保存されたファイルを特定するための名前がファイル名です。その付け方は?

2016.11.23

コンピュータは、いくつかの装置から構成されています。その主な5つの装置(機能)って何?

2022.07.10

データを記憶する部品のことで、ハードディスク、ハードディスクドライブと呼ばれます。電源の供給がなくてもデータが消えない記憶装置です。

2022.07.14

「ゆるゆるプログラム」のコンテンツを紹介しています。興味のある方はこの記事をご覧ください。

2020.03.23

広告