|
| 1 | +/** |
| 2 | + * @file generic-helpers.scad |
| 3 | + * @brief Generic Helper Functions. Not gridfinity specific. |
| 4 | + */ |
| 5 | + |
| 6 | +function clp(x,a,b) = min(max(x,a),b); |
| 7 | + |
| 8 | +module rounded_rectangle(length, width, height, rad) { |
| 9 | + linear_extrude(height) |
| 10 | + offset(rad) |
| 11 | + offset(-rad) |
| 12 | + square([length,width], center = true); |
| 13 | +} |
| 14 | + |
| 15 | +module rounded_square(length, height, rad) { |
| 16 | + rounded_rectangle(length, length, height, rad); |
| 17 | +} |
| 18 | + |
| 19 | +module copy_mirror(vec=[0,1,0]) { |
| 20 | + children(); |
| 21 | + if (vec != [0,0,0]) |
| 22 | + mirror(vec) |
| 23 | + children(); |
| 24 | +} |
| 25 | + |
| 26 | +module pattern_linear(x = 1, y = 1, sx = 0, sy = 0) { |
| 27 | + yy = sy <= 0 ? sx : sy; |
| 28 | + translate([-(x-1)*sx/2,-(y-1)*yy/2,0]) |
| 29 | + for (i = [1:ceil(x)]) |
| 30 | + for (j = [1:ceil(y)]) |
| 31 | + translate([(i-1)*sx,(j-1)*yy,0]) |
| 32 | + children(); |
| 33 | +} |
| 34 | + |
| 35 | +module pattern_circular(n=2) { |
| 36 | + for (i = [1:n]) |
| 37 | + rotate(i*360/n) |
| 38 | + children(); |
| 39 | +} |
| 40 | + |
| 41 | +/** |
| 42 | + * @brief Unity (no change) affine transformation matrix. |
| 43 | + * @details For use with multmatrix transforms. |
| 44 | + */ |
| 45 | +unity_matrix = [ |
| 46 | + [1, 0, 0, 0], |
| 47 | + [0, 1, 0, 0], |
| 48 | + [0, 0, 1, 0], |
| 49 | + [0, 0, 0, 1] |
| 50 | +]; |
| 51 | + |
| 52 | +/** |
| 53 | + * @brief Get the magnitude of a 2d or 3d vector |
| 54 | + * @param vector A 2d or 3d vectorm |
| 55 | + * @returns Magnitude of the vector. |
| 56 | + */ |
| 57 | + function vector_magnitude(vector) = |
| 58 | + sqrt(vector.x^2 + vector.y^2 + (len(vector) == 3 ? vector.z^2 : 0)); |
| 59 | + |
| 60 | +/** |
| 61 | + * @brief Convert a 2d or 3d vector into a unit vector |
| 62 | + * @returns The unit vector. Where total magnitude is 1. |
| 63 | + */ |
| 64 | +function vector_as_unit(vector) = vector / vector_magnitude(vector); |
| 65 | + |
| 66 | +/** |
| 67 | + * @brief Convert a 2d vector into an angle. |
| 68 | + * @details Just a wrapper around atan2. |
| 69 | + * @param A 2d vectorm |
| 70 | + * @returns Angle of the vector. |
| 71 | + */ |
| 72 | +function atanv(vector) = atan2(vector.y, vector.x); |
| 73 | + |
| 74 | +function _affine_rotate_x(angle_x) = [ |
| 75 | + [1, 0, 0, 0], |
| 76 | + [0, cos(angle_x), -sin(angle_x), 0], |
| 77 | + [0, sin(angle_x), cos(angle_x), 0], |
| 78 | + [0, 0, 0, 1] |
| 79 | +]; |
| 80 | + |
| 81 | +function _affine_rotate_y(angle_y) = [ |
| 82 | + [cos(angle_y), 0, sin(angle_y), 0], |
| 83 | + [0, 1, 0, 0], |
| 84 | + [-sin(angle_y), 0, cos(angle_y), 0], |
| 85 | + [0, 0, 0, 1] |
| 86 | +]; |
| 87 | + |
| 88 | +function _affine_rotate_z(angle_z) = [ |
| 89 | + [cos(angle_z), -sin(angle_z), 0, 0], |
| 90 | + [sin(angle_z), cos(angle_z), 0, 0], |
| 91 | + [0, 0, 1, 0], |
| 92 | + [0, 0, 0, 1] |
| 93 | +]; |
| 94 | + |
| 95 | + |
| 96 | +/** |
| 97 | + * @brief Affine transformation matrix equivalent of `rotate` |
| 98 | + * @param angle_vector @see `rotate` |
| 99 | + * @details Equivalent to `rotate([0, angle, 0])` |
| 100 | + * @returns An affine transformation matrix for use with `multmatrix()` |
| 101 | + */ |
| 102 | +function affine_rotate(angle_vector) = |
| 103 | + _affine_rotate_z(angle_vector.z) * _affine_rotate_y(angle_vector.y) * _affine_rotate_x(angle_vector.x); |
| 104 | + |
| 105 | +/** |
| 106 | + * @brief Affine transformation matrix equivalent of `translate` |
| 107 | + * @param vector @see `translate` |
| 108 | + * @returns An affine transformation matrix for use with `multmatrix()` |
| 109 | + */ |
| 110 | +function affine_translate(vector) = [ |
| 111 | + [1, 0, 0, vector.x], |
| 112 | + [0, 1, 0, vector.y], |
| 113 | + [0, 0, 1, vector.z], |
| 114 | + [0, 0, 0, 1] |
| 115 | +]; |
| 116 | + |
| 117 | +/** |
| 118 | + * @brief Create a rectangle with rounded corners by sweeping a 2d object along a path. |
| 119 | + * Centered on origin. |
| 120 | + */ |
| 121 | +module sweep_rounded(width=10, length=10) { |
| 122 | + half_width = width/2; |
| 123 | + half_length = length/2; |
| 124 | + path_points = [ |
| 125 | + [-half_width, half_length], //Start |
| 126 | + [half_width, half_length], // Over |
| 127 | + [half_width, -half_length], //Down |
| 128 | + [-half_width, -half_length], // Back over |
| 129 | + [-half_width, half_length] // Up to start |
| 130 | + ]; |
| 131 | + path_vectors = [ |
| 132 | + path_points[1] - path_points[0], |
| 133 | + path_points[2] - path_points[1], |
| 134 | + path_points[3] - path_points[2], |
| 135 | + path_points[4] - path_points[3], |
| 136 | + ]; |
| 137 | + // These contain the translations, but not the rotations |
| 138 | + // OpenSCAD requires this hacky for loop to get accumulate to work! |
| 139 | + first_translation = affine_translate([path_points[0].y, 0,path_points[0].x]); |
| 140 | + affine_translations = concat([first_translation], [ |
| 141 | + for (i = 0, a = first_translation; |
| 142 | + i < len(path_vectors); |
| 143 | + a=a * affine_translate([path_vectors[i].y, 0, path_vectors[i].x]), i=i+1) |
| 144 | + a * affine_translate([path_vectors[i].y, 0, path_vectors[i].x]) |
| 145 | + ]); |
| 146 | + |
| 147 | + // Bring extrusion to the xy plane |
| 148 | + affine_matrix = affine_rotate([90, 0, 90]); |
| 149 | + |
| 150 | + walls = [ |
| 151 | + for (i = [0 : len(path_vectors) - 1]) |
| 152 | + affine_matrix * affine_translations[i] |
| 153 | + * affine_rotate([0, atanv(path_vectors[i]), 0]) |
| 154 | + ]; |
| 155 | + |
| 156 | + union() |
| 157 | + { |
| 158 | + for (i = [0 : len(walls) - 1]){ |
| 159 | + multmatrix(walls[i]) |
| 160 | + linear_extrude(vector_magnitude(path_vectors[i])) |
| 161 | + children(); |
| 162 | + |
| 163 | + // Rounded Corners |
| 164 | + multmatrix(walls[i] * affine_rotate([-90, 0, 0])) |
| 165 | + rotate_extrude(angle = 90, convexity = 4) |
| 166 | + children(); |
| 167 | + } |
| 168 | + } |
| 169 | +} |
0 commit comments