Line data Source code
1 : /**
2 : Copyright 2013 BlackBerry Inc.
3 : Copyright (c) 2014-2015 Chukong Technologies
4 : Copyright (c) 2017-2022 Roman Katuntsev <sbkarr@stappler.org>
5 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
6 :
7 : Licensed under the Apache License, Version 2.0 (the "License");
8 : you may not use this file except in compliance with the License.
9 : You may obtain a copy of the License at
10 :
11 : http://www.apache.org/licenses/LICENSE-2.0
12 :
13 : Unless required by applicable law or agreed to in writing, software
14 : distributed under the License is distributed on an "AS IS" BASIS,
15 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 : See the License for the specific language governing permissions and
17 : limitations under the License.
18 :
19 : Original file from GamePlay3D: http://gameplay3d.org
20 :
21 : This file was modified to fit the cocos2d-x project
22 : This file was modified for stappler project
23 : */
24 :
25 : #ifndef STAPPLER_GEOM_SPVEC2_H_
26 : #define STAPPLER_GEOM_SPVEC2_H_
27 :
28 : #include "SPGeom.h"
29 :
30 : namespace STAPPLER_VERSIONIZED stappler::geom {
31 :
32 : class Mat4;
33 : struct Size2;
34 : struct Extent2;
35 :
36 : class Vec2 {
37 : public:
38 : static constexpr size_t Dimansions = 2;
39 :
40 : static const Vec2 ZERO;
41 : static const Vec2 ONE;
42 : static const Vec2 UNIT_X;
43 : static const Vec2 UNIT_Y;
44 :
45 269731 : static constexpr void add(const Vec2 &v1, const Vec2 &v2, Vec2 *dst) {
46 269731 : dst->x = v1.x + v2.x; dst->y = v1.y + v2.y;
47 269731 : }
48 :
49 3463979 : static constexpr void subtract(const Vec2 &v1, const Vec2 &v2, Vec2 *dst) {
50 3463979 : dst->x = v1.x - v2.x; dst->y = v1.y - v2.y;
51 3463979 : }
52 :
53 10 : static constexpr void scale(const Vec2 &v1, const Vec2 &v2, Vec2 *dst) {
54 10 : dst->x = v1.x * v2.x; dst->y = v1.y * v2.y;
55 10 : }
56 :
57 : static constexpr void unscale(const Vec2& v1, const Vec2 &v2, Vec2 *dst) {
58 : dst->x = v1.x / v2.x; dst->y = v1.y / v2.y;
59 : }
60 :
61 : static constexpr float cross(const Vec2 &v1, const Vec2 &v2) {
62 : return v1.x * v2.y - v1.y * v2.x;
63 : }
64 :
65 50 : static constexpr float dot(const Vec2 &v1, const Vec2 &v2) {
66 50 : return v1.x * v2.x + v1.y * v2.y;
67 : }
68 :
69 : static float angle(const Vec2& v1, const Vec2& v2);
70 :
71 : /** Clamps the specified vector within the specified range and returns it in dst. */
72 : static void clamp(const Vec2& v, const Vec2& min, const Vec2& max, Vec2* dst);
73 :
74 300 : static constexpr Vec2 forAngle(const float a) {
75 300 : return Vec2(cosf(a), sinf(a));
76 : }
77 :
78 : /** A general line-line intersection test
79 : @param A the startpoint for the first line L1 = (A - B)
80 : @param B the endpoint for the first line L1 = (A - B)
81 : @param C the startpoint for the second line L2 = (C - D)
82 : @param D the endpoint for the second line L2 = (C - D)
83 : @param S the range for a hitpoint in L1 (p = A + S*(B - A))
84 : @param T the range for a hitpoint in L2 (p = C + T*(D - C))
85 : @returns whether these two lines interects. */
86 : static bool isLineIntersect(const Vec2 &A, const Vec2 &B, const Vec2 &C, const Vec2 &D,
87 : float *S = nullptr, float *T = nullptr);
88 :
89 : static bool isLineOverlap(const Vec2 &A, const Vec2 &B, const Vec2 &C, const Vec2 &D);
90 :
91 : static bool isLineParallel(const Vec2 &A, const Vec2 &B, const Vec2 &C, const Vec2 &D);
92 :
93 : static bool isSegmentOverlap(const Vec2 &A, const Vec2 &B, const Vec2 &C, const Vec2 &D,
94 : Vec2 *S = nullptr, Vec2 *E = nullptr);
95 :
96 : static bool isSegmentIntersect(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& D);
97 : static Vec2 getIntersectPoint(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& D);
98 :
99 : template <typename Callback>
100 : static bool getSegmentIntersectPoint(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& D, const Callback &);
101 :
102 : static bool isCounterClockwise(const Vec2 &u, const Vec2 &v, const Vec2 &w);
103 :
104 : template <typename Functor>
105 : static constexpr std::bitset<2> bitop(const Vec2& v, const Functor &f) {
106 : std::bitset<2> ret;
107 : ret.set(0, f(v.x));
108 : ret.set(1, f(v.y));
109 : return ret;
110 : }
111 :
112 : template <typename Functor>
113 : static constexpr std::bitset<2> bitop(const Vec2& v1, const Vec2& v2, const Functor &f) {
114 : std::bitset<2> ret;
115 : ret.set(0, f(v1.x, v2.x));
116 : ret.set(1, f(v1.y, v2.y));
117 : return ret;
118 : }
119 :
120 : static constexpr Vec2 fill(float v) {
121 : return Vec2(v, v);
122 : }
123 :
124 : float x;
125 : float y;
126 :
127 39458800 : constexpr Vec2() : x(0.0f), y(0.0f) { }
128 431182172 : constexpr Vec2(float xx, float yy) : x(xx), y(yy) { }
129 :
130 : constexpr Vec2(const Vec2 &p1, const Vec2 &p2) : x(p2.x - p1.x), y(p2.y - p1.y) { }
131 :
132 : template <typename Functor>
133 50 : constexpr Vec2(const Vec2 &v, const Functor &f) : x(f(v.x)), y(f(v.y)) { }
134 :
135 : template <typename Functor>
136 : constexpr Vec2(const Vec2 &v1, const Vec2 &v2, const Functor &f) : x(f(v1.x, v2.x)), y(f(v1.y, v2.y)) { }
137 :
138 : constexpr Vec2(const Vec2 ©) = default;
139 :
140 : explicit Vec2(const Size2 &);
141 : explicit Vec2(const Extent2 &);
142 :
143 10246802 : constexpr bool isValid() const { return !std::isnan(x) && !std::isnan(y); }
144 :
145 : constexpr void add(const float &v) {
146 : x += v; y += v;
147 : }
148 :
149 13320 : constexpr void add(const Vec2 &v) {
150 13320 : x += v.x; y += v.y;
151 13320 : }
152 :
153 : constexpr void subtract(const float &v) {
154 : x -= v; y -= v;
155 : }
156 :
157 : constexpr void subtract(const Vec2 &v) {
158 : x -= v.x; y -= v.y;
159 : }
160 :
161 366668 : constexpr void scale(const float &v) {
162 366668 : x *= v; y *= v;
163 366668 : }
164 :
165 : constexpr void scale(const Vec2 &v) {
166 : x *= v.x; y *= v.y;
167 : }
168 :
169 154 : constexpr void unscale(const float &v) {
170 154 : x /= v; y /= v;
171 154 : }
172 :
173 : constexpr void unscale(const Vec2 &v) {
174 : x /= v.x; y /= v.y;
175 : }
176 :
177 : void clamp(const Vec2& min, const Vec2& max);
178 :
179 9344 : constexpr float distanceSquared(const Vec2& v) const {
180 9344 : const float dx = v.x - x;
181 9344 : const float dy = v.y - y;
182 9344 : return (dx * dx + dy * dy);
183 : }
184 :
185 2398 : constexpr float lengthSquared() const {
186 2398 : return (x * x + y * y);
187 : }
188 :
189 1826 : constexpr float distance(const Vec2& other) const {
190 1826 : return std::sqrt(distanceSquared(other));
191 : }
192 :
193 2398 : constexpr float length() const {
194 2398 : return std::sqrt(lengthSquared());
195 : }
196 :
197 : constexpr bool isWithinDistance(const Vec2& v, float val) const {
198 : return distanceSquared(v) < val * val;
199 : }
200 :
201 75 : constexpr float dot(const Vec2& v) const { return (x * v.x + y * v.y); }
202 :
203 25 : constexpr float cross(const Vec2& v) const { return x * v.y - y * v.x; }
204 :
205 341125 : constexpr void negate() { x = -x; y = -y; }
206 :
207 : constexpr Vec2 & normalize();
208 :
209 : Vec2 getNormalized() const;
210 :
211 419884544 : constexpr bool fuzzyEquals(const Vec2& b, float var = NumericLimits<float>::epsilon()) const {
212 419884544 : return (x - var <= b.x && b.x <= x + var) && (y - var <= b.y && b.y <= y + var);
213 : }
214 :
215 25 : constexpr float getAngle() const {
216 25 : return std::atan2(y, x);
217 : }
218 :
219 : /** Calculates perpendicular of v, rotated 90 degrees counter-clockwise -- cross(v, perp(v)) >= 0 */
220 : constexpr Vec2 getPerp() const {
221 : return Vec2(-y, x);
222 : }
223 :
224 105 : constexpr Vec2 getMidpoint(const Vec2& other) const {
225 105 : return Vec2((x + other.x) / 2.0f, (y + other.y) / 2.0f);
226 : }
227 :
228 : constexpr Vec2 getClampPoint(const Vec2& min_inclusive, const Vec2& max_inclusive) const {
229 : return Vec2(math::clamp(x,min_inclusive.x,max_inclusive.x), math::clamp(y, min_inclusive.y, max_inclusive.y));
230 : }
231 :
232 : /** Calculates perpendicular of v, rotated 90 degrees clockwise -- cross(v, rperp(v)) <= 0 */
233 350050 : constexpr Vec2 getRPerp() const { return Vec2(y, -x); }
234 :
235 : /** Calculates the projection of this over other. */
236 : constexpr Vec2 project(const Vec2& other) const;
237 :
238 : /** Complex multiplication of two points ("rotates" two points).
239 : @return Vec2 vector with an angle of this.getAngle() + other.getAngle(),
240 : and a length of this.getLength() * other.getLength(). */
241 25 : constexpr Vec2 rotate(const Vec2& other) const {
242 25 : return Vec2(x*other.x - y*other.y, x*other.y + y*other.x);
243 : }
244 :
245 : /** Unrotates two points.
246 : @return Vec2 vector with an angle of this.getAngle() - other.getAngle(),
247 : and a length of this.getLength() * other.getLength(). */
248 : constexpr Vec2 unrotate(const Vec2& other) const {
249 : return Vec2(x*other.x + y*other.y, y*other.x - x*other.y);
250 : }
251 :
252 : float getAngle(const Vec2& other) const;
253 : Vec2 rotateByAngle(const Vec2& pivot, float angle) const;
254 :
255 : void rotate(const Vec2& point, float angle);
256 :
257 : constexpr Vec2& operator+=(const float &v) {
258 : add(v);
259 : return *this;
260 : }
261 :
262 13320 : constexpr Vec2& operator+=(const Vec2& v) {
263 13320 : add(v);
264 13320 : return *this;
265 : }
266 :
267 : constexpr Vec2& operator-=(const float &v) {
268 : subtract(v);
269 : return *this;
270 : }
271 :
272 : constexpr Vec2& operator-=(const Vec2& v) {
273 : subtract(v);
274 : return *this;
275 : }
276 :
277 : constexpr Vec2& operator*=(const float &v) {
278 : scale(v);
279 : return *this;
280 : }
281 :
282 : constexpr Vec2& operator*=(const Vec2 &s) {
283 : scale(s);
284 : return *this;
285 : }
286 :
287 109 : constexpr Vec2& operator/=(const float &v) {
288 109 : unscale(v);
289 109 : return *this;
290 : }
291 :
292 : constexpr Vec2& operator/=(const Vec2 &s) {
293 : unscale(s);
294 : return *this;
295 : }
296 :
297 : SP_THREE_WAY_COMPARISON_FRIEND_CONSTEXPR(Vec2)
298 : };
299 :
300 350125 : constexpr inline Vec2 & Vec2::normalize() {
301 350125 : float n = x * x + y * y;
302 : // Already normalized.
303 350125 : if (n == 1.0f) {
304 0 : return *this;
305 : }
306 :
307 345350 : n = std::sqrt(n);
308 : // Too close to zero.
309 345350 : if (n < math::MATH_TOLERANCE) {
310 0 : return *this;
311 : }
312 :
313 344475 : n = 1.0f / n;
314 344475 : x *= n;
315 344475 : y *= n;
316 :
317 344475 : return *this;
318 : }
319 :
320 : #ifndef __LCC__
321 :
322 : constexpr const Vec2 Vec2::ZERO(0.0f, 0.0f);
323 : constexpr const Vec2 Vec2::ONE(1.0f, 1.0f);
324 : constexpr const Vec2 Vec2::UNIT_X(1.0f, 0.0f);
325 : constexpr const Vec2 Vec2::UNIT_Y(0.0f, 1.0f);
326 :
327 : #endif
328 :
329 269731 : constexpr inline const Vec2 operator+(const Vec2 &l, const Vec2 &r) {
330 269731 : Vec2 result;
331 269731 : Vec2::add(l, r, &result);
332 269731 : return result;
333 : }
334 :
335 : constexpr inline const Vec2 operator+(const Vec2 &l, const float &r) {
336 : Vec2 result(l);
337 : result.add(r);
338 : return result;
339 : }
340 :
341 : constexpr inline const Vec2 operator+(const float &l, const Vec2 &r) {
342 : Vec2 result(r);
343 : result.add(l);
344 : return result;
345 : }
346 :
347 3464631 : constexpr inline const Vec2 operator-(const Vec2 &l, const Vec2 &r) {
348 3464631 : Vec2 result;
349 3464631 : Vec2::subtract(l, r, &result);
350 3464989 : return result;
351 : }
352 :
353 : constexpr inline const Vec2 operator-(const Vec2 &l, const float &r) {
354 : Vec2 result(l);
355 : result.subtract(r);
356 : return result;
357 : }
358 :
359 10 : constexpr inline const Vec2 operator*(const Vec2 &l, const Vec2 &r) {
360 10 : Vec2 result;
361 10 : Vec2::scale(l, r, &result);
362 10 : return result;
363 : }
364 :
365 366668 : constexpr inline const Vec2 operator*(const Vec2 &l, const float &r) {
366 366668 : Vec2 result(l);
367 366668 : result.scale(r);
368 366668 : return result;
369 : }
370 :
371 : constexpr inline const Vec2 operator*(const float &l, const Vec2 &r) {
372 : Vec2 result(r);
373 : result.scale(l);
374 : return result;
375 : }
376 :
377 : constexpr inline const Vec2 operator/(const Vec2 &l, const Vec2 &r) {
378 : Vec2 result;
379 : Vec2::unscale(l, r, &result);
380 : return result;
381 : }
382 :
383 25 : constexpr inline const Vec2 operator/(const Vec2 &l, const float &r) {
384 25 : Vec2 result(l);
385 25 : result.unscale(r);
386 25 : return result;
387 : }
388 :
389 25 : constexpr Vec2 operator-(const Vec2& v) {
390 25 : Vec2 result(v);
391 25 : result.negate();
392 25 : return result;
393 : }
394 :
395 25 : constexpr inline Vec2 Vec2::project(const Vec2& other) const {
396 25 : return other * (dot(other)/other.dot(other));
397 : }
398 :
399 : namespace Anchor {
400 :
401 : constexpr const Vec2 Middle(0.5f, 0.5f);
402 : constexpr const Vec2 BottomLeft(0.0f, 0.0f);
403 : constexpr const Vec2 TopLeft(0.0f, 1.0f);
404 : constexpr const Vec2 BottomRight(1.0f, 0.0f);
405 : constexpr const Vec2 TopRight(1.0f, 1.0f);
406 : constexpr const Vec2 MiddleRight(1.0f, 0.5f);
407 : constexpr const Vec2 MiddleLeft(0.0f, 0.5f);
408 : constexpr const Vec2 MiddleTop(0.5f, 1.0f);
409 : constexpr const Vec2 MiddleBottom(0.5f, 0.0f);
410 :
411 : }
412 :
413 : inline std::basic_ostream<char> &
414 2100 : operator << (std::basic_ostream<char> & os, const Vec2 & vec) {
415 2100 : os << "(x: " << std::setprecision(std::numeric_limits<float>::digits10 + 3) << vec.x << "; y: " << vec.y << ")";
416 2100 : return os;
417 : }
418 :
419 : template <typename Callback>
420 : inline bool Vec2::getSegmentIntersectPoint(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& D, const Callback &cb) {
421 : float S, T;
422 :
423 : const auto minXAB = std::min(A.x, B.x);
424 : const auto minYAB = std::min(A.y, B.y);
425 :
426 : const auto minXCD = std::min(C.x, D.x);
427 : const auto minYCD = std::min(C.y, D.y);
428 :
429 : const auto maxXAB = std::max(A.x, B.x);
430 : const auto maxYAB = std::max(A.y, B.y);
431 :
432 : const auto internalBoxWidth = (maxXAB - minXAB) - (minXCD - minXAB);
433 : const auto internalBoxheight = (maxYAB - minYAB) - (minYCD - minYAB);
434 :
435 : if (internalBoxWidth > 0.0f && internalBoxheight > 0.0f) {
436 : if (isLineIntersect(A, B, C, D, &S, &T )&& (S > 0.0f && S < 1.0f && T > 0.0f && T < 1.0f)) {
437 : // Vec2 of intersection
438 : cb(Vec2(A.x + S * (B.x - A.x), A.y + S * (B.y - A.y)), S, T);
439 : return true;
440 : }
441 : }
442 :
443 : return false;
444 : }
445 :
446 3893519 : inline bool Vec2::isCounterClockwise(const Vec2 &u, const Vec2 &v, const Vec2 &w) {
447 3893519 : return (u.x * (v.y - w.y) + v.x * (w.y - u.y) + w.x * (u.y - v.y)) >= 0;
448 : }
449 :
450 : }
451 :
452 : #endif /* STAPPLER_GEOM_SPVEC2_H_ */
|