Results 1 to 10 of 21

Thread: Circle vs pie segment collision detection

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    I am already comparing the distance between the circle and the beam, I just wasn't sure how to compare a circle against the two angles...

    hmm...I might try looking at dot products or similar + the line normal and see if I can test against the 2 lines and circle that way

    cheers,
    Paul

  2. #2
    An idea: transform the object/player coordinates to polar (you know: <angle, distance>) relative to the origin of your beam. In pseudocode:
    Code:
      IF vector_length (object.position - beam.position) < beam.radius THEN
        new_object.position := object.position - beam.position;
        polar_object := polar (new_object.position);
        IF polar_object.angle BETWEEN beam.angle1 AND beam.angle2 THEN
          object.hit ();
        END IF;
      END IF;
    No signature provided yet.

  3. #3
    With functions in my lib:
    Code:
    // Angle between 2 vectors, given in radians
    function Angle(src,dest: single): single;
    begin
      result:=src-dest;
      while result<-PI do result:=result+PI*2;
      while result>PI do result:=result-PI*2;
    end;
    
    // By pythagoras a^2+b^2=c^2 you don't need Sqrt() to determine the equality
    function PointInCircle(const p,circle: TVector2f; const radius: single): boolean;
    var x,y: single;
    begin
      x:=circle.x-p.x; y:=circle.y-p.y;
      PointInCircle:=(x*x+y*y)<(radius*radius);
    end;
    And knowing the angle_delta that is half of pie's slice angle, we can count if point is between them:

    Code:
    if PointInCircle(beam.position, player.position, radius) then
      if abs(Angle(beam.angle, angle_from_beam_to_player)) < angle_delta then begin
        Collide;
      end;
    You can also use this for the angle from beam to player:
    Code:
    function Angle(const px1,py1,px2,py2: single): single;
    begin
      result:=arctan2(py2-py1,px2-px1);
      if result<0 then result:=result+PI*2;
    end;
    Last edited by User137; 27-10-2010 at 01:02 PM.

  4. #4
    @?ëu?±o Mart??nez and User137: thanks guys, but you seem to have overlooked the fact that I want to check if a circle, not a point is between the 2 angle

    cheers,
    Paul

  5. #5
    indeed it would have been a lot easier if it was a point vs pie. but anyway, I just had a quick look into the problem and here's what I came up with:
    Code:
    TCircle = record
      public
        c: TG2Vec2;
        r: Single;
      end;
    
      TPie = record
      public
        c: TG2Vec2;
        r: Single;
        AngStart: Single;
        AngEnd: Single;
      end;
    ...
    function CircleVsPieIntersect(const c: TCircle; const p: TPie): Boolean;
      var v1, v2, n1, n2, n3, a1, a2: TG2Vec2;
      var d1, d2, l: Single;
    begin
      l := (c.c - p.c).Len;
      if l > c.r + p.r then
      begin
        Result := False;
        Exit;
      end;
      G2SinCos(p.AngStart, v1.y, v1.x);
      G2SinCos(p.AngEnd, v2.y, v2.x);
      n3 := -(v1 + v2);
      if (n3.Dot(c.c) > n3.Dot(p.c))
      and (l > c.r) then
      begin
        Result := False;
        Exit;
      end;
      n1 := v1.Perp; if n1.Dot(v1 - v2) < 0 then n1 := -n1;
      n2 := v2.Perp; if n2.Dot(v2 - v1) < 0 then n2 := -n2;
      d1 := n1.Dot(p.c) + c.r;
      d2 := n2.Dot(p.c) + c.r;
      if (n1.Dot(c.c) > d1)
      or (n2.Dot(c.c) > d2) then
      begin
        Result := False;
        Exit;
      end;
      a1 := p.c + v1 * p.r;
      a2 := p.c + v2 * p.r;
      if (
        (n1.Dot(c.c) > n1.Dot(p.c))
        and (v1.Dot(c.c) > v1.Dot(a1))
        and ((c.c - a1).Len > c.r)
      )
      or (
        (n2.Dot(c.c) > n2.Dot(p.c))
        and (v2.Dot(c.c) > v2.Dot(a2))
        and ((c.c - a2).Len > c.r)
      ) then
      begin
        Result := False;
        Exit;
      end;
      Result := True;
    end;
    this is not a best solution, just my solution
    One limitation though, the algorithm will consider the pie to be the lesser part of the circle.
    for example if the angle of your pie is > 180 then the algorithm will reverse the pie and use its smaller part.
    so basically if you use a pie with an angle < 180, the algorithm will work.
    There are a few methods from my game engine, so if you have any trouble understanding them - let me know.

  6. #6
    Nice! Thanks Dan...I will modify it and see if it works for me

    EDIT hmm...is TG2Vec2 a class or a record with methods?

    cheers
    Paul
    Last edited by paul_nicholls; 28-10-2010 at 03:17 AM.

  7. #7
    it's a record:
    Code:
    TG2Vec2 = record
      strict private
        function GetArr(const Index: Integer): Single; {$IFDEF G2_USE_INLINE} inline; {$ENDIF}
        procedure SetArr(const Index: Integer; const Value: Single); {$IFDEF G2_USE_INLINE} inline; {$ENDIF}
      public
        x, y: Single;
        property Arr[const Index: Integer]: Single read GetArr write SetArr; default;
        class operator Negative(const v: TG2Vec2): TG2Vec2;
        class operator Explicit(const v: TG2Vec2): TG2Vec2Ref;
        class operator Explicit(const v: TG2Vec2Ref): TG2Vec2;
        class operator Explicit(const v: TPoint): TG2Vec2;
        class operator Implicit(const v: TG2Vec2): TG2Vec2Ref;
        class operator Implicit(const v: TG2Vec2Ref): TG2Vec2;
        class operator Implicit(const v: TPoint): TG2Vec2;
        class operator Equal(const v1, v2: TG2Vec2): Boolean;
        class operator NotEqual(const v1, v2: TG2Vec2): Boolean;
        class operator Add(const v1, v2: TG2Vec2): TG2Vec2;
        class operator Add(const v: TG2Vec2; const s: Single): TG2Vec2;
        class operator Subtract(const v1, v2: TG2Vec2): TG2Vec2;
        class operator Subtract(const v: TG2Vec2; const s: Single): TG2Vec2;
        class operator Multiply(const v1, v2: TG2Vec2): Single;
        class operator Multiply(const v: TG2Vec2; const s: Single): TG2Vec2;
        class operator Multiply(const v: TG2Vec2; const m: TG2Mat): TG2Vec2;
        class operator Multiply(const v: TG2Vec2; const m: TG2Mat2): TG2Vec2;
        class operator Divide(const v: TG2Vec2; const s: Single): TG2Vec2;
        procedure SetValue(const _X, _Y: Single); {$IFDEF G2_USE_INLINE} inline; {$ENDIF}
        procedure Normalize; {$IFDEF G2_USE_INLINE} inline; {$ENDIF}
        function Normalized: TG2Vec2; {$IFDEF G2_USE_INLINE} inline; {$ENDIF}
        function Len: Single; {$IFDEF G2_USE_INLINE} inline; {$ENDIF}
        function LenSq: Single; {$IFDEF G2_USE_INLINE} inline; {$ENDIF}
        function Dot(const v: TG2Vec2): Single; {$IFDEF G2_USE_INLINE} inline; {$ENDIF}
        function Cross(const v: TG2Vec2): Single; {$IFDEF G2_USE_INLINE} inline; {$ENDIF}
        function Angle(const v: TG2Vec2): Single; {$IFDEF G2_USE_INLINE} inline; {$ENDIF}
        function Perp: TG2Vec2; {$IFDEF G2_USE_INLINE} inline; {$ENDIF}
        function Reflect(const n: TG2Vec2): TG2Vec2; {$IFDEF G2_USE_INLINE} inline; {$ENDIF}
        function Rotate(const Angle: Single): TG2Vec2; {$IFDEF G2_USE_INLINE} inline; {$ENDIF}
      end;
    if you want I could just attach the whole math unit here.

  8. #8
    Quote Originally Posted by paul_nicholls View Post
    @?ëu?±o Mart??nez and User137: thanks guys, but you seem to have overlooked the fact that I want to check if a circle, not a point is between the 2 angle
    Well..
    Code:
    if PointInCircle(beam.position, player.position, radius) then
    would change into
    Code:
    if PointInCircle(beam.position, player.position, radius+playerRadius) then
    That leaves the "triangle check" remaining to be fixed. It could really be a circle vs triangle check.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •