Line data Source code
1 : /**
2 : Copyright 2013 BlackBerry Inc.
3 : Copyright (c) 2017-2022 Roman Katuntsev <sbkarr@stappler.org>
4 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
5 :
6 : Licensed under the Apache License, Version 2.0 (the "License");
7 : you may not use this file except in compliance with the License.
8 : You may obtain a copy of the License at
9 :
10 : http://www.apache.org/licenses/LICENSE-2.0
11 :
12 : Unless required by applicable law or agreed to in writing, software
13 : distributed under the License is distributed on an "AS IS" BASIS,
14 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 : See the License for the specific language governing permissions and
16 : limitations under the License.
17 :
18 : Original file from GamePlay3D: http://gameplay3d.org
19 :
20 : This file was modified to fit the cocos2d-x project
21 : This file was modified for stappler project
22 : */
23 :
24 : #include "SPVec2.h"
25 : #include "SPGeometry.h"
26 :
27 : namespace STAPPLER_VERSIONIZED stappler::geom {
28 :
29 100 : static bool isOneDimensionSegmentOverlap(float A, float B, float C, float D, float *S, float * E) {
30 100 : const float ABmin = std::min(A, B);
31 100 : const float ABmax = std::max(A, B);
32 100 : const float CDmin = std::min(C, D);
33 100 : const float CDmax = std::max(C, D);
34 :
35 100 : if (ABmax < CDmin || CDmax < ABmin) {
36 : // ABmin->ABmax->CDmin->CDmax or CDmin->CDmax->ABmin->ABmax
37 0 : return false;
38 : } else {
39 100 : if (ABmin >= CDmin && ABmin <= CDmax) {
40 : // CDmin->ABmin->CDmax->ABmax or CDmin->ABmin->ABmax->CDmax
41 50 : if (S != nullptr) *S = ABmin;
42 50 : if (E != nullptr) *E = CDmax < ABmax ? CDmax : ABmax;
43 50 : } else if (ABmax >= CDmin && ABmax <= CDmax) {
44 : // ABmin->CDmin->ABmax->CDmax
45 25 : if (S != nullptr) *S = CDmin;
46 25 : if (E != nullptr) *E = ABmax;
47 : } else {
48 : // ABmin->CDmin->CDmax->ABmax
49 25 : if (S != nullptr) *S = CDmin;
50 25 : if (E != nullptr) *E = CDmax;
51 : }
52 100 : return true;
53 : }
54 : }
55 :
56 : // cross procuct of 2 vector. A->B X C->D
57 625 : static float crossProduct2Vector(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& D) {
58 625 : return (D.y - C.y) * (B.x - A.x) - (D.x - C.x) * (B.y - A.y);
59 : }
60 :
61 2294 : Vec2::Vec2(const Size2 &s) : x(s.width), y(s.height) { }
62 :
63 25 : Vec2::Vec2(const Extent2 &s) : x(s.width), y(s.height) { }
64 :
65 25 : float Vec2::angle(const Vec2& v1, const Vec2& v2) {
66 25 : const float dz = v1.x * v2.y - v1.y * v2.x;
67 25 : return atan2f(fabsf(dz) + math::MATH_FLOAT_SMALL, dot(v1, v2));
68 : }
69 :
70 50 : void Vec2::clamp(const Vec2& min, const Vec2& max) {
71 50 : assert(!(min.x > max.x || min.y > max.y ));
72 :
73 : // Clamp the x value.
74 50 : if (x < min.x) {
75 25 : x = min.x;
76 : }
77 :
78 50 : if (x > max.x) {
79 25 : x = max.x;
80 : }
81 :
82 : // Clamp the y value.
83 50 : if (y < min.y) {
84 25 : y = min.y;
85 : }
86 :
87 50 : if (y > max.y) {
88 25 : y = max.y;
89 : }
90 50 : }
91 :
92 50 : void Vec2::clamp(const Vec2& v, const Vec2& min, const Vec2& max, Vec2* dst) {
93 50 : assert(dst);
94 50 : assert(!(min.x > max.x || min.y > max.y ));
95 :
96 : // Clamp the x value.
97 50 : dst->x = v.x;
98 50 : if (dst->x < min.x) {
99 25 : dst->x = min.x;
100 : }
101 50 : if (dst->x > max.x) {
102 25 : dst->x = max.x;
103 : }
104 :
105 : // Clamp the y value.
106 50 : dst->y = v.y;
107 50 : if (dst->y < min.y) {
108 25 : dst->y = min.y;
109 : }
110 50 : if (dst->y > max.y) {
111 25 : dst->y = max.y;
112 : }
113 50 : }
114 :
115 75 : Vec2 Vec2::getNormalized() const {
116 75 : Vec2 v(*this);
117 75 : v.normalize();
118 75 : return v;
119 : }
120 :
121 50 : void Vec2::rotate(const Vec2& point, float angle) {
122 50 : const double sinAngle = sin(angle);
123 50 : const double cosAngle = cos(angle);
124 :
125 50 : if (point == Vec2::ZERO) {
126 25 : float tempX = x * cosAngle - y * sinAngle;
127 25 : y = y * cosAngle + x * sinAngle;
128 25 : x = tempX;
129 : } else {
130 25 : float tempX = x - point.x;
131 25 : float tempY = y - point.y;
132 :
133 25 : x = tempX * cosAngle - tempY * sinAngle + point.x;
134 25 : y = tempY * cosAngle + tempX * sinAngle + point.y;
135 : }
136 50 : }
137 :
138 25 : float Vec2::getAngle(const Vec2& other) const {
139 25 : Vec2 a2 = getNormalized();
140 25 : Vec2 b2 = other.getNormalized();
141 25 : const float angle = atan2f(a2.cross(b2), a2.dot(b2));
142 25 : if( fabs(angle) < NumericLimits<float>::epsilon() ) {
143 25 : return 0.f;
144 : }
145 0 : return angle;
146 : }
147 :
148 25 : Vec2 Vec2::rotateByAngle(const Vec2& pivot, float angle) const {
149 25 : return pivot + (*this - pivot).rotate(Vec2::forAngle(angle));
150 : }
151 :
152 125 : bool Vec2::isLineIntersect(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& D, float *S, float *T) {
153 : // FAIL: Line undefined
154 125 : if ( (A.x==B.x && A.y==B.y) || (C.x==D.x && C.y==D.y) ) {
155 0 : return false;
156 : }
157 :
158 125 : const float denom = crossProduct2Vector(A, B, C, D);
159 :
160 125 : if (denom == 0) {
161 : // Lines parallel or overlap
162 0 : return false;
163 : }
164 :
165 125 : if (S != nullptr) {
166 125 : *S = crossProduct2Vector(C, D, C, A) / denom;
167 : }
168 125 : if (T != nullptr) {
169 125 : *T = crossProduct2Vector(A, B, C, A) / denom;
170 : }
171 :
172 125 : return true;
173 : }
174 :
175 50 : bool Vec2::isLineParallel(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& D) {
176 : // FAIL: Line undefined
177 50 : if ( (A.x==B.x && A.y==B.y) || (C.x==D.x && C.y==D.y) ) {
178 0 : return false;
179 : }
180 :
181 50 : if (crossProduct2Vector(A, B, C, D) == 0) {
182 : // line overlap
183 0 : if (crossProduct2Vector(C, D, C, A) == 0 || crossProduct2Vector(A, B, C, A) == 0) {
184 0 : return false;
185 : }
186 :
187 0 : return true;
188 : }
189 :
190 50 : return false;
191 : }
192 :
193 150 : bool Vec2::isLineOverlap(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& D) {
194 : // FAIL: Line undefined
195 150 : if ( (A.x==B.x && A.y==B.y) || (C.x==D.x && C.y==D.y) ) {
196 0 : return false;
197 : }
198 :
199 150 : if (crossProduct2Vector(A, B, C, D) == 0 && (crossProduct2Vector(C, D, C, A) == 0 || crossProduct2Vector(A, B, C, A) == 0)) {
200 50 : return true;
201 : }
202 :
203 100 : return false;
204 : }
205 :
206 100 : bool Vec2::isSegmentOverlap(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& D, Vec2* S, Vec2* E) {
207 100 : if (isLineOverlap(A, B, C, D)) {
208 50 : return isOneDimensionSegmentOverlap(A.x, B.x, C.x, D.x, &S->x, &E->x)
209 50 : && isOneDimensionSegmentOverlap(A.y, B.y, C.y, D.y, &S->y, &E->y);
210 : }
211 :
212 50 : return false;
213 : }
214 :
215 50 : bool Vec2::isSegmentIntersect(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& D) {
216 : float S, T;
217 :
218 50 : if (isLineIntersect(A, B, C, D, &S, &T )&& (S >= 0.0f && S <= 1.0f && T >= 0.0f && T <= 1.0f)) {
219 25 : return true;
220 : }
221 :
222 25 : return false;
223 : }
224 :
225 25 : Vec2 Vec2::getIntersectPoint(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& D) {
226 : float S, T;
227 :
228 25 : if (isLineIntersect(A, B, C, D, &S, &T)) {
229 : // Vec2 of intersection
230 25 : Vec2 P;
231 25 : P.x = A.x + S * (B.x - A.x);
232 25 : P.y = A.y + S * (B.y - A.y);
233 25 : return P;
234 : }
235 :
236 0 : return Vec2(nan(), nan());
237 : }
238 :
239 : #ifdef __LCC__
240 :
241 : const Vec2 Vec2::ZERO(0.0f, 0.0f);
242 : const Vec2 Vec2::ONE(1.0f, 1.0f);
243 : const Vec2 Vec2::UNIT_X(1.0f, 0.0f);
244 : const Vec2 Vec2::UNIT_Y(0.0f, 1.0f);
245 :
246 : #endif
247 :
248 : }
|