n角形の図形を三角形の集合にわける方法
- MoNoQLoREATOR
- 記事: 284
- 登録日時: 13年前
- 住所: 東京
n角形の図形を三角形の集合にわける方法
私は現在、点と面の当たり判定について考えています。
三角形の中に点が含まれているか否かの判定方法は思いつきました。
だから、n角形の図形の中に点が含まれているか否かを判定するには、それを三角形の集合に分けることができれば可能だろうと考えました。
しかし、その方法が考えつきません。
具体的な状況を説明します。
ここに頂点情報(x,y)がn個格納されたvector配列があります。(ベクターでなくても構わないのですが)
格納されている順番に点を繋げて出来上がった図形について考えます。
ただし最後の要素が示す頂点は最初の要素が示す頂点につながります。
また、その図形の各線分同士は交差していないものとします。
このとき、ある点(x,y)がその図形の内部に存在しているかどうかを判定したいのです。
判定することさえできれば、三角形に分ける必要はもちろんございません。
ご教授よろしくお願い致します。
三角形の中に点が含まれているか否かの判定方法は思いつきました。
だから、n角形の図形の中に点が含まれているか否かを判定するには、それを三角形の集合に分けることができれば可能だろうと考えました。
しかし、その方法が考えつきません。
具体的な状況を説明します。
ここに頂点情報(x,y)がn個格納されたvector配列があります。(ベクターでなくても構わないのですが)
格納されている順番に点を繋げて出来上がった図形について考えます。
ただし最後の要素が示す頂点は最初の要素が示す頂点につながります。
また、その図形の各線分同士は交差していないものとします。
このとき、ある点(x,y)がその図形の内部に存在しているかどうかを判定したいのです。
判定することさえできれば、三角形に分ける必要はもちろんございません。
ご教授よろしくお願い致します。
Re: n角形の図形を三角形の集合にわける方法
効率良いプログラムが作れる方法かどうか判りませんが、、、
判定対象となる点から無限遠に半直線を引きます。
この半直線が多角形の辺と何回交差するかで判定できます。
奇数なら多角形の中、偶数なら多角形の外です。
判定対象となる点から無限遠に半直線を引きます。
この半直線が多角形の辺と何回交差するかで判定できます。
奇数なら多角形の中、偶数なら多角形の外です。
Re: n角形の図形を三角形の集合にわける方法
追記
セジウィック先生の『アルゴリズムC++』にもこの方法で書いてあったので、
この方法で問題ないでしょう。本にはサンプルプログラムが載っています。
キーワードは「多角形による包含」
セジウィック先生の『アルゴリズムC++』にもこの方法で書いてあったので、
この方法で問題ないでしょう。本にはサンプルプログラムが載っています。
キーワードは「多角形による包含」
- MoNoQLoREATOR
- 記事: 284
- 登録日時: 13年前
- 住所: 東京
Re: n角形の図形を三角形の集合にわける方法
なるほど。確かにその方法ならうまく判定できそうですね。
というわけでさっそく書いてみたのですが、ごく稀にしか内部判定が出ませんでした。
原因は今のところ不明です。
ソースコードはこちらです。
線分同士が交わらないようにランダムに多角形を生成する方法が思いつかなかったのでむちゃくちゃな図形が出現しますが、ちゃんとした結果が出る場所はあると思います。
矢印キーで点を動かすことができます。
スペースキーを押すと再度ランダム生成を行います。
とりあえず途中報告ということで。
何か進展があればまた書き込みます。
というわけでさっそく書いてみたのですが、ごく稀にしか内部判定が出ませんでした。
原因は今のところ不明です。
ソースコードはこちらです。
#include "DxLib.h"
#include <vector>
struct coor{
int x;
int y;
coor(){}
coor(int x, int y){
this->x = x;
this->y = y;
}
};
struct line{
double a;
double b;
bool useful;
line(){ useful = false; }
line & set(const coor & beg, const coor & end){
if(beg.x == end.x){
useful = false;
a = beg.x;
}
else{
useful = true;
a = (beg.y+end.y) / (beg.x-end.x);
b = beg.y - a*beg.x;
}
return *this;
}
line(const coor & beg, const coor & end){ set(beg, end); }
line & operator() (const coor & beg, const coor & end){ return set(beg, end); }
};
struct cross{
double x;
double y;
bool useful;
cross(){ useful = false; }
bool compute(const line & one,const line & another){
if(one.a == another.a){ return useful = false; }
x = (another.b-one.b) / (one.a-another.a);
y = one.a*x + one.b;
return useful = true;
}
cross(const line & one,const line & another){ compute(one, another); }
bool operator() (const line & one,const line & another){ return compute(one, another); }
};
typedef unsigned int uint;
std::vector<coor> v;
coor dot;
void refresh(){
uint num = GetRand(10)+5;
v.resize(0);
v.reserve(num);
for(uint i=0;i<num;++i){
int x = GetRand(640);
int y = GetRand(480);
coor c(x, y);
v.push_back(c);
}
dot.x = GetRand(640);
dot.y = GetRand(480);
}
bool crossing(const line & segment, const coor & beg,const coor & end){
coor zero(0,0);
line ray(zero, dot);
cross c(segment, ray);
if(c.x > dot.x) return false;
//対象の点から(0,0)方向への半直線上に交点が無い場合は
//交点(x,y)のどちらも対象の点のそれよりも大きいから(x,y)のどちらかを比較するだけで良い。
//今回は、たまたまxを使用した。
if(c.useful==false) return false; //usefulがfalseの場合は交点を持たないから。
int x1 = beg.x;
int x2 = end.x;
if(x1 > x2){
x1 = end.x;
x2 = beg.x;
}
bool flag = c.x>=x1 && c.x<=x2;
if(flag==false) return false;
int y1 = beg.y;
int y2 = end.y;
if(y1 > y2){
y1 = end.y;
y2 = beg.y;
}
flag = c.y>=y1 && c.y<=y2;
if(flag==false) return false;
return true;
}
bool inside(){
uint num = 0;
for(uint i=0;i<v.size();++i){
uint next = (i+1)%v.size();
line segment(v[i], v[next]);
if(crossing(segment, v[i],v[next]) ) ++num;
}
return num%2 == 1;
}
char key[256];
int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpC, int nC){
ChangeWindowMode(true);
SetOutApplicationLogValidFlag(false);
SetWindowText("InsideTest");
SetMultiThreadFlag(false);
if(DxLib_Init() == -1) return(-1);
SetAlwaysRunFlag(false);
SetDrawScreen(DX_SCREEN_BACK);
SetDragFileValidFlag(false);
refresh();
while(ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0){
ClsDrawScreen();
GetHitKeyStateAll(key);
if(key[KEY_INPUT_SPACE] != 0) refresh();
if(key[KEY_INPUT_UP] != 0) dot.y -= 5;
if(key[KEY_INPUT_DOWN] != 0) dot.y += 5;
if(key[KEY_INPUT_LEFT]) dot.x -=5;
if(key[KEY_INPUT_RIGHT]) dot.x += 5;
for(uint i=0;i<v.size();++i){
uint next = (i+1)%v.size();
DrawLine(v[i].x,v[i].y, v[next].x,v[next].y, 0xffffff, 2);
}
DrawCircle(dot.x,dot.y, 3, GetColor(255,0,0), true);
if(inside() ) DrawString(0,0, "inside!", GetColor(0,0,255) );
else DrawString(0,0, "outside", GetColor(0,0,255) );
ScreenFlip();
}
DxLib_End();
return(0);
}
矢印キーで点を動かすことができます。
スペースキーを押すと再度ランダム生成を行います。
とりあえず途中報告ということで。
何か進展があればまた書き込みます。
Re: n角形の図形を三角形の集合にわける方法
> というわけでさっそく書いてみたのですが、ごく稀にしか内部判定が出ませんでした。
> 原因は今のところ不明です。
ソースはちゃんと読んでいませんが、ランダムだとデバッグしにくくないですか?
まずは単純な図形で判定ができることを確認した方が良いと思いますが。
> //対象の点から(0,0)方向への半直線上に交点が無い場合は
半直線の向きは自由なので、xの無限大の方向(傾き0)とかの方が楽ではないかと。
> 原因は今のところ不明です。
ソースはちゃんと読んでいませんが、ランダムだとデバッグしにくくないですか?
まずは単純な図形で判定ができることを確認した方が良いと思いますが。
> //対象の点から(0,0)方向への半直線上に交点が無い場合は
半直線の向きは自由なので、xの無限大の方向(傾き0)とかの方が楽ではないかと。
- MoNoQLoREATOR
- 記事: 284
- 登録日時: 13年前
- 住所: 東京
Re: n角形の図形を三角形の集合にわける方法
仰る通りです。
というわけでその方針でソースコードを修正しました。
ちゃんと判定されているようです。
今回のプログラムでは三角形のみで判定を行っていますが、おそらくどんな図形でも正確な判定結果が出ると思います。
ソースコードと実行ファイルを載せておきますので、ご自由にお使いください。
点はマウスポインタの位置になります。
スペースキーを押すと三角形がランダムに再生成されます。
実行ファイルは下記よりダウンロードしてください。
無事解決しました。本当にありがとうございました。
というわけでその方針でソースコードを修正しました。
ちゃんと判定されているようです。
今回のプログラムでは三角形のみで判定を行っていますが、おそらくどんな図形でも正確な判定結果が出ると思います。
ソースコードと実行ファイルを載せておきますので、ご自由にお使いください。
#include "DxLib.h"
#include <vector>
struct coor{
int x;
int y;
coor(){}
coor(int x, int y){
this->x = x;
this->y = y;
}
};
struct line{
double a;
double b;
bool useful;
line(){ useful = false; }
line & set(const coor & beg, const coor & end){
if(beg.x == end.x){
useful = false;
a = 0.0;
b = beg.x;
}
else{
useful = true;
a = (double)(beg.y-end.y) / (double)(beg.x-end.x);
b = beg.y - a*beg.x;
}
return *this;
}
line(const coor & beg, const coor & end){ set(beg, end); }
line & operator() (const coor & beg, const coor & end){ return set(beg, end); }
};
typedef unsigned int uint;
std::vector<coor> v;
void refresh(){
for(uint i=0;i<v.size();++i){
int x = GetRand(640);
int y = GetRand(480);
coor c(x, y);
v[i]=c;
}
}
char key[256];
bool crossing(const coor & dot, const line & segment, const coor & beg,const coor & end){
int y1 = beg.y;
int y2 = end.y;
if(y1 > y2){
y1 = end.y;
y2 = beg.y;
}
bool flag = dot.y>=y1 && dot.y<=y2;
if(flag==false) return false;
if(segment.a==0){
if(beg.x>dot.x && end.x>dot.x) return false; //この場合2直線は並行。ある点よりもx座標が大きければ交点をもたない。
else return true;
}
double x = (double)(dot.y-segment.b) / (double)segment.a;
if(x >= dot.x) return true;
return false;
}
bool inside(const coor & dot){
uint num = 0;
for(uint i=0;i<v.size();++i){
uint next = (i+1)%v.size();
line segment(v[i], v[next]);
if(crossing(dot, segment, v[i],v[next]) ) ++num;
}
return num%2 == 1;
}
int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpC, int nC){
ChangeWindowMode(true);
SetOutApplicationLogValidFlag(false);
SetWindowText("InsideTest");
SetMultiThreadFlag(false);
if(DxLib_Init() == -1) return(-1);
SetAlwaysRunFlag(false);
SetDrawScreen(DX_SCREEN_BACK);
SetDragFileValidFlag(false);
v.resize(3);
refresh();
while(ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0){
ClsDrawScreen();
GetHitKeyStateAll(key);
coor dot;
GetMousePoint(&dot.x, &dot.y);
if(key[KEY_INPUT_SPACE] != 0) refresh();
if(key[KEY_INPUT_UP] != 0) dot.y -= 5;
if(key[KEY_INPUT_DOWN] != 0) dot.y += 5;
if(key[KEY_INPUT_LEFT]) dot.x -=5;
if(key[KEY_INPUT_RIGHT]) dot.x += 5;
for(uint i=0;i<v.size();++i){
uint next = (i+1)%v.size();
DrawLine(v[i].x,v[i].y, v[next].x,v[next].y, 0xffffff, 2);
}
DrawCircle(dot.x,dot.y, 3, GetColor(255,0,0), true);
if(inside(dot) ) DrawString(0,0, "inside!", GetColor(0,0,255) );
else DrawString(0,0, "outside", GetColor(0,0,255) );
ScreenFlip();
}
DxLib_End();
return(0);
}
スペースキーを押すと三角形がランダムに再生成されます。
実行ファイルは下記よりダウンロードしてください。
無事解決しました。本当にありがとうございました。
- 添付ファイル
-
- insideTest.rar
- (1.05 MiB) ダウンロード数: 101 回
Re: n角形の図形を三角形の集合にわける方法
ミスありです。
この2つの画像見ればあらかた検討付きますが一応ご報告まで。✜ で C ご ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
: す + 注 :
¦ か + 文 ¦
: ? Is the は :
✜ order C++? ✜
糸冬
――――――――
制作・著作 NHK
――――――――
制作・著作 NHK
Re: n角形の図形を三角形の集合にわける方法
ランダムでデバッグしにくいことの1つですね。
3角形((1, 0), (-1, 1), (-1, -1))と原点を判定するテストを用意しましょう。
このような一連のテストを作ることができると、この手のバグは激減しますよ。
一朝一夕にはできるようにならないので、
長期間取り組むテーマの1つとして考えて下さい。
3角形((1, 0), (-1, 1), (-1, -1))と原点を判定するテストを用意しましょう。
このような一連のテストを作ることができると、この手のバグは激減しますよ。
一朝一夕にはできるようにならないので、
長期間取り組むテーマの1つとして考えて下さい。
Re: n角形の図形を三角形の集合にわける方法
まぁ横槍なんですけれど、次のような凸多角形を使うアルゴリズムもあるにはあります。
(凸多角形とは内角がすべて180°未満で構成された多角形)
①与えられた図形が凸多角形の時
高速で判定できます。
与えられた座標が各辺のどちら側にいるかを判定します。つまり、右回りに辺を巡っていって、すべて右手に与えられた座標があれば多角形の中にいます。
ベクトルの外積を使えば簡単に求まります。
②与えられた図形が凸多角形でない場合。
まず与えられたすべての頂点を含むような凸多角形を求めます。これを図形Aとします。
これは凸包のアルゴリズムを調べればいくらでも出てくると思います。
凸多角形に含まれていない頂点は、図形のへこんでいる部分に相当します。
そこで求めた凸多角形から図形のへこんでいる部分だけを抽出します。これを図形Bとします。
与えられた座標が、多角形内にいるかどうかは次のように判定できます。
1、図形Aの外側にいる→与えられた点は多角形の内側にいない
2、図形Aの内側にいる
→図形Bの外側にいれば、多角形の内側にいる
→図形Bの内側にいれば、多角形の外側にいる
図形Aとの判定は①を使えます。
また図形Bは多角形の集合です。
図形Bの内側に与えられた点がいるかどうかは、②の方法を再帰的に繰り返せば判定できます。
図形の内角の大きさが180°の境界を超えない限り、図形が変形、回転しても凸包の判定をして、
図形の階層構造をつくる工程は1度で済みます。
外積をとる回数自体は、凸多角形でもそうでなくても一定のはずなので、
一旦図形を凸包の形に分解してしまえばもしかしたらそこそこスピードが出るかもしれません。
出ないかもしれません。
3次元の場合はこちらの方が考えるのが楽かも。
(線分と半直線は判定しやすいが、自由な多角形で区切られた平面と半直線の判定はそこまで高速とは言えないから)
(凸多角形とは内角がすべて180°未満で構成された多角形)
①与えられた図形が凸多角形の時
高速で判定できます。
与えられた座標が各辺のどちら側にいるかを判定します。つまり、右回りに辺を巡っていって、すべて右手に与えられた座標があれば多角形の中にいます。
ベクトルの外積を使えば簡単に求まります。
②与えられた図形が凸多角形でない場合。
まず与えられたすべての頂点を含むような凸多角形を求めます。これを図形Aとします。
これは凸包のアルゴリズムを調べればいくらでも出てくると思います。
凸多角形に含まれていない頂点は、図形のへこんでいる部分に相当します。
そこで求めた凸多角形から図形のへこんでいる部分だけを抽出します。これを図形Bとします。
与えられた座標が、多角形内にいるかどうかは次のように判定できます。
1、図形Aの外側にいる→与えられた点は多角形の内側にいない
2、図形Aの内側にいる
→図形Bの外側にいれば、多角形の内側にいる
→図形Bの内側にいれば、多角形の外側にいる
図形Aとの判定は①を使えます。
また図形Bは多角形の集合です。
図形Bの内側に与えられた点がいるかどうかは、②の方法を再帰的に繰り返せば判定できます。
図形の内角の大きさが180°の境界を超えない限り、図形が変形、回転しても凸包の判定をして、
図形の階層構造をつくる工程は1度で済みます。
外積をとる回数自体は、凸多角形でもそうでなくても一定のはずなので、
一旦図形を凸包の形に分解してしまえばもしかしたらそこそこスピードが出るかもしれません。
出ないかもしれません。
3次元の場合はこちらの方が考えるのが楽かも。
(線分と半直線は判定しやすいが、自由な多角形で区切られた平面と半直線の判定はそこまで高速とは言えないから)
- MoNoQLoREATOR
- 記事: 284
- 登録日時: 13年前
- 住所: 東京
Re: n角形の図形を三角形の集合にわける方法
>>獅子さん
ご報告ありがとうございます。
私も、この判定方法の抜け穴には気づいていました。
半直線が図形の頂点を通るときは正確な判定をすることができないのですよね。
このとき、1回交差したことにすべきか2回、3回、あるいはそれ以上交差(平行に交わった場合に有りうる)したことにすべきかは、状況によって判断する必要があり、それをプログラム上で判断する方法は今のところ思いつきません。
だから、GRAMさんに教えて頂いた方法で正確性を追求しようと思います。
>>GRAMさん
返信ありがとうございます。
凸多角形の内部に点が存在するかどうかを判定する方法については理解しました。
凸包のアルゴリズムについてはこれから調べます。
何か進展があればまた返信いたします。
ご報告ありがとうございます。
私も、この判定方法の抜け穴には気づいていました。
半直線が図形の頂点を通るときは正確な判定をすることができないのですよね。
このとき、1回交差したことにすべきか2回、3回、あるいはそれ以上交差(平行に交わった場合に有りうる)したことにすべきかは、状況によって判断する必要があり、それをプログラム上で判断する方法は今のところ思いつきません。
だから、GRAMさんに教えて頂いた方法で正確性を追求しようと思います。
>>GRAMさん
返信ありがとうございます。
凸多角形の内部に点が存在するかどうかを判定する方法については理解しました。
凸包のアルゴリズムについてはこれから調べます。
何か進展があればまた返信いたします。
Re: n角形の図形を三角形の集合にわける方法
そうでしょうか?このとき、1回交差したことにすべきか2回、3回、あるいはそれ以上交差(平行に交わった場合に有りうる)したことにすべきかは、状況によって判断する必要があり、それをプログラム上で判断する方法は今のところ思いつきません。
n角形に対し、
1定点からn+1本の異なる半直線を引けば必ず妥当な半直線が1本あるはずですが。
(頂点はn個しかないから)
追記:
180°境界を超えない限りのくだりは僕の勘違いですね。
よく考えたら、図形が変形したら、もう一度凸包を考える必要がありそうです。
回転に関しては問題ないですね。
- MoNoQLoREATOR
- 記事: 284
- 登録日時: 13年前
- 住所: 東京
Re: n角形の図形を三角形の集合にわける方法
なるほど。
頂点と交わってしまったときのことを考えるのではなくて、頂点と交わらないような半直線を引くことを考えればよいのですね。
それが最も簡単そうです。
さっそく組んでみることにします。
頂点と交わってしまったときのことを考えるのではなくて、頂点と交わらないような半直線を引くことを考えればよいのですね。
それが最も簡単そうです。
さっそく組んでみることにします。
- MoNoQLoREATOR
- 記事: 284
- 登録日時: 13年前
- 住所: 東京
Re: n角形の図形を三角形の集合にわける方法
とりあえずソースコードはできました。
しかし、外部判定しか出ません。
原因は今のところ不明です。
進展があればまた返信いたします。
fw::Mouse.h
ご覧の通り、自作【クラス・構造体・関数】を多用しています。
そうです。めんどくさかったんです。いちいちコピペするのが。
要望があればアップします。
あと解決したら解決コードを載せるルールがあるようですので、そのときは・・・どうしましょう。多分コピペすると思います。
しかし、外部判定しか出ません。
原因は今のところ不明です。
進展があればまた返信いたします。
#define _CRT_SECURE_NO_DEPRECATE
#include "DxLib.h"
#define FW_WIN_MAIN_
#define FW_ALL_POP_UP_
#define FW_TYPEDEF_
#include "../fireworks/fireworks.h"
void refresh(fw::figure & f){
f.init();
for(uint i=0;i<3;++i){
int x = fw::random(640);
int y = fw::random(480);
f << fw::coor(x,y);
}
}
int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpC, int nC){
ChangeWindowMode(true);
SetOutApplicationLogValidFlag(false);
SetWindowText("InsideTest");
SetMultiThreadFlag(false);
if(DxLib_Init() == -1) return(-1);
SetAlwaysRunFlag(false);
SetDrawScreen(DX_SCREEN_BACK);
SetDragFileValidFlag(false);
static fw::figure f;
refresh(f);
static fw::Mouse dot;
while(ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0){
ClsDrawScreen();
dot.refresh();
char key[256];
GetHitKeyStateAll(key);
if(key[KEY_INPUT_SPACE] != 0) refresh(f);
for(uint i=0;i<f.size();++i){
uint next = (i+1)%f.size();
DrawLine(f[i].x,f[i].y, f[next].x,f[next].y, 0xffffff, 2);
}
DrawCircle(dot.x(),dot.y(), 3, GetColor(255,0,0), true);
if(dot.in(fw::coor(0,0),f) ) DrawString(0,0, "inside!", GetColor(0,0,255) );
else DrawString(0,0, "outside", GetColor(0,0,255) );
ScreenFlip();
}
DxLib_End();
return(0);
}
#pragma once
namespace fw{
class Mouse{
int bx, by;
int myx, myy;
bool bleft;
bool left;
bool bright;
bool right;
int wheel;
uint crossing(const fw::coor dist, const line & segment, const coor & beg,const coor & end) const {
fw::line ray(fw::coor(myx,myy), dist);
fw::cross c(ray, segment);
if(c.parallel) return 2; //半直線と図形の一辺(線分)が平行なら問答無用で半直線を変更する
if(c.intersect==false) return 0; //交点がなければ0を返す
fw::real basevecx(dist.x-myx);
fw::real vecx(c.x-myx);
if(basevecx*vecx < 0) return 0; //交点が無限遠の方向になければ交点なし
fw::real most = fw::distance(beg, end);
fw::real sub1 = fw::distance(beg, c);
fw::real sub2 = fw::distance(end, c);
if(sub1>most || sub2>most) return 0; //直線として考えたときの交点が線分上になければ交点なし
if(c==beg || c==end) return 2; //半直線が頂点を通るようなら半直線を変更する
return 1;
/*
int y1 = beg.y;
int y2 = end.y;
if(y1 > y2){
y1 = end.y;
y2 = beg.y;
}
bool flag = myy>=y1 && myy<=y2;
if(flag==false) return false;
if(segment.a==0){
if(beg.x>myx && end.x>myx) return false; //この場合2直線は並行。ある点よりもx座標が大きければ交点をもたない。
else return true;
}
double x = (double)(myy-segment.b.num() ) / (double)segment.a;
if(x >= myx) return true;
return false;
//*/
}
fw::coor Get2DJoypadAngle(int joygle) const {
int jg = joygle % 8000;
if(jg < 0) jg = 8000 - abs(jg);
if(jg <= 1000) return fw::coor(jg, 1000);
if(jg <= 3000) return fw::coor(1000, 1000 - (jg-1000) );
if(jg <= 5000) return fw::coor(1000 - (jg-3000), -1000);
if(jg <= 7000) return fw::coor(-1000, -1000 + (jg-5000) );
return fw::coor(-1000 + (jg-7000), 1000);
}
bool inside(const fw::vector<coor> & v) const {
fw::coor dist(0+myx,1000+myy);
int joygle = 8000 / (v.size()+1);
fw::coor gap = Get2DJoypadAngle(joygle);
uint num = 0;
uint i = 0;
while(i < v.size() ){
uint next = (i+1)%v.size();
line segment(v[i], v[next]);
uint result = crossing(dist, segment, v[i],v[next]);
if(result == 2){
dist += gap;
i = 0;
num = 0;
continue;
}
if(result == 1) ++num;
++i;
}
return num%2 == 1;
}
bool insidec(const coor & base, int r) const {
fw::real length = fw::distance(base, coor(myx,myy) );
return length <= r;
}
public:
Mouse(){
GetMousePoint(&myx, &myy);
left = (GetMouseInput() & MOUSE_INPUT_LEFT)!=0;
right = (GetMouseInput() & MOUSE_INPUT_RIGHT)!=0;
wheel = 0;
}
void refresh(){
bx = myx;
by = myy;
GetMousePoint(&myx, &myy);
bleft = left;
left = (GetMouseInput() & MOUSE_INPUT_LEFT)!=0;
bright = right;
right = (GetMouseInput() & MOUSE_INPUT_RIGHT)!=0;
wheel = GetMouseWheelRotVol();
}
bool in(const coor & base, const fw::figure & f) const {
if(f.cflagdata() ) return insidec(base, f.rdata() );
fw::vector<coor> v;
v.requre(f.size() );
for(uint i=0;i<f.size();++i){
coor c;
c.x = base.x + f[i].x;
c.y = base.y + f[i].y;
v += c;
}
return inside(v);
}
bool lclick() const { return left==false && bleft; }
bool lpush() const { return left && bleft==false; }
bool ldown() const { return left; }
bool lfree() const { return !left; }
bool rclick() const { return right==false && bright; }
bool rpush() const { return right && bright==false; }
bool rdown() const { return right; }
bool rfree() const { return !right; }
bool free() const { return !(left || right); }
int vx() const { return myx-bx; }
int vy() const { return myy-by; }
int x() const { return myx; }
int y() const { return myy; }
int step() const { return wheel; }
void set(int x, int y) const { SetMousePoint(x, y); }
void show() const {
int num = ShowCursor(true);
while(num != 0){
if(num > 0) num = ShowCursor(false);
if(num < 0) num = ShowCursor(true);
}
}
void hidden() const {
int num = ShowCursor(false);
while(num != -1){
if(num > -1) num = ShowCursor(false);
if(num < -1) num = ShowCursor(true);
}
}
void normal() const { SetClassLongPtr(GetMainWindowHandle(), GCL_HCURSOR, (LONG_PTR)(HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(32512), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED) ); }
void plus() const { SetClassLongPtr(GetMainWindowHandle(), GCL_HCURSOR, (LONG_PTR)(HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(32515), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED) ); }
void timer() const { SetClassLongPtr(GetMainWindowHandle(), GCL_HCURSOR, (LONG_PTR)(HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(32514), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED) ); }
void minitimer() const { SetClassLongPtr(GetMainWindowHandle(), GCL_HCURSOR, (LONG_PTR)(HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(32650), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED) ); }
void help() const { SetClassLongPtr(GetMainWindowHandle(), GCL_HCURSOR, (LONG_PTR)(HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(32651), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED) ); }
void text() const { SetClassLongPtr(GetMainWindowHandle(), GCL_HCURSOR, (LONG_PTR)(HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(32513), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED) ); }
void ban() const { SetClassLongPtr(GetMainWindowHandle(), GCL_HCURSOR, (LONG_PTR)(HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(32648), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED) ); }
void hand() const { SetClassLongPtr(GetMainWindowHandle(), GCL_HCURSOR, (LONG_PTR)(HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(32649), IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED) ); }
~Mouse(){
normal();
show();
}
};
}
ご覧の通り、自作【クラス・構造体・関数】を多用しています。
そうです。めんどくさかったんです。いちいちコピペするのが。
要望があればアップします。
あと解決したら解決コードを載せるルールがあるようですので、そのときは・・・どうしましょう。多分コピペすると思います。
- MoNoQLoREATOR
- 記事: 284
- 登録日時: 13年前
- 住所: 東京
Re: n角形の図形を三角形の集合にわける方法
今度こそ解決しました。
無事正確な判定結果を得ることができるようになりました。
三角形、四角形、五角形でのみテストを行いましたが、おそらくn角形の図形でも正確な判定結果を得ることができると思います。
解決したソースコードを載せることがここのルールだそうですので、一応載せておきますが、非常に長いコードとなっております。
なぜこれほどまでにも長いコードなのかと申しますと、自作の【クラス・構造体・関数】を多用しているからです。
いつもはインクルード文一行で済むのですがね・・・。
今回最も注目すべきコードは、fwネームスペースの一番下の方で定義されているMouseクラスのin関数です。
もともとマウスと図形の当たり判定を行いたかったのですよ。
ちなみにMouseクラスの定義で、in関数に関係しないメンバは削除しました。Mouseクラスは見やすくなっていると思います。
ですから、in関数を解析して、詳細が知りたい【クラス・構造体・関数】があったら右クリック→「定義へ」をクリック(VisualStudioをお使いの場合の話ですが)するという作業を行えば、判定方法がわかるのではないかと思います。
fw::vectorについてはこのページ(少し情報が古いですが)を、fw::cnctについてはこのページを参照してくださればよくわかると思います。
私に直接質問してくださっても構いませんが、おそらく新しくトピックを立てて、自分なりに考えたコードを載せ、たいちうさんやGRAMさんから個別指導をしていただく方がよくわかるし何より自分の力になると思います^^;
ちなみに、ここに載せてあるソースコードのご使用は完全に自由です。
使ってみようという猛者の方はお好きにどうぞ(笑)
長くなりましたが、これがソースコードです↓
ついでに、テストに使用した実行ファイルを下の方にアップしておきました。
マウスの座標が判定すべき点(赤色で表示される)になります。
最初は五角形が表示されていますが、スペースキーを押すと三角形がランダムに生成されます。
最後に、
たいちうさん、GRAMさん、獅子さん
本当にありがとうございました。
無事正確な判定結果を得ることができるようになりました。
三角形、四角形、五角形でのみテストを行いましたが、おそらくn角形の図形でも正確な判定結果を得ることができると思います。
解決したソースコードを載せることがここのルールだそうですので、一応載せておきますが、非常に長いコードとなっております。
なぜこれほどまでにも長いコードなのかと申しますと、自作の【クラス・構造体・関数】を多用しているからです。
いつもはインクルード文一行で済むのですがね・・・。
今回最も注目すべきコードは、fwネームスペースの一番下の方で定義されているMouseクラスのin関数です。
もともとマウスと図形の当たり判定を行いたかったのですよ。
ちなみにMouseクラスの定義で、in関数に関係しないメンバは削除しました。Mouseクラスは見やすくなっていると思います。
ですから、in関数を解析して、詳細が知りたい【クラス・構造体・関数】があったら右クリック→「定義へ」をクリック(VisualStudioをお使いの場合の話ですが)するという作業を行えば、判定方法がわかるのではないかと思います。
fw::vectorについてはこのページ(少し情報が古いですが)を、fw::cnctについてはこのページを参照してくださればよくわかると思います。
私に直接質問してくださっても構いませんが、おそらく新しくトピックを立てて、自分なりに考えたコードを載せ、たいちうさんやGRAMさんから個別指導をしていただく方がよくわかるし何より自分の力になると思います^^;
ちなみに、ここに載せてあるソースコードのご使用は完全に自由です。
使ってみようという猛者の方はお好きにどうぞ(笑)
長くなりましたが、これがソースコードです↓
► スポイラーを表示
マウスの座標が判定すべき点(赤色で表示される)になります。
最初は五角形が表示されていますが、スペースキーを押すと三角形がランダムに生成されます。
最後に、
たいちうさん、GRAMさん、獅子さん
本当にありがとうございました。
- 添付ファイル
-
- InsideProject.rar
- (1.04 MiB) ダウンロード数: 103 回