Ver código fonte

G26 Hilbert Curve followup (#21480)

Marcio T 3 anos atrás
pai
commit
45c1432946
Nenhuma conta vinculada ao e-mail do autor do commit

+ 1
- 1
Marlin/src/core/utility.h Ver arquivo

34
   inline void serial_delay(const millis_t) {}
34
   inline void serial_delay(const millis_t) {}
35
 #endif
35
 #endif
36
 
36
 
37
-#if GRID_MAX_POINTS_X && GRID_MAX_POINTS_Y
37
+#if (GRID_MAX_POINTS_X) && (GRID_MAX_POINTS_Y)
38
 
38
 
39
   // 16x16 bit arrays
39
   // 16x16 bit arrays
40
   template <int W, int H>
40
   template <int W, int H>

+ 19
- 19
Marlin/src/feature/bedlevel/abl/abl.cpp Ver arquivo

85
 //#define EXTRAPOLATE_FROM_EDGE
85
 //#define EXTRAPOLATE_FROM_EDGE
86
 
86
 
87
 #if ENABLED(EXTRAPOLATE_FROM_EDGE)
87
 #if ENABLED(EXTRAPOLATE_FROM_EDGE)
88
-  #if GRID_MAX_POINTS_X < GRID_MAX_POINTS_Y
88
+  #if (GRID_MAX_POINTS_X) < (GRID_MAX_POINTS_Y)
89
     #define HALF_IN_X
89
     #define HALF_IN_X
90
-  #elif GRID_MAX_POINTS_Y < GRID_MAX_POINTS_X
90
+  #elif (GRID_MAX_POINTS_Y) < (GRID_MAX_POINTS_X)
91
     #define HALF_IN_Y
91
     #define HALF_IN_Y
92
   #endif
92
   #endif
93
 #endif
93
 #endif
98
  */
98
  */
99
 void extrapolate_unprobed_bed_level() {
99
 void extrapolate_unprobed_bed_level() {
100
   #ifdef HALF_IN_X
100
   #ifdef HALF_IN_X
101
-    constexpr uint8_t ctrx2 = 0, xlen = GRID_MAX_POINTS_X - 1;
101
+    constexpr uint8_t ctrx2 = 0, xend = GRID_MAX_POINTS_X - 1;
102
   #else
102
   #else
103
-    constexpr uint8_t ctrx1 = (GRID_MAX_POINTS_X - 1) / 2, // left-of-center
104
-                      ctrx2 = (GRID_MAX_POINTS_X) / 2,     // right-of-center
105
-                      xlen = ctrx1;
103
+    constexpr uint8_t ctrx1 = (GRID_MAX_CELLS_X) / 2, // left-of-center
104
+                      ctrx2 = (GRID_MAX_POINTS_X) / 2,  // right-of-center
105
+                      xend = ctrx1;
106
   #endif
106
   #endif
107
 
107
 
108
   #ifdef HALF_IN_Y
108
   #ifdef HALF_IN_Y
109
-    constexpr uint8_t ctry2 = 0, ylen = GRID_MAX_POINTS_Y - 1;
109
+    constexpr uint8_t ctry2 = 0, yend = GRID_MAX_POINTS_Y - 1;
110
   #else
110
   #else
111
-    constexpr uint8_t ctry1 = (GRID_MAX_POINTS_Y - 1) / 2, // top-of-center
112
-                      ctry2 = (GRID_MAX_POINTS_Y) / 2,     // bottom-of-center
113
-                      ylen = ctry1;
111
+    constexpr uint8_t ctry1 = (GRID_MAX_CELLS_Y) / 2, // top-of-center
112
+                      ctry2 = (GRID_MAX_POINTS_Y) / 2,  // bottom-of-center
113
+                      yend = ctry1;
114
   #endif
114
   #endif
115
 
115
 
116
-  LOOP_LE_N(xo, xlen)
117
-    LOOP_LE_N(yo, ylen) {
116
+  LOOP_LE_N(xo, xend)
117
+    LOOP_LE_N(yo, yend) {
118
       uint8_t x2 = ctrx2 + xo, y2 = ctry2 + yo;
118
       uint8_t x2 = ctrx2 + xo, y2 = ctry2 + yo;
119
       #ifndef HALF_IN_X
119
       #ifndef HALF_IN_X
120
         const uint8_t x1 = ctrx1 - xo;
120
         const uint8_t x1 = ctrx1 - xo;
143
 
143
 
144
 #if ENABLED(ABL_BILINEAR_SUBDIVISION)
144
 #if ENABLED(ABL_BILINEAR_SUBDIVISION)
145
 
145
 
146
-  #define ABL_GRID_POINTS_VIRT_X (GRID_MAX_POINTS_X - 1) * (BILINEAR_SUBDIVISIONS) + 1
147
-  #define ABL_GRID_POINTS_VIRT_Y (GRID_MAX_POINTS_Y - 1) * (BILINEAR_SUBDIVISIONS) + 1
146
+  #define ABL_GRID_POINTS_VIRT_X GRID_MAX_CELLS_X * (BILINEAR_SUBDIVISIONS) + 1
147
+  #define ABL_GRID_POINTS_VIRT_Y GRID_MAX_CELLS_Y * (BILINEAR_SUBDIVISIONS) + 1
148
   #define ABL_TEMP_POINTS_X (GRID_MAX_POINTS_X + 2)
148
   #define ABL_TEMP_POINTS_X (GRID_MAX_POINTS_X + 2)
149
   #define ABL_TEMP_POINTS_Y (GRID_MAX_POINTS_Y + 2)
149
   #define ABL_TEMP_POINTS_Y (GRID_MAX_POINTS_Y + 2)
150
   float z_values_virt[ABL_GRID_POINTS_VIRT_X][ABL_GRID_POINTS_VIRT_Y];
150
   float z_values_virt[ABL_GRID_POINTS_VIRT_X][ABL_GRID_POINTS_VIRT_Y];
161
   #define LINEAR_EXTRAPOLATION(E, I) ((E) * 2 - (I))
161
   #define LINEAR_EXTRAPOLATION(E, I) ((E) * 2 - (I))
162
   float bed_level_virt_coord(const uint8_t x, const uint8_t y) {
162
   float bed_level_virt_coord(const uint8_t x, const uint8_t y) {
163
     uint8_t ep = 0, ip = 1;
163
     uint8_t ep = 0, ip = 1;
164
-    if (x > GRID_MAX_POINTS_X + 1 || y > GRID_MAX_POINTS_Y + 1) {
164
+    if (x > (GRID_MAX_POINTS_X) + 1 || y > (GRID_MAX_POINTS_Y) + 1) {
165
       // The requested point requires extrapolating two points beyond the mesh.
165
       // The requested point requires extrapolating two points beyond the mesh.
166
       // These values are only requested for the edges of the mesh, which are always an actual mesh point,
166
       // These values are only requested for the edges of the mesh, which are always an actual mesh point,
167
       // and do not require interpolation. When interpolation is not needed, this "Mesh + 2" point is
167
       // and do not require interpolation. When interpolation is not needed, this "Mesh + 2" point is
171
     }
171
     }
172
     if (!x || x == ABL_TEMP_POINTS_X - 1) {
172
     if (!x || x == ABL_TEMP_POINTS_X - 1) {
173
       if (x) {
173
       if (x) {
174
-        ep = GRID_MAX_POINTS_X - 1;
175
-        ip = GRID_MAX_POINTS_X - 2;
174
+        ep = (GRID_MAX_POINTS_X) - 1;
175
+        ip = GRID_MAX_CELLS_X - 1;
176
       }
176
       }
177
       if (WITHIN(y, 1, ABL_TEMP_POINTS_Y - 2))
177
       if (WITHIN(y, 1, ABL_TEMP_POINTS_Y - 2))
178
         return LINEAR_EXTRAPOLATION(
178
         return LINEAR_EXTRAPOLATION(
187
     }
187
     }
188
     if (!y || y == ABL_TEMP_POINTS_Y - 1) {
188
     if (!y || y == ABL_TEMP_POINTS_Y - 1) {
189
       if (y) {
189
       if (y) {
190
-        ep = GRID_MAX_POINTS_Y - 1;
191
-        ip = GRID_MAX_POINTS_Y - 2;
190
+        ep = (GRID_MAX_POINTS_Y) - 1;
191
+        ip = GRID_MAX_CELLS_Y - 1;
192
       }
192
       }
193
       if (WITHIN(x, 1, ABL_TEMP_POINTS_X - 2))
193
       if (WITHIN(x, 1, ABL_TEMP_POINTS_X - 2))
194
         return LINEAR_EXTRAPOLATION(
194
         return LINEAR_EXTRAPOLATION(

+ 3
- 5
Marlin/src/feature/bedlevel/hilbert_curve.cpp Ver arquivo

36
 static inline bool eval_candidate(int8_t x, int8_t y, hilbert_curve::callback_ptr func, void *data) {
36
 static inline bool eval_candidate(int8_t x, int8_t y, hilbert_curve::callback_ptr func, void *data) {
37
   // The print bed likely has fewer points than the full Hilbert
37
   // The print bed likely has fewer points than the full Hilbert
38
   // curve, so cull unecessary points
38
   // curve, so cull unecessary points
39
-  return x < GRID_MAX_POINTS_X && y < GRID_MAX_POINTS_Y ? func(x, y, data) : false;
39
+  return x < (GRID_MAX_POINTS_X) && y < (GRID_MAX_POINTS_Y) ? func(x, y, data) : false;
40
 }
40
 }
41
 
41
 
42
 bool hilbert_curve::hilbert(int8_t x, int8_t y, int8_t xi, int8_t xj, int8_t yi, int8_t yj, uint8_t n, hilbert_curve::callback_ptr func, void *data) {
42
 bool hilbert_curve::hilbert(int8_t x, int8_t y, int8_t xi, int8_t xj, int8_t yi, int8_t yj, uint8_t n, hilbert_curve::callback_ptr func, void *data) {
102
  */
102
  */
103
 bool hilbert_curve::search_from_closest(const xy_pos_t &pos, hilbert_curve::callback_ptr func, void *data) {
103
 bool hilbert_curve::search_from_closest(const xy_pos_t &pos, hilbert_curve::callback_ptr func, void *data) {
104
   // Find closest grid intersection
104
   // Find closest grid intersection
105
-  uint8_t grid_x = LROUND(float(pos.x - MESH_MIN_X) / MESH_X_DIST);
106
-  uint8_t grid_y = LROUND(float(pos.y - MESH_MIN_Y) / MESH_Y_DIST);
107
-  LIMIT(grid_x, 0, GRID_MAX_POINTS_X);
108
-  LIMIT(grid_y, 0, GRID_MAX_POINTS_Y);
105
+  const uint8_t grid_x = LROUND(constrain(float(pos.x - (MESH_MIN_X)) / (MESH_X_DIST), 0, (GRID_MAX_POINTS_X) - 1));
106
+  const uint8_t grid_y = LROUND(constrain(float(pos.y - (MESH_MIN_Y)) / (MESH_Y_DIST), 0, (GRID_MAX_POINTS_Y) - 1));
109
   return search_from(grid_x, grid_y, func, data);
107
   return search_from(grid_x, grid_y, func, data);
110
 }
108
 }
111
 
109
 

+ 4
- 4
Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.cpp Ver arquivo

64
     void mesh_bed_leveling::line_to_destination(const_feedRate_t scaled_fr_mm_s, uint8_t x_splits, uint8_t y_splits) {
64
     void mesh_bed_leveling::line_to_destination(const_feedRate_t scaled_fr_mm_s, uint8_t x_splits, uint8_t y_splits) {
65
       // Get current and destination cells for this line
65
       // Get current and destination cells for this line
66
       xy_int8_t scel = cell_indexes(current_position), ecel = cell_indexes(destination);
66
       xy_int8_t scel = cell_indexes(current_position), ecel = cell_indexes(destination);
67
-      NOMORE(scel.x, GRID_MAX_POINTS_X - 2);
68
-      NOMORE(scel.y, GRID_MAX_POINTS_Y - 2);
69
-      NOMORE(ecel.x, GRID_MAX_POINTS_X - 2);
70
-      NOMORE(ecel.y, GRID_MAX_POINTS_Y - 2);
67
+      NOMORE(scel.x, GRID_MAX_CELLS_X - 1);
68
+      NOMORE(scel.y, GRID_MAX_CELLS_Y - 1);
69
+      NOMORE(ecel.x, GRID_MAX_CELLS_X - 1);
70
+      NOMORE(ecel.y, GRID_MAX_CELLS_Y - 1);
71
 
71
 
72
       // Start and end in the same cell? No split needed.
72
       // Start and end in the same cell? No split needed.
73
       if (scel == ecel) {
73
       if (scel == ecel) {

+ 7
- 7
Marlin/src/feature/bedlevel/mbl/mesh_bed_leveling.h Ver arquivo

32
   MeshReset       // G29 S5
32
   MeshReset       // G29 S5
33
 };
33
 };
34
 
34
 
35
-#define MESH_X_DIST (float(MESH_MAX_X - (MESH_MIN_X)) / float(GRID_MAX_POINTS_X - 1))
36
-#define MESH_Y_DIST (float(MESH_MAX_Y - (MESH_MIN_Y)) / float(GRID_MAX_POINTS_Y - 1))
35
+#define MESH_X_DIST (float(MESH_MAX_X - (MESH_MIN_X)) / (GRID_MAX_CELLS_X))
36
+#define MESH_Y_DIST (float(MESH_MAX_Y - (MESH_MIN_Y)) / (GRID_MAX_CELLS_Y))
37
 #define _GET_MESH_X(I) mbl.index_to_xpos[I]
37
 #define _GET_MESH_X(I) mbl.index_to_xpos[I]
38
 #define _GET_MESH_Y(J) mbl.index_to_ypos[J]
38
 #define _GET_MESH_Y(J) mbl.index_to_ypos[J]
39
 #define Z_VALUES_ARR mbl.z_values
39
 #define Z_VALUES_ARR mbl.z_values
61
   static inline void zigzag(const int8_t index, int8_t &px, int8_t &py) {
61
   static inline void zigzag(const int8_t index, int8_t &px, int8_t &py) {
62
     px = index % (GRID_MAX_POINTS_X);
62
     px = index % (GRID_MAX_POINTS_X);
63
     py = index / (GRID_MAX_POINTS_X);
63
     py = index / (GRID_MAX_POINTS_X);
64
-    if (py & 1) px = (GRID_MAX_POINTS_X - 1) - px; // Zig zag
64
+    if (py & 1) px = (GRID_MAX_POINTS_X) - 1 - px; // Zig zag
65
   }
65
   }
66
 
66
 
67
   static void set_zigzag_z(const int8_t index, const_float_t z) {
67
   static void set_zigzag_z(const int8_t index, const_float_t z) {
72
 
72
 
73
   static int8_t cell_index_x(const_float_t x) {
73
   static int8_t cell_index_x(const_float_t x) {
74
     int8_t cx = (x - (MESH_MIN_X)) * RECIPROCAL(MESH_X_DIST);
74
     int8_t cx = (x - (MESH_MIN_X)) * RECIPROCAL(MESH_X_DIST);
75
-    return constrain(cx, 0, (GRID_MAX_POINTS_X) - 2);
75
+    return constrain(cx, 0, GRID_MAX_CELLS_X - 1);
76
   }
76
   }
77
   static int8_t cell_index_y(const_float_t y) {
77
   static int8_t cell_index_y(const_float_t y) {
78
     int8_t cy = (y - (MESH_MIN_Y)) * RECIPROCAL(MESH_Y_DIST);
78
     int8_t cy = (y - (MESH_MIN_Y)) * RECIPROCAL(MESH_Y_DIST);
79
-    return constrain(cy, 0, (GRID_MAX_POINTS_Y) - 2);
79
+    return constrain(cy, 0, GRID_MAX_CELLS_Y - 1);
80
   }
80
   }
81
   static inline xy_int8_t cell_indexes(const_float_t x, const_float_t y) {
81
   static inline xy_int8_t cell_indexes(const_float_t x, const_float_t y) {
82
     return { cell_index_x(x), cell_index_y(y) };
82
     return { cell_index_x(x), cell_index_y(y) };
85
 
85
 
86
   static int8_t probe_index_x(const_float_t x) {
86
   static int8_t probe_index_x(const_float_t x) {
87
     int8_t px = (x - (MESH_MIN_X) + 0.5f * (MESH_X_DIST)) * RECIPROCAL(MESH_X_DIST);
87
     int8_t px = (x - (MESH_MIN_X) + 0.5f * (MESH_X_DIST)) * RECIPROCAL(MESH_X_DIST);
88
-    return WITHIN(px, 0, GRID_MAX_POINTS_X - 1) ? px : -1;
88
+    return WITHIN(px, 0, (GRID_MAX_POINTS_X) - 1) ? px : -1;
89
   }
89
   }
90
   static int8_t probe_index_y(const_float_t y) {
90
   static int8_t probe_index_y(const_float_t y) {
91
     int8_t py = (y - (MESH_MIN_Y) + 0.5f * (MESH_Y_DIST)) * RECIPROCAL(MESH_Y_DIST);
91
     int8_t py = (y - (MESH_MIN_Y) + 0.5f * (MESH_Y_DIST)) * RECIPROCAL(MESH_Y_DIST);
92
-    return WITHIN(py, 0, GRID_MAX_POINTS_Y - 1) ? py : -1;
92
+    return WITHIN(py, 0, (GRID_MAX_POINTS_Y) - 1) ? py : -1;
93
   }
93
   }
94
   static inline xy_int8_t probe_indexes(const_float_t x, const_float_t y) {
94
   static inline xy_int8_t probe_indexes(const_float_t x, const_float_t y) {
95
     return { probe_index_x(x), probe_index_y(y) };
95
     return { probe_index_x(x), probe_index_y(y) };

+ 2
- 2
Marlin/src/feature/bedlevel/ubl/ubl.cpp Ver arquivo

190
   const xy_int8_t curr = closest_indexes(xy_pos_t(current_position) + probe.offset_xy);
190
   const xy_int8_t curr = closest_indexes(xy_pos_t(current_position) + probe.offset_xy);
191
 
191
 
192
   if (!lcd) SERIAL_EOL();
192
   if (!lcd) SERIAL_EOL();
193
-  for (int8_t j = GRID_MAX_POINTS_Y - 1; j >= 0; j--) {
193
+  for (int8_t j = (GRID_MAX_POINTS_Y) - 1; j >= 0; j--) {
194
 
194
 
195
     // Row Label (J index)
195
     // Row Label (J index)
196
     if (human) {
196
     if (human) {
217
         if (human && f >= 0.0) SERIAL_CHAR(f > 0 ? '+' : ' ');  // Display sign also for positive numbers (' ' for 0)
217
         if (human && f >= 0.0) SERIAL_CHAR(f > 0 ? '+' : ' ');  // Display sign also for positive numbers (' ' for 0)
218
         SERIAL_ECHO_F(f, 3);                                    // Positive: 5 digits, Negative: 6 digits
218
         SERIAL_ECHO_F(f, 3);                                    // Positive: 5 digits, Negative: 6 digits
219
       }
219
       }
220
-      if (csv && i < GRID_MAX_POINTS_X - 1) SERIAL_CHAR('\t');
220
+      if (csv && i < (GRID_MAX_POINTS_X) - 1) SERIAL_CHAR('\t');
221
 
221
 
222
       // Closing Brace or Space
222
       // Closing Brace or Space
223
       if (human) SERIAL_CHAR(is_current ? ']' : ' ');
223
       if (human) SERIAL_CHAR(is_current ? ']' : ' ');

+ 23
- 23
Marlin/src/feature/bedlevel/ubl/ubl.h Ver arquivo

38
 
38
 
39
 struct mesh_index_pair;
39
 struct mesh_index_pair;
40
 
40
 
41
-#define MESH_X_DIST (float(MESH_MAX_X - (MESH_MIN_X)) / float(GRID_MAX_POINTS_X - 1))
42
-#define MESH_Y_DIST (float(MESH_MAX_Y - (MESH_MIN_Y)) / float(GRID_MAX_POINTS_Y - 1))
41
+#define MESH_X_DIST (float(MESH_MAX_X - (MESH_MIN_X)) / (GRID_MAX_CELLS_X))
42
+#define MESH_Y_DIST (float(MESH_MAX_Y - (MESH_MIN_Y)) / (GRID_MAX_CELLS_Y))
43
 
43
 
44
 #if ENABLED(OPTIMIZED_MESH_STORAGE)
44
 #if ENABLED(OPTIMIZED_MESH_STORAGE)
45
   typedef int16_t mesh_store_t[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
45
   typedef int16_t mesh_store_t[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
142
   }
142
   }
143
 
143
 
144
   static int8_t cell_index_x_valid(const_float_t x) {
144
   static int8_t cell_index_x_valid(const_float_t x) {
145
-    return WITHIN(cell_index_x_raw(x), 0, (GRID_MAX_POINTS_X - 2));
145
+    return WITHIN(cell_index_x_raw(x), 0, GRID_MAX_CELLS_X - 1);
146
   }
146
   }
147
 
147
 
148
   static int8_t cell_index_y_valid(const_float_t y) {
148
   static int8_t cell_index_y_valid(const_float_t y) {
149
-    return WITHIN(cell_index_y_raw(y), 0, (GRID_MAX_POINTS_Y - 2));
149
+    return WITHIN(cell_index_y_raw(y), 0, GRID_MAX_CELLS_Y - 1);
150
   }
150
   }
151
 
151
 
152
   static int8_t cell_index_x(const_float_t x) {
152
   static int8_t cell_index_x(const_float_t x) {
153
-    return constrain(cell_index_x_raw(x), 0, (GRID_MAX_POINTS_X) - 2);
153
+    return constrain(cell_index_x_raw(x), 0, GRID_MAX_CELLS_X - 1);
154
   }
154
   }
155
 
155
 
156
   static int8_t cell_index_y(const_float_t y) {
156
   static int8_t cell_index_y(const_float_t y) {
157
-    return constrain(cell_index_y_raw(y), 0, (GRID_MAX_POINTS_Y) - 2);
157
+    return constrain(cell_index_y_raw(y), 0, GRID_MAX_CELLS_Y - 1);
158
   }
158
   }
159
 
159
 
160
   static inline xy_int8_t cell_indexes(const_float_t x, const_float_t y) {
160
   static inline xy_int8_t cell_indexes(const_float_t x, const_float_t y) {
164
 
164
 
165
   static int8_t closest_x_index(const_float_t x) {
165
   static int8_t closest_x_index(const_float_t x) {
166
     const int8_t px = (x - (MESH_MIN_X) + (MESH_X_DIST) * 0.5) * RECIPROCAL(MESH_X_DIST);
166
     const int8_t px = (x - (MESH_MIN_X) + (MESH_X_DIST) * 0.5) * RECIPROCAL(MESH_X_DIST);
167
-    return WITHIN(px, 0, GRID_MAX_POINTS_X - 1) ? px : -1;
167
+    return WITHIN(px, 0, (GRID_MAX_POINTS_X) - 1) ? px : -1;
168
   }
168
   }
169
   static int8_t closest_y_index(const_float_t y) {
169
   static int8_t closest_y_index(const_float_t y) {
170
     const int8_t py = (y - (MESH_MIN_Y) + (MESH_Y_DIST) * 0.5) * RECIPROCAL(MESH_Y_DIST);
170
     const int8_t py = (y - (MESH_MIN_Y) + (MESH_Y_DIST) * 0.5) * RECIPROCAL(MESH_Y_DIST);
171
-    return WITHIN(py, 0, GRID_MAX_POINTS_Y - 1) ? py : -1;
171
+    return WITHIN(py, 0, (GRID_MAX_POINTS_Y) - 1) ? py : -1;
172
   }
172
   }
173
   static inline xy_int8_t closest_indexes(const xy_pos_t &xy) {
173
   static inline xy_int8_t closest_indexes(const xy_pos_t &xy) {
174
     return { closest_x_index(xy.x), closest_y_index(xy.y) };
174
     return { closest_x_index(xy.x), closest_y_index(xy.y) };
204
    * the case where the printer is making a vertical line that only crosses horizontal mesh lines.
204
    * the case where the printer is making a vertical line that only crosses horizontal mesh lines.
205
    */
205
    */
206
   static inline float z_correction_for_x_on_horizontal_mesh_line(const_float_t rx0, const int x1_i, const int yi) {
206
   static inline float z_correction_for_x_on_horizontal_mesh_line(const_float_t rx0, const int x1_i, const int yi) {
207
-    if (!WITHIN(x1_i, 0, GRID_MAX_POINTS_X - 1) || !WITHIN(yi, 0, GRID_MAX_POINTS_Y - 1)) {
207
+    if (!WITHIN(x1_i, 0, (GRID_MAX_POINTS_X) - 1) || !WITHIN(yi, 0, (GRID_MAX_POINTS_Y) - 1)) {
208
 
208
 
209
       if (DEBUGGING(LEVELING)) {
209
       if (DEBUGGING(LEVELING)) {
210
-        if (WITHIN(x1_i, 0, GRID_MAX_POINTS_X - 1)) DEBUG_ECHOPGM("yi"); else DEBUG_ECHOPGM("x1_i");
210
+        if (WITHIN(x1_i, 0, (GRID_MAX_POINTS_X) - 1)) DEBUG_ECHOPGM("yi"); else DEBUG_ECHOPGM("x1_i");
211
         DEBUG_ECHOLNPAIR(" out of bounds in z_correction_for_x_on_horizontal_mesh_line(rx0=", rx0, ",x1_i=", x1_i, ",yi=", yi, ")");
211
         DEBUG_ECHOLNPAIR(" out of bounds in z_correction_for_x_on_horizontal_mesh_line(rx0=", rx0, ",x1_i=", x1_i, ",yi=", yi, ")");
212
       }
212
       }
213
 
213
 
218
     const float xratio = (rx0 - mesh_index_to_xpos(x1_i)) * RECIPROCAL(MESH_X_DIST),
218
     const float xratio = (rx0 - mesh_index_to_xpos(x1_i)) * RECIPROCAL(MESH_X_DIST),
219
                 z1 = z_values[x1_i][yi];
219
                 z1 = z_values[x1_i][yi];
220
 
220
 
221
-    return z1 + xratio * (z_values[_MIN(x1_i, GRID_MAX_POINTS_X - 2) + 1][yi] - z1); // Don't allow x1_i+1 to be past the end of the array
222
-                                                                                    // If it is, it is clamped to the last element of the
223
-                                                                                    // z_values[][] array and no correction is applied.
221
+    return z1 + xratio * (z_values[_MIN(x1_i, (GRID_MAX_POINTS_X) - 2) + 1][yi] - z1);  // Don't allow x1_i+1 to be past the end of the array
222
+                                                                                        // If it is, it is clamped to the last element of the
223
+                                                                                        // z_values[][] array and no correction is applied.
224
   }
224
   }
225
 
225
 
226
   //
226
   //
227
   // See comments above for z_correction_for_x_on_horizontal_mesh_line
227
   // See comments above for z_correction_for_x_on_horizontal_mesh_line
228
   //
228
   //
229
   static inline float z_correction_for_y_on_vertical_mesh_line(const_float_t ry0, const int xi, const int y1_i) {
229
   static inline float z_correction_for_y_on_vertical_mesh_line(const_float_t ry0, const int xi, const int y1_i) {
230
-    if (!WITHIN(xi, 0, GRID_MAX_POINTS_X - 1) || !WITHIN(y1_i, 0, GRID_MAX_POINTS_Y - 1)) {
230
+    if (!WITHIN(xi, 0, (GRID_MAX_POINTS_X) - 1) || !WITHIN(y1_i, 0, (GRID_MAX_POINTS_Y) - 1)) {
231
 
231
 
232
       if (DEBUGGING(LEVELING)) {
232
       if (DEBUGGING(LEVELING)) {
233
-        if (WITHIN(xi, 0, GRID_MAX_POINTS_X - 1)) DEBUG_ECHOPGM("y1_i"); else DEBUG_ECHOPGM("xi");
233
+        if (WITHIN(xi, 0, (GRID_MAX_POINTS_X) - 1)) DEBUG_ECHOPGM("y1_i"); else DEBUG_ECHOPGM("xi");
234
         DEBUG_ECHOLNPAIR(" out of bounds in z_correction_for_y_on_vertical_mesh_line(ry0=", ry0, ", xi=", xi, ", y1_i=", y1_i, ")");
234
         DEBUG_ECHOLNPAIR(" out of bounds in z_correction_for_y_on_vertical_mesh_line(ry0=", ry0, ", xi=", xi, ", y1_i=", y1_i, ")");
235
       }
235
       }
236
 
236
 
241
     const float yratio = (ry0 - mesh_index_to_ypos(y1_i)) * RECIPROCAL(MESH_Y_DIST),
241
     const float yratio = (ry0 - mesh_index_to_ypos(y1_i)) * RECIPROCAL(MESH_Y_DIST),
242
                 z1 = z_values[xi][y1_i];
242
                 z1 = z_values[xi][y1_i];
243
 
243
 
244
-    return z1 + yratio * (z_values[xi][_MIN(y1_i, GRID_MAX_POINTS_Y - 2) + 1] - z1); // Don't allow y1_i+1 to be past the end of the array
245
-                                                                                    // If it is, it is clamped to the last element of the
246
-                                                                                    // z_values[][] array and no correction is applied.
244
+    return z1 + yratio * (z_values[xi][_MIN(y1_i, (GRID_MAX_POINTS_Y) - 2) + 1] - z1);  // Don't allow y1_i+1 to be past the end of the array
245
+                                                                                        // If it is, it is clamped to the last element of the
246
+                                                                                        // z_values[][] array and no correction is applied.
247
   }
247
   }
248
 
248
 
249
   /**
249
   /**
266
 
266
 
267
     const float z1 = calc_z0(rx0,
267
     const float z1 = calc_z0(rx0,
268
                              mesh_index_to_xpos(cx), z_values[cx][cy],
268
                              mesh_index_to_xpos(cx), z_values[cx][cy],
269
-                             mesh_index_to_xpos(cx + 1), z_values[_MIN(cx, GRID_MAX_POINTS_X - 2) + 1][cy]);
269
+                             mesh_index_to_xpos(cx + 1), z_values[_MIN(cx, (GRID_MAX_POINTS_X) - 2) + 1][cy]);
270
 
270
 
271
     const float z2 = calc_z0(rx0,
271
     const float z2 = calc_z0(rx0,
272
-                             mesh_index_to_xpos(cx), z_values[cx][_MIN(cy, GRID_MAX_POINTS_Y - 2) + 1],
273
-                             mesh_index_to_xpos(cx + 1), z_values[_MIN(cx, GRID_MAX_POINTS_X - 2) + 1][_MIN(cy, GRID_MAX_POINTS_Y - 2) + 1]);
272
+                             mesh_index_to_xpos(cx), z_values[cx][_MIN(cy, (GRID_MAX_POINTS_Y) - 2) + 1],
273
+                             mesh_index_to_xpos(cx + 1), z_values[_MIN(cx, (GRID_MAX_POINTS_X) - 2) + 1][_MIN(cy, (GRID_MAX_POINTS_Y) - 2) + 1]);
274
 
274
 
275
     float z0 = calc_z0(ry0,
275
     float z0 = calc_z0(ry0,
276
                        mesh_index_to_ypos(cy), z1,
276
                        mesh_index_to_ypos(cy), z1,
302
   static inline float get_z_correction(const xy_pos_t &pos) { return get_z_correction(pos.x, pos.y); }
302
   static inline float get_z_correction(const xy_pos_t &pos) { return get_z_correction(pos.x, pos.y); }
303
 
303
 
304
   static inline float mesh_index_to_xpos(const uint8_t i) {
304
   static inline float mesh_index_to_xpos(const uint8_t i) {
305
-    return i < GRID_MAX_POINTS_X ? pgm_read_float(&_mesh_index_to_xpos[i]) : MESH_MIN_X + i * (MESH_X_DIST);
305
+    return i < (GRID_MAX_POINTS_X) ? pgm_read_float(&_mesh_index_to_xpos[i]) : MESH_MIN_X + i * (MESH_X_DIST);
306
   }
306
   }
307
   static inline float mesh_index_to_ypos(const uint8_t i) {
307
   static inline float mesh_index_to_ypos(const uint8_t i) {
308
-    return i < GRID_MAX_POINTS_Y ? pgm_read_float(&_mesh_index_to_ypos[i]) : MESH_MIN_Y + i * (MESH_Y_DIST);
308
+    return i < (GRID_MAX_POINTS_Y) ? pgm_read_float(&_mesh_index_to_ypos[i]) : MESH_MIN_Y + i * (MESH_Y_DIST);
309
   }
309
   }
310
 
310
 
311
   #if UBL_SEGMENTED
311
   #if UBL_SEGMENTED

+ 4
- 4
Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp Ver arquivo

433
             SERIAL_DECIMAL(param.XY_pos.y);
433
             SERIAL_DECIMAL(param.XY_pos.y);
434
             SERIAL_ECHOLNPGM(").\n");
434
             SERIAL_ECHOLNPGM(").\n");
435
           }
435
           }
436
-          const xy_pos_t near_probe_xy = param.XY_pos + probe.offset_xy;
437
-          probe_entire_mesh(near_probe_xy, parser.seen('T'), parser.seen('E'), parser.seen('U'));
436
+          probe_entire_mesh(param.XY_pos, parser.seen('T'), parser.seen('E'), parser.seen('U'));
438
 
437
 
439
           report_current_position();
438
           report_current_position();
440
           probe_deployed = true;
439
           probe_deployed = true;
1140
   }
1139
   }
1141
 
1140
 
1142
   // If X or Y are not valid, use center of the bed values
1141
   // If X or Y are not valid, use center of the bed values
1143
-  if (!COORDINATE_OKAY(sx, X_MIN_BED, X_MAX_BED)) sx = X_CENTER;
1144
-  if (!COORDINATE_OKAY(sy, Y_MIN_BED, Y_MAX_BED)) sy = Y_CENTER;
1142
+  // (for UBL_HILBERT_CURVE default to lower-left corner instead)
1143
+  if (!COORDINATE_OKAY(sx, X_MIN_BED, X_MAX_BED)) sx = TERN(UBL_HILBERT_CURVE, 0, X_CENTER);
1144
+  if (!COORDINATE_OKAY(sy, Y_MIN_BED, Y_MAX_BED)) sy = TERN(UBL_HILBERT_CURVE, 0, Y_CENTER);
1145
 
1145
 
1146
   if (err_flag) return UBL_ERR;
1146
   if (err_flag) return UBL_ERR;
1147
 
1147
 

+ 2
- 2
Marlin/src/feature/bedlevel/ubl/ubl_motion.cpp Ver arquivo

397
         int8_t((raw.x - (MESH_MIN_X)) * RECIPROCAL(MESH_X_DIST)),
397
         int8_t((raw.x - (MESH_MIN_X)) * RECIPROCAL(MESH_X_DIST)),
398
         int8_t((raw.y - (MESH_MIN_Y)) * RECIPROCAL(MESH_Y_DIST))
398
         int8_t((raw.y - (MESH_MIN_Y)) * RECIPROCAL(MESH_Y_DIST))
399
       };
399
       };
400
-      LIMIT(icell.x, 0, (GRID_MAX_POINTS_X) - 1);
401
-      LIMIT(icell.y, 0, (GRID_MAX_POINTS_Y) - 1);
400
+      LIMIT(icell.x, 0, GRID_MAX_CELLS_X);
401
+      LIMIT(icell.y, 0, GRID_MAX_CELLS_Y);
402
 
402
 
403
       float z_x0y0 = z_values[icell.x  ][icell.y  ],  // z at lower left corner
403
       float z_x0y0 = z_values[icell.x  ][icell.y  ],  // z at lower left corner
404
             z_x1y0 = z_values[icell.x+1][icell.y  ],  // z at upper left corner
404
             z_x1y0 = z_values[icell.x+1][icell.y  ],  // z at upper left corner

+ 295
- 300
Marlin/src/gcode/bedlevel/G26.cpp Ver arquivo

113
 #include "../../module/temperature.h"
113
 #include "../../module/temperature.h"
114
 #include "../../lcd/marlinui.h"
114
 #include "../../lcd/marlinui.h"
115
 
115
 
116
+#if ENABLED(UBL_HILBERT_CURVE)
117
+  #include "../../feature/bedlevel/hilbert_curve.h"
118
+#endif
119
+
116
 #define EXTRUSION_MULTIPLIER 1.0
120
 #define EXTRUSION_MULTIPLIER 1.0
117
 #define PRIME_LENGTH 10.0
121
 #define PRIME_LENGTH 10.0
118
 #define OOZE_AMOUNT 0.3
122
 #define OOZE_AMOUNT 0.3
145
 
149
 
146
 constexpr float g26_e_axis_feedrate = 0.025;
150
 constexpr float g26_e_axis_feedrate = 0.025;
147
 
151
 
148
-static MeshFlags circle_flags, horizontal_mesh_line_flags, vertical_mesh_line_flags;
152
+static MeshFlags circle_flags;
149
 float g26_random_deviation = 0.0;
153
 float g26_random_deviation = 0.0;
150
 
154
 
151
-static bool g26_retracted = false; // Track the retracted state of the nozzle so mismatched
152
-                                   // retracts/recovers won't result in a bad state.
153
-
154
-float g26_extrusion_multiplier,
155
-      g26_retraction_multiplier,
156
-      g26_layer_height,
157
-      g26_prime_length;
158
-
159
-xy_pos_t g26_xy_pos; // = { 0, 0 }
160
-
161
-int16_t g26_bed_temp,
162
-        g26_hotend_temp;
163
-
164
-int8_t g26_prime_flag;
165
-
166
 #if HAS_LCD_MENU
155
 #if HAS_LCD_MENU
167
 
156
 
168
   /**
157
   /**
178
 
167
 
179
 #endif
168
 #endif
180
 
169
 
181
-mesh_index_pair find_closest_circle_to_print(const xy_pos_t &pos) {
182
-  float closest = 99999.99;
183
-  mesh_index_pair out_point;
184
-
185
-  out_point.pos = -1;
186
-
187
-  GRID_LOOP(i, j) {
188
-    if (!circle_flags.marked(i, j)) {
189
-      // We found a circle that needs to be printed
190
-      const xy_pos_t m = { _GET_MESH_X(i), _GET_MESH_Y(j) };
191
-
192
-      // Get the distance to this intersection
193
-      float f = (pos - m).magnitude();
194
-
195
-      // It is possible that we are being called with the values
196
-      // to let us find the closest circle to the start position.
197
-      // But if this is not the case, add a small weighting to the
198
-      // distance calculation to help it choose a better place to continue.
199
-      f += (g26_xy_pos - m).magnitude() / 15.0f;
200
-
201
-      // Add the specified amount of Random Noise to our search
202
-      if (g26_random_deviation > 1.0) f += random(0.0, g26_random_deviation);
203
-
204
-      if (f < closest) {
205
-        closest = f;          // Found a closer un-printed location
206
-        out_point.pos.set(i, j);  // Save its data
207
-        out_point.distance = closest;
208
-      }
209
-    }
210
-  }
211
-  circle_flags.mark(out_point); // Mark this location as done.
212
-  return out_point;
213
-}
214
-
215
 void move_to(const_float_t rx, const_float_t ry, const_float_t z, const_float_t e_delta) {
170
 void move_to(const_float_t rx, const_float_t ry, const_float_t z, const_float_t e_delta) {
216
   static float last_z = -999.99;
171
   static float last_z = -999.99;
217
 
172
 
218
   const xy_pos_t dest = { rx, ry };
173
   const xy_pos_t dest = { rx, ry };
219
 
174
 
220
-  const bool has_xy_component = dest != current_position; // Check if X or Y is involved in the movement.
221
-  const bool has_e_component = e_delta != 0.0;
222
-
223
-  destination = current_position;
175
+  const bool has_xy_component = dest != current_position, // Check if X or Y is involved in the movement.
176
+             has_e_component = e_delta != 0.0;
224
 
177
 
225
   if (z != last_z) {
178
   if (z != last_z) {
226
-    last_z = destination.z = z;
179
+    last_z = z;
180
+    destination.set(current_position.x, current_position.y, z, current_position.e);
227
     const feedRate_t fr_mm_s = planner.settings.max_feedrate_mm_s[Z_AXIS] * 0.5f; // Use half of the Z_AXIS max feed rate
181
     const feedRate_t fr_mm_s = planner.settings.max_feedrate_mm_s[Z_AXIS] * 0.5f; // Use half of the Z_AXIS max feed rate
228
     prepare_internal_move_to_destination(fr_mm_s);
182
     prepare_internal_move_to_destination(fr_mm_s);
229
   }
183
   }
239
   prepare_internal_move_to_destination(fr_mm_s);
193
   prepare_internal_move_to_destination(fr_mm_s);
240
 }
194
 }
241
 
195
 
242
-FORCE_INLINE void move_to(const xyz_pos_t &where, const_float_t de) { move_to(where.x, where.y, where.z, de); }
196
+void move_to(const xyz_pos_t &where, const_float_t de) { move_to(where.x, where.y, where.z, de); }
243
 
197
 
244
-void retract_filament(const xyz_pos_t &where) {
245
-  if (!g26_retracted) { // Only retract if we are not already retracted!
246
-    g26_retracted = true;
247
-    move_to(where, -1.0f * g26_retraction_multiplier);
248
-  }
249
-}
198
+typedef struct {
199
+  float extrusion_multiplier  = EXTRUSION_MULTIPLIER,
200
+        retraction_multiplier = G26_RETRACT_MULTIPLIER,
201
+        layer_height          = MESH_TEST_LAYER_HEIGHT,
202
+        prime_length          = PRIME_LENGTH;
250
 
203
 
251
-// TODO: Parameterize the Z lift with a define
252
-void retract_lift_move(const xyz_pos_t &s) {
253
-  retract_filament(destination);
254
-  move_to(current_position.x, current_position.y, current_position.z + 0.5f, 0.0);  // Z lift to minimize scraping
255
-  move_to(s.x, s.y, s.z + 0.5f, 0.0);  // Get to the starting point with no extrusion while lifted
256
-}
204
+  int16_t bed_temp            = MESH_TEST_BED_TEMP,
205
+          hotend_temp         = MESH_TEST_HOTEND_TEMP;
206
+
207
+  float nozzle                = MESH_TEST_NOZZLE_SIZE,
208
+        filament_diameter     = DEFAULT_NOMINAL_FILAMENT_DIA,
209
+        ooze_amount;            // 'O' ... OOZE_AMOUNT
257
 
210
 
258
-void recover_filament(const xyz_pos_t &where) {
259
-  if (g26_retracted) { // Only un-retract if we are retracted.
260
-    move_to(where, 1.2f * g26_retraction_multiplier);
261
-    g26_retracted = false;
211
+  bool continue_with_closest,   // 'C'
212
+       keep_heaters_on;         // 'K'
213
+
214
+  xy_pos_t xy_pos; // = { 0, 0 }
215
+
216
+  int8_t prime_flag = 0;
217
+
218
+  bool g26_retracted = false;  // Track the retracted state during G26 so mismatched
219
+                               // retracts/recovers don't result in a bad state.
220
+
221
+  void retract_filament(const xyz_pos_t &where) {
222
+    if (!g26_retracted) { // Only retract if we are not already retracted!
223
+      g26_retracted = true;
224
+      move_to(where, -1.0f * retraction_multiplier);
225
+    }
262
   }
226
   }
263
-}
264
 
227
 
265
-/**
266
- * print_line_from_here_to_there() takes two cartesian coordinates and draws a line from one
267
- * to the other. But there are really three sets of coordinates involved. The first coordinate
268
- * is the present location of the nozzle. We don't necessarily want to print from this location.
269
- * We first need to move the nozzle to the start of line segment where we want to print. Once
270
- * there, we can use the two coordinates supplied to draw the line.
271
- *
272
- * Note:  Although we assume the first set of coordinates is the start of the line and the second
273
- * set of coordinates is the end of the line, it does not always work out that way. This function
274
- * optimizes the movement to minimize the travel distance before it can start printing. This saves
275
- * a lot of time and eliminates a lot of nonsensical movement of the nozzle. However, it does
276
- * cause a lot of very little short retracement of th nozzle when it draws the very first line
277
- * segment of a 'circle'. The time this requires is very short and is easily saved by the other
278
- * cases where the optimization comes into play.
279
- */
280
-void print_line_from_here_to_there(const xyz_pos_t &s, const xyz_pos_t &e) {
228
+  // TODO: Parameterize the Z lift with a define
229
+  void retract_lift_move(const xyz_pos_t &s) {
230
+    retract_filament(destination);
231
+    move_to(current_position.x, current_position.y, current_position.z + 0.5f, 0.0f);  // Z lift to minimize scraping
232
+    move_to(s.x, s.y, s.z + 0.5f, 0.0f);  // Get to the starting point with no extrusion while lifted
233
+  }
281
 
234
 
282
-  // Distances to the start / end of the line
283
-  xy_float_t svec = current_position - s, evec = current_position - e;
235
+  void recover_filament(const xyz_pos_t &where) {
236
+    if (g26_retracted) { // Only un-retract if we are retracted.
237
+      move_to(where, 1.2f * retraction_multiplier);
238
+      g26_retracted = false;
239
+    }
240
+  }
284
 
241
 
285
-  const float dist_start = HYPOT2(svec.x, svec.y),
286
-              dist_end = HYPOT2(evec.x, evec.y),
287
-              line_length = HYPOT(e.x - s.x, e.y - s.y);
242
+  /**
243
+   * print_line_from_here_to_there() takes two cartesian coordinates and draws a line from one
244
+   * to the other. But there are really three sets of coordinates involved. The first coordinate
245
+   * is the present location of the nozzle. We don't necessarily want to print from this location.
246
+   * We first need to move the nozzle to the start of line segment where we want to print. Once
247
+   * there, we can use the two coordinates supplied to draw the line.
248
+   *
249
+   * Note:  Although we assume the first set of coordinates is the start of the line and the second
250
+   * set of coordinates is the end of the line, it does not always work out that way. This function
251
+   * optimizes the movement to minimize the travel distance before it can start printing. This saves
252
+   * a lot of time and eliminates a lot of nonsensical movement of the nozzle. However, it does
253
+   * cause a lot of very little short retracement of th nozzle when it draws the very first line
254
+   * segment of a 'circle'. The time this requires is very short and is easily saved by the other
255
+   * cases where the optimization comes into play.
256
+   */
257
+  void print_line_from_here_to_there(const xyz_pos_t &s, const xyz_pos_t &e) {
288
 
258
 
289
-  // If the end point of the line is closer to the nozzle, flip the direction,
290
-  // moving from the end to the start. On very small lines the optimization isn't worth it.
291
-  if (dist_end < dist_start && (INTERSECTION_CIRCLE_RADIUS) < ABS(line_length))
292
-    return print_line_from_here_to_there(e, s);
259
+    // Distances to the start / end of the line
260
+    xy_float_t svec = current_position - s, evec = current_position - e;
293
 
261
 
294
-  // Decide whether to retract & lift
295
-  if (dist_start > 2.0) retract_lift_move(s);
262
+    const float dist_start = HYPOT2(svec.x, svec.y),
263
+                dist_end = HYPOT2(evec.x, evec.y),
264
+                line_length = HYPOT(e.x - s.x, e.y - s.y);
296
 
265
 
297
-  move_to(s, 0.0); // Get to the starting point with no extrusion / un-Z lift
266
+    // If the end point of the line is closer to the nozzle, flip the direction,
267
+    // moving from the end to the start. On very small lines the optimization isn't worth it.
268
+    if (dist_end < dist_start && (INTERSECTION_CIRCLE_RADIUS) < ABS(line_length))
269
+      return print_line_from_here_to_there(e, s);
298
 
270
 
299
-  const float e_pos_delta = line_length * g26_e_axis_feedrate * g26_extrusion_multiplier;
271
+    // Decide whether to retract & lift
272
+    if (dist_start > 2.0) retract_lift_move(s);
300
 
273
 
301
-  recover_filament(destination);
302
-  move_to(e, e_pos_delta);  // Get to the ending point with an appropriate amount of extrusion
303
-}
274
+    move_to(s, 0.0); // Get to the starting point with no extrusion / un-Z lift
304
 
275
 
305
-inline bool look_for_lines_to_connect() {
306
-  xyz_pos_t s, e;
307
-  s.z = e.z = g26_layer_height;
276
+    const float e_pos_delta = line_length * g26_e_axis_feedrate * extrusion_multiplier;
308
 
277
 
309
-  GRID_LOOP(i, j) {
278
+    recover_filament(destination);
279
+    move_to(e, e_pos_delta);  // Get to the ending point with an appropriate amount of extrusion
280
+  }
310
 
281
 
311
-    if (TERN0(HAS_LCD_MENU, user_canceled())) return true;
282
+  void connect_neighbor_with_line(const xy_int8_t &p1, int8_t dx, int8_t dy) {
283
+    xy_int8_t p2;
284
+    p2.x = p1.x + dx;
285
+    p2.y = p1.y + dy;
286
+
287
+    if (p2.x < 0 || p2.x >= (GRID_MAX_POINTS_X)) return;
288
+    if (p2.y < 0 || p2.y >= (GRID_MAX_POINTS_Y)) return;
289
+
290
+    if(circle_flags.marked(p1.x, p1.y) && circle_flags.marked(p2.x, p2.y)) {
291
+      xyz_pos_t s, e;
292
+      s.x = _GET_MESH_X(p1.x) + (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)) * dx;
293
+      e.x = _GET_MESH_X(p2.x) - (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)) * dx;
294
+      s.y = _GET_MESH_Y(p1.y) + (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)) * dy;
295
+      e.y = _GET_MESH_Y(p2.y) - (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)) * dy;
296
+      s.z = e.z = layer_height;
297
+
298
+      #if HAS_ENDSTOPS
299
+        LIMIT(s.y, Y_MIN_POS + 1, Y_MAX_POS - 1);
300
+        LIMIT(e.y, Y_MIN_POS + 1, Y_MAX_POS - 1);
301
+        LIMIT(s.x, X_MIN_POS + 1, X_MAX_POS - 1);
302
+        LIMIT(e.x, X_MIN_POS + 1, X_MAX_POS - 1);
303
+      #endif
304
+
305
+      if (position_is_reachable(s.x, s.y) && position_is_reachable(e.x, e.y))
306
+        print_line_from_here_to_there(s, e);
307
+    }
308
+  }
312
 
309
 
313
-    if (i < (GRID_MAX_POINTS_X)) {  // Can't connect to anything farther to the right than GRID_MAX_POINTS_X.
314
-                                    // Already a half circle at the edge of the bed.
310
+  /**
311
+   * Turn on the bed and nozzle heat and
312
+   * wait for them to get up to temperature.
313
+   */
314
+  bool turn_on_heaters() {
315
 
315
 
316
-      if (circle_flags.marked(i, j) && circle_flags.marked(i + 1, j)) {   // Test whether a leftward line can be done
317
-        if (!horizontal_mesh_line_flags.marked(i, j)) {
318
-          // Two circles need a horizontal line to connect them
319
-          s.x = _GET_MESH_X(  i  ) + (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // right edge
320
-          e.x = _GET_MESH_X(i + 1) - (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // left edge
316
+    SERIAL_ECHOLNPGM("Waiting for heatup.");
321
 
317
 
322
-          #if HAS_ENDSTOPS
323
-            LIMIT(s.x, X_MIN_POS + 1, X_MAX_POS - 1);
324
-            s.y = e.y = constrain(_GET_MESH_Y(j), Y_MIN_POS + 1, Y_MAX_POS - 1);
325
-            LIMIT(e.x, X_MIN_POS + 1, X_MAX_POS - 1);
326
-          #else
327
-            s.y = e.y = _GET_MESH_Y(j);
328
-          #endif
318
+    #if HAS_HEATED_BED
329
 
319
 
330
-          if (position_is_reachable(s.x, s.y) && position_is_reachable(e.x, e.y))
331
-            print_line_from_here_to_there(s, e);
320
+      if (bed_temp > 25) {
321
+        #if HAS_WIRED_LCD
322
+          ui.set_status_P(GET_TEXT(MSG_G26_HEATING_BED), 99);
323
+          ui.quick_feedback();
324
+          TERN_(HAS_LCD_MENU, ui.capture());
325
+        #endif
326
+        thermalManager.setTargetBed(bed_temp);
332
 
327
 
333
-          horizontal_mesh_line_flags.mark(i, j); // Mark done, even if skipped
334
-        }
328
+        // Wait for the temperature to stabilize
329
+        if (!thermalManager.wait_for_bed(true
330
+            #if G26_CLICK_CAN_CANCEL
331
+              , true
332
+            #endif
333
+          )
334
+        ) return G26_ERR;
335
       }
335
       }
336
 
336
 
337
-      if (j < (GRID_MAX_POINTS_Y)) {  // Can't connect to anything further back than GRID_MAX_POINTS_Y.
338
-                                      // Already a half circle at the edge of the bed.
339
-
340
-        if (circle_flags.marked(i, j) && circle_flags.marked(i, j + 1)) {   // Test whether a downward line can be done
341
-          if (!vertical_mesh_line_flags.marked(i, j)) {
342
-            // Two circles that need a vertical line to connect them
343
-            s.y = _GET_MESH_Y(  j  ) + (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // top edge
344
-            e.y = _GET_MESH_Y(j + 1) - (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // bottom edge
345
-
346
-            #if HAS_ENDSTOPS
347
-              s.x = e.x = constrain(_GET_MESH_X(i), X_MIN_POS + 1, X_MAX_POS - 1);
348
-              LIMIT(s.y, Y_MIN_POS + 1, Y_MAX_POS - 1);
349
-              LIMIT(e.y, Y_MIN_POS + 1, Y_MAX_POS - 1);
350
-            #else
351
-              s.x = e.x = _GET_MESH_X(i);
352
-            #endif
337
+    #else
353
 
338
 
354
-            if (position_is_reachable(s.x, s.y) && position_is_reachable(e.x, e.y))
355
-              print_line_from_here_to_there(s, e);
339
+      UNUSED(bed_temp);
356
 
340
 
357
-            vertical_mesh_line_flags.mark(i, j); // Mark done, even if skipped
358
-          }
359
-        }
360
-      }
361
-    }
341
+    #endif // HAS_HEATED_BED
342
+
343
+    // Start heating the active nozzle
344
+    #if HAS_WIRED_LCD
345
+      ui.set_status_P(GET_TEXT(MSG_G26_HEATING_NOZZLE), 99);
346
+      ui.quick_feedback();
347
+    #endif
348
+    thermalManager.setTargetHotend(hotend_temp, active_extruder);
349
+
350
+    // Wait for the temperature to stabilize
351
+    if (!thermalManager.wait_for_hotend(active_extruder, true
352
+      #if G26_CLICK_CAN_CANCEL
353
+        , true
354
+      #endif
355
+    )) return G26_ERR;
356
+
357
+    #if HAS_WIRED_LCD
358
+      ui.reset_status();
359
+      ui.quick_feedback();
360
+    #endif
361
+
362
+    return G26_OK;
362
   }
363
   }
363
-  return false;
364
-}
365
 
364
 
366
-/**
367
- * Turn on the bed and nozzle heat and
368
- * wait for them to get up to temperature.
369
- */
370
-inline bool turn_on_heaters() {
365
+  /**
366
+   * Prime the nozzle if needed. Return true on error.
367
+   */
368
+  bool prime_nozzle() {
371
 
369
 
372
-  SERIAL_ECHOLNPGM("Waiting for heatup.");
370
+    const feedRate_t fr_slow_e = planner.settings.max_feedrate_mm_s[E_AXIS] / 15.0f;
371
+    #if HAS_LCD_MENU && !HAS_TOUCH_BUTTONS // ui.button_pressed issue with touchscreen
372
+      #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
373
+        float Total_Prime = 0.0;
374
+      #endif
373
 
375
 
374
-  #if HAS_HEATED_BED
376
+      if (prime_flag == -1) {  // The user wants to control how much filament gets purged
377
+        ui.capture();
378
+        ui.set_status_P(GET_TEXT(MSG_G26_MANUAL_PRIME), 99);
379
+        ui.chirp();
375
 
380
 
376
-    if (g26_bed_temp > 25) {
381
+        destination = current_position;
382
+
383
+        recover_filament(destination); // Make sure G26 doesn't think the filament is retracted().
384
+
385
+        while (!ui.button_pressed()) {
386
+          ui.chirp();
387
+          destination.e += 0.25;
388
+          #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
389
+            Total_Prime += 0.25;
390
+            if (Total_Prime >= EXTRUDE_MAXLENGTH) {
391
+              ui.release();
392
+              return G26_ERR;
393
+            }
394
+          #endif
395
+          prepare_internal_move_to_destination(fr_slow_e);
396
+          destination = current_position;
397
+          planner.synchronize();    // Without this synchronize, the purge is more consistent,
398
+                                    // but because the planner has a buffer, we won't be able
399
+                                    // to stop as quickly. So we put up with the less smooth
400
+                                    // action to give the user a more responsive 'Stop'.
401
+        }
402
+
403
+        ui.wait_for_release();
404
+
405
+        ui.set_status_P(GET_TEXT(MSG_G26_PRIME_DONE), 99);
406
+        ui.quick_feedback();
407
+        ui.release();
408
+      }
409
+      else
410
+    #endif
411
+    {
377
       #if HAS_WIRED_LCD
412
       #if HAS_WIRED_LCD
378
-        ui.set_status_P(GET_TEXT(MSG_G26_HEATING_BED), 99);
413
+        ui.set_status_P(GET_TEXT(MSG_G26_FIXED_LENGTH), 99);
379
         ui.quick_feedback();
414
         ui.quick_feedback();
380
-        TERN_(HAS_LCD_MENU, ui.capture());
381
       #endif
415
       #endif
382
-      thermalManager.setTargetBed(g26_bed_temp);
383
-
384
-      // Wait for the temperature to stabilize
385
-      if (!thermalManager.wait_for_bed(true
386
-          #if G26_CLICK_CAN_CANCEL
387
-            , true
388
-          #endif
389
-        )
390
-      ) return G26_ERR;
416
+      destination = current_position;
417
+      destination.e += prime_length;
418
+      prepare_internal_move_to_destination(fr_slow_e);
419
+      destination.e -= prime_length;
420
+      retract_filament(destination);
391
     }
421
     }
392
 
422
 
393
-  #endif // HAS_HEATED_BED
423
+    return G26_OK;
424
+  }
394
 
425
 
395
-  // Start heating the active nozzle
396
-  #if HAS_WIRED_LCD
397
-    ui.set_status_P(GET_TEXT(MSG_G26_HEATING_NOZZLE), 99);
398
-    ui.quick_feedback();
399
-  #endif
400
-  thermalManager.setTargetHotend(g26_hotend_temp, active_extruder);
426
+  /**
427
+   * Find the nearest point at which to print a circle
428
+   */
429
+  mesh_index_pair find_closest_circle_to_print(const xy_pos_t &pos) {
401
 
430
 
402
-  // Wait for the temperature to stabilize
403
-  if (!thermalManager.wait_for_hotend(active_extruder, true
404
-    #if G26_CLICK_CAN_CANCEL
405
-      , true
406
-    #endif
407
-  )) return G26_ERR;
431
+    mesh_index_pair out_point;
432
+    out_point.pos = -1;
408
 
433
 
409
-  #if HAS_WIRED_LCD
410
-    ui.reset_status();
411
-    ui.quick_feedback();
412
-  #endif
434
+    #if ENABLED(UBL_HILBERT_CURVE)
413
 
435
 
414
-  return G26_OK;
415
-}
436
+      auto test_func = [](uint8_t i, uint8_t j, void *data) -> bool {
437
+        if (!circle_flags.marked(i, j)) {
438
+          mesh_index_pair *out_point = (mesh_index_pair*)data;
439
+          out_point->pos.set(i, j);  // Save its data
440
+          return true;
441
+        }
442
+        return false;
443
+      };
416
 
444
 
417
-/**
418
- * Prime the nozzle if needed. Return true on error.
419
- */
420
-inline bool prime_nozzle() {
445
+      hilbert_curve::search_from_closest(pos, test_func, &out_point);
421
 
446
 
422
-  const feedRate_t fr_slow_e = planner.settings.max_feedrate_mm_s[E_AXIS] / 15.0f;
423
-  #if HAS_LCD_MENU && !HAS_TOUCH_BUTTONS // ui.button_pressed issue with touchscreen
424
-    #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
425
-      float Total_Prime = 0.0;
426
-    #endif
447
+    #else
427
 
448
 
428
-    if (g26_prime_flag == -1) {  // The user wants to control how much filament gets purged
429
-      ui.capture();
430
-      ui.set_status_P(GET_TEXT(MSG_G26_MANUAL_PRIME), 99);
431
-      ui.chirp();
449
+      float closest = 99999.99;
432
 
450
 
433
-      destination = current_position;
451
+      GRID_LOOP(i, j) {
452
+        if (!circle_flags.marked(i, j)) {
453
+          // We found a circle that needs to be printed
454
+          const xy_pos_t m = { _GET_MESH_X(i), _GET_MESH_Y(j) };
434
 
455
 
435
-      recover_filament(destination); // Make sure G26 doesn't think the filament is retracted().
456
+          // Get the distance to this intersection
457
+          float f = (pos - m).magnitude();
436
 
458
 
437
-      while (!ui.button_pressed()) {
438
-        ui.chirp();
439
-        destination.e += 0.25;
440
-        #if ENABLED(PREVENT_LENGTHY_EXTRUDE)
441
-          Total_Prime += 0.25;
442
-          if (Total_Prime >= EXTRUDE_MAXLENGTH) {
443
-            ui.release();
444
-            return G26_ERR;
459
+          // It is possible that we are being called with the values
460
+          // to let us find the closest circle to the start position.
461
+          // But if this is not the case, add a small weighting to the
462
+          // distance calculation to help it choose a better place to continue.
463
+          f += (xy_pos - m).magnitude() / 15.0f;
464
+
465
+          // Add the specified amount of Random Noise to our search
466
+          if (g26_random_deviation > 1.0) f += random(0.0, g26_random_deviation);
467
+
468
+          if (f < closest) {
469
+            closest = f;          // Found a closer un-printed location
470
+            out_point.pos.set(i, j);  // Save its data
471
+            out_point.distance = closest;
445
           }
472
           }
446
-        #endif
447
-        prepare_internal_move_to_destination(fr_slow_e);
448
-        destination = current_position;
449
-        planner.synchronize();    // Without this synchronize, the purge is more consistent,
450
-                                  // but because the planner has a buffer, we won't be able
451
-                                  // to stop as quickly. So we put up with the less smooth
452
-                                  // action to give the user a more responsive 'Stop'.
473
+        }
453
       }
474
       }
454
 
475
 
455
-      ui.wait_for_release();
456
-
457
-      ui.set_status_P(GET_TEXT(MSG_G26_PRIME_DONE), 99);
458
-      ui.quick_feedback();
459
-      ui.release();
460
-    }
461
-    else
462
-  #endif
463
-  {
464
-    #if HAS_WIRED_LCD
465
-      ui.set_status_P(GET_TEXT(MSG_G26_FIXED_LENGTH), 99);
466
-      ui.quick_feedback();
467
     #endif
476
     #endif
468
-    destination = current_position;
469
-    destination.e += g26_prime_length;
470
-    prepare_internal_move_to_destination(fr_slow_e);
471
-    destination.e -= g26_prime_length;
472
-    retract_filament(destination);
477
+
478
+    circle_flags.mark(out_point); // Mark this location as done.
479
+    return out_point;
473
   }
480
   }
474
 
481
 
475
-  return G26_OK;
476
-}
482
+} g26_helper_t;
477
 
483
 
478
 /**
484
 /**
479
  * G26: Mesh Validation Pattern generation.
485
  * G26: Mesh Validation Pattern generation.
510
   // Change the tool first, if specified
516
   // Change the tool first, if specified
511
   if (parser.seenval('T')) tool_change(parser.value_int());
517
   if (parser.seenval('T')) tool_change(parser.value_int());
512
 
518
 
513
-  g26_extrusion_multiplier    = EXTRUSION_MULTIPLIER;
514
-  g26_retraction_multiplier   = G26_RETRACT_MULTIPLIER;
515
-  g26_layer_height            = MESH_TEST_LAYER_HEIGHT;
516
-  g26_prime_length            = PRIME_LENGTH;
517
-  g26_bed_temp                = MESH_TEST_BED_TEMP;
518
-  g26_hotend_temp             = MESH_TEST_HOTEND_TEMP;
519
-  g26_prime_flag              = 0;
520
-
521
-  float g26_nozzle            = MESH_TEST_NOZZLE_SIZE,
522
-        g26_filament_diameter = DEFAULT_NOMINAL_FILAMENT_DIA,
523
-        g26_ooze_amount       = parser.linearval('O', OOZE_AMOUNT);
519
+  g26_helper_t g26;
524
 
520
 
525
-  bool g26_continue_with_closest = parser.boolval('C'),
526
-       g26_keep_heaters_on       = parser.boolval('K');
521
+  g26.ooze_amount           = parser.linearval('O', OOZE_AMOUNT);
522
+  g26.continue_with_closest = parser.boolval('C');
523
+  g26.keep_heaters_on       = parser.boolval('K');
527
 
524
 
528
   // Accept 'I' if temperature presets are defined
525
   // Accept 'I' if temperature presets are defined
529
   #if PREHEAT_COUNT
526
   #if PREHEAT_COUNT
548
         SERIAL_ECHOLNPAIR("?Specified bed temperature not plausible (40-", BED_MAX_TARGET, "C).");
545
         SERIAL_ECHOLNPAIR("?Specified bed temperature not plausible (40-", BED_MAX_TARGET, "C).");
549
         return;
546
         return;
550
       }
547
       }
551
-      g26_bed_temp = bedtemp;
548
+      g26.bed_temp = bedtemp;
552
     }
549
     }
553
 
550
 
554
   #endif // HAS_HEATED_BED
551
   #endif // HAS_HEATED_BED
555
 
552
 
556
   if (parser.seenval('L')) {
553
   if (parser.seenval('L')) {
557
-    g26_layer_height = parser.value_linear_units();
558
-    if (!WITHIN(g26_layer_height, 0.0, 2.0)) {
554
+    g26.layer_height = parser.value_linear_units();
555
+    if (!WITHIN(g26.layer_height, 0.0, 2.0)) {
559
       SERIAL_ECHOLNPGM("?Specified layer height not plausible.");
556
       SERIAL_ECHOLNPGM("?Specified layer height not plausible.");
560
       return;
557
       return;
561
     }
558
     }
563
 
560
 
564
   if (parser.seen('Q')) {
561
   if (parser.seen('Q')) {
565
     if (parser.has_value()) {
562
     if (parser.has_value()) {
566
-      g26_retraction_multiplier = parser.value_float();
567
-      if (!WITHIN(g26_retraction_multiplier, 0.05, 15.0)) {
563
+      g26.retraction_multiplier = parser.value_float();
564
+      if (!WITHIN(g26.retraction_multiplier, 0.05, 15.0)) {
568
         SERIAL_ECHOLNPGM("?Specified Retraction Multiplier not plausible.");
565
         SERIAL_ECHOLNPGM("?Specified Retraction Multiplier not plausible.");
569
         return;
566
         return;
570
       }
567
       }
576
   }
573
   }
577
 
574
 
578
   if (parser.seenval('S')) {
575
   if (parser.seenval('S')) {
579
-    g26_nozzle = parser.value_float();
580
-    if (!WITHIN(g26_nozzle, 0.1, 2.0)) {
576
+    g26.nozzle = parser.value_float();
577
+    if (!WITHIN(g26.nozzle, 0.1, 2.0)) {
581
       SERIAL_ECHOLNPGM("?Specified nozzle size not plausible.");
578
       SERIAL_ECHOLNPGM("?Specified nozzle size not plausible.");
582
       return;
579
       return;
583
     }
580
     }
586
   if (parser.seen('P')) {
583
   if (parser.seen('P')) {
587
     if (!parser.has_value()) {
584
     if (!parser.has_value()) {
588
       #if HAS_LCD_MENU
585
       #if HAS_LCD_MENU
589
-        g26_prime_flag = -1;
586
+        g26.prime_flag = -1;
590
       #else
587
       #else
591
         SERIAL_ECHOLNPGM("?Prime length must be specified when not using an LCD.");
588
         SERIAL_ECHOLNPGM("?Prime length must be specified when not using an LCD.");
592
         return;
589
         return;
593
       #endif
590
       #endif
594
     }
591
     }
595
     else {
592
     else {
596
-      g26_prime_flag++;
597
-      g26_prime_length = parser.value_linear_units();
598
-      if (!WITHIN(g26_prime_length, 0.0, 25.0)) {
593
+      g26.prime_flag++;
594
+      g26.prime_length = parser.value_linear_units();
595
+      if (!WITHIN(g26.prime_length, 0.0, 25.0)) {
599
         SERIAL_ECHOLNPGM("?Specified prime length not plausible.");
596
         SERIAL_ECHOLNPGM("?Specified prime length not plausible.");
600
         return;
597
         return;
601
       }
598
       }
603
   }
600
   }
604
 
601
 
605
   if (parser.seenval('F')) {
602
   if (parser.seenval('F')) {
606
-    g26_filament_diameter = parser.value_linear_units();
607
-    if (!WITHIN(g26_filament_diameter, 1.0, 4.0)) {
603
+    g26.filament_diameter = parser.value_linear_units();
604
+    if (!WITHIN(g26.filament_diameter, 1.0, 4.0)) {
608
       SERIAL_ECHOLNPGM("?Specified filament size not plausible.");
605
       SERIAL_ECHOLNPGM("?Specified filament size not plausible.");
609
       return;
606
       return;
610
     }
607
     }
611
   }
608
   }
612
-  g26_extrusion_multiplier *= sq(1.75) / sq(g26_filament_diameter); // If we aren't using 1.75mm filament, we need to
609
+  g26.extrusion_multiplier *= sq(1.75) / sq(g26.filament_diameter); // If we aren't using 1.75mm filament, we need to
613
                                                                     // scale up or down the length needed to get the
610
                                                                     // scale up or down the length needed to get the
614
                                                                     // same volume of filament
611
                                                                     // same volume of filament
615
 
612
 
616
-  g26_extrusion_multiplier *= g26_filament_diameter * sq(g26_nozzle) / sq(0.3); // Scale up by nozzle size
613
+  g26.extrusion_multiplier *= g26.filament_diameter * sq(g26.nozzle) / sq(0.3); // Scale up by nozzle size
617
 
614
 
618
   // Get a temperature from 'I' or 'H'
615
   // Get a temperature from 'I' or 'H'
619
   celsius_t noztemp = 0;
616
   celsius_t noztemp = 0;
632
       SERIAL_ECHOLNPGM("?Specified nozzle temperature not plausible.");
629
       SERIAL_ECHOLNPGM("?Specified nozzle temperature not plausible.");
633
       return;
630
       return;
634
     }
631
     }
635
-    g26_hotend_temp = noztemp;
632
+    g26.hotend_temp = noztemp;
636
   }
633
   }
637
 
634
 
638
   // 'U' to Randomize and optionally set circle deviation
635
   // 'U' to Randomize and optionally set circle deviation
660
   }
657
   }
661
 
658
 
662
   // Set a position with 'X' and/or 'Y'. Default: current_position
659
   // Set a position with 'X' and/or 'Y'. Default: current_position
663
-  g26_xy_pos.set(parser.seenval('X') ? RAW_X_POSITION(parser.value_linear_units()) : current_position.x,
660
+  g26.xy_pos.set(parser.seenval('X') ? RAW_X_POSITION(parser.value_linear_units()) : current_position.x,
664
                  parser.seenval('Y') ? RAW_Y_POSITION(parser.value_linear_units()) : current_position.y);
661
                  parser.seenval('Y') ? RAW_Y_POSITION(parser.value_linear_units()) : current_position.y);
665
-  if (!position_is_reachable(g26_xy_pos)) {
662
+  if (!position_is_reachable(g26.xy_pos)) {
666
     SERIAL_ECHOLNPGM("?Specified X,Y coordinate out of bounds.");
663
     SERIAL_ECHOLNPGM("?Specified X,Y coordinate out of bounds.");
667
     return;
664
     return;
668
   }
665
   }
680
     planner.calculate_volumetric_multipliers();
677
     planner.calculate_volumetric_multipliers();
681
   #endif
678
   #endif
682
 
679
 
683
-  if (turn_on_heaters() != G26_OK) goto LEAVE;
680
+  if (g26.turn_on_heaters() != G26_OK) goto LEAVE;
684
 
681
 
685
   current_position.e = 0.0;
682
   current_position.e = 0.0;
686
   sync_plan_position_e();
683
   sync_plan_position_e();
687
 
684
 
688
-  if (g26_prime_flag && prime_nozzle() != G26_OK) goto LEAVE;
685
+  if (g26.prime_flag && g26.prime_nozzle() != G26_OK) goto LEAVE;
689
 
686
 
690
   /**
687
   /**
691
    *  Bed is preheated
688
    *  Bed is preheated
698
    */
695
    */
699
 
696
 
700
   circle_flags.reset();
697
   circle_flags.reset();
701
-  horizontal_mesh_line_flags.reset();
702
-  vertical_mesh_line_flags.reset();
703
 
698
 
704
   // Move nozzle to the specified height for the first layer
699
   // Move nozzle to the specified height for the first layer
705
   destination = current_position;
700
   destination = current_position;
706
-  destination.z = g26_layer_height;
701
+  destination.z = g26.layer_height;
707
   move_to(destination, 0.0);
702
   move_to(destination, 0.0);
708
-  move_to(destination, g26_ooze_amount);
703
+  move_to(destination, g26.ooze_amount);
709
 
704
 
710
   TERN_(HAS_LCD_MENU, ui.capture());
705
   TERN_(HAS_LCD_MENU, ui.capture());
711
 
706
 
732
   mesh_index_pair location;
727
   mesh_index_pair location;
733
   do {
728
   do {
734
     // Find the nearest confluence
729
     // Find the nearest confluence
735
-    location = find_closest_circle_to_print(g26_continue_with_closest ? xy_pos_t(current_position) : g26_xy_pos);
730
+    location = g26.find_closest_circle_to_print(g26.continue_with_closest ? xy_pos_t(current_position) : g26.xy_pos);
736
 
731
 
737
     if (location.valid()) {
732
     if (location.valid()) {
738
       const xy_pos_t circle = _GET_MESH_POS(location.pos);
733
       const xy_pos_t circle = _GET_MESH_POS(location.pos);
762
           if (!b) { e.x = circle.x; e.y += INTERSECTION_CIRCLE_RADIUS; }
757
           if (!b) { e.x = circle.x; e.y += INTERSECTION_CIRCLE_RADIUS; }
763
           arc_length = (f || b) ? ARC_LENGTH(1) : ARC_LENGTH(2);
758
           arc_length = (f || b) ? ARC_LENGTH(1) : ARC_LENGTH(2);
764
         }
759
         }
765
-        else if (r) {                             // right edge
760
+        else if (r) {                               // right edge
766
           if (b) s.set(circle.x - (INTERSECTION_CIRCLE_RADIUS), circle.y);
761
           if (b) s.set(circle.x - (INTERSECTION_CIRCLE_RADIUS), circle.y);
767
           else   s.set(circle.x, circle.y + INTERSECTION_CIRCLE_RADIUS);
762
           else   s.set(circle.x, circle.y + INTERSECTION_CIRCLE_RADIUS);
768
           if (f) e.set(circle.x - (INTERSECTION_CIRCLE_RADIUS), circle.y);
763
           if (f) e.set(circle.x - (INTERSECTION_CIRCLE_RADIUS), circle.y);
782
         const xy_float_t dist = current_position - s;   // Distance from the start of the actual circle
777
         const xy_float_t dist = current_position - s;   // Distance from the start of the actual circle
783
         const float dist_start = HYPOT2(dist.x, dist.y);
778
         const float dist_start = HYPOT2(dist.x, dist.y);
784
         const xyze_pos_t endpoint = {
779
         const xyze_pos_t endpoint = {
785
-          e.x, e.y, g26_layer_height,
786
-          current_position.e + (arc_length * g26_e_axis_feedrate * g26_extrusion_multiplier)
780
+          e.x, e.y, g26.layer_height,
781
+          current_position.e + (arc_length * g26_e_axis_feedrate * g26.extrusion_multiplier)
787
         };
782
         };
788
 
783
 
789
         if (dist_start > 2.0) {
784
         if (dist_start > 2.0) {
790
-          s.z = g26_layer_height + 0.5f;
791
-          retract_lift_move(s);
785
+          s.z = g26.layer_height + 0.5f;
786
+          g26.retract_lift_move(s);
792
         }
787
         }
793
 
788
 
794
-        s.z = g26_layer_height;
789
+        s.z = g26.layer_height;
795
         move_to(s, 0.0);  // Get to the starting point with no extrusion / un-Z lift
790
         move_to(s, 0.0);  // Get to the starting point with no extrusion / un-Z lift
796
 
791
 
797
-        recover_filament(destination);
792
+        g26.recover_filament(destination);
798
 
793
 
799
-        const feedRate_t old_feedrate = feedrate_mm_s;
800
-        feedrate_mm_s = PLANNER_XY_FEEDRATE() * 0.1f;
801
-        plan_arc(endpoint, arc_offset, false, 0);  // Draw a counter-clockwise arc
802
-        feedrate_mm_s = old_feedrate;
803
-        destination = current_position;
794
+        { REMEMBER(fr, feedrate_mm_s, PLANNER_XY_FEEDRATE() * 0.1f);
795
+          plan_arc(endpoint, arc_offset, false, 0);  // Draw a counter-clockwise arc
796
+          destination = current_position;
797
+        }
804
 
798
 
805
         if (TERN0(HAS_LCD_MENU, user_canceled())) goto LEAVE; // Check if the user wants to stop the Mesh Validation
799
         if (TERN0(HAS_LCD_MENU, user_canceled())) goto LEAVE; // Check if the user wants to stop the Mesh Validation
806
 
800
 
828
 
822
 
829
           if (TERN0(HAS_LCD_MENU, user_canceled())) goto LEAVE; // Check if the user wants to stop the Mesh Validation
823
           if (TERN0(HAS_LCD_MENU, user_canceled())) goto LEAVE; // Check if the user wants to stop the Mesh Validation
830
 
824
 
831
-          xyz_float_t p = { circle.x + _COS(ind    ), circle.y + _SIN(ind    ), g26_layer_height },
832
-                      q = { circle.x + _COS(ind + 1), circle.y + _SIN(ind + 1), g26_layer_height };
825
+          xyz_float_t p = { circle.x + _COS(ind    ), circle.y + _SIN(ind    ), g26.layer_height },
826
+                      q = { circle.x + _COS(ind + 1), circle.y + _SIN(ind + 1), g26.layer_height };
833
 
827
 
834
           #if IS_KINEMATIC
828
           #if IS_KINEMATIC
835
             // Check to make sure this segment is entirely on the bed, skip if not.
829
             // Check to make sure this segment is entirely on the bed, skip if not.
841
             LIMIT(q.y, Y_MIN_POS + 1, Y_MAX_POS - 1);
835
             LIMIT(q.y, Y_MIN_POS + 1, Y_MAX_POS - 1);
842
           #endif
836
           #endif
843
 
837
 
844
-          print_line_from_here_to_there(p, q);
838
+          g26.print_line_from_here_to_there(p, q);
845
           SERIAL_FLUSH();   // Prevent host M105 buffer overrun.
839
           SERIAL_FLUSH();   // Prevent host M105 buffer overrun.
846
         }
840
         }
847
 
841
 
848
       #endif // !ARC_SUPPORT
842
       #endif // !ARC_SUPPORT
849
 
843
 
850
-      if (look_for_lines_to_connect()) goto LEAVE;
844
+      g26.connect_neighbor_with_line(location.pos, -1,  0);
845
+      g26.connect_neighbor_with_line(location.pos,  1,  0);
846
+      g26.connect_neighbor_with_line(location.pos,  0, -1);
847
+      g26.connect_neighbor_with_line(location.pos,  0,  1);
848
+      if (TERN0(HAS_LCD_MENU, user_canceled())) goto LEAVE;
851
     }
849
     }
852
 
850
 
853
     SERIAL_FLUSH(); // Prevent host M105 buffer overrun.
851
     SERIAL_FLUSH(); // Prevent host M105 buffer overrun.
857
   LEAVE:
855
   LEAVE:
858
   ui.set_status_P(GET_TEXT(MSG_G26_LEAVING), -1);
856
   ui.set_status_P(GET_TEXT(MSG_G26_LEAVING), -1);
859
 
857
 
860
-  retract_filament(destination);
858
+  g26.retract_filament(destination);
861
   destination.z = Z_CLEARANCE_BETWEEN_PROBES;
859
   destination.z = Z_CLEARANCE_BETWEEN_PROBES;
862
-  move_to(destination, 0);                                    // Raise the nozzle
863
-
864
-  destination = g26_xy_pos;                                   // Move back to the starting XY position
865
-  move_to(destination, 0);                                    // Move back to the starting position
860
+  move_to(destination, 0);                                   // Raise the nozzle
866
 
861
 
867
   #if DISABLED(NO_VOLUMETRICS)
862
   #if DISABLED(NO_VOLUMETRICS)
868
     parser.volumetric_enabled = volumetric_was_enabled;
863
     parser.volumetric_enabled = volumetric_was_enabled;
871
 
866
 
872
   TERN_(HAS_LCD_MENU, ui.release()); // Give back control of the LCD
867
   TERN_(HAS_LCD_MENU, ui.release()); // Give back control of the LCD
873
 
868
 
874
-  if (!g26_keep_heaters_on) {
869
+  if (!g26.keep_heaters_on) {
875
     TERN_(HAS_HEATED_BED, thermalManager.setTargetBed(0));
870
     TERN_(HAS_HEATED_BED, thermalManager.setTargetBed(0));
876
     thermalManager.setTargetHotend(active_extruder, 0);
871
     thermalManager.setTargetHotend(active_extruder, 0);
877
   }
872
   }

+ 2
- 2
Marlin/src/gcode/bedlevel/M420.cpp Ver arquivo

68
                   y_min = probe.min_y(), y_max = probe.max_y();
68
                   y_min = probe.min_y(), y_max = probe.max_y();
69
       #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
69
       #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
70
         bilinear_start.set(x_min, y_min);
70
         bilinear_start.set(x_min, y_min);
71
-        bilinear_grid_spacing.set((x_max - x_min) / (GRID_MAX_POINTS_X - 1),
72
-                                  (y_max - y_min) / (GRID_MAX_POINTS_Y - 1));
71
+        bilinear_grid_spacing.set((x_max - x_min) / (GRID_MAX_CELLS_X),
72
+                                  (y_max - y_min) / (GRID_MAX_CELLS_Y));
73
       #endif
73
       #endif
74
       GRID_LOOP(x, y) {
74
       GRID_LOOP(x, y) {
75
         Z_VALUES(x, y) = 0.001 * random(-200, 200);
75
         Z_VALUES(x, y) = 0.001 * random(-200, 200);

+ 3
- 3
Marlin/src/gcode/bedlevel/abl/G29.cpp Ver arquivo

295
           // Get nearest i / j from rx / ry
295
           // Get nearest i / j from rx / ry
296
           i = (rx - bilinear_start.x + 0.5 * abl.gridSpacing.x) / abl.gridSpacing.x;
296
           i = (rx - bilinear_start.x + 0.5 * abl.gridSpacing.x) / abl.gridSpacing.x;
297
           j = (ry - bilinear_start.y + 0.5 * abl.gridSpacing.y) / abl.gridSpacing.y;
297
           j = (ry - bilinear_start.y + 0.5 * abl.gridSpacing.y) / abl.gridSpacing.y;
298
-          LIMIT(i, 0, GRID_MAX_POINTS_X - 1);
299
-          LIMIT(j, 0, GRID_MAX_POINTS_Y - 1);
298
+          LIMIT(i, 0, (GRID_MAX_POINTS_X) - 1);
299
+          LIMIT(j, 0, (GRID_MAX_POINTS_Y) - 1);
300
         }
300
         }
301
-        if (WITHIN(i, 0, GRID_MAX_POINTS_X - 1) && WITHIN(j, 0, GRID_MAX_POINTS_Y)) {
301
+        if (WITHIN(i, 0, (GRID_MAX_POINTS_X) - 1) && WITHIN(j, 0, (GRID_MAX_POINTS_Y) - 1)) {
302
           set_bed_leveling_enabled(false);
302
           set_bed_leveling_enabled(false);
303
           z_values[i][j] = rz;
303
           z_values[i][j] = rz;
304
           TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate());
304
           TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate());

+ 5
- 5
Marlin/src/gcode/bedlevel/mbl/G29.cpp Ver arquivo

106
         SET_SOFT_ENDSTOP_LOOSE(false);
106
         SET_SOFT_ENDSTOP_LOOSE(false);
107
       }
107
       }
108
       // If there's another point to sample, move there with optional lift.
108
       // If there's another point to sample, move there with optional lift.
109
-      if (mbl_probe_index < GRID_MAX_POINTS) {
109
+      if (mbl_probe_index < (GRID_MAX_POINTS)) {
110
         // Disable software endstops to allow manual adjustment
110
         // Disable software endstops to allow manual adjustment
111
         // If G29 is left hanging without completion they won't be re-enabled!
111
         // If G29 is left hanging without completion they won't be re-enabled!
112
         SET_SOFT_ENDSTOP_LOOSE(true);
112
         SET_SOFT_ENDSTOP_LOOSE(true);
142
     case MeshSet:
142
     case MeshSet:
143
       if (parser.seenval('I')) {
143
       if (parser.seenval('I')) {
144
         ix = parser.value_int();
144
         ix = parser.value_int();
145
-        if (!WITHIN(ix, 0, GRID_MAX_POINTS_X - 1)) {
146
-          SERIAL_ECHOLNPAIR("I out of range (0-", GRID_MAX_POINTS_X - 1, ")");
145
+        if (!WITHIN(ix, 0, (GRID_MAX_POINTS_X) - 1)) {
146
+          SERIAL_ECHOLNPAIR("I out of range (0-", (GRID_MAX_POINTS_X) - 1, ")");
147
           return;
147
           return;
148
         }
148
         }
149
       }
149
       }
152
 
152
 
153
       if (parser.seenval('J')) {
153
       if (parser.seenval('J')) {
154
         iy = parser.value_int();
154
         iy = parser.value_int();
155
-        if (!WITHIN(iy, 0, GRID_MAX_POINTS_Y - 1)) {
156
-          SERIAL_ECHOLNPAIR("J out of range (0-", GRID_MAX_POINTS_Y - 1, ")");
155
+        if (!WITHIN(iy, 0, (GRID_MAX_POINTS_Y) - 1)) {
156
+          SERIAL_ECHOLNPAIR("J out of range (0-", (GRID_MAX_POINTS_Y) - 1, ")");
157
           return;
157
           return;
158
         }
158
         }
159
       }
159
       }

+ 5
- 0
Marlin/src/inc/Conditionals_post.h Ver arquivo

224
   #endif
224
   #endif
225
 #endif
225
 #endif
226
 
226
 
227
+#ifdef GRID_MAX_POINTS_X
228
+  #define GRID_MAX_CELLS_X (GRID_MAX_POINTS_X - 1)
229
+  #define GRID_MAX_CELLS_Y (GRID_MAX_POINTS_Y - 1)
230
+#endif
231
+
227
 /**
232
 /**
228
  * Host keep alive
233
  * Host keep alive
229
  */
234
  */

+ 3
- 3
Marlin/src/inc/SanityCheck.h Ver arquivo

1263
   #elif ENABLED(DELTA_CALIBRATION_MENU) && !HAS_LCD_MENU
1263
   #elif ENABLED(DELTA_CALIBRATION_MENU) && !HAS_LCD_MENU
1264
     #error "DELTA_CALIBRATION_MENU requires an LCD Controller."
1264
     #error "DELTA_CALIBRATION_MENU requires an LCD Controller."
1265
   #elif ABL_USES_GRID
1265
   #elif ABL_USES_GRID
1266
-    #if (GRID_MAX_POINTS_X & 1) == 0 || (GRID_MAX_POINTS_Y & 1) == 0
1266
+    #if ((GRID_MAX_POINTS_X) & 1) == 0 || ((GRID_MAX_POINTS_Y) & 1) == 0
1267
       #error "DELTA requires GRID_MAX_POINTS_X and GRID_MAX_POINTS_Y to be odd numbers."
1267
       #error "DELTA requires GRID_MAX_POINTS_X and GRID_MAX_POINTS_Y to be odd numbers."
1268
-    #elif GRID_MAX_POINTS_X < 3
1268
+    #elif (GRID_MAX_POINTS_X) < 3
1269
       #error "DELTA requires GRID_MAX_POINTS_X and GRID_MAX_POINTS_Y to be 3 or higher."
1269
       #error "DELTA requires GRID_MAX_POINTS_X and GRID_MAX_POINTS_Y to be 3 or higher."
1270
     #endif
1270
     #endif
1271
   #endif
1271
   #endif
1518
   // Mesh Bed Leveling
1518
   // Mesh Bed Leveling
1519
   #if ENABLED(DELTA)
1519
   #if ENABLED(DELTA)
1520
     #error "MESH_BED_LEVELING is not compatible with DELTA printers."
1520
     #error "MESH_BED_LEVELING is not compatible with DELTA printers."
1521
-  #elif GRID_MAX_POINTS_X > 9 || GRID_MAX_POINTS_Y > 9
1521
+  #elif (GRID_MAX_POINTS_X) > 9 || (GRID_MAX_POINTS_Y) > 9
1522
     #error "GRID_MAX_POINTS_X and GRID_MAX_POINTS_Y must be less than 10 for MBL."
1522
     #error "GRID_MAX_POINTS_X and GRID_MAX_POINTS_Y must be less than 10 for MBL."
1523
   #endif
1523
   #endif
1524
 
1524
 

+ 1
- 1
Marlin/src/lcd/HD44780/marlinui_HD44780.cpp Ver arquivo

1279
                    pixels_per_x_mesh_pnt, pixels_per_y_mesh_pnt,
1279
                    pixels_per_x_mesh_pnt, pixels_per_y_mesh_pnt,
1280
                    suppress_x_offset = 0, suppress_y_offset = 0;
1280
                    suppress_x_offset = 0, suppress_y_offset = 0;
1281
 
1281
 
1282
-        const uint8_t y_plot_inv = (GRID_MAX_POINTS_Y - 1) - y_plot;
1282
+        const uint8_t y_plot_inv = (GRID_MAX_POINTS_Y) - 1 - y_plot;
1283
 
1283
 
1284
         upper_left.column  = 0;
1284
         upper_left.column  = 0;
1285
         upper_left.row     = 0;
1285
         upper_left.row     = 0;

+ 1
- 1
Marlin/src/lcd/dogm/marlinui_DOGM.cpp Ver arquivo

529
 
529
 
530
       // Fill in the Specified Mesh Point
530
       // Fill in the Specified Mesh Point
531
 
531
 
532
-      const uint8_t y_plot_inv = (GRID_MAX_POINTS_Y - 1) - y_plot;  // The origin is typically in the lower right corner.  We need to
532
+      const uint8_t y_plot_inv = (GRID_MAX_POINTS_Y) - 1 - y_plot;  // The origin is typically in the lower right corner.  We need to
533
                                                                     // invert the Y to get it to plot in the right location.
533
                                                                     // invert the Y to get it to plot in the right location.
534
 
534
 
535
       const u8g_uint_t by = y_offset + y_plot_inv * pixels_per_y_mesh_pnt;
535
       const u8g_uint_t by = y_offset + y_plot_inv * pixels_per_y_mesh_pnt;

+ 5
- 5
Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bed_mesh_screen.cpp Ver arquivo

53
 #endif
53
 #endif
54
 
54
 
55
 void BedMeshScreen::drawMesh(int16_t x, int16_t y, int16_t w, int16_t h, ExtUI::bed_mesh_t data, uint8_t opts, float autoscale_max) {
55
 void BedMeshScreen::drawMesh(int16_t x, int16_t y, int16_t w, int16_t h, ExtUI::bed_mesh_t data, uint8_t opts, float autoscale_max) {
56
-  constexpr uint8_t rows       = GRID_MAX_POINTS_Y;
57
-  constexpr uint8_t cols       = GRID_MAX_POINTS_X;
56
+  constexpr uint8_t rows = GRID_MAX_POINTS_Y;
57
+  constexpr uint8_t cols = GRID_MAX_POINTS_X;
58
 
58
 
59
-  #define VALUE(X,Y)         (data ? data[X][Y] : 0)
60
-  #define ISVAL(X,Y)         (data ? !isnan(VALUE(X,Y)) : true)
61
-  #define HEIGHT(X,Y)        (ISVAL(X,Y) ? (VALUE(X,Y) - val_min) * scale_z : 0)
59
+  #define VALUE(X,Y)  (data ? data[X][Y] : 0)
60
+  #define ISVAL(X,Y)  (data ? !isnan(VALUE(X,Y)) : true)
61
+  #define HEIGHT(X,Y) (ISVAL(X,Y) ? (VALUE(X,Y) - val_min) * scale_z : 0)
62
 
62
 
63
   // Compute the mean, min and max for the points
63
   // Compute the mean, min and max for the points
64
 
64
 

+ 1
- 1
Marlin/src/lcd/extui/ui_api.cpp Ver arquivo

859
       bed_mesh_t& getMeshArray() { return Z_VALUES_ARR; }
859
       bed_mesh_t& getMeshArray() { return Z_VALUES_ARR; }
860
       float getMeshPoint(const xy_uint8_t &pos) { return Z_VALUES(pos.x, pos.y); }
860
       float getMeshPoint(const xy_uint8_t &pos) { return Z_VALUES(pos.x, pos.y); }
861
       void setMeshPoint(const xy_uint8_t &pos, const_float_t zoff) {
861
       void setMeshPoint(const xy_uint8_t &pos, const_float_t zoff) {
862
-        if (WITHIN(pos.x, 0, GRID_MAX_POINTS_X) && WITHIN(pos.y, 0, GRID_MAX_POINTS_Y)) {
862
+        if (WITHIN(pos.x, 0, (GRID_MAX_POINTS_X) - 1) && WITHIN(pos.y, 0, (GRID_MAX_POINTS_Y) - 1)) {
863
           Z_VALUES(pos.x, pos.y) = zoff;
863
           Z_VALUES(pos.x, pos.y) = zoff;
864
           TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate());
864
           TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate());
865
         }
865
         }

+ 2
- 2
Marlin/src/lcd/menu/menu_bed_leveling.cpp Ver arquivo

214
     static uint8_t xind, yind; // =0
214
     static uint8_t xind, yind; // =0
215
     START_MENU();
215
     START_MENU();
216
     BACK_ITEM(MSG_BED_LEVELING);
216
     BACK_ITEM(MSG_BED_LEVELING);
217
-    EDIT_ITEM(uint8, MSG_MESH_X, &xind, 0, GRID_MAX_POINTS_X - 1);
218
-    EDIT_ITEM(uint8, MSG_MESH_Y, &yind, 0, GRID_MAX_POINTS_Y - 1);
217
+    EDIT_ITEM(uint8, MSG_MESH_X, &xind, 0, (GRID_MAX_POINTS_X) - 1);
218
+    EDIT_ITEM(uint8, MSG_MESH_Y, &yind, 0, (GRID_MAX_POINTS_Y) - 1);
219
     EDIT_ITEM_FAST(float43, MSG_MESH_EDIT_Z, &Z_VALUES(xind, yind), -(LCD_PROBE_Z_RANGE) * 0.5, (LCD_PROBE_Z_RANGE) * 0.5, refresh_planner);
219
     EDIT_ITEM_FAST(float43, MSG_MESH_EDIT_Z, &Z_VALUES(xind, yind), -(LCD_PROBE_Z_RANGE) * 0.5, (LCD_PROBE_Z_RANGE) * 0.5, refresh_planner);
220
     END_MENU();
220
     END_MENU();
221
   }
221
   }

+ 2
- 2
Marlin/src/lcd/menu/menu_ubl.cpp Ver arquivo

484
     #if IS_KINEMATIC
484
     #if IS_KINEMATIC
485
       n_edit_pts = 9; // TODO: Delta accessible edit points
485
       n_edit_pts = 9; // TODO: Delta accessible edit points
486
     #else
486
     #else
487
-      const bool xc = WITHIN(x, 1, GRID_MAX_POINTS_X - 2),
488
-                 yc = WITHIN(y, 1, GRID_MAX_POINTS_Y - 2);
487
+      const bool xc = WITHIN(x, 1, (GRID_MAX_POINTS_X) - 2),
488
+                 yc = WITHIN(y, 1, (GRID_MAX_POINTS_Y) - 2);
489
       n_edit_pts = yc ? (xc ? 9 : 6) : (xc ? 6 : 4); // Corners
489
       n_edit_pts = yc ? (xc ? 9 : 6) : (xc ? 6 : 4); // Corners
490
     #endif
490
     #endif
491
 
491
 

+ 7
- 7
Marlin/src/lcd/tft/ui_320x240.cpp Ver arquivo

462
     tft.set_background(COLOR_BACKGROUND);
462
     tft.set_background(COLOR_BACKGROUND);
463
     tft.add_rectangle(0, 0, GRID_WIDTH, GRID_HEIGHT, COLOR_WHITE);
463
     tft.add_rectangle(0, 0, GRID_WIDTH, GRID_HEIGHT, COLOR_WHITE);
464
 
464
 
465
-    for (uint16_t x = 0; x < GRID_MAX_POINTS_X ; x++)
466
-      for (uint16_t y = 0; y < GRID_MAX_POINTS_Y ; y++)
465
+    for (uint16_t x = 0; x < (GRID_MAX_POINTS_X); x++)
466
+      for (uint16_t y = 0; y < (GRID_MAX_POINTS_Y); y++)
467
         if (position_is_reachable({ ubl.mesh_index_to_xpos(x), ubl.mesh_index_to_ypos(y) }))
467
         if (position_is_reachable({ ubl.mesh_index_to_xpos(x), ubl.mesh_index_to_ypos(y) }))
468
-          tft.add_bar(1 + (x * 2 + 1) * (GRID_WIDTH - 4) / GRID_MAX_POINTS_X / 2, GRID_HEIGHT - 3 - ((y * 2 + 1) * (GRID_HEIGHT - 4) / GRID_MAX_POINTS_Y / 2), 2, 2, COLOR_UBL);
468
+          tft.add_bar(1 + (x * 2 + 1) * (GRID_WIDTH - 4) / (GRID_MAX_POINTS_X) / 2, GRID_HEIGHT - 3 - ((y * 2 + 1) * (GRID_HEIGHT - 4) / (GRID_MAX_POINTS_Y) / 2), 2, 2, COLOR_UBL);
469
 
469
 
470
-    tft.add_rectangle((x_plot * 2 + 1) * (GRID_WIDTH - 4) / GRID_MAX_POINTS_X / 2 - 1, GRID_HEIGHT - 5 - ((y_plot * 2 + 1) * (GRID_HEIGHT - 4) / GRID_MAX_POINTS_Y / 2), 6, 6, COLOR_UBL);
470
+    tft.add_rectangle((x_plot * 2 + 1) * (GRID_WIDTH - 4) / (GRID_MAX_POINTS_X) / 2 - 1, GRID_HEIGHT - 5 - ((y_plot * 2 + 1) * (GRID_HEIGHT - 4) / (GRID_MAX_POINTS_Y) / 2), 6, 6, COLOR_UBL);
471
 
471
 
472
     const xy_pos_t pos = { ubl.mesh_index_to_xpos(x_plot), ubl.mesh_index_to_ypos(y_plot) },
472
     const xy_pos_t pos = { ubl.mesh_index_to_xpos(x_plot), ubl.mesh_index_to_ypos(y_plot) },
473
                    lpos = pos.asLogical();
473
                    lpos = pos.asLogical();
512
     #if ENABLED(TOUCH_SCREEN)
512
     #if ENABLED(TOUCH_SCREEN)
513
       touch.clear();
513
       touch.clear();
514
       draw_menu_navigation = false;
514
       draw_menu_navigation = false;
515
-      add_control(GRID_OFFSET_X + GRID_WIDTH + CONTROL_OFFSET,      GRID_OFFSET_Y + CONTROL_OFFSET,                    UBL,   ENCODER_STEPS_PER_MENU_ITEM * GRID_MAX_POINTS_X, imgUp);
516
-      add_control(GRID_OFFSET_X + GRID_WIDTH + CONTROL_OFFSET,      GRID_OFFSET_Y + GRID_HEIGHT - CONTROL_OFFSET - 32, UBL, - ENCODER_STEPS_PER_MENU_ITEM * GRID_MAX_POINTS_X, imgDown);
517
-      add_control(GRID_OFFSET_X + CONTROL_OFFSET,                   GRID_OFFSET_Y + GRID_HEIGHT + CONTROL_OFFSET,      UBL, - ENCODER_STEPS_PER_MENU_ITEM, imgLeft);
515
+      add_control(GRID_OFFSET_X + GRID_WIDTH + CONTROL_OFFSET,      GRID_OFFSET_Y + CONTROL_OFFSET,                    UBL,  (ENCODER_STEPS_PER_MENU_ITEM) * (GRID_MAX_POINTS_X), imgUp);
516
+      add_control(GRID_OFFSET_X + GRID_WIDTH + CONTROL_OFFSET,      GRID_OFFSET_Y + GRID_HEIGHT - CONTROL_OFFSET - 32, UBL, -(ENCODER_STEPS_PER_MENU_ITEM) * (GRID_MAX_POINTS_X), imgDown);
517
+      add_control(GRID_OFFSET_X + CONTROL_OFFSET,                   GRID_OFFSET_Y + GRID_HEIGHT + CONTROL_OFFSET,      UBL, -(ENCODER_STEPS_PER_MENU_ITEM), imgLeft);
518
       add_control(GRID_OFFSET_X + GRID_WIDTH - CONTROL_OFFSET - 32, GRID_OFFSET_Y + GRID_HEIGHT + CONTROL_OFFSET,      UBL,   ENCODER_STEPS_PER_MENU_ITEM, imgRight);
518
       add_control(GRID_OFFSET_X + GRID_WIDTH - CONTROL_OFFSET - 32, GRID_OFFSET_Y + GRID_HEIGHT + CONTROL_OFFSET,      UBL,   ENCODER_STEPS_PER_MENU_ITEM, imgRight);
519
       add_control(224, GRID_OFFSET_Y + GRID_HEIGHT + CONTROL_OFFSET, CLICK, imgLeveling);
519
       add_control(224, GRID_OFFSET_Y + GRID_HEIGHT + CONTROL_OFFSET, CLICK, imgLeveling);
520
       add_control(144, 206, BACK, imgBack);
520
       add_control(144, 206, BACK, imgBack);

+ 7
- 7
Marlin/src/lcd/tft/ui_480x320.cpp Ver arquivo

462
     tft.set_background(COLOR_BACKGROUND);
462
     tft.set_background(COLOR_BACKGROUND);
463
     tft.add_rectangle(0, 0, GRID_WIDTH, GRID_HEIGHT, COLOR_WHITE);
463
     tft.add_rectangle(0, 0, GRID_WIDTH, GRID_HEIGHT, COLOR_WHITE);
464
 
464
 
465
-    for (uint16_t x = 0; x < GRID_MAX_POINTS_X ; x++)
466
-      for (uint16_t y = 0; y < GRID_MAX_POINTS_Y ; y++)
465
+    for (uint16_t x = 0; x < (GRID_MAX_POINTS_X); x++)
466
+      for (uint16_t y = 0; y < (GRID_MAX_POINTS_Y); y++)
467
         if (position_is_reachable({ ubl.mesh_index_to_xpos(x), ubl.mesh_index_to_ypos(y) }))
467
         if (position_is_reachable({ ubl.mesh_index_to_xpos(x), ubl.mesh_index_to_ypos(y) }))
468
-          tft.add_bar(1 + (x * 2 + 1) * (GRID_WIDTH - 4) / GRID_MAX_POINTS_X / 2, GRID_HEIGHT - 3 - ((y * 2 + 1) * (GRID_HEIGHT - 4) / GRID_MAX_POINTS_Y / 2), 2, 2, COLOR_UBL);
468
+          tft.add_bar(1 + (x * 2 + 1) * (GRID_WIDTH - 4) / (GRID_MAX_POINTS_X) / 2, GRID_HEIGHT - 3 - ((y * 2 + 1) * (GRID_HEIGHT - 4) / (GRID_MAX_POINTS_Y) / 2), 2, 2, COLOR_UBL);
469
 
469
 
470
-    tft.add_rectangle((x_plot * 2 + 1) * (GRID_WIDTH - 4) / GRID_MAX_POINTS_X / 2 - 1, GRID_HEIGHT - 5 - ((y_plot * 2 + 1) * (GRID_HEIGHT - 4) / GRID_MAX_POINTS_Y / 2), 6, 6, COLOR_UBL);
470
+    tft.add_rectangle((x_plot * 2 + 1) * (GRID_WIDTH - 4) / (GRID_MAX_POINTS_X) / 2 - 1, GRID_HEIGHT - 5 - ((y_plot * 2 + 1) * (GRID_HEIGHT - 4) / (GRID_MAX_POINTS_Y) / 2), 6, 6, COLOR_UBL);
471
 
471
 
472
     const xy_pos_t pos = { ubl.mesh_index_to_xpos(x_plot), ubl.mesh_index_to_ypos(y_plot) },
472
     const xy_pos_t pos = { ubl.mesh_index_to_xpos(x_plot), ubl.mesh_index_to_ypos(y_plot) },
473
                    lpos = pos.asLogical();
473
                    lpos = pos.asLogical();
512
     #if ENABLED(TOUCH_SCREEN)
512
     #if ENABLED(TOUCH_SCREEN)
513
       touch.clear();
513
       touch.clear();
514
       draw_menu_navigation = false;
514
       draw_menu_navigation = false;
515
-      add_control(GRID_OFFSET_X + GRID_WIDTH + CONTROL_OFFSET,      GRID_OFFSET_Y + CONTROL_OFFSET,                    UBL,   ENCODER_STEPS_PER_MENU_ITEM * GRID_MAX_POINTS_X, imgUp);
516
-      add_control(GRID_OFFSET_X + GRID_WIDTH + CONTROL_OFFSET,      GRID_OFFSET_Y + GRID_HEIGHT - CONTROL_OFFSET - 32, UBL, - ENCODER_STEPS_PER_MENU_ITEM * GRID_MAX_POINTS_X, imgDown);
517
-      add_control(GRID_OFFSET_X + CONTROL_OFFSET,                   GRID_OFFSET_Y + GRID_HEIGHT + CONTROL_OFFSET,      UBL, - ENCODER_STEPS_PER_MENU_ITEM, imgLeft);
515
+      add_control(GRID_OFFSET_X + GRID_WIDTH + CONTROL_OFFSET,      GRID_OFFSET_Y + CONTROL_OFFSET,                    UBL,  (ENCODER_STEPS_PER_MENU_ITEM) * (GRID_MAX_POINTS_X), imgUp);
516
+      add_control(GRID_OFFSET_X + GRID_WIDTH + CONTROL_OFFSET,      GRID_OFFSET_Y + GRID_HEIGHT - CONTROL_OFFSET - 32, UBL, -(ENCODER_STEPS_PER_MENU_ITEM) * (GRID_MAX_POINTS_X), imgDown);
517
+      add_control(GRID_OFFSET_X + CONTROL_OFFSET,                   GRID_OFFSET_Y + GRID_HEIGHT + CONTROL_OFFSET,      UBL, -(ENCODER_STEPS_PER_MENU_ITEM), imgLeft);
518
       add_control(GRID_OFFSET_X + GRID_WIDTH - CONTROL_OFFSET - 32, GRID_OFFSET_Y + GRID_HEIGHT + CONTROL_OFFSET,      UBL,   ENCODER_STEPS_PER_MENU_ITEM, imgRight);
518
       add_control(GRID_OFFSET_X + GRID_WIDTH - CONTROL_OFFSET - 32, GRID_OFFSET_Y + GRID_HEIGHT + CONTROL_OFFSET,      UBL,   ENCODER_STEPS_PER_MENU_ITEM, imgRight);
519
       add_control(320, GRID_OFFSET_Y + GRID_HEIGHT + CONTROL_OFFSET, CLICK, imgLeveling);
519
       add_control(320, GRID_OFFSET_Y + GRID_HEIGHT + CONTROL_OFFSET, CLICK, imgLeveling);
520
       add_control(224, TFT_HEIGHT - 34, BACK, imgBack);
520
       add_control(224, TFT_HEIGHT - 34, BACK, imgBack);

+ 2
- 2
Marlin/src/module/settings.cpp Ver arquivo

1605
 
1605
 
1606
         #if ENABLED(MESH_BED_LEVELING)
1606
         #if ENABLED(MESH_BED_LEVELING)
1607
           if (!validating) mbl.z_offset = dummyf;
1607
           if (!validating) mbl.z_offset = dummyf;
1608
-          if (mesh_num_x == GRID_MAX_POINTS_X && mesh_num_y == GRID_MAX_POINTS_Y) {
1608
+          if (mesh_num_x == (GRID_MAX_POINTS_X) && mesh_num_y == (GRID_MAX_POINTS_Y)) {
1609
             // EEPROM data fits the current mesh
1609
             // EEPROM data fits the current mesh
1610
             EEPROM_READ(mbl.z_values);
1610
             EEPROM_READ(mbl.z_values);
1611
           }
1611
           }
1652
         EEPROM_READ_ALWAYS(grid_max_x);                // 1 byte
1652
         EEPROM_READ_ALWAYS(grid_max_x);                // 1 byte
1653
         EEPROM_READ_ALWAYS(grid_max_y);                // 1 byte
1653
         EEPROM_READ_ALWAYS(grid_max_y);                // 1 byte
1654
         #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
1654
         #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
1655
-          if (grid_max_x == GRID_MAX_POINTS_X && grid_max_y == GRID_MAX_POINTS_Y) {
1655
+          if (grid_max_x == (GRID_MAX_POINTS_X) && grid_max_y == (GRID_MAX_POINTS_Y)) {
1656
             if (!validating) set_bed_leveling_enabled(false);
1656
             if (!validating) set_bed_leveling_enabled(false);
1657
             EEPROM_READ(bilinear_grid_spacing);        // 2 ints
1657
             EEPROM_READ(bilinear_grid_spacing);        // 2 ints
1658
             EEPROM_READ(bilinear_start);               // 2 ints
1658
             EEPROM_READ(bilinear_start);               // 2 ints

Carregando…
Cancelar
Salvar