0

2 本の線が交差しているかどうかを検出するための線交差コードを作成しようとしています。私が持っている形式は、Lo(l subscript O) 行を持つことができる O 個のオブジェクトがあり、各行には 2 つのポイントがあり、各ポイントには ax と y があります。これがレコード形式です。

 TPoint = record
    x,y:integer;
  end;
  TLine = record
    Point : array[0..1] of TPoint;
    Color : Tcolor;
  end;
  TFill = record
    Point : TPoint;
    Color : Tcolor;
  end;
  TDObject = record
    Lines : array of TLine;
    Fills : array of TFill;
    Rotation : integer;
    Position : Tpoint;
    BoundTop,Boundleft,Boundbottom,Boundright:integer;
  end;

Code を呼び出して、衝突をテストする 2 つのオブジェクトの各行の組み合わせを反復処理します。

Function DoCollide(obj1,obj2:Tdobject):boolean;
var i,j:integer;
 coll:boolean;
begin
  coll:=false;
  for i:=0 to length(obj1.lines) do
  begin
    for j:=0 to length(obj2.lines) do
    begin
      coll:=DoesIntersect(obj2.lines[i],obj2.lines[j])or coll;
    end;
  end;
  result:=coll;
end;

各ラインテストはそのように行われます

Function DoesIntersect(Line1,Line2:Tline):boolean;

var
  m1,m2,c1,c2,intersect:real;
  v1,v2:Boolean;
begin
//return true if lines cross
  // if line if verticle do not workout gradient
  if ((line1.point[1].x)-(line1.point[0].x))=0 then
    v1:=true // remember line 1 is verticle
  else
  begin
    m1 := ((line1.point[1].y)-(line1.point[0].y))/((line1.point[1].x)-(line1.point[0].x));
    c1 := line1.point[0].y - (line1.point[0].x*m1);
  end;

  if ((line2.point[1].x)-(line2.point[0].x))=0 then
    v2:=true    // remember line 2 is verticle
  else
  begin
    m2 := ((line2.point[1].y)-(line2.point[0].y))/((line2.point[1].x)-(line2.point[0].x));
    c2 := line2.point[0].y - (line2.point[0].x*m2);
  end;

  if ((NOT(m1=m2)) and (NOT(v1 or v2))) then  // non parrellel and non verticle
  begin

      //lines cross find where
      intersect := (c2-c1)/(m1-m2);   //line intersect solved for x
      if ((round(intersect)>= Min(line1.point[0].x,line1.point[1].x))
      and(round(intersect)<=max(line1.point[0].x,line1.point[1].x))
      and(round(intersect)>=min(line2.point[0].x,line2.point[1].x))
      and(round(intersect)<=max(line2.point[0].x,line2.point[1].x))) then
        result := true
      else
        result := false

  end
  else if (v1 and v2) then  // both lines are parralel
  begin
      // double verticle parallel exeption
      if (((line1.Point[0].y>=min(line2.Point[0].y,line2.Point[1].y))
      and(line1.Point[0].y<=max(line2.Point[0].y,line2.Point[1].y)))
      or ((line1.Point[1].y>=min(line2.Point[0].y,line2.Point[1].y))
      and(line1.Point[1].y<=max(line2.Point[0].y,line2.Point[1].y)))
      or ((line2.Point[0].y>=min(line1.Point[0].y,line1.Point[1].y))
      and(line2.Point[0].y<=max(line1.Point[0].y,line1.Point[1].y)))
      or ((line2.Point[1].y>=min(line1.Point[0].y,line1.Point[1].y))
      and(line2.Point[1].y<=max(line1.Point[0].y,line1.Point[1].y)))) then
        result := true
      else
        result := false;

  end
  else if (v1 and not v2) then  // line 1 is verticle and line 2 is not
  begin

      if ((((line1.Point[0].x*m2+c2)>=min(line1.Point[0].y,line1.Point[1].y))
      and ((line1.Point[0].x*m2+c2)<=max(line1.Point[0].y,line1.Point[1].y)))) then
        result := true
      else
        result := false
  end
  else if (v2 and not v1) then  // line 2 is verticle and line 1 is not
  begin

      if (((line2.Point[0].x*m1+c1)>min(line2.Point[0].y,line2.Point[1].y))
      and ((line2.Point[0].x*m1+c1)<max(line2.Point[0].y,line2.Point[1].y))) then
        result := true
      else
        result := false

  end
  else if (m1=m2) then  // parrellel non verticle lines
  begin

      if (((line1.Point[0].x>=min(line2.Point[0].x,line2.Point[1].x))
      and(line1.Point[0].x<=max(line2.Point[0].x,line2.Point[1].x)))
      or ((line1.Point[1].x>=min(line2.Point[0].x,line2.Point[1].x))
      and(line1.Point[1].x<=max(line2.Point[0].x,line2.Point[1].x)))
      or ((line2.Point[0].x>=min(line1.Point[0].x,line1.Point[1].x))
      and(line2.Point[0].x<=max(line1.Point[0].x,line1.Point[1].x)))
      or ((line2.Point[1].x>=min(line1.Point[0].x,line1.Point[1].x))
      and(line2.Point[1].x<=max(line1.Point[0].x,line1.Point[1].x)))) then
        result := true
      else
        result := false;

  end;
end;

しかし、私のコードによれば、すべての行は常に交差します.....したがって、私は間違いを犯しました...私は愚かな方法でこれを行っていますか?

4

1 に答える 1

1

2 組の線が交差しているかどうかを検出するより良い方法があります、今は気にしなくてもかまいません。

あなたのプログラムは、すべてが交差していることを検出するのに十分な時間実行されたのではないかと心配しています。配列の境界を超えて反復するため、プログラムがクラッシュするはずです。常に範囲チェックを有効のままにします。

ジオメトリを作成する場合は、線分線分を区別する必要があります。2 次元では、平行でない線は常に交差します。平行線でも、一致していれば交差できます。また、平行垂直のスペルを正しく取得することも当然のことです。

の計算intersectが間違っています。勾配の差をy切片の差で割る必要があります。

if c1 = c2 then
  intersect := c1
else
  intersect := (m1 - m2) / (c2 - c1);

両方の線が垂直の場合、 y座標で重なり合っているかどうかを確認するだけでは不十分です。また、それらのx座標が等しいことも確認する必要があります。同様に、平行な非垂直線では、y切片が等しいかどうかを確認する必要があります。

これらの問題をすべて修正しても、まだ間違った結果が得られる場合は、デバッガーを払いのけるときです。関数がtrueを返すが、実際には交差していない線分のペアを見つけます。これらの値で関数を呼び出し、デバッガーで関数をステップ実行します。デバッグを容易にするために、これらの多くの行の条件式をいくつかの中間変数に分割して、それぞれを個別にチェックできるようにします。どの計算が間違っているかを特定し、修正します。テスト データセットに、関数で考えられる各条件パスを実行する要素が含まれていることを確認してください。

于 2010-06-30T14:09:54.133 に答える