Einzelnen Beitrag anzeigen

Namenloser

Registriert seit: 7. Jun 2006
Ort: Karlsruhe
3.724 Beiträge
 
FreePascal / Lazarus
 
#16

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

  Alt 23. Mär 2012, 13:14
Funktioniert das Ganze vielleicht auch irgendwie mit einem Polygon, bzw. einer beliebigen Form die durch ein Punkte-Array definiert ist?
Kann ich z.B. ermitteln wenn sich die Maus in einem Kreis befindet? Derzeit lege ich ein Rechteck außen herum, aber das ist je nach Form sehr ungenau.
Kreis ist einfach, da musst du nur prüfen, ob die Distanz zum Mittelpunkt kleiner dem Radius ist:
PtInCirle := sqr(X-P.X)+sqr(Y-P.Y) < sqr(R) , wobei X und Y die Koordinaten z.B. des Cursors sind, P.X und P.Y der Mittelpunkt des Kreises und R der Radius. Die Gleichung wurde hier quadriert um die Wurzel zu sparen.

Für Polygone gibt es auch Verfahren (engl.), aber wenn es wirklich nur um einen Kreis geht, macht es absolut keinen Sinn, das zu implementieren. Ansonsten gibt es natürlich noch die von DeddyH verwendete API-Funktion, aber manchmal will man nicht mit Windows-Regions arbeiten...

[edit]

Hab mal meinen Port für den verlinten Algorithmus ausgegraben:
Delphi-Quellcode:
function TMapRegion.PointInRegion(APoint: TPoint): boolean;
var
  Pt1, Pt2: TPoint;
  PtOld, PtNew: TPoint;
  i: integer;
begin
  if (APoint.X >= FVertexList.BoundingBox.Left) and
     (APoint.X <= FVertexList.BoundingBox.Right) and
     (APoint.Y >= FVertexList.BoundingBox.Top) and
     (APoint.Y <= FVertexList.BoundingBox.Bottom) and
     (FVertexList.Count >= 3) then
  begin
    ///
    /// Ported from http://www.visibone.com/inpoly/
    ///
    Result := False;
    PtOld := FVertexList.Last;
    for i := 0 to FVertexList.Count - 1 do
    begin
      PtNew := FVertexList[i];
      if PtNew.X > PtOld.X then
      begin
        Pt1 := PtOld;
        Pt2 := PtNew;
      end
      else
      begin
        Pt1 := PtNew;
        Pt2 := PtOld;
      end;
      if ((PtNew.X < APoint.X) = (APoint.X <= PtOld.X)) and
         ((APoint.Y-Pt1.Y)*(Pt2.X-Pt1.X) < (Pt2.Y-Pt1.Y)*(APoint.X-Pt1.X)) then
      begin
        Result := not Result;
      end;
      PtOld := PtNew;
    end;
  end
  else
    Result := False;
end;
Bin jetzt zu Faul, den Code für normale Arrays zu verallgemeinern, aber es sollte nicht schwierig sein, ihn entsprechend abzuändern. Relevant ist übrigens nur der Teil innerhalb des if-Konstrukts. In der Abfrage davor wird nur erst mal gegen eine Bounding Box verglichen, was aber lediglich aus Performancegründen geschieht und somit weglassen werden kann.

[/edit]

Geändert von Namenloser (23. Mär 2012 um 13:25 Uhr)
  Mit Zitat antworten Zitat