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

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

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

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

Q&A

解決済

1回答

1547閲覧

[Win32API] 回転した楕円のリージョンを取得するには?

hiro-ta

総合スコア14

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

0グッド

0クリップ

投稿2019/07/09 09:17

編集2019/07/10 00:41

回転した楕円のリージョンを取得するにはどうすればいいでしょうか?
楕円の4隅(左上、右上、左下、右下)の座標は分かっています。

回転していなければCreateEllipticRgnで一発なのですが・・・。

PtInRegion(指定した座標がリージョンに含まれるか調べる)とInvalidateRgn(リージョンの再描画)が目的です。
InvalidateRgnのほうは厳密にやらないなら別のやり方があるので、PtInRegionをなんとかできればと思っています。

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

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

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

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

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

yoorwm

2019/07/09 09:24

楕円をどこで回転させるのか分かりませんが、回転させる中心と一番遠い点の円になりませんか?
hiro-ta

2019/07/09 09:36

円の中心で回転させます。
atata0319

2019/07/09 17:56

リージョンをどのように使用するかがわからないと回答が難しいです。汎用的な方法があるにはあるのですが、この質問をしてきている時点でサンプルコードなしに理解できるとは思えません。
hiro-ta

2019/07/10 00:06

PtInRegion(指定した座標がリージョンに含まれるか調べる)とInvalidateRgn(リージョンの再描画)が目的です。 InvalidateRgnのほうは厳密にやらないなら別のやり方があるので、PtInRegionをなんとかできればと思っています。
guest

回答1

0

ベストアンサー

単に点とリージョンの当たり判定を取るのであれば、「リージョンを回転させる」より「点を逆回転させる」方が求めやすいと思います。
更に言えば、リージョンを使わなくても判定できます。

cpp

1// 思いつきで書いたので、動作は不定 2bool point_in_rotated_ellipse(const RECT &rect, double rad, const POINT &pt) 3{ 4 // 楕円のサイズ 5 int width = rect.right - rect.left; 6 int height = rect.bottom - rect.top; 7 // 楕円の中心座標 8 int cx = rect.left + width / 2; 9 int cy = rect.top + height / 2; 10 11 // 中心座標→点のベクトル 12 int dx = pt.x - cx; 13 int dy = pt.y - cy; 14 15 // ベクトルを逆回転させる。 16 double x = dx * std::cos(-rad) - dy * std::sin(-rad); 17 double y = dx * std::sin(-rad) + dy * std::cos(-rad); 18 19 // PtInRegionを使うのであれば、ここで(cx+x, cy+y)の座標とチェックする。 20 21 // 楕円ではなく円で判定させるために、横を縦のサイズにあわせる。 22 x *= static_cast<double>(width) / height; 23 24 // 円の中に点があれば、ヒット 25 return (x * x + y * y <= height / 2.0 * height / 2.0); 26}

一応、回転した楕円のリージョンの作り方も書いておきます。

質問に書かれているとおり一発ではできないので、複雑なリージョンを作成できるExtCreateRegion関数を使います。

第一引数にマトリクスっぽいものが指定できるので、回転はそちらで指定します。

cpp

1// リージョン作成に使う構造体 2typedef struct RegionData { 3 RGNDATAHEADER rdh; 4 RECT rect[1]; 5 } RegionData; 6 7// こちらは、一応FillRgnを呼んで描画して確認してみた。 8HRGN create_ellipse_region(const RECT &rect, double angle) 9{ 10 // 回転していない楕円を、高さ1ドットの矩形を並べて作成 11 // もしかすると、CreateEllipticRgnで楕円リージョンを作って、GetRegionDataでリージョンデータを取ってきてもいいかもしれない。 12 int width = rect.right - rect.left; 13 int height = rect.bottom - rect.top; 14 size_t size = sizeof(RegionData) + sizeof(RECT) * (height - 1); 15 RegionData *rgn_data = reinterpret_cast<RegionData *>(std::malloc(size)); 16 rgn_data->rdh.dwSize = sizeof(rgn_data->rdh); 17 rgn_data->rdh.iType = RDH_RECTANGLES; 18 rgn_data->rdh.nCount = height; 19 rgn_data->rdh.nRgnSize = 0; 20 rgn_data->rdh.rcBound = rect; 21 for (int i = 0; i < height; ++i) { 22 rgn_data->rect[i].top = rect.top + i; 23 rgn_data->rect[i].bottom = rgn_data->rect[i].top + 1; 24 int x = static_cast<int>(std::abs(static_cast<double>(width) / 2.0 * std::cos(std::asin(1.0f - 2.0f * i / height)))); 25 rgn_data->rect[i].left = rect.left + width / 2 - x; 26 rgn_data->rect[i].right = rect.left + width / 2 + x; 27 } 28 29 // マトリクスを作成 30 XFORM xform; 31 { 32 double cx = static_cast<double>(rect.left + width / 2); 33 double cy = static_cast<double>(rect.top + height / 2); 34 double c = std::cos(angle); 35 double s = std::sin(angle); 36 // eMnnは回転要素 37 // https://ja.wikipedia.org/wiki/%E5%9B%9E%E8%BB%A2%E8%A1%8C%E5%88%97 38 xform.eM11 = static_cast<float>(c); 39 xform.eM12 = static_cast<float>(s); 40 xform.eM21 = static_cast<float>(-s); 41 xform.eM22 = static_cast<float>(c); 42 // eDnは平行移動要素 43 // 楕円の中心で回転するように、一旦中心座標に移動して、回転後の原点に戻す。 44 xform.eDx = cx - (cx * c - cy * s); 45 xform.eDy = cy - (cy * c + cx * s); 46 } 47 48 HRGN h = ExtCreateRegion(&xform, size, reinterpret_cast<RGNDATA *>(rgn_data)); 49 if (h == NULL) { 50 std::fprintf(stderr, "%s(%d): failed to create region.\n", __FILE__, __LINE__); 51 std::fflush(stderr); 52 } 53 std::free(rgn_data); 54 return h; 55}

投稿2019/07/10 11:23

編集2019/07/10 11:33
katsuko

総合スコア3471

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

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

hiro-ta

2019/07/11 10:35

ありがとうございます! create_ellipse_regionでバッチリうまくいきました。 丁寧なサンプルコードをつけていただきありがとうございました。本当に助かりました。 #リージョン作成部分はGetRegionDataで大丈夫でした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問