MarlinMesh.scad 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /**************************************\
  2. * *
  3. * OpenSCAD Mesh Display *
  4. * by Thinkyhead - April 2017 *
  5. * *
  6. * Copy the grid output from Marlin, *
  7. * paste below as shown, and use *
  8. * OpenSCAD to see a visualization *
  9. * of your mesh. *
  10. * *
  11. \**************************************/
  12. //$t = 0.15; // comment out during animation
  13. //
  14. // Mesh info and points
  15. //
  16. mesh_width = 200; // X Size in mm of the probed area
  17. mesh_height = 200; // Y Size...
  18. zprobe_offset = 0; // Added to the points
  19. NAN = 0; // Z to use for un-measured points
  20. measured_z = [
  21. [ -1.20, -1.13, -1.09, -1.03, -1.19 ],
  22. [ -1.16, -1.25, -1.27, -1.25, -1.08 ],
  23. [ -1.13, -1.26, -1.39, -1.31, -1.18 ],
  24. [ -1.09, -1.20, -1.26, -1.21, -1.18 ],
  25. [ -1.13, -0.99, -1.03, -1.06, -1.32 ]
  26. ];
  27. //
  28. // Geometry
  29. //
  30. max_z_scale = 100; // Scale at Time 0.5
  31. min_z_scale = 10; // Scale at Time 0.0 and 1.0
  32. thickness = 0.5; // thickness of the mesh triangles
  33. tesselation = 1; // levels of tesselation from 0-2
  34. alternation = 2; // direction change modulus (try it)
  35. //
  36. // Appearance
  37. //
  38. show_plane = true;
  39. show_labels = true;
  40. arrow_length = 5;
  41. label_font_lg = "Arial";
  42. label_font_sm = "Arial";
  43. mesh_color = [1,1,1,0.5];
  44. plane_color = [0.4,0.6,0.9,0.6];
  45. //================================================ Derive useful values
  46. big_z = max_2D(measured_z,0);
  47. lil_z = min_2D(measured_z,0);
  48. mean_value = (big_z + lil_z) / 2.0;
  49. mesh_points_y = len(measured_z);
  50. mesh_points_x = len(measured_z[0]);
  51. xspace = mesh_width / (mesh_points_x - 1);
  52. yspace = mesh_height / (mesh_points_y - 1);
  53. // At $t=0 and $t=1 scale will be 100%
  54. z_scale_factor = min_z_scale + (($t > 0.5) ? 1.0 - $t : $t) * (max_z_scale - min_z_scale) * 2;
  55. //
  56. // Min and max recursive functions for 1D and 2D arrays
  57. // Return the smallest or largest value in the array
  58. //
  59. function min_1D(b,i) = (i<len(b)-1) ? min(b[i], min_1D(b,i+1)) : b[i];
  60. function min_2D(a,j) = (j<len(a)-1) ? min_2D(a,j+1) : min_1D(a[j], 0);
  61. function max_1D(b,i) = (i<len(b)-1) ? max(b[i], max_1D(b,i+1)) : b[i];
  62. function max_2D(a,j) = (j<len(a)-1) ? max_2D(a,j+1) : max_1D(a[j], 0);
  63. //
  64. // Get the corner probe points of a grid square.
  65. //
  66. // Input : x,y grid indexes
  67. // Output : An array of the 4 corner points
  68. //
  69. function grid_square(x,y) = [
  70. [x * xspace, y * yspace, z_scale_factor * (measured_z[y][x] - mean_value)],
  71. [x * xspace, (y+1) * yspace, z_scale_factor * (measured_z[y+1][x] - mean_value)],
  72. [(x+1) * xspace, (y+1) * yspace, z_scale_factor * (measured_z[y+1][x+1] - mean_value)],
  73. [(x+1) * xspace, y * yspace, z_scale_factor * (measured_z[y][x+1] - mean_value)]
  74. ];
  75. // The corner point of a grid square with Z centered on the mean
  76. function pos(x,y,z) = [x * xspace, y * yspace, z_scale_factor * (z - mean_value)];
  77. //
  78. // Draw the point markers and labels
  79. //
  80. module point_markers(show_home=true) {
  81. // Mark the home position 0,0
  82. color([0,0,0,0.25]) translate([1,1]) cylinder(r=1, h=z_scale_factor, center=true);
  83. for (x=[0:mesh_points_x-1], y=[0:mesh_points_y-1]) {
  84. z = measured_z[y][x];
  85. down = z < mean_value;
  86. translate(pos(x, y, z)) {
  87. // Label each point with the Z
  88. if (show_labels) {
  89. v = z - mean_value;
  90. color(abs(v) < 0.1 ? [0,0.5,0] : [0.25,0,0])
  91. translate([0,0,down?-10:10]) {
  92. $fn=8;
  93. rotate([90,0])
  94. text(str(z), 6, label_font_lg, halign="center", valign="center");
  95. translate([0,0,down?-6:6]) rotate([90,0])
  96. text(str(down ? "" : "+", v), 3, label_font_sm, halign="center", valign="center");
  97. }
  98. }
  99. // Show an arrow pointing up or down
  100. rotate([0, down ? 180 : 0]) translate([0,0,-1])
  101. cylinder(
  102. r1=0.5,
  103. r2=0.1,
  104. h=arrow_length, $fn=12, center=1
  105. );
  106. }
  107. }
  108. }
  109. //
  110. // Split a square on the diagonal into
  111. // two triangles and render them.
  112. //
  113. // s : a square
  114. // alt : a flag to split on the other diagonal
  115. //
  116. module tesselated_square(s, alt=false) {
  117. add = [0,0,thickness];
  118. p1 = [
  119. s[0], s[1], s[2], s[3],
  120. s[0]+add, s[1]+add, s[2]+add, s[3]+add
  121. ];
  122. f1 = alt
  123. ? [ [0,1,3], [4,5,1,0], [4,7,5], [5,7,3,1], [7,4,0,3] ]
  124. : [ [0,1,2], [4,5,1,0], [4,6,5], [5,6,2,1], [6,4,0,2] ];
  125. f2 = alt
  126. ? [ [1,2,3], [5,6,2,1], [5,6,7], [6,7,3,2], [7,5,1,3] ]
  127. : [ [0,2,3], [4,6,2,0], [4,7,6], [6,7,3,2], [7,4,0,3] ];
  128. // Use the other diagonal
  129. polyhedron(points=p1, faces=f1);
  130. polyhedron(points=p1, faces=f2);
  131. }
  132. /**
  133. * The simplest mesh display
  134. */
  135. module simple_mesh(show_plane=show_plane) {
  136. if (show_plane) color(plane_color) cube([mesh_width, mesh_height, thickness]);
  137. color(mesh_color)
  138. for (x=[0:mesh_points_x-2], y=[0:mesh_points_y-2])
  139. tesselated_square(grid_square(x, y));
  140. }
  141. /**
  142. * Subdivide the mesh into smaller squares.
  143. */
  144. module bilinear_mesh(show_plane=show_plane,tesselation=tesselation) {
  145. if (show_plane) color(plane_color) translate([-5,-5]) cube([mesh_width+10, mesh_height+10, thickness]);
  146. tesselation = tesselation % 4;
  147. color(mesh_color)
  148. for (x=[0:mesh_points_x-2], y=[0:mesh_points_y-2]) {
  149. square = grid_square(x, y);
  150. if (tesselation < 1) {
  151. tesselated_square(square,(x%alternation)-(y%alternation));
  152. }
  153. else {
  154. subdiv_4 = subdivided_square(square);
  155. if (tesselation < 2) {
  156. for (i=[0:3]) tesselated_square(subdiv_4[i],i%alternation);
  157. }
  158. else {
  159. for (i=[0:3]) {
  160. subdiv_16 = subdivided_square(subdiv_4[i]);
  161. if (tesselation < 3) {
  162. for (j=[0:3]) tesselated_square(subdiv_16[j],j%alternation);
  163. }
  164. else {
  165. for (j=[0:3]) {
  166. subdiv_64 = subdivided_square(subdiv_16[j]);
  167. if (tesselation < 4) {
  168. for (k=[0:3]) tesselated_square(subdiv_64[k]);
  169. }
  170. }
  171. }
  172. }
  173. }
  174. }
  175. }
  176. }
  177. //
  178. // Subdivision helpers
  179. //
  180. function ctrz(a) = (a[0][2]+a[1][2]+a[3][2]+a[2][2])/4;
  181. function avgx(a,i) = (a[i][0]+a[(i+1)%4][0])/2;
  182. function avgy(a,i) = (a[i][1]+a[(i+1)%4][1])/2;
  183. function avgz(a,i) = (a[i][2]+a[(i+1)%4][2])/2;
  184. //
  185. // Convert one square into 4, applying bilinear averaging
  186. //
  187. // Input : 1 square (4 points)
  188. // Output : An array of 4 squares
  189. //
  190. function subdivided_square(a) = [
  191. [ // SW square
  192. a[0], // SW
  193. [a[0][0],avgy(a,0),avgz(a,0)], // CW
  194. [avgx(a,1),avgy(a,0),ctrz(a)], // CC
  195. [avgx(a,1),a[0][1],avgz(a,3)] // SC
  196. ],
  197. [ // NW square
  198. [a[0][0],avgy(a,0),avgz(a,0)], // CW
  199. a[1], // NW
  200. [avgx(a,1),a[1][1],avgz(a,1)], // NC
  201. [avgx(a,1),avgy(a,0),ctrz(a)] // CC
  202. ],
  203. [ // NE square
  204. [avgx(a,1),avgy(a,0),ctrz(a)], // CC
  205. [avgx(a,1),a[1][1],avgz(a,1)], // NC
  206. a[2], // NE
  207. [a[2][0],avgy(a,0),avgz(a,2)] // CE
  208. ],
  209. [ // SE square
  210. [avgx(a,1),a[0][1],avgz(a,3)], // SC
  211. [avgx(a,1),avgy(a,0),ctrz(a)], // CC
  212. [a[2][0],avgy(a,0),avgz(a,2)], // CE
  213. a[3] // SE
  214. ]
  215. ];
  216. //================================================ Run the plan
  217. translate([-mesh_width / 2, -mesh_height / 2]) {
  218. $fn = 12;
  219. point_markers();
  220. bilinear_mesh();
  221. }