Last active
January 13, 2025 08:46
2D chamfer/fillet of point in list of points
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 2d-chamfer.scad by ouroborus@ouroborus.org is marked with CC0 1.0. To view a copy of this license, visit https://creativecommons.org/publicdomain/zero/1.0/ | |
/* Chamfer by length of new edge | |
* chamfer([[?,?],...], ?, ?) | |
* chamfer(points=[[?,?],...], idx=?, length=?) | |
* Chamfer by lengths of two adjacent edges | |
* chamfer([[?,?],...], ?, ?, ?) | |
* chamfer(points=[[?,?],...], idx=?, length=?, length2=?) | |
* Chamfer by distance from point | |
* chamfer([[?,?],...], ?, depth=?) | |
* chamfer(points=[[?,?],...], idx=?, depth=?) | |
* points: A list of 2d points representing a polygon | |
* idx: The index of the point to chamfer | |
* returns: The chamfered list of 2d points | |
*/ | |
function chamfer(points, idx, length, length2, depth) = let ( | |
l = len(points), | |
last = l-1, | |
head = idx > 0 ? [for(i=[0:idx-1]) points[i]] : [], | |
tail = idx < last ? [for(i=[idx+1:last]) points[i]] : [], | |
target = [points[(idx-1+l)%l], points[idx], points[(idx+1)%l]], | |
vector_a = target[0] - target[1], | |
vector_b = target[2] - target[1], | |
norm_a = vector_a / norm(vector_a), | |
norm_b = vector_b / norm(vector_b), | |
chamfer1 = function() let ( | |
hyp = length / sqrt(2 - 2 * (norm_a * norm_b)), | |
) [ | |
norm_a * hyp, | |
norm_b * hyp | |
], | |
chamfer2 = function() [ | |
norm_a * length, | |
norm_b * length2, | |
], | |
chamfer3 = function() let ( | |
leg = sqrt(2) * depth / sqrt(norm_a * norm_b + 1) | |
) [ | |
norm_a * leg, | |
norm_b * leg | |
], | |
p = is_undef(depth) ? is_undef(length2) ? chamfer1() : chamfer2() : chamfer3() | |
) [each head, p[0] + target[1], p[1] + target[1], each tail]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 2d-fillet.scad by ouroborus@ouroborus.org is marked with CC0 1.0. To view a copy of this license, visit https://creativecommons.org/publicdomain/zero/1.0/ | |
/* Fillet a 2d point in a list of 2d points | |
* fillet([[?,?],...], ?, ?) | |
* fillet(points=[[?,?],...], idx=?, radius=?) | |
* points: A list of 2d points representing a polygon | |
* idx: The index of the point to fillet | |
* $fn and $fa work the same as in native shapes. | |
* returns: The filleted list of 2d points | |
*/ | |
function fillet(points, idx, radius, $fn=$fn, $fa=$fa) = let ( | |
lerp = function(a, b, t) a + t * (b - a), | |
get_angle = function(a, b) atan2(b.y - a.y, b.x - a.x), | |
l = len(points), | |
last = l-1, | |
head = idx > 0 ? [for(i=[0:idx-1]) points[i]] : [], | |
tail = idx < last ? [for(i=[idx+1:last]) points[i]] : [], | |
target = [points[(idx-1+l)%l], points[idx], points[(idx+1)%l]], | |
vector_a = target[0] - target[1], | |
vector_b = target[2] - target[1], | |
norm_a = vector_a / norm(vector_a), | |
norm_b = vector_b / norm(vector_b), | |
vector_bisect = norm_a + norm_b, | |
norm_bisect = vector_bisect / norm(vector_bisect), | |
dotp = norm_a * norm_b, | |
crossp = cross(norm_a, norm_b), | |
divisor = sqrt(1 - dotp), | |
leg = sqrt(1 + dotp) * radius / divisor, | |
hyp = sqrt(2) * radius / divisor, | |
p_start = target[1] + norm_a * leg, | |
p_stop = target[1] + norm_b * leg, | |
center = target[1] + hyp * norm_bisect, | |
start_angle = get_angle(center, p_start), | |
stop_angle = get_angle(center, p_stop), | |
stop_angle_up = stop_angle < start_angle ? stop_angle + 360 : stop_angle, | |
a_start = crossp >= 0 ? start_angle + 360 : start_angle, | |
a_stop = stop_angle_up, | |
spread = abs(a_stop - a_start), | |
step_t = 1 / ($fn > 0 ? $fn : ceil(spread / $fa)), | |
curve = [for(i=[step_t:step_t:1-step_t]) let( | |
l = (lerp(a_start, a_stop, i) + 360) % 360 | |
) center + [cos(l) * radius, sin(l) * radius] | |
], | |
) [each head, p_start, each curve, p_stop, each tail]; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment