parametric-flake.scad
1 unit = [1, 0]; 2 origin = [0, 0]; 3 4 5 /* 6 Returns a 2D rotation matrix given an angle. 7 */ 8 function rot2d(angle) = [ 9 [+cos(angle), -sin(angle)], 10 [+sin(angle), +cos(angle)] 11 ]; 12 13 14 /* 15 Calculates the points for a hexagon. 16 Used to reference off of for creating the lambda. 17 Points are created starting from the right and moving counter-clockwise. 18 19 2 1 20 21 3 0 22 23 4 5 24 */ 25 function inner_hex_points(data) = [ 26 for (angle = [0 : 60 : 300]) 27 dict_get(data, "scale") * rot2d(angle) * unit 28 ]; 29 30 31 32 /* 33 Calculates the points for making a lambda. 34 35 Returns two a list of two lists. 36 The first list contains the offset for making a flake. 37 The second list is used to form the lambda polygon. 38 */ 39 function lambda_points(data) = 40 let ( 41 hex_points = inner_hex_points(data), 42 thickness = dict_get(data, "thickness") / 2, 43 top_left = hex_points[2], 44 bottom_left = hex_points[4], 45 bottom_right = hex_points[5], 46 v_0 = thickness * unit, 47 v_p60 = thickness * rot2d(60) * unit, 48 v_n60 = thickness * rot2d(-60) * unit, 49 v_n90 = thickness * rot2d(-90) * unit, 50 gap = dict_get(data, "gap") * rot2d(-60) * unit 51 ) 52 [ 53 [ 54 top_left + v_p60, 55 ], 56 [ 57 top_left - v_p60 + gap, 58 top_left + v_p60 + gap, 59 bottom_right + v_0, 60 bottom_right - v_0, 61 sqrt(3) * v_n90, 62 bottom_left + v_0, 63 bottom_left, 64 bottom_left - v_n60, 65 -v_0 66 ] 67 ]; 68 69 70 /* 71 Generates a single lambda at the origin. 72 */ 73 module lambda(data) { 74 new_data = update_params(data); 75 linear_extrude(dict_get(new_data, "height")) 76 polygon(lambda_points(new_data)[1]); 77 } 78 79 80 /* 81 Generates a NixOS flake. 82 */ 83 module flake(data) { 84 new_data = update_params(data); 85 colors = dict_get(data, "colors"); 86 echo(colors); 87 for (idx = [0 : 5]) { 88 color(colors[idx % len(colors)]) 89 rotate([0, 0, idx * 60]) 90 translate(-lambda_points(new_data)[0][0]) 91 translate([-dict_get(new_data, "scale"), 0, 0]) 92 linear_extrude(dict_get(new_data, "height")) 93 polygon(lambda_points(new_data)[1]); 94 } 95 } 96 97 98 /* 99 Returns the value from a associative array/dictionary type structure given some key. 100 101 Values can be of any type. 102 The dictionary must of be of the form: 103 [ 104 [ "key0", <value0> ], 105 [ "key1", <value1> ], 106 ... 107 ] 108 */ 109 function dict_get(dict, key) = 110 dict[search([key], dict)[0]][1]; 111 112 113 /* 114 Updates the user parameters so the flake is unit size when `scale = 1`. 115 */ 116 function update_params(data) = let 117 // factor was empirically found. It gives a flake that is circumscribed by the unit circle. 118 (factor = 2.25) [ 119 [ "gap", 0.75 * dict_get(data, "scale") * dict_get(data, "gap") / factor ], 120 [ "height", dict_get(data, "height") ], 121 [ "scale", dict_get(data, "scale") / factor ], 122 [ "thickness", dict_get(data, "scale") * dict_get(data, "thickness") / factor ], 123 ]; 124 125 126 /* 127 The parameters for generating a NixOS flake. 128 129 `gap` - The gap between lambdas. 130 `height` - The z-height of the flake. 131 `scale` - The radial (x,y) size of the flake. 132 `thickness` - The thickness of the lambda legs. 133 134 `scale` updates `gap` and `thickness` so there is no need to compesate these values. 135 A `gap` of 0 will leave no gap between the lambdas. 136 A `gap` of 1 will remove the top portion of the long lambda leg until the point where the two lambda legs intersect. 137 138 A `gap` of 0.05 to 0.15 is a good value for replicating the official NixOS flake. 139 A `thickness` of 0.5 is a good value for replicating the official NixOS flake. 140 OpenSCAD doesn't have a concept of units so use `scale` and `height` values in the desired ratio. 141 */ 142 params = [ 143 [ "gap", 0.1 ], 144 [ "height", 1 ], 145 [ "scale", 10 ], 146 [ "thickness", 0.5 ], 147 // [ "colors", ["#5277C3", "#7EBAE4"]], 148 [ "colors", ["#b40bdf", "#ffd200"]], 149 ]; 150 151 152 flake(params);