Merge pull request #6248 from thinkyhead/rc_marlin_scad_mesh
Add hidden option to output Bilinear grids in JSON
This commit is contained in:
commit
034e912c85
3
.gitattributes
vendored
3
.gitattributes
vendored
@ -3,11 +3,12 @@
|
|||||||
|
|
||||||
# Files with Unix line endings
|
# Files with Unix line endings
|
||||||
*.c text eol=lf
|
*.c text eol=lf
|
||||||
# *.cpp text eol=lf
|
*.cpp text eol=lf
|
||||||
*.h text eol=lf
|
*.h text eol=lf
|
||||||
*.ino text eol=lf
|
*.ino text eol=lf
|
||||||
*.py text eol=lf
|
*.py text eol=lf
|
||||||
*.sh text eol=lf
|
*.sh text eol=lf
|
||||||
|
*.scad text eol=lf
|
||||||
|
|
||||||
# Files with native line endings
|
# Files with native line endings
|
||||||
# *.sln text
|
# *.sln text
|
||||||
|
@ -399,11 +399,11 @@ int feedrate_percentage = 100, saved_feedrate_percentage,
|
|||||||
|
|
||||||
bool axis_relative_modes[] = AXIS_RELATIVE_MODES,
|
bool axis_relative_modes[] = AXIS_RELATIVE_MODES,
|
||||||
volumetric_enabled =
|
volumetric_enabled =
|
||||||
#if ENABLED(VOLUMETRIC_DEFAULT_ON)
|
#if ENABLED(VOLUMETRIC_DEFAULT_ON)
|
||||||
true
|
true
|
||||||
#else
|
#else
|
||||||
false
|
false
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
float filament_size[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(DEFAULT_NOMINAL_FILAMENT_DIA),
|
float filament_size[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(DEFAULT_NOMINAL_FILAMENT_DIA),
|
||||||
volumetric_multiplier[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(1.0);
|
volumetric_multiplier[EXTRUDERS] = ARRAY_BY_EXTRUDERS1(1.0);
|
||||||
@ -588,7 +588,6 @@ static uint8_t target_extruder;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||||
#define UNPROBED 9999.0f
|
|
||||||
int bilinear_grid_spacing[2], bilinear_start[2];
|
int bilinear_grid_spacing[2], bilinear_start[2];
|
||||||
float bed_level_grid[ABL_GRID_MAX_POINTS_X][ABL_GRID_MAX_POINTS_Y];
|
float bed_level_grid[ABL_GRID_MAX_POINTS_X][ABL_GRID_MAX_POINTS_Y];
|
||||||
#endif
|
#endif
|
||||||
@ -2344,7 +2343,7 @@ static void clean_up_after_endstop_or_probe_move() {
|
|||||||
bilinear_grid_spacing[X_AXIS] = bilinear_grid_spacing[Y_AXIS] = 0;
|
bilinear_grid_spacing[X_AXIS] = bilinear_grid_spacing[Y_AXIS] = 0;
|
||||||
for (uint8_t x = 0; x < ABL_GRID_MAX_POINTS_X; x++)
|
for (uint8_t x = 0; x < ABL_GRID_MAX_POINTS_X; x++)
|
||||||
for (uint8_t y = 0; y < ABL_GRID_MAX_POINTS_Y; y++)
|
for (uint8_t y = 0; y < ABL_GRID_MAX_POINTS_Y; y++)
|
||||||
bed_level_grid[x][y] = UNPROBED;
|
bed_level_grid[x][y] = NAN;
|
||||||
#elif ENABLED(AUTO_BED_LEVELING_UBL)
|
#elif ENABLED(AUTO_BED_LEVELING_UBL)
|
||||||
ubl.reset();
|
ubl.reset();
|
||||||
#endif
|
#endif
|
||||||
@ -2353,6 +2352,76 @@ static void clean_up_after_endstop_or_probe_move() {
|
|||||||
|
|
||||||
#endif // PLANNER_LEVELING
|
#endif // PLANNER_LEVELING
|
||||||
|
|
||||||
|
#if ENABLED(AUTO_BED_LEVELING_BILINEAR) || ENABLED(MESH_BED_LEVELING)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Enable if you prefer your output in JSON format
|
||||||
|
// suitable for SCAD or JavaScript mesh visualizers.
|
||||||
|
//
|
||||||
|
// Visualize meshes in OpenSCAD using the included script.
|
||||||
|
//
|
||||||
|
// buildroot/shared/scripts/MarlinMesh.scad
|
||||||
|
//
|
||||||
|
//#define SCAD_MESH_OUTPUT
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print calibration results for plotting or manual frame adjustment.
|
||||||
|
*/
|
||||||
|
static void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, float (*fn)(const uint8_t, const uint8_t)) {
|
||||||
|
#ifndef SCAD_MESH_OUTPUT
|
||||||
|
for (uint8_t x = 0; x < sx; x++) {
|
||||||
|
for (uint8_t i = 0; i < precision + 2 + (x < 10 ? 1 : 0); i++)
|
||||||
|
SERIAL_PROTOCOLCHAR(' ');
|
||||||
|
SERIAL_PROTOCOL((int)x);
|
||||||
|
}
|
||||||
|
SERIAL_EOL;
|
||||||
|
#endif
|
||||||
|
#ifdef SCAD_MESH_OUTPUT
|
||||||
|
SERIAL_PROTOCOLLNPGM("measured_z = ["); // open 2D array
|
||||||
|
#endif
|
||||||
|
for (uint8_t y = 0; y < sy; y++) {
|
||||||
|
#ifdef SCAD_MESH_OUTPUT
|
||||||
|
SERIAL_PROTOCOLLNPGM(" ["); // open sub-array
|
||||||
|
#else
|
||||||
|
if (y < 10) SERIAL_PROTOCOLCHAR(' ');
|
||||||
|
SERIAL_PROTOCOL((int)y);
|
||||||
|
#endif
|
||||||
|
for (uint8_t x = 0; x < sx; x++) {
|
||||||
|
SERIAL_PROTOCOLCHAR(' ');
|
||||||
|
const float offset = fn(x, y);
|
||||||
|
if (offset != NAN) {
|
||||||
|
if (offset >= 0) SERIAL_PROTOCOLCHAR('+');
|
||||||
|
SERIAL_PROTOCOL_F(offset, precision);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
#ifdef SCAD_MESH_OUTPUT
|
||||||
|
for (uint8_t i = 3; i < precision + 3; i++)
|
||||||
|
SERIAL_PROTOCOLCHAR(' ');
|
||||||
|
SERIAL_PROTOCOLPGM("NAN");
|
||||||
|
#else
|
||||||
|
for (uint8_t i = 0; i < precision + 3; i++)
|
||||||
|
SERIAL_PROTOCOLCHAR(i ? '=' : ' ');
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#ifdef SCAD_MESH_OUTPUT
|
||||||
|
if (x < sx - 1) SERIAL_PROTOCOLCHAR(',');
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#ifdef SCAD_MESH_OUTPUT
|
||||||
|
SERIAL_PROTOCOLCHAR(' ');
|
||||||
|
SERIAL_PROTOCOLCHAR(']'); // close sub-array
|
||||||
|
if (y < sy - 1) SERIAL_PROTOCOLCHAR(',');
|
||||||
|
#endif
|
||||||
|
SERIAL_EOL;
|
||||||
|
}
|
||||||
|
#ifdef SCAD_MESH_OUTPUT
|
||||||
|
SERIAL_PROTOCOLPGM("\n];"); // close 2D array
|
||||||
|
#endif
|
||||||
|
SERIAL_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2372,7 +2441,7 @@ static void clean_up_after_endstop_or_probe_move() {
|
|||||||
SERIAL_CHAR(']');
|
SERIAL_CHAR(']');
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (bed_level_grid[x][y] != UNPROBED) {
|
if (bed_level_grid[x][y] != NAN) {
|
||||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||||
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM(" (done)");
|
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM(" (done)");
|
||||||
#endif
|
#endif
|
||||||
@ -2386,9 +2455,9 @@ static void clean_up_after_endstop_or_probe_move() {
|
|||||||
c1 = bed_level_grid[x + xdir][y + ydir], c2 = bed_level_grid[x + xdir * 2][y + ydir * 2];
|
c1 = bed_level_grid[x + xdir][y + ydir], c2 = bed_level_grid[x + xdir * 2][y + ydir * 2];
|
||||||
|
|
||||||
// Treat far unprobed points as zero, near as equal to far
|
// Treat far unprobed points as zero, near as equal to far
|
||||||
if (a2 == UNPROBED) a2 = 0.0; if (a1 == UNPROBED) a1 = a2;
|
if (a2 == NAN) a2 = 0.0; if (a1 == NAN) a1 = a2;
|
||||||
if (b2 == UNPROBED) b2 = 0.0; if (b1 == UNPROBED) b1 = b2;
|
if (b2 == NAN) b2 = 0.0; if (b1 == NAN) b1 = b2;
|
||||||
if (c2 == UNPROBED) c2 = 0.0; if (c1 == UNPROBED) c1 = c2;
|
if (c2 == NAN) c2 = 0.0; if (c1 == NAN) c1 = c2;
|
||||||
|
|
||||||
const float a = 2 * a1 - a2, b = 2 * b1 - b2, c = 2 * c1 - c2;
|
const float a = 2 * a1 - a2, b = 2 * b1 - b2, c = 2 * c1 - c2;
|
||||||
|
|
||||||
@ -2453,39 +2522,10 @@ static void clean_up_after_endstop_or_probe_move() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Print calibration results for plotting or manual frame adjustment.
|
|
||||||
*/
|
|
||||||
static void print_2d_array(const uint8_t sx, const uint8_t sy, const uint8_t precision, float (*fn)(const uint8_t, const uint8_t)) {
|
|
||||||
for (uint8_t x = 0; x < sx; x++) {
|
|
||||||
for (uint8_t i = 0; i < precision + 2 + (x < 10 ? 1 : 0); i++)
|
|
||||||
SERIAL_PROTOCOLCHAR(' ');
|
|
||||||
SERIAL_PROTOCOL((int)x);
|
|
||||||
}
|
|
||||||
SERIAL_EOL;
|
|
||||||
for (uint8_t y = 0; y < sy; y++) {
|
|
||||||
if (y < 10) SERIAL_PROTOCOLCHAR(' ');
|
|
||||||
SERIAL_PROTOCOL((int)y);
|
|
||||||
for (uint8_t x = 0; x < sx; x++) {
|
|
||||||
SERIAL_PROTOCOLCHAR(' ');
|
|
||||||
float offset = fn(x, y);
|
|
||||||
if (offset != UNPROBED) {
|
|
||||||
if (offset >= 0) SERIAL_PROTOCOLCHAR('+');
|
|
||||||
SERIAL_PROTOCOL_F(offset, precision);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
for (uint8_t i = 0; i < precision + 3; i++)
|
|
||||||
SERIAL_PROTOCOLCHAR(i ? '=' : ' ');
|
|
||||||
}
|
|
||||||
SERIAL_EOL;
|
|
||||||
}
|
|
||||||
SERIAL_EOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_bilinear_leveling_grid() {
|
static void print_bilinear_leveling_grid() {
|
||||||
SERIAL_ECHOLNPGM("Bilinear Leveling Grid:");
|
SERIAL_ECHOLNPGM("Bilinear Leveling Grid:");
|
||||||
print_2d_array(ABL_GRID_MAX_POINTS_X, ABL_GRID_MAX_POINTS_Y, 2,
|
print_2d_array(ABL_GRID_MAX_POINTS_X, ABL_GRID_MAX_POINTS_Y, 3,
|
||||||
[](const uint8_t x, const uint8_t y) { return bed_level_grid[x][y]; }
|
[](const uint8_t ix, const uint8_t iy) { return bed_level_grid[ix][iy]; }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2501,7 +2541,7 @@ static void clean_up_after_endstop_or_probe_move() {
|
|||||||
static void bed_level_virt_print() {
|
static void bed_level_virt_print() {
|
||||||
SERIAL_ECHOLNPGM("Subdivided with CATMULL ROM Leveling Grid:");
|
SERIAL_ECHOLNPGM("Subdivided with CATMULL ROM Leveling Grid:");
|
||||||
print_2d_array(ABL_GRID_POINTS_VIRT_X, ABL_GRID_POINTS_VIRT_Y, 5,
|
print_2d_array(ABL_GRID_POINTS_VIRT_X, ABL_GRID_POINTS_VIRT_Y, 5,
|
||||||
[](const uint8_t x, const uint8_t y) { return bed_level_grid_virt[x][y]; }
|
[](const uint8_t ix, const uint8_t iy) { return bed_level_grid_virt[ix][iy]; }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3715,13 +3755,9 @@ inline void gcode_G28() {
|
|||||||
SERIAL_PROTOCOLLNPGM("Num X,Y: " STRINGIFY(MESH_NUM_X_POINTS) "," STRINGIFY(MESH_NUM_Y_POINTS));
|
SERIAL_PROTOCOLLNPGM("Num X,Y: " STRINGIFY(MESH_NUM_X_POINTS) "," STRINGIFY(MESH_NUM_Y_POINTS));
|
||||||
SERIAL_PROTOCOLPGM("Z offset: "); SERIAL_PROTOCOL_F(mbl.z_offset, 5);
|
SERIAL_PROTOCOLPGM("Z offset: "); SERIAL_PROTOCOL_F(mbl.z_offset, 5);
|
||||||
SERIAL_PROTOCOLLNPGM("\nMeasured points:");
|
SERIAL_PROTOCOLLNPGM("\nMeasured points:");
|
||||||
for (uint8_t py = 0; py < MESH_NUM_Y_POINTS; py++) {
|
print_2d_array(MESH_NUM_X_POINTS, MESH_NUM_Y_POINTS, 5,
|
||||||
for (uint8_t px = 0; px < MESH_NUM_X_POINTS; px++) {
|
[](const uint8_t ix, const uint8_t iy) { return mbl.z_values[ix][iy]; }
|
||||||
SERIAL_PROTOCOLPGM(" ");
|
);
|
||||||
SERIAL_PROTOCOL_F(mbl.z_values[py][px], 5);
|
|
||||||
}
|
|
||||||
SERIAL_EOL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -6440,6 +6476,13 @@ inline void gcode_M115() {
|
|||||||
SERIAL_PROTOCOLLNPGM("Cap:Z_PROBE:0");
|
SERIAL_PROTOCOLLNPGM("Cap:Z_PROBE:0");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// MESH_REPORT (M420 V)
|
||||||
|
#if PLANNER_LEVELING
|
||||||
|
SERIAL_PROTOCOLLNPGM("Cap:LEVELING_DATA:1");
|
||||||
|
#else
|
||||||
|
SERIAL_PROTOCOLLNPGM("Cap:LEVELING_DATA:0");
|
||||||
|
#endif
|
||||||
|
|
||||||
// SOFTWARE_POWER (G30)
|
// SOFTWARE_POWER (G30)
|
||||||
#if HAS_POWER_SWITCH
|
#if HAS_POWER_SWITCH
|
||||||
SERIAL_PROTOCOLLNPGM("Cap:SOFTWARE_POWER:1");
|
SERIAL_PROTOCOLLNPGM("Cap:SOFTWARE_POWER:1");
|
||||||
@ -7479,9 +7522,9 @@ void quickstop_stepper() {
|
|||||||
* Z[height] Sets the Z fade height (0 or none to disable)
|
* Z[height] Sets the Z fade height (0 or none to disable)
|
||||||
* V[bool] Verbose - Print the leveling grid
|
* V[bool] Verbose - Print the leveling grid
|
||||||
*
|
*
|
||||||
* With AUTO_BED_LEVELING_UBL only:
|
* With AUTO_BED_LEVELING_UBL only:
|
||||||
*
|
*
|
||||||
* L[index] Load UBL mesh from index (0 is default)
|
* L[index] Load UBL mesh from index (0 is default)
|
||||||
*/
|
*/
|
||||||
inline void gcode_M420() {
|
inline void gcode_M420() {
|
||||||
|
|
||||||
@ -7498,9 +7541,6 @@ void quickstop_stepper() {
|
|||||||
ubl.load_mesh(storage_slot);
|
ubl.load_mesh(storage_slot);
|
||||||
if (storage_slot != ubl.state.eeprom_storage_slot) ubl.store_state();
|
if (storage_slot != ubl.state.eeprom_storage_slot) ubl.store_state();
|
||||||
ubl.state.eeprom_storage_slot = storage_slot;
|
ubl.state.eeprom_storage_slot = storage_slot;
|
||||||
ubl.display_map(0); // Right now, we only support one type of map
|
|
||||||
SERIAL_ECHOLNPAIR("UBL_MESH_VALID = ", UBL_MESH_VALID);
|
|
||||||
SERIAL_ECHOLNPAIR("eeprom_storage_slot = ", ubl.state.eeprom_storage_slot);
|
|
||||||
}
|
}
|
||||||
#endif // AUTO_BED_LEVELING_UBL
|
#endif // AUTO_BED_LEVELING_UBL
|
||||||
|
|
||||||
@ -7515,10 +7555,6 @@ void quickstop_stepper() {
|
|||||||
bed_level_virt_print();
|
bed_level_virt_print();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#elif ENABLED(AUTO_BED_LEVELING_UBL)
|
|
||||||
ubl.display_map(0); // Currently only supports one map type
|
|
||||||
SERIAL_ECHOLNPAIR("UBL_MESH_VALID = ", UBL_MESH_VALID);
|
|
||||||
SERIAL_ECHOLNPAIR("eeprom_storage_slot = ", ubl.state.eeprom_storage_slot);
|
|
||||||
#elif ENABLED(MESH_BED_LEVELING)
|
#elif ENABLED(MESH_BED_LEVELING)
|
||||||
if (mbl.has_mesh()) {
|
if (mbl.has_mesh()) {
|
||||||
SERIAL_ECHOLNPGM("Mesh Bed Level data:");
|
SERIAL_ECHOLNPGM("Mesh Bed Level data:");
|
||||||
@ -7527,6 +7563,15 @@ void quickstop_stepper() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
||||||
|
// L to load a mesh from the EEPROM
|
||||||
|
if (code_seen('L') || code_seen('V')) {
|
||||||
|
ubl.display_map(0); // Currently only supports one map type
|
||||||
|
SERIAL_ECHOLNPAIR("UBL_MESH_VALID = ", UBL_MESH_VALID);
|
||||||
|
SERIAL_ECHOLNPAIR("eeprom_storage_slot = ", ubl.state.eeprom_storage_slot);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool to_enable = false;
|
bool to_enable = false;
|
||||||
if (code_seen('S')) {
|
if (code_seen('S')) {
|
||||||
to_enable = code_value_bool();
|
to_enable = code_value_bool();
|
||||||
|
256
buildroot/share/scripts/MarlinMesh.scad
Normal file
256
buildroot/share/scripts/MarlinMesh.scad
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
/**************************************\
|
||||||
|
* *
|
||||||
|
* OpenSCAD Mesh Display *
|
||||||
|
* by Thinkyhead - April 2017 *
|
||||||
|
* *
|
||||||
|
* Copy the grid output from Marlin, *
|
||||||
|
* paste below as shown, and use *
|
||||||
|
* OpenSCAD to see a visualization *
|
||||||
|
* of your mesh. *
|
||||||
|
* *
|
||||||
|
\**************************************/
|
||||||
|
|
||||||
|
//$t = 0.15; // comment out during animation
|
||||||
|
|
||||||
|
//
|
||||||
|
// Mesh info and points
|
||||||
|
//
|
||||||
|
|
||||||
|
mesh_width = 200; // X Size in mm of the probed area
|
||||||
|
mesh_height = 200; // Y Size...
|
||||||
|
zprobe_offset = 0; // Added to the points
|
||||||
|
NAN = 0; // Z to use for un-measured points
|
||||||
|
|
||||||
|
measured_z = [
|
||||||
|
[ -1.20, -1.13, -1.09, -1.03, -1.19 ],
|
||||||
|
[ -1.16, -1.25, -1.27, -1.25, -1.08 ],
|
||||||
|
[ -1.13, -1.26, -1.39, -1.31, -1.18 ],
|
||||||
|
[ -1.09, -1.20, -1.26, -1.21, -1.18 ],
|
||||||
|
[ -1.13, -0.99, -1.03, -1.06, -1.32 ]
|
||||||
|
];
|
||||||
|
|
||||||
|
//
|
||||||
|
// Geometry
|
||||||
|
//
|
||||||
|
|
||||||
|
max_z_scale = 100; // Scale at Time 0.5
|
||||||
|
min_z_scale = 10; // Scale at Time 0.0 and 1.0
|
||||||
|
thickness = 0.5; // thickness of the mesh triangles
|
||||||
|
tesselation = 1; // levels of tesselation from 0-2
|
||||||
|
alternation = 2; // direction change modulus (try it)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Appearance
|
||||||
|
//
|
||||||
|
|
||||||
|
show_plane = true;
|
||||||
|
show_labels = true;
|
||||||
|
arrow_length = 5;
|
||||||
|
|
||||||
|
label_font_lg = "Arial";
|
||||||
|
label_font_sm = "Arial";
|
||||||
|
mesh_color = [1,1,1,0.5];
|
||||||
|
plane_color = [0.4,0.6,0.9,0.6];
|
||||||
|
|
||||||
|
//================================================ Derive useful values
|
||||||
|
|
||||||
|
big_z = max_2D(measured_z,0);
|
||||||
|
lil_z = min_2D(measured_z,0);
|
||||||
|
|
||||||
|
mean_value = (big_z + lil_z) / 2.0;
|
||||||
|
|
||||||
|
mesh_points_y = len(measured_z);
|
||||||
|
mesh_points_x = len(measured_z[0]);
|
||||||
|
|
||||||
|
xspace = mesh_width / (mesh_points_x - 1);
|
||||||
|
yspace = mesh_height / (mesh_points_y - 1);
|
||||||
|
|
||||||
|
// At $t=0 and $t=1 scale will be 100%
|
||||||
|
z_scale_factor = min_z_scale + (($t > 0.5) ? 1.0 - $t : $t) * (max_z_scale - min_z_scale) * 2;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Min and max recursive functions for 1D and 2D arrays
|
||||||
|
// Return the smallest or largest value in the array
|
||||||
|
//
|
||||||
|
function min_1D(b,i) = (i<len(b)-1) ? min(b[i], min_1D(b,i+1)) : b[i];
|
||||||
|
function min_2D(a,j) = (j<len(a)-1) ? min_2D(a,j+1) : min_1D(a[j], 0);
|
||||||
|
function max_1D(b,i) = (i<len(b)-1) ? max(b[i], max_1D(b,i+1)) : b[i];
|
||||||
|
function max_2D(a,j) = (j<len(a)-1) ? max_2D(a,j+1) : max_1D(a[j], 0);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Get the corner probe points of a grid square.
|
||||||
|
//
|
||||||
|
// Input : x,y grid indexes
|
||||||
|
// Output : An array of the 4 corner points
|
||||||
|
//
|
||||||
|
function grid_square(x,y) = [
|
||||||
|
[x * xspace, y * yspace, z_scale_factor * (measured_z[y][x] - mean_value)],
|
||||||
|
[x * xspace, (y+1) * yspace, z_scale_factor * (measured_z[y+1][x] - mean_value)],
|
||||||
|
[(x+1) * xspace, (y+1) * yspace, z_scale_factor * (measured_z[y+1][x+1] - mean_value)],
|
||||||
|
[(x+1) * xspace, y * yspace, z_scale_factor * (measured_z[y][x+1] - mean_value)]
|
||||||
|
];
|
||||||
|
|
||||||
|
// The corner point of a grid square with Z centered on the mean
|
||||||
|
function pos(x,y,z) = [x * xspace, y * yspace, z_scale_factor * (z - mean_value)];
|
||||||
|
|
||||||
|
//
|
||||||
|
// Draw the point markers and labels
|
||||||
|
//
|
||||||
|
module point_markers(show_home=true) {
|
||||||
|
// Mark the home position 0,0
|
||||||
|
color([0,0,0,0.25]) translate([1,1]) cylinder(r=1, h=z_scale_factor, center=true);
|
||||||
|
|
||||||
|
for (x=[0:mesh_points_x-1], y=[0:mesh_points_y-1]) {
|
||||||
|
z = measured_z[y][x];
|
||||||
|
down = z < mean_value;
|
||||||
|
translate(pos(x, y, z)) {
|
||||||
|
|
||||||
|
// Label each point with the Z
|
||||||
|
if (show_labels) {
|
||||||
|
v = z - mean_value;
|
||||||
|
|
||||||
|
color(abs(v) < 0.1 ? [0,0.5,0] : [0.25,0,0])
|
||||||
|
translate([0,0,down?-10:10]) {
|
||||||
|
|
||||||
|
$fn=8;
|
||||||
|
rotate([90,0])
|
||||||
|
text(str(z), 6, label_font_lg, halign="center", valign="center");
|
||||||
|
|
||||||
|
translate([0,0,down?-6:6]) rotate([90,0])
|
||||||
|
text(str(down ? "" : "+", v), 3, label_font_sm, halign="center", valign="center");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show an arrow pointing up or down
|
||||||
|
rotate([0, down ? 180 : 0]) translate([0,0,-1])
|
||||||
|
cylinder(
|
||||||
|
r1=0.5,
|
||||||
|
r2=0.1,
|
||||||
|
h=arrow_length, $fn=12, center=1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Split a square on the diagonal into
|
||||||
|
// two triangles and render them.
|
||||||
|
//
|
||||||
|
// s : a square
|
||||||
|
// alt : a flag to split on the other diagonal
|
||||||
|
//
|
||||||
|
module tesselated_square(s, alt=false) {
|
||||||
|
add = [0,0,thickness];
|
||||||
|
p1 = [
|
||||||
|
s[0], s[1], s[2], s[3],
|
||||||
|
s[0]+add, s[1]+add, s[2]+add, s[3]+add
|
||||||
|
];
|
||||||
|
f1 = alt
|
||||||
|
? [ [0,1,3], [4,5,1,0], [4,7,5], [5,7,3,1], [7,4,0,3] ]
|
||||||
|
: [ [0,1,2], [4,5,1,0], [4,6,5], [5,6,2,1], [6,4,0,2] ];
|
||||||
|
f2 = alt
|
||||||
|
? [ [1,2,3], [5,6,2,1], [5,6,7], [6,7,3,2], [7,5,1,3] ]
|
||||||
|
: [ [0,2,3], [4,6,2,0], [4,7,6], [6,7,3,2], [7,4,0,3] ];
|
||||||
|
|
||||||
|
// Use the other diagonal
|
||||||
|
polyhedron(points=p1, faces=f1);
|
||||||
|
polyhedron(points=p1, faces=f2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The simplest mesh display
|
||||||
|
*/
|
||||||
|
module simple_mesh(show_plane=show_plane) {
|
||||||
|
if (show_plane) color(plane_color) cube([mesh_width, mesh_height, thickness]);
|
||||||
|
color(mesh_color)
|
||||||
|
for (x=[0:mesh_points_x-2], y=[0:mesh_points_y-2])
|
||||||
|
tesselated_square(grid_square(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subdivide the mesh into smaller squares.
|
||||||
|
*/
|
||||||
|
module bilinear_mesh(show_plane=show_plane,tesselation=tesselation) {
|
||||||
|
if (show_plane) color(plane_color) translate([-5,-5]) cube([mesh_width+10, mesh_height+10, thickness]);
|
||||||
|
tesselation = tesselation % 4;
|
||||||
|
color(mesh_color)
|
||||||
|
for (x=[0:mesh_points_x-2], y=[0:mesh_points_y-2]) {
|
||||||
|
square = grid_square(x, y);
|
||||||
|
if (tesselation < 1) {
|
||||||
|
tesselated_square(square,(x%alternation)-(y%alternation));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
subdiv_4 = subdivided_square(square);
|
||||||
|
if (tesselation < 2) {
|
||||||
|
for (i=[0:3]) tesselated_square(subdiv_4[i],i%alternation);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (i=[0:3]) {
|
||||||
|
subdiv_16 = subdivided_square(subdiv_4[i]);
|
||||||
|
if (tesselation < 3) {
|
||||||
|
for (j=[0:3]) tesselated_square(subdiv_16[j],j%alternation);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (j=[0:3]) {
|
||||||
|
subdiv_64 = subdivided_square(subdiv_16[j]);
|
||||||
|
if (tesselation < 4) {
|
||||||
|
for (k=[0:3]) tesselated_square(subdiv_64[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Subdivision helpers
|
||||||
|
//
|
||||||
|
function ctrz(a) = (a[0][2]+a[1][2]+a[3][2]+a[2][2])/4;
|
||||||
|
function avgx(a,i) = (a[i][0]+a[(i+1)%4][0])/2;
|
||||||
|
function avgy(a,i) = (a[i][1]+a[(i+1)%4][1])/2;
|
||||||
|
function avgz(a,i) = (a[i][2]+a[(i+1)%4][2])/2;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Convert one square into 4, applying bilinear averaging
|
||||||
|
//
|
||||||
|
// Input : 1 square (4 points)
|
||||||
|
// Output : An array of 4 squares
|
||||||
|
//
|
||||||
|
function subdivided_square(a) = [
|
||||||
|
[ // SW square
|
||||||
|
a[0], // SW
|
||||||
|
[a[0][0],avgy(a,0),avgz(a,0)], // CW
|
||||||
|
[avgx(a,1),avgy(a,0),ctrz(a)], // CC
|
||||||
|
[avgx(a,1),a[0][1],avgz(a,3)] // SC
|
||||||
|
],
|
||||||
|
[ // NW square
|
||||||
|
[a[0][0],avgy(a,0),avgz(a,0)], // CW
|
||||||
|
a[1], // NW
|
||||||
|
[avgx(a,1),a[1][1],avgz(a,1)], // NC
|
||||||
|
[avgx(a,1),avgy(a,0),ctrz(a)] // CC
|
||||||
|
],
|
||||||
|
[ // NE square
|
||||||
|
[avgx(a,1),avgy(a,0),ctrz(a)], // CC
|
||||||
|
[avgx(a,1),a[1][1],avgz(a,1)], // NC
|
||||||
|
a[2], // NE
|
||||||
|
[a[2][0],avgy(a,0),avgz(a,2)] // CE
|
||||||
|
],
|
||||||
|
[ // SE square
|
||||||
|
[avgx(a,1),a[0][1],avgz(a,3)], // SC
|
||||||
|
[avgx(a,1),avgy(a,0),ctrz(a)], // CC
|
||||||
|
[a[2][0],avgy(a,0),avgz(a,2)], // CE
|
||||||
|
a[3] // SE
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
//================================================ Run the plan
|
||||||
|
|
||||||
|
translate([-mesh_width / 2, -mesh_height / 2]) {
|
||||||
|
$fn = 12;
|
||||||
|
point_markers();
|
||||||
|
bilinear_mesh();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user