• ベストアンサー

斜め長方形の変形

幾何はさっぱりでして。 斜めの長方形(ABCD)があります。 C点をC'点に任意移動させた時、長方形の形を保ったままで(AB'C'D')を描画したいのです。 新しいB'、C'の座標点を求めるプログラム記述はどのようになるでしょうか? CADのラバーバンドでの使用になるので、できれば少し高速なものを。 使用言語はDelphiですが、BasicでもCでもかまいません。 ヒントだけでも。よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • ki073
  • ベストアンサー率77% (491/634)
回答No.3

サンプルプログラムが出来てしまったので、書いておきます。 Rubyで書いていますが、Rubyが分からない人でもなるべく分かりやすく書いているつもりです。 3行3列の行列のかけ算がいたるところで使われています。速度的にそんなに遅くないと思いますが、行列計算を普通の計算に展開すると多少は速くなるかもしれませんが。 No.1でリンクしたアフィン変換をそのまま使っています。 require "matrix" ax=1.0; ay=2.0 bx=3.0; by=1.0 a0=Matrix.column_vector([ax, ay, 1.0]) # 列ベクトルに b0=Matrix.column_vector([bx, by, 1.0]) af1=Matrix[[1.0, 0.0, -ax], [0.0, 1.0, -ay], [0.0, 0.0, 1.0]] # Aを原点に移動 b1=af1*b0 angle=Math.atan2(b1[1, 0], b1[0, 0]) cosAB=Math.cos(angle); sinAB=Math.sin(angle) af2=Matrix[[cosAB, sinAB, 0.0], [-sinAB, cosAB, 0.0], [0.0, 0.0, 1.0]] # ABがX軸上になるよう回転 af3=Matrix[[cosAB, -sinAB, 0.0], [sinAB, cosAB, 0.0], [0.0, 0.0, 1.0]] # af2の逆回転 af4=Matrix[[1.0, 0.0, ax], [0.0, 1.0, ay], [0.0, 0.0, 1.0]] # af1の逆移動 af12=af2*af1 # af1の操作の後af2の操作をする変換行列 af34=af4*af3 # af3の操作の後af4の操作をする変換行列 cx=5.0; cy=-2.0 # C'座標 c0=Matrix.column_vector([cx, cy, 1.0]) c2=af12*c0 bd2=Matrix.column_vector([c2[0,0], 0.0, 1.0]) # 移動回転後のB' dd2=Matrix.column_vector([0.0, c2[1,0], 1.0]) # 移動回転後のD' bd0=af34*bd2 # 元の位置に戻す dd0=af34*dd2 p [bd0[0, 0], bd0[1, 0]] # B'の座標を表示 p [dd0[0, 0], dd0[1, 0]] # D'の座標を表示

situmonnsya
質問者

お礼

サンプルソースまで書いて頂き恐縮です。 参考にしてDelphiに書直しました。(私にとっては難しかったです) A点(x1,y1) B点(x2,y2) C点(x3,y3) D点(x4,y4) //.....線分ABの傾き ang :=ArcTan2((y1-y2),(x1-x2)); //.....A点を中心に角度angだけC点を回転した結果のX座標値,X座標値 x0:=x1 + (x3-x1)*Cos(-ang) - (y3-y1)*Sin(-ang);  y0:=y1 + (x3-x1)*Sin(-ang) + (y3-y1)*Cos(-ang); //角度angで逆回転し新しいB点とD点に代入 x2:=x1 + (x0-x1)*Cos(ang); //.....x2:=x1 + (x0-x1)*Cos(ang) - (y1-y1)*Sin(ang); y2:=y1 + (x0-x1)*Sin(ang); //.....y2:=y1 + (x0-x1)*Sin(ang) + (y1-y1)*Cos(ang); x4:=x1 - (y0-y1)*Sin(ang); //.....x4:=x1 + (x1-x1)*Cos(ang) - (y0-y1)*Sin(ang); y4:=y1 + (y0-y1)*Cos(ang); //.....y4:=y1 + (x1-x1)*Sin(ang) + (y0-y1)*Cos(ang); 2行2列(?)の行列で計算しました。 検証した実際の変数名をわかりやすく変えたのですが、これで間違いないかと思います。 >難しく考えずに次のようにすれば求まります。 考えすぎてました。 Ruby,いいですね。パール(誕生石6月)とルビー(誕生石7月)の関係なんですね。 機会をみて勉強してみます。

その他の回答 (2)

  • ki073
  • ベストアンサー率77% (491/634)
回答No.2

No.1です。 まずAが原点になるように移動してから回転します。その方が楽だと思います。 必要があればサンプルプログラムを書き込みますので、お礼欄にでもその旨書き込んでください。

  • ki073
  • ベストアンサー率77% (491/634)
回答No.1

難しく考えずに次のようにすれば求まります。 1) Aが原点になるように図形の点を平行移動させる 2) 次にBがX軸上にくるように回転させる 3) 以上の操作で移動したC'のXとY座標を求めB''とC''とする(移動したB'とD'と同じ点、各軸上に移動している) 4) B''とD''を2)と逆方向に回転する 5) さらに1) の逆方向に移動させる B''とD''の座標がB’とD'になります。 以上の操作で全部の点がもとの位置に戻っているはずです。 移動、回転はアフィン変換行列を使えば簡単にできます。 http://imagingsolution.blog107.fc2.com/blog-entry-284.html ここで、1)と2)の変換行列はAとBの点が分かれば求まり、4)と5)も求まります。つまり、C'の点とは無関係に変換行列が求まります。 また1)と2)の積、3)と4)の積をあらかじめ計算できますので、比較的高速に計算できます。 分からないところがありましたら、書き込んでください。

situmonnsya
質問者

お礼

何回読返しても、理解できませんでしたがヒントを得ました。 X軸からみた線ABの角度(K度)だけ、A点を原点にC'点を逆回転(-K度)。(C'は点T1に) その時のT1のX座標点TX(Y=0)とY座標点TY(X=0)を更に逆回転(K度)して元に戻す。 これでいかがでしょうか? 明日プログラムを書き検証してみます。

situmonnsya
質問者

補足

質問の訂正 >長方形の形を保ったままで 各点の角度は90度で、隣合う辺の長さは任意。(相似形ではない) >新しいB'、C'の座標点を 新しいB'、D'の座標点を