Statistik  Mitglieder gesamt: 68138  Mitglieder online: 3  Gäste online: 1 mehr...
Anzeige
| Thread: JS: Brauche komplizierte math. Flächenberechnung
 16.05.2008 08:10 Uhr
|
|
|
|
|
Morgen zusammen!
Ich frage mich nun langsam wieso ich eigentlich über die Fläche eines Dreiecks rede, wenn ich doch dann Vielecke berechnen müsste, das versch. Zonen im Spielbereich aus Dreiecksvermaschung total umständlich wären.
Es gibt auch Techniken, mehreckige Fläche auf diese Weise zu berechnen. Jedoch bräuchte ich ein Verfahren, dass auch Flächen mit Nuten, Einsparungen, etc. berechnen kann.
|
|
 16.05.2008 09:22 Uhr
|
|
|
|
|
Ob ein Punkt innerhalb oder außerhalb eines Beliebigen 2D-Körpers bzw 2D-Polygons liegt kann man recht einfach berechnen. Hab da in meiner Ausbildung mal so einen Algorithmus in VisualBasic6 für meinen Ausbilder geschrieben. Leider kann ich den hier nicht mehr auf meinem Rechner finden (vielleicht reiche ich den später noch nach). Aber ich erklär den mal kurz:
Du benötigst erst mal die Koordinaten des Punktes der geprüft werden soll, weiter brauchst du jeden Punkt des Polygons. Anschließend bildest du (wenn ich mich recht erinner, mit dem zu testenden Punkt als Koordinatenursprung) die Summe über den Winkel zu den Punkten des Polygons mittels arcsin(). Als Lösung kannst du zwei unterschiedliche Werte des Gesamtwinkels erhalten: Beträgt dieser Winkel nun 360°, so liegt der Punkt innerhalb des Polygons, ist der Winkel 0°, so liegt der Punkt außerhalb.
Zu beachten dabei ist, dass ein Computer nur fehlerbehaftet mit Fließkommazahlen rechnen kann, so dass man durchaus Abweichungen von mehreren Grad erhalten kann, und dass bei der Verwendung von arcsin() den Winkel in Rad zurückgibt und du den Wert erst noch in Grad umrechnen musst, falls du lieber mit Grad rechnest.
___________________________ Programmieren ist eine Sucht deren Rausch ein Gefühl der Macht ist... sofern man den Computer bezwingt. Gefährliche Nebenwirkungen: Verstärkter Kaffee-Konsum, erhöhter Ehrgeiz und ggf. Wutausbrüche und verknotete Gehirnwindungen.
|
|
 16.05.2008 09:59 Uhr
|
|
|
|
|
Danke Hangman!
Das klingt interessant und scheint eine geeignete Lösung zu sein. Also ich habe alles nochmal durchgedacht, ich nehme keine Dreiecke, sondern gleich Flächen mit beliebig vielen Punkten, wozu auch Dreiecke? ja vielleicht findest du noch den Script, wenn nicht könntest du mir ja die genaue Bezeichnung des Verfahrens nennen oder auf andere Seiten, die sowas erklären verweisen. Übrigens, funktioniert diese Methode bei absolut jeder Flächenform? zB. auch wenn Zick-Zacks an der Seite sind und sowas ? Sonst hab ich am Schluss noch Tausend Bugs im Spiel!
 1 mal bearbeitet Armon: 16.05.2008, 10:00 Uhr
|
|
 16.05.2008 11:41 Uhr
|
|
|
|
|
Du kannst das Verfahren natürlich auch auf kleinere Bereiche anwenden, indem du zB irgendwie Beziehungen zwischen einzelnen Flächen herstellst. Dadurch brauchst du dann nicht alle Flächen berechnen, was die Performance heben könnte. Also zB eine Fläche mit wenigen Ecken, die wiederum mehrere Flächen mit vielen Polygonen enthalten kann. Liegt der Punkt außerhalb der Fläche mit wenig Punkten, so liegt der Punkt natürlich auch außerhalb aller enthaltenen Flächen
Name des Verfahrens: KA. Ist mir irgendwann mal in der Mittagspause eingefallen :)
Das Verfahren sollte bei jeder beliebigen Form funktionieren.
UND: Du hast Glück. Hab den Code in meinen Backups gefunden diff: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
| Option Explicit
Public Type Vector
x As Single
y As Single
End Type
Dim loPolygon() As Vector
Dim loTest As Vector
Dim liPolysize As Long
Dim lbTestSet As Boolean
Public Sub init()
loTest.x = 0
loTest.y = 0
liPolysize = -1
lbTestSet = False
End Sub
Public Sub clearPolygon()
ReDim loPolygon(0)
liPolysize = -1
lbTestSet = False
Form1.picGrid.Cls
drawGrid
End Sub
Public Sub addPolyVector(x As Single, y As Single)
Dim vec As Vector
vec.x = x
vec.y = y
liPolysize = liPolysize + 1
ReDim Preserve loPolygon(liPolysize)
loPolygon(liPolysize) = vec
End Sub
Public Sub setTestVector(x As Single, y As Single)
loTest.x = x
loTest.y = y
lbTestSet = True
End Sub
Public Sub drawGrid()
Dim i As Integer
Form1.picGrid.DrawWidth = 1
Form1.picGrid.ForeColor = RGB(200, 200, 200)
For i = 1 To Form1.picGrid.ScaleWidth - 1
Form1.picGrid.Line (i, 0)-(i, Form1.picGrid.ScaleHeight)
Next i
For i = 1 To Form1.picGrid.ScaleHeight - 1
Form1.picGrid.Line (0, i)-(Form1.picGrid.ScaleWidth, i)
Next i
End Sub
Public Sub Repaint()
Dim i As Integer
Form1.picGrid.Cls
drawGrid
If (liPolysize >= 0) Then
Form1.picGrid.ForeColor = RGB(0, 0, 0)
Form1.picGrid.DrawWidth = 5
Form1.picGrid.PSet (loPolygon(0).x, loPolygon(0).y)
Form1.picGrid.DrawWidth = 1
For i = 0 To UBound(loPolygon) - 1
Form1.picGrid.DrawWidth = 5
Form1.picGrid.PSet (loPolygon(i + 1).x, loPolygon(i + 1).y)
Form1.picGrid.DrawWidth = 1
Form1.picGrid.Line (loPolygon(i).x, loPolygon(i).y)-(loPolygon(i + 1).x, loPolygon(i + 1).y)
Next i
Form1.picGrid.Line (loPolygon(UBound(loPolygon)).x, loPolygon(UBound(loPolygon)).y)-(loPolygon(0).x, loPolygon(0).y)
End If
If (lbTestSet) Then
If (isInPolygon()) Then
Form1.picGrid.ForeColor = RGB(0, 200, 0)
Form1.lblStatus.Caption = "Testpunkt (" & Round(loTest.x, 2) & ";" & Round(loTest.y, 2) & ") liegt innerhalb des Polygons"
Else
Form1.picGrid.ForeColor = RGB(200, 0, 0)
Form1.lblStatus.Caption = "Testpunkt (" & Round(loTest.x, 2) & ";" & Round(loTest.y, 2) & ") liegt außerhalb des Polygons"
End If
Form1.picGrid.DrawWidth = 5
Form1.picGrid.PSet (loTest.x, loTest.y)
End If
End Sub
Public Function isInPolygon() As Boolean
Dim i As Integer
Dim a As Vector
Dim b As Vector
Dim phi As Double
Dim nexti As Long
Dim tmp As Double
phi = 0
If (liPolysize > 0) Then
' es werden ausgehend vom testpunkt jeweils zwei aufeinanderfolgende punkte im polygon betrachtet:
' nach ermitteln der richtungsvektoren der geraden zwischen dem testpunkt und punkt i im polygon,
' sowie testpunkt und punkt i+1 im polygon kann der schnittwinkel der beiden richtungsvektoren
' berechnet werden. alle winkel werden summiert. liegt der testpunkt innerhalb des polygons, so
' ergibt die summe aller winkel (+-)360°, da beim ermitteln der schnittwinkel einmal vollständig
' um den testpunkt gedreht werden muß.
' liegt der testpunkt außerhalb, so ergibt die summe aller winkel genau 0, da nach links genauso
' weit gedreht werden muß, wie nach rechts.
For i = 0 To UBound(loPolygon)
' es werden immer 2 benachbarte punkte des polygons p0..pn benötigt, um im letzten schritt die
' punkte pn und p1 zu erhalten wird zunächst der folgevektor pi+1 mit hilfe des modulo operators
' ermittelt. dadurch erhält man im n-ten schritt wieder den vektor p0 des polygons
nexti = (i + 1) Mod (UBound(loPolygon) + 1)
' richtungsvektor der geraden vom testpunkt zum i-ten punkt im polygon
a.x = loPolygon(i).x - loTest.x
a.y = loPolygon(i).y - loTest.y
' richtungsvektor der geraden vom testpunkt zum (i+1)-ten punkt im polygon
b.x = loPolygon(nexti).x - loTest.x
b.y = loPolygon(nexti).y - loTest.y
' die geraden mit richtungsvektoren a und b schneiden sich zwangsläufig im schnittpunkt loTest
' wodurch der schnittwinkel zwischen den richtungsvektoren a und b wie folgt berechnet werden
' kann:
' / (a*b) \ / a.x*b.x + a.y*b.y \
' phi = arccos | ------- | = arccos | ------------------------------------- |
' \ |a|*|b| / \ sqrt(a.x^2+a.y^2) * sqrt(b.x^2+b.y^2) /
' da arccos das ergebnis in rad liefert muß anschließend noch durch PI/180 dividiert werden um
' das ergebnis in grad zu erhalten. da PI in vb nicht deklariert ist, wird der wert duch 4*arctan(1)
' ermittelt.
tmp = arccos(((a.x * b.x + a.y * b.y) / ((a.x ^ 2 + a.y ^ 2) ^ (1 / 2) * (b.x ^ 2 + b.y ^ 2) ^ (1 / 2)))) / (4 * Atn(1) / 180)
' anschließend wird noch das vorzeichen des winkels benötigt. dies erhält man aus den koordinaten
' des testpunktes und der beiden punkte, die aktuell geprüft werden.
tmp = tmp * Sign((loPolygon(i).x - loTest.x) * (loPolygon(nexti).y - loTest.y) - (loPolygon(i).y - loTest.y) * (loPolygon(nexti).x - loTest.x))
' nun nur noch den neu berechneten winkel auf die bisher berechnete summe addieren
phi = phi + tmp
Next i
' ist der winkel 0° (alle winkel heben sich auf), so liegt der punkt außerhalb des polygons, in allen
' anderen fällen beträgt der winkel 360° und der testpunkt liegt innerhalb des polygons.
' aufgrund der schlechten kondition bei der berechnung etwas spielraum erlauben. besser wäre es, den
' absoluten fehler zu berechnen und die toleranz nur in diesem bereich zu gestatten.
isInPolygon = Not (phi < 5 And phi > -5)
End If
End Function
' arcus cosinus mit hilfe anderer trigonometrischen funktionen berechnen, da arccos in vb6 fehlt
Public Function arccos(n As Double) As Double
arccos = Atn(-n / Sqr(-n * n + 1)) + 2 * Atn(1)
End Function
' funktion zum ermitteln des vorzeichens einer zahl (rückgabe: -1;0;1)
Public Function Sign(n As Double) As Integer
If (n < 0) Then
Sign = -1
ElseIf (n > 0) Then
Sign = 1
Else
Sign = 0
End If
End Function |
 1 mal bearbeitet ___________________________ Programmieren ist eine Sucht deren Rausch ein Gefühl der Macht ist... sofern man den Computer bezwingt. Gefährliche Nebenwirkungen: Verstärkter Kaffee-Konsum, erhöhter Ehrgeiz und ggf. Wutausbrüche und verknotete Gehirnwindungen.
|
|
 16.05.2008 11:46 Uhr
|
|
|
|
|
Wow Danke! Es geht nichts über Backups! :-)
Nun wirds spannend beim Übersetzten in Javascript.
|
|
 16.05.2008 11:48 Uhr
|
|
|
|
|
Zitat: Nun wirds spannend beim Übersetzten in Javascript.
Ja. Aber das ist ja dann nicht mehr mein Problem
Objektorientiert Javascript programmieren funktioniert besser als in VB6. Der Aufwand kann sich sehr in Grenzen halten.
 1 mal bearbeitet ___________________________ Programmieren ist eine Sucht deren Rausch ein Gefühl der Macht ist... sofern man den Computer bezwingt. Gefährliche Nebenwirkungen: Verstärkter Kaffee-Konsum, erhöhter Ehrgeiz und ggf. Wutausbrüche und verknotete Gehirnwindungen.
|
|
 16.05.2008 12:04 Uhr
|
|
|
|
|
ich seh's mal so, wenigstens hab ich jetzt was Job fürs Wochenende! :-)
Jetzt aber geh ich erst grillen!
 2 mal bearbeitet Armon: 16.05.2008, 12:05 Uhr Armon: 16.05.2008, 12:13 Uhr
|
|
|