1 /*
2 * Kuklomenos
3 * Copyright (C) 2008-2009 Martin Bays <mbays@sdf.lonestar.org>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see http://www.gnu.org/licenses/.
17 */
18
19 #include <cmath>
20
21 #include "collision.h"
22 #include "coords.h"
23
pointHitsCircle(float x,float y,float vx,float vy,float rad,float et)24 float pointHitsCircle(float x, float y, float vx, float vy, float rad, float et)
25 {
26 if (et >= 0)
27 {
28 if ((x < -rad && x+et*vx < -rad) || (x > rad && x+et*vx > rad) ||
29 (y < -rad && y+et*vy < -rad) || (y > rad && y+et*vy > rad))
30 return -1;
31 }
32 else
33 if ((x < -rad && vx < 0) || (x > rad && vx > 0) ||
34 (y < -rad && vy < 0) || (y > rad && vy > 0))
35 return -1;
36
37 if (x*x + y*y <= rad*rad)
38 return 0;
39
40 float a = vx*vx+vy*vy;
41 float b = vx*x+vy*y;
42 float c = x*x+y*y-rad*rad;
43
44 /* answer is the lesser real solution to at^2+2bt+c=0, if it has any; we
45 * just use the quadratic formula! */
46 float discriminantOverFour = b*b-a*c;
47 if (discriminantOverFour < 0)
48 return -1;
49 float t = (-b - sqrt(discriminantOverFour))/a;
50 if (t < 0 || (et >= 0 && t > et))
51 return -1;
52 return t;
53 }
54
pointHitsPolygon(RelCartCoord * points,int n,RelCartCoord p,RelCartCoord v,float et)55 float pointHitsPolygon(RelCartCoord* points, int n, RelCartCoord p,
56 RelCartCoord v, float et )
57 {
58 double maxIn=0;
59 double minOut=-1;
60 for (int i=0; i < n; i++)
61 {
62 RelCartCoord next;
63 if (i+1 < n)
64 next = points[i+1];
65 else
66 next = points[0];
67 RelCartCoord dir = next - points[i];
68 RelCartCoord r = p - points[i];
69 // ddy*(rdx+t.vx) - ddx(rdy+t.vy) = 0
70 // t(ddy.vx - ddx.vy) = ddx.rdy-ddy.rdx
71 double vel = dir.dy*v.dx - dir.dx*v.dy;
72 double d = dir.dy*r.dx - dir.dx*r.dy;
73 if (vel == 0)
74 {
75 if (d > 0)
76 return -1;
77 else
78 continue;
79 }
80
81 double t = d/-vel;
82 if (d > 0)
83 {
84 // enter halfplane at time t
85 if (t < 0 || (et >= 0 && t > et))
86 return -1;
87 if (t > maxIn)
88 maxIn = t;
89 }
90 else
91 {
92 // leave halfplane at time t
93 if (t < 0 || (et >= 0 && t > et))
94 continue;
95 if (minOut == -1 || t < minOut)
96 minOut = t;
97 }
98 }
99 if (minOut == -1 || maxIn < minOut)
100 return float(maxIn);
101 else
102 return -1;
103 }
104
pointIn(float x,float y) const105 bool CollisionObject::pointIn(float x, float y) const
106 {
107 return (pointHits(x, y, 0, 0, 0) == 0);
108 }
pointHits(float x,float y,float vx,float vy,float et) const109 float CollisionObject::pointHits(float x, float y, float vx, float vy, float et) const
110 {
111 return pointHits(CartCoord(x,y), RelCartCoord(vx,vy), et);
112 }
pointIn(CartCoord p) const113 bool CollisionObject::pointIn(CartCoord p) const
114 {
115 return pointIn(p.x, p.y);
116 }
117
objectCollides(const CollisionCircle & other) const118 bool CollisionObject::objectCollides(const CollisionCircle& other) const
119 {
120 return circleIntersects(other.startPos, other.radius);
121 }
objectCollides(const CollisionPolygon & other) const122 bool CollisionObject::objectCollides(const CollisionPolygon& other) const
123 {
124 // UNIMPLEMENTED
125 return false;
126 }
127
pointHits(CartCoord p,RelCartCoord v,float et) const128 float CollisionCircle::pointHits(CartCoord p, RelCartCoord v, float et) const
129 {
130 return pointHitsCircle(p.x - startPos.x, p.y - startPos.y,
131 v.dx - velocity.dx, v.dy - velocity.dy, radius, et);
132 }
133
circleIntersects(CartCoord c,float rad) const134 bool CollisionCircle::circleIntersects(CartCoord c, float rad) const
135 {
136 return (pointHitsCircle(startPos.x - c.x, startPos.y - c.y, 0, 0,
137 radius + rad, 0) == 0);
138 }
139
pointHits(CartCoord p,RelCartCoord v,float et) const140 float CollisionPolygon::pointHits(CartCoord p, RelCartCoord v, float et) const
141 {
142 RelCartCoord rp = (p - startPos).rotated(-angle);
143 RelCartCoord rv = (v - velocity).rotated(-angle);
144 return pointHitsPolygon(points, numPoints, rp, rv, et);
145 }
146
circleIntersects(CartCoord c,float rad) const147 bool CollisionPolygon::circleIntersects(CartCoord c, float rad) const
148 {
149 // TODO properly
150 return pointIn(c);
151 }
152