-
Notifications
You must be signed in to change notification settings - Fork 0
/
RotateableRectangle.cs
247 lines (198 loc) · 10.3 KB
/
RotateableRectangle.cs
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
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Limestone.Utility;
namespace Limestone
{
public class RotateableRectangle
{
private Vector2 topLeft;
private Vector2 bottomLeft;
private Vector2 topRight;
private Vector2 bottomRight;
public Vector2 source;
public Vector2 position { get { return topLeft; } set { } }
public Vector2 sizeWH { get { return new Vector2(width, height); }set { } }
private Vector2 size;
public float width { get { return topRight.X - topLeft.X; } }
public float height { get { return bottomLeft.Y - topLeft.Y; } }
public Vector2 center { get { return VectorHelper.GetMidPoint(topLeft, bottomRight); } set { } }
public float angle;
//public Vector2 position { get { return topLeft; } set { } }
public RotateableRectangle(Rectangle rectangle, Vector2 source, float angle)
{
topLeft = rectangle.Location.ToVector2();
bottomLeft = new Vector2(rectangle.Location.X, rectangle.Location.Y + rectangle.Height);
topRight = new Vector2(rectangle.Location.X + rectangle.Width, rectangle.Location.Y);
bottomRight = (rectangle.Location + rectangle.Size).ToVector2();
this.source = source;
this.size = rectangle.Size.ToVector2();
this.angle = angle;
RotateTo(source, angle);
}
public RotateableRectangle(Rectangle rectangle)
{
topLeft = rectangle.Location.ToVector2();
bottomLeft = new Vector2(rectangle.Location.X, rectangle.Location.Y + rectangle.Height);
topRight = new Vector2(rectangle.Location.X + rectangle.Width, rectangle.Location.Y);
bottomRight = (rectangle.Location + rectangle.Size).ToVector2();
this.size = rectangle.Size.ToVector2();
}
public bool Intersects(RotateableRectangle rect)
{
Vector2 normal; //The normal of the current side.
//extremely ugly way to do this
bool topOverlap = false, rightOverlap = false, bottomOverlap = false, leftOverlap = false;
normal = VectorHelper.GetNormal(topLeft, topRight); //First: top side
if (CheckAllProjectedForOverlap(normal, rect))
topOverlap = true;
normal = VectorHelper.GetNormal(topRight, bottomRight); //Second: right side
if (CheckAllProjectedForOverlap(normal, rect))
rightOverlap = true;
normal = VectorHelper.GetNormal(bottomRight, bottomLeft); //bottom
if (CheckAllProjectedForOverlap(normal, rect))
bottomOverlap = true;
normal = VectorHelper.GetNormal(bottomLeft, topLeft); //left
if (CheckAllProjectedForOverlap(normal, rect))
leftOverlap = true;
if (topOverlap && rightOverlap && bottomOverlap && leftOverlap)
{
return true;
}
else return false;
}
public bool Intersects(Rectangle rectunrotated)
{
RotateableRectangle rect = new RotateableRectangle(rectunrotated);
Vector2 normal; //The normal of the current side.
//extremely ugly way to do this
bool topOverlap = false, rightOverlap = false, bottomOverlap = false, leftOverlap = false;
normal = VectorHelper.GetNormal(topLeft, topRight); //First: top side
if (CheckAllProjectedForOverlap(normal, rect))
topOverlap = true;
normal = VectorHelper.GetNormal(topRight, bottomRight); //Second: right side
if (CheckAllProjectedForOverlap(normal, rect))
rightOverlap = true;
normal = VectorHelper.GetNormal(bottomRight, bottomLeft); //bottom
if (CheckAllProjectedForOverlap(normal, rect))
bottomOverlap = true;
normal = VectorHelper.GetNormal(bottomLeft, topLeft); //left
if (CheckAllProjectedForOverlap(normal, rect))
leftOverlap = true;
if (topOverlap && rightOverlap && bottomOverlap && leftOverlap)
{
return true;
}
else return false;
}
private bool CheckAllProjectedForOverlap(Vector2 normal, RotateableRectangle rect)
{
float dotTopLeft = Vector2.Dot(topLeft, normal);
float dotTopRight = Vector2.Dot(topRight, normal);
float dotBottomLeft = Vector2.Dot(bottomLeft, normal);
float dotBottomRight = Vector2.Dot(bottomRight, normal);
float[] allcorners = { dotTopLeft, dotTopRight, dotBottomLeft, dotBottomRight};
float largest = allcorners.Max();
float smallest = allcorners.Min();
float dotTopLeft2 = Vector2.Dot(rect.topLeft, normal);
float dotTopRight2 = Vector2.Dot(rect.topRight, normal);
float dotBottomLeft2 = Vector2.Dot(rect.bottomLeft, normal);
float dotBottomRight2 = Vector2.Dot(rect.bottomRight, normal);
float[] allcorners2 = { dotTopLeft2, dotTopRight2, dotBottomLeft2, dotBottomRight2 };
float largest2 = allcorners2.Max();
float smallest2 = allcorners2.Min();
if (largest2 > smallest || largest < smallest2)
{
return true;
}
else return false;
}
public void Move(Vector2 movedir)
{
topLeft += movedir;
topRight += movedir;
bottomLeft += movedir;
bottomRight += movedir;
}
public void MoveTo(Vector2 moveTo, Vector2 source)
{ //note that this moves relative to a center position.
float currentRot = GetCurrentRotation();
RotateTo(source, 0);
topLeft = moveTo - (size / 2);
bottomRight = moveTo + (size / 2);
topRight = new Vector2(moveTo.X + (size.X / 2), moveTo.Y - (size.Y / 2));
bottomLeft = new Vector2(moveTo.X - (size.X / 2), moveTo.Y + (size.Y / 2));
Rotate(source, currentRot);
}
public void MoveTo(Vector2 moveTo)
{ //note that this moves relative to a center position.
topLeft = moveTo - (size / 2);
bottomRight = moveTo + (size / 2);
topRight = new Vector2(moveTo.X + (size.X / 2), moveTo.Y - (size.Y / 2));
bottomLeft = new Vector2(moveTo.X - (size.X / 2), moveTo.Y + (size.Y / 2));
}
public void Rotate(Vector2 source, float angle)
{
Matrix rotateMatrix = Matrix.CreateRotationZ(MathHelper.ToRadians(angle));
Vector2 topLeftR = Vector2.Transform(topLeft - source, rotateMatrix); //Rotate relative to origin
topLeft = topLeftR + source; //Move it back to original position
Vector2 bottomLeftR = Vector2.Transform(bottomLeft - source, rotateMatrix);
bottomLeft = bottomLeftR + source;
Vector2 topRightR = Vector2.Transform(topRight - source, rotateMatrix);
topRight = topRightR + source;
Vector2 bottomRightR = Vector2.Transform(bottomRight - source, rotateMatrix);
bottomRight = bottomRightR + source;
}
public void RotateTo(Vector2 source, float angle)
{
float angleDist = GetCurrentRotation() - angle;
Matrix rotateMatrix = Matrix.CreateRotationZ(MathHelper.ToRadians(angleDist));
Vector2 topLeftR = Vector2.Transform(topLeft - source, rotateMatrix); //Rotate relative to origin
topLeft = topLeftR + source; //Move it back to original position
Vector2 bottomLeftR = Vector2.Transform(bottomLeft - source, rotateMatrix);
bottomLeft = bottomLeftR + source;
Vector2 topRightR = Vector2.Transform(topRight - source, rotateMatrix);
topRight = topRightR + source;
Vector2 bottomRightR = Vector2.Transform(bottomRight - source, rotateMatrix);
bottomRight = bottomRightR + source;
}
public static RotateableRectangle Rotate(RotateableRectangle rect, Vector2 source, float angle)
{
Matrix rotateMatrix = Matrix.CreateRotationZ(MathHelper.ToRadians(angle));
rect.topLeft = Vector2.Transform(source, rotateMatrix);
rect.bottomLeft = Vector2.Transform(source, rotateMatrix);
rect.topRight = Vector2.Transform(source, rotateMatrix);
rect.bottomRight = Vector2.Transform(source, rotateMatrix);
return rect;
}
public float GetCurrentRotation()
{
Vector2 midCheck = VectorHelper.GetMidPoint(topLeft, topRight); //Get the midpoint
Vector2 normal = VectorHelper.GetNormal(topLeft, topRight) * 32;//Get the normal, multiply by 32 for safety's sake
float a = VectorHelper.GetAngleBetweenPoints(midCheck, midCheck + normal);//Get the angle between the midpoint and the normal added to the midpoint (since normal is a scalar vector)
return a;
}
public static float GetRectRotation(RotateableRectangle rect)
{
Vector2 midCheck = VectorHelper.GetMidPoint(rect.topLeft, rect.topRight); //Get the midpoint
Vector2 normal = VectorHelper.GetNormal(rect.topLeft, rect.topRight) * 32;//Get the normal, multiply by 32 for safety's sake
float a = VectorHelper.GetAngleBetweenPoints(midCheck, midCheck + normal);//Get the angle between the midpoint and the normal added to the midpoint (since normal is a scalar vector)
return a;
}
public void DebugDraw(SpriteBatch batch)
{
DrawGeometry.DrawLine(batch, topLeft, topRight, Color.OrangeRed, 1);
DrawGeometry.DrawLine(batch, topRight, bottomRight, Color.OrangeRed, 1);
DrawGeometry.DrawLine(batch, bottomRight, bottomLeft, Color.OrangeRed, 1);
DrawGeometry.DrawLine(batch, topLeft, bottomLeft, Color.OrangeRed, 1);
DrawGeometry.DrawLine(batch, center, bottomRight, Color.Red);
}
public Rectangle ToRectangle()
{
return new Rectangle(topLeft.ToPoint(), new Point((int)width, (int)height));
}
}
}