![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?c9bd177)
こんにちは.
私はプログラミングを勉強しはじめて3ヵ月くらいです.
今、与えられた多角形(例えば、(0,0),(3,7),(5,7),(8,3),(4,1),(1,0)の五点からなる多角形)の内部に格子点が存在するかどうかをチェックする(存在すれば1を返す等)ということをプログラミングを利用して,解決したいと思っています.最終的にはそれを利用して与えられた多角形をビットマップ表示にすることが目的です.
現在ある一つの自分の決めた点に関しては与えられた多角形を打ち込むことによって中か外かを判定する関数はできているのですが、100×100個の計10000個分の格子点に関してすべて中にあるか外にあるかを判定したいのですが、なかなか上手くいきません.
分かる方いらっしゃいましたら、アドバイスやプログラムの方よろしくお願いします.
今できているプログラムをのせておきます.
#include <stdio.h>
#include <stdlib.h>
/* #define JUST_ON 2 */
#define JUST_ON 1
int insidePolygon(int x, int y, int pn, int *px, int *py);
int insidePolygon(int x, int y, int pn, int *px, int *py)
/* x and y are the vertex I want to know in polygon.
pn is the number of vertex of polygon
*px and *py are the vertex of polygon */
{
int i, j;
int inside;
double yy;
if (pn < 1) return 0;
if (pn == 1) return x==px[0] && y==py[0];
/* Point (x,y) just lies on the edge or vertex of polygon */
for (i = 0, j = pn-1; i < pn; j = i++) {
if (py[i] == py[j] && y == py[i] &&
((px[i]<=x && x<=px[j]) || (px[j]<=x && x<=px[i])))
return JUST_ON;
else if (py[i] != py[j] &&
((py[i]<=y && y<=py[j]) || (py[j]<=y && y<=py[i])) &&
x == (double)(px[j]-px[i])*(y-py[i])/(py[j]-py[i])+px[i])
return JUST_ON;
}
/* Point (x,y) is inside/outside polygon */
inside = 0;
yy = y + 0.5; /* shift y to avoid acrossing the poly's edges or vertices */
for (i = 0, j = pn-1; i < pn; j = i++) {
if (((py[i]<=y && y<py[j]) || (py[j]<=y && y<py[i])) &&
x < (double)(px[j]-px[i])*(yy-py[i])/(py[j]-py[i])+px[i])
inside = !inside;
}
return inside;
}
int main()
{
int ii;
int xx, yy;
int pnpn;
int pxpx[100], pypy[100];
int ret;
printf("Enter (x,y) of a point -> ");
scanf("%d %d", &xx, &yy);
printf("Enter the number of vertics of the polygons -> ");
scanf("%d", &pnpn);
for (ii= 0; ii < pnpn; ii++) {
printf("Enter %d-th vertics's (x, y) -> ", ii+1);
scanf("%d %d", &pxpx[ii], &pypy[ii]);
}
ret = insidePolygon(xx, yy, pnpn, pxpx, pypy);
if (ret == 0) printf("The point is outside the polygon.\n");
else printf("The point is inside the polygon\n");
}
A 回答 (5件)
- 最新から表示
- 回答順に表示
No.5
- 回答日時:
No.4です。
泥臭いプログラムを載せたのですが、もっとエレガントな方法があります。
凸多角形(全ての内角が180度以下)に限定したものですが、
x,yが多角形の内側かどうかを判定するのに、まず最初の辺(0,0)→(3,7)を考えます、内側の時は進行方向に向かってみると必ず右側にあります。
次の辺の進行方向に向かってみても右側、一周してみると全部右側になるはずです。
数学的には外積を計算し符号で判定できます。
判定する点を(x,y)とし辺(x1,y1)→(x2, y2)の場合の外積は
(y2-y1)*(x-x1)-(y-y1)*(x2-x1)
になります。線上にあれば0になりますので、全部の辺について0または正(あるいは負)なることを調べればよいわけです。
辺の回る方向によっては正負が変わりますが、外側の場合には必ず正の辺と負の辺の両方があらわれます。
回る方向を気にせずに、全部の辺に対して外積が正負の両方が現れた時には外側、正負の一方と0の場合は内側(あるいは線上)判断できるはずです。
ただし、凸多角形でないとできませんので、最初に凸多角形か判断し、そうでなければ凸多角形になるように分割する必要があります。
凸多角形かどうかも外積の符号で判断できます。
No.4
- 回答日時:
見てもよく分からないので、ちょっと作ってみました。
その方が早いので。なぜ整数型になっているのかなと不思議に思っていたのですが、理由が分かりました。私が作ったのは実数型なので答えは違いますが、実数で計算して判定だけ丸めを考えれば簡単なように思います。(プログラムはそうしているのかな?)
多角形の場合、全部の角度が180度より小さい場合と大きいものが混ざっている場合で考え方を変えないといけません(多分)
質問者さんの例が全部180度より小さいかったので安直にそちらの場合だけにしました。その場合には各辺を伸ばしていっても、図形の内側は必ず他の頂点の存在する側にあります。ということは各辺を通る直線より上か下かで図形の内側かどうか判断できます。例は六角形ですので、直線6本分の判定をしています。
それとy軸に平行な辺があると、y=ax+bじゃなしにxの値で判断しないといけませんが、ここではサボッています。傾きが無限大になりますので私の書いたプログラムではエラーになります。
180度以上の角度がある場合には、補助線を引いて三角形なり、180度以下になる四角形に分解してやれば簡単にできます。
プログラムが読む気力がなかったので、もしそのように考えているのでしたら、ごめんなさい。
Rubyで書いてましたので一応載せておきます。
points=[[0.0,0.0], [3.0,7.0], [5.0,7.0], [8.0,3.0], [4.0,1.0], [1.0,0.0]]
insidepolygon_funcs=(points+points[0..1]).each_cons(3).collect{|xy1, xy2, xy3|
a=(xy1[1]-xy2[1])/(xy1[0]-xy2[0])
b=xy1[1]-a*xy1[0]
# 直線の上か下かによって判定する関数を作成
xy3[0]*a+b>xy3[1] ? lambda{|x, y| x*a+b>=y} : lambda{|x, y| x*a+b<=y}
}
# test
[[1.0, 1.0], [-1.0, 0.0], [10.0, 0.0]].each do |x, y|
p insidepolygon_funcs.all?{|f| f[x, y]}
end
No.3
- 回答日時:
とりあえず、insidePolygonが正しいと仮定します(検証が面倒なので)
10000個の点について判定したいのなら、一番単純な方法は10000回書くことです。
ret = insidePolygon(0, 0, pnpn, pxpx, pypy);
if (ret == 0) printf("The point(0,0) is outside the polygon.\n");
else printf("The point(0,0) is inside the polygon\n");
ret = insidePolygon(0, 1, pnpn, pxpx, pypy);
if (ret == 0) printf("The point(0,1) is outside the polygon.\n");
else printf("The point(0,1) is inside the polygon\n");
(以下略。合計10000個)
そんなのやってられないから、for等でループにするわけです。
for(i=0;i<10000;i++){
xx=i番目のx座標;
yy=i番目のy座標;
ret = insidePolygon(xx, yy, pnpn, pxpx, pypy);
if (ret == 0) 略
}
100x100なら、二重ループにするのがいいかもしれません。
あとは、結果を文字で出力する代りに、配列に入れたり、対応する座標の色を変えたりすればよいでしょう。
No.2
- 回答日時:
「insidepolygonの関数のなかの変更が上手くできない」とか「mainの中でforループまわすだけではうまくいってくれなくて」っていわれても, 何のことやらさっぱりわかりません. もっと具体的に, 何がどうダメなのか説明できませんか (ただし説明があったとしても私が答えるとは限りません. 念のため)?
ああ, この関数で本当にうまく動くかどうか私は確認していません. めんどくさいし, 厳密に考えだすと難しそうなので.
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# プログラミング c言語 4 2023/03/07 01:05
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# C 言語の Gauss Jordan 法について 2 2022/12/28 11:16
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# C言語 プログラミング 4 2022/05/22 11:53
- C言語・C++・C# 並列プログラミングのπ計算について 1 2022/07/16 22:30
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
画像の拡大・縮小
-
intとlongは同じ?
-
クイックソート
-
processingのプログラムの書き...
-
C言語で%を使わない余りの出し方
-
DXライブラリによるパズルゲー...
-
再起呼び出しの回数をカウント...
-
カードシャッフルのブログラム...
-
プログラムの時、フローチャー...
-
C言語の問題
-
C++でフィボナッチ数
-
argvのNULLチェック
-
迷路を脱出する経路探索プログ...
-
迷路の解を見つけるアルゴリズム
-
2の補数を計算するプログラム
-
c++でテンプレートのコードでわ...
-
#define _CRT_SECURE_NO_WARNIN...
-
Enterキーを押されたら次の処理...
-
2分法で方程式の複数の解を自...
-
比較回数と交換回数表示について
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
intとlongは同じ?
-
C言語で%を使わない余りの出し方
-
2の補数を計算するプログラム
-
再起呼び出しの回数をカウント...
-
画像の拡大・縮小
-
迷路を脱出する経路探索プログ...
-
分数の足し算をさせるプログラ...
-
OpenCVによる4値化について
-
3のつく数と3の倍数を表示 C言語
-
C言語で簡単なパックマンゲーム...
-
ヌメロンのプログラム
-
C++で表を作成したいのです ...
-
複数の共有メモリの作成
-
カードシャッフルのブログラム...
-
whileとifを使い偶数を出すには
-
関数とビット列
-
【C#】SQL文の中に変数を埋め込...
-
異なるn個の整数からr個の整数...
-
c言語プログラミングについて f...
-
条件が多い場合
おすすめ情報