aboutsummaryrefslogtreecommitdiff
path: root/buildroot/share/scripts/MarlinMesh.scad
diff options
context:
space:
mode:
authorGeorgiy Bondarenko <69736697+nehilo@users.noreply.github.com>2021-03-04 20:54:23 +0300
committerGeorgiy Bondarenko <69736697+nehilo@users.noreply.github.com>2021-03-04 20:54:23 +0300
commite8701195e66f2d27ffe17fb514eae8173795aaf7 (patch)
tree9f519c4abf6556b9ae7190a6210d87ead1dfadde /buildroot/share/scripts/MarlinMesh.scad
downloadkp3s-lgvl-e8701195e66f2d27ffe17fb514eae8173795aaf7.tar.xz
kp3s-lgvl-e8701195e66f2d27ffe17fb514eae8173795aaf7.zip
Initial commit
Diffstat (limited to 'buildroot/share/scripts/MarlinMesh.scad')
-rw-r--r--buildroot/share/scripts/MarlinMesh.scad304
1 files changed, 304 insertions, 0 deletions
diff --git a/buildroot/share/scripts/MarlinMesh.scad b/buildroot/share/scripts/MarlinMesh.scad
new file mode 100644
index 0000000..6d78bb9
--- /dev/null
+++ b/buildroot/share/scripts/MarlinMesh.scad
@@ -0,0 +1,304 @@
+ /**************************************\
+ * *
+ * 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!
+X = 0; Y = 1;
+L = 0; R = 1; F = 2; B = 3;
+
+//
+// Sample Mesh - Replace with your own
+//
+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 ]
+];
+
+//
+// An offset to add to all points in the mesh
+//
+zadjust = 0;
+
+//
+// Mesh characteristics
+//
+bed_size = [ 200, 200 ];
+
+mesh_inset = [ 10, 10, 10, 10 ]; // L, F, R, B
+
+mesh_bounds = [
+ [ mesh_inset[L], mesh_inset[F] ],
+ [ bed_size[X] - mesh_inset[R], bed_size[Y] - mesh_inset[B] ]
+];
+
+mesh_size = mesh_bounds[1] - mesh_bounds[0];
+
+ // NOTE: Marlin meshes already subtract the probe offset
+NAN = 0; // Z to use for un-measured points
+
+//
+// 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;
+show_coords = 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_size[X] / (mesh_points_x - 1);
+yspace = mesh_size[Y] / (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 some_1D(b,i) = (i<len(b)-1) ? (b[i] && some_1D(b,i+1)) : b[i] != 0;
+function some_2D(a,j) = (j<len(a)-1) ? some_2D(a,j+1) : some_1D(a[j], 0);
+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
+ if (show_home)
+ translate([1,1]) color([0,0,0,0.25])
+ 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] - zadjust;
+ down = z < mean_value;
+ xyz = pos(x, y, z);
+ translate([ xyz[0], xyz[1] ]) {
+
+ // Show the XY as well as the Z!
+ if (show_coords) {
+ color("black")
+ translate([0,0,0.5]) {
+ $fn=8;
+ rotate([0,0]) {
+ posx = floor(mesh_bounds[0][X] + x * xspace);
+ posy = floor(mesh_bounds[0][Y] + y * yspace);
+ text(str(posx, ",", posy), 2, label_font_sm, halign="center", valign="center");
+ }
+ }
+ }
+
+ translate([ 0, 0, xyz[2] ]) {
+ // Label each point with the Z
+ v = z - mean_value;
+ if (show_labels) {
+
+ 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");
+
+ if (v)
+ translate([0,0,down?-6:6]) rotate([90,0])
+ text(str(down || !v ? "" : "+", v), 3, label_font_sm, halign="center", valign="center");
+ }
+ }
+
+ // Show an arrow pointing up or down
+ if (v) {
+ rotate([0, down ? 180 : 0]) translate([0,0,-1])
+ cylinder(
+ r1=0.5,
+ r2=0.1,
+ h=arrow_length, $fn=12, center=1
+ );
+ }
+ else
+ color([1,0,1,0.4]) sphere(r=1.0, $fn=20, 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_size[X], mesh_size[Y], 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_size[X]+10, mesh_size[Y]+10, thickness]);
+
+ if (some_2D(measured_z, 0)) {
+
+ 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_size[X] / 2, -mesh_size[Y] / 2]) {
+ $fn = 12;
+ point_markers();
+ bilinear_mesh();
+}