/ src / shapes / sculpted_square.scad
sculpted_square.scad
  1  // rounded square shape with additional sculpting functions to better approximate
  2  
  3  // When sculpting sides, how much in should the tops come
  4  $side_sculpting_factor = 4.5;
  5  // When sculpting corners, how much extra radius should be added
  6  $corner_sculpting_factor = 1;
  7  // When doing more side sculpting corners, how much extra radius should be added
  8  $more_side_sculpting_factor = 0.4;
  9  
 10  
 11  // side sculpting functions
 12  // bows the sides out on stuff like SA and DSA keycaps
 13  function side_sculpting(progress) = (1 - progress) * $side_sculpting_factor;
 14  // makes the rounded corners of the keycap grow larger as they move upwards
 15  function corner_sculpting(progress) = pow(progress, 2) * $corner_sculpting_factor;
 16  
 17  module sculpted_square_shape(size, delta, progress) {
 18    width = size[0];
 19    height = size[1];
 20  
 21    width_difference = delta[0];
 22    height_difference = delta[1];
 23    // makes the sides bow
 24    extra_side_size =  side_sculpting(progress);
 25    // makes the rounded corners of the keycap grow larger as they move upwards
 26    extra_corner_size = corner_sculpting(progress);
 27  
 28    // computed values for this slice
 29    extra_width_this_slice = (width_difference - extra_side_size) * progress;
 30    extra_height_this_slice = (height_difference - extra_side_size) * progress;
 31    extra_corner_radius_this_slice = ($corner_radius + extra_corner_size);
 32  
 33    square_size = [
 34      width - extra_width_this_slice,
 35      height - extra_height_this_slice
 36    ];
 37  
 38    offset(r = extra_corner_radius_this_slice, $fa=360/$shape_facets) {
 39      offset(r = -extra_corner_radius_this_slice) {
 40        side_rounded_square(square_size, r = $more_side_sculpting_factor * progress);
 41      }
 42    }
 43  }
 44  
 45  function new_side_rounded_square(size, r, cornerRadius=0) =
 46    let(
 47      width = (size.x - r)/2,
 48      height = (size.y - r)/2,
 49  
 50      // fudge numbers! the radius conflict resolution in polyround smooths out
 51      // the entire shape based on the ratios between conflicting radii. bumping
 52      // these up makes the whole shape more fluid
 53      widthRadius = r ? width*8 : 0,
 54      heightRadius = r ? height*8 : 0,
 55  
 56      bow = r/2,
 57  
 58      // close enough :/
 59      facets = 360 / $shape_facets/2,
 60  
 61      points = [
 62         [-width,-height,cornerRadius],
 63         [0,-height-bow,widthRadius],
 64         [width,-height,cornerRadius],
 65         [width + bow,0,heightRadius],
 66         [width,height,cornerRadius],
 67         [0,height + bow,widthRadius],
 68         [-width,height,cornerRadius],
 69         [-width-bow,0,heightRadius]
 70      ]
 71    ) polyRound(points,facets);
 72  
 73  
 74  function skin_sculpted_square_shape(size, delta, progress, thickness_difference) =
 75    let(
 76      width = size[0],
 77      height = size[1],
 78  
 79      width_difference = delta[0],
 80      height_difference = delta[1],
 81      // makes the sides bow
 82      extra_side_size =  side_sculpting(progress),
 83      // makes the rounded corners of the keycap grow larger as they move upwards
 84      extra_corner_size = corner_sculpting(progress),
 85  
 86      // computed values for this slice
 87      extra_width_this_slice = (width_difference - extra_side_size) * progress,
 88      extra_height_this_slice = (height_difference - extra_side_size) * progress,
 89      extra_corner_radius_this_slice = ($corner_radius + extra_corner_size),
 90  
 91      square_size = [
 92        width - extra_width_this_slice - thickness_difference,
 93        height - extra_height_this_slice - thickness_difference
 94      ]
 95    ) new_side_rounded_square(square_size, $more_side_sculpting_factor * progress, extra_corner_radius_this_slice);
 96  
 97  
 98  module side_rounded_square(size, r) {
 99      iw = size.x - 2 * r;
100      ih = size.y - 2 * r;
101      resolution = 100;
102      sr = r / resolution * 2;
103      sh = ih / resolution;
104      sw = iw / resolution;
105      union() {
106        if (sr > 0) {
107          translate([-iw/2, 0]) scale([sr, sh]) circle(d = resolution, $fa=360/$shape_facets);
108          translate([iw/2, 0]) scale([sr, sh]) circle(d = resolution, $fa=360/$shape_facets);
109          translate([0, -ih/2]) scale([sw, sr]) circle(d = resolution, $fa=360/$shape_facets);
110          translate([0, ih/2]) scale([sw, sr]) circle(d = resolution, $fa=360/$shape_facets);
111        }
112          square([iw, ih], center=true);
113      }
114  }