Delphi-PRAXiS
Seite 3 von 4     123 4      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi auf linen klicken (https://www.delphipraxis.net/80500-auf-linen-klicken.html)

idontwantaname 14. Nov 2006 21:11

Re: auf linen klicken
 
Eine recht einfache Möglichkeit das Problem zu lösen ist über die Hessesche Normalform:
Delphi-Quellcode:
var
 // Gegeben
  A: TPoint; // Punkt der Geraden
  B: TPoint; // Punkt der Geraden
  P: TPoint; // Punkt des Mausklicks

 // errechnete Werte
  g: TPoint; // Richtungsvektor
  n: TPoint; // Normalvektor
  d: Integer; // d = a*x + b*y

  HNF: Double;
begin
  g := Point(B.X - A.X, B.Y - A.Y);
  n := Point(g.Y, -g.X);
  d := n.X * A.X + n.Y * A.Y;

  HNF := Abs((n.X * P.X + n.Y * P.Y - d) / Sqrt(n.X * n.X + n.Y * n.Y));

  // hier Wert anpassen
  if HNF < 20 then
    ShowMessage('getroffen')
  else
    ShowMessage('daneben');
end;
Edit: Falls du wirklich schauen möchtest, ob der Punkt auf der Geraden liegt (was hier unsinnig ist durch die Ungenauigkeit von Pixeln), so musst du folgendes überprüfen:
Delphi-Quellcode:
if n.X * P.X + n.Y * P.Y = d then
  ShowMessage('Punkt liegt auf der Geraden')
else
  ShowMessage('Punkt liegt nicht auf der Geraden');

flossinger 15. Nov 2006 04:17

Re: auf linen klicken
 
Hallo,

zu der Frage, wo der Schnittpunkt ist, habe ich eine Lösung ausgearbeitet, die bewusst ohne Vektorrechnung auskommt und mit skalarer Algebra nachvollziehbar ist.

Dabei habe ich eine line von x1,y1 nach x2,y2.
Die senkrecte Linie darauf verläuft vom Clickpunkt x3,y3 nach x4,y4.
Wobei wie gesagt x4:=x3+(y2-y1); und y4:=y3-(x2-x1);

Der Schnittpunkt x,y berechnet sich nun so:
Delphi-Quellcode:
dxa:=x2-x1;
dya:=y2-y1;
dxb:=x4-x3;
dyb:=y4-y3;
x:=round(((y3-y1)*dxa*dxb+x1*dya*dxb-x3*dyb*dxa)/(dya*dxb-dyb*dxa));
if abs(dxa)>abs(dxb) then
  y:=round(((x-x1)*dya+y1*dxa)/dxa)
  else
  y:=round(((x-x3)*dyb+y3*dxb)/dxb);
// die genauere Variante wird gewählt und /0 vermieden
Die Distanz vom Clickpunkt zur Geraden, die durch die line verläuft beträgt:
Delphi-Quellcode:
dist:=round(sqrt(sqr(x3-x)+sqr(y3-y)));
Mit der folgenden Bedingung kann noch abgefragt werden, ob die senkrechte Gerade die line trifft, oder ob der Schnittpunkt ausserhalb der Endpunkte liegt:
Delphi-Quellcode:
if not((((x<=x1)and(x>=x2))or((x>=x1)and(x<=x2)))
   and (((y<=y1)and(y>=y2))or((y>=y1)and(y<=y2)))) then
  dist:=-1;
Wenns Fragen gibt, nur her damit. Der code ist übrigens gut ausgetestet.

grüsse,
der flossinger

mimi 22. Dez 2006 15:16

Re: auf linen klicken
 
gut dann wollen wir mal fragen.
Tut mir leid das ich erst jetzt antworte: habe die frage aus den augen verloren :?

also ich habe eine frage hierzu:
dxa:=x2-x1; // MoveTo
dya:=y2-y1;// MoveTo

dxb:=x4-x3; // line to
dyb:=y4-y3; // line to ?

damit meine ich die position der line... sind die kometare richtig angeben ?

und
x:=round(((y3-y1)*dxa*dxb+x1*dya*dxb-x3*dyb*dxa)/(dya*dxb-dyb*dxa));
könntes du mir das bitte noch etwas genauer beschreiben\erkläeren ?


Zitat:

Mit der folgenden Bedingung kann noch abgefragt werden, ob die senkrechte Gerade die line trifft, oder ob der Schnittpunkt ausserhalb der Endpunkte liegt:
und was hat es sich mit der senkrechten gerade aufsich ?
ich möchte doch linen zeichnen die irgenwie sind:
waagerecht, senkrecht, schräg, und soweiter !


vielen dank !

flossinger 23. Dez 2006 10:52

Re: auf linen klicken
 
Hallo Michael,

das ist doch kein Problem, wenn man eine Frage etwas aus den Augen verliert. Das geht mir auch oft so. Man hat ja so vieles im Kopf.

Die Variablen dxa, dya. dxb, dyb enthalten nur Zwichenergebnisse für die Berechnung von x und y. Durch das Abspeichern dieser Zwischenergebnisse werden die Zeilen, wo x und y berechnet werden etwas vereinfacht und fallen dadurch kürzer aus.

Die "senkrechte Gerade" von der ich schreibe, verläuft nicht senkrecht auf dem Bilschirm von oben nach unten. Da hast du recht, so eine Einschränkung wäre nicht gut. Ich meine die Gerade, in der ich im Posting #14 schreibe.
Zitat:

Ich habe eine line von x1,y1 nach x2,y2.
Dann clicke ich und habe den clickpunkt x3,y3. Den ergänze ich mit einem weitern Punkt, so dass ich eine zweite line habe, die senkrecht auf die erste steht.
Delphi-Quellcode:
image1.canvas.moveto(x3,y3);
  x4:=x3+(y2-y1);
  y4:=y3-(x2-x1);
//  image1.canvas.lineto(x4,y4); // test

Diese line von x3/y3 nach x4/y4 verläuft also senkrecht zur ursprünglichen line, die von x1/y1 nach x2/y2 verläuft. Senkrecht heisst, die beiden lines verlaufen im rechten Winkel zu einander.

Ich schlage vor, du testest einmal das, was hier aus dem Posting #14 wiederholt wurde. Wenn etwas nicht klappen sollte, kannst du gerne zurückfragen. Wenn es geklappt hat, hast du schon etwas mehr Durchblick für die Fortsetzung. Teste so, dass du in deinem Programm eine line siehst, die im rechten Winkel auf die ursprüngliche line verläuft. Poste, was dein ergebnis ist, und dann setze ich gerne fort.

oT: Gratulation zum Neustart des Forums! Das war ja schon eine schöne Bescherung.

grüsse,
der flossinger

mimi 23. Dez 2006 12:10

Re: auf linen klicken
 
ich habe versucht draus eine funktion zu entwicklen.
Delphi-Quellcode:
function GetLineClick(x1,y1,x2,y2:Integer):Boolean;
var
  dxa,dya,dxb,dyb,x,y,x4,y4:Integer;
begin
  dxa:=x2-x1;
  dya:=y2-y1;
  x4:=x3+(y2-y1);
  y4:=y3-(x2-x1);

  dxb:=x4-x3;
  dyb:=y4-y3;
  x:=round(((y3-y1)*dxa*dxb+x1*dya*dxb-x3*dyb*dxa)/(dya*dxb-dyb*dxa));
  if abs(dxa)>abs(dxb) then
    y:=round(((x-x1)*dya+y1*dxa)/dxa)
  else
    y:=round(((x-x3)*dyb+y3*dxb)/dxb);
// die genauere Variante wird gewählt und /0 vermieden
  dist:=round(sqrt(sqr(x3-x)+sqr(y3-y)));
 
  if not((((x<=x1)and(x>=x2))or((x>=x1)and(x<=x2))) and (((y<=y1)and(y>=y2))or((y>=y1)and(y<=y2)))) then
    result:=false
  else
    result:=true;
end;
allerdings weiß ich nicht genau was x3 und y3 bedeuteten

edit: x3 und y3 ist bestimmt der klickpunk mit der maus,oder ?

flossinger 23. Dez 2006 12:40

Re: auf linen klicken
 
ja,

ganz genau: x3/y3 ist der der clickpunkt. Ds heisst, in x3 und y3 müssen die Mauskoordinaten abgespeichert werden.

Dann kannst du dir auch die line von x3/y3 nach x4/y4 anzeigen lassen.

der flossinger

edit:tippfehler

mimi 23. Dez 2006 12:44

Re: auf linen klicken
 
ich habe jetzt nochmal" idontwantaname" lösung probiert !
Sie läuft besser als "flossinger" lösung allerdins habe ich dennoch ein problem:
ich habe eine obj was auf ein andres liegt z.b.
eine line liegt auf ein viereck dann wird die line nicht mehr erkannt:
Delphi-Quellcode:
function GetLineClickA(x1,y1,x2,y2,x3,y3:Integer):Boolean;
var
// Gegeben
  A: TPoint; // Punkt der Geraden
  B: TPoint; // Punkt der Geraden
  P: TPoint; // Punkt des Mausklicks
// errechnete Werte
  g: TPoint; // Richtungsvektor
  n: TPoint; // Normalvektor
  d: Integer; // d = a*x + b*y

  HNF: Double;

begin
  a.x:=x1; a.y:=y1;
  b.x:=x2; b.y:=y2;
  p.x:=x3; p.y:=y3;
 
  g := Point(B.X - A.X, B.Y - A.Y);
  n := Point(g.Y, -g.X);
  d := n.X * A.X + n.Y * A.Y;

  HNF := Abs((n.X * P.X + n.Y * P.Y - d) / Sqrt(n.X * n.X + n.Y * n.Y));

  // hier Wert anpassen
  if HNF < 20 then
    result:=True
 //   ShowMessage('getroffen')
  else
    result:=false;
//    ShowMessage('daneben');
end;  

// verwenden tue ich das hier:
function TmyList.GetItemIndex(x,y:Integer;Obj:TObjectList;state:TShiftState):Integer;
var
  i,pIndex:Integer;
  r:TRect;
  Region:    THandle;
begin
  pIndex:=-1;

  for i:=0 to obj.count-1 do begin
    with TPaint2BasesObj(liste.items[i]) do begin
      if obj.Items[i] is TLine = false then begin
        r.left:=position.x; r.top:=position.y; r.Right:=size.x;r.Bottom:=size.y;
        if PtInRect(r,point(x,y)) = true then
          pindex:=i;
      end
      else begin
      if (GetLineClickA(position.x,position.y,size.x,size.y,x,y) = true) and (pindex = -1) then
         pindex:=i;
      end;
    end;
  end;
  if pindex > -1 then begin
    selobject:=TPaint2BasesObj(liste.items[pindex]);
    itemindex:=pIndex;
  end;
  writeLn(IntTostr(Pindex));

  result:=Pindex;
  if pindex > -1 then begin
    if ssshift in state then
    TPaint2BasesObj(liste.items[pindex]).Sel:=True;
  end
  else begin
    SetSelObj(false);
    selobject:=bg;
  end;
  Region:=0;
//  Region
end;
nun die fehler:
bei flossinger function die ich oben gepostet habe habe ich leider folgenden fehler:
ich habe wieder mehre objekte und nun platzier ich linen auf die paintbox.... nun kann ich nur noch die line und das erste objekt auswählen. :cry:

mimi 23. Dez 2006 12:48

Re: auf linen klicken
 
jetzt geht ihr müst einfach in der zeile
if (GetLineClickA(position.x,position.y,size.x,size.y ,x,y) = true) then das pindex - 1
rauß nehmen. das hatte ich zum testen drin...

aufjedenfall geht es jetzt.. . mit" idontwantaname's" lösung !
vielen dank für eure hilfe !

flossinger 23. Dez 2006 13:01

Re: auf linen klicken
 
Liste der Anhänge anzeigen (Anzahl: 1)
Na dann hast du flossingers Lösung nicht richtig umgesetzt.
Wie der screenshot zeigt, funktioniert das perfekt.
Anstatt zu behaupten, dass etwas nicht funktioniert, könntest du auch weitere Fragen stellen.

der flossinger

mimi 23. Dez 2006 13:06

Re: auf linen klicken
 
also folgende:
sobalt ich mehre objekte paltze und dein code ausprobiere
habe ich das problem das ich nur noch ein object und die line auswählen kann aller andren objekte sind dann "tod"


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:24 Uhr.
Seite 3 von 4     123 4      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz