Browse Source

One or the other?

Scott Lahteine 7 years ago
parent
commit
5cce532a29
2 changed files with 318 additions and 321 deletions
  1. 18
    15
      Marlin/ubl.h
  2. 300
    306
      Marlin/ubl_motion.cpp

+ 18
- 15
Marlin/ubl.h View File

@@ -326,21 +326,24 @@
326 326
         return i < GRID_MAX_POINTS_Y ? pgm_read_float(&_mesh_index_to_ypos[i]) : MESH_MIN_Y + i * (MESH_Y_DIST);
327 327
       }
328 328
 
329
-      static bool prepare_segmented_line_to(const float (&rtarget)[XYZE], const float &feedrate);
330
-      static void line_to_destination_cartesian(const float &fr, uint8_t e);
331
-
332
-    #define _CMPZ(a,b) (z_values[a][b] == z_values[a][b+1])
333
-    #define CMPZ(a) (_CMPZ(a, 0) && _CMPZ(a, 1))
334
-    #define ZZER(a) (z_values[a][0] == 0)
335
-
336
-    FORCE_INLINE bool mesh_is_valid() {
337
-      return !(
338
-        (    CMPZ(0) && CMPZ(1) && CMPZ(2) // adjacent z values all equal?
339
-          && ZZER(0) && ZZER(1) && ZZER(2) // all zero at the edge?
340
-        )
341
-        || isnan(z_values[0][0])
342
-      );
343
-    }
329
+      #if UBL_SEGMENTED
330
+        static bool prepare_segmented_line_to(const float (&rtarget)[XYZE], const float &feedrate);
331
+      #else
332
+        static void line_to_destination_cartesian(const float &fr, const uint8_t e);
333
+      #endif
334
+
335
+      #define _CMPZ(a,b) (z_values[a][b] == z_values[a][b+1])
336
+      #define CMPZ(a) (_CMPZ(a, 0) && _CMPZ(a, 1))
337
+      #define ZZER(a) (z_values[a][0] == 0)
338
+
339
+      FORCE_INLINE bool mesh_is_valid() {
340
+        return !(
341
+          (    CMPZ(0) && CMPZ(1) && CMPZ(2) // adjacent z values all equal?
342
+            && ZZER(0) && ZZER(1) && ZZER(2) // all zero at the edge?
343
+          )
344
+          || isnan(z_values[0][0])
345
+        );
346
+      }
344 347
   }; // class unified_bed_leveling
345 348
 
346 349
   extern unified_bed_leveling ubl;

+ 300
- 306
Marlin/ubl_motion.cpp View File

@@ -36,193 +36,322 @@
36 36
     extern void set_current_from_destination();
37 37
   #endif
38 38
 
39
-  void unified_bed_leveling::line_to_destination_cartesian(const float &feed_rate, uint8_t extruder) {
40
-    /**
41
-     * Much of the nozzle movement will be within the same cell. So we will do as little computation
42
-     * as possible to determine if this is the case. If this move is within the same cell, we will
43
-     * just do the required Z-Height correction, call the Planner's buffer_line() routine, and leave
44
-     */
45
-    const float start[XYZE] = {
46
-                  current_position[X_AXIS],
47
-                  current_position[Y_AXIS],
48
-                  current_position[Z_AXIS],
49
-                  current_position[E_AXIS]
50
-                },
51
-                end[XYZE] = {
52
-                  destination[X_AXIS],
53
-                  destination[Y_AXIS],
54
-                  destination[Z_AXIS],
55
-                  destination[E_AXIS]
56
-                };
57
-
58
-    const int cell_start_xi = get_cell_index_x(start[X_AXIS]),
59
-              cell_start_yi = get_cell_index_y(start[Y_AXIS]),
60
-              cell_dest_xi  = get_cell_index_x(end[X_AXIS]),
61
-              cell_dest_yi  = get_cell_index_y(end[Y_AXIS]);
62
-
63
-    if (g26_debug_flag) {
64
-      SERIAL_ECHOPAIR(" ubl.line_to_destination(xe=", end[X_AXIS]);
65
-      SERIAL_ECHOPAIR(", ye=", end[Y_AXIS]);
66
-      SERIAL_ECHOPAIR(", ze=", end[Z_AXIS]);
67
-      SERIAL_ECHOPAIR(", ee=", end[E_AXIS]);
68
-      SERIAL_CHAR(')');
69
-      SERIAL_EOL();
70
-      debug_current_and_destination(PSTR("Start of ubl.line_to_destination()"));
71
-    }
39
+  #if !UBL_SEGMENTED
72 40
 
73
-    if (cell_start_xi == cell_dest_xi && cell_start_yi == cell_dest_yi) { // if the whole move is within the same cell,
41
+    void unified_bed_leveling::line_to_destination_cartesian(const float &feed_rate, const uint8_t extruder) {
74 42
       /**
75
-       * we don't need to break up the move
76
-       *
77
-       * If we are moving off the print bed, we are going to allow the move at this level.
78
-       * But we detect it and isolate it. For now, we just pass along the request.
43
+       * Much of the nozzle movement will be within the same cell. So we will do as little computation
44
+       * as possible to determine if this is the case. If this move is within the same cell, we will
45
+       * just do the required Z-Height correction, call the Planner's buffer_line() routine, and leave
79 46
        */
47
+      const float start[XYZE] = {
48
+                    current_position[X_AXIS],
49
+                    current_position[Y_AXIS],
50
+                    current_position[Z_AXIS],
51
+                    current_position[E_AXIS]
52
+                  },
53
+                  end[XYZE] = {
54
+                    destination[X_AXIS],
55
+                    destination[Y_AXIS],
56
+                    destination[Z_AXIS],
57
+                    destination[E_AXIS]
58
+                  };
59
+
60
+      const int cell_start_xi = get_cell_index_x(start[X_AXIS]),
61
+                cell_start_yi = get_cell_index_y(start[Y_AXIS]),
62
+                cell_dest_xi  = get_cell_index_x(end[X_AXIS]),
63
+                cell_dest_yi  = get_cell_index_y(end[Y_AXIS]);
64
+
65
+      if (g26_debug_flag) {
66
+        SERIAL_ECHOPAIR(" ubl.line_to_destination(xe=", end[X_AXIS]);
67
+        SERIAL_ECHOPAIR(", ye=", end[Y_AXIS]);
68
+        SERIAL_ECHOPAIR(", ze=", end[Z_AXIS]);
69
+        SERIAL_ECHOPAIR(", ee=", end[E_AXIS]);
70
+        SERIAL_CHAR(')');
71
+        SERIAL_EOL();
72
+        debug_current_and_destination(PSTR("Start of ubl.line_to_destination()"));
73
+      }
80 74
 
81
-      if (!WITHIN(cell_dest_xi, 0, GRID_MAX_POINTS_X - 1) || !WITHIN(cell_dest_yi, 0, GRID_MAX_POINTS_Y - 1)) {
75
+      if (cell_start_xi == cell_dest_xi && cell_start_yi == cell_dest_yi) { // if the whole move is within the same cell,
76
+        /**
77
+         * we don't need to break up the move
78
+         *
79
+         * If we are moving off the print bed, we are going to allow the move at this level.
80
+         * But we detect it and isolate it. For now, we just pass along the request.
81
+         */
82 82
 
83
-        // Note: There is no Z Correction in this case. We are off the grid and don't know what
84
-        // a reasonable correction would be.
83
+        if (!WITHIN(cell_dest_xi, 0, GRID_MAX_POINTS_X - 1) || !WITHIN(cell_dest_yi, 0, GRID_MAX_POINTS_Y - 1)) {
85 84
 
86
-        planner.buffer_segment(end[X_AXIS], end[Y_AXIS], end[Z_AXIS], end[E_AXIS], feed_rate, extruder);
87
-        set_current_from_destination();
85
+          // Note: There is no Z Correction in this case. We are off the grid and don't know what
86
+          // a reasonable correction would be.
87
+
88
+          planner.buffer_segment(end[X_AXIS], end[Y_AXIS], end[Z_AXIS], end[E_AXIS], feed_rate, extruder);
89
+          set_current_from_destination();
90
+
91
+          if (g26_debug_flag)
92
+            debug_current_and_destination(PSTR("out of bounds in ubl.line_to_destination()"));
93
+
94
+          return;
95
+        }
96
+
97
+        FINAL_MOVE:
98
+
99
+        /**
100
+         * Optimize some floating point operations here. We could call float get_z_correction(float x0, float y0) to
101
+         * generate the correction for us. But we can lighten the load on the CPU by doing a modified version of the function.
102
+         * We are going to only calculate the amount we are from the first mesh line towards the second mesh line once.
103
+         * We will use this fraction in both of the original two Z Height calculations for the bi-linear interpolation. And,
104
+         * instead of doing a generic divide of the distance, we know the distance is MESH_X_DIST so we can use the preprocessor
105
+         * to create a 1-over number for us. That will allow us to do a floating point multiply instead of a floating point divide.
106
+         */
107
+
108
+        const float xratio = (end[X_AXIS] - mesh_index_to_xpos(cell_dest_xi)) * (1.0 / (MESH_X_DIST));
109
+
110
+        float z1 = z_values[cell_dest_xi    ][cell_dest_yi    ] + xratio *
111
+                  (z_values[cell_dest_xi + 1][cell_dest_yi    ] - z_values[cell_dest_xi][cell_dest_yi    ]),
112
+              z2 = z_values[cell_dest_xi    ][cell_dest_yi + 1] + xratio *
113
+                  (z_values[cell_dest_xi + 1][cell_dest_yi + 1] - z_values[cell_dest_xi][cell_dest_yi + 1]);
114
+
115
+        if (cell_dest_xi >= GRID_MAX_POINTS_X - 1) z1 = z2 = 0.0;
116
+
117
+        // we are done with the fractional X distance into the cell. Now with the two Z-Heights we have calculated, we
118
+        // are going to apply the Y-Distance into the cell to interpolate the final Z correction.
119
+
120
+        const float yratio = (end[Y_AXIS] - mesh_index_to_ypos(cell_dest_yi)) * (1.0 / (MESH_Y_DIST));
121
+        float z0 = cell_dest_yi < GRID_MAX_POINTS_Y - 1 ? (z1 + (z2 - z1) * yratio) * planner.fade_scaling_factor_for_z(end[Z_AXIS]) : 0.0;
122
+
123
+        /**
124
+         * If part of the Mesh is undefined, it will show up as NAN
125
+         * in z_values[][] and propagate through the
126
+         * calculations. If our correction is NAN, we throw it out
127
+         * because part of the Mesh is undefined and we don't have the
128
+         * information we need to complete the height correction.
129
+         */
130
+        if (isnan(z0)) z0 = 0.0;
131
+
132
+        planner.buffer_segment(end[X_AXIS], end[Y_AXIS], end[Z_AXIS] + z0, end[E_AXIS], feed_rate, extruder);
88 133
 
89 134
         if (g26_debug_flag)
90
-          debug_current_and_destination(PSTR("out of bounds in ubl.line_to_destination()"));
135
+          debug_current_and_destination(PSTR("FINAL_MOVE in ubl.line_to_destination()"));
91 136
 
137
+        set_current_from_destination();
92 138
         return;
93 139
       }
94 140
 
95
-      FINAL_MOVE:
141
+      /**
142
+       * If we get here, we are processing a move that crosses at least one Mesh Line. We will check
143
+       * for the simple case of just crossing X or just crossing Y Mesh Lines after we get all the details
144
+       * of the move figured out. We can process the easy case of just crossing an X or Y Mesh Line with less
145
+       * computation and in fact most lines are of this nature. We will check for that in the following
146
+       * blocks of code:
147
+       */
148
+
149
+      const float dx = end[X_AXIS] - start[X_AXIS],
150
+                  dy = end[Y_AXIS] - start[Y_AXIS];
151
+
152
+      const int left_flag = dx < 0.0 ? 1 : 0,
153
+                down_flag = dy < 0.0 ? 1 : 0;
154
+
155
+      const float adx = left_flag ? -dx : dx,
156
+                  ady = down_flag ? -dy : dy;
157
+
158
+      const int dxi = cell_start_xi == cell_dest_xi ? 0 : left_flag ? -1 : 1,
159
+                dyi = cell_start_yi == cell_dest_yi ? 0 : down_flag ? -1 : 1;
96 160
 
97 161
       /**
98
-       * Optimize some floating point operations here. We could call float get_z_correction(float x0, float y0) to
99
-       * generate the correction for us. But we can lighten the load on the CPU by doing a modified version of the function.
100
-       * We are going to only calculate the amount we are from the first mesh line towards the second mesh line once.
101
-       * We will use this fraction in both of the original two Z Height calculations for the bi-linear interpolation. And,
102
-       * instead of doing a generic divide of the distance, we know the distance is MESH_X_DIST so we can use the preprocessor
103
-       * to create a 1-over number for us. That will allow us to do a floating point multiply instead of a floating point divide.
162
+       * Compute the scaling factor for the extruder for each partial move.
163
+       * We need to watch out for zero length moves because it will cause us to
164
+       * have an infinate scaling factor. We are stuck doing a floating point
165
+       * divide to get our scaling factor, but after that, we just multiply by this
166
+       * number. We also pick our scaling factor based on whether the X or Y
167
+       * component is larger. We use the biggest of the two to preserve precision.
104 168
        */
105 169
 
106
-      const float xratio = (end[X_AXIS] - mesh_index_to_xpos(cell_dest_xi)) * (1.0 / (MESH_X_DIST));
170
+      const bool use_x_dist = adx > ady;
107 171
 
108
-      float z1 = z_values[cell_dest_xi    ][cell_dest_yi    ] + xratio *
109
-                (z_values[cell_dest_xi + 1][cell_dest_yi    ] - z_values[cell_dest_xi][cell_dest_yi    ]),
110
-            z2 = z_values[cell_dest_xi    ][cell_dest_yi + 1] + xratio *
111
-                (z_values[cell_dest_xi + 1][cell_dest_yi + 1] - z_values[cell_dest_xi][cell_dest_yi + 1]);
172
+      float on_axis_distance = use_x_dist ? dx : dy,
173
+            e_position = end[E_AXIS] - start[E_AXIS],
174
+            z_position = end[Z_AXIS] - start[Z_AXIS];
112 175
 
113
-      if (cell_dest_xi >= GRID_MAX_POINTS_X - 1) z1 = z2 = 0.0;
176
+      const float e_normalized_dist = e_position / on_axis_distance,
177
+                  z_normalized_dist = z_position / on_axis_distance;
114 178
 
115
-      // we are done with the fractional X distance into the cell. Now with the two Z-Heights we have calculated, we
116
-      // are going to apply the Y-Distance into the cell to interpolate the final Z correction.
179
+      int current_xi = cell_start_xi,
180
+          current_yi = cell_start_yi;
117 181
 
118
-      const float yratio = (end[Y_AXIS] - mesh_index_to_ypos(cell_dest_yi)) * (1.0 / (MESH_Y_DIST));
119
-      float z0 = cell_dest_yi < GRID_MAX_POINTS_Y - 1 ? (z1 + (z2 - z1) * yratio) * planner.fade_scaling_factor_for_z(end[Z_AXIS]) : 0.0;
182
+      const float m = dy / dx,
183
+                  c = start[Y_AXIS] - m * start[X_AXIS];
120 184
 
185
+      const bool inf_normalized_flag = (isinf(e_normalized_dist) != 0),
186
+                 inf_m_flag = (isinf(m) != 0);
121 187
       /**
122
-       * If part of the Mesh is undefined, it will show up as NAN
123
-       * in z_values[][] and propagate through the
124
-       * calculations. If our correction is NAN, we throw it out
125
-       * because part of the Mesh is undefined and we don't have the
126
-       * information we need to complete the height correction.
188
+       * This block handles vertical lines. These are lines that stay within the same
189
+       * X Cell column. They do not need to be perfectly vertical. They just can
190
+       * not cross into another X Cell column.
127 191
        */
128
-      if (isnan(z0)) z0 = 0.0;
129
-
130
-      planner.buffer_segment(end[X_AXIS], end[Y_AXIS], end[Z_AXIS] + z0, end[E_AXIS], feed_rate, extruder);
192
+      if (dxi == 0) {       // Check for a vertical line
193
+        current_yi += down_flag;  // Line is heading down, we just want to go to the bottom
194
+        while (current_yi != cell_dest_yi + down_flag) {
195
+          current_yi += dyi;
196
+          const float next_mesh_line_y = mesh_index_to_ypos(current_yi);
197
+
198
+          /**
199
+           * if the slope of the line is infinite, we won't do the calculations
200
+           * else, we know the next X is the same so we can recover and continue!
201
+           * Calculate X at the next Y mesh line
202
+           */
203
+          const float rx = inf_m_flag ? start[X_AXIS] : (next_mesh_line_y - c) / m;
204
+
205
+          float z0 = z_correction_for_x_on_horizontal_mesh_line(rx, current_xi, current_yi)
206
+                     * planner.fade_scaling_factor_for_z(end[Z_AXIS]);
207
+
208
+          /**
209
+           * If part of the Mesh is undefined, it will show up as NAN
210
+           * in z_values[][] and propagate through the
211
+           * calculations. If our correction is NAN, we throw it out
212
+           * because part of the Mesh is undefined and we don't have the
213
+           * information we need to complete the height correction.
214
+           */
215
+          if (isnan(z0)) z0 = 0.0;
216
+
217
+          const float ry = mesh_index_to_ypos(current_yi);
218
+
219
+          /**
220
+           * Without this check, it is possible for the algorithm to generate a zero length move in the case
221
+           * where the line is heading down and it is starting right on a Mesh Line boundary. For how often that
222
+           * happens, it might be best to remove the check and always 'schedule' the move because
223
+           * the planner.buffer_segment() routine will filter it if that happens.
224
+           */
225
+          if (ry != start[Y_AXIS]) {
226
+            if (!inf_normalized_flag) {
227
+              on_axis_distance = use_x_dist ? rx - start[X_AXIS] : ry - start[Y_AXIS];
228
+              e_position = start[E_AXIS] + on_axis_distance * e_normalized_dist;
229
+              z_position = start[Z_AXIS] + on_axis_distance * z_normalized_dist;
230
+            }
231
+            else {
232
+              e_position = end[E_AXIS];
233
+              z_position = end[Z_AXIS];
234
+            }
131 235
 
132
-      if (g26_debug_flag)
133
-        debug_current_and_destination(PSTR("FINAL_MOVE in ubl.line_to_destination()"));
236
+            planner.buffer_segment(rx, ry, z_position + z0, e_position, feed_rate, extruder);
237
+          } //else printf("FIRST MOVE PRUNED  ");
238
+        }
134 239
 
135
-      set_current_from_destination();
136
-      return;
137
-    }
240
+        if (g26_debug_flag)
241
+          debug_current_and_destination(PSTR("vertical move done in ubl.line_to_destination()"));
138 242
 
139
-    /**
140
-     * If we get here, we are processing a move that crosses at least one Mesh Line. We will check
141
-     * for the simple case of just crossing X or just crossing Y Mesh Lines after we get all the details
142
-     * of the move figured out. We can process the easy case of just crossing an X or Y Mesh Line with less
143
-     * computation and in fact most lines are of this nature. We will check for that in the following
144
-     * blocks of code:
145
-     */
243
+        //
244
+        // Check if we are at the final destination. Usually, we won't be, but if it is on a Y Mesh Line, we are done.
245
+        //
246
+        if (current_position[X_AXIS] != end[X_AXIS] || current_position[Y_AXIS] != end[Y_AXIS])
247
+          goto FINAL_MOVE;
146 248
 
147
-    const float dx = end[X_AXIS] - start[X_AXIS],
148
-                dy = end[Y_AXIS] - start[Y_AXIS];
249
+        set_current_from_destination();
250
+        return;
251
+      }
149 252
 
150
-    const int left_flag = dx < 0.0 ? 1 : 0,
151
-              down_flag = dy < 0.0 ? 1 : 0;
253
+      /**
254
+       *
255
+       * This block handles horizontal lines. These are lines that stay within the same
256
+       * Y Cell row. They do not need to be perfectly horizontal. They just can
257
+       * not cross into another Y Cell row.
258
+       *
259
+       */
152 260
 
153
-    const float adx = left_flag ? -dx : dx,
154
-                ady = down_flag ? -dy : dy;
261
+      if (dyi == 0) {             // Check for a horizontal line
262
+        current_xi += left_flag;  // Line is heading left, we just want to go to the left
263
+                                  // edge of this cell for the first move.
264
+        while (current_xi != cell_dest_xi + left_flag) {
265
+          current_xi += dxi;
266
+          const float next_mesh_line_x = mesh_index_to_xpos(current_xi),
267
+                      ry = m * next_mesh_line_x + c;   // Calculate Y at the next X mesh line
268
+
269
+          float z0 = z_correction_for_y_on_vertical_mesh_line(ry, current_xi, current_yi)
270
+                     * planner.fade_scaling_factor_for_z(end[Z_AXIS]);
271
+
272
+          /**
273
+           * If part of the Mesh is undefined, it will show up as NAN
274
+           * in z_values[][] and propagate through the
275
+           * calculations. If our correction is NAN, we throw it out
276
+           * because part of the Mesh is undefined and we don't have the
277
+           * information we need to complete the height correction.
278
+           */
279
+          if (isnan(z0)) z0 = 0.0;
280
+
281
+          const float rx = mesh_index_to_xpos(current_xi);
282
+
283
+          /**
284
+           * Without this check, it is possible for the algorithm to generate a zero length move in the case
285
+           * where the line is heading left and it is starting right on a Mesh Line boundary. For how often
286
+           * that happens, it might be best to remove the check and always 'schedule' the move because
287
+           * the planner.buffer_segment() routine will filter it if that happens.
288
+           */
289
+          if (rx != start[X_AXIS]) {
290
+            if (!inf_normalized_flag) {
291
+              on_axis_distance = use_x_dist ? rx - start[X_AXIS] : ry - start[Y_AXIS];
292
+              e_position = start[E_AXIS] + on_axis_distance * e_normalized_dist;  // is based on X or Y because this is a horizontal move
293
+              z_position = start[Z_AXIS] + on_axis_distance * z_normalized_dist;
294
+            }
295
+            else {
296
+              e_position = end[E_AXIS];
297
+              z_position = end[Z_AXIS];
298
+            }
155 299
 
156
-    const int dxi = cell_start_xi == cell_dest_xi ? 0 : left_flag ? -1 : 1,
157
-              dyi = cell_start_yi == cell_dest_yi ? 0 : down_flag ? -1 : 1;
300
+            planner.buffer_segment(rx, ry, z_position + z0, e_position, feed_rate, extruder);
301
+          } //else printf("FIRST MOVE PRUNED  ");
302
+        }
158 303
 
159
-    /**
160
-     * Compute the scaling factor for the extruder for each partial move.
161
-     * We need to watch out for zero length moves because it will cause us to
162
-     * have an infinate scaling factor. We are stuck doing a floating point
163
-     * divide to get our scaling factor, but after that, we just multiply by this
164
-     * number. We also pick our scaling factor based on whether the X or Y
165
-     * component is larger. We use the biggest of the two to preserve precision.
166
-     */
304
+        if (g26_debug_flag)
305
+          debug_current_and_destination(PSTR("horizontal move done in ubl.line_to_destination()"));
167 306
 
168
-    const bool use_x_dist = adx > ady;
307
+        if (current_position[X_AXIS] != end[X_AXIS] || current_position[Y_AXIS] != end[Y_AXIS])
308
+          goto FINAL_MOVE;
169 309
 
170
-    float on_axis_distance = use_x_dist ? dx : dy,
171
-          e_position = end[E_AXIS] - start[E_AXIS],
172
-          z_position = end[Z_AXIS] - start[Z_AXIS];
310
+        set_current_from_destination();
311
+        return;
312
+      }
173 313
 
174
-    const float e_normalized_dist = e_position / on_axis_distance,
175
-                z_normalized_dist = z_position / on_axis_distance;
314
+      /**
315
+       *
316
+       * This block handles the generic case of a line crossing both X and Y Mesh lines.
317
+       *
318
+       */
176 319
 
177
-    int current_xi = cell_start_xi,
178
-        current_yi = cell_start_yi;
320
+      int xi_cnt = cell_start_xi - cell_dest_xi,
321
+          yi_cnt = cell_start_yi - cell_dest_yi;
179 322
 
180
-    const float m = dy / dx,
181
-                c = start[Y_AXIS] - m * start[X_AXIS];
323
+      if (xi_cnt < 0) xi_cnt = -xi_cnt;
324
+      if (yi_cnt < 0) yi_cnt = -yi_cnt;
182 325
 
183
-    const bool inf_normalized_flag = (isinf(e_normalized_dist) != 0),
184
-               inf_m_flag = (isinf(m) != 0);
185
-    /**
186
-     * This block handles vertical lines. These are lines that stay within the same
187
-     * X Cell column. They do not need to be perfectly vertical. They just can
188
-     * not cross into another X Cell column.
189
-     */
190
-    if (dxi == 0) {       // Check for a vertical line
191
-      current_yi += down_flag;  // Line is heading down, we just want to go to the bottom
192
-      while (current_yi != cell_dest_yi + down_flag) {
193
-        current_yi += dyi;
194
-        const float next_mesh_line_y = mesh_index_to_ypos(current_yi);
326
+      current_xi += left_flag;
327
+      current_yi += down_flag;
195 328
 
196
-        /**
197
-         * if the slope of the line is infinite, we won't do the calculations
198
-         * else, we know the next X is the same so we can recover and continue!
199
-         * Calculate X at the next Y mesh line
200
-         */
201
-        const float rx = inf_m_flag ? start[X_AXIS] : (next_mesh_line_y - c) / m;
329
+      while (xi_cnt > 0 || yi_cnt > 0) {
202 330
 
203
-        float z0 = z_correction_for_x_on_horizontal_mesh_line(rx, current_xi, current_yi)
204
-                   * planner.fade_scaling_factor_for_z(end[Z_AXIS]);
331
+        const float next_mesh_line_x = mesh_index_to_xpos(current_xi + dxi),
332
+                    next_mesh_line_y = mesh_index_to_ypos(current_yi + dyi),
333
+                    ry = m * next_mesh_line_x + c,   // Calculate Y at the next X mesh line
334
+                    rx = (next_mesh_line_y - c) / m; // Calculate X at the next Y mesh line
335
+                                                     // (No need to worry about m being zero.
336
+                                                     //  If that was the case, it was already detected
337
+                                                     //  as a vertical line move above.)
205 338
 
206
-        /**
207
-         * If part of the Mesh is undefined, it will show up as NAN
208
-         * in z_values[][] and propagate through the
209
-         * calculations. If our correction is NAN, we throw it out
210
-         * because part of the Mesh is undefined and we don't have the
211
-         * information we need to complete the height correction.
212
-         */
213
-        if (isnan(z0)) z0 = 0.0;
339
+        if (left_flag == (rx > next_mesh_line_x)) { // Check if we hit the Y line first
340
+          // Yes!  Crossing a Y Mesh Line next
341
+          float z0 = z_correction_for_x_on_horizontal_mesh_line(rx, current_xi - left_flag, current_yi + dyi)
342
+                     * planner.fade_scaling_factor_for_z(end[Z_AXIS]);
214 343
 
215
-        const float ry = mesh_index_to_ypos(current_yi);
344
+          /**
345
+           * If part of the Mesh is undefined, it will show up as NAN
346
+           * in z_values[][] and propagate through the
347
+           * calculations. If our correction is NAN, we throw it out
348
+           * because part of the Mesh is undefined and we don't have the
349
+           * information we need to complete the height correction.
350
+           */
351
+          if (isnan(z0)) z0 = 0.0;
216 352
 
217
-        /**
218
-         * Without this check, it is possible for the algorithm to generate a zero length move in the case
219
-         * where the line is heading down and it is starting right on a Mesh Line boundary. For how often that
220
-         * happens, it might be best to remove the check and always 'schedule' the move because
221
-         * the planner.buffer_segment() routine will filter it if that happens.
222
-         */
223
-        if (ry != start[Y_AXIS]) {
224 353
           if (!inf_normalized_flag) {
225
-            on_axis_distance = use_x_dist ? rx - start[X_AXIS] : ry - start[Y_AXIS];
354
+            on_axis_distance = use_x_dist ? rx - start[X_AXIS] : next_mesh_line_y - start[Y_AXIS];
226 355
             e_position = start[E_AXIS] + on_axis_distance * e_normalized_dist;
227 356
             z_position = start[Z_AXIS] + on_axis_distance * z_normalized_dist;
228 357
           }
@@ -230,64 +359,27 @@
230 359
             e_position = end[E_AXIS];
231 360
             z_position = end[Z_AXIS];
232 361
           }
362
+          planner.buffer_segment(rx, next_mesh_line_y, z_position + z0, e_position, feed_rate, extruder);
363
+          current_yi += dyi;
364
+          yi_cnt--;
365
+        }
366
+        else {
367
+          // Yes!  Crossing a X Mesh Line next
368
+          float z0 = z_correction_for_y_on_vertical_mesh_line(ry, current_xi + dxi, current_yi - down_flag)
369
+                     * planner.fade_scaling_factor_for_z(end[Z_AXIS]);
370
+
371
+          /**
372
+           * If part of the Mesh is undefined, it will show up as NAN
373
+           * in z_values[][] and propagate through the
374
+           * calculations. If our correction is NAN, we throw it out
375
+           * because part of the Mesh is undefined and we don't have the
376
+           * information we need to complete the height correction.
377
+           */
378
+          if (isnan(z0)) z0 = 0.0;
233 379
 
234
-          planner.buffer_segment(rx, ry, z_position + z0, e_position, feed_rate, extruder);
235
-        } //else printf("FIRST MOVE PRUNED  ");
236
-      }
237
-
238
-      if (g26_debug_flag)
239
-        debug_current_and_destination(PSTR("vertical move done in ubl.line_to_destination()"));
240
-
241
-      //
242
-      // Check if we are at the final destination. Usually, we won't be, but if it is on a Y Mesh Line, we are done.
243
-      //
244
-      if (current_position[X_AXIS] != end[X_AXIS] || current_position[Y_AXIS] != end[Y_AXIS])
245
-        goto FINAL_MOVE;
246
-
247
-      set_current_from_destination();
248
-      return;
249
-    }
250
-
251
-    /**
252
-     *
253
-     * This block handles horizontal lines. These are lines that stay within the same
254
-     * Y Cell row. They do not need to be perfectly horizontal. They just can
255
-     * not cross into another Y Cell row.
256
-     *
257
-     */
258
-
259
-    if (dyi == 0) {             // Check for a horizontal line
260
-      current_xi += left_flag;  // Line is heading left, we just want to go to the left
261
-                                // edge of this cell for the first move.
262
-      while (current_xi != cell_dest_xi + left_flag) {
263
-        current_xi += dxi;
264
-        const float next_mesh_line_x = mesh_index_to_xpos(current_xi),
265
-                    ry = m * next_mesh_line_x + c;   // Calculate Y at the next X mesh line
266
-
267
-        float z0 = z_correction_for_y_on_vertical_mesh_line(ry, current_xi, current_yi)
268
-                   * planner.fade_scaling_factor_for_z(end[Z_AXIS]);
269
-
270
-        /**
271
-         * If part of the Mesh is undefined, it will show up as NAN
272
-         * in z_values[][] and propagate through the
273
-         * calculations. If our correction is NAN, we throw it out
274
-         * because part of the Mesh is undefined and we don't have the
275
-         * information we need to complete the height correction.
276
-         */
277
-        if (isnan(z0)) z0 = 0.0;
278
-
279
-        const float rx = mesh_index_to_xpos(current_xi);
280
-
281
-        /**
282
-         * Without this check, it is possible for the algorithm to generate a zero length move in the case
283
-         * where the line is heading left and it is starting right on a Mesh Line boundary. For how often
284
-         * that happens, it might be best to remove the check and always 'schedule' the move because
285
-         * the planner.buffer_segment() routine will filter it if that happens.
286
-         */
287
-        if (rx != start[X_AXIS]) {
288 380
           if (!inf_normalized_flag) {
289
-            on_axis_distance = use_x_dist ? rx - start[X_AXIS] : ry - start[Y_AXIS];
290
-            e_position = start[E_AXIS] + on_axis_distance * e_normalized_dist;  // is based on X or Y because this is a horizontal move
381
+            on_axis_distance = use_x_dist ? next_mesh_line_x - start[X_AXIS] : ry - start[Y_AXIS];
382
+            e_position = start[E_AXIS] + on_axis_distance * e_normalized_dist;
291 383
             z_position = start[Z_AXIS] + on_axis_distance * z_normalized_dist;
292 384
           }
293 385
           else {
@@ -295,122 +387,24 @@
295 387
             z_position = end[Z_AXIS];
296 388
           }
297 389
 
298
-          planner.buffer_segment(rx, ry, z_position + z0, e_position, feed_rate, extruder);
299
-        } //else printf("FIRST MOVE PRUNED  ");
390
+          planner.buffer_segment(next_mesh_line_x, ry, z_position + z0, e_position, feed_rate, extruder);
391
+          current_xi += dxi;
392
+          xi_cnt--;
393
+        }
394
+
395
+        if (xi_cnt < 0 || yi_cnt < 0) break; // we've gone too far, so exit the loop and move on to FINAL_MOVE
300 396
       }
301 397
 
302 398
       if (g26_debug_flag)
303
-        debug_current_and_destination(PSTR("horizontal move done in ubl.line_to_destination()"));
399
+        debug_current_and_destination(PSTR("generic move done in ubl.line_to_destination()"));
304 400
 
305 401
       if (current_position[X_AXIS] != end[X_AXIS] || current_position[Y_AXIS] != end[Y_AXIS])
306 402
         goto FINAL_MOVE;
307 403
 
308 404
       set_current_from_destination();
309
-      return;
310 405
     }
311 406
 
312
-    /**
313
-     *
314
-     * This block handles the generic case of a line crossing both X and Y Mesh lines.
315
-     *
316
-     */
317
-
318
-    int xi_cnt = cell_start_xi - cell_dest_xi,
319
-        yi_cnt = cell_start_yi - cell_dest_yi;
320
-
321
-    if (xi_cnt < 0) xi_cnt = -xi_cnt;
322
-    if (yi_cnt < 0) yi_cnt = -yi_cnt;
323
-
324
-    current_xi += left_flag;
325
-    current_yi += down_flag;
326
-
327
-    while (xi_cnt > 0 || yi_cnt > 0) {
328
-
329
-      const float next_mesh_line_x = mesh_index_to_xpos(current_xi + dxi),
330
-                  next_mesh_line_y = mesh_index_to_ypos(current_yi + dyi),
331
-                  ry = m * next_mesh_line_x + c,   // Calculate Y at the next X mesh line
332
-                  rx = (next_mesh_line_y - c) / m; // Calculate X at the next Y mesh line
333
-                                                   // (No need to worry about m being zero.
334
-                                                   //  If that was the case, it was already detected
335
-                                                   //  as a vertical line move above.)
336
-
337
-      if (left_flag == (rx > next_mesh_line_x)) { // Check if we hit the Y line first
338
-        // Yes!  Crossing a Y Mesh Line next
339
-        float z0 = z_correction_for_x_on_horizontal_mesh_line(rx, current_xi - left_flag, current_yi + dyi)
340
-                   * planner.fade_scaling_factor_for_z(end[Z_AXIS]);
341
-
342
-        /**
343
-         * If part of the Mesh is undefined, it will show up as NAN
344
-         * in z_values[][] and propagate through the
345
-         * calculations. If our correction is NAN, we throw it out
346
-         * because part of the Mesh is undefined and we don't have the
347
-         * information we need to complete the height correction.
348
-         */
349
-        if (isnan(z0)) z0 = 0.0;
350
-
351
-        if (!inf_normalized_flag) {
352
-          on_axis_distance = use_x_dist ? rx - start[X_AXIS] : next_mesh_line_y - start[Y_AXIS];
353
-          e_position = start[E_AXIS] + on_axis_distance * e_normalized_dist;
354
-          z_position = start[Z_AXIS] + on_axis_distance * z_normalized_dist;
355
-        }
356
-        else {
357
-          e_position = end[E_AXIS];
358
-          z_position = end[Z_AXIS];
359
-        }
360
-        planner.buffer_segment(rx, next_mesh_line_y, z_position + z0, e_position, feed_rate, extruder);
361
-        current_yi += dyi;
362
-        yi_cnt--;
363
-      }
364
-      else {
365
-        // Yes!  Crossing a X Mesh Line next
366
-        float z0 = z_correction_for_y_on_vertical_mesh_line(ry, current_xi + dxi, current_yi - down_flag)
367
-                   * planner.fade_scaling_factor_for_z(end[Z_AXIS]);
368
-
369
-        /**
370
-         * If part of the Mesh is undefined, it will show up as NAN
371
-         * in z_values[][] and propagate through the
372
-         * calculations. If our correction is NAN, we throw it out
373
-         * because part of the Mesh is undefined and we don't have the
374
-         * information we need to complete the height correction.
375
-         */
376
-        if (isnan(z0)) z0 = 0.0;
377
-
378
-        if (!inf_normalized_flag) {
379
-          on_axis_distance = use_x_dist ? next_mesh_line_x - start[X_AXIS] : ry - start[Y_AXIS];
380
-          e_position = start[E_AXIS] + on_axis_distance * e_normalized_dist;
381
-          z_position = start[Z_AXIS] + on_axis_distance * z_normalized_dist;
382
-        }
383
-        else {
384
-          e_position = end[E_AXIS];
385
-          z_position = end[Z_AXIS];
386
-        }
387
-
388
-        planner.buffer_segment(next_mesh_line_x, ry, z_position + z0, e_position, feed_rate, extruder);
389
-        current_xi += dxi;
390
-        xi_cnt--;
391
-      }
392
-
393
-      if (xi_cnt < 0 || yi_cnt < 0) break; // we've gone too far, so exit the loop and move on to FINAL_MOVE
394
-    }
395
-
396
-    if (g26_debug_flag)
397
-      debug_current_and_destination(PSTR("generic move done in ubl.line_to_destination()"));
398
-
399
-    if (current_position[X_AXIS] != end[X_AXIS] || current_position[Y_AXIS] != end[Y_AXIS])
400
-      goto FINAL_MOVE;
401
-
402
-    set_current_from_destination();
403
-  }
404
-
405
-  #if UBL_SEGMENTED
406
-
407
-    // macro to inline copy exactly 4 floats, don't rely on sizeof operator
408
-    #define COPY_XYZE( target, source ) { \
409
-                target[X_AXIS] = source[X_AXIS]; \
410
-                target[Y_AXIS] = source[Y_AXIS]; \
411
-                target[Z_AXIS] = source[Z_AXIS]; \
412
-                target[E_AXIS] = source[E_AXIS]; \
413
-            }
407
+  #else // UBL_SEGMENTED
414 408
 
415 409
     #if IS_SCARA // scale the feed rate from mm/s to degrees/s
416 410
       static float scara_feed_factor, scara_oldA, scara_oldB;

Loading…
Cancel
Save