|
@@ -46,11 +46,11 @@
|
46
|
46
|
#define PRIME_LENGTH 10.0
|
47
|
47
|
#define OOZE_AMOUNT 0.3
|
48
|
48
|
|
49
|
|
-#define SIZE_OF_INTERSECTION_CIRCLES 5
|
50
|
|
-#define SIZE_OF_CROSSHAIRS 3
|
|
49
|
+#define INTERSECTION_CIRCLE_RADIUS 5
|
|
50
|
+#define CROSSHAIRS_SIZE 3
|
51
|
51
|
|
52
|
|
-#if SIZE_OF_CROSSHAIRS >= SIZE_OF_INTERSECTION_CIRCLES
|
53
|
|
- #error "SIZE_OF_CROSSHAIRS must be less than SIZE_OF_INTERSECTION_CIRCLES."
|
|
52
|
+#if CROSSHAIRS_SIZE >= INTERSECTION_CIRCLE_RADIUS
|
|
53
|
+ #error "CROSSHAIRS_SIZE must be less than INTERSECTION_CIRCLE_RADIUS."
|
54
|
54
|
#endif
|
55
|
55
|
|
56
|
56
|
#define G26_OK false
|
|
@@ -305,7 +305,7 @@ void print_line_from_here_to_there(const float &sx, const float &sy, const float
|
305
|
305
|
|
306
|
306
|
// If the end point of the line is closer to the nozzle, flip the direction,
|
307
|
307
|
// moving from the end to the start. On very small lines the optimization isn't worth it.
|
308
|
|
- if (dist_end < dist_start && (SIZE_OF_INTERSECTION_CIRCLES) < FABS(line_length))
|
|
308
|
+ if (dist_end < dist_start && (INTERSECTION_CIRCLE_RADIUS) < FABS(line_length))
|
309
|
309
|
return print_line_from_here_to_there(ex, ey, ez, sx, sy, sz);
|
310
|
310
|
|
311
|
311
|
// Decide whether to retract & bump
|
|
@@ -345,8 +345,8 @@ inline bool look_for_lines_to_connect() {
|
345
|
345
|
// We found two circles that need a horizontal line to connect them
|
346
|
346
|
// Print it!
|
347
|
347
|
//
|
348
|
|
- sx = _GET_MESH_X( i ) + (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // right edge
|
349
|
|
- ex = _GET_MESH_X(i + 1) - (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // left edge
|
|
348
|
+ sx = _GET_MESH_X( i ) + (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // right edge
|
|
349
|
+ ex = _GET_MESH_X(i + 1) - (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // left edge
|
350
|
350
|
|
351
|
351
|
sx = constrain(sx, X_MIN_POS + 1, X_MAX_POS - 1);
|
352
|
352
|
sy = ey = constrain(_GET_MESH_Y(j), Y_MIN_POS + 1, Y_MAX_POS - 1);
|
|
@@ -378,8 +378,8 @@ inline bool look_for_lines_to_connect() {
|
378
|
378
|
// We found two circles that need a vertical line to connect them
|
379
|
379
|
// Print it!
|
380
|
380
|
//
|
381
|
|
- sy = _GET_MESH_Y( j ) + (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // top edge
|
382
|
|
- ey = _GET_MESH_Y(j + 1) - (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // bottom edge
|
|
381
|
+ sy = _GET_MESH_Y( j ) + (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // top edge
|
|
382
|
+ ey = _GET_MESH_Y(j + 1) - (INTERSECTION_CIRCLE_RADIUS - (CROSSHAIRS_SIZE)); // bottom edge
|
383
|
383
|
|
384
|
384
|
sx = ex = constrain(_GET_MESH_X(i), X_MIN_POS + 1, X_MAX_POS - 1);
|
385
|
385
|
sy = constrain(sy, Y_MIN_POS + 1, Y_MAX_POS - 1);
|
|
@@ -551,9 +551,6 @@ float valid_trig_angle(float d) {
|
551
|
551
|
*/
|
552
|
552
|
void GcodeSuite::G26() {
|
553
|
553
|
SERIAL_ECHOLNPGM("G26 command started. Waiting for heater(s).");
|
554
|
|
- float tmp, start_angle, end_angle;
|
555
|
|
- int i, xi, yi;
|
556
|
|
- mesh_index_pair location;
|
557
|
554
|
|
558
|
555
|
// Don't allow Mesh Validation without homing first,
|
559
|
556
|
// or if the parameter parsing did not go OK, abort
|
|
@@ -726,17 +723,18 @@ void GcodeSuite::G26() {
|
726
|
723
|
//debug_current_and_destination(PSTR("Starting G26 Mesh Validation Pattern."));
|
727
|
724
|
|
728
|
725
|
/**
|
729
|
|
- * Declare and generate a sin() & cos() table to be used during the circle drawing. This will lighten
|
730
|
|
- * the CPU load and make the arc drawing faster and more smooth
|
|
726
|
+ * Pre-generate radius offset values at 30 degree intervals to reduce CPU load.
|
|
727
|
+ * All angles are offset by 15 degrees to allow for a smaller table.
|
731
|
728
|
*/
|
732
|
|
- float sin_table[360 / 30 + 1], cos_table[360 / 30 + 1];
|
733
|
|
- for (i = 0; i <= 360 / 30; i++) {
|
734
|
|
- cos_table[i] = SIZE_OF_INTERSECTION_CIRCLES * cos(RADIANS(valid_trig_angle(i * 30.0)));
|
735
|
|
- sin_table[i] = SIZE_OF_INTERSECTION_CIRCLES * sin(RADIANS(valid_trig_angle(i * 30.0)));
|
736
|
|
- }
|
|
729
|
+ #define A_CNT ((360 / 30) / 2)
|
|
730
|
+ #define _COS(A) (trig_table[((N + A_CNT * 8) % A_CNT)] * (A >= A_CNT ? -1 : 1))
|
|
731
|
+ #define _SIN(A) (-_COS((A + A_CNT / 2) % (A_CNT * 2)))
|
|
732
|
+ float trig_table[A_CNT];
|
|
733
|
+ for (uint8_t i = 0; i < A_CNT; i++)
|
|
734
|
+ trig_table[i] = INTERSECTION_CIRCLE_RADIUS * cos(RADIANS(i * 30 + 15));
|
737
|
735
|
|
738
|
736
|
do {
|
739
|
|
- location = g26_continue_with_closest
|
|
737
|
+ const mesh_index_pair location = g26_continue_with_closest
|
740
|
738
|
? find_closest_circle_to_print(current_position[X_AXIS], current_position[Y_AXIS])
|
741
|
739
|
: find_closest_circle_to_print(g26_x_pos, g26_y_pos); // Find the closest Mesh Intersection to where we are now.
|
742
|
740
|
|
|
@@ -745,12 +743,29 @@ void GcodeSuite::G26() {
|
745
|
743
|
circle_y = _GET_MESH_Y(location.y_index);
|
746
|
744
|
|
747
|
745
|
// If this mesh location is outside the printable_radius, skip it.
|
748
|
|
-
|
749
|
746
|
if (!position_is_reachable(circle_x, circle_y)) continue;
|
750
|
747
|
|
751
|
|
- xi = location.x_index; // Just to shrink the next few lines and make them easier to understand
|
752
|
|
- yi = location.y_index;
|
753
|
|
-
|
|
748
|
+ // Determine where to start and end the circle,
|
|
749
|
+ // which is always drawn counter-clockwise.
|
|
750
|
+ const uint8_t xi = location.x_index, yi = location.y_index;
|
|
751
|
+ const bool f = yi == 0, r = xi == GRID_MAX_POINTS_X - 1, b = yi == GRID_MAX_POINTS_Y - 1;
|
|
752
|
+ int8_t start_ind = -2, end_ind = 10; // Assume a full circle (from 4:30 to 4:30)
|
|
753
|
+ if (xi == 0) { // Left edge? Just right half.
|
|
754
|
+ start_ind = f ? 0 : -3; // 05:30 (02:30 for front-left)
|
|
755
|
+ end_ind = b ? -1 : 2; // 12:30 (03:30 for back-left)
|
|
756
|
+ }
|
|
757
|
+ else if (r) { // Right edge? Just left half.
|
|
758
|
+ start_ind = f ? 5 : 3; // 11:30 (09:30 for front-right)
|
|
759
|
+ end_ind = b ? 6 : 8; // 06:30 (08:30 for back-right)
|
|
760
|
+ }
|
|
761
|
+ else if (f) { // Front edge? Just back half.
|
|
762
|
+ start_ind = 0; // 02:30
|
|
763
|
+ end_ind = 5; // 09:30
|
|
764
|
+ }
|
|
765
|
+ else if (b) { // Back edge? Just front half.
|
|
766
|
+ start_ind = 6; // 08:30
|
|
767
|
+ end_ind = 11; // 03:30
|
|
768
|
+ }
|
754
|
769
|
if (g26_debug_flag) {
|
755
|
770
|
SERIAL_ECHOPAIR(" Doing circle at: (xi=", xi);
|
756
|
771
|
SERIAL_ECHOPAIR(", yi=", yi);
|
|
@@ -758,47 +773,17 @@ void GcodeSuite::G26() {
|
758
|
773
|
SERIAL_EOL();
|
759
|
774
|
}
|
760
|
775
|
|
761
|
|
- start_angle = 0.0; // assume it is going to be a full circle
|
762
|
|
- end_angle = 360.0;
|
763
|
|
- if (xi == 0) { // Check for bottom edge
|
764
|
|
- start_angle = -90.0;
|
765
|
|
- end_angle = 90.0;
|
766
|
|
- if (yi == 0) // it is an edge, check for the two left corners
|
767
|
|
- start_angle = 0.0;
|
768
|
|
- else if (yi == GRID_MAX_POINTS_Y - 1)
|
769
|
|
- end_angle = 0.0;
|
770
|
|
- }
|
771
|
|
- else if (xi == GRID_MAX_POINTS_X - 1) { // Check for top edge
|
772
|
|
- start_angle = 90.0;
|
773
|
|
- end_angle = 270.0;
|
774
|
|
- if (yi == 0) // it is an edge, check for the two right corners
|
775
|
|
- end_angle = 180.0;
|
776
|
|
- else if (yi == GRID_MAX_POINTS_Y - 1)
|
777
|
|
- start_angle = 180.0;
|
778
|
|
- }
|
779
|
|
- else if (yi == 0) {
|
780
|
|
- start_angle = 0.0; // only do the top side of the cirlce
|
781
|
|
- end_angle = 180.0;
|
782
|
|
- }
|
783
|
|
- else if (yi == GRID_MAX_POINTS_Y - 1) {
|
784
|
|
- start_angle = 180.0; // only do the bottom side of the cirlce
|
785
|
|
- end_angle = 360.0;
|
786
|
|
- }
|
787
|
|
-
|
788
|
|
- for (tmp = start_angle; tmp < end_angle - 0.1; tmp += 30.0) {
|
|
776
|
+ for (int8_t ind = start_ind; ind < end_ind; ind++) {
|
789
|
777
|
|
790
|
778
|
#if ENABLED(NEWPANEL)
|
791
|
|
- if (user_canceled()) goto LEAVE; // Check if the user wants to stop the Mesh Validation
|
|
779
|
+ if (user_canceled()) goto LEAVE; // Check if the user wants to stop the Mesh Validation
|
792
|
780
|
#endif
|
793
|
781
|
|
794
|
|
- int tmp_div_30 = tmp / 30.0;
|
795
|
|
- if (tmp_div_30 < 0) tmp_div_30 += 360 / 30;
|
796
|
|
- if (tmp_div_30 > 11) tmp_div_30 -= 360 / 30;
|
|
782
|
+ float rx = circle_x + _COS(ind), // For speed, these are now a lookup table entry
|
|
783
|
+ ry = circle_y + _SIN(ind),
|
|
784
|
+ xe = circle_x + _COS(ind + 1),
|
|
785
|
+ ye = circle_y + _SIN(ind + 1);
|
797
|
786
|
|
798
|
|
- float rx = circle_x + cos_table[tmp_div_30], // for speed, these are now a lookup table entry
|
799
|
|
- ry = circle_y + sin_table[tmp_div_30],
|
800
|
|
- xe = circle_x + cos_table[tmp_div_30 + 1],
|
801
|
|
- ye = circle_y + sin_table[tmp_div_30 + 1];
|
802
|
787
|
#if IS_KINEMATIC
|
803
|
788
|
// Check to make sure this segment is entirely on the bed, skip if not.
|
804
|
789
|
if (!position_is_reachable(rx, ry) || !position_is_reachable(xe, ye)) continue;
|