直線上の座標かどうか


青いコニタン  2007-09-02 03:15:02  No: 27616

Canvas.MoveTo  Canvas.LineToで描画した直線に対して、マウスでクリックした際に、その座標が描画した直線上かどうかの判定方法を考えようとしています。
ここのキーワード検索の仕方がまずいのか、検索結果が多すぎてだめでした。

皆様のご教授をお願いいたします。


えーと  2007-09-02 08:01:31  No: 27617

そのクリックした位置の色を見るといいのでは?


いちあん  2007-09-02 08:11:01  No: 27618

>そのクリックした位置の色を見るといいのでは?
複数の線分を区別しないのならソレでもいいけど、
特定の線分上にあるかチェックする場合はマズイね。

直線(線分)をAB、マウスポインタ座標をCとして、
ABとACの傾きが等しく、ABよりACが短いならば、点Cは線分AB上にあると
いえるかな...
ただし、座標が整数値なので線分上にあっても傾きがわずかに違うことも
あるので、どの程度の差まで許容するかの問題はあるけど...
点Cの色が線分ABの色と同じかを追加チェックすればカンペキか...


えーと  2007-09-02 11:06:03  No: 27619

>ABとACの傾きが等しく、ABよりACが短いならば、点Cは線分AB上にあると

言えませんね。C がABの延長上にあって、かつ、ABよりACが短い場合がありますから。

>Canvas.MoveTo  Canvas.LineToで描画した直線に対して

で、描画した線上にあればいいんですから、色を見るだけの精度でOKでは?


えーと  2007-09-02 11:19:50  No: 27620

一般のグラフィックソフトのように、描かれた線分をマウスで「選択」するような用途では、直線の一般式

Ax + By + C = 0

にマウス座標が乗っていて、かつ、その座標の x または y 座標が両端の座標の
間に入っていれば線分上にあると言えますね。いちあんさんがおっしゃるように
座標は整数なので誤差が生じます。どれだけ厳密にするかで、許容する誤差を
決定して、線分上にあるかどうかを検討しなければなりません。


石橋屋  2007-09-06 22:49:26  No: 27621

「いちあん 」さんの回答を見て思いつきました。
何をやっているのかはコードから判断してください。
なお、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;


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加