1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include "[float2.h]"19 #include "[float3.h]"20 #include "[float4.h]"21 #include "[MathFunc.h]"22 #include "../Algorithm/Random/LCG.h"23 #include "[assume.h]"24 #include <string.h>25 #include <stdlib.h>26 #include <locale.h>27 28 #ifdef MATH_ENABLE_STL_SUPPORT29 #include "[myassert.h]"30 #include <iostream>31 #include <utility>32 #include <algorithm>33 #endif34 35 [MATH_BEGIN_NAMESPACE]36 37 using namespace std;38 39 [float2::float2](float x_, float y_)40 :x(x_), y(y_)41 {42 }43 44 [float2::float2](float scalar)45 :x(scalar), y(scalar)46 {47 }48 49 [float2::float2](const float *data)50 {51 [assume](data);52 #ifndef MATH_ENABLE_INSECURE_OPTIMIZATIONS53 if (!data)54 return;55 #endif56 [x] = data[0];57 [y] = data[1];58 }59 60 [CONST_WIN32] float [float2::At](int index) const61 {62 [assume](index >= 0);63 [assume](index < [Size]);64 #ifndef MATH_ENABLE_INSECURE_OPTIMIZATIONS65 if (index < 0 || index >= [Size])66 return [FLOAT_NAN];67 #endif68 return [ptr]()[index];69 }70 71 float &[float2::At](int index)72 {73 [assume](index >= 0);74 [assume](index < [Size]);75 #ifndef MATH_ENABLE_INSECURE_OPTIMIZATIONS76 if (index < 0 || index >= [Size])77 return [ptr]()[0];78 #endif79 return [ptr]()[index];80 }81 82 [float2] [float2::Swizzled](int i, int j) const83 {84 return [float2]([At](i), [At](j));85 }86 87 [float3] [float2::Swizzled](int i, int j, int k) const88 {89 return [float3]([At](i), [At](j), [At](k));90 }91 92 [float4] [float2::Swizzled](int i, int j, int k, int l) const93 {94 return [float4]([At](i), [At](j), [At](k), [At](l));95 }96 97 float [float2::LengthSq]() const98 {99 return [x]*[x] + [y]*[y];100 }101 102 float [float2::Length]() const103 {104 return [Sqrt]([LengthSq]());105 }106 107 void [float2::SetFromPolarCoordinates](float theta, float length)108 {109 float sin, cos;110 [SinCos](theta, sin, cos);111 [x] = cos * length;112 [y] = sin * length;113 }114 115 [float2] [float2::FromPolarCoordinates](float theta, float length)116 {117 [float2] euclidean;118 euclidean.[SetFromPolarCoordinates](theta, length);119 return euclidean;120 }121 122 [float2] [float2::ToPolarCoordinates]() const123 {124 float radius = [Length]();125 if (radius > 1[e]-4f)126 return [float2](atan2([y], [x]), radius);127 else128 return [float2::zero];129 }130 131 float [float2::AimedAngle]() const132 {133 [assume](![IsZero]());134 return atan2([y], [x]);135 }136 137 float [float2::Normalize]()138 {139 [assume]([IsFinite]());140 float lengthSq = [LengthSq]();141 if (lengthSq > 1[e]-6f)142 {143 float length = [Sqrt](lengthSq);144 *this *= 1.f / length;145 return length;146 }147 else148 {149 [Set](1.f, 0.f); 150 return 0; 151 }152 }153 154 [float2] [float2::Normalized]() const155 {156 [float2] copy = *this;157 float oldLength = copy.[Normalize]();158 [assume](oldLength > 0.f && "float2::Normalized() failed!");159 MARK_UNUSED(oldLength);160 return copy;161 }162 163 float [float2::ScaleToLength](float newLength)164 {165 float length = [LengthSq]();166 if (length < 1[e]-6f)167 return 0.f;168 169 length = [Sqrt](length);170 float scalar = newLength / length;171 [x] *= scalar;172 [y] *= scalar;173 return length;174 }175 176 [float2] [float2::ScaledToLength](float newLength) const177 {178 [assume](![IsZero]());179 180 [float2] v = *this;181 v.[ScaleToLength](newLength);182 return v;183 }184 185 bool [float2::IsNormalized](float epsilonSq) const186 {187 return [MATH_NS::Abs]([LengthSq]()-1.f) <= epsilonSq;188 }189 190 bool [float2::IsZero](float epsilonSq) const191 {192 return [LengthSq]() <= epsilonSq;193 }194 195 bool [float2::IsFinite]() const196 {197 return [MATH_NS::IsFinite]([x]) && [MATH_NS::IsFinite]([y]);198 }199 200 bool [float2::IsPerpendicular](const [float2] &other, float epsilonSq) const201 {202 float dot = [Dot](other);203 return dot*dot <= epsilonSq * [LengthSq]() * other.[LengthSq]();204 }205 206 bool [float2::Equals](const [float2] &rhs, float [epsilon]) const207 {208 return [EqualAbs]([x], rhs.[x], epsilon) && [EqualAbs]([y], rhs.[y], epsilon);209 }210 211 bool [float2::Equals](float x_, float y_, float [epsilon]) const212 {213 return [EqualAbs]([x], x_, epsilon) && [EqualAbs]([y], y_, epsilon);214 }215 216 bool [float2::BitEquals](const [float2] &other) const217 {218 return [ReinterpretAsU32]([x]) == [ReinterpretAsU32](other.[x]) &&219 [ReinterpretAsU32]([y]) == [ReinterpretAsU32](other.[y]);220 }221 222 223 224 225 bool [IsNeutralCLocale]()226 {227 228 229 #ifndef ANDROID230 lconv *lc = localeconv();231 if (strcmp(lc->decimal_point, "."))232 return false;233 #endif234 return true;235 }236 237 #ifdef MATH_ENABLE_STL_SUPPORT238 std::string [float2::ToString]() const239 {240 char str[256];241 sprintf(str, "(%f, %f)", [x], [y]);242 return std::string(str);243 }244 245 std::string [float2::SerializeToString]() const246 {247 char str[256];248 char *s = [SerializeFloat]([x], str); *s = ','; ++s;249 s = [SerializeFloat]([y], s);250 [assert](s+1 - str < 256);251 MARK_UNUSED(s);252 return str;253 }254 255 std::string [float2::SerializeToCodeString]() const256 {257 return "float2(" + [SerializeToString]() + ")";258 }259 #endif260 261 [float2] [float2::FromString](const char *str, const char **outEndStr)262 {263 [assert]([IsNeutralCLocale]());264 [assume](str);265 if (!str)266 return [float2::nan];267 [MATH_SKIP_WORD](str, "float2");268 [MATH_SKIP_WORD](str, "(");269 [float2] f;270 f.[x] = [DeserializeFloat](str, &str);271 f.[y] = [DeserializeFloat](str, &str);272 if (*str == ')')273 ++str;274 if (*str == ',')275 ++str;276 if (outEndStr)277 *outEndStr = str;278 return f;279 }280 281 float [float2::SumOfElements]() const282 {283 return [x] + [y];284 }285 286 float [float2::ProductOfElements]() const287 {288 return [x] * [y];289 }290 291 float [float2::AverageOfElements]() const292 {293 return ([x] + [y]) * 0.5f;294 }295 296 float [float2::MinElement]() const297 {298 return [MATH_NS::Min]([x], [y]);299 }300 301 int [float2::MinElementIndex]() const302 {303 return ([x] <= [y]) ? 0 : 1;304 }305 306 float [float2::MaxElement]() const307 {308 return [MATH_NS::Max]([x], [y]);309 }310 311 int [float2::MaxElementIndex]() const312 {313 return ([x] > [y]) ? 0 : 1;314 }315 316 [float2] [float2::Abs]() const317 {318 return [float2]([MATH_NS::Abs]([x]), [MATH_NS::Abs]([y]));319 }320 321 [float2] [float2::Neg]() const322 {323 return [float2](-[x], -[y]);324 }325 326 [float2] [float2::Recip]() const327 {328 return [float2](1.f/[x], 1.f/[y]);329 }330 331 [float2] [float2::Min](float floor) const332 {333 return [float2]([MATH_NS::Min]([x], floor), [MATH_NS::Min]([x], floor));334 }335 336 [float2] [float2::Min](const [float2] &floor) const337 {338 return [float2]([MATH_NS::Min]([x], floor.[x]), [MATH_NS::Min]([x], floor.[x]));339 }340 341 [float2] [float2::Max](float ceil) const342 {343 return [float2]([MATH_NS::Max]([x], ceil), [MATH_NS::Max]([x], ceil));344 }345 346 [float2] [float2::Max](const [float2] &ceil) const347 {348 return [float2]([MATH_NS::Max]([x], ceil.[x]), [MATH_NS::Max]([x], ceil.[x]));349 }350 351 [float2] [float2::Clamp](const [float2] &floor, const [float2] &ceil) const352 {353 return [float2]([MATH_NS::Clamp]([x], floor.[x], ceil.[x]), [MATH_NS::Clamp]([y], floor.[y], ceil.[y]));354 }355 356 [float2] [float2::Clamp](float floor, float ceil) const357 {358 return [float2]([MATH_NS::Clamp]([x], floor, ceil), [MATH_NS::Clamp]([y], floor, ceil));359 }360 361 [float2] [float2::Clamp01]() const362 {363 return [Clamp](0.f, 1.f);364 }365 366 float [float2::DistanceSq](const [float2] &rhs) const367 {368 float dx = [x] - rhs.[x];369 float dy = [y] - rhs.[y];370 return dx*dx + dy*dy;371 }372 373 float [float2::Distance](const [float2] &rhs) const374 {375 return [Sqrt]([DistanceSq](rhs));376 }377 378 float [float2::Dot](const [float2] &rhs) const379 {380 return [x] * rhs.[x] + [y] * rhs.[y];381 }382 383 [float2] [float2::Perp]() const384 {385 return [float2](-[y], [x]);386 }387 388 float [float2::PerpDot](const [float2] &rhs) const389 {390 return [x] * rhs.[y] - [y] * rhs.[x];391 }392 393 [float2] [float2::Reflect](const [float2] &normal) const394 {395 [assume2](normal.[IsNormalized](), normal.[SerializeToCodeString](), normal.[Length]());396 return 2.f * this->[ProjectToNorm](normal) - *this;397 }398 399 400 [float2] [float2::Refract](const [float2] &normal, float negativeSideRefractionIndex, float positiveSideRefractionIndex) const401 {402 403 float n = negativeSideRefractionIndex / positiveSideRefractionIndex;404 float cosI = this->[Dot](normal);405 float sinT2 = n*n*(1.f - cosI*cosI);406 if (sinT2 > 1.f) 407 return (-*this).Reflect(normal);408 return n * *this - (n + [Sqrt](1.f - sinT2)) * normal;409 }410 411 [float2] [float2::ProjectTo](const [float2] &direction) const412 {413 [assume](!direction.[IsZero]());414 return direction * this->[Dot](direction) / direction.[LengthSq]();415 }416 417 [float2] [float2::ProjectToNorm](const [float2] &direction) const418 {419 [assume](direction.[IsNormalized]());420 return direction * this->[Dot](direction);421 }422 423 float [float2::AngleBetween](const [float2] &other) const424 {425 return acos([Dot](other)) / [Sqrt]([LengthSq]() * other.[LengthSq]());426 }427 428 float [float2::AngleBetweenNorm](const [float2] &other) const429 {430 [assume](this->[IsNormalized]());431 [assume](other.[IsNormalized]());432 return acos([Dot](other));433 }434 435 [float2] [float2::Lerp](const [float2] &b, float t) const436 {437 [assume](0.f <= t && t <= 1.f);438 return (1.f - t) * *this + t * b;439 }440 441 [float2] [float2::Lerp](const [float2] &a, const [float2] &b, float t)442 {443 return a.[Lerp](b, t);444 }445 446 void [float2::Decompose](const [float2] &direction, [float2] &outParallel, [float2] &outPerpendicular) const447 {448 [assume](direction.[IsNormalized]());449 outParallel = this->[Dot](direction) * direction;450 outPerpendicular = *this - outParallel;451 }452 453 void [float2::Orthogonalize](const [float2] &a, [float2] &b)454 {455 [assume](!a.[IsZero]());456 b -= a.[Dot](b) / a.[Length]() * a;457 }458 459 bool [float2::AreOrthogonal](const [float2] &a, const [float2] &b, float [epsilon])460 {461 return a.[IsPerpendicular](b, epsilon);462 }463 464 465 void [float2::Orthonormalize]([float2] &a, [float2] &b)466 {467 [assume](!a.[IsZero]());468 a.[Normalize]();469 b -= a.[Dot](b) * a;470 }471 472 [float2] [float2::FromScalar](float scalar)473 {474 return [float2](scalar, scalar);475 }476 477 void [float2::SetFromScalar](float scalar)478 {479 [x] = scalar;480 [y] = scalar;481 }482 483 void [float2::Set](float x_, float y_)484 {485 [x] = x_;486 [y] = y_;487 }488 489 void [float2::Rotate90CW]()490 {491 float oldX = [x];492 [x] = [y];493 [y] = -oldX;494 }495 496 [float2] [float2::Rotated90CW]() const497 {498 return [float2]([y], -[x]);499 }500 501 void [float2::Rotate90CCW]()502 {503 float oldX = [x];504 [x] = -[y];505 [y] = oldX;506 }507 508 [float2] [float2::Rotated90CCW]() const509 {510 return [float2](-[y], [x]);511 }512 513 bool [float2::OrientedCCW](const [float2] &a, const [float2] &b, const [float2] &c)514 {515 516 517 518 519 520 return (a.[x]-c.[x])*(b.[y]-c.[y]) - (a.[y]-c.[y])*(b.[x]-c.[x]) >= 0.f;521 }522 523 class [SortByPolarAngle]524 {525 public:526 [float2] [perspective];527 528 bool [operator()](const [float2] &a, const [float2] &b) const529 {530 [float2] A = a - [perspective];531 [float2] B = b - [perspective];532 return B.[x]*A.[y] < A.[x]*B.[y];533 }534 };535 536 #ifdef MATH_ENABLE_STL_SUPPORT537 void [float2::ConvexHull](const [float2] *pointArray, int numPoints, std::vector<float2> &outConvexHull)538 {539 outConvexHull.clear();540 if (numPoints == 0)541 return;542 outConvexHull.insert(outConvexHull.end(), pointArray, pointArray + numPoints);543 int convexHullSize = [ConvexHullInPlace](&outConvexHull[0], (int)outConvexHull.size());544 outConvexHull.resize(convexHullSize);545 }546 #endif547 548 #ifdef MATH_ENABLE_STL_SUPPORT549 550 551 552 553 int [float2::ConvexHullInPlace]([float2] *p, int n)554 {555 if (n <= 2)556 return n;557 558 if (n >= 50)559 {560 561 562 563 564 565 566 567 568 569 570 int minX = 0, minY = 0, maxX = 0, maxY = 0;571 for(int i = 1; i < n; ++i)572 {573 if (p[i].[x] < p[minX].[x]) minX = i;574 else if (p[i].x > p[maxX].x) maxX = i;575 if (p[i].[y] < p[minY].[y]) minY = i;576 else if (p[i].y > p[maxY].y) maxY = i;577 }578 579 [float2] e0 = (p[maxX] - p[minY]).[Rotated90CCW]();580 [float2] e1 = (p[maxY] - p[maxX]).[Rotated90CCW]();581 [float2] [e2] = (p[minX] - p[maxY]).[Rotated90CCW]();582 [float2] e3 = (p[minY] - p[minX]).[Rotated90CCW]();583 584 585 586 const float [eps] = 1[e]-6f;587 float e0_d = e0.[Dot](p[minY]) + [eps];588 float e1_d = e1.[Dot](p[maxX]) + [eps];589 float e2_d = e2.[Dot](p[maxY]) + [eps];590 float e3_d = e3.[Dot](p[minX]) + [eps];591 592 for(int i = 0; i < n; ++i)593 if (e0.[Dot](p[i]) > e0_d && e1.[Dot](p[i]) > e1_d && e2.[Dot](p[i]) > e2_d && e3.[Dot](p[i]) > e3_d)594 [Swap](p[i--], p[--n]);595 }596 597 598 [SortByPolarAngle] pred;599 pred.[perspective] = p[0];600 int smallestY = 0;601 for(int i = 1; i < n; ++i)602 if (p[i].y < pred.[perspective].[y] || (p[i].[y] == pred.[perspective].[y] && p[i].[x] < pred.[perspective].[x]))603 {604 pred.[perspective] = p[i];605 smallestY = i;606 }607 [Swap](p[0], p[smallestY]);608 609 610 611 612 int [d] = 0;613 for(int i = 1; i < n; ++i)614 if (!p[i].[Equals](p[0]))615 p[++[d]] = p[i];616 n = d+1;617 618 std::sort(&p[1], &p[n], pred);619 620 621 d = 0;622 for(int i = 1; i < n; ++i)623 if (!p[i].[Equals](p[d]))624 p[++[d]] = p[i];625 n = d+1;626 627 int h = 1; 628 629 [float2] a = p[h] - p[h-1];630 const float epsilon = 1[e]-5f;631 for(int i = 2; i < n; ++i)632 {633 634 [float2] d = p[i] - p[h-1];635 float dir = d.[x]*a.[y] - d.[y]*a.[x];636 637 638 while(dir > epsilon || (dir > -epsilon && d.[Dot](d) >= a.[Dot](a)))639 {640 --h;641 if (h >= 1)642 {643 a = p[h] - p[h-1];644 d = p[i] - p[h-1];645 dir = d.[x]*a.[y] - d.[y]*a.[x];646 }647 else648 break;649 }650 p[++h] = p[i];651 a = p[i] - p[h-1];652 }653 654 655 return h+1;656 }657 658 bool [float2::ConvexHullContains](const [float2] *convexHull, int numPointsInConvexHull, const [float2] &point)659 {660 int j = numPointsInConvexHull-1;661 for(int i = 0; i < numPointsInConvexHull; ++i)662 {663 [float2] d = (convexHull[i] - convexHull[j]).[Rotated90CCW](); 664 [float2] n = point - convexHull[j];665 if (n.[IsZero]()) return true;666 if (n.[Dot](d) < 0.f)667 return false;668 j = i;669 }670 return true;671 }672 673 #endif674 675 #define NEXT_P(ptr) ((ptr)+1 < (pEnd) ? (ptr)+1 : (p))676 677 float [float2::MinAreaRectInPlace]([float2] *p, int n, [float2] ¢er, [float2] &uDir, [float2] &vDir, float &minU, float &maxU, float &minV, float &maxV)678 {679 [assume](p || n == 0);680 if (!p)681 return 0.f;682 683 684 685 n = [float2::ConvexHullInPlace](p, n);686 687 688 [float2] *[e][4] = { p, p, p, p };689 690 691 692 693 for(int i = 1; i < n; ++i)694 {695 if (p[i].x < e[0]->x) e[0] = &p[i];696 else if (p[i].x > e[2]->x) e[2] = &p[i];697 if (p[i].y < e[1]->y) e[1] = &p[i];698 else if (p[i].y > e[3]->y) e[3] = &p[i];699 }700 701 702 703 704 [float2] ed = -[float2::unitY];705 float minArea = [FLOAT_INF]; 706 const [float2] * const pEnd = p + n; 707 708 709 [float2] d[4];710 d[0] = (*[NEXT_P](e[0]) - *e[0]).[Normalized]();711 d[1] = (*[NEXT_P](e[1]) - *e[1]).[Normalized]();712 d[2] = (*[NEXT_P](e[2]) - *e[2]).[Normalized]();713 d[3] = (*[NEXT_P](e[3]) - *e[3]).[Normalized]();714 715 716 717 while(ed.[y] <= 0.f)718 {719 720 float cosA0 = ed.[Dot](d[0]);721 float cosA1 = ed.[PerpDot](d[1]);722 float cosA2 = -ed.[Dot](d[2]);723 float cosA3 = -ed.[PerpDot](d[3]);724 725 float maxCos = [MATH_NS::Max]([MATH_NS::Max](cosA0, cosA1), [MATH_NS::Max](cosA2, cosA3));726 727 if (cosA0 >= maxCos) { ed = d[0]; e[0] = [NEXT_P](e[0]); d[0] = (*[NEXT_P](e[0]) - *e[0]).[Normalized](); }728 else if (cosA1 >= maxCos) { ed = d[1].[Rotated90CW](); e[1] = [NEXT_P](e[1]); d[1] = (*[NEXT_P](e[1]) - *e[1]).[Normalized](); }729 else if (cosA2 >= maxCos) { ed = -d[2]; e[2] = [NEXT_P](e[2]); d[2] = (*[NEXT_P](e[2]) - *e[2]).[Normalized](); }730 else { ed = d[3].[Rotated90CCW](); e[3] = [NEXT_P](e[3]); d[3] = (*[NEXT_P](e[3]) - *e[3]).[Normalized](); }731 732 733 float minu = ed.[PerpDot](*e[0]);734 float maxu = ed.[PerpDot](*e[2]);735 float minv = ed.[Dot](*e[1]);736 float maxv = ed.[Dot](*e[3]);737 738 float area = [MATH_NS::Abs]((maxu-minu) * (maxv-minv));739 if (area < minArea)740 {741 vDir = ed;742 minArea = area;743 minU = [MATH_NS::Min](minu, maxu);744 maxU = [MATH_NS::Max](minu, maxu);745 minV = [MATH_NS::Min](minv, maxv);746 maxV = [MATH_NS::Max](minv, maxv);747 }748 }749 uDir = vDir.[Rotated90CCW]();750 center = 0.5f * (uDir * (minU+maxU) + vDir * (minV+maxV));751 752 return minArea;753 }754 755 [float2] [float2::RandomDir]([LCG] &lcg, float r)756 {757 [assume](r > 1e-3f);758 for(int i = 0; i < 1000; ++i)759 {760 float x = lcg.[Float](-r, r);761 float y = lcg.[Float](-r, r);762 float lenSq = x*x + y*[y];763 if (lenSq >= 1e-6f && lenSq <= r*r)764 return r / [Sqrt](lenSq) * [float2](x,y);765 }766 [assume](false && "Failed to generate a random float2 direction vector!");767 return [float2](r, 0);768 }769 770 [MUST_USE_RESULT] [float2] [float2::RandomBox]([LCG] &lcg, float minElem, float maxElem)771 {772 float x = lcg.[Float](minElem, maxElem);773 float y = lcg.[Float](minElem, maxElem);774 return [float2](x, y);775 }776 777 [float2] [float2::operator +](const [float2] &rhs) const778 {779 return [float2](x + rhs.[x], y + rhs.[y]);780 }781 782 [float2] [float2::operator -](const [float2] &rhs) const783 {784 return [float2](x - rhs.[x], y - rhs.[y]);785 }786 787 [float2] [float2::operator -]() const788 {789 return [float2](-x, -y);790 }791 792 [float2] [float2::operator *](float scalar) const793 {794 return [float2](x * scalar, y * scalar);795 }796 797 [float2] [operator *](float scalar, const [float2] &rhs)798 {799 return [float2](scalar * rhs.[x], scalar * rhs.[y]);800 }801 802 [float2] [float2::operator /](float scalar) const803 {804 float invScalar = 1.f / scalar;805 return [float2](x * invScalar, y * invScalar);806 }807 808 [float2] &[float2::operator +=](const [float2] &rhs)809 {810 x += rhs.[x];811 y += rhs.[y];812 813 return *this;814 }815 816 [float2] &[float2::operator -=](const [float2] &rhs)817 {818 x -= rhs.[x];819 y -= rhs.[y];820 821 return *this;822 }823 824 [float2] &[float2::operator *=](float scalar)825 {826 x *= scalar;827 y *= scalar;828 829 return *this;830 }831 832 [float2] [float2::Add](float s) const833 {834 return [float2](x + s, y + s);835 }836 837 [float2] [float2::Sub](float s) const838 {839 return [float2](x - s, y - s);840 }841 842 [float2] [float2::SubLeft](float s) const843 {844 return [float2](s - x, s - y);845 }846 847 [float2] [float2::DivLeft](float s) const848 {849 return [float2](s / x, s / y);850 }851 852 [float2] [float2::Mul](const [float2] &rhs) const853 {854 return [float2](x * rhs.[x], y * rhs.[y]);855 }856 857 [float2] [float2::Div](const [float2] &rhs) const858 {859 return [float2](x / rhs.[x], y / rhs.[y]);860 }861 862 [float2] &[float2::operator /=](float scalar)863 {864 float invScalar = 1.f / scalar;865 x *= invScalar;866 y *= invScalar;867 868 return *this;869 }870 871 #ifdef MATH_ENABLE_STL_SUPPORT872 std::ostream &[operator <<](std::ostream &out, const [float2] &rhs)873 {874 std::string str = rhs.[ToString]();875 out << str;876 return out;877 }878 #endif879 880 const [float2] [float2::zero] = [float2](0, 0);881 const [float2] [float2::one] = [float2](1, 1);882 const [float2] [float2::unitX] = [float2](1, 0);883 const [float2] [float2::unitY] = [float2](0, 1);884 const [float2] [float2::nan] = [float2]([FLOAT_NAN], [FLOAT_NAN]);885 const [float2] [float2::inf] = [float2]([FLOAT_INF], [FLOAT_INF]);886 887 [MATH_END_NAMESPACE] Go back to previous page