Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - schnittpunkt lokalisieren (Schnitt von Geraden)


Fussel9 - Mo 14.02.11 18:35
Titel: schnittpunkt lokalisieren (Schnitt von Geraden)
hallo, habe zwei rechtecke die sich schneiden.
jetzt muss ich herausfinden an welcher seite...

Ich habe von dem einen Rechteck zwei Punkte von der geraden auf der es sich bewegt und von dem anderen Rechteck habe ich ja Top|left und top|(Left+width)

jetz will ich bestimmen ob die beiden geraden sich schneiden, nur wie mache ich das im Quelltext?

und wie stelle ich die geradengleichungen auf, bzw. brauche ich die überhaupt?

normaler weise würde man ja jetzt zwei geradengleichungen erstellen und die dann gleichsetzen...

das wäre ja ziehmlich aufwendig... hat delphi da schon funktionen..?


elundril - Mo 14.02.11 18:43

Du könntest ev. mittels IntersectRect [http://msdn.microsoft.com/en-us/library/dd145001%28VS.85%29.aspx] auf eine Schnittfläche bei den beiden Rechtecken prüfen.

lg elundril


Fussel9 - Mo 14.02.11 18:48

Das mach ich schon, aber ich muss wissen ob das zweite rechteck von links/rechts oder von oben/unten
berührt wird.


Lannes - Mo 14.02.11 19:49

Hallo,

aus dem Ergebnis-Rect kannst Du es ermitteln:


Delphi-Quelltext
1:
2:
3:
4:
5:
var aR, bR, ergR: TRect;
begin
  aRect := Rect(100,100,200,200);
  bRect := Rect(10,10,120,120);
  IntersectRect(ergRect,aRect,bRect);//=> ergRect(100,100,120,120)

Ist ergRect.Left gleich aRect.Left, dann Berührung von links
...
...


Fussel9 - Mo 14.02.11 20:26

wie soll das funktionieren?
Siehe angehängte Grafik.

Ich habe jetzt einen mathematischen Weg, nur als Quelltext funktioniert der nicht und ich weiß nicht wieso...


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
function TFormMain.LineCollision(x1: Integer; y1: Integer; x2: Integer;
                                 y2: Integer; x3: Integer; y3: Integer;
                                 x4: Integer; y4: Integer) : Boolean;
var m1,m2,b1,b2,resultX: Real;
begin
result:=FALSE;
  m1:=(y2-y1)/(x2-x1);
  m2:=(y4-y3)/(x4-x3);
  b1:=y1-m1*x1;
  b2:=y3-m2*x3;
  resultX:=(b1-b2)/(m2-m1);
  ShowMessage(FloatToStr(resultX));
if not(resultX=0then
  begin
    result:=TRUE;
  end;
end;


für jede gerade: m=(y2-y1)/(x2-x1) b=y1-m*x1
und dann für den Schnittpunkt: x=(b1-b2)/(m2-m1)


will nur einfach nicht funktionieren... bei resultX:=(b1-b2)/(m2-m1); fliegt der compiler raus mit der Meldung:
'Ungültige Gleitkommaoperation!'


Lannes - Mo 14.02.11 20:36

Hallo,

in dem Fall der Grafik ist:
ergRect.Right = aRect.Right
und
ergRect.Bottom = aRect.Bottom
=> von rechts/unten


Fussel9 - Mo 14.02.11 20:39

Und genau das ist das problem, ich muss genau zwischen unten oder oben und rechts oder links unterscheiden.

Bei Rechts/Links muss die XKoordinate invertiert werden,
Bei Oben/Unten die YKoordinate...

Daher auch die function oben


PS: nach dem ich die function mit realen werten benutze tritt der selbe fehler jetzt schon hier auf: m1:=(y2-y1)/(x2-x1); (in der funtion)


Fussel9 - Mo 14.02.11 21:38

(!)

Das ganze funktioniert einiger maßen, aber nicht immer unbedingt richtig und es kommt zu divisionen durch null...
Ich gebe hier mal den Quelltext aus...
Kann mir jemand helfen?

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
procedure TFormMain.MoveBall(pCollisionObject: array of TPanel);
var tempObject,CollisionRect,BallAlt: TRect;
    I,: Integer;
begin
//-----------------------------save old Parameters----------------------------//
BallAlt.Top:=Ball.Top;
BallAlt.Bottom:=Ball.Bottom;
BallAlt.Left:=Ball.Left;
BallAlt.Right:=Ball.Right;
oldXCor:=XCor;
oldYCor:=YCor;
//----------------------------------------------------------------------------//
//--------------------Move Ball Check for Wall Collision(x)-------------------//
  sball.left:=sball.left+XCor;
  Ball.Left:=SBall.Left;
  Ball.Right:=SBall.Left+SBall.Width;
    if sball.left < (PLinks.Left+PLinks.Width) then
      begin
      sball.left := (PLinks.Left+PLinks.Width);
      Xcor := -Xcor;
      end;
    if sball.left > PRechts.Left - sball.width then
      begin
      sball.left := (PRechts.Left - sball.width);
      XCor := -XCor;
      end;
//----------------------------------------------------------------------------//
//--------------------Move Ball Check for Wall Collision(y)-------------------//
  sball.top := sball.top+YCor;
  Ball.Top:=SBall.Top;
  Ball.Bottom:=SBall.Top+SBall.Height;
    if sball.top < (POben.Top+POben.Height) then
      begin
      sball.Top := (POben.Top+POben.Height);
      YCor := -YCor;
      end;
    if sball.top > (self.height - sball.height) then
      begin
      sball.top := (self.height - sball.height);
      YCor := -YCor;
      end;
//----------------------------------------------------------------------------//
//-----------------------------Collision Ball Stick---------------------------//
    if IntersectRect(Collision,Ball,Stick) then
      begin
        sball.top := (PStick.top - sball.height);
        YCor:= -YCor;
        XCor:= XCor-1;
      end;
//----------------------------------------------------------------------------//
//------------------------Collision Ball Brick--------------------------------//
for I := 0 to High(pCollisionObject) - 1 do
  begin
    tempObject.Left:=pCollisionObject[I].Left;
    tempObject.Right:=pCollisionObject[I].Left+pCollisionObject[I].Width;
    tempObject.Top:=pCollisionObject[I].Top;
    tempObject.Bottom:=pCollisionObject[I].Top+pCollisionObject[I].Height;
    if IntersectRect(CollisionRect,tempObject,Ball) then
      begin
        TMover.Enabled:=False;
        case Richtung of
          0begin
               //Ball läuft nach Unten Rechts
             if LineCollision(BallAlt.Left,BallAlt.Top,Ball.Left,Ball.Top,
                              pCollisionObject[I].Left,pCollisionObject[I].Top,
                              pCollisionObject[I].Left+pCollisionObject[I].Width,
                              pCollisionObject[I].Top)=TRUE then
               begin
                 SBall.Top:=(pCollisionObject[I].Top-SBall.Height);
                 YCor:= -YCor;
               end
             else
               begin
                 SBall.Left:=(pCollisionObject[I].Left-SBall.Width);
                 XCor:= -XCor;
               end;
             end;
          1begin
               //Ball läuft nach Oben Rechts
             if LineCollision(BallAlt.Left,BallAlt.Top,Ball.Left,Ball.Top,
                              pCollisionObject[I].Left,
                              pCollisionObject[I].Top+pCollisionObject[I].Height,
                              pCollisionObject[I].Left+pCollisionObject[I].Width,
                              pCollisionObject[I].Top+pCollisionObject[I].Height)
                              =TRUE then
               begin
                 SBall.Top:=(pCollisionObject[I].Top+SBall.Height);
                 YCor:= -YCor;
               end
             else
               begin
                 SBall.Left:=(pCollisionObject[I].Left-SBall.Width);
                 XCor:= -XCor;
               end;
             end;
          2begin
              //Ball läuft nach Oben Links
             if LineCollision(BallAlt.Left,BallAlt.Top,Ball.Left,Ball.Top,
                              pCollisionObject[I].Left,
                              pCollisionObject[I].Top+pCollisionObject[I].Height,
                              pCollisionObject[I].Left+pCollisionObject[I].Width,
                              pCollisionObject[I].Top+pCollisionObject[I].Height)
                              =TRUE then
               begin
                 SBall.Top:=(pCollisionObject[I].Top+SBall.Height);
                 YCor:= -YCor;
               end
             else
               begin
                 SBall.Left:=(pCollisionObject[I].Left+SBall.Width);
                 XCor:= -XCor;
               end;
             end;
          3begin
              //Ball läuft nach Unten Links
             if LineCollision(BallAlt.Left,BallAlt.Top,Ball.Left,Ball.Top,
                              pCollisionObject[I].Left,pCollisionObject[I].Top,
                              pCollisionObject[I].Left+pCollisionObject[I].Width,
                              pCollisionObject[I].Top)=TRUE then
               begin
                 SBall.Top:=(pCollisionObject[I].Top-SBall.Height);
                 YCor:= -YCor;
               end
             else
               begin
                 SBall.Left:=(pCollisionObject[I].Left+SBall.Width);
                 XCor:= -XCor;
               end;
             end;
        end;
        TMover.Enabled:=TRUE;
      end;
  end;
//----------------------------------------------------------------------------//
//-------------------------Ball doesn't hit Stick-----------------------------//
    if Sball.Top > PStick.Top then
      begin
        SBall.Visible:=False;
        TMover.Enabled:=False;
        MessageDLG('Game Over!',mtWarning,[mbOk],0);
        SpawnBall;
      end;
//----------------------------------------------------------------------------//
//------------------------Save (?)new(?) Direction----------------------------//
if ((BallAlt.Left-Ball.Left)<0then
  begin
    //links
    if ((BallAlt.Top-Ball.Top)<0then
      begin
        //schräg unten links
        Richtung:=3;
      end
    else
      begin
        if ((BallAlt.Top-Ball.Top)>0then
          begin
            //schräg oben links
            Richtung:=2;
          end;
      end;
  end
else
  begin
    if ((BallAlt.Left-Ball.Left)>0then
      begin
        //rechts
        if ((BallAlt.Top-Ball.Top)<0then
          begin
            //schräg unten rechts
            Richtung:=0;
          end
        else
          begin
            if ((BallAlt.Top-Ball.Top)>0then
              begin
                //schräg oben rechts
                Richtung:=1;
              end;
          end;
      end;
  end;
//----------------------------------------------------------------------------//
end;


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
function TFormMain.LineCollision(x1: Integer; y1: Integer; x2: Integer;
                                 y2: Integer; x3: Integer; y3: Integer;
                                 x4: Integer; y4: Integer) : Boolean;
var m1,m2,b1,b2,resultX: Real;
begin
//ShowMessage('x1:'+IntToStr(x1)+'y1:'+IntToStr(y1)+'x2:'+IntToStr(x2)+'y2:'+
//            IntToStr(y2)+'x3:'+IntToStr(x3)+'y3:'+IntToStr(y3)+'x4:'+
//            IntToStr(x4)+'y4:'+IntToStr(y4));
result:=FALSE;
  m1:=(y2-y1)/(x2-x1);
//ShowMessage(FloatToStr(m1));
  m2:=(y4-y3)/(x4-x3);
//ShowMessage(FloatToStr(m2));
  b1:=y1-m1*x1;
//ShowMessage(FloatToStr(b1));
  b2:=y3-m2*x3;
//ShowMessage(FloatToStr(b2));
  resultX:=(b1-b2)/(m2-m1);
//ShowMessage(FloatToStr(resultX));
if not(resultX=0then
  begin
    result:=TRUE;
  end;
end;



Danke schon mal für jeden Tip der ratlose Fussel :shock:


Fiete - Di 15.02.11 13:11

Moin Fussel9,
schau mal hier nach:
http://mathenexus.zum.de/html/analysis/funktionen_lineare/weiterfuehrendes/LinFkt_SchneideGeraden.htm
Gruß
Fiete


Fussel9 - Di 15.02.11 20:30

Oh, ok jetz hab ich also noch eine Abfrage nach m1<>m2 hinzugefügt...

jetzt fliegt das Programm nicht mehr wegen Divisionen durch 0 raus, das ist gut;

aber das Programm berechnet irgendwie die collisionen und so noch nit richtig, irgendwo muss noch ein fehler in der moveBall procedure bestehen...

Ich finde ihn aber einfach nicht zur anschauung im anhang mal die .pas und die .exe

Ich hoffe ihr könnt mir nochmal weiter helfen :?


!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!<<Edit>>!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
---> Nach einigen Überlegungen und Beobachtungen des Programes ist mir der Fehler aufgefallen:
---> Bei der procedure LineCollision liegt der Fehler: die procedure funktioniert, das Problem ist, das die function immer True ausgeben wird, außer es handelt sich um Parallelen, was schon daher nicht sein kann da ich den Wert 0 für Xcor/Ycor abfange und neu auswürfeln lasse!...
Mit anderen Worten: da ich Geraden berechne und nicht Strecken werden diese immer einen Schnittpunkt haben!
--Ich hab die function LineCollision jetzt so erweitert das sie prüft ob der Schnittpunkt auf der Kante des Steins liegt mit dem der Ball kollidiert..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Es funktioniert aber immer noch nicht... jemand eine Idee wieso *verzweiflungs smiley*


Fiete - Mi 16.02.11 18:07

Moin Fussel9,
versuchs mal hiermit (Objekte als Rechtecke oder Kreise):
http://www.delphi-forum.de/topic_Kollisionsabfrage_103385.html
Gruß
Fiete