// Get the Z adjustment for non-linear bed leveling float bilinear_z_offset(const float raw[XYZ]) { static float z1, d2, z3, d4, L, D, ratio_x, ratio_y, last_x = -999.999, last_y = -999.999; // Whole units for the grid line indices. Constrained within bounds. static int8_t gridx, gridy, nextx, nexty, last_gridx = -99, last_gridy = -99; // XY relative to the probed area const float rx = raw[X_AXIS] - bilinear_start[X_AXIS], ry = raw[Y_AXIS] - bilinear_start[Y_AXIS]; #if ENABLED(EXTRAPOLATE_BEYOND_GRID) // Keep using the last grid box #define FAR_EDGE_OR_BOX 2 #else // Just use the grid far edge #define FAR_EDGE_OR_BOX 1 #endif if (last_x != rx) { last_x = rx; ratio_x = rx * ABL_BG_FACTOR(X_AXIS); const float gx = constrain(FLOOR(ratio_x), 0, ABL_BG_POINTS_X - (FAR_EDGE_OR_BOX)); ratio_x -= gx; // Subtract whole to get the ratio within the grid box #if DISABLED(EXTRAPOLATE_BEYOND_GRID) // Beyond the grid maintain height at grid edges NOLESS(ratio_x, 0); // Never < 0.0. (> 1.0 is ok when nextx==gridx.) #endif gridx = gx; nextx = MIN(gridx + 1, ABL_BG_POINTS_X - 1); } if (last_y != ry || last_gridx != gridx) { if (last_y != ry) { last_y = ry; ratio_y = ry * ABL_BG_FACTOR(Y_AXIS); const float gy = constrain(FLOOR(ratio_y), 0, ABL_BG_POINTS_Y - (FAR_EDGE_OR_BOX)); ratio_y -= gy; #if DISABLED(EXTRAPOLATE_BEYOND_GRID) // Beyond the grid maintain height at grid edges NOLESS(ratio_y, 0); // Never < 0.0. (> 1.0 is ok when nexty==gridy.) #endif gridy = gy; nexty = MIN(gridy + 1, ABL_BG_POINTS_Y - 1); } if (last_gridx != gridx || last_gridy != gridy) { last_gridx = gridx; last_gridy = gridy; // Z at the box corners z1 = ABL_BG_GRID(gridx, gridy); // left-front d2 = ABL_BG_GRID(gridx, nexty) - z1; // left-back (delta) z3 = ABL_BG_GRID(nextx, gridy); // right-front d4 = ABL_BG_GRID(nextx, nexty) - z3; // right-back (delta) } // Bilinear interpolate. Needed since ry or gridx has changed. L = z1 + d2 * ratio_y; // Linear interp. LF -> LB const float R = z3 + d4 * ratio_y; // Linear interp. RF -> RB D = R - L; } const float offset = L + ratio_x * D; // the offset almost always changes /* static float last_offset = 0; if (ABS(last_offset - offset) > 0.2) { SERIAL_ECHOPGM("Sudden Shift at "); SERIAL_ECHOPAIR("x=", rx); SERIAL_ECHOPAIR(" / ", bilinear_grid_spacing[X_AXIS]); SERIAL_ECHOLNPAIR(" -> gridx=", gridx); SERIAL_ECHOPAIR(" y=", ry); SERIAL_ECHOPAIR(" / ", bilinear_grid_spacing[Y_AXIS]); SERIAL_ECHOLNPAIR(" -> gridy=", gridy); SERIAL_ECHOPAIR(" ratio_x=", ratio_x); SERIAL_ECHOLNPAIR(" ratio_y=", ratio_y); SERIAL_ECHOPAIR(" z1=", z1); SERIAL_ECHOPAIR(" z2=", z2); SERIAL_ECHOPAIR(" z3=", z3); SERIAL_ECHOLNPAIR(" z4=", z4); SERIAL_ECHOPAIR(" L=", L); SERIAL_ECHOPAIR(" R=", R); SERIAL_ECHOLNPAIR(" offset=", offset); } last_offset = offset; //*/ return offset; }
// Get the Z adjustment for non-linear bed leveling float Bed_level::bilinear_z_offset(const float logical[XYZ]) { static float z1, d2, z3, d4, L, D, ratio_x, ratio_y, last_x = -999.999, last_y = -999.999; // Whole units for the grid line indices. Constrained within bounds. static int8_t gridx, gridy, nextx, nexty, last_gridx = -99, last_gridy = -99; // XY relative to the probed area const float x = RAW_X_POSITION(logical[X_AXIS]) - bilinear_start[X_AXIS], y = RAW_Y_POSITION(logical[Y_AXIS]) - bilinear_start[Y_AXIS]; if (last_x != x) { last_x = x; ratio_x = x * ABL_BG_FACTOR(X_AXIS); const float gx = constrain(floor(ratio_x), 0, ABL_BG_POINTS_X - 1); ratio_x -= gx; // Subtract whole to get the ratio within the grid box NOLESS(ratio_x, 0); // Never < 0.0. (> 1.0 is ok when nextx==gridx.) gridx = gx; nextx = min(gridx + 1, ABL_BG_POINTS_X - 1); } if (last_y != y || last_gridx != gridx) { if (last_y != y) { last_y = y; ratio_y = y * ABL_BG_FACTOR(Y_AXIS); const float gy = constrain(floor(ratio_y), 0, ABL_BG_POINTS_Y - 1); ratio_y -= gy; NOLESS(ratio_y, 0); gridy = gy; nexty = min(gridy + 1, ABL_BG_POINTS_Y - 1); } if (last_gridx != gridx || last_gridy != gridy) { last_gridx = gridx; last_gridy = gridy; // Z at the box corners z1 = ABL_BG_GRID(gridx, gridy); // left-front d2 = ABL_BG_GRID(gridx, nexty) - z1; // left-back (delta) z3 = ABL_BG_GRID(nextx, gridy); // right-front d4 = ABL_BG_GRID(nextx, nexty) - z3; // right-back (delta) } // Bilinear interpolate. Needed since y or gridx has changed. L = z1 + d2 * ratio_y; // Linear interp. LF -> LB const float R = z3 + d4 * ratio_y; // Linear interp. RF -> RB D = R - L; } const float offset = L + ratio_x * D; // the offset almost always changes /* static float last_offset = 0; if (FABS(last_offset - offset) > 0.2) { SERIAL_MSG("Sudden Shift at "); SERIAL_MV("x=", x); SERIAL_MV(" / ", ABL_BG_SPACING(X_AXIS)); SERIAL_EMV(" -> gridx=", gridx); SERIAL_MV(" y=", y); SERIAL_MV(" / ", ABL_BG_SPACING(Y_AXIS)); SERIAL_EMV(" -> gridy=", gridy); SERIAL_MV(" ratio_x=", ratio_x); SERIAL_EMV(" ratio_y=", ratio_y); SERIAL_MV(" z1=", z1); SERIAL_MV(" d2=", d2); SERIAL_MV(" z3=", z3); SERIAL_EMV(" d4=", d4); SERIAL_MV(" L=", L); SERIAL_MV(" R=", R); SERIAL_EMV(" offset=", offset); } last_offset = offset; */ return offset; }