Canvas.MoveTo Canvas.LineToで描画した直線に対して、マウスでクリックした際に、その座標が描画した直線上かどうかの判定方法を考えようとしています。
ここのキーワード検索の仕方がまずいのか、検索結果が多すぎてだめでした。
皆様のご教授をお願いいたします。
そのクリックした位置の色を見るといいのでは?
>そのクリックした位置の色を見るといいのでは?
複数の線分を区別しないのならソレでもいいけど、
特定の線分上にあるかチェックする場合はマズイね。
直線(線分)をAB、マウスポインタ座標をCとして、
ABとACの傾きが等しく、ABよりACが短いならば、点Cは線分AB上にあると
いえるかな...
ただし、座標が整数値なので線分上にあっても傾きがわずかに違うことも
あるので、どの程度の差まで許容するかの問題はあるけど...
点Cの色が線分ABの色と同じかを追加チェックすればカンペキか...
>ABとACの傾きが等しく、ABよりACが短いならば、点Cは線分AB上にあると
言えませんね。C がABの延長上にあって、かつ、ABよりACが短い場合がありますから。
>Canvas.MoveTo Canvas.LineToで描画した直線に対して
で、描画した線上にあればいいんですから、色を見るだけの精度でOKでは?
一般のグラフィックソフトのように、描かれた線分をマウスで「選択」するような用途では、直線の一般式
Ax + By + C = 0
にマウス座標が乗っていて、かつ、その座標の x または y 座標が両端の座標の
間に入っていれば線分上にあると言えますね。いちあんさんがおっしゃるように
座標は整数なので誤差が生じます。どれだけ厳密にするかで、許容する誤差を
決定して、線分上にあるかどうかを検討しなければなりません。
「いちあん 」さんの回答を見て思いつきました。
何をやっているのかはコードから判断してください。
なお、p1,p2は線分の両端を表す変数で、p1,p2:TPointです。
p0,px,q1,q2も同様にTPoint変数です。
q1:=p1;
q2:=p2;
px.X:=x;//クリックした点
px.Y:=y;
p0:=px;
if _r(q1,px)>_r(q2,px) then begin
q1:=p2;
q2:=p1;
end;//クリックした点より遠い点を基準点とする
q1.X:=q1.X-q2.X;
q1.Y:=q1.y-q2.Y;
px.X:=px.X-q2.X;
px.Y:=px.Y-q2.Y;
r:=q1.Y*px.X-q1.X*px.Y; //=|q1|*|px|*sin(φ)
r:=r/sqrt(sqr(q1.X)+sqr(q1.Y))/sqrt(sqr(px.X)+sqr(px.Y));
//=sin(φ)
if (abs(r)<0.005) and WithinRange(p1,p2,p0) then
label1.Caption:='On the line';//0.005は誤差限界の例
else
label1.Caption:='Out of the line';
****************
2点間の距離の2乗を求める
function TForm1._r(z1,zx:TPoint):double;
begin
result:=sqr(z1.X-zx.X)+sqr(z1.Y-zx.Y);
end;
*****************
線分の範囲内かどうかの判断
function TForm1.WithinRange(org,term,click:TPoint):boolean;
var large,small,buff:integer;
begin
if abs(org.X-term.X)>abs(org.Y-term.Y) then begin //x軸で評価
large:=org.X;
small:=term.X;
if small>large then begin
large:=term.X;
small:=org.X;
end;
result:=(click.X<=large) and (click.x>=small);
end else begin //y軸で評価
large:=org.Y;
small:=term.Y;
if small>large then begin
large:=term.Y;
small:=org.Y;
end;
result:=(click.Y<=large) and (click.Y>=small);
end; end;
ツイート | ![]() |