-
Notifications
You must be signed in to change notification settings - Fork 0
/
Collisions.js
218 lines (201 loc) · 5.65 KB
/
Collisions.js
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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/*
Determina se due poligoni stanno collidendo o no
*/
function detectCollision(s1, s2) {
//genero assi per il primo oggetto
var axes = getAxes(s1);
for (var i=0; i<axes.length; i++) {
var axis = axes[i];
//genero proiezioni delle due figure sull'asse
var p1 = makeProjection(s1, axis);
var p2 = makeProjection(s2, axis);
if (!overlaps(p1, p2)) {
return false;
}
}
//genero assi per il secondo oggetto
var axes = getAxes(s2);
for (var i=0; i<axes.length; i++) {
var axis = axes[i];
var p1 = makeProjection(s1, axis);
var p2 = makeProjection(s2, axis);
if (!overlaps(p1, p2)) {
return false;
}
}
return true;
}
/*
Determina se un cerchio e un poligono stanno collidendo
*/
function detectCircleShapeCollision(center, radius, shape) {
var result = {
overlaps: false,
p: null,
isInside: false,
closestPoint: null
};
//ciclo su tutti i lati del poligono
for (var i=0; i<shape.vertices.length; i++) {
var v1 = shape.vertices[i];
var v2 = shape.vertices[(i+1)%shape.vertices.length];
//calcolo il vettore su cui si trova il lato, e lo normalizzo
var edge = v1.subtract(v2);
//calcolo il vettore con il centro del cerchio
var circleVect = v1.subtract(center);
var length = distance(v1, v2);
//calcolo il prodotto scalare
var dot = edge.dotp(circleVect)/(length*length);
//trovo le coordinate della proiezione del centro sul vettore
var cPoint = new point(v1.x + dot * edge.x, v1.y + dot * edge.y);
///var showP = new ball(cPoint, 5, new color(255, 255, 255), new color(255, 255, 255), 0, 0).drawWithLights();
var d1 = distance(v1, cPoint);
var d2 = distance(v2, cPoint);
if (d1+d2 < length - 20 || d1+d2 > length + 20) {
continue;
}
if (distance(cPoint, center) <= radius) {
//se si trova all'interno del lato del poligono e la distanza è minore del raggio c'è collisione
result.overlaps = true;
break;
}
}
//se il centro si trova all'interno del poligono c'è collisione
if (contains(shape, center)) {
result.overlaps = true;
result.isInside = true;
}
result.p = edge.perp();
return result;
}
/*
Genera gli assi di un poligono
*/
function getAxes(shape) {
var axes = [];
for (var i=0; i<shape.vertices.length; i++) {
var v1 = shape.vertices[i];
var v2 = shape.vertices[(i+1)%shape.vertices.length];
var edge = v1.subtract(v2);
//perpendicolare al lato
var normal = edge.perp();
axes[i] = normal;
}
//normalizzo gli assi
for (axis in axes) {
axis = axis.normalize();
}
return axes;
}
/*
Calcola gli estremi della proiezione di una figura su una retta
*/
function makeProjection(shape, axis) {
var min = axis.dotp(shape.vertices[0]);
var max = min;
for (var i=1; i<shape.vertices.length; i++) {
var p = axis.dotp(shape.vertices[i]);
if (p < min)
min = p;
if (p > max)
max = p;
}
return new projection(min, max);
}
/*
Calcola se due proiezioni si sovrappongono
*/
function overlaps(p1, p2) {
return (!(p1.max < p2.min || p1.min > p2.max));
}
/*
Restituisce true se il punto è contenuto nella figura, false altrimenti
*/
function contains(shape, point) {
var cn = 0;
//conto quanti lati incrociano il semiasse orizzontale che parte dal punto 'point'
for (var i=0; i<shape.vertices.length; i++) {
if (crossing(shape.vertices[i], shape.vertices[(i+1)%shape.vertices.length], point))
cn++;
}
//se un solo lato incrocia il semiasse, il punto è all'interno della figura (il modulo serve nel caso la figura sia concava)
if (cn%2 == 1)
return true;
else
return false;
}
/*
Calcola se il semiasse orizzontale che parte da p incrocia il segmento v1-v2 (lato del poligono)
*/
function crossing(v1, v2, p) {
//retta orizzontale
if (v1.y == v2.y)
return false;
//retta verticale
if (v1.x == v2.x)
//se la y del punto p è compresa nel segmento p e si trova a sinistra della retta, si incrociano
if (v1.x > p.x && betweenY(v1, v2, p))
return true;
else
return false;
//se la y del punto è fuori dall'intervallo dei due vertici, non si incrociano
if (!betweenY(v1, v2, p) || (v1.x < p.x && v2.x < p.x))
return false;
//calcolo retta passante per i due vertici
var r = new retta((v1.y - v2.y)/(v1.x - v2.x), (v1.x*v2.y - v2.x*v1.y)/(v1.x - v2.x));
//calcolo la x dell'incrocio tra le due rette
var x = (p.y - r.q)/r.m;
//se il punto è a sinistra del punto di incontro si incrociano
if (x > p.x)
return true;
else
return false;
}
/*
Calcola se l'ordinata del punto p è compresa tra quelle dei vertici v1 e v2
*/
function betweenY(v1, v2, p) {
if (p.y > Math.min(v1.y, v2.y) && p.y < Math.max(v1.y, v2.y))
return true;
else
return false;
}
/*
Calcola la distanza tra due punti
*/
function distance(p1, p2) {
return Math.sqrt((p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y));
}
/*==============Oggetti==============*/
function projection(min, max) {
this.min = min;
this.max = max;
this.print = function() {
console.log(min+" "+max);
}
}
function vector(x, y) {
this.x = x;
this.y = y;
//restituisce il vettore perpendicolare
this.perp = function() {
return new vector(-this.y, this.x);
}
//calcola il prodotto scalare con il vettore p
this.dotp = function(p) {
return this.x * p.x + this.y * p.y;
}
//restituisce il vettore inverso
this.inverse = function() {
return new vector(-this.x, -this.y);
}
//normalizza il vettore
this.normalize = function() {
var div = Math.sqrt(this.x * this.x + this.y * this.y);
return new vector(this.x/div, this.y/div);
}
}
function retta(m, q) {
this.m = m;
this.q = q;
}