/ src / function_grapher.scad
function_grapher.scad
  1  /**
  2  * function_grapher.scad
  3  *
  4  * @copyright Justin Lin, 2017
  5  * @license https://opensource.org/licenses/lgpl-3.0.html
  6  *
  7  * @see https://openhome.cc/eGossip/OpenSCAD/lib3x-function_grapher.html
  8  *
  9  **/ 
 10  
 11  use <util/reverse.scad>
 12  use <hull_polyline3d.scad>
 13  use <path_extrude.scad>
 14  use <shape_circle.scad>
 15  
 16  module function_grapher(points, thickness = 1, style = "FACES") {
 17      echo("`function_grapher` is deprecated since 3.1. Use `sf_thicken` instead.");
 18  
 19      rows = len(points);
 20      columns = len(points[0]);
 21  
 22      yi_range = [0:rows - 2];
 23      xi_range =  [0:columns - 2];
 24  
 25      half_thickness = thickness / 2;
 26  
 27      // Increasing $fn will be slow when you use "LINES", "HULL_FACES" or "HULL_LINES".
 28      
 29      module faces() {
 30          function xy_to_index(x, y, columns) = y * columns + x; 
 31  
 32          top_pts = [
 33              for(row_pts = points)
 34                  for(pt = row_pts)
 35                      pt
 36          ];
 37              
 38          base_pts = [
 39              for(pt = top_pts)
 40                  [pt[0], pt[1], pt[2] - thickness]
 41          ];
 42          
 43          leng_pts = len(top_pts);
 44                  
 45          top_tri_faces1 = [
 46              for(yi = yi_range) 
 47                  for(xi = xi_range)
 48                      [
 49                          xy_to_index(xi, yi, columns),
 50                          xy_to_index(xi + 1, yi + 1, columns),
 51                          xy_to_index(xi + 1, yi, columns)
 52                      ]    
 53          ];
 54  
 55          top_tri_faces2 = [
 56              for(yi = yi_range) 
 57                  for(xi = xi_range)
 58                      [
 59                          xy_to_index(xi, yi, columns),
 60                          xy_to_index(xi, yi + 1, columns),
 61                          xy_to_index(xi + 1, yi + 1, columns)
 62                      ]    
 63          ];        
 64  
 65          offset_v = [leng_pts, leng_pts, leng_pts];
 66          base_tri_faces1 = [
 67              for(face = top_tri_faces1)
 68                  reverse(face) + offset_v
 69          ];
 70  
 71          base_tri_faces2 = [
 72              for(face = top_tri_faces2)
 73                  reverse(face) + offset_v
 74          ];
 75          
 76          side_faces1 = [
 77              for(xi = xi_range)
 78                  let(
 79                      idx1 = xy_to_index(xi, 0, columns),
 80                      idx2 = xy_to_index(xi + 1, 0, columns)
 81                  )
 82                  [
 83                      idx1,
 84                      idx2,
 85                      idx2 + leng_pts,
 86                      idx1 + leng_pts
 87                  ]
 88          ];
 89  
 90          side_faces2 = [
 91              for(yi = yi_range)
 92                  let(
 93                      xi = columns - 1,
 94                      idx1 = xy_to_index(xi, yi, columns),
 95                      idx2 = xy_to_index(xi, yi + 1, columns)
 96                  )
 97                  [
 98                      idx1,
 99                      idx2,
100                      idx2 + leng_pts,
101                      idx1 + leng_pts
102                  ]
103          ];                  
104        
105          side_faces3 = [
106              for(xi = xi_range)
107                  let(
108                      yi = rows - 1,
109                      idx1 = xy_to_index(xi, yi, columns), 
110                      idx2 = xy_to_index(xi + 1, yi, columns)
111                  )
112                  [
113                      idx2,
114                      idx1,
115                      idx1 + leng_pts,
116                      idx2 + leng_pts
117                  ]
118          ];
119          
120          side_faces4 = [
121              for(yi = yi_range)
122                  let(
123                      idx1 = xy_to_index(0, yi, columns),
124                      idx2 = xy_to_index(0, yi + 1, columns)
125                  )
126                  [
127                      idx2,
128                      idx1,
129                      idx1 + leng_pts,
130                      idx2 + leng_pts
131                  ]
132          ];                  
133          
134          pts = concat(top_pts, base_pts);
135          face_idxs = concat(
136                  top_tri_faces1, top_tri_faces2,
137                  base_tri_faces1, base_tri_faces2, 
138                  side_faces1, 
139                  side_faces2, 
140                  side_faces3, 
141                  side_faces4
142              );
143  
144          polyhedron(
145              points = pts, 
146              faces = face_idxs
147          );
148  
149          // hook for testing
150          test_function_grapher_faces(pts, face_idxs);
151      }
152  
153      module hull_pts(tri) {
154         hull() {
155             translate(tri[0]) sphere(half_thickness);
156             translate(tri[1]) sphere(half_thickness);
157             translate(tri[2]) sphere(half_thickness);
158         }    
159      }
160      
161      module tri_to_hull_faces(tri1, tri2) {
162         hull_pts(tri1);
163         hull_pts(tri2);
164      }    
165      
166      if(style == "FACES") {
167          faces();
168      }
169      else if(style == "HULL_FACES") {
170          twintri_lt = 
171              [
172                  for(yi = yi_range)
173                      for(xi = xi_range)
174                          [
175                              [
176                                  points[yi][xi], 
177                                  points[yi][xi + 1], 
178                                  points[yi + 1][xi]
179                              ],
180                              [
181                                  points[yi + 1][xi], 
182                                  points[yi][xi + 1], 
183                                  points[yi + 1][xi + 1]                        
184                              ]
185                          ]
186              ];
187          
188          for(twintri = twintri_lt) {
189              tri_to_hull_faces(twintri[0], twintri[1]);
190          }  
191      }
192      else {
193          if(style == "LINES") {
194              section = shape_circle(radius = half_thickness);
195              for(row = points) {
196                  path_extrude(section, row);
197              }
198  
199              for(x = [0:columns - 1]) {
200                  path_extrude(section, [for(y = [0:rows - 1]) points[y][x]]);
201              }
202  
203              for(c = [0:columns - 2]) {
204                  path_extrude(section, [for(r = [0:rows - 1 - c]) points[r + c][r]]);
205              }
206  
207              for(c = [0:columns - 2]) {
208                  path_extrude(section, [for(r = [0:rows - 1 - c]) points[r][r + c]]);
209              }
210          }
211          else {
212              for(row = points) {
213                  hull_polyline3d(row, thickness);
214              }
215  
216              for(x = [0:columns - 1]) {
217                  hull_polyline3d([for(y = [0:rows - 1]) points[y][x]], thickness);
218              }
219  
220              for(c = [0:columns - 2]) {
221                  hull_polyline3d([for(r = [0:rows - 1 - c]) points[r + c][r]], thickness);
222              }
223              
224              for(c = [0:columns - 2]) {
225                  hull_polyline3d([for(r = [0:rows - 1 - c]) points[r][r + c]], thickness);
226              }
227          }
228      }
229  }
230  
231  // override it to test
232  module test_function_grapher_faces(points, faces) {
233  
234  }