-
-
Notifications
You must be signed in to change notification settings - Fork 180
/
Copy pathMath.c
217 lines (177 loc) · 6.66 KB
/
Math.c
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
/*
* Copyright (c) scott.cgi All Rights Reserved.
*
* This source code belongs to project Mojoc, which is a pure C Game Engine hosted on GitHub.
* The Mojoc Game Engine is licensed under the MIT License, and will continue to be iterated with coding passion.
*
* License : https://github.com/scottcgi/Mojoc/blob/master/LICENSE
* GitHub : https://github.com/scottcgi/Mojoc
* CodeStyle: https://github.com/scottcgi/Mojoc/blob/master/Docs/CodeStyle.md
*
* Since : 2013-1-24
* Update : 2019-1-18
* Author : scott.cgi
*/
#include "Engine/Toolkit/Platform/Log.h"
#include "Engine/Toolkit/Math/Math.h"
/**
* Test polygon contains 2D point(x, y).
*
* first — foreach vector(preX - curX, preY - curY) of polygon
* second — check the point's y on the y area of vector
* third — cross product between vector(x - curX, y - curY) and vector(preX - curX, preY - curY)
* fourth — get the result is (x - curX) * (preY - curY) - (y - curY) * (preX - curX) = 0
* then —
*
* if result zero means point on the vector
* if result positive means point on the right of vector
* if result negative means point on the left of vector
*/
#define TestPolygonXY(polygon, x, y, pointOnRight, pointOnLeft) \
float* points = polygon->data; \
int preIndex = polygon->length - 2; \
\
for (int i = 0; i < polygon->length; i += 2) \
{ \
float curY = points[i + 1]; \
float preY = points[preIndex + 1]; \
\
if ((curY < y && preY >= y) || (preY < y && curY >= y)) \
{ \
float curX = points[i]; \
\
if (curX + (y - curY) / (preY - curY) * (points[preIndex] - curX) <= x) \
{ \
pointOnRight; \
} \
else \
{ \
pointOnLeft; \
} \
} \
\
preIndex = i; \
} \
static bool TestPolygonPoint(Array(float)* polygon, float x, float y)
{
bool inside = false;
TestPolygonXY
(
polygon,
x,
y,
// point on the right of polygon vector
inside = !inside,
);
return inside;
}
static bool TestPolygonAB(Array(float)* polygonA, Array(float)* polygonB)
{
bool inside = false;
for (int i = 0; i < polygonA->length; i += 2)
{
float x = AArray_Get(polygonA, i, float);
float y = AArray_Get(polygonA, i + 1, float);
TestPolygonXY
(
polygonB,
x,
y,
// point on the right of polygon vector
inside = !inside,
);
if (inside)
{
return true;
}
}
return inside;
}
static bool TestPolygonPolygon(Array(float)* polygonA, Array(float)* polygonB)
{
return TestPolygonAB(polygonA, polygonB) || TestPolygonAB(polygonB, polygonA);
}
static bool TestPolygonABStrict(Array(float)* polygonA, Array(float)* polygonB)
{
int leftCount = 0;
int rightCount = 0;
for (int i = 0; i < polygonA->length; i += 2)
{
float x = AArray_Get(polygonA, i, float);
float y = AArray_Get(polygonA, i + 1, float);
TestPolygonXY
(
polygonB,
x,
y,
// count point on the right of polygon vector
++rightCount,
// count point on the left of polygon vector
++leftCount
);
if (rightCount % 2 != 0)
{
return true;
}
}
return rightCount != 0 && leftCount == rightCount;
}
static bool TestPolygonPolygonStrict(Array(float)* polygonA, Array(float)* polygonB)
{
return TestPolygonABStrict(polygonA, polygonB) || TestPolygonABStrict(polygonB, polygonA);
}
static bool TestLineAB(Array(float)* lineA, Array(float)* lineB)
{
bool flags[2] = {false, false};
for (int i = 0; i < lineA->length; i += 2)
{
float x = AArray_Get(lineA, i, float);
float y = AArray_Get(lineA, i + 1, float);
TestPolygonXY
(
lineB,
x,
y,
// flag point on the right of line vector
flags[(unsigned int) i >> 1] = true,
// flag point on the left of line vector
flags[(unsigned int) i >> 1] = true
);
}
// test lineA two points both sides of lineB
return flags[0] && flags[1];
}
static bool TestLineLine(Array(float)* lineA, Array(float)* lineB)
{
return TestLineAB(lineA, lineB) || TestLineAB(lineB, lineA);
}
static void RotatePoints(Array(float)* pointArr, float angle, Array(float)* outRotatedPointArr)
{
ALog_A
(
outRotatedPointArr->length >= pointArr->length,
"AMath RotatePoints2 outRotatedPointArr length must larger than pointArr."
);
float cos = AMath_Cos(angle);
float sin = AMath_Sin(angle);
float* arr1 = (float*) pointArr->data;
float* arr2 = (float*) outRotatedPointArr->data;
for (int i = 0; i < pointArr->length; i += 2)
{
float x = arr1[i];
float y = arr1[i + 1];
arr2[i] = x * cos - y * sin;
arr2[i + 1] = x * sin + y * cos;
}
}
struct AMath AMath[1] =
{{
TestPolygonPoint,
TestPolygonAB,
TestPolygonPolygon,
TestPolygonABStrict,
TestPolygonPolygonStrict,
TestLineAB,
TestLineLine,
RotatePoints,
}};