AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein GUI-Design mit VCL / FireMonkey / Common Controls Delphi Überprüfen ob Mausklick in bestimmten bereich war
Thema durchsuchen
Ansicht
Themen-Optionen

Überprüfen ob Mausklick in bestimmten bereich war

Ein Thema von xZise · begonnen am 30. Jul 2006 · letzter Beitrag vom 26. Mär 2012
 
Benutzerbild von Aphton
Aphton

Registriert seit: 31. Mai 2009
1.198 Beiträge
 
Turbo Delphi für Win32
 
#12

AW: Überprüfen ob Mausklick in bestimmten bereich war

  Alt 23. Mär 2012, 16:03
Hier, eine etwas allgemeinere Lösung SAT (Separating Axis Theorem)

Kurze Erläuterung der Funktionsweise (soweit ich das richtig in Erinnerung habe):
Man berechnet zu allen Seiten beider Polygone schrittweise die Normalen, und projeziert alle Punkte auf diese Achse (Normale). Dann berechnet man sich die Min-Max Werte auf der Achse für Polygon 1 & 2. Schneiden sich nun diese beiden Bereiche nicht, so gibt es keine Kollision -> die Überprüfung kann vorzeitig beendet werden. Ansonsten kommt es höchstwahrscheinlich (nicht sicher!) zu einer Kollision.

Bild 1
Bild 2
(bei Bild 2 sieht man, dass der grüne und rote Bereich sich nicht schneiden -> keine Kollision)

Delphi-Quellcode:
type
  TVector = record
    X, Y: Single;
    procedure Assign(const AX, AY: Single);
  end;
  TVectorArray = Array of TVector;
  PPolygon = ^TPolygon;
  TPolygon = TVectorArray;

procedure TVector.Assign(const AX, AY: Single);
begin
  X := AX;
  Y := AY;
end;

function vector(const AX, AY: Single): TVector;
begin
  Result.Assign(AX, AY);
end;

function scalarProduct(const A, B: TVector): Single;
begin
  Result := A.X*B.X + A.Y*B.Y;
end;

procedure normalize(var V: TVector);
var
  size: Single;
begin
  size := SQRT(scalarProduct(V, V));
  if size <> 0 then V.Assign(V.X/size, V.Y/size);
end;

function normal(const V: TVector): TVector;
begin
  Result.Assign(V.Y, -V.X);
end;

function BoundingBoxCollisionCheck(const A1, A2, B1, B2: TVector): Boolean; overload;
{  1
    +---------+
    |        |
    |        |
    +---------+ 2
}

begin
  Result := not((A1.X > B2.X) or (A2.X < B1.X) or
    (A1.Y > B2.Y) or (A2.Y < B1.Y));
end;

function BoundingBoxCollisionCheck(const PolyA, PolyB: TPolygon): Boolean; overload;
var
  boxA1, boxA2,
  boxB1, boxB2: TVector;
  procedure createBoundingBox(const P: TPolygon; var bbox1, bbox2: TVector);
  var
    i: Integer;
  begin
    for i := 0 to High(P) do
    begin
      if P[i].X < bbox1.X then
        bbox1.X := P[i].X
      else
      if P[i].X > bbox2.X then
        bbox2.X := P[i].X;
      if P[i].Y < bbox1.Y then
        bbox1.Y := P[i].Y
      else
      if P[i].Y > bbox2.Y then
        bbox2.Y := P[i].Y
    end;
  end;
begin
  with PolyA[0] do
  begin
    boxA1.Assign(X, Y);
    boxA2.Assign(X, Y);
  end;
  with PolyB[0] do
  begin
    boxB1.Assign(X, Y);
    boxB2.Assign(X, Y);
  end;
  createBoundingBox(PolyA, boxA1, boxA2);
  createBoundingBox(PolyB, boxB1, boxB2);
  Result := BoundingBoxCollisionCheck(boxA1, boxA2, boxB1, boxB2);
end;

function SATCollisionCheck(const PolyA, PolyB: TPolygon): Boolean;
var
  P1, P2: PPolygon;
  function collisionCheck: boolean;
  var
    len: Integer;
    i: Integer;
    n: TVector;
    minMaxA, minMaxB: TVector;
    procedure getMinMaxAxisMappedValues(const Polygon: PPolygon; var min, max: Single);
    // axis = n
    var
      j: Integer;
      scalar: Single;
    begin
      min := scalarProduct(Polygon^[0], n);
      max := min;
      for j := 1 to high(Polygon^) do
      begin
        scalar := scalarProduct(Polygon^[j], n);
        if (scalar < min) then
          min := scalar
        else
        if scalar > max then
          max := scalar;
      end;
    end;
    function collision1DCheck(const A, B: TVector): Boolean;
    begin
      Result := not((A.X > B.Y) or (A.Y < B.X));
    end;
  begin
    Result := False;
    // gehe alle Punkte des Polygons 1 durch, bilde die Gerade und berechne darauf die Normale
    len := Length(P1^);
    for i := 0 to len do
    begin
      with P1^[(i+1) mod len] do
        n := normal(vector(X - P1^[i].X, Y - P1^[i].Y)); // n = normal(AB)
      normalize(n);
      // mappe nun alle punkte beider Polygone auf die Achse (punkt * n) und merke dir
      // min max Werte
      getMinMaxAxisMappedValues(P1, minMaxA.X, minMaxA.Y);
      getMinMaxAxisMappedValues(P2, minMaxB.X, minMaxB.Y);
      // wenn beide Bereiche sich NICHT schneiden, so kommts zu keienr Kollision und es kann beendet werden
      if not collision1DCheck(minMaxA, minMaxB) then Exit;
    end;
    Result := True;
  end;
begin
  Result := False;
  if (Length(PolyA) < 2) or (Length(PolyB) < 2) then Exit;
  if not BoundingBoxCollisionCheck(PolyA, PolyB) then Exit;
  P1 := @PolyA;
  P2 := @PolyB;
  if collisionCheck then
  begin
    P1 := @PolyB;
    P2 := @PolyA;
    Result := collisionCheck;
  end;
end;
Das ganze ist noch mit Bounding Boxes optimiert.
Hf
das Erkennen beginnt, wenn der Erkennende vom zu Erkennenden Abstand nimmt
MfG

Geändert von Aphton (23. Mär 2012 um 16:12 Uhr)
  Mit Zitat antworten Zitat
 


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:27 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz