質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

3回答

1238閲覧

任意点における回転行列と座標

退会済みユーザー

退会済みユーザー

総合スコア0

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2017/06/29 09:15

編集2017/06/29 09:22

###実現したいこと
height*widthの長方形の任意の座標を
「長方形の中心」を中心にして回転行列によって90°回転させた後の座標を表示させたいです。

###発生している問題
この数値を配列のインデクスとして利用するため、x, yともに0~9の値が重複なしで出てほしいです。
どのようにすれば改善できますか。

C++

1neutral_y is -0 //「0」とでてほしい 2neutral_x is 10 //「9」とでてほしい 3 4neutral_y is 0 //「1」とでてほしい 5neutral_x is 10 6 7neutral_y is 1 8neutral_x is 10 9 10neutral_y is 2 11neutral_x is 10 12 13neutral_y is 3 14neutral_x is 10 15 16neutral_y is 4 17neutral_x is 10 18 19neutral_y is 5 20neutral_x is 10 21 22neutral_y is 6 23neutral_x is 10 24 25neutral_y is 7 26neutral_x is 10 27 28neutral_y is 9 29neutral_x is 10

###該当のソースコード

C++

1void neutral_coor(int rot_num, int x, int y){ //(90°回転を何回するか, 回転したいx座標, y座標) 2 double degree = rot_num*90*(M_PI / 180); //弧度からラジアンへ 3 double O_x = width*0.5; //xの回転中心 4 double O_y = height*0.5; //yの回転中心 5 double neutral_x = x*cos(degree) - y*sin(degree) + O_x*(1-cos(degree)) + O_y*sin(degree); //回転後のx 6 double neutral_y = x*sin(degree) + y*cos(degree) - O_x*sin(degree) + O_y*(1-cos(degree)); //回転後のy 7 cout << "neutral_y is " << int(neutral_y) << endl; 8 cout << "neutral_x is " << int(neutral_x) << endl; 9 cout << endl; 10} 11 12int main(void){ 13 for (int x = 0; x < width; x++){ 14 neutral_coor(1, x, 0); 15 } 16}

###補足
任意点における回転行列は以下のサイトを参考にしました
http://imagingsolution.blog107.fc2.com/blog-entry-111.html

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

こんにちは。

widthとheightはたぶん10ですね?
中心が(width0.5, height0.5)のようですから、(5.0, 5.0)が中心ですね?
すると、原点はこの四角形の1つの角なので90度回転すると、(0, 10)になるでしょう。
従って、10を9にするのは元の四角形を歪ませることになるのではないでしょうか?
どうしても10が困るのであれば、四角形のサイズを 9.0 x 9.0にする、もしくは、四角形の境界線上の点(例えば(0.0, 0.0))は四角形の「外」と定義するしかないと思います。

次にint型に -0 は存在しないのが一般的です。そのプログラムでneutral_y is -0と表示されるとしたら、かなり珍しい処理系です。どのコンパイラをお使いでしょうか?

次のように記述すれば恐らく先頭は0, 次は1, 2, 3, ...になると思います。

cout << "neutral_y is " << static_cast<int>(round(neutral_y)) << endl;

cout << "neutral_x is " << static_cast<int>(round(neutral_x)) << endl;

double型演算は微細な誤差がでますから、例えば0.99999...を直接int型へ変換すると0になります。
一旦四捨五入してから、int型へ変換すれば多くの場合、意図通りに変換されます。

投稿2017/06/29 10:03

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

sinやcos関数によって座標計算をするとどうしても誤差が出てしまいます。というのもこの関数の引数や結果は有理数とは限らないので計算機で正確な演算をすることは基本的に期待できません。

しかしながら90度(=π/2)に限定した回転ならば正確な演算結果とすることはできます。なぜなら数学的にπ/2の整数倍のsinやcosは-1,0,1のいずれかの値しかとらないからです。sinやcos関数を用いて誤差のある演算をするかわりに数学的定義に従い-1,0,1のいずれかの値を直接用いるようにすればよいのです。

角度sincos
001
1/2 π10
π0-1
3/2 π-10
.........

追記:直角限定でのsinとcosの定義をよりはっきりさせる意味合いで、ご質問のコード中にあるrot_numを用いた関数の定義例を挙げておきます。ネーミングは直角のことをright angleというらしいのでra_sin, ra_cosとしてみました。

C

1static int ra_sine_table[] = { 0, 1, 0, -1 }; 2 3int ra_sin(int rot_num) { 4 rot_num %= 4; 5 // 負の数の場合の配慮 6 rot_num = (rot_num + 4) % 4; 7 return ra_sine_table[rot_num]; 8} 9 10int ra_cos(int rot_num) { 11 return ra_sin(rot_num + 1); 12}

投稿2017/06/29 09:29

編集2017/06/29 10:41
KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KSwordOfHaste

2017/06/29 10:45

ご質問の問題の原因とは少々はずれた話をしてしまったようです。 Chironianさんやyubaさんの回答の方を参照ください。失礼しました!
guest

0

ベストアンサー

中心点の算出の仕方が意図と異なる結果が出る原因です。
10 * 0.5 で 5.0 を中心座標としてしまっていますが、「0と9を端とする範囲の中心」ですよね。そしたら 4.5 でなければいけません。
この質問に限らず、矩形を扱う際には植木算がとにかくややこしいので、2×2みたいな小さな矩形に置き換えて考えてみるなどしてみてください。

このことは別の問題も含んでいます。質問文内の例では縦も横も辺の長さが10だからいいのですが、
widthとheightの組み合わせが偶数vs奇数だった場合、中心点はどうなるでしょう?
90°回転の結果の座業が、必ず整数ではなくなってしまうことに気付くと思います。その場合どんな結果を望むのか、決めてあるでしょうか。

投稿2017/06/29 10:38

yuba

総合スコア5568

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問