-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRectangle.lua
301 lines (261 loc) · 7.68 KB
/
Rectangle.lua
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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
Rectangle = Class{}
-- rectangle parallel to x and y axis oriented by an angle
function Rectangle:init(origin,size)
self.c=origin --origin is the botom left point
self.s=size
end
function Rectangle:type()
return "Rectangle"
end
function Rectangle:toString()
return "Rectangle : origin -> "..self.c:toString().." size -> "..self.s:toString()
end
--warning C is the 4th point in a trigo rectangle a->b->d->c is the hull
function Rectangle:findVertices()
if not self.a then
self.a=Vector(self.c.x,self.c.y+self.s.y) --top left vertice
self.b=Vector(self.c.x+self.s.x,self.a.y) --top right vertice
self.d=Vector(self.b.x,self.c.y)
end
return {[0]=self.a,[1]=self.b,[2]=self.d,[3]=self.c}
end
-- return true if this rectangle collides the rectangle in parameter
function Rectangle:ColR(rect)
return MSoverlapping(self.c.x,self.c.x+self.s.x,rect.c.x,rect.c.x+rect.s.x) and MSoverlapping(self.c.y,self.c.y+self.s.y,rect.c.y,rect.c.y+rect.s.y)
end
function Rectangle:ColL(line)
local n =line.direction:rotate90()
self:findVertices()
local dp1=n:dotProd(self.a:sub(l.base))
local dp2=n:dotProd(self.b:sub(l.base))
local dp3=n:dotProd(self.c:sub(l.base))
local dp4=n:dotProd(self.d:sub(l.base))
return dp1*dp2<=0 or dp2*dp3<=0 or dp3*dp4<=0
end
--[[Testcode
require "MathStructs"
l = Line(Vector(6, 8), Vector(2, -3))
r = Rectangle(Vector(3, 2),Vector(6, 4))
assert(r:ColL(l),"Rectangle Line Collision function error")
]]
function Rectangle:ColS(segment)
if not Line(segment.startp,segment.endp:sub(segment.startp))then
return false
end
if not Range(self.c.x,self.c.x+self.s.x):overlapping(Range(segment.startp.x,segment.endp.x))then
return false
end
return Range(self.c.y,self.c.y+self.s.y):overlapping(Range(segment.startp.y,segment.endp.y))
end
--[[Testcode
require "MathStructs"
r = Rectangle(Vector(3, 2), Vector(6, 4))
s = Segment(Vector(6, 8), Vector(10, 2))
assert(r:ColS(s),"Segment Rectangle collision function issue")
]]
function Rectangle:corner(num)
return self:findVertices()[num%4]
end
--nr is the number of the edge wanted
function Rectangle:Edge(nr)
local v=self:findVertices()
return Segment(v[nr % 4],v[(nr+ 1) %4])
end
function Rectangle:Edges()
self:findVertices()
return {
[0]=Segment(self.a,self.b),
[1]=Segment(self.b,self.d),
[2]=Segment(self.d,self.c),
[3]=Segment(self.c,self.a)
}
end
function Rectangle:SepAxis(seg)
local n= seg.startp:sub(seg.endp)
local rA=Segment(self:corner(0),self:corner(1))
local rB=Segment(self:corner(2),self:corner(3))
local rea=rA:project(n)
local reb=rB:project(n)
local rProj=rea:hull(reb)
arange=seg:project(n)
return not rProj:hull(arange)
end
function Rectangle:enlarge(point)
return Rectangle(
Vector(math.min(self.c.x,point.x),math.min(self.c.y,point.y)),
Vector(math.max(self.c.x+self.s.x,point.x),math.max(self.c.y+self.s.y,point.y))
)
end
function Rectangle:ColP(point)
return self.c.x <= point.x and
self.c.y <= point.y and
self.s.x + self.c.x >= point.x and
self.c.y + self.s.y >= point.y
end
--[[Testcode
require "MathStructs"
r = Rectangle(Vector(3, 2), Vector(6, 4))
p1 = Vector(4, 5)
p2 = Vector(11, 4)
assert(r:ColP(p1),"Rectangle Point collision function issue");
assert(not r:ColP(p2),"Rectangle Point collision function issue");
]]
function Rectangle:toCircle()
--circular hull fo the rectangle
local halfsize=self.s:divide(2)
return Circle(self.c:add(halfsize),halfsize:length())
end
function Rectangle:ColC(circle)
return circle:ColR(self)
end
function Rectangle:ColOR(orect)
return orect:ColR(self)
end
--return the opposite edge of rectangle to a point
function Rectangle:OpEdgesP(point)
local result ={}
local edges=self:Edges()
if self:ColP(point) then
return edges
end
if point.x < self.b.x then
table.insert(result,edges[1])
end
if point.x > self.c.x then
table.insert(result,edges[3])
end
if point.y < self.b.y then
table.insert(result,edges[0])
end
if point.y > self.c.y then
table.insert(result,edges[2])
end
return result
end
ORectangle = Class{}
-- center is a point or vector halfExtend is the vector between center and top right corner
function ORectangle:init(center,halfExtend,rotation)
self.c=center
self.he=halfExtend
self.r=rotation
--na serve for finding the points 1 and 3 as 2is center + he and 4 is center-he
end
function ORectangle:type()
return "ORectangle"
end
function ORectangle:toRect(origin)
return Rectangle(origin or NullVec,self.he:multiply(2))
end
function ORectangle:findVertices()
--na serve for finding the points 1 and 3 as 2is center + he and 4 is center-he
--here if na is already loaded in memory don't redo the heavy calculus
if not self.na then
self.na=self.he:rotate(-2*self.r)
end
if not self.v1 then
self.v1=self.c:sub(self.na)
self.v2=self.c:add(self.he)
self.v3=self.c:add(self.na)
self.v4=self.c:sub(self.he)
end
return { [0]=self.v1,[1]=self.v2,[2]=self.v3,[3]=self.v4}
end
--nr is the number of the edge wanted
function ORectangle:Edge(nr)
local v=self:findVertices()
return Segment(v[nr % 4],v[(nr+ 1) %4])
end
-- separating axis for oriented rectangle
function ORectangle:SepAxis(axis)
local n=axis.startp:sub(axis.endp)
local Proj= self:Edge(0):project(n):hull(self:Edge(2):project(n))
return not axis:project(n):overlapping(Proj)
end
--Oriented rectange to oriented rectangle collision
function ORectangle:ColOR(orec)
local edge=self:Edge(0)
if orec:SepAxis(edge) then
return false
end
edge=self:Edge(1)
if orec:SepAxis(edge) then
return false
end
end
--[[Testcode
require "MathStructs"
v1= Vector(3, 5)
v2= Vector(1, 3)
v3= Vector(10, 5)
v4= Vector(2, 2)
a = ORectangle(v1,v2,15)
b = ORectangle(v3,v4, -15)
assert(not a:ColOR(b),"Oriented rectangle collision issue");
]]
function ORectangle:ColC(cir)
return Circle(cir.c:sub(self.c):add(self.he),cir.r):ColR(Rectangle(Vector(0,0),self.he:multiply(2)))
end
--[[Testcode
require "MathStructs"
r = ORectangle(Vector(5, 4),Vector(3, 2), 30)
c = Circle(Vector(5, 7), 2)
assert(r:ColC(c),"Oriented rectangle circle collision issue")
]]
function ORectangle:corner(nr)
return self:findVertices()[nr%4]
end
function ORectangle:hullR()
--Rectangular hull of the Orect
local rect=Rectangle(self.c,NullVec)
for i=0,4 do
rect=rect:enlarge(self:corner(i))
end
return rect
end
function ORectangle:ColR(rect)
if not self:hullR():ColR(rect) then
return false
end
if not rect:SepAxis(self:Edge(0)) then
return false
end
return not rect:SepAxis(self:Edge(1))
end
--[[Testcode
require "MathStructs"
Aar = Rectangle(Vector(1, 5), Vector(3, 3))
OR = ORectangle(Vector(10, 4),Vector(4, 2), 25)
assert(not OR:ColR(Aar),"Oriented rectangle rectangle collision function issue");
]]
function ORectangle:ColP(point)
return self:toRect():ColP(point:sub(self.c):rotate(-self.r):add(self.he))
end
--[[Testcode
require "MathStructs"
r =ORectangle(Vector(5, 4), Vector(3, 2), 30)
a = Vector(6, 5)
b = Vector(10, 6)
assert(r:ColP(a),"Oriented Rectangle point collision function issue")
assert(not r:ColP(b),"Oriented Rectangle point collision function issue")
]]
function ORectangle:ColS(s)
return self:toRect():ColS(
Segment(
s.startp:sub(self.c):rotate(-self.r):add(self.he),
s.endp:sub(self.c):rotate(-self.r):add(self.he)
)
)
end
--[[Testcode
require "MathStructs"
s = Segment(Vector(1, 8),Vector(7, 5))
r = ORectangle(Vector(5, 4),Vector(3, 2), 30)
assert(r:ColS(s),"Orect segment function collision issue");
]]
function ORectangle:toCircle()
--To get a circular hull of the Orec
return Circle(self.c,self.he:length())
end
function ORectangle:ColL(line)
return line:ColOR(self)
end