some ISO enter updates

This commit is contained in:
Bob - Home - Windows 2017-11-11 17:32:27 -05:00
parent dcc13b7d35
commit 5f60c1889b
18 changed files with 1283 additions and 110 deletions

117
key.scad
View File

@ -135,6 +135,23 @@ module rounded_shape() {
}
}
//corollary is shape_hull
module ISOEnterShapeHull(thickness_difference, depth_difference, modifier){
height = $total_depth - depth_difference;
width_scale = top_total_key_width() / total_key_width();
height_scale = top_total_key_height() / total_key_height();
translate([0,19.05 * 0.5,0])
linear_extrude(height = height, scale = [width_scale, height_scale]) {
// TODO completely making up these numbers here
// 0.86mm is from the unit function, 18.16 - 19.02. no idea what the 18 is, shows me for not leaving better comments
translate([0,-19.05 * 0.5,0])
fakeISOEnter(thickness_difference);
}
}
// basic key shape, no dish, no inside
// modifier multiplies the height and top differences of the shape,
// which is only used for dishing to cut the dish off correctly
@ -158,18 +175,25 @@ module shape_hull(thickness_difference, depth_difference, modifier, extra_slices
module shape_slice(index, total, thickness_difference, depth_difference, modifier) {
progress = index / (total);
// TODO extract these out somehow so you can make custom rounded sides
// makes the sides bow
extra_side_size = $enable_side_sculpting ? (total - index)/4 : 0;
// makes the rounded corners of the keycap grow larger as they move upwards
extra_corner_size = $enable_side_sculpting ? pow(progress, 2) : 0;
// width and height differences for this slice
extra_width_difference = ($width_difference - extra_side_size) * progress * modifier;
extra_height_difference = ($height_difference - extra_side_size) * progress * modifier;
translate([
0,
$top_skew * progress,
($total_depth * modifier - depth_difference) * progress
]) rotate([-$top_tilt / $key_height * progress,0,0]){
roundedRect([
total_key_width() - thickness_difference - (($width_difference - extra_side_size) * progress * modifier),
total_key_height() - thickness_difference - (($height_difference - extra_side_size) * progress * modifier),
total_key_width() - thickness_difference - extra_width_difference,
total_key_height() - thickness_difference - extra_height_difference,
.001
],$corner_radius + extra_corner_size);
}
@ -311,92 +335,3 @@ module example_key(){
}
example_key();
//minkowski_key();
// Experimental stuff, except not really anymore
// corollary is roundedRect
// NOT 3D
module fakeISOEnter(thickness_difference = 0){
// 1u is the space taken upy by a 1u keycap.
// unit is the space taken up by a unit space for a keycap.
// formula is 1u + unit *(length - 1)
// t is all modifications to the polygon array
t = $corner_radius + thickness_difference/2;
function unit(length) = 19.02 * (length) + (18.16 - 19.02);
pointArray = [
[ 0 + t, 0 + t],
[unit(1.5) - t, 0 + t],
[unit(1.5) - t, unit(1) - t],
[unit(1.25) - t, unit(1) - t],
[unit(1.25) - t, unit(2) - t],
[ 0 + t, unit(2) - t]
];
offset(r=$corner_radius) {
polygon(points=pointArray, center=true);
}
}
//corollary is shape_hull
module ISOEnterShapeHull(thickness_difference, depth_difference, modifier){
// TODO move this somewhere
function unit(length) = 19.02 * (length) + (18.16 - 19.02);
height = $total_depth - depth_difference;
width_scale = top_total_key_width() / total_key_width();
height_scale = top_total_key_height() / total_key_height();
linear_extrude(height = height, scale = [width_scale, height_scale]) {
// TODO completely making up these numbers here
// 0.86mm is from the unit function, 18.16 - 19.02. no idea what the 18 is, shows me for not leaving better comments
translate([unit(-.5), unit(-1) + 0.86]) fakeISOEnter(thickness_difference);
}
}
// old stuff
// old non-sliced shape hull
/*module oldshape_hull(thickness_difference, depth_difference, modifier){
if ($ISOEnter) {
ISOEnterShapeHull(thickness_difference, depth_difference, modifier);
} else {
hull(){
// $bottom_key_width + ($key_length -1) * unit is the correct length of the
// key. only 1u of the key should be $bottom_key_width long; all others
// should be 1u
roundedRect([total_key_width() - thickness_difference, total_key_height() - thickness_difference, .001],$corner_radius);
//depth_difference outside of modifier because that doesnt make sense
translate([0,$top_skew,$total_depth * modifier - depth_difference]){
rotate([-$top_tilt / $key_height,0,0]){
roundedRect([
total_key_width() - thickness_difference - $width_difference * modifier,
total_key_height() - thickness_difference - $height_difference * modifier,
.001
],$corner_radius);
}
}
}
}
}*/

View File

@ -418,4 +418,5 @@ module legend(text, inset=false) {
children();
}
translate_u(0, 0) oem_row(1) cherry() key();
translate_u(1.125, 0.5) fake_iso_enter() cherry() key();
translate_u(0, 0) dcs_row(2) cherry() key();

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2014 Oskar Linde
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,81 @@
scad-utils
==========
Utility libraries for OpenSCAD
Morphology
----------
contains basic 2D morphology operations
inset(d=1) - creates a polygon at an offset d inside a 2D shape
outset(d=1) - creates a polygon at an offset d outside a 2D shape
fillet(r=1) - adds fillets of radius r to all concave corners of a 2D shape
rounding(r=1) - adds rounding to all convex corners of a 2D shape
shell(d,center=false) - makes a shell of width d along the edge of a 2D shape
- positive values of d places the shell on the outside
- negative values of d places the shell on the inside
- center=true and positive d places the shell centered on the edge
### Examples
With a basic sample polygon shape,
module shape() {
polygon([[0,0],[1,0],[1.5,1],[2.5,1],[2,-1],[0,-1]]);
}
and `$fn=32;`.
* `inset(d=0.3) shape();`
![](http://oskarlinde.github.io/scad-utils/img/morph-0.png)
* `outset(d=0.3) shape();`
![](http://oskarlinde.github.io/scad-utils/img/morph-1.png)
* `rounding(r=0.3) shape();`
![](http://oskarlinde.github.io/scad-utils/img/morph-2.png)
* `fillet(r=0.3) shape();`
![](http://oskarlinde.github.io/scad-utils/img/morph-3.png)
*`shell(d=0.3) shape();`
![](http://oskarlinde.github.io/scad-utils/img/morph-4.png)
*`shell(d=-0.3) shape();`
![](http://oskarlinde.github.io/scad-utils/img/morph-5.png)
*`shell(d=0.3,center=true) shape();`
![](http://oskarlinde.github.io/scad-utils/img/morph-6.png)
Mirror
------
contains simple mirroring functions
mirror_x()
mirror_y()
mirror_z()
example:
module arrow(l=1,w=.6,t=0.15) {
mirror_y() polygon([[0,0],[l,0],[l-w/2,w/2],[l-w/2-sqrt(2)*t,w/2],[l-t/2-sqrt(2)*t,t/2],[0,t/2]]);
}

View File

@ -0,0 +1,324 @@
// NOTE: this code uses
// * experimental let() syntax
// * experimental list comprehension syntax
// * search() bugfix and feature addition
// * vector min()/max()
// Calculates the convex hull of a set of points.
// The result is expressed in point indices.
// If the points are collinear (or 2d), the result is a convex
// polygon [i1,i2,i3,...], otherwise a triangular
// polyhedron [[i1,i2,i3],[i2,i3,i4],...]
function hull(points) =
!(len(points) > 0) ? [] :
len(points[0]) == 2 ? convexhull2d(points) :
len(points[0]) == 3 ? convexhull3d(points) : [];
epsilon = 1e-9;
// 2d version
function convexhull2d(points) =
len(points) < 3 ? [] : let(
a=0, b=1,
c = find_first_noncollinear([a,b], points, 2)
) c == len(points) ? convexhull_collinear(points) : let(
remaining = [ for (i = [2:len(points)-1]) if (i != c) i ],
polygon = area_2d(points[a], points[b], points[c]) > 0 ? [a,b,c] : [b,a,c]
) convex_hull_iterative_2d(points, polygon, remaining);
// Adds the remaining points one by one to the convex hull
function convex_hull_iterative_2d(points, polygon, remaining, i_=0) = i_ >= len(remaining) ? polygon :
let (
// pick a point
i = remaining[i_],
// find the segments that are in conflict with the point (point not inside)
conflicts = find_conflicting_segments(points, polygon, points[i])
// no conflicts, skip point and move on
) len(conflicts) == 0 ? convex_hull_iterative_2d(points, polygon, remaining, i_+1) : let(
// find the first conflicting segment and the first not conflicting
// conflict will be sorted, if not wrapping around, do it the easy way
polygon = remove_conflicts_and_insert_point(polygon, conflicts, i)
) convex_hull_iterative_2d(
points,
polygon,
remaining,
i_+1
);
function find_conflicting_segments(points, polygon, point) = [
for (i = [0:len(polygon)-1]) let(j = (i+1) % len(polygon))
if (area_2d(points[polygon[i]], points[polygon[j]], point) < 0)
i
];
// remove the conflicting segments from the polygon
function remove_conflicts_and_insert_point(polygon, conflicts, point) =
conflicts[0] == 0 ? let(
nonconflicting = [ for(i = [0:len(polygon)-1]) if (!contains(conflicts, i)) i ],
new_indices = concat(nonconflicting, (nonconflicting[len(nonconflicting)-1]+1) % len(polygon)),
polygon = concat([ for (i = new_indices) polygon[i] ], point)
) polygon : let(
prior_to_first_conflict = [ for(i = [0:1:min(conflicts)]) polygon[i] ],
after_last_conflict = [ for(i = [max(conflicts)+1:1:len(polygon)-1]) polygon[i] ],
polygon = concat(prior_to_first_conflict, point, after_last_conflict)
) polygon;
// 3d version
function convexhull3d(points) =
len(points) < 3 ? [ for(i = [0:1:len(points)-1]) i ] : let (
// start with a single triangle
a=0, b=1, c=2,
plane = plane(points,a,b,c),
d = find_first_noncoplanar(plane, points, 3)
) d == len(points) ? /* all coplanar*/ let (
pts2d = [ for (p = points) plane_project(p, points[a], points[b], points[c]) ],
hull2d = convexhull2d(pts2d)
) hull2d : let(
remaining = [for (i = [3:len(points)-1]) if (i != d) i],
// Build an initial tetrahedron
// swap b,c if d is in front of triangle t
bc = in_front(plane, points[d]) ? [c,b] : [b,c],
b = bc[0], c = bc[1],
triangles = [
[a,b,c],
[d,b,a],
[c,d,a],
[b,d,c],
],
// calculate the plane equations
planes = [ for (t = triangles) plane(points, t[0], t[1], t[2]) ]
) convex_hull_iterative(points, triangles, planes, remaining);
// A plane equation (normal, offset)
function plane(points, a, b, c) = let(
normal = unit(cross(points[c]-points[a], points[b]-points[a]))
) [
normal,
normal * points[a]
];
// Adds the remaining points one by one to the convex hull
function convex_hull_iterative(points, triangles, planes, remaining, i_=0) = i_ >= len(remaining) ? triangles :
let (
// pick a point
i = remaining[i_],
// find the triangles that are in conflict with the point (point not inside)
conflicts = find_conflicts(points[i], planes),
// for all triangles that are in conflict, collect their halfedges
halfedges = [
for(c = conflicts)
for(i = [0:2]) let(j = (i+1)%3)
[triangles[c][i], triangles[c][j]]
],
// find the outer perimeter of the set of conflicting triangles
horizon = remove_internal_edges(halfedges),
// generate a new triangle for each horizon halfedge together with the picked point i
new_triangles = [ for (h = horizon) concat(h,i) ],
// calculate the corresponding plane equations
new_planes = [ for (t = new_triangles) plane(points, t[0], t[1], t[2]) ]
) convex_hull_iterative(
points,
// remove the conflicting triangles and add the new ones
concat(remove_elements(triangles, conflicts), new_triangles),
concat(remove_elements(planes, conflicts), new_planes),
remaining,
i_+1
);
function convexhull_collinear(points) = let(
n = points[1] - points[0],
a = points[0],
points1d = [ for(p = points) (p-a)*n ],
min_i = min_index(points1d),
max_i = max_index(points1d)
) [ min_i, max_i ];
function min_index(values,min_,min_i_,i_) =
i_ == undef ? min_index(values,values[0],0,1) :
i_ >= len(values) ? min_i_ :
values[i_] < min_ ? min_index(values,values[i_],i_,i_+1)
: min_index(values,min_,min_i_,i_+1);
function max_index(values,max_,max_i_,i_) =
i_ == undef ? max_index(values,values[0],0,1) :
i_ >= len(values) ? max_i_ :
values[i_] > max_ ? max_index(values,values[i_],i_,i_+1)
: max_index(values,max_,max_i_,i_+1);
function remove_elements(array, elements) = [
for (i = [0:len(array)-1])
if (!search(i, elements))
array[i]
];
function remove_internal_edges(halfedges) = [
for (h = halfedges)
if (!contains(halfedges, reverse(h)))
h
];
function plane_project(point, a, b, c) = let(
u = b-a,
v = c-a,
n = cross(u,v),
w = cross(n,u),
relpoint = point-a
) [relpoint * u, relpoint * w];
function plane_unproject(point, a, b, c) = let(
u = b-a,
v = c-a,
n = cross(u,v),
w = cross(n,u)
) a + point[0] * u + point[1] * w;
function reverse(arr) = [ for (i = [len(arr)-1:-1:0]) arr[i] ];
function contains(arr, element) = search([element],arr)[0] != [] ? true : false;
function find_conflicts(point, planes) = [
for (i = [0:len(planes)-1])
if (in_front(planes[i], point))
i
];
function find_first_noncollinear(line, points, i) =
i >= len(points) ? len(points) :
collinear(points[line[0]],
points[line[1]],
points[i]) ? find_first_noncollinear(line, points, i+1)
: i;
function find_first_noncoplanar(plane, points, i) =
i >= len(points) ? len(points) :
coplanar(plane, points[i]) ? find_first_noncoplanar(plane, points, i+1)
: i;
function distance(plane, point) = plane[0] * point - plane[1];
function in_front(plane, point) = distance(plane, point) > epsilon;
function coplanar(plane, point) = abs(distance(plane,point)) <= epsilon;
function unit(v) = v/norm(v);
function area_2d(a,b,c) = (
a[0] * (b[1] - c[1]) +
b[0] * (c[1] - a[1]) +
c[0] * (a[1] - b[1])) / 2;
function collinear(a,b,c) = abs(area_2d(a,b,c)) < epsilon;
function spherical(cartesian) = [
atan2(cartesian[1], cartesian[0]),
asin(cartesian[2])
];
function cartesian(spherical) = [
cos(spherical[1]) * cos(spherical[0]),
cos(spherical[1]) * sin(spherical[0]),
sin(spherical[1])
];
/// TESTCODE
phi = 1.618033988749895;
testpoints_on_sphere = [ for(p =
[
[1,phi,0], [-1,phi,0], [1,-phi,0], [-1,-phi,0],
[0,1,phi], [0,-1,phi], [0,1,-phi], [0,-1,-phi],
[phi,0,1], [-phi,0,1], [phi,0,-1], [-phi,0,-1]
])
unit(p)
];
testpoints_spherical = [ for(p = testpoints_on_sphere) spherical(p) ];
testpoints_circular = [ for(a = [0:15:360-epsilon]) [cos(a),sin(a)] ];
testpoints_coplanar = let(u = unit([1,3,7]), v = unit([-2,1,-2])) [ for(i = [1:10]) rands(-1,1,1)[0] * u + rands(-1,1,1)[0] * v ];
testpoints_collinear_2d = let(u = unit([5,3])) [ for(i = [1:20]) rands(-1,1,1)[0] * u ];
testpoints_collinear_3d = let(u = unit([5,3,-5])) [ for(i = [1:20]) rands(-1,1,1)[0] * u ];
testpoints2d = 20 * [for (i = [1:10]) concat(rands(-1,1,2))];
testpoints3d = 20 * [for (i = [1:50]) concat(rands(-1,1,3))];
// All points are on the sphere, no point should be red
translate([-50,0]) visualize_hull(20*testpoints_on_sphere);
// 2D points
translate([50,0]) visualize_hull(testpoints2d);
// All points on a circle, no point should be red
translate([0,50]) visualize_hull(20*testpoints_circular);
// All points 3d but collinear
translate([0,-50]) visualize_hull(20*testpoints_coplanar);
// Collinear
translate([50,50]) visualize_hull(20*testpoints_collinear_2d);
// Collinear
translate([-50,50]) visualize_hull(20*testpoints_collinear_3d);
// 3D points
visualize_hull(testpoints3d);
module visualize_hull(points) {
hull = hull(points);
%if (len(hull) > 0 && len(hull[0]) > 0)
polyhedron(points=points, faces = hull);
else
polyhedron(points=points, faces = [hull]);
for (i = [0:len(points)-1]) assign(p = points[i], $fn = 16) {
translate(p) {
if (hull_contains_index(hull,i)) {
color("blue") sphere(1);
} else {
color("red") sphere(1);
}
}
}
function hull_contains_index(hull, index) =
search(index,hull,1,0) ||
search(index,hull,1,1) ||
search(index,hull,1,2);
}

View File

@ -0,0 +1,32 @@
// very minimal set of linalg functions needed by so3, se3 etc.
// cross and norm are builtins
//function cross(x,y) = [x[1]*y[2]-x[2]*y[1], x[2]*y[0]-x[0]*y[2], x[0]*y[1]-x[1]*y[0]];
//function norm(v) = sqrt(v*v);
function vec3(p) = len(p) < 3 ? concat(p,0) : p;
function vec4(p) = let (v3=vec3(p)) len(v3) < 4 ? concat(v3,1) : v3;
function unit(v) = v/norm(v);
function identity3()=[[1,0,0],[0,1,0],[0,0,1]];
function identity4()=[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]];
function take3(v) = [v[0],v[1],v[2]];
function tail3(v) = [v[3],v[4],v[5]];
function rotation_part(m) = [take3(m[0]),take3(m[1]),take3(m[2])];
function rot_trace(m) = m[0][0] + m[1][1] + m[2][2];
function rot_cos_angle(m) = (rot_trace(m)-1)/2;
function rotation_part(m) = [take3(m[0]),take3(m[1]),take3(m[2])];
function translation_part(m) = [m[0][3],m[1][3],m[2][3]];
function transpose_3(m) = [[m[0][0],m[1][0],m[2][0]],[m[0][1],m[1][1],m[2][1]],[m[0][2],m[1][2],m[2][2]]];
function transpose_4(m) = [[m[0][0],m[1][0],m[2][0],m[3][0]],
[m[0][1],m[1][1],m[2][1],m[3][1]],
[m[0][2],m[1][2],m[2][2],m[3][2]],
[m[0][3],m[1][3],m[2][3],m[3][3]]];
function invert_rt(m) = construct_Rt(transpose_3(rotation_part(m)), -(transpose_3(rotation_part(m)) * translation_part(m)));
function construct_Rt(R,t) = [concat(R[0],t[0]),concat(R[1],t[1]),concat(R[2],t[2]),[0,0,0,1]];
// Hadamard product of n-dimensional arrays
function hadamard(a,b) = !(len(a)>0) ? a*b : [ for(i = [0:len(a)-1]) hadamard(a[i],b[i]) ];

View File

@ -0,0 +1,48 @@
// List helpers
/*!
Flattens a list one level:
flatten([[0,1],[2,3]]) => [0,1,2,3]
*/
function flatten(list) = [ for (i = list, v = i) v ];
/*!
Creates a list from a range:
range([0:2:6]) => [0,2,4,6]
*/
function range(r) = [ for(x=r) x ];
/*!
Reverses a list:
reverse([1,2,3]) => [3,2,1]
*/
function reverse(list) = [for (i = [len(list)-1:-1:0]) list[i]];
/*!
Extracts a subarray from index begin (inclusive) to end (exclusive)
FIXME: Change name to use list instead of array?
subarray([1,2,3,4], 1, 2) => [2,3]
*/
function subarray(list,begin=0,end=-1) = [
let(end = end < 0 ? len(list) : end)
for (i = [begin : 1 : end-1])
list[i]
];
/*!
Returns a copy of a list with the element at index i set to x
set([1,2,3,4], 2, 5) => [1,2,5,4]
*/
function set(list, i, x) = [for (i_=[0:len(list)-1]) i == i_ ? x : list[i_]];
/*!
Remove element from the list by index.
remove([4,3,2,1],1) => [4,2,1]
*/
function remove(list, i) = [for (i_=[0:1:len(list)-2]) list[i_ < i ? i_ : i_ + 1]];

View File

@ -0,0 +1,30 @@
// Copyright (c) 2013 Oskar Linde. All rights reserved.
// License: BSD
//
// This library contains simple mirroring functions
//
// mirror_x()
// mirror_y()
// mirror_z()
module mirror_x() {
union() {
child();
scale([-1,1,1]) child();
}
}
module mirror_y() {
union() {
child();
scale([1,-1,1]) child();
}
}
module mirror_z() {
union() {
child();
scale([1,1,-1]) child();
}
}

View File

@ -0,0 +1,109 @@
// Copyright (c) 2013 Oskar Linde. All rights reserved.
// License: BSD
//
// This library contains basic 2D morphology operations
//
// outset(d=1) - creates a polygon at an offset d outside a 2D shape
// inset(d=1) - creates a polygon at an offset d inside a 2D shape
// fillet(r=1) - adds fillets of radius r to all concave corners of a 2D shape
// rounding(r=1) - adds rounding to all convex corners of a 2D shape
// shell(d,center=false) - makes a shell of width d along the edge of a 2D shape
// - positive values of d places the shell on the outside
// - negative values of d places the shell on the inside
// - center=true and positive d places the shell centered on the edge
module outset(d=1) {
// Bug workaround for older OpenSCAD versions
if (version_num() < 20130424) render() outset_extruded(d) child();
else minkowski() {
circle(r=d);
child();
}
}
module outset_extruded(d=1) {
projection(cut=true) minkowski() {
cylinder(r=d);
linear_extrude(center=true) child();
}
}
module inset(d=1) {
render() inverse() outset(d=d) inverse() child();
}
module fillet(r=1) {
inset(d=r) render() outset(d=r) child();
}
module rounding(r=1) {
outset(d=r) inset(d=r) child();
}
module shell(d,center=false) {
if (center && d > 0) {
difference() {
outset(d=d/2) child();
inset(d=d/2) child();
}
}
if (!center && d > 0) {
difference() {
outset(d=d) child();
child();
}
}
if (!center && d < 0) {
difference() {
child();
inset(d=-d) child();
}
}
if (d == 0) child();
}
// Below are for internal use only
module inverse() {
difference() {
square(1e5,center=true);
child();
}
}
// TEST CODE
use <mirror.scad>
module arrow(l=1,w=.6,t=0.15) {
mirror_y() polygon([[0,0],[l,0],[l-w/2,w/2],[l-w/2-sqrt(2)*t,w/2],[l-t/2-sqrt(2)*t,t/2],[0,t/2]]);
}
module shape() {
polygon([[0,0],[1,0],[1.5,1],[2.5,1],[2,-1],[0,-1]]);
}
if(0) assign($fn=32) {
for (p = [0:10*3-1]) assign(o=floor(p/3)) {
translate([(p%3)*2.5,-o*3]) {
//%if (p % 3 == 1) translate([0,0,1]) shape();
if (p % 3 == 0) shape();
if (p % 3 == 1) translate([0.6,0]) arrow();
if (p % 3 == 2) {
if (o == 0) inset(d=0.3) shape();
if (o == 1) outset(d=0.3) shape();
if (o == 2) rounding(r=0.3) shape();
if (o == 3) fillet(r=0.3) shape();
if (o == 4) shell(d=0.3) shape();
if (o == 5) shell(d=-0.3) shape();
if (o == 6) shell(d=0.3,center=true) shape();
if (o == 7) rounding(r=0.3) fillet(r=0.3) shape();
if (o == 8) shell(d=0.3,center=true) fillet(r=0.3) rounding(r=0.3) shape();
if (o == 9) shell(d=-0.3) fillet(r=0.3) rounding(r=0.3) shape();
}
}
}
}

View File

@ -0,0 +1,60 @@
use <linalg.scad>
use <so3.scad>
function combine_se3_exp(w, ABt) = construct_Rt(rodrigues_so3_exp(w, ABt[0], ABt[1]), ABt[2]);
// [A,B,t]
function se3_exp_1(t,w) = concat(
so3_exp_1(w*w),
[t + 0.5 * cross(w,t)]
);
function se3_exp_2(t,w) = se3_exp_2_0(t,w,w*w);
function se3_exp_2_0(t,w,theta_sq) =
se3_exp_23(
so3_exp_2(theta_sq),
C = (1.0 - theta_sq/20) / 6,
t=t,w=w);
function se3_exp_3(t,w) = se3_exp_3_0(t,w,sqrt(w*w)*180/PI,1/sqrt(w*w));
function se3_exp_3_0(t,w,theta_deg,inv_theta) =
se3_exp_23(
so3_exp_3_0(theta_deg = theta_deg, inv_theta = inv_theta),
C = (1 - sin(theta_deg) * inv_theta) * (inv_theta * inv_theta),
t=t,w=w);
function se3_exp_23(AB,C,t,w) =
[AB[0], AB[1], t + AB[1] * cross(w,t) + C * cross(w,cross(w,t)) ];
function se3_exp(mu) = se3_exp_0(t=take3(mu),w=tail3(mu)/180*PI);
function se3_exp_0(t,w) =
combine_se3_exp(w,
// Evaluate by Taylor expansion when near 0
w*w < 1e-8
? se3_exp_1(t,w)
: w*w < 1e-6
? se3_exp_2(t,w)
: se3_exp_3(t,w)
);
function se3_ln(m) = se3_ln_to_deg(se3_ln_rad(m));
function se3_ln_to_deg(v) = concat(take3(v),tail3(v)*180/PI);
function se3_ln_rad(m) = se3_ln_0(m,
rot = so3_ln_rad(rotation_part(m)));
function se3_ln_0(m,rot) = se3_ln_1(m,rot,
theta = sqrt(rot*rot));
function se3_ln_1(m,rot,theta) = se3_ln_2(m,rot,theta,
shtot = theta > 0.00001 ? sin(theta/2*180/PI)/theta : 0.5,
halfrotator = so3_exp_rad(rot * -.5));
function se3_ln_2(m,rot,theta,shtot,halfrotator) =
concat( (halfrotator * translation_part(m) -
(theta > 0.001
? rot * ((translation_part(m) * rot) * (1-2*shtot) / (rot*rot))
: rot * ((translation_part(m) * rot)/24)
)) / (2 * shtot), rot);
__se3_test = [20,-40,60,-80,100,-120];
echo(UNITTEST_se3=norm(__se3_test-se3_ln(se3_exp(__se3_test))) < 1e-8);

View File

@ -0,0 +1,16 @@
function square(size) = [[-size,-size], [-size,size], [size,size], [size,-size]] / 2;
function circle(r) = [for (i=[0:$fn-1]) let (a=i*360/$fn) r * [cos(a), sin(a)]];
function regular(r, n) = circle(r, $fn=n);
function rectangle_profile(size=[1,1]) = [
// The first point is the anchor point, put it on the point corresponding to [cos(0),sin(0)]
[ size[0]/2, 0],
[ size[0]/2, size[1]/2],
[-size[0]/2, size[1]/2],
[-size[0]/2, -size[1]/2],
[ size[0]/2, -size[1]/2],
];
// FIXME: Move rectangle and rounded rectangle from extrusion

View File

@ -0,0 +1,82 @@
// so3
use <linalg.scad>
function rodrigues_so3_exp(w, A, B) = [
[1.0 - B*(w[1]*w[1] + w[2]*w[2]), B*(w[0]*w[1]) - A*w[2], B*(w[0]*w[2]) + A*w[1]],
[B*(w[0]*w[1]) + A*w[2], 1.0 - B*(w[0]*w[0] + w[2]*w[2]), B*(w[1]*w[2]) - A*w[0]],
[B*(w[0]*w[2]) - A*w[1], B*(w[1]*w[2]) + A*w[0], 1.0 - B*(w[0]*w[0] + w[1]*w[1])]
];
function so3_exp(w) = so3_exp_rad(w/180*PI);
function so3_exp_rad(w) =
combine_so3_exp(w,
w*w < 1e-8
? so3_exp_1(w*w)
: w*w < 1e-6
? so3_exp_2(w*w)
: so3_exp_3(w*w));
function combine_so3_exp(w,AB) = rodrigues_so3_exp(w,AB[0],AB[1]);
// Taylor series expansions close to 0
function so3_exp_1(theta_sq) = [
1 - 1/6*theta_sq,
0.5
];
function so3_exp_2(theta_sq) = [
1.0 - theta_sq * (1.0 - theta_sq/20) / 6,
0.5 - 0.25/6 * theta_sq
];
function so3_exp_3_0(theta_deg, inv_theta) = [
sin(theta_deg) * inv_theta,
(1 - cos(theta_deg)) * (inv_theta * inv_theta)
];
function so3_exp_3(theta_sq) = so3_exp_3_0(sqrt(theta_sq)*180/PI, 1/sqrt(theta_sq));
function rot_axis_part(m) = [m[2][1] - m[1][2], m[0][2] - m[2][0], m[1][0] - m[0][1]]*0.5;
function so3_ln(m) = 180/PI*so3_ln_rad(m);
function so3_ln_rad(m) = so3_ln_0(m,
cos_angle = rot_cos_angle(m),
preliminary_result = rot_axis_part(m));
function so3_ln_0(m, cos_angle, preliminary_result) =
so3_ln_1(m, cos_angle, preliminary_result,
sin_angle_abs = sqrt(preliminary_result*preliminary_result));
function so3_ln_1(m, cos_angle, preliminary_result, sin_angle_abs) =
cos_angle > sqrt(1/2)
? sin_angle_abs > 0
? preliminary_result * asin(sin_angle_abs)*PI/180 / sin_angle_abs
: preliminary_result
: cos_angle > -sqrt(1/2)
? preliminary_result * acos(cos_angle)*PI/180 / sin_angle_abs
: so3_get_symmetric_part_rotation(
preliminary_result,
m,
angle = PI - asin(sin_angle_abs)*PI/180,
d0 = m[0][0] - cos_angle,
d1 = m[1][1] - cos_angle,
d2 = m[2][2] - cos_angle
);
function so3_get_symmetric_part_rotation(preliminary_result, m, angle, d0, d1, d2) =
so3_get_symmetric_part_rotation_0(preliminary_result,angle,so3_largest_column(m, d0, d1, d2));
function so3_get_symmetric_part_rotation_0(preliminary_result, angle, c_max) =
angle * unit(c_max * preliminary_result < 0 ? -c_max : c_max);
function so3_largest_column(m, d0, d1, d2) =
d0*d0 > d1*d1 && d0*d0 > d2*d2
? [d0, (m[1][0]+m[0][1])/2, (m[0][2]+m[2][0])/2]
: d1*d1 > d2*d2
? [(m[1][0]+m[0][1])/2, d1, (m[2][1]+m[1][2])/2]
: [(m[0][2]+m[2][0])/2, (m[2][1]+m[1][2])/2, d2];
__so3_test = [12,-125,110];
echo(UNITTEST_so3=norm(__so3_test-so3_ln(so3_exp(__so3_test))) < 1e-8);

View File

@ -0,0 +1,113 @@
// Spline module for scad-util library
// Author Sergei Kuzmin, 2014.
// For n+1 given point and hense n intervals returns the spline coefficient matrix.
// param p defines the anchor points.
// File defines two functions: spline_args and spline.
// example usage:
// spl1 = spline_args(point, v1=[0,1,0], closed=false);
// interpolated_points = [for(t=[0:0.1:len(point)-1]) spline(spl1, t)]
use <linalg.scad>
use <lists.scad>
q1=[[1,0,0,0],[1,1,1,1],[0,1,2,3],[0,0,1,3]];
q1inv=[[1,0,0,0],[-3,3,-2,1],[3,-3,3,-2],[-1,1,-1,1]];
q2=[[0,0,0,0],[0,0,0,0],[0,-1,0,0],[0,0,-1,0]];
qn1i2=-q1inv*q2;
z3=[0,0,0];
z4=[0,0,0,0];
function matrix_power(m,n)= n==0? (len(m)==3?identity3():identity4()) :
n==1 ? m : (n%2==1) ? matrix_power(m*m,floor(n/2))*m : matrix_power(m*m,n/2);
function det(m) = let(r=[for(i=[0:1:len(m)-1]) i]) det_help(m, 0, r);
// Construction indices list is inefficient, but currently there is no way to imperatively
// assign to a list element
function det_help(m, i, r) = len(r) == 0 ? 1 :
m[len(m)-len(r)][r[i]]*det_help(m,0,remove(r,i)) - (i+1<len(r)? det_help(m, i+1, r) : 0);
function matrix_invert(m) = let(r=[for(i=[0:len(m)-1]) i]) [for(i=r) [for(j=r)
((i+j)%2==0 ? 1:-1) * matrix_minor(m,0,remove(r,j),remove(r,i))]] / det(m);
function matrix_minor(m,k,ri, rj) = let(len_r=len(ri)) len_r == 0 ? 1 :
m[ri[0]][rj[k]]*matrix_minor(m,0,remove(ri,0),remove(rj,k)) - (k+1<len_r?matrix_minor(m,k+1,ri,rj) : 0);
function spline_u(i,p) = [p[i],p[i+1],z3,z3];
function spline_args(p, closed=false, v1=undef, v2=undef)=len(p)<2 ? []:
let(q3=closed?q2:[z4, z4, v1==undef?[0,0,1,0]:[0,1,0,0], z4],
q4=closed?q1:[[1,0,0,0], [1,1,1,1], z4, v2==undef?[0,0,1,3]:[0,1,2,3]],
pcnt=closed? len(p) + 1 : len(p),
un=[p[pcnt-2],p[closed?0:pcnt-1],v1==undef?z4:v1, v2==undef?z4:v2],
sn=matrix_invert(q4+q3*matrix_power(qn1i2,pcnt-2))*(un-q3*q1inv*spline_helper(0, pcnt, p)))
// result[i+1] recurrently defines result[i]. This is O(n) runtime with imperative language and
// may be O(n^2) if OpenSCAD doesn't cache spline_si(i+1).
[for(i=[0:pcnt-2]) spline_si(i, pcnt-2, p, sn)];
// n is number of points including pseudopoint for closed contour
// Weird construct cause there is no if statement for functions
function spline_helper(i, n, p) = let(u=[p[i], p[i+1], z3, z3]) i+3>=n? u : u-q2*q1inv*spline_helper(i+1, n, p);
// knowing s[j+1], calculate s[j]. Stop when found s[i]
function spline_si(i,n, p, sn) = i == n ? sn : q1inv*(spline_u(i,p)-q2*spline_si(i+1, n, p, sn));
// Takes array of (3n+1) points or (2n + 2) points, if tangent segments are symmetric.
// For non-symmetric version input is: point0, normal0, neg_normal1, point1, normal1, ... neg_normal_n, point_n
// For symmetric version: point0, normal0, point1, normal1, ... , normal_n_sub_1, point_n
// In the second case second tangent is constructed from the next tangent by symmetric map.
// I.e. if current points are p0,p1,p2 then anchor points are p0 and p2, first tangent defined by p1-p0,
// second tangent defined by p3-p2.
// Return array of coefficients accepted by spline(), spline_tan() and similar
function bezier3_args(p, symmetric=false) = let(step=symmetric?2:3)
[for(i=[0:step:len(p)-3]) [[1,0,0,0],[-3,3,0,0],[3,-6,3,0],[-1,3,-3,1]]*
(symmetric?[p[i],p[i]+p[i+1],p[i+2]-p[i+3],p[i+2]] : [p[i], p[i]+p[i+1], p[i+3]+p[i+2], p[i+3]])];
// s - spline arguments calculated by spline_args
// t - defines point on curve. each segment length is 1. I.e. t= 0..1 is first segment, t=1..2 - second.
function spline(s, t)= let(i=t>=len(s)?len(s)-1: floor(t), t2=t-i) [1,t2,t2*t2,t2*t2*t2]*s[i];
function spline_tan(s, t)= let(i=t>=len(s)?len(s)-1: floor(t), t2=t-i) [0,1,2*t2,3*t2*t2]*s[i];
function spline_tan_unit(s, t)= unit(spline_tan(s,t));
function spline_d2(s,t)= let(i=t>=len(s)?len(s)-1: floor(t), t2=t-i) [0,0,2,6*t2]*s[i];
function spline_binormal_unit(s,t)= unit(cross(spline_tan(s, t), spline_d2(s,t)));
function spline_normal_unit(s,t)= unit(cross(spline_tan(s, t), spline_binormal_unit(s,t)));
function spline_transform(s, t)=
construct_Rt(transpose_3([spline_normal_unit(s,t), spline_binormal_unit(s,t), spline_tan_unit(s,t)]), spline(s,t));
// Unit tests
__s = spline_args([[0,10,0], [10,0,0],[0,-5,2]], v1=[0,1,0], v2=[-1,0,0], closed=true);
for(t=[0:0.01:len(__s)]) translate(spline(__s, t))
cube([0.2,0.2,0.2], center=true);
__s1=spline_args([[0,0,0],[0,0,15], [26,0,26+15]], /*v1=[0,0,100],*/ v2=[40,0,0]);
for(t=[0:0.01:len(s1)]) translate(spline(__s1, t))
cube([0.2,0.2,0.2], center=true);
__s2=bezier3_args([[0,0,0],[0,0,10],[0,0,15],[0,0,26*0.552284],[26,0,41],[26*0.552284,0,0]],symmetric=true);
echo(__s2);
for(t=[0:0.01:len(__s2)]) translate(spline(__s2, t))
cube([0.2,0.2,0.2], center=true);
// Rotation methods taken from list-comprehension-demos/sweep.scad to demonstrate normal and binormal
// Normally spline_transform is more convenient
function __rotation_from_axis(x,y,z) = [[x[0],y[0],z[0]],[x[1],y[1],z[1]],[x[2],y[2],z[2]]];
function __rotate_from_to(a,b,_axis=[]) =
len(_axis) == 0
? __rotate_from_to(a,b,unit(cross(a,b)))
: _axis*_axis >= 0.99 ? __rotation_from_axis(unit(b),_axis,cross(_axis,unit(b))) *
transpose_3(__rotation_from_axis(unit(a),_axis,cross(_axis,unit(a)))) : identity3();
__s3 = spline_args([[0,10,0], [6,6,0], [10,0,0],[0,-5,4]], v1=[0,1,0], v2=[-1,0,0], closed=true);
for(t=[0:0.05:len(__s3)]) translate(spline(__s3, t)) {
translate([0,0,3]) multmatrix(m=__rotate_from_to([0,0,1],spline_normal_unit(__s3,t)))
cylinder(r1=0.1, r2=0, h=1, $fn=3);
translate([0,0,6]) multmatrix(m=__rotate_from_to([0,0,1],spline_binormal_unit(__s3,t)))
cylinder(r1=0.1, r2=0, h=1, $fn=3);
}
translate([0,0,9]) for(t=[0:0.025:len(__s3)])
multmatrix(spline_transform(__s3,t)) cube([1,1,0.1],center=true);

View File

@ -0,0 +1,43 @@
use <so3.scad>
function val(a=undef,default=undef) = a == undef ? default : a;
function vec_is_undef(x,index_=0) = index_ >= len(x) ? true :
is_undef(x[index_]) && vec_is_undef(x,index_+1);
function is_undef(x) = len(x) > 0 ? vec_is_undef(x) : x == undef;
// Either a or b, but not both
function either(a,b,default=undef) = is_undef(a) ? (is_undef(b) ? default : b) : is_undef(b) ? a : undef;
function translationv(left=undef,right=undef,up=undef,down=undef,forward=undef,backward=undef,translation=undef) =
translationv_2(
x = either(up,-down),
y = either(right,-left),
z = either(forward,-backward),
translation = translation);
function translationv_2(x,y,z,translation) =
x == undef && y == undef && z == undef ? translation :
is_undef(translation) ? [val(x,0),val(y,0),val(z,0)]
: undef;
function rotationv(pitch=undef,yaw=undef,roll=undef,rotation=undef) =
rotation == undef ? [val(yaw,0),val(pitch,0),val(roll,0)] :
pitch == undef && yaw == undef && roll == undef ? rotation :
undef;
function trajectory(
left=undef, right=undef,
up=undef, down=undef,
forward=undef, backward=undef,
translation=undef,
pitch=undef,
yaw=undef,
roll=undef,
rotation=undef
) = concat(
translationv(left=left,right=right,up=up,down=down,forward=forward,backward=backward,translation=translation),
rotationv(pitch=pitch,yaw=yaw,roll=roll,rotation=rotation)
);
function rotationm(rotation=undef,pitch=undef,yaw=undef,roll=undef) = so3_exp(rotationv(rotation=rotation,pitch=pitch,yaw=yaw,roll=roll));

View File

@ -0,0 +1,89 @@
use <linalg.scad>
use <se3.scad>
function left_multiply(a,bs,i_=0) = i_ >= len(bs) ? [] :
concat([
a * bs[i_]
], left_multiply(a,bs,i_+1));
function right_multiply(as,b,i_=0) = i_ >= len(as) ? [] :
concat([
as[i_] * b
], right_multiply(as,b,i_+1));
function quantize_trajectory(trajectory,step=undef,start_position=0,steps=undef,i_=0,length_=undef) =
length_ == undef ? quantize_trajectory(
trajectory=trajectory,
start_position=(step==undef?norm(take3(trajectory))/steps*start_position:start_position),
length_=norm(take3(trajectory)),
step=step,steps=steps,i_=i_) :
(steps==undef?start_position > length_:i_>=steps) ? [] :
concat([
// if steps is defined, ignore start_position
se3_exp(trajectory*(steps==undef ? start_position/length_
: i_/(steps>1?steps-1:1)))
], quantize_trajectory(trajectory=trajectory,step=step,start_position=(steps==undef?start_position+step:start_position),steps=steps,i_=i_+1,length_=length_));
function close_trajectory_loop(trajectories) = concat(trajectories,[se3_ln(invert_rt(trajectories_end_position(trajectories)))]);
function quantize_trajectories(trajectories,step=undef,start_position=0,steps=undef,loop=false,last_=identity4(),i_=0,current_length_=undef,j_=0) =
// due to quantization differences, the last step may be missed. In that case, add it:
loop==true ? quantize_trajectories(
trajectories=close_trajectory_loop(trajectories),
step=step,
start_position = start_position,
steps=steps,
loop=false,
last_=last_,
i_=i_,
current_length_=current_length_,
j_=j_) :
i_ >= len(trajectories) ? (j_ < steps ? [last_] : []) :
current_length_ == undef ?
quantize_trajectories(
trajectories=trajectories,
step = (step == undef ? trajectories_length(trajectories) / steps : step),
start_position = (step == undef ? start_position * trajectories_length(trajectories) / steps : start_position),
steps=steps,
loop=loop,
last_=last_,
i_=i_,
current_length_=norm(take3(trajectories[i_])),
j_=j_) :
concat(
left_multiply(last_,quantize_trajectory(
trajectory=trajectories[i_],
start_position=start_position,
step=step)),
quantize_trajectories(
trajectories=trajectories,
step=step,
start_position = start_position > current_length_
? start_position - current_length_
: step - ((current_length_-start_position) % step),
steps=steps,
loop=loop,
last_=last_ * se3_exp(trajectories[i_]),
i_=i_+1,
current_length_ = undef,
j_=j_+len(
quantize_trajectory(
trajectory=trajectories[i_],
start_position=start_position,
step=step
))
))
;
function trajectories_length(trajectories, i_=0) = i_ >= len(trajectories) ? 0
: norm(take3(trajectories[i_])) + trajectories_length(trajectories,i_+1);
function trajectories_end_position(rt,i_=0,last_=identity4()) =
i_ >= len(rt) ? last_ :
trajectories_end_position(rt, i_+1, last_ * se3_exp(rt[i_]));

View File

@ -0,0 +1,43 @@
use <se3.scad>
use <linalg.scad>
use <lists.scad>
/*!
Creates a rotation matrix
xyz = euler angles = rz * ry * rx
axis = rotation_axis * rotation_angle
*/
function rotation(xyz=undef, axis=undef) =
xyz != undef && axis != undef ? undef :
xyz == undef ? se3_exp([0,0,0,axis[0],axis[1],axis[2]]) :
len(xyz) == undef ? rotation(axis=[0,0,xyz]) :
(len(xyz) >= 3 ? rotation(axis=[0,0,xyz[2]]) : identity4()) *
(len(xyz) >= 2 ? rotation(axis=[0,xyz[1],0]) : identity4()) *
(len(xyz) >= 1 ? rotation(axis=[xyz[0],0,0]) : identity4());
/*!
Creates a scaling matrix
*/
function scaling(v) = [
[v[0],0,0,0],
[0,v[1],0,0],
[0,0,v[2],0],
[0,0,0,1],
];
/*!
Creates a translation matrix
*/
function translation(v) = [
[1,0,0,v[0]],
[0,1,0,v[1]],
[0,0,1,v[2]],
[0,0,0,1],
];
// Convert between cartesian and homogenous coordinates
function project(x) = subarray(x,end=len(x)-1) / x[len(x)-1];
function transform(m, list) = [for (p=list) project(m * vec4(p))];
function to_3d(list) = [ for(v = list) vec3(v) ];

137
libraries/skin.scad Normal file
View File

@ -0,0 +1,137 @@
use <scad-utils/transformations.scad>
use <scad-utils/lists.scad>
// Skin a set of profiles with a polyhedral mesh
module skin(profiles, loop=false /* unimplemented */) {
P = max_len(profiles);
N = len(profiles);
profiles = [
for (p = profiles)
for (pp = augment_profile(to_3d(p),P))
pp
];
function quad(i,P,o) = [[o+i, o+i+P, o+i%P+P+1], [o+i, o+i%P+P+1, o+i%P+1]];
function profile_triangles(tindex) = [
for (index = [0:P-1])
let (qs = quad(index+1, P, P*(tindex-1)-1))
for (q = qs) q
];
triangles = [
for(index = [1:N-1])
for(t = profile_triangles(index))
t
];
start_cap = [range([0:P-1])];
end_cap = [range([P*N-1 : -1 : P*(N-1)])];
polyhedron(convexity=2, points=profiles, faces=concat(start_cap, triangles, end_cap));
}
// Augments the profile with steiner points making the total number of vertices n
function augment_profile(profile, n) =
subdivide(profile,insert_extra_vertices_0([profile_lengths(profile),dup(0,len(profile))],n-len(profile))[1]);
function subdivide(profile,subdivisions) = let (N=len(profile)) [
for (i = [0:N-1])
let(n = len(subdivisions)>0 ? subdivisions[i] : subdivisions)
for (p = interpolate(profile[i],profile[(i+1)%N],n+1))
p
];
function interpolate(a,b,subdivisions) = [
for (index = [0:subdivisions-1])
let(t = index/subdivisions)
a*(1-t)+b*t
];
function distribute_extra_vertex(lengths_count,ma_=-1) = ma_<0 ? distribute_extra_vertex(lengths_count, max_element(lengths_count[0])) :
concat([set(lengths_count[0],ma_,lengths_count[0][ma_] * (lengths_count[1][ma_]+1) / (lengths_count[1][ma_]+2))], [increment(lengths_count[1],max_element(lengths_count[0]),1)]);
function insert_extra_vertices_0(lengths_count,n_extra) = n_extra <= 0 ? lengths_count :
insert_extra_vertices_0(distribute_extra_vertex(lengths_count),n_extra-1);
// Find the index of the maximum element of arr
function max_element(arr,ma_,ma_i_=-1,i_=0) = i_ >= len(arr) ? ma_i_ :
i_ == 0 || arr[i_] > ma_ ? max_element(arr,arr[i_],i_,i_+1) : max_element(arr,ma_,ma_i_,i_+1);
function max_len(arr) = max([for (i=arr) len(i)]);
function increment(arr,i,x=1) = set(arr,i,arr[i]+x);
function profile_lengths(profile) = [
for (i = [0:len(profile)-1])
profile_segment_length(profile,i)
];
function profile_segment_length(profile,i) = norm(profile[(i+1)%len(profile)] - profile[i]);
// Generates an array with n copies of value (default 0)
function dup(value=0,n) = [for (i = [1:n]) value];
use <scad-utils/transformations.scad>
use <scad-utils/trajectory_path.scad>
use <scad-utils/trajectory.scad>
use <scad-utils/shapes.scad>
module fakeISOEnter(thickness_difference = 0){
// 1u is the space taken upy by a 1u keycap.
// unit is the space taken up by a unit space for a keycap.
// formula is 1u + unit *(length - 1)
// t is all modifications to the polygon array
t = thickness_difference/2 - (19.02 - 18.16);
function unit(length) = 19.02 * length;
pointArray = [
[19.05 * (-.5) + t, 19.05 * (-1) + t],
[19.05 * (0.5) - t, 19.05 * (-1) + t],
[19.05 * (0.5) - t, 19.05 * (1) - t],
[19.05 * (-0.75) + t, 19.05 * (1) - t],
[19.05 * (-0.75) + t, 19.05 * (0) + t],
[19.05 * (-0.5) + t, 19.05 * (0) + t]
];
/*translate([unit(-.5), unit(-1) + 0.86]){*/
minkowski() {
circle($corner_radius, $fn=20);
offset(r=-$corner_radius * 2, $fn=20) polygon(points=pointArray);
}
/*}*/
}
function isoEnter() = [
[19.05 * (-.5) + (19.02 - 18.16), 19.05 * (-1) + (19.02 - 18.16)],
[19.05 * (0.5) - (19.02 - 18.16), 19.05 * (-1) + (19.02 - 18.16)],
[19.05 * (0.5) - (19.02 - 18.16), 19.05 * (1) - (19.02 - 18.16)],
[19.05 * (-0.75) + (19.02 - 18.16), 19.05 * (1) - (19.02 - 18.16)],
[19.05 * (-0.75) + (19.02 - 18.16), 19.05 * (0) + (19.02 - 18.16)],
[19.05 * (-0.5) + (19.02 - 18.16), 19.05 * (0) + (19.02 - 18.16)]
];
path_definition = [
trajectory(forward = 10, roll = 0),
];
// sweep
path = quantize_trajectories(path_definition, steps=100);
// skin
myLen = len(path)-1;
trans = [ for (i=[0:len(path)-1]) transform(path[i], isoEnter()) ];
translate([0,10,0])
skin(trans);

View File

@ -1,7 +1,6 @@
$fs=.1;
//centered
// offset, who knew?
// centered
module roundedRect(size, radius, center=true) {
linear_extrude(height = size[2]){
roundedSquare([size[0], size[1]], radius, center=center);
@ -14,25 +13,35 @@ module roundedSquare(size, radius, center = true) {
}
}
module oldroundedRect(size, radius) {
x = size[0];
y = size[1];
z = size[2];
// corollary is roundedRect
// NOT 3D
module fakeISOEnter(thickness_difference = 0){
// 1u is the space taken upy by a 1u keycap.
// unit is the space taken up by a unit space for a keycap.
// formula is 1u + unit *(length - 1)
translate([-x/2,-y/2,0])
linear_extrude(height=z)
hull() {
translate([radius, radius, 0])
circle(r=radius);
// t is all modifications to the polygon array
// t used to contain a corner radius adjustment, but due to
// the offset we need that expansion back
t = (thickness_difference - (19.05 - 18.16));
translate([x - radius, radius, 0])
circle(r=radius);
function unit(length) = 19.05 * length;
translate([x - radius, y - radius, 0])
circle(r=radius);
pointArray = [
[unit(-.625) + t, unit(-1) + t],
[unit(0.625) - t, unit(-1) + t],
[unit(0.625) - t, unit(1) - t],
[unit(-0.875) + t, unit(1) - t],
[unit(-0.875) + t, unit(0) + t],
[unit(-0.625) + t, unit(0) + t]
];
translate([radius, y - radius, 0])
circle(r=radius);
minkowski(){
circle(r=$corner_radius);
// gives us rounded inner corner
offset(r=-$corner_radius*2) {
polygon(points=pointArray);
}
}
}