dl
dl_math.h
浏览该文件的文档.
1
10#pragma once
11
12#include <numeric>
13#include <list>
14#include <version>
15#include <functional>
16
17#include "dl_type.h"
18#include "io/dl_log.h"
19#include "base/dl_concept.h"
20#include "dl_algorithm.h"
21#include "dl_range.h"
22
23
24#include "system/dl_platform.h"
25#if (DL_PLATFORM == DL_PLATFORM_WIN32)
26#include <numbers>
27#endif
28
30namespace dl::Numbers
31{
32 constexpr Float EARTH_fADIUS = 6371.393_f;
33 constexpr Float GRAVITY = 9.8_f;
34 constexpr Float EULER = 2.718281828459045_f;
35 constexpr Float RATIO_GOLD = 0.618033988749894_f;
36 constexpr Float SQRT_2 = 1.41421356237_f;
37 constexpr Float PI = 3.1415926536_f;
38}
39
41namespace dl::Numeric
42{
44 template<typename T, size_t N>
45 void Min(Array<T, N>& container)
46 {
47 for (size_t i = 0; i < N; ++i)
48 {
49 container[i] = (std::numeric_limits<T>::min)();
50 }
51 }
52 template<typename T, size_t N>
53 void Max(Array<T, N>& container)
54 {
55 for (size_t i = 0; i < N; ++i)
56 {
57 container[i] = (std::numeric_limits<T>::max)();
58 }
59 }
60}
61
67//void RectBinPack(const Size& size, list<>& map_fect, map<size_t, RectU>& map_fet)
68//{
69// //0按面积排序
70//}
71namespace dl::Math
72{
76template<typename T>
77constexpr bool IsOutRange(T x, T a, T b)
78{
79 return x < a || b < x;
80}
81
84constexpr float Radian2Angle(float radin)
85{
86 return radin * 180.0f / Numbers::PI;
87}
88
91constexpr float Angle2Radian(float angle)
92{
93 return angle * Numbers::PI / 180.0f;
94}
95
100constexpr void RangeRadian(std::array<float, 2>& arr)
101{
102 constexpr float PI_2 = Numbers::PI * 2;
103 if (arr[0] > arr[1])
104 {
105 arr[1] += PI_2 * (std::floor((arr[0] - arr[1]) / PI_2) + 1);
106 }
107}
108
111
112#if DL_PLATFORM == DL_PLATFORM_WIN32
113inline uint32_t ByteReverse(uint32_t x)
114{
115 return _byteswap_ulong(x);
116}
117#else
118constexpr uint32_t ByteReverse(uint32_t x)
119{
120 return __builtin_bswap32(x);
121}
122#endif
123
124
130template<typename T>
131constexpr T Pow(T x, T n)
132{
133 T ret = 1;
134 for (T i = 0; i < n; ++i)
135 {
136 ret *= x;
137 }
138 return ret;
139}
140constexpr uint64_t Pow64(uint64_t x, uint8_t n)
141{
142 uint64_t ret = 1;
143 for (uint8_t i = 0; i < n; ++i)
144 {
145 ret *= x;
146 }
147 return ret;
148}
149constexpr uint32_t Pow32(uint32_t x, uint8_t n)
150{
151 uint32_t ret = 1;
152 for (uint8_t i = 0; i < n; ++i)
153 {
154 ret *= x;
155 }
156 return ret;
157}
158
162constexpr uint64_t ARRAY_POW2[] = {
163 Pow64(2,0),Pow64(2,1),Pow64(2,2),Pow64(2,3),Pow64(2,4),Pow64(2,5),Pow64(2,6),Pow64(2,7),
164 Pow64(2,8),Pow64(2,9),Pow64(2,10),Pow64(2,11),Pow64(2,12),Pow64(2,13),Pow64(2,14),Pow64(2,15),
165 Pow64(2,16),Pow64(2,17),Pow64(2,18),Pow64(2,19),Pow64(2,20),Pow64(2,21),Pow64(2,22),Pow64(2,23),
166 Pow64(2,24),Pow64(2,25),Pow64(2,26),Pow64(2,27),Pow64(2,28),Pow64(2,29),Pow64(2,30),Pow64(2,31),
167 Pow64(2,32),Pow64(2,33),Pow64(2,34),Pow64(2,35),Pow64(2,36),Pow64(2,37),Pow64(2,38),Pow64(2,39),
168 Pow64(2,40),Pow64(2,41),Pow64(2,42),Pow64(2,43),Pow64(2,44),Pow64(2,45),Pow64(2,46),Pow64(2,47),
169 Pow64(2,48),Pow64(2,49),Pow64(2,50),Pow64(2,51),Pow64(2,52),Pow64(2,53),Pow64(2,54),Pow64(2,55),
170 Pow64(2,56),Pow64(2,57),Pow64(2,58),Pow64(2,59),Pow64(2,60),Pow64(2,61),Pow64(2,62),Pow64(2,63) };
171constexpr uint32_t ARRAY_POW2_32[] = {
172 Pow32(2,0),Pow32(2,1),Pow32(2,2),Pow32(2,3),Pow32(2,4),Pow32(2,5),Pow32(2,6),Pow32(2,7),
173 Pow32(2,8),Pow32(2,9),Pow32(2,10),Pow32(2,11),Pow32(2,12),Pow32(2,13),Pow32(2,14),Pow32(2,15),
174 Pow32(2,16),Pow32(2,17),Pow32(2,18),Pow32(2,19),Pow32(2,20),Pow32(2,21),Pow32(2,22),Pow32(2,23),
175 Pow32(2,24),Pow32(2,25),Pow32(2,26),Pow32(2,27),Pow32(2,28),Pow32(2,29),Pow32(2,30),Pow32(2,31) };
176
182#define DND_ARRAY_POW_LINE(index) if (x <= ARRAY_POW2[index])return ARRAY_POW2[index]
183constexpr uint64_t CeilToPow2(uint64_t&& x)
184{
193
194 log("数值过大,超过2^63:" + std::to_string(x));
195 return 0;
196}
197#define DND_ARRAY_POW_LINE_32(index) if (x <= ARRAY_POW2_32[index])return ARRAY_POW2_32[index]
208
213template <typename T>
214inline T CeilToPow2(const T& x)
215{
216#if (DL_PLATFORM == DL_PLATFORM_WIN32)
217 return std::bit_ceil(x);
218#else
219 return CeilToPow2(x);
220#endif
221}
222
223
230inline float RSqrt(float x)
231{
232 long i;
233 float x2, y;
234 const float threehalfs = 1.5f;
235
236 x2 = x * 0.5f;
237 y = x;
238 i = *(long*)&y;
239 i = 0x5f3759df - (i >> 1);
240 y = *(float*)&i;
241 y = y * (threehalfs - (x2 * y * y));
242 return y;
243}
244
245
249template<size_t N>
251{
252 float length = 0;
253 for (size_t i = 0; i < N; ++i)
254 {
255 length += (v[i] * v[i]);
256 }
257
258 length = RSqrt(length);
259 for (size_t i = 0; i < N; ++i)
260 {
261 v[i] *= length;
262 }
263}
264
268template <IsUnsigned T0, IsSigned T1>
269T0 AddU(T0 a, T1 b)
270{
271 if (b >= 0)
272 return a + (T0)b;
273 T0 nag_b = (T0)-b;
274 return nag_b < a ? a - nag_b : 0;
275}
276
279template <IsUnsigned T0, IsSigned T1, size_t N>
281{
282 for (size_t i = 0; i < N; ++i)
283 a[i] = AddU(a[i], b[i]);
284}
285
286template <IsUnsigned T0, IsSigned T1, size_t N>
287[[nodiscard]]
289{
290 Array<T0, N> ret = a;
291 for (size_t i = 0; i < N; ++i)
292 AddU(ret, b[i]);
293 return ret;
294}
295
298template <IsUnsigned T0, IsSigned T1>
299bool AddUCheck(T0 a, T1 b, T0& ret)
300{
301 if (b >= 0)
302 return a + (T0)b;
303 T0 nag_b = (T0)-b;
304 if (nag_b > a)
305 return false;
306 ret = a - nag_b;
307 return true;
308}
309
312template <IsUnsigned T0, IsSigned T1, size_t N>
313bool AddUCheck(const Array<T0, N>& a, const Array<T1, N>& b, const Array<T0, N>& ret)
314{
315 for (size_t i = 0; i < N; ++i)
316 {
317 if (!AddUCheck(a[i], b[i], ret[i]))
318 return false;
319 }
320 return true;
321}
322
325template <IsUnsigned T>
326T SubU(T a, T b)
327{
328 return a > b ? a - b : 0;
329}
330
333template <IsUnsigned T0, IsSigned T1>
334T0 SubU(T0 a, T1 b)
335{
336 if (b <= 0)
337 return a + -b;
338 return SubU(a, (T0)b);
339}
340
343template <IsUnsigned T, size_t N>
345{
346 Array<T, N> ret;
347 for (size_t i = 0; i < N; ++i)
348 ret[i] = SubU(a[i], b[i]);
349 return ret;
350}
351
354template <IsUnsigned T0, IsSigned T1, size_t N>
356{
357 Array<T0, N> ret;
358 for (size_t i = 0; i < N; ++i)
359 ret[i] = SubU(a[i], b[i]);
360 return ret;
361}
362
365template <IsUnsigned T>
366T DisU(T a, T b)
367{
368 return a < b ? b - a : a - b;
369}
370
374template <IsUnsigned T, size_t N>
376{
377 Array<T, N> ret;
378 for (size_t i = 0; i < N; ++i)
379 ret[i] = DisU(a[i], b[i]);
380 return ret;
381}
382
383
384//-------------------------------向量距离-----------------------------
388template <typename T>
390{
391 return a[0] * a[0] + a[1] * a[1];
392}
393
394template <typename T>
396{
397 return a[0] * a[0] + a[1] * a[1] + a[2] * a[2];
398}
399
400template <typename T>
402{
403 return a[0] * a[0] + a[1] * a[1] + a[2] * a[2] + a[3] * a[3];
404}
405template <typename T>
407{
408 return static_cast<T>(std::sqrt(DistancePow2(a)));
409}
410template <typename T>
412{
413 return static_cast<T>(std::sqrt(DistancePow2(a)));
414}
415template <typename T>
417{
418 return static_cast<T>(std::sqrt(DistancePow2(a)));
419}
420
424template <IsSigned T>
426{
427 return DistancePow2(b - a);
428}
429
433template <IsUnsigned T>
435{
436 unsigned dx = DisU(a[0], b[0]);
437 unsigned dy = DisU(a[1], b[1]);
438 return dx * dx + dy * dy;
439}
440
444template <IsUnsigned T>
446{
447 return static_cast<T>(std::sqrt(DistancePow2U(a, b)));
448}
449
452template <IsSigned T, size_t N>
454{
455 T length = DistancePow2(v);
456 length = sqrt(length);
457
458 v /= length;
459}
460
461template <IsSigned T, size_t N>
462[[nodiscard]]
464{
465 Array<T, N> ret = v;
466 Normalize(ret);
467 return ret;
468}
469
474std::vector<PointU> GetCircle(const Size& size, const PointU& xy, unsigned rad);
475
476
481std::vector<Point> GetCircle(const Point& xy, unsigned rad);
482
483
489constexpr double PI(unsigned n = 1, unsigned d = 1)
490{
491#ifdef false
492 return std::numbers::pi * n / d;
493#else
494 return 3.1415926535897932384626433832795 * n / d;
495#endif
496}
497constexpr float PIF(unsigned n = 1, unsigned d = 1)
498{
499#ifdef false
500 return (float)std::numbers::pi * n / d;
501#else
502 return 3.1415926535897932384626433832795f * n / d;
503#endif
504}
505
509/*dnd::Direction IndexRpg2Direction(size_t index)
510{
511 if (index == 0)
512 return Direction::DOWN;
513 if (index == 1)
514 return Direction::LEFT;
515 if (index == 2)
516 return Direction::RIGHT;
517 if (index == 3)
518 return Direction::UP;
519
520 debug_warn("错误的下标![0, 3]");
521 return Direction::DOWN;
522}*/
523
527//DirectionMask::Var Dir2Mask(const Vector2& dir)
528//{
529// if (Every::Zero(dir))
530// return DirectionMask::NONE;
531// double r = atan2(dir[1], dir[0]);//返回(-pi, pi],从正x轴向正y轴旋转
532// if (r < 0)//变换到(0, 2pi],x轴不变
533// r += (std::numbers::pi * 2.0);
534// r += (std::numbers::pi / 8.0);//四舍五入 加pi/8
535// size_t index = r / (std::numbers::pi / 4.0);//2pi分为8个方向为pi/4
536
537// dnd_assert(index >= 0 && index <= 7);
538// //x为0
539// if (index == 0)
540// return DirectionMask::RIGHT;
541// else if (index == 1)
542// return DirectionMask::RIGHT_DOWN;
543// else if (index == 2)
544// return DirectionMask::DOWN;
545// else if (index == 3)
546// return DirectionMask::LEFT_DOWN;
547// else if (index == 4)
548// return DirectionMask::LEFT;
549// else if (index == 5)
550// return DirectionMask::LEFT_UP;
551// else if (index == 6)
552// return DirectionMask::UP;
553// else if (index == 7)
554// return DirectionMask::RIGHT_UP;
555// return DirectionMask::NONE;
556//}
557
563template<IsReal T>
564constexpr T AlignF(T x, T align)
565{
566 assert(align > 0);
567
568 if (x < 0)
569 {
570 T ret = -align;
571 while (x < ret)
572 {
573 ret -= align;
574 }
575 return ret + align;
576 }
577 else
578 {
579 T ret = align;
580 while (x > ret)
581 {
582 ret += align;
583 }
584 return ret;
585 }
586}
587
592template<IsUnsigned T>
593constexpr T Align(T x, T align)
594{
595 assert(align != 0);
596
597 T ret = align;
598 while (x > ret)
599 {
600 ret += align;
601 }
602 return ret;
603}
604
608constexpr unsigned IsPow2(unsigned x)
609{
610 return x && !(x & (x - 1));
611}
612
617constexpr unsigned AlignPow2(unsigned x, unsigned align)
618{
619 if (!IsPow2(align))
620 return 0;
621
622 return (x + align - 1) & ~(align - 1);
623}
624
630constexpr unsigned div_found(unsigned n, unsigned d)
631{
632 unsigned q = n / d;
633 unsigned r = n % d;
634 return r >= (d >> 1) ? q + 1 : q;
635}
636
643constexpr unsigned div_found_fast(unsigned n, unsigned d)
644{
645 return (n + (d >> 1)) / d;
646}
647
659constexpr float OffsetOrder(float order, int u = 1, int v = 0, int w = 0)
660{
661 constexpr int NUM_ORDER_DT = 100;
662 float ret = order + (w + v * NUM_ORDER_DT + u * NUM_ORDER_DT * NUM_ORDER_DT)
663 * std::numeric_limits<float>::epsilon();
664 if (!is_saturate(ret))
665 {
666 log_("order超出范围:{}", ret);
667 return saturate(ret);
668 }
669 return ret;
670}
671
674constexpr Float CrossProduct(const Position2& a, const Position2& b)
675{
676 return a[0] * b[1] - a[1] * b[0];
677}
678
679constexpr Position3 CrossProduct(const Position3& a, const Position3& b)
680{
681 return {
682 a[1] * b[2] - b[1] * a[2],
683 a[2] * b[0] - b[2] * a[0],
684 a[0] * b[1] - b[0] * a[1]
685 };
686}
687
691template<typename T, size_t N>
692constexpr T DotProduct(const Array<T, N>& a, const Array<T, N>& b)
693{
694 T ret = 0;
695 for (size_t i = 0; i < N; ++i)
696 ret += a[i] * b[i];
697 return ret;
698}
699
704Position4 Slerp(const Position4& q0, const Position4& q1, const Float& t);
705
709//constexpr void Rect2Uv(const Size& tex_size, const RectU& rect, floatx2* uv)
710//{
711// floatx4 ltrb;
712// ltrb[LTRB::LEFT] = float(rect[LTRB::LEFT]) / tex_size[0];
713// ltrb[LTRB::TOP] = float(rect[LTRB::TOP]) / tex_size[1];
714// ltrb[LTRB::RIGHT] = float(rect[LTRB::RIGHT]) / tex_size[0];
715// ltrb[LTRB::BUTTOM] = float(rect[LTRB::BUTTOM]) / tex_size[1];
716//
717//
718// uv[Corner::LT] = { ltrb[LTRB::LEFT], ltrb[LTRB::TOP] };
719// uv[Corner::RT] = { ltrb[LTRB::RIGHT], ltrb[LTRB::TOP] };
720// uv[Corner::LB] = { ltrb[LTRB::LEFT], ltrb[LTRB::BUTTOM] };
721// uv[Corner::RB] = { ltrb[LTRB::RIGHT], ltrb[LTRB::BUTTOM] };
722//}
723
727template<typename C>
728constexpr auto DistanceDiagonal(const C& p0, const C& p1)
729{
730 C dt = p1 - p0;
731 Every::Abs(dt);
732 return Select::Max(dt);
733}
734
735
739std::vector<Point> DrawLineLerp(const Point& p0, const Point& p1);
740
744std::vector<Point> DrawLineBresenham(const Point& p0, const Point& p1);
745
750std::vector<Point> DrawLineOrth(const Point& p0, const Point& p1);
751
756std::vector<Point> DrawLineCover(const Point& p0, const Point& p1);
757
762void MergePath(std::list<Point>& list_pos);
763
768template<typename F>
769void MergePathDirect(std::list<Point>& list_pos, F func_pass)
770{
771 if (list_pos.size() < 3)
772 return;
773 auto iter_last = list_pos.end();//最后一个点总是有效的
774 --iter_last;
775 for (auto iter_0 = list_pos.begin(); iter_0 != iter_last;)
776 {//直到前一个点到 iter_last(最后一个点)
777 //iter_0的下一个点
778 auto iter_0_next = iter_0;
779 ++iter_0_next;
780 //是否删除了节点
781 bool b_del = false;
782 for (auto iter_1 = iter_last; iter_1 != iter_0_next; --iter_1)
783 {//后一个点 从后往前遍历,直到iter_0_next
784 if (func_pass(*iter_0, *iter_1))
785 {//如果可通行 删除中间的节点
786 for (auto iter = iter_0_next; iter != iter_1;)
787 iter = list_pos.erase(iter);
788 iter_0 = iter_1;//后一个点此时成为起点
789 b_del = true;
790 break;
791 }
792 }
793 if (!b_del)
794 ++iter_0;
795 }
796}
797
798
799//----------------Quad和Rect的操作不同,Quad需要加名字-------
803template<typename T>
804constexpr T GetQuadSize(const Array<T, 4>& quad)
805{
806 return quad[2] - quad[0];
807}
808
813template<typename T>
815{
816 return { quad[0], quad[1], quad[2] };
817}
818template<typename T>
820{
821 return { quad[0], quad[2], quad[3] };
822}
823
829template<typename T>
830constexpr bool IsRectValid(const Array<T, 4>& rect)
831{
832 return rect[0] <= rect[2]
833 && rect[1] <= rect[3];
834}
835
839template<typename T>
840constexpr bool IsRectEmpty(const Array<T, 4>& rect)
841{
842 return rect[0] == rect[2]
843 && rect[1] == rect[3];
844}
845
850template<typename T>
851constexpr bool IsRectInSize(const Array<T, 4>& rect, const Size& size)
852{
853 if (!IsRectValid(rect))
854 return false;
855 return rect[0] >= 0
856 && rect[1] >= 0
857 && rect[2] <= size[0]
858 && rect[3] <= size[1];
859}
860
864constexpr bool IsXyInSize(const Point& xy, const Size& size)
865{
866 if (Each::Less(xy, {}))
867 return false;
868 return unsigned(xy[0]) < size[0]
869 && unsigned(xy[1]) < size[1];
870}
871
876constexpr bool IsXyInRect(const Point& xy, const Rect& rect)
877{
878 return xy[0] >= rect[0]
879 && xy[1] >= rect[1]
880 && xy[0] < rect[2]
881 && xy[1] < rect[3];
882}
883
887constexpr bool IsTriangle(const Triangle& triangle)
888{
889 Position ab = triangle[0] - triangle[1];
890 Position ac = triangle[0] - triangle[2];
891
892 return CrossProduct(ab, ac) != 0;
893}
894
900constexpr bool IsDotInTriangle(const Position& dot, const Triangle& triangle)
901{
902 if (!IsTriangle(triangle))
903 return false;
904 Position pa = triangle[0] - dot;
905 Position pb = triangle[1] - dot;
906 Position pc = triangle[2] - dot;
907 Float t1 = CrossProduct(pa, pb);
908 Float t2 = CrossProduct(pb, pc);
909 Float t3 = CrossProduct(pc, pa);
910 return t1 * t2 >= 0 &&
911 t1 * t3 >= 0 &&
912 t2 * t3 >= 0;
913}
914
920constexpr bool IsDotInQuad(const Position& dot, const Quad& quad)
921{
922 return Math::IsDotInTriangle(dot, GetQuadTriangle0(quad))
924}
925
931//constexpr bool IsDotInQuadConvex(const Position& dot, const Quad& quad)
932//{
933//
934//}
935
940{
941 return { w, w * Numbers::RATIO_GOLD };
942}
943
949template<typename T, typename F>
950void GetRectTrim(F func, Array<T, 4>& rect)
951{
952 if (!IsRectValid(rect) || IsRectEmpty(rect))
953 {
954 return;
955 }
956 // 向下移动y
957 while (rect.top < rect.bottom)
958 {
959 bool can_trim = true;
960 for (T x = rect.left; x < rect.right; ++x)
961 {
962 if (func(x, rect.top))
963 {
964 can_trim = false;
965 break;
966 }
967 }
968 if (can_trim)
969 ++rect.top;
970 else
971 break;
972 }
973 // 向上移动y
974 while (rect.bottom - 1 > rect.top)
975 {
976 bool can_trim = true;
977 for (T x = rect.left; x < rect.right; ++x)
978 {
979 if (func(x, rect.bottom - 1))
980 {
981 can_trim = false;
982 break;
983 }
984 }
985 if (can_trim)
986 --rect.bottom;
987 else
988 break;
989 }
990 // 向右移动x
991 while (rect.left < rect.right)
992 {
993 bool can_trim = true;
994 for (T y = rect.top; y < rect.bottom; ++y)
995 {
996 if (func(rect.left, y))
997 {
998 can_trim = false;
999 break;
1000 }
1001 }
1002 if (can_trim)
1003 ++rect.left;
1004 else
1005 break;
1006 }
1007 // 向左移动
1008 while (rect.right - 1 > rect.left)
1009 {
1010 bool can_trim = true;
1011 for (T y = rect.top; y < rect.bottom; ++y)
1012 {
1013 if (func(rect.right - 1, y))
1014 {
1015 can_trim = false;
1016 break;
1017 }
1018 }
1019 if (can_trim)
1020 --rect.right;
1021 else
1022 break;
1023 }
1024}
1025
1031template<typename T>
1032void ExtendRectLeft(T min_left, Array<T, 4>& rect, T extend = 1)
1033{
1034 if (rect.left >= min_left + extend)
1035 rect.left -= extend;
1036}
1037
1042template<typename T>
1043void ExtendRectTop(T min_top, Array<T, 4>& rect, T extend = 1)
1044{
1045 if (rect.top >= min_top + extend)
1046 rect.top -= extend;
1047}
1048
1053template<typename T>
1054void ExtendRectRight(T max_right, Array<T, 4>& rect, T extend = 1)
1055{
1056 if (rect.right + extend <= max_right)
1057 rect.right += extend;
1058}
1059
1064template<typename T>
1065void ExtendRectBottom(T max_bottom, Array<T, 4>& rect, T extend = 1)
1066{
1067 if (rect.bottom + extend <= max_bottom)
1068 rect.bottom += extend;
1069}
1070
1076template<typename T>
1077void ExtendRect(const Array<T, 4>& rect_big, Array<T, 4>& rect, T extend = 1)
1078{
1079 ExtendRectLeft(rect_big.left, rect, extend);
1080 ExtendRectTop(rect_big.top, rect, extend);
1081 ExtendRectRight(rect_big.right, rect, extend);
1082 ExtendRectBottom(rect_big.bottom, rect, extend);
1083}
1084
1090template<typename T>
1091void ExtendRect(const Array<T, 2>& size, Array<T, 4>& rect, T extend = 1)
1092{
1093 ExtendRectLeft((T)0, rect, extend);
1094 ExtendRectTop((T)0, rect, extend);
1095 ExtendRectRight(size.w, rect, extend);
1096 ExtendRectBottom(size.h, rect, extend);
1097}
1098
1103template<typename T>
1104void ExtendRectRB(const Array<T, 2>& size, Array<T, 4>& rect, T extend = 1)
1105{
1106 ExtendRectRight(size.w, rect, extend);
1107 ExtendRectBottom(size.h, rect, extend);
1108}
1109
1110
1112inline unsigned GetCircleNumMax(unsigned rad)
1113{
1114 // todo 待证明更优的公式
1115 return (unsigned)std::ceil(PI() * (rad + 1) * (rad + 1));
1116}
1117
1118namespace RingX
1119{
1120 // size不能为0
1121
1123 inline void Clamp(const Size& size, PointU& xy)
1124 {
1125 if (xy.y >= size.h)
1126 xy.y = size.h - 1;
1127 while (xy.x >= size.w)
1128 xy.x -= size.w;
1129 }
1130
1131 inline bool Clamp(const Size& size, Point xy, PointU& out_xy)
1132 {
1133 if (xy.y < 0 || xy.y >= (int)size.h)
1134 return false;
1135 while (xy.x < 0)
1136 xy.x += size.w;
1137 while (xy.x >= (int)size.w)
1138 xy.x -= size.w;
1139 out_xy = toSizeDefault(xy);
1140 return true;
1141 }
1142
1146 inline unsigned DistancePow2NoCheck(const Size& size, const PointU& a, const PointU& b)
1147 {
1148 PointU dt;
1149 dt.x = DisU(a.x, b.x);
1150 if (dt.x > size.w / 2)
1151 dt.x = size.w - dt.x;
1152 dt.y = DisU(a.y, b.y);
1153 return Math::DistancePow2(dt);
1154 }
1155
1159 inline unsigned Distance(const Size& size, const PointU& a, const PointU& b)
1160 {
1161 PointU aa = a;
1162 Clamp(size, aa);
1163 PointU bb = b;
1164 Clamp(size, bb);
1165 PointU dt;
1166 dt.x = DisU(aa.x, bb.x);
1167 if (dt.x > size.w / 2)
1168 dt.x = size.w / 2 - dt.x;
1169 dt.y = DisU(aa.y, bb.y);
1170 return Math::Distance(dt);
1171 }
1172
1179 std::vector<PointU> GetCircle(const Size& size, const PointU& xy, unsigned rad);
1180
1181
1184 {
1185 public:
1187 void SetSize(const Size& size)
1188 {
1189 _size = size;
1190 }
1191
1192 // 失败会修改原值
1193
1194 bool Left(PointU& xy)
1195 {
1196 if (!CheckVaildY(xy))
1197 return false;
1198 if (xy.x == 0)
1199 xy.x = _size.w - 1;
1200 else
1201 {
1202 if (xy.x - 1 >= _size.w)
1203 return false;
1204 --xy.x;
1205 }
1206 return true;
1207 }
1208 bool Right(PointU& xy)
1209 {
1210 if (!CheckVaildY(xy))
1211 return false;
1212 if (xy.x + 1 > _size.w)
1213 return false;
1214
1215 if (xy.x + 1 == _size.w)
1216 xy.x = 0;
1217 else
1218 ++xy.x;
1219 return true;
1220 }
1221 bool Top(PointU& xy)
1222 {
1223 if (!CheckVaildX(xy))
1224 return false;
1225 if (xy.y == 0)
1226 return false;
1227 if (xy.y - 1 >= _size.h)
1228 return false;
1229 --xy.y;
1230 return true;
1231 }
1232 bool Bottom(PointU& xy)
1233 {
1234 if (!CheckVaildX(xy))
1235 return false;
1236 if (xy.y + 1 >= _size.h)
1237 return false;
1238 ++xy.y;
1239 return true;
1240 }
1241 bool LeftTop(PointU& xy)
1242 {
1243 if (!Top(xy))
1244 return false;
1245 return Left(xy);
1246 }
1248 {
1249 if (!Bottom(xy))
1250 return false;
1251 return Left(xy);
1252 }
1254 {
1255 if (!Top(xy))
1256 return false;
1257 return Right(xy);
1258 }
1260 {
1261 if (!Bottom(xy))
1262 return false;
1263 return Right(xy);
1264 }
1265 bool CheckVaild(const PointU& xy)
1266 {
1267 return xy.x < _size.w && xy.y < _size.h;
1268 }
1269 bool CheckVaildX(const PointU& xy)
1270 {
1271 return xy.x < _size.w;
1272 }
1273 bool CheckVaildY(const PointU& xy)
1274 {
1275 return xy.y < _size.h;
1276 }
1277 private:
1278 Size _size;
1279 };
1280
1281
1282 using FnDiffusionCheck = std::function<bool(const PointU& xy)>;
1283 using FnDiffusionCb = std::function<void(unsigned, const std::list<PointU>& xy)>;
1284
1294 std::vector<PointU> Diffusion(const Size& size, const PointU& xy, unsigned count,
1295 FnDiffusionCheck func_valid, FnDiffusionCb func_cb);
1296}
1297
1298
1299
1301constexpr double DegreesToRadians(double deg)
1302{
1303 return deg * PI() / 180.0;
1304}
1305
1307constexpr double RadiansToDegrees(double rad)
1308{
1309 return rad * 180.0f / PI();
1310}
1311
1312//! 判断是否是闰年
1313constexpr bool IsLeapYear(int year)
1314{
1315 // 本质是一个无限的判断,但在短时间(几万年)内精度够用
1316 return (year % 4 == 0 && year % 100 != 0)
1317 || year % 400 == 0;
1318}
1319
1320//! 获取某月的天数
1321constexpr int GetMouthDayNum(int year, int mouth)
1322{
1323 switch (mouth)
1324 {
1325 case 1:
1326 case 3:
1327 case 5:
1328 case 7:
1329 case 8:
1330 case 10:
1331 case 12:
1332 return 31;
1333 case 2:
1334 return IsLeapYear(year) ? 29 : 28;
1335 default:
1336 break;
1337 }
1338 return 30;
1339}
1340
1341//--------------------------------地理相关函数由ai生成,简单整理而成,非专业函数
1342
1349double GetSolarDeclination(int day);
1350
1357double GetSolarElevation(double latitude, double declination);
1358
1363int GetSeason(int day, double latitude);
1370double GetBaseTemperature(double latitude, int day);
1371
1372}
地图限制器(x轴为环状)
bool CheckVaildY(const PointU &xy)
bool Left(PointU &xy)
传入越界,但返回合法,也会返回true
void SetSize(const Size &size)
设置大小
bool RightBottom(PointU &xy)
bool CheckVaildX(const PointU &xy)
bool LeftBottom(PointU &xy)
bool CheckVaild(const PointU &xy)
用于模板限定,更好的报错信息
日志系统
#define log_(...)
#define DND_ARRAY_POW_LINE_32(index)
#define DND_ARRAY_POW_LINE(index)
向上取2的幂次
平台宏
范围操作
通用类型
constexpr bool Less(const Array< T, N > &a, const Array< T, N > &b)
每个元素都小于返回真
void Abs(C &c)
取绝对值
std::function< bool(const PointU &xy)> FnDiffusionCheck
unsigned Distance(const Size &size, const PointU &a, const PointU &b)
返回 距离,x轴为环形
std::vector< PointU > GetCircle(const Size &size, const PointU &xy, unsigned rad)
返回圆形范围的节点,x轴为环形
unsigned DistancePow2NoCheck(const Size &size, const PointU &a, const PointU &b)
返回 距离,x轴为环形
std::vector< PointU > Diffusion(const Size &size, const PointU &xy, unsigned count, FnDiffusionCheck func_valid, FnDiffusionCb func_cb)
扩散遍历
void Clamp(const Size &size, PointU &xy)
限制到大小内
std::function< void(unsigned, const std::list< PointU > &xy)> FnDiffusionCb
2维装箱算法
T SubU(T a, T b)
无符号类型相减,负数转为0
uint32_t ByteReverse(uint32_t x)
翻转字节序
constexpr unsigned IsPow2(unsigned x)
是否2的幂
int GetSeason(int day, double latitude)
返回季节
std::vector< Point > DrawLineOrth(const Point &p0, const Point &p1)
正交 画线算法
constexpr bool IsXyInRect(const Point &xy, const Rect &rect)
判断 点是否在矩形内
constexpr double RadiansToDegrees(double rad)
将弧度转为角度
constexpr uint64_t Pow64(uint64_t x, uint8_t n)
T DistancePow2U(const Array< T, 2 > &a, const Array< T, 2 > &b)
返回 距离的平方
constexpr float PIF(unsigned n=1, unsigned d=1)
constexpr bool IsOutRange(T x, T a, T b)
判断数值是否越界(前闭后开)
constexpr T Align(T x, T align)
对齐align的倍数
constexpr Float CrossProduct(const Position2 &a, const Position2 &b)
叉乘(四指指向a,弯向b,大拇指指向c)
constexpr bool IsTriangle(const Triangle &triangle)
判断是否三角形
constexpr unsigned AlignPow2(unsigned x, unsigned align)
对齐align的倍数
constexpr Position CreatePositionByRatioGoldW(Float w)
判断点是否在凸四边形内
constexpr double DegreesToRadians(double deg)
将角度转为弧度
constexpr float OffsetOrder(float order, int u=1, int v=0, int w=0)
偏移order
double GetSolarElevation(double latitude, double declination)
计算正午太阳高度角
std::vector< Point > DrawLineLerp(const Point &p0, const Point &p1)
线性插值 画线算法
constexpr bool IsLeapYear(int year)
void MergePathDirect(std::list< Point > &list_pos, F func_pass)
路径合并(网格路径)
T Distance(const Array< T, 2 > &a)
constexpr uint32_t ARRAY_POW2_32[]
constexpr T AlignF(T x, T align)
RGP资源下标转方向
std::vector< PointU > GetCircle(const Size &size, const PointU &xy, unsigned rad)
返回圆形范围的节点,考虑越界
constexpr unsigned div_found(unsigned n, unsigned d)
无符号除法,返回四舍五入结果
constexpr bool IsRectEmpty(const Array< T, 4 > &rect)
判断 矩形 是否空
constexpr bool IsXyInSize(const Point &xy, const Size &size)
判断 点是否在大小内
constexpr T GetQuadSize(const Array< T, 4 > &quad)
返回 Quad 的大小
constexpr uint32_t Pow32(uint32_t x, uint8_t n)
constexpr T Pow(T x, T n)
返回x的n次方
bool AddUCheck(T0 a, T1 b, T0 &ret)
无符号 加 有符号,检查负数
std::vector< Point > DrawLineCover(const Point &p0, const Point &p1)
覆盖 画线算法
void Normalize(Array< T, N > &v)
向量单位化
void ExtendRectRB(const Array< T, 2 > &size, Array< T, 4 > &rect, T extend=1)
向右下拓展矩形
constexpr unsigned div_found_fast(unsigned n, unsigned d)
无符号除法,返回四舍五入结果
unsigned GetCircleNumMax(unsigned rad)
返回圆所占格子数(GetCircle函数使用)
constexpr Array< T, 3 > GetQuadTriangle0(const Array< T, 4 > &quad)
返回 Quad的三角形
Position4 Slerp(const Position4 &q0, const Position4 &q1, const Float &t)
球面线性插值
constexpr double PI(unsigned n=1, unsigned d=1)
返回PI的分数
void MergePath(std::list< Point > &list_pos)
路径合并(网格路径)
float RSqrt(float x)
返回平方根的倒数
void ExtendRectLeft(T min_left, Array< T, 4 > &rect, T extend=1)
向左拓展矩形
constexpr float Radian2Angle(float radin)
弧度转角度
T DisU(T a, T b)
返回无符号类型的差值
constexpr int GetMouthDayNum(int year, int mouth)
void NormalizeFast(Array< float, N > &v)
向量单位化,精度低速度快
void ExtendRectBottom(T max_bottom, Array< T, 4 > &rect, T extend=1)
向下拓展矩形
void GetRectTrim(F func, Array< T, 4 > &rect)
裁切图像、网格
constexpr uint64_t ARRAY_POW2[]
2的整数次幂列表
T DistancePow2(const Array< T, 2 > &a)
返回 向量 距离的平方
constexpr void RangeRadian(std::array< float, 2 > &arr)
void ExtendRectRight(T max_right, Array< T, 4 > &rect, T extend=1)
向右拓展矩形
void ExtendRectTop(T min_top, Array< T, 4 > &rect, T extend=1)
向上拓展矩形
double GetBaseTemperature(double latitude, int day)
基于纬度估算海平面基准温度(℃)
std::vector< Point > DrawLineBresenham(const Point &p0, const Point &p1)
bresenham 画线算法
constexpr auto DistanceDiagonal(const C &p0, const C &p1)
纹理区域转uv
constexpr T DotProduct(const Array< T, N > &a, const Array< T, N > &b)
点乘
void ExtendRect(const Array< T, 4 > &rect_big, Array< T, 4 > &rect, T extend=1)
拓展矩形
constexpr bool IsDotInQuad(const Position &dot, const Quad &quad)
判断点是否在四边形内(包含边)
constexpr uint64_t CeilToPow2(uint64_t &&x)
constexpr Array< T, 3 > GetQuadTriangle1(const Array< T, 4 > &quad)
T DistanceU(const Array< T, 2 > &a, const Array< T, 2 > &b)
返回 距离
constexpr bool IsRectValid(const Array< T, 4 > &rect)
判断 矩形 是否有效
constexpr bool IsRectInSize(const Array< T, 4 > &rect, const Size &size)
判断 矩形 在 大小 内,首先它必须是有效的矩形
constexpr float Angle2Radian(float angle)
角度转弧度
T0 AddU(T0 a, T1 b)
无符号 加 有符号,防止小于0
double GetSolarDeclination(int day)
计算太阳赤纬(太阳直射点纬度)
constexpr bool IsDotInTriangle(const Position &dot, const Triangle &triangle)
判断点是否在三角形内(包含边)
类似std::numbers的常数
constexpr Float EULER
自然常数
constexpr Float EARTH_fADIUS
地球半径km
constexpr Float GRAVITY
地球重力加速度(赤道最小)
constexpr Float PI
圆周率
constexpr Float SQRT_2
根号2
constexpr Float RATIO_GOLD
黄金比例
类似numeric头文件的数值操作
void Min(Array< T, N > &container)
返回的是最小正数(假设有符号)
void Max(Array< T, N > &container)
constexpr auto Max(const C &container)
返回容器最大值
Position2 Position
float Float
constexpr Array< PointU::value_type, N > toSizeDefault(const Array< T, N > &a)
有符号转无符号,直接转换,负数会直接转为大正数
Array< Float, 2 > Position2
constexpr T is_saturate(const T &x)
是否数值在[0, 1]
Array< Position, 3 > Triangle
void log(std::string_view str, DL_SOURCE_LOCATION)
以当前设置输出
Point2U PointU
Array< Float, 3 > Position3
Array< Float, 4 > Position4
constexpr T saturate(const T &x)
限制数值到 [0, 1]
Point4 Rect
Array< Position, 4 > Quad
PointU Size
Point2 Point