My Marlin configs for Fabrikator Mini and CTC i3 Pro B
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

types.h 55KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. /**
  2. * Marlin 3D Printer Firmware
  3. * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
  4. *
  5. * Based on Sprinter and grbl.
  6. * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. *
  21. */
  22. #pragma once
  23. #include <math.h>
  24. #include <stddef.h>
  25. #include "../inc/MarlinConfigPre.h"
  26. //
  27. // Conditional type assignment magic. For example...
  28. //
  29. // typename IF<(MYOPT==12), int, float>::type myvar;
  30. //
  31. template <bool, class L, class R>
  32. struct IF { typedef R type; };
  33. template <class L, class R>
  34. struct IF<true, L, R> { typedef L type; };
  35. #define NUM_AXIS_GANG(V...) GANG_N(NUM_AXES, V)
  36. #define NUM_AXIS_CODE(V...) CODE_N(NUM_AXES, V)
  37. #define NUM_AXIS_LIST(V...) LIST_N(NUM_AXES, V)
  38. #define NUM_AXIS_ARRAY(V...) { NUM_AXIS_LIST(V) }
  39. #define NUM_AXIS_ARGS(T...) NUM_AXIS_LIST(T x, T y, T z, T i, T j, T k, T u, T v, T w)
  40. #define NUM_AXIS_ELEM(O) NUM_AXIS_LIST(O.x, O.y, O.z, O.i, O.j, O.k, O.u, O.v, O.w)
  41. #define NUM_AXIS_DEFS(T,V) NUM_AXIS_LIST(T x=V, T y=V, T z=V, T i=V, T j=V, T k=V, T u=V, T v=V, T w=V)
  42. #define LOGICAL_AXIS_GANG(E,V...) NUM_AXIS_GANG(V) GANG_ITEM_E(E)
  43. #define LOGICAL_AXIS_CODE(E,V...) NUM_AXIS_CODE(V) CODE_ITEM_E(E)
  44. #define LOGICAL_AXIS_LIST(E,V...) NUM_AXIS_LIST(V) LIST_ITEM_E(E)
  45. #define LOGICAL_AXIS_ARRAY(E,V...) { LOGICAL_AXIS_LIST(E,V) }
  46. #define LOGICAL_AXIS_ARGS(T...) LOGICAL_AXIS_LIST(T e, T x, T y, T z, T i, T j, T k, T u, T v, T w)
  47. #define LOGICAL_AXIS_ELEM(O) LOGICAL_AXIS_LIST(O.e, O.x, O.y, O.z, O.i, O.j, O.k, O.u, O.v, O.w)
  48. #define LOGICAL_AXIS_DECL(T,V) LOGICAL_AXIS_LIST(T e=V, T x=V, T y=V, T z=V, T i=V, T j=V, T k=V, T u=V, T v=V, T w=V)
  49. #define LOGICAL_AXES_STRING LOGICAL_AXIS_GANG("E", "X", "Y", "Z", STR_I, STR_J, STR_K, STR_U, STR_V, STR_W)
  50. #define XYZ_GANG(V...) GANG_N(PRIMARY_LINEAR_AXES, V)
  51. #define XYZ_CODE(V...) CODE_N(PRIMARY_LINEAR_AXES, V)
  52. #define SECONDARY_AXIS_GANG(V...) GANG_N(SECONDARY_AXES, V)
  53. #define SECONDARY_AXIS_CODE(V...) CODE_N(SECONDARY_AXES, V)
  54. #if HAS_ROTATIONAL_AXES
  55. #define ROTATIONAL_AXIS_GANG(V...) GANG_N(ROTATIONAL_AXES, V)
  56. #endif
  57. #if HAS_EXTRUDERS
  58. #define LIST_ITEM_E(N) , N
  59. #define CODE_ITEM_E(N) ; N
  60. #define GANG_ITEM_E(N) N
  61. #else
  62. #define LIST_ITEM_E(N)
  63. #define CODE_ITEM_E(N)
  64. #define GANG_ITEM_E(N)
  65. #endif
  66. #define AXIS_COLLISION(L) (AXIS4_NAME == L || AXIS5_NAME == L || AXIS6_NAME == L || AXIS7_NAME == L || AXIS8_NAME == L || AXIS9_NAME == L)
  67. //
  68. // Enumerated axis indices
  69. //
  70. // - X_AXIS, Y_AXIS, and Z_AXIS should be used for axes in Cartesian space
  71. // - A_AXIS, B_AXIS, and C_AXIS should be used for Steppers, corresponding to XYZ on Cartesians
  72. // - X_HEAD, Y_HEAD, and Z_HEAD should be used for Steppers on Core kinematics
  73. //
  74. enum AxisEnum : uint8_t {
  75. // Linear axes may be controlled directly or indirectly
  76. NUM_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS, U_AXIS, V_AXIS, W_AXIS)
  77. // Extruder axes may be considered distinctly
  78. #define _EN_ITEM(N) , E##N##_AXIS
  79. REPEAT(EXTRUDERS, _EN_ITEM)
  80. #undef _EN_ITEM
  81. // Core also keeps toolhead directions
  82. #if ANY(IS_CORE, MARKFORGED_XY, MARKFORGED_YX)
  83. , X_HEAD, Y_HEAD, Z_HEAD
  84. #endif
  85. // Distinct axes, including all E and Core
  86. , NUM_AXIS_ENUMS
  87. // Most of the time we refer only to the single E_AXIS
  88. #if HAS_EXTRUDERS
  89. , E_AXIS = E0_AXIS
  90. #endif
  91. // A, B, and C are for DELTA, SCARA, etc.
  92. , A_AXIS = X_AXIS
  93. #if HAS_Y_AXIS
  94. , B_AXIS = Y_AXIS
  95. #endif
  96. #if HAS_Z_AXIS
  97. , C_AXIS = Z_AXIS
  98. #endif
  99. // To refer to all or none
  100. , ALL_AXES_ENUM = 0xFE, NO_AXIS_ENUM = 0xFF
  101. };
  102. typedef IF<(NUM_AXIS_ENUMS > 8), uint16_t, uint8_t>::type axis_bits_t;
  103. typedef IF<(NUM_AXES > 8), uint16_t, uint8_t>::type linear_axis_bits_t;
  104. //
  105. // Loop over axes
  106. //
  107. #define LOOP_ABC(VAR) LOOP_S_LE_N(VAR, A_AXIS, C_AXIS)
  108. #define LOOP_NUM_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, NUM_AXES)
  109. #define LOOP_LOGICAL_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, LOGICAL_AXES)
  110. #define LOOP_DISTINCT_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, DISTINCT_AXES)
  111. #define LOOP_DISTINCT_E(VAR) LOOP_L_N(VAR, DISTINCT_E)
  112. //
  113. // feedRate_t is just a humble float
  114. //
  115. typedef float feedRate_t;
  116. //
  117. // celsius_t is the native unit of temperature. Signed to handle a disconnected thermistor value (-14).
  118. // For more resolition (e.g., for a chocolate printer) this may later be changed to Celsius x 100
  119. //
  120. typedef uint16_t raw_adc_t;
  121. typedef int16_t celsius_t;
  122. typedef float celsius_float_t;
  123. //
  124. // On AVR pointers are only 2 bytes so use 'const float &' for 'const float'
  125. //
  126. #ifdef __AVR__
  127. typedef const float & const_float_t;
  128. #else
  129. typedef const float const_float_t;
  130. #endif
  131. typedef const_float_t const_feedRate_t;
  132. typedef const_float_t const_celsius_float_t;
  133. // Conversion macros
  134. #define MMM_TO_MMS(MM_M) feedRate_t(static_cast<float>(MM_M) / 60.0f)
  135. #define MMS_TO_MMM(MM_S) (static_cast<float>(MM_S) * 60.0f)
  136. //
  137. // Coordinates structures for XY, XYZ, XYZE...
  138. //
  139. // Helpers
  140. #define _RECIP(N) ((N) ? 1.0f / static_cast<float>(N) : 0.0f)
  141. #define _ABS(N) ((N) < 0 ? -(N) : (N))
  142. #define _LS(N) (N = (T)(uint32_t(N) << v))
  143. #define _RS(N) (N = (T)(uint32_t(N) >> v))
  144. #define FI FORCE_INLINE
  145. // Forward declarations
  146. template<typename T> struct XYval;
  147. template<typename T> struct XYZval;
  148. template<typename T> struct XYZEval;
  149. typedef struct XYval<bool> xy_bool_t;
  150. typedef struct XYZval<bool> xyz_bool_t;
  151. typedef struct XYZEval<bool> xyze_bool_t;
  152. typedef struct XYval<char> xy_char_t;
  153. typedef struct XYZval<char> xyz_char_t;
  154. typedef struct XYZEval<char> xyze_char_t;
  155. typedef struct XYval<unsigned char> xy_uchar_t;
  156. typedef struct XYZval<unsigned char> xyz_uchar_t;
  157. typedef struct XYZEval<unsigned char> xyze_uchar_t;
  158. typedef struct XYval<int8_t> xy_int8_t;
  159. typedef struct XYZval<int8_t> xyz_int8_t;
  160. typedef struct XYZEval<int8_t> xyze_int8_t;
  161. typedef struct XYval<uint8_t> xy_uint8_t;
  162. typedef struct XYZval<uint8_t> xyz_uint8_t;
  163. typedef struct XYZEval<uint8_t> xyze_uint8_t;
  164. typedef struct XYval<int16_t> xy_int_t;
  165. typedef struct XYZval<int16_t> xyz_int_t;
  166. typedef struct XYZEval<int16_t> xyze_int_t;
  167. typedef struct XYval<uint16_t> xy_uint_t;
  168. typedef struct XYZval<uint16_t> xyz_uint_t;
  169. typedef struct XYZEval<uint16_t> xyze_uint_t;
  170. typedef struct XYval<int32_t> xy_long_t;
  171. typedef struct XYZval<int32_t> xyz_long_t;
  172. typedef struct XYZEval<int32_t> xyze_long_t;
  173. typedef struct XYval<uint32_t> xy_ulong_t;
  174. typedef struct XYZval<uint32_t> xyz_ulong_t;
  175. typedef struct XYZEval<uint32_t> xyze_ulong_t;
  176. typedef struct XYZval<volatile int32_t> xyz_vlong_t;
  177. typedef struct XYZEval<volatile int32_t> xyze_vlong_t;
  178. typedef struct XYval<float> xy_float_t;
  179. typedef struct XYZval<float> xyz_float_t;
  180. typedef struct XYZEval<float> xyze_float_t;
  181. typedef struct XYval<feedRate_t> xy_feedrate_t;
  182. typedef struct XYZval<feedRate_t> xyz_feedrate_t;
  183. typedef struct XYZEval<feedRate_t> xyze_feedrate_t;
  184. typedef xy_uint8_t xy_byte_t;
  185. typedef xyz_uint8_t xyz_byte_t;
  186. typedef xyze_uint8_t xyze_byte_t;
  187. typedef xyz_long_t abc_long_t;
  188. typedef xyze_long_t abce_long_t;
  189. typedef xyz_ulong_t abc_ulong_t;
  190. typedef xyze_ulong_t abce_ulong_t;
  191. typedef xy_float_t xy_pos_t;
  192. typedef xyz_float_t xyz_pos_t;
  193. typedef xyze_float_t xyze_pos_t;
  194. typedef xy_float_t ab_float_t;
  195. typedef xyz_float_t abc_float_t;
  196. typedef xyze_float_t abce_float_t;
  197. typedef ab_float_t ab_pos_t;
  198. typedef abc_float_t abc_pos_t;
  199. typedef abce_float_t abce_pos_t;
  200. // External conversion methods
  201. void toLogical(xy_pos_t &raw);
  202. void toLogical(xyz_pos_t &raw);
  203. void toLogical(xyze_pos_t &raw);
  204. void toNative(xy_pos_t &raw);
  205. void toNative(xyz_pos_t &raw);
  206. void toNative(xyze_pos_t &raw);
  207. //
  208. // Paired XY coordinates, counters, flags, etc.
  209. //
  210. template<typename T>
  211. struct XYval {
  212. union {
  213. struct { T x, y; };
  214. struct { T a, b; };
  215. T pos[2];
  216. };
  217. // Set all to 0
  218. FI void reset() { x = y = 0; }
  219. // Setters taking struct types and arrays
  220. FI void set(const T px) { x = px; }
  221. #if HAS_Y_AXIS
  222. FI void set(const T px, const T py) { x = px; y = py; }
  223. FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; }
  224. #endif
  225. #if NUM_AXES > XY
  226. FI void set(const T (&arr)[NUM_AXES]) { x = arr[0]; y = arr[1]; }
  227. #endif
  228. #if LOGICAL_AXES > NUM_AXES
  229. FI void set(const T (&arr)[LOGICAL_AXES]) { x = arr[0]; y = arr[1]; }
  230. #if DISTINCT_AXES > LOGICAL_AXES
  231. FI void set(const T (&arr)[DISTINCT_AXES]) { x = arr[0]; y = arr[1]; }
  232. #endif
  233. #endif
  234. // Length reduced to one dimension
  235. FI T magnitude() const { return (T)sqrtf(x*x + y*y); }
  236. // Pointer to the data as a simple array
  237. FI operator T* () { return pos; }
  238. // If any element is true then it's true
  239. FI operator bool() { return x || y; }
  240. // Explicit copy and copies with conversion
  241. FI XYval<T> copy() const { return *this; }
  242. FI XYval<T> ABS() const { return { T(_ABS(x)), T(_ABS(y)) }; }
  243. FI XYval<int16_t> asInt() { return { int16_t(x), int16_t(y) }; }
  244. FI XYval<int16_t> asInt() const { return { int16_t(x), int16_t(y) }; }
  245. FI XYval<int32_t> asLong() { return { int32_t(x), int32_t(y) }; }
  246. FI XYval<int32_t> asLong() const { return { int32_t(x), int32_t(y) }; }
  247. FI XYval<int32_t> ROUNDL() { return { int32_t(LROUND(x)), int32_t(LROUND(y)) }; }
  248. FI XYval<int32_t> ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)) }; }
  249. FI XYval<float> asFloat() { return { static_cast<float>(x), static_cast<float>(y) }; }
  250. FI XYval<float> asFloat() const { return { static_cast<float>(x), static_cast<float>(y) }; }
  251. FI XYval<float> reciprocal() const { return { _RECIP(x), _RECIP(y) }; }
  252. // Marlin workspace shifting is done with G92 and M206
  253. FI XYval<float> asLogical() const { XYval<float> o = asFloat(); toLogical(o); return o; }
  254. FI XYval<float> asNative() const { XYval<float> o = asFloat(); toNative(o); return o; }
  255. // Cast to a type with more fields by making a new object
  256. FI operator XYZval<T>() { return { x, y }; }
  257. FI operator XYZval<T>() const { return { x, y }; }
  258. FI operator XYZEval<T>() { return { x, y }; }
  259. FI operator XYZEval<T>() const { return { x, y }; }
  260. // Accessor via an AxisEnum (or any integer) [index]
  261. FI T& operator[](const int n) { return pos[n]; }
  262. FI const T& operator[](const int n) const { return pos[n]; }
  263. // Assignment operator overrides do the expected thing
  264. FI XYval<T>& operator= (const T v) { set(v, v ); return *this; }
  265. FI XYval<T>& operator= (const XYZval<T> &rs) { set(rs.x, rs.y); return *this; }
  266. FI XYval<T>& operator= (const XYZEval<T> &rs) { set(rs.x, rs.y); return *this; }
  267. // Override other operators to get intuitive behaviors
  268. FI XYval<T> operator+ (const XYval<T> &rs) const { XYval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
  269. FI XYval<T> operator+ (const XYval<T> &rs) { XYval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
  270. FI XYval<T> operator- (const XYval<T> &rs) const { XYval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
  271. FI XYval<T> operator- (const XYval<T> &rs) { XYval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
  272. FI XYval<T> operator* (const XYval<T> &rs) const { XYval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
  273. FI XYval<T> operator* (const XYval<T> &rs) { XYval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
  274. FI XYval<T> operator/ (const XYval<T> &rs) const { XYval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
  275. FI XYval<T> operator/ (const XYval<T> &rs) { XYval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
  276. FI XYval<T> operator+ (const XYZval<T> &rs) const { XYval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
  277. FI XYval<T> operator+ (const XYZval<T> &rs) { XYval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
  278. FI XYval<T> operator- (const XYZval<T> &rs) const { XYval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
  279. FI XYval<T> operator- (const XYZval<T> &rs) { XYval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
  280. FI XYval<T> operator* (const XYZval<T> &rs) const { XYval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
  281. FI XYval<T> operator* (const XYZval<T> &rs) { XYval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
  282. FI XYval<T> operator/ (const XYZval<T> &rs) const { XYval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
  283. FI XYval<T> operator/ (const XYZval<T> &rs) { XYval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
  284. FI XYval<T> operator+ (const XYZEval<T> &rs) const { XYval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
  285. FI XYval<T> operator+ (const XYZEval<T> &rs) { XYval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
  286. FI XYval<T> operator- (const XYZEval<T> &rs) const { XYval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
  287. FI XYval<T> operator- (const XYZEval<T> &rs) { XYval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
  288. FI XYval<T> operator* (const XYZEval<T> &rs) const { XYval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
  289. FI XYval<T> operator* (const XYZEval<T> &rs) { XYval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
  290. FI XYval<T> operator/ (const XYZEval<T> &rs) const { XYval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
  291. FI XYval<T> operator/ (const XYZEval<T> &rs) { XYval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
  292. FI XYval<T> operator* (const float &v) const { XYval<T> ls = *this; ls.x *= v; ls.y *= v; return ls; }
  293. FI XYval<T> operator* (const float &v) { XYval<T> ls = *this; ls.x *= v; ls.y *= v; return ls; }
  294. FI XYval<T> operator* (const int &v) const { XYval<T> ls = *this; ls.x *= v; ls.y *= v; return ls; }
  295. FI XYval<T> operator* (const int &v) { XYval<T> ls = *this; ls.x *= v; ls.y *= v; return ls; }
  296. FI XYval<T> operator/ (const float &v) const { XYval<T> ls = *this; ls.x /= v; ls.y /= v; return ls; }
  297. FI XYval<T> operator/ (const float &v) { XYval<T> ls = *this; ls.x /= v; ls.y /= v; return ls; }
  298. FI XYval<T> operator/ (const int &v) const { XYval<T> ls = *this; ls.x /= v; ls.y /= v; return ls; }
  299. FI XYval<T> operator/ (const int &v) { XYval<T> ls = *this; ls.x /= v; ls.y /= v; return ls; }
  300. FI XYval<T> operator>>(const int &v) const { XYval<T> ls = *this; _RS(ls.x); _RS(ls.y); return ls; }
  301. FI XYval<T> operator>>(const int &v) { XYval<T> ls = *this; _RS(ls.x); _RS(ls.y); return ls; }
  302. FI XYval<T> operator<<(const int &v) const { XYval<T> ls = *this; _LS(ls.x); _LS(ls.y); return ls; }
  303. FI XYval<T> operator<<(const int &v) { XYval<T> ls = *this; _LS(ls.x); _LS(ls.y); return ls; }
  304. FI const XYval<T> operator-() const { XYval<T> o = *this; o.x = -x; o.y = -y; return o; }
  305. FI XYval<T> operator-() { XYval<T> o = *this; o.x = -x; o.y = -y; return o; }
  306. // Modifier operators
  307. FI XYval<T>& operator+=(const XYval<T> &rs) { x += rs.x; y += rs.y; return *this; }
  308. FI XYval<T>& operator-=(const XYval<T> &rs) { x -= rs.x; y -= rs.y; return *this; }
  309. FI XYval<T>& operator*=(const XYval<T> &rs) { x *= rs.x; y *= rs.y; return *this; }
  310. FI XYval<T>& operator+=(const XYZval<T> &rs) { x += rs.x; y += rs.y; return *this; }
  311. FI XYval<T>& operator-=(const XYZval<T> &rs) { x -= rs.x; y -= rs.y; return *this; }
  312. FI XYval<T>& operator*=(const XYZval<T> &rs) { x *= rs.x; y *= rs.y; return *this; }
  313. FI XYval<T>& operator+=(const XYZEval<T> &rs) { x += rs.x; y += rs.y; return *this; }
  314. FI XYval<T>& operator-=(const XYZEval<T> &rs) { x -= rs.x; y -= rs.y; return *this; }
  315. FI XYval<T>& operator*=(const XYZEval<T> &rs) { x *= rs.x; y *= rs.y; return *this; }
  316. FI XYval<T>& operator*=(const float &v) { x *= v; y *= v; return *this; }
  317. FI XYval<T>& operator*=(const int &v) { x *= v; y *= v; return *this; }
  318. FI XYval<T>& operator>>=(const int &v) { _RS(x); _RS(y); return *this; }
  319. FI XYval<T>& operator<<=(const int &v) { _LS(x); _LS(y); return *this; }
  320. // Exact comparisons. For floats a "NEAR" operation may be better.
  321. FI bool operator==(const XYval<T> &rs) { return x == rs.x && y == rs.y; }
  322. FI bool operator==(const XYZval<T> &rs) { return x == rs.x && y == rs.y; }
  323. FI bool operator==(const XYZEval<T> &rs) { return x == rs.x && y == rs.y; }
  324. FI bool operator==(const XYval<T> &rs) const { return x == rs.x && y == rs.y; }
  325. FI bool operator==(const XYZval<T> &rs) const { return x == rs.x && y == rs.y; }
  326. FI bool operator==(const XYZEval<T> &rs) const { return x == rs.x && y == rs.y; }
  327. FI bool operator!=(const XYval<T> &rs) { return !operator==(rs); }
  328. FI bool operator!=(const XYZval<T> &rs) { return !operator==(rs); }
  329. FI bool operator!=(const XYZEval<T> &rs) { return !operator==(rs); }
  330. FI bool operator!=(const XYval<T> &rs) const { return !operator==(rs); }
  331. FI bool operator!=(const XYZval<T> &rs) const { return !operator==(rs); }
  332. FI bool operator!=(const XYZEval<T> &rs) const { return !operator==(rs); }
  333. };
  334. //
  335. // Linear Axes coordinates, counters, flags, etc.
  336. //
  337. template<typename T>
  338. struct XYZval {
  339. union {
  340. struct { T NUM_AXIS_ARGS(); };
  341. struct { T NUM_AXIS_LIST(a, b, c, _i, _j, _k, _u, _v, _w); };
  342. T pos[NUM_AXES];
  343. };
  344. // Set all to 0
  345. FI void reset() { NUM_AXIS_GANG(x =, y =, z =, i =, j =, k =, u =, v =, w =) 0; }
  346. // Setters taking struct types and arrays
  347. FI void set(const T px) { x = px; }
  348. FI void set(const T px, const T py) { x = px; y = py; }
  349. FI void set(const XYval<T> pxy) { x = pxy.x; y = pxy.y; }
  350. FI void set(const XYval<T> pxy, const T pz) { NUM_AXIS_CODE(x = pxy.x, y = pxy.y, z = pz, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP); }
  351. FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; }
  352. #if HAS_Z_AXIS
  353. FI void set(const T (&arr)[NUM_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); }
  354. FI void set(NUM_AXIS_ARGS(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w ); }
  355. #endif
  356. #if LOGICAL_AXES > NUM_AXES
  357. FI void set(const T (&arr)[LOGICAL_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); }
  358. FI void set(LOGICAL_AXIS_ARGS(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w ); }
  359. #if DISTINCT_AXES > LOGICAL_AXES
  360. FI void set(const T (&arr)[DISTINCT_AXES]) { NUM_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5], u = arr[6], v = arr[7], w = arr[8]); }
  361. #endif
  362. #endif
  363. #if HAS_I_AXIS
  364. FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; }
  365. #endif
  366. #if HAS_J_AXIS
  367. FI void set(const T px, const T py, const T pz, const T pi) { x = px; y = py; z = pz; i = pi; }
  368. #endif
  369. #if HAS_K_AXIS
  370. FI void set(const T px, const T py, const T pz, const T pi, const T pj) { x = px; y = py; z = pz; i = pi; j = pj; }
  371. #endif
  372. #if HAS_U_AXIS
  373. FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; }
  374. #endif
  375. #if HAS_V_AXIS
  376. FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pm) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; u = pu; }
  377. #endif
  378. #if HAS_W_AXIS
  379. FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pm, const T po) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; u = pu; v = pv; }
  380. #endif
  381. // Length reduced to one dimension
  382. FI T magnitude() const { return (T)sqrtf(NUM_AXIS_GANG(x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)); }
  383. // Pointer to the data as a simple array
  384. FI operator T* () { return pos; }
  385. // If any element is true then it's true
  386. FI operator bool() { return NUM_AXIS_GANG(x, || y, || z, || i, || j, || k, || u, || v, || w); }
  387. // Explicit copy and copies with conversion
  388. FI XYZval<T> copy() const { XYZval<T> o = *this; return o; }
  389. FI XYZval<T> ABS() const { return NUM_AXIS_ARRAY(T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k)), T(_ABS(u)), T(_ABS(v)), T(_ABS(w))); }
  390. FI XYZval<int16_t> asInt() { return NUM_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); }
  391. FI XYZval<int16_t> asInt() const { return NUM_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); }
  392. FI XYZval<int32_t> asLong() { return NUM_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); }
  393. FI XYZval<int32_t> asLong() const { return NUM_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); }
  394. FI XYZval<int32_t> ROUNDL() { return NUM_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); }
  395. FI XYZval<int32_t> ROUNDL() const { return NUM_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); }
  396. FI XYZval<float> asFloat() { return NUM_AXIS_ARRAY(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(i), static_cast<float>(j), static_cast<float>(k), static_cast<float>(u), static_cast<float>(v), static_cast<float>(w)); }
  397. FI XYZval<float> asFloat() const { return NUM_AXIS_ARRAY(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(i), static_cast<float>(j), static_cast<float>(k), static_cast<float>(u), static_cast<float>(v), static_cast<float>(w)); }
  398. FI XYZval<float> reciprocal() const { return NUM_AXIS_ARRAY(_RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k), _RECIP(u), _RECIP(v), _RECIP(w)); }
  399. // Marlin workspace shifting is done with G92 and M206
  400. FI XYZval<float> asLogical() const { XYZval<float> o = asFloat(); toLogical(o); return o; }
  401. FI XYZval<float> asNative() const { XYZval<float> o = asFloat(); toNative(o); return o; }
  402. // In-place cast to types having fewer fields
  403. FI operator XYval<T>&() { return *(XYval<T>*)this; }
  404. FI operator const XYval<T>&() const { return *(const XYval<T>*)this; }
  405. // Cast to a type with more fields by making a new object
  406. FI operator XYZEval<T>() const { return NUM_AXIS_ARRAY(x, y, z, i, j, k, u, v, w); }
  407. // Accessor via an AxisEnum (or any integer) [index]
  408. FI T& operator[](const int n) { return pos[n]; }
  409. FI const T& operator[](const int n) const { return pos[n]; }
  410. // Assignment operator overrides do the expected thing
  411. FI XYZval<T>& operator= (const T v) { set(ARRAY_N_1(NUM_AXES, v)); return *this; }
  412. FI XYZval<T>& operator= (const XYval<T> &rs) { set(rs.x, rs.y ); return *this; }
  413. FI XYZval<T>& operator= (const XYZEval<T> &rs) { set(NUM_AXIS_ELEM(rs)); return *this; }
  414. // Override other operators to get intuitive behaviors
  415. FI XYZval<T> operator+ (const XYval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; }
  416. FI XYZval<T> operator+ (const XYval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; }
  417. FI XYZval<T> operator- (const XYval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; }
  418. FI XYZval<T> operator- (const XYval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; }
  419. FI XYZval<T> operator* (const XYval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; }
  420. FI XYZval<T> operator* (const XYval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; }
  421. FI XYZval<T> operator/ (const XYval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; }
  422. FI XYZval<T> operator/ (const XYval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP , NOOP , NOOP , NOOP , NOOP , NOOP , NOOP ); return ls; }
  423. FI XYZval<T> operator+ (const XYZval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; }
  424. FI XYZval<T> operator+ (const XYZval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; }
  425. FI XYZval<T> operator- (const XYZval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; }
  426. FI XYZval<T> operator- (const XYZval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; }
  427. FI XYZval<T> operator* (const XYZval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; }
  428. FI XYZval<T> operator* (const XYZval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; }
  429. FI XYZval<T> operator/ (const XYZval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; }
  430. FI XYZval<T> operator/ (const XYZval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; }
  431. FI XYZval<T> operator+ (const XYZEval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; }
  432. FI XYZval<T> operator+ (const XYZEval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; }
  433. FI XYZval<T> operator- (const XYZEval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; }
  434. FI XYZval<T> operator- (const XYZEval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; }
  435. FI XYZval<T> operator* (const XYZEval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; }
  436. FI XYZval<T> operator* (const XYZEval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; }
  437. FI XYZval<T> operator/ (const XYZEval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; }
  438. FI XYZval<T> operator/ (const XYZEval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; }
  439. FI XYZval<T> operator* (const float &v) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v, ls.u *= v, ls.v *= v, ls.w *= v ); return ls; }
  440. FI XYZval<T> operator* (const float &v) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v, ls.u *= v, ls.v *= v, ls.w *= v ); return ls; }
  441. FI XYZval<T> operator* (const int &v) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v, ls.u *= v, ls.v *= v, ls.w *= v ); return ls; }
  442. FI XYZval<T> operator* (const int &v) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v, ls.u *= v, ls.v *= v, ls.w *= v ); return ls; }
  443. FI XYZval<T> operator/ (const float &v) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v, ls.u /= v, ls.v /= v, ls.w /= v ); return ls; }
  444. FI XYZval<T> operator/ (const float &v) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v, ls.u /= v, ls.v /= v, ls.w /= v ); return ls; }
  445. FI XYZval<T> operator/ (const int &v) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v, ls.u /= v, ls.v /= v, ls.w /= v ); return ls; }
  446. FI XYZval<T> operator/ (const int &v) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v, ls.u /= v, ls.v /= v, ls.w /= v ); return ls; }
  447. FI XYZval<T> operator>>(const int &v) const { XYZval<T> ls = *this; NUM_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k), _RS(ls.u), _RS(ls.v), _RS(ls.w) ); return ls; }
  448. FI XYZval<T> operator>>(const int &v) { XYZval<T> ls = *this; NUM_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k), _RS(ls.u), _RS(ls.v), _RS(ls.w) ); return ls; }
  449. FI XYZval<T> operator<<(const int &v) const { XYZval<T> ls = *this; NUM_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k), _LS(ls.u), _LS(ls.v), _LS(ls.w) ); return ls; }
  450. FI XYZval<T> operator<<(const int &v) { XYZval<T> ls = *this; NUM_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k), _LS(ls.u), _LS(ls.v), _LS(ls.w) ); return ls; }
  451. FI const XYZval<T> operator-() const { XYZval<T> o = *this; NUM_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z, o.i = -i, o.j = -j, o.k = -k, o.u = -u, o.v = -v, o.w = -w); return o; }
  452. FI XYZval<T> operator-() { XYZval<T> o = *this; NUM_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z, o.i = -i, o.j = -j, o.k = -k, o.u = -u, o.v = -v, o.w = -w); return o; }
  453. // Modifier operators
  454. FI XYZval<T>& operator+=(const XYval<T> &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP ); return *this; }
  455. FI XYZval<T>& operator-=(const XYval<T> &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP ); return *this; }
  456. FI XYZval<T>& operator*=(const XYval<T> &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP ); return *this; }
  457. FI XYZval<T>& operator/=(const XYval<T> &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP, NOOP ); return *this; }
  458. FI XYZval<T>& operator+=(const XYZval<T> &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; }
  459. FI XYZval<T>& operator-=(const XYZval<T> &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; }
  460. FI XYZval<T>& operator*=(const XYZval<T> &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; }
  461. FI XYZval<T>& operator/=(const XYZval<T> &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; }
  462. FI XYZval<T>& operator+=(const XYZEval<T> &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; }
  463. FI XYZval<T>& operator-=(const XYZEval<T> &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; }
  464. FI XYZval<T>& operator*=(const XYZEval<T> &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; }
  465. FI XYZval<T>& operator/=(const XYZEval<T> &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; }
  466. FI XYZval<T>& operator*=(const float &v) { NUM_AXIS_CODE(x *= v, y *= v, z *= v, i *= v, j *= v, k *= v, u *= v, v *= v, w *= v); return *this; }
  467. FI XYZval<T>& operator*=(const int &v) { NUM_AXIS_CODE(x *= v, y *= v, z *= v, i *= v, j *= v, k *= v, u *= v, v *= v, w *= v); return *this; }
  468. FI XYZval<T>& operator>>=(const int &v) { NUM_AXIS_CODE(_RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k), _RS(u), _RS(v), _RS(w)); return *this; }
  469. FI XYZval<T>& operator<<=(const int &v) { NUM_AXIS_CODE(_LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k), _LS(u), _LS(v), _LS(w)); return *this; }
  470. // Exact comparisons. For floats a "NEAR" operation may be better.
  471. FI bool operator==(const XYZEval<T> &rs) { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); }
  472. FI bool operator==(const XYZEval<T> &rs) const { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); }
  473. FI bool operator!=(const XYZEval<T> &rs) { return !operator==(rs); }
  474. FI bool operator!=(const XYZEval<T> &rs) const { return !operator==(rs); }
  475. };
  476. //
  477. // Logical Axes coordinates, counters, etc.
  478. //
  479. template<typename T>
  480. struct XYZEval {
  481. union {
  482. struct { T LOGICAL_AXIS_ARGS(); };
  483. struct { T LOGICAL_AXIS_LIST(_e, a, b, c, _i, _j, _k, _u, _v, _w); };
  484. T pos[LOGICAL_AXES];
  485. };
  486. // Reset all to 0
  487. FI void reset() { LOGICAL_AXIS_GANG(e =, x =, y =, z =, i =, j =, k =, u =, v =, w =) 0; }
  488. // Setters for some number of linear axes, not all
  489. FI void set(const T px) { x = px; }
  490. FI void set(const T px, const T py) { x = px; y = py; }
  491. #if HAS_I_AXIS
  492. FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; }
  493. #endif
  494. #if HAS_J_AXIS
  495. FI void set(const T px, const T py, const T pz, const T pi) { x = px; y = py; z = pz; i = pi; }
  496. #endif
  497. #if HAS_K_AXIS
  498. FI void set(const T px, const T py, const T pz, const T pi, const T pj) { x = px; y = py; z = pz; i = pi; j = pj; }
  499. #endif
  500. #if HAS_U_AXIS
  501. FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; }
  502. #endif
  503. #if HAS_V_AXIS
  504. FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pm) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; u = pu; }
  505. #endif
  506. #if HAS_W_AXIS
  507. FI void set(const T px, const T py, const T pz, const T pi, const T pj, const T pk, const T pm, const T po) { x = px; y = py; z = pz; i = pi; j = pj; k = pk; u = pm; v = pv; }
  508. #endif
  509. // Setters taking struct types and arrays
  510. FI void set(const XYval<T> pxy) { x = pxy.x; y = pxy.y; }
  511. FI void set(const XYZval<T> pxyz) { set(NUM_AXIS_ELEM(pxyz)); }
  512. #if HAS_Z_AXIS
  513. FI void set(NUM_AXIS_ARGS(const T)) { NUM_AXIS_CODE(a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w); }
  514. #endif
  515. FI void set(const XYval<T> pxy, const T pz) { set(pxy); TERN_(HAS_Z_AXIS, z = pz); }
  516. #if LOGICAL_AXES > NUM_AXES
  517. FI void set(const XYval<T> pxy, const T pz, const T pe) { set(pxy, pz); e = pe; }
  518. FI void set(const XYZval<T> pxyz, const T pe) { set(pxyz); e = pe; }
  519. FI void set(LOGICAL_AXIS_ARGS(const T)) { LOGICAL_AXIS_CODE(_e = e, a = x, b = y, c = z, _i = i, _j = j, _k = k, _u = u, _v = v, _w = w); }
  520. #endif
  521. // Length reduced to one dimension
  522. FI T magnitude() const { return (T)sqrtf(LOGICAL_AXIS_GANG(+ e*e, + x*x, + y*y, + z*z, + i*i, + j*j, + k*k, + u*u, + v*v, + w*w)); }
  523. // Pointer to the data as a simple array
  524. FI operator T* () { return pos; }
  525. // If any element is true then it's true
  526. FI operator bool() { return 0 LOGICAL_AXIS_GANG(|| e, || x, || y, || z, || i, || j, || k, || u, || v, || w); }
  527. // Explicit copy and copies with conversion
  528. FI XYZEval<T> copy() const { XYZEval<T> v = *this; return v; }
  529. FI XYZEval<T> ABS() const { return LOGICAL_AXIS_ARRAY(T(_ABS(e)), T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k)), T(_ABS(u)), T(_ABS(v)), T(_ABS(w))); }
  530. FI XYZEval<int16_t> asInt() { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); }
  531. FI XYZEval<int16_t> asInt() const { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k), int16_t(u), int16_t(v), int16_t(w)); }
  532. FI XYZEval<int32_t> asLong() { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); }
  533. FI XYZEval<int32_t> asLong() const { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k), int32_t(u), int32_t(v), int32_t(w)); }
  534. FI XYZEval<int32_t> ROUNDL() { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); }
  535. FI XYZEval<int32_t> ROUNDL() const { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k)), int32_t(LROUND(u)), int32_t(LROUND(v)), int32_t(LROUND(w))); }
  536. FI XYZEval<float> asFloat() { return LOGICAL_AXIS_ARRAY(static_cast<float>(e), static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(i), static_cast<float>(j), static_cast<float>(k), static_cast<float>(u), static_cast<float>(v), static_cast<float>(w)); }
  537. FI XYZEval<float> asFloat() const { return LOGICAL_AXIS_ARRAY(static_cast<float>(e), static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(i), static_cast<float>(j), static_cast<float>(k), static_cast<float>(u), static_cast<float>(v), static_cast<float>(w)); }
  538. FI XYZEval<float> reciprocal() const { return LOGICAL_AXIS_ARRAY(_RECIP(e), _RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k), _RECIP(u), _RECIP(v), _RECIP(w)); }
  539. // Marlin workspace shifting is done with G92 and M206
  540. FI XYZEval<float> asLogical() const { XYZEval<float> o = asFloat(); toLogical(o); return o; }
  541. FI XYZEval<float> asNative() const { XYZEval<float> o = asFloat(); toNative(o); return o; }
  542. // In-place cast to types having fewer fields
  543. FI operator XYval<T>&() { return *(XYval<T>*)this; }
  544. FI operator const XYval<T>&() const { return *(const XYval<T>*)this; }
  545. FI operator XYZval<T>&() { return *(XYZval<T>*)this; }
  546. FI operator const XYZval<T>&() const { return *(const XYZval<T>*)this; }
  547. // Accessor via an AxisEnum (or any integer) [index]
  548. FI T& operator[](const int n) { return pos[n]; }
  549. FI const T& operator[](const int n) const { return pos[n]; }
  550. // Assignment operator overrides do the expected thing
  551. FI XYZEval<T>& operator= (const T v) { set(LIST_N_1(NUM_AXES, v)); return *this; }
  552. FI XYZEval<T>& operator= (const XYval<T> &rs) { set(rs.x, rs.y); return *this; }
  553. FI XYZEval<T>& operator= (const XYZval<T> &rs) { set(NUM_AXIS_ELEM(rs)); return *this; }
  554. // Override other operators to get intuitive behaviors
  555. FI XYZEval<T> operator+ (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
  556. FI XYZEval<T> operator+ (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
  557. FI XYZEval<T> operator- (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
  558. FI XYZEval<T> operator- (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
  559. FI XYZEval<T> operator* (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
  560. FI XYZEval<T> operator* (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
  561. FI XYZEval<T> operator/ (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
  562. FI XYZEval<T> operator/ (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
  563. FI XYZEval<T> operator+ (const XYZval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; }
  564. FI XYZEval<T> operator+ (const XYZval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; }
  565. FI XYZEval<T> operator- (const XYZval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; }
  566. FI XYZEval<T> operator- (const XYZval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; }
  567. FI XYZEval<T> operator* (const XYZval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; }
  568. FI XYZEval<T> operator* (const XYZval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; }
  569. FI XYZEval<T> operator/ (const XYZval<T> &rs) const { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; }
  570. FI XYZEval<T> operator/ (const XYZval<T> &rs) { XYZval<T> ls = *this; NUM_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; }
  571. FI XYZEval<T> operator+ (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e += rs.e, ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; }
  572. FI XYZEval<T> operator+ (const XYZEval<T> &rs) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e += rs.e, ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k, ls.u += rs.u, ls.v += rs.v, ls.w += rs.w); return ls; }
  573. FI XYZEval<T> operator- (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e -= rs.e, ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; }
  574. FI XYZEval<T> operator- (const XYZEval<T> &rs) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e -= rs.e, ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k, ls.u -= rs.u, ls.v -= rs.v, ls.w -= rs.w); return ls; }
  575. FI XYZEval<T> operator* (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e *= rs.e, ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; }
  576. FI XYZEval<T> operator* (const XYZEval<T> &rs) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e *= rs.e, ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k, ls.u *= rs.u, ls.v *= rs.v, ls.w *= rs.w); return ls; }
  577. FI XYZEval<T> operator/ (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e /= rs.e, ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; }
  578. FI XYZEval<T> operator/ (const XYZEval<T> &rs) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e /= rs.e, ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k, ls.u /= rs.u, ls.v /= rs.v, ls.w /= rs.w); return ls; }
  579. FI XYZEval<T> operator* (const float &v) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v, ls.u *= v, ls.v *= v, ls.w *= v ); return ls; }
  580. FI XYZEval<T> operator* (const float &v) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v, ls.u *= v, ls.v *= v, ls.w *= v ); return ls; }
  581. FI XYZEval<T> operator* (const int &v) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v, ls.u *= v, ls.v *= v, ls.w *= v ); return ls; }
  582. FI XYZEval<T> operator* (const int &v) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v, ls.u *= v, ls.v *= v, ls.w *= v ); return ls; }
  583. FI XYZEval<T> operator/ (const float &v) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v, ls.u /= v, ls.v /= v, ls.w /= v ); return ls; }
  584. FI XYZEval<T> operator/ (const float &v) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v, ls.u /= v, ls.v /= v, ls.w /= v ); return ls; }
  585. FI XYZEval<T> operator/ (const int &v) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v, ls.u /= v, ls.v /= v, ls.w /= v ); return ls; }
  586. FI XYZEval<T> operator/ (const int &v) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v, ls.u /= v, ls.v /= v, ls.w /= v ); return ls; }
  587. FI XYZEval<T> operator>>(const int &v) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(_RS(ls.e), _RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k), _RS(ls.u), _RS(ls.v), _RS(ls.w) ); return ls; }
  588. FI XYZEval<T> operator>>(const int &v) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(_RS(ls.e), _RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k), _RS(ls.u), _RS(ls.v), _RS(ls.w) ); return ls; }
  589. FI XYZEval<T> operator<<(const int &v) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(_LS(ls.e), _LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k), _LS(ls.u), _LS(ls.v), _LS(ls.w) ); return ls; }
  590. FI XYZEval<T> operator<<(const int &v) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(_LS(ls.e), _LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k), _LS(ls.u), _LS(ls.v), _LS(ls.w) ); return ls; }
  591. FI const XYZEval<T> operator-() const { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z, -i, -j, -k, -u, -v, -w); }
  592. FI XYZEval<T> operator-() { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z, -i, -j, -k, -u, -v, -w); }
  593. // Modifier operators
  594. FI XYZEval<T>& operator+=(const XYval<T> &rs) { x += rs.x; y += rs.y; return *this; }
  595. FI XYZEval<T>& operator-=(const XYval<T> &rs) { x -= rs.x; y -= rs.y; return *this; }
  596. FI XYZEval<T>& operator*=(const XYval<T> &rs) { x *= rs.x; y *= rs.y; return *this; }
  597. FI XYZEval<T>& operator/=(const XYval<T> &rs) { x /= rs.x; y /= rs.y; return *this; }
  598. FI XYZEval<T>& operator+=(const XYZval<T> &rs) { NUM_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; }
  599. FI XYZEval<T>& operator-=(const XYZval<T> &rs) { NUM_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; }
  600. FI XYZEval<T>& operator*=(const XYZval<T> &rs) { NUM_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; }
  601. FI XYZEval<T>& operator/=(const XYZval<T> &rs) { NUM_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; }
  602. FI XYZEval<T>& operator+=(const XYZEval<T> &rs) { LOGICAL_AXIS_CODE(e += rs.e, x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k, u += rs.u, v += rs.v, w += rs.w); return *this; }
  603. FI XYZEval<T>& operator-=(const XYZEval<T> &rs) { LOGICAL_AXIS_CODE(e -= rs.e, x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k, u -= rs.u, v -= rs.v, w -= rs.w); return *this; }
  604. FI XYZEval<T>& operator*=(const XYZEval<T> &rs) { LOGICAL_AXIS_CODE(e *= rs.e, x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k, u *= rs.u, v *= rs.v, w *= rs.w); return *this; }
  605. FI XYZEval<T>& operator/=(const XYZEval<T> &rs) { LOGICAL_AXIS_CODE(e /= rs.e, x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k, u /= rs.u, v /= rs.v, w /= rs.w); return *this; }
  606. FI XYZEval<T>& operator*=(const T &v) { LOGICAL_AXIS_CODE(e *= v, x *= v, y *= v, z *= v, i *= v, j *= v, k *= v, u *= v, v *= v, w *= v); return *this; }
  607. FI XYZEval<T>& operator>>=(const int &v) { LOGICAL_AXIS_CODE(_RS(e), _RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k), _RS(u), _RS(v), _RS(w)); return *this; }
  608. FI XYZEval<T>& operator<<=(const int &v) { LOGICAL_AXIS_CODE(_LS(e), _LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k), _LS(u), _LS(v), _LS(w)); return *this; }
  609. // Exact comparisons. For floats a "NEAR" operation may be better.
  610. FI bool operator==(const XYZval<T> &rs) { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); }
  611. FI bool operator==(const XYZval<T> &rs) const { return true NUM_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k, && u == rs.u, && v == rs.v, && w == rs.w); }
  612. FI bool operator!=(const XYZval<T> &rs) { return !operator==(rs); }
  613. FI bool operator!=(const XYZval<T> &rs) const { return !operator==(rs); }
  614. };
  615. #undef _RECIP
  616. #undef _ABS
  617. #undef _LS
  618. #undef _RS
  619. #undef FI