Javaで行列を回転させる

管理人のタツです。

何の機会だったか忘れましたが、
行列を回転させる処理をJavaで作らなければいけなかった時がありました。

自分なりに作ってみたメソッドがありますので、ご紹介します。

ソース

さっそく、ソースは以下です。

/**
 * @fn      bMatrixAroundRotate
 * @brief	行列(2次元配列)の回転を行う
 * @param	int[][] iArray    回転元行列
 *          int[][] iArrayRtn  回転後格納配列
 *          int 	iRotateCnt 回転数
 * @return	boolean     true  : 計算成功
 *                      false : 計算失敗
 * @detail  正方行列以外は回転できない
 */
static boolean bMatrixAroundRotate(int[][] iArray, int[][] iArrayRtn, int iRotateCnt)
{
	boolean bRtn = true;
	
	//当然、元の行列と答えの行列の行数、列数は一致しないとダメ
	int iLengthRowOrigin = iArray.length;	//回転前の行列行数
	int iLengthRow = iArrayRtn.length;		//回転後の行列行数
	if(iLengthRowOrigin != iLengthRow)
		return false;
	
	int iLengthColOrigin = iArray[0].length;	//回転前の行列列数
	for(int i = 1; i < iLengthRow; i++)
	{
		int iLength = iArray[i].length;
		if(iLengthColOrigin != iLength)
			return false;  //長方行列じゃないときはreturn
	}
	int iLengthCol = iArrayRtn[0].length;		//回転後の行列列数
	for(int i = 1; i < iLengthRow; i++)
	{
	int iLength = iArrayRtn[i].length;
		if(iLengthCol != iLength)
			return false;  //長方行列じゃないときはreturn
	}
	
	if(iLengthColOrigin != iLengthRow || iLengthCol != iLengthRow)
		return false;   //正方行列じゃない
	
	//回転処理開始
	
	//内側を埋める(内側は変化なし)
	int iLength = iLengthRow;
	for(int i = 1; i < iLength - 1; i++)
	{
		for(int j = 1; j < iLength; j++)
		{
			iArrayRtn[i][j] = iArray[i][j];
		}
	}
	
	
	int iRotate = iRotateCnt % 4;
	
	//一番上の行
	for(int i = 0; i < iLength; i++)
	{
		int iTemp = 0;
		switch(iRotate)
		{
		case 0: //回転なし
			iTemp = iArray[0][i];
			break;
		case 1:  //正の方向へ1回転→iArrayの再右列がiArrayRtnの最上行へ
		case -3: //負の方向へ3回転→iArrayの再右列がiArrayRtnの最上行へ
			iTemp = iArray[i][iLength - 1];
			break;
		case 2:  //正の方向へ2回転→iArrayの再下行がiArrayRtnの最上行へ
		case -2: //負の方向へ2回転→iArrayの再下行がiArrayRtnの最上行へ
			iTemp = iArray[iLength - 1][iLength - 1 - i];
			break;
		case 3:  //正の方向へ3回転→iArrayの再左列がiArrayRtnの最上行へ
		case -1: //負の方向へ1回転→iArrayの再左列がiArrayRtnの最上行へ	
			iTemp = iArray[iLength - 1 - i][0];
			break;
		default:
				break;
		}
		iArrayRtn[0][i] = iTemp;
	}
	
	//一番左の列
	for(int i = 0; i < iLength; i++)
	{
		int iTemp = 0;
		switch(iRotate)
		{
		case 0: //回転なし
			iTemp = iArray[i][0];
			break;
		case 1:  //正の方向へ1回転→iArrayの再上行がiArrayRtnの最左列へ
		case -3: //負の方向へ3回転→iArrayの再上行がiArrayRtnの最左列へ
			iTemp = iArray[0][iLength - 1 -i];
			break;
		case 2:  //正の方向へ2回転→iArrayの再右列がiArrayRtnの最左列へ
		case -2: //負の方向へ2回転→iArrayの再右列がiArrayRtnの最左列へ
			iTemp = iArray[iLength - 1 - i][iLength - 1];
			break;
		case 3:  //正の方向へ3回転→iArrayの再下行がiArrayRtnの最左列へ
		case -1: //負の方向へ1回転→iArrayの再下行がiArrayRtnの最左列へ	
			iTemp = iArray[iLength - 1][i];
			break;
		default:
				break;
		}
		iArrayRtn[i][0] = iTemp;
	}
	
	//一番下の行
	for(int i = 0; i < iLength; i++)
	{
		int iTemp = 0;
		switch(iRotate)
		{
		case 0: //回転なし
			iTemp = iArray[iLength - 1][i];
			break;
		case 1:  //正の方向へ1回転→iArrayの再左列がiArrayRtnの最下行へ
		case -3: //負の方向へ3回転→iArrayの再左列がiArrayRtnの最下行へ
			iTemp = iArray[i][0];
			break;
		case 2:  //正の方向へ2回転→iArrayの再上行がiArrayRtnの最下行へ
		case -2: //負の方向へ2回転→iArrayの再上行がiArrayRtnの最下行へ
			iTemp = iArray[0][iLength - 1 - i];
			break;
		case 3:  //正の方向へ3回転→iArrayの再右列がiArrayRtnの最下行へ
		case -1: //負の方向へ1回転→iArrayの再右列がiArrayRtnの最下行へ	
			iTemp = iArray[iLength - 1 - i][iLength - 1];
			break;
		default:
				break;
		}
		iArrayRtn[iLength - 1][i] = iTemp;
	}
	
	//一番右の列
	for(int i = 0; i < iLength; i++)
	{
		int iTemp = 0;
		switch(iRotate)
		{
		case 0: //回転なし
			iTemp = iArray[i][iLength - 1];
			break;
		case 1:  //正の方向へ1回転→iArrayの再下行がiArrayRtnの最右列へ
		case -3: //負の方向へ3回転→iArrayの再下行がiArrayRtnの最右列へ
			iTemp = iArray[iLength - 1][iLength - 1 - i];
			break;
		case 2:  //正の方向へ2回転→iArrayの再左列がiArrayRtnの最右列へ
		case -2: //負の方向へ2回転→iArrayの再左列がiArrayRtnの最右列へ
			iTemp = iArray[iLength - 1 - i][0];
			break;
		case 3:  //正の方向へ3回転→iArrayの再上行がiArrayRtnの最右列へ
		case -1: //負の方向へ1回転→iArrayの再上行がiArrayRtnの最右列へ	
			iTemp = iArray[0][i];
			break;
		default:
				break;
		}
		iArrayRtn[i][iLength - 1] = iTemp;
	}
	
	return bRtn;
}

解説

引数の1つ目は回転元行列、2つ目は回転させた行列を格納させます。
3つ目のint型は何回転させるかです。
左回転を正とします。

37行目までは、そもそも回転できる行列(すなわち正方行列)かの判定をし、
回転不能であればfalseを返してます。

  • L16~L19 : 引数二つの行数が等しいか判定
  • L21~L27 : 回転元が長方行列か判定
  • L28~L34 : 回転格納行列が長方行列か判定
  • L36~L37 : 回転元行列の列と回転格納行列の行、回転元行列の行と回転格納行列の列が等しくないということは、正方行列ではないのでfalseリターン

L42~L49では、内側は回転対象ではないので、先に埋めておきます。

52行目で、回転数を4で割ります。
4回転と0回転は同じなので。

後は外側をそれぞれ埋めていきます。
回転数によって、回転元のどの行・どの列を取ってくるか、注意します。

  • L55~L79 : 回転格納の0行目を埋めます
  • L82~L105 : 回転格納の0列目を埋めます
  • L109~L133 : 回転格納の最後の行を埋めます
  • L136~L160 : 回転格納の最後の列を埋めます

実行結果

main関数内を以下のように記述しました。

public static void main(String[] args)
	{
		int[][] iArray1 = {{1, 2, 3,4}, {5, 6, 7, 8}, {9, 10, 11, 12},{13, 14, 15, 16}};
		int[][] iArray2 = new int[4][4];
		
		for(int i = 0; i < 5; i++)
		{
			if(bMatrixAroundRotate(iArray1, iArray2, i))
			{
				Disp(iArray1);
				Disp();
				Disp("↓↓" + i + "回転後");
				Disp();
				Disp(iArray2);
			}
			
			Disp();
			Disp();	
		}
	}

0~4回転させてます。
Dispメソッドについては以前作ったものです。
自分で言うのもですが、結構便利でよく使ってます。

今回は正方行列は確定してるので、
8行目の条件は必ずtrueが返ってきます。

コンソールには以下が表示されました。

一応、自分が期待する応えが出てきました。

今回はここまでです。

コメント

タイトルとURLをコピーしました